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