mxlib
c++ tools for analyzing astronomical data and other tasks by Jared R. Males. [git repo]
turbLayer.hpp
Go to the documentation of this file.
1 /** \file turbLayer.hpp
2  * \brief Declaration and definition of a turbulence layer.
3  *
4  * \author Jared R. Males (jaredmales@gmail.com)
5  *
6  * \ingroup mxAO_sim_files
7  *
8  */
9 
10 //***********************************************************************//
11 // Copyright 2023 Jared R. Males (jaredmales@gmail.com)
12 //
13 // This file is part of mxlib.
14 //
15 // mxlib is free software: you can redistribute it and/or modify
16 // it under the terms of the GNU General Public License as published by
17 // the Free Software Foundation, either version 3 of the License, or
18 // (at your option) any later version.
19 //
20 // mxlib is distributed in the hope that it will be useful,
21 // but WITHOUT ANY WARRANTY; without even the implied warranty of
22 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 // GNU General Public License for more details.
24 //
25 // You should have received a copy of the GNU General Public License
26 // along with mxlib. If not, see <http://www.gnu.org/licenses/>.
27 //***********************************************************************//
28 
29 #ifndef mx_AO_sim_turbLayer_hpp
30 #define mx_AO_sim_turbLayer_hpp
31 
32 #include <vector>
33 
34 #include <Eigen/Dense>
35 
36 #include "../../improc/imageTransforms.hpp"
37 
38 namespace mx
39 {
40 namespace AO
41 {
42 namespace sim
43 {
44 
45 template<typename _aoSystemT>
46 struct turbAtmosphere;
47 
48 ///Simulation of a single turbulent layer
49 /** \todo document this
50  * \todo add facility for changing interpolator
51  *
52  * \ingroup mxAOSim
53  */
54 template<typename _aoSystemT>
55 struct turbLayer
56 {
57  typedef _aoSystemT aoSystemT;
58  typedef typename aoSystemT::realT realT;
59  typedef Eigen::Array<realT, -1, -1> imageT;
60 
61  turbAtmosphere<aoSystemT> * m_parent {nullptr};
62 
63  uint32_t m_layerNo;
64 
65  uint32_t m_scrnSz;
66 
67  imageT m_freq;
68  imageT m_psd;
69 
70  realT m_dx {0};
71  realT m_dy {0};
72 
73  realT m_x0;
74  realT m_y0;
75 
76  int m_last_wdx;
77  int m_last_wdy;
78 
79  imageT m_phase;
80  imageT m_shiftPhaseWP;
81  imageT m_shiftPhase;
82  imageT m_shiftPhaseWork;
83 
84  mx::math::uniDistT<realT> uniVar; ///< Uniform deviate, used in shiftRandom.
85 
86  void setLayer( turbAtmosphere<aoSystemT> * parent,
87  int layerNo,
88  uint32_t scrnSz
89  );
90 
91  uint32_t layerNo();
92 
93  uint32_t scrnSz();
94 
95  void alloc();
96 
97  /// Deallocate memory necessary for phase screen generation.
98  void genDealloc();
99 
100  ///Shift to a timestep.
101  /**
102  * \param [in] dt is the new timestep.
103  */
104  void shift( realT dt );
105 
106  ///Seed the uniform deviation. Call this if you intend to use shiftRandom.
107  /** This only needs to be called once.
108  */
109  void initRandom();
110 
111  ///Shift by a random amount using the uniform distribution
112  /** Call initRandom() once before calling this method.
113  *
114  * \param [in] nofract if true then the fractional part is ignored, and only a whole-pixel shift is executed. Default=false
115  */
116  void shiftRandom( bool nofract=false );
117 
118 
119 };
120 
121 // template<typename aoSystemT>
122 // turbLayer<aoSystemT>::turbLayer()
123 // {
124 // }
125 
126 template<typename aoSystemT>
128  int layerNo,
129  uint32_t scrnSz
130  )
131 {
132  m_parent = parent;
133  m_layerNo = layerNo;
134 
135  m_scrnSz = scrnSz;
136 
137  if(m_parent == nullptr)
138  {
139  mxThrowException(err::paramnotset, "mx::AO::sim::turbLayer::setLayer", "parent is not set (m_parent is nullptr)");
140  }
141 
142  if(m_parent->aosys() == nullptr)
143  {
144  mxThrowException(err::paramnotset, "mx::AO::sim::turbLayer::setLayer", "parent ao system is not set (m_parent->aosys() is nullptr)");
145  }
146 
147  realT vwind = m_parent->aosys()->atm.layer_v_wind(m_layerNo);
148  realT dwind = m_parent->aosys()->atm.layer_dir(m_layerNo);
149  realT pupD = m_parent->aosys()->D();
150  uint32_t wfSz = m_parent->wfSz();
151 
152  m_dx = vwind*cos(dwind)/(pupD/wfSz);
153  m_dy = vwind*sin(dwind)/(pupD/wfSz);
154 
155  alloc();
156 }
157 
158 template<typename aoSystemT>
159 uint32_t turbLayer<aoSystemT>::layerNo()
160 {
161  return m_layerNo;
162 }
163 
164 template<typename aoSystemT>
165 uint32_t turbLayer<aoSystemT>::scrnSz()
166 {
167  return m_scrnSz;
168 }
169 
170 template<typename aoSystemT>
171 void turbLayer<aoSystemT>::alloc()
172 {
173  if(m_parent == nullptr)
174  {
175  mxThrowException(err::paramnotset, "mx::AO::sim::turbLayer::alloc", "parent is not set (m_parent is nullptr)");
176  }
177 
178  if(m_parent->aosys() == nullptr)
179  {
180  mxThrowException(err::paramnotset, "mx::AO::sim::turbLayer::alloc", "parent ao system is not set (m_parent->aosys() is nullptr)");
181  }
182 
183  m_phase.resize(m_scrnSz, m_scrnSz);
184 
185  uint32_t wfSz = m_parent->wfSz();
186 
187  uint32_t buffSz = m_parent->buffSz();
188 
189  m_shiftPhaseWP.resize( wfSz+2*buffSz, wfSz+2*buffSz);
190 
191  m_shiftPhase.resize( wfSz+2*buffSz, wfSz+2*buffSz);
192 
193  m_shiftPhaseWork.resize( wfSz+2*buffSz, wfSz+2*buffSz);
194 
195  initRandom();
196 
197  m_x0 = 0;
198  m_y0 = 0;
199  m_last_wdx = m_scrnSz + 1;
200  m_last_wdy = m_scrnSz + 1;
201 
202  //Now set up for generation
203  realT r0 = m_parent->aosys()->atm.r_0(m_parent->aosys()->lam_sci());
204  realT L0 = m_parent->aosys()->atm.L_0(m_layerNo);
205  realT l0 = m_parent->aosys()->atm.l_0(m_layerNo);
206 
207  m_psd.resize(m_scrnSz, m_scrnSz);
208 
209  m_freq.resize(m_scrnSz, m_scrnSz);
210  sigproc::frequencyGrid<imageT>(m_freq, m_parent->aosys()->D()/wfSz);
211 
212  realT beta = 0.0218/pow( r0, 5./3.);
213  realT sqrt_alpha = 0.5*11./3.;
214 
215  realT L02;
216  if(L0 > 0) L02 = 1.0/(L0*L0);
217  else L02 = 0;
218 
219  #pragma omp parallel for
220  for(size_t jj =0; jj < m_scrnSz; ++jj)
221  {
222  for(size_t ii=0; ii < m_scrnSz; ++ii)
223  {
224  realT p;
225  if(m_freq(ii,jj) == 0 && L02 == 0)
226  {
227  p = 0;
228  }
229  else
230  {
231  p = beta / pow( pow(m_freq(ii,jj),2) + L02, sqrt_alpha);
232  if(l0 > 0 ) p *= exp(-1*pow( m_freq(ii,jj)*l0, 2));
233  }
234 
235  realT Ppiston = 0;
236  realT Ptiptilt = 0;
237  if(m_parent->aosys()->psd.subPiston())
238  {
239  Ppiston = pow(2*math::func::jinc(math::pi<realT>() * m_freq(ii,jj) * m_parent->aosys()->D()), 2);
240  }
241  if(m_parent->aosys()->psd.subTipTilt())
242  {
243  Ptiptilt = pow(4*math::func::jincN(2,math::pi<realT>() * m_freq(ii,jj) * m_parent->aosys()->D()), 2);
244  }
245 
246  m_psd(ii,jj) = sqrt(p*(1.0-Ppiston-Ptiptilt));
247 
248  }
249  }
250 
251  if(m_parent->shLevel() > 0)
252  {
253  m_psd(0,0) = 0;
254  m_psd(0,1) *= 0.5*0.5;
255  m_psd(1,0) *= 0.5*0.5;
256  m_psd(m_psd.rows()-1, 0) *= 0.5*0.5;
257  m_psd(0, m_psd.cols()-1) *= 0.5*0.5;
258 
259  m_psd(1,1) *= 0.75*0.75;
260  m_psd(m_psd.rows()-1, m_psd.cols()-1) *= 0.75*0.75;
261  m_psd(m_psd.rows()-1, 1) *= 0.75*0.75;
262  m_psd(1, m_psd.cols()-1) *= 0.75*0.75;
263  }
264 }
265 
266 template<typename aoSystemT>
268 {
269  m_freq.resize(0,0);
270  m_psd.resize(0,0);
271 }
272 
273 template<typename aoSystemT>
275 {
276  int wdx, wdy;
277  realT ddx, ddy;
278 
279  ddx = m_x0 + m_dx*dt;
280  ddy = m_y0 + m_dy*dt;
281 
282  wdx = (int) trunc(ddx);
283  ddx -= wdx;
284 
285  wdy = (int) trunc(ddy);
286  ddy -= wdy;
287 
288  wdx %= m_scrnSz;
289  wdy %= m_scrnSz;
290 
291  //Check for a new whole-pixel shift
292  if(wdx != m_last_wdx || wdy != m_last_wdy)
293  {
294  //Need a whole pixel shift (this also extracts the m_wfSz + m_buffSz subarray)
295  improc::imageShiftWP(m_shiftPhaseWP, m_phase, wdx, wdy);
296  }
297 
298  //Do the sub-pixel shift
299  improc::imageShift( m_shiftPhase, m_shiftPhaseWP, ddx, ddy, improc::cubicConvolTransform<realT>(-0.5));
300 
301  m_last_wdx = wdx;
302  m_last_wdy = wdy;
303 }
304 
305 template<typename aoSystemT>
307 {
308  uniVar.seed();
309 }
310 
311 template<typename aoSystemT>
313 {
314  int wdx, wdy;
315  realT ddx, ddy;
316 
317  ddx = uniVar * (m_scrnSz);
318  ddy = uniVar * (m_scrnSz);
319 
320  wdx = (int) trunc(ddx);
321  ddx -= wdx;
322  wdy = (int) trunc(ddy);
323  ddy -= wdy;
324 
325  if(nofract)
326  {
327  ddx=0;
328  ddy=0;
329  }
330 
331  improc::imageShiftWP(m_shiftPhaseWP, m_phase, wdx, wdy);
332 
333  if(ddx !=0 || ddy != 0)
334  {
335  improc::imageShift( m_shiftPhase, m_shiftPhaseWP, ddx, ddy, improc::cubicConvolTransform<realT>(-0.5));
336  }
337  else
338  {
339  m_shiftPhase = m_shiftPhaseWP;
340  }
341 }
342 
343 } //namespace sim
344 } //namespace AO
345 } //namespace mx
346 
347 #endif //mx_AO_sim_turbLayer_hpp
mxException for parameters which aren't set
A random number type, which functions like any other arithmetic type.
Definition: randomT.hpp:61
T2 jincN(const T1 &v, const T2 &x)
The JincN function.
Definition: jinc.hpp:120
T jinc(const T &x)
The Jinc function.
Definition: jinc.hpp:64
void imageShift(arrOutT &transim, const arrInT &im, floatT1 dx, floatT2 dy, transformT trans)
Shift an image.
void imageShiftWP(outputArrT &out, inputArrT &in, int dx, int dy, bool wrap=true)
Shift an image by whole pixels with (optional) wrapping.
The mxlib c++ namespace.
Definition: mxError.hpp:107
Simulation of a single turbulent layer.
Definition: turbLayer.hpp:56
void genDealloc()
Deallocate memory necessary for phase screen generation.
Definition: turbLayer.hpp:267
void initRandom()
Seed the uniform deviation. Call this if you intend to use shiftRandom.
Definition: turbLayer.hpp:306
mx::math::uniDistT< realT > uniVar
Uniform deviate, used in shiftRandom.
Definition: turbLayer.hpp:84
void shift(realT dt)
Shift to a timestep.
Definition: turbLayer.hpp:274
void shiftRandom(bool nofract=false)
Shift by a random amount using the uniform distribution.
Definition: turbLayer.hpp:312
Transformation by cubic convolution interpolation.