mxlib
c++ tools for analyzing astronomical data and other tasks by Jared R. Males. [git repo]
Loading...
Searching...
No Matches
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
38namespace mx
39{
40namespace AO
41{
42namespace sim
43{
44
45template <typename _aoSystemT, class _verboseT>
46struct 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 */
54template <typename _aoSystemT, class _verboseT = mx::verbose::d>
56{
57 typedef _aoSystemT aoSystemT;
58 typedef _verboseT verboseT;
59
60 typedef typename aoSystemT::realT realT;
61 typedef Eigen::Array<realT, -1, -1> imageT;
62
63 turbAtmosphere<aoSystemT, verboseT> *m_parent{ nullptr };
64
65 uint32_t m_layerNo;
66
67 uint32_t m_scrnSz;
68
69 imageT m_freq;
70 imageT m_psd;
71
72 realT m_dx{ 0 };
73 realT m_dy{ 0 };
74
75 realT m_x0;
76 realT m_y0;
77
78 int m_last_wdx;
79 int m_last_wdy;
80
81 imageT m_phase;
82 imageT m_shiftPhaseWP;
83 imageT m_shiftPhase;
84 imageT m_shiftPhaseWork;
85
86 mx::math::uniDistT<realT> uniVar; ///< Uniform deviate, used in shiftRandom.
87
88 void setLayer( turbAtmosphere<aoSystemT, verboseT> *parent, int layerNo, uint32_t scrnSz );
89
90 uint32_t layerNo();
91
92 uint32_t scrnSz();
93
94 void alloc();
95
96 /// Deallocate memory necessary for phase screen generation.
97 void genDealloc();
98
99 /// Shift to a timestep.
100 /**
101 * \param [in] dt is the new timestep.
102 */
103 void shift( realT dt );
104
105 /// Seed the uniform deviation. Call this if you intend to use shiftRandom.
106 /** This only needs to be called once.
107 */
108 void initRandom();
109
110 /// Shift by a random amount using the uniform distribution
111 /** Call initRandom() once before calling this method.
112 *
113 * \param [in] nofract if true then the fractional part is ignored, and only a whole-pixel shift is executed.
114 * Default=false
115 */
116 void shiftRandom( bool nofract = false );
117};
118
119// template<typename aoSystemT>
120// turbLayer<aoSystemT, verboseT>::turbLayer()
121// {
122// }
123
124template <typename aoSystemT, class verboseT>
126 int layerNo,
127 uint32_t scrnSz )
128{
129 m_parent = parent;
130 m_layerNo = layerNo;
131
132 m_scrnSz = scrnSz;
133
134 if( m_parent == nullptr )
135 {
136 throw mx::exception<verboseT>( error_t::paramnotset, "parent is not set (m_parent is nullptr)" );
137 }
138
139 if( m_parent->aosys() == nullptr )
140 {
141 throw mx::exception<verboseT>( error_t::paramnotset, "parent is not set (m_parent->aosys() is nullptr)" );
142 }
143
144 realT vwind = m_parent->aosys()->atm.layer_v_wind( m_layerNo );
145 realT dwind = m_parent->aosys()->atm.layer_dir( m_layerNo );
146 realT pupD = m_parent->aosys()->D();
147 uint32_t wfSz = m_parent->wfSz();
148
149 m_dx = vwind * cos( dwind ) / ( pupD / wfSz );
150 m_dy = vwind * sin( dwind ) / ( pupD / wfSz );
151
152 alloc();
153}
154
155template <typename aoSystemT, class verboseT>
156uint32_t turbLayer<aoSystemT, verboseT>::layerNo()
157{
158 return m_layerNo;
159}
160
161template <typename aoSystemT, class verboseT>
162uint32_t turbLayer<aoSystemT, verboseT>::scrnSz()
163{
164 return m_scrnSz;
165}
166
167template <typename aoSystemT, class verboseT>
168void turbLayer<aoSystemT, verboseT>::alloc()
169{
170 if( m_parent == nullptr )
171 {
172 throw mx::exception<verboseT>( error_t::paramnotset, "parent is not set (m_parent is nullptr)" );
173 }
174
175 if( m_parent->aosys() == nullptr )
176 {
177 throw mx::exception<verboseT>( error_t::paramnotset, "parent is not set (m_parent->aosys() is nullptr)" );
178 }
179
180 m_phase.resize( m_scrnSz, m_scrnSz );
181
182 uint32_t wfSz = m_parent->wfSz();
183
184 uint32_t buffSz = m_parent->buffSz();
185
186 m_shiftPhaseWP.resize( wfSz + 2 * buffSz, wfSz + 2 * buffSz );
187
188 m_shiftPhase.resize( wfSz + 2 * buffSz, wfSz + 2 * buffSz );
189
190 m_shiftPhaseWork.resize( wfSz + 2 * buffSz, wfSz + 2 * buffSz );
191
192 initRandom();
193
194 m_x0 = 0;
195 m_y0 = 0;
196 m_last_wdx = m_scrnSz + 1;
197 m_last_wdy = m_scrnSz + 1;
198
199 // Now set up for generation
200 realT r0 = m_parent->aosys()->atm.r_0( m_parent->aosys()->lam_sci() );
201 realT L0 = m_parent->aosys()->atm.L_0( m_layerNo );
202 realT l0 = m_parent->aosys()->atm.l_0( m_layerNo );
203
204 m_psd.resize( m_scrnSz, m_scrnSz );
205
206 m_freq.resize( m_scrnSz, m_scrnSz );
207 sigproc::frequencyGrid<imageT>( m_freq, m_parent->aosys()->D() / wfSz );
208
209 realT beta = 0.0218 / pow( r0, 5. / 3. );
210 realT sqrt_alpha = 0.5 * 11. / 3.;
211
212 realT L02;
213 if( L0 > 0 )
214 {
215 L02 = 1.0 / ( L0 * L0 );
216 }
217 else
218 {
219 L02 = 0;
220 }
221
222 // clang-format off
223 #pragma omp parallel for // clang-format on
224 for( size_t jj = 0; jj < m_scrnSz; ++jj )
225 {
226 for( size_t ii = 0; ii < m_scrnSz; ++ii )
227 {
228 realT p;
229 if( m_freq( ii, jj ) == 0 && L02 == 0 )
230 {
231 p = 0;
232 }
233 else
234 {
235 p = beta / pow( pow( m_freq( ii, jj ), 2 ) + L02, sqrt_alpha );
236 if( l0 > 0 )
237 {
238 p *= exp( -1 * pow( m_freq( ii, jj ) * l0, 2 ) );
239 }
240 }
241
242 realT Ppiston = 0;
243 realT Ptiptilt = 0;
244 if( m_parent->aosys()->psd.subPiston() )
245 {
246 Ppiston =
247 pow( 2 * math::func::jinc( math::pi<realT>() * m_freq( ii, jj ) * m_parent->aosys()->D() ), 2 );
248 }
249 if( m_parent->aosys()->psd.subTipTilt() )
250 {
251 Ptiptilt =
252 pow( 4 * math::func::jincN( 2, math::pi<realT>() * m_freq( ii, jj ) * m_parent->aosys()->D() ), 2 );
253 }
254
255 m_psd( ii, jj ) = sqrt( p * ( 1.0 - Ppiston - Ptiptilt ) );
256 }
257 }
258
259 if( m_parent->shLevel() > 0 )
260 {
261 realT onoff = 1;
262 if( m_parent->outerSubHarmonics() )
263 {
264 onoff = 0; // just make all of these 0
265 }
266
267 m_psd( 0, 0 ) = 0;
268 m_psd( 0, 1 ) *= 0.5 * 0.5 * onoff;
269 m_psd( 1, 0 ) *= 0.5 * 0.5 * onoff;
270 m_psd( m_psd.rows() - 1, 0 ) *= 0.5 * 0.5 * onoff;
271 m_psd( 0, m_psd.cols() - 1 ) *= 0.5 * 0.5 * onoff;
272
273 m_psd( 1, 1 ) *= 0.75 * 0.75 * onoff;
274 m_psd( m_psd.rows() - 1, m_psd.cols() - 1 ) *= 0.75 * 0.75 * onoff;
275 m_psd( m_psd.rows() - 1, 1 ) *= 0.75 * 0.75 * onoff;
276 m_psd( 1, m_psd.cols() - 1 ) *= 0.75 * 0.75 * onoff;
277 }
278}
279
280template <typename aoSystemT, class verboseT>
282{
283 m_freq.resize( 0, 0 );
284 m_psd.resize( 0, 0 );
285}
286
287template <typename aoSystemT, class verboseT>
289{
290 int wdx, wdy;
291 realT ddx, ddy;
292
293 ddx = m_x0 + m_dx * dt;
294 ddy = m_y0 + m_dy * dt;
295
296 wdx = (int)trunc( ddx );
297 ddx -= wdx;
298
299 wdy = (int)trunc( ddy );
300 ddy -= wdy;
301
302 wdx %= m_scrnSz;
303 wdy %= m_scrnSz;
304
305 if( dt == 0 )
306 {
307 m_shiftPhase = m_phase;
308 }
309 else
310 {
311 // Check for a new whole-pixel shift
312 if( wdx != m_last_wdx || wdy != m_last_wdy )
313 {
314 // Need a whole pixel shift (this also extracts the m_wfSz + m_buffSz subarray)
315 improc::imageShiftWP( m_shiftPhaseWP, m_phase, wdx, wdy );
316 }
317
318 // Do the sub-pixel shift
319 improc::imageShift( m_shiftPhase, m_shiftPhaseWP, ddx, ddy, improc::cubicConvolTransform<realT>( -0.5 ) );
320 }
321
322 m_last_wdx = wdx;
323 m_last_wdy = wdy;
324}
325
326template <typename aoSystemT, class verboseT>
328{
329 uniVar.seed();
330}
331
332template <typename aoSystemT, class verboseT>
334{
335 int wdx, wdy;
336 realT ddx, ddy;
337
338 ddx = uniVar * ( m_scrnSz );
339 ddy = uniVar * ( m_scrnSz );
340
341 wdx = (int)trunc( ddx );
342 ddx -= wdx;
343 wdy = (int)trunc( ddy );
344 ddy -= wdy;
345
346 if( nofract )
347 {
348 ddx = 0;
349 ddy = 0;
350 }
351
352 improc::imageShiftWP( m_shiftPhaseWP, m_phase, wdx, wdy );
353
354 if( ddx != 0 || ddy != 0 )
355 {
356 improc::imageShift( m_shiftPhase, m_shiftPhaseWP, ddx, ddy, improc::cubicConvolTransform<realT>( -0.5 ) );
357 }
358 else
359 {
360 m_shiftPhase = m_shiftPhaseWP;
361 }
362}
363
364} // namespace sim
365} // namespace AO
366} // namespace mx
367
368#endif // mx_AO_sim_turbLayer_hpp
Augments an exception with the source file and line.
Definition exception.hpp:42
A random number type, which functions like any other arithmetic type.
Definition randomT.hpp:64
@ paramnotset
A parameter was not set.
T2 jincN(const T1 &v, const T2 &x)
The JincN function.
Definition jinc.hpp:112
T jinc(const T &x)
The Jinc function.
Definition jinc.hpp:61
constexpr floatT six_fifths()
Return 6/5 in the specified precision.
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 mxlib.hpp:37
A turbulent atmosphere simulator.
Simulation of a single turbulent layer.
Definition turbLayer.hpp:56
void genDealloc()
Deallocate memory necessary for phase screen generation.
mx::math::uniDistT< realT > uniVar
Uniform deviate, used in shiftRandom.
Definition turbLayer.hpp:86
void shift(realT dt)
Shift to a timestep.
void shiftRandom(bool nofract=false)
Shift by a random amount using the uniform distribution.
void initRandom()
Seed the uniform deviation. Call this if you intend to use shiftRandom.
Transformation by cubic convolution interpolation.