237 if( m_turbAtmo ==
nullptr )
240 "mx::AO::sim::turbSubHarmonic::initGrid",
241 "atmosphere is not set (m_turbAtmo is nullptr)" );
244 if( m_turbAtmo->aosys() ==
nullptr )
247 "mx::AO::sim::turbSubHarmonic::initGrid",
248 "ao system is not set (m_turbAtmo->m_aosys is nullptr)" );
251 if( m_turbAtmo->nLayers() <= layerNo )
254 "mx::AO::sim::turbSubHarmonic::initGrid",
255 "atmosphere is not setup (m_turbAtmo->m_layers size is <= layerNo)" );
264 N = 36.0 + 32.0 * ( m_level - 1 );
266 if( m_outerSubHarmonics )
274 m_sqrtPSD.resize( N );
277 m_scrnSz = m_turbAtmo->layer( layerNo ).scrnSz();
283 this->setChangePoint();
287 realT r0 = m_turbAtmo->aosys()->atm.r_0( m_turbAtmo->aosys()->lam_sci() );
288 realT D = m_turbAtmo->aosys()->D();
289 uint32_t wfSz = m_turbAtmo->wfSz();
291 realT beta = 0.0218 / pow( r0, 5. / 3. ) / pow( ( D / wfSz ) * m_scrnSz, 2 );
293 realT sqrt_alpha = 0.5 * 11. / 3.;
295 realT L0 = m_turbAtmo->aosys()->atm.L_0( layerNo );
299 L02 = 1.0 / pow( L0, 2 );
305 m_modes.resize( m_scrnSz, m_scrnSz, N );
308 std::vector<realT> scs;
310 if( m_outerSubHarmonics )
314 m_m = std::vector<realT>( { -1.25, -0.75, -0.25, 0.25, 0.75, 1.25, -1.25, 1.25, -1.25, 1.25,
315 -1.25, 1.25, -1.25, 1.25, -1.25, -0.75, -0.25, 0.25, 0.75, 1.25 } );
316 m_n = std::vector<realT>( { -1.25, -1.25, -1.25, -1.25, -1.25, -1.25, -0.75, -0.75, -0.25, -0.25,
317 0.25, 0.25, 0.75, 0.75, 1.25, 1.25, 1.25, 1.25, 1.25, 1.25 } );
318 scs.resize( m_m.size(), sc );
321 for(
int nl = 1; nl <= m_level; ++nl )
323 realT sc = pow( 3.0, -nl );
325 for(
int mp = -3; mp < 3; ++mp )
327 for(
int np = -3; np < 3; ++np )
333 if( np == -1 || np == 0 )
338 if( np == -1 || np == 0 )
343 m_m.push_back( sc * ( mp + 0.5 ) );
344 m_n.push_back( sc * ( np + 0.5 ) );
351 for(
int n = 0; n < m_m.size(); ++n )
353 realT k = sqrt( ( pow( m_m[n], 2 ) + pow( m_n[n], 2 ) ) ) / ( ( D / wfSz ) * m_scrnSz );
355 realT tpsd = beta / pow( k * k + L02, sqrt_alpha );
359 if( m_turbAtmo->aosys()->psd.subPiston() )
364 if( m_turbAtmo->aosys()->psd.subTipTilt() )
369 m_sqrtPSD[n] = scs[n] * sqrt( tpsd * ( 1 - Ppiston - Ptiptilt ) );
373 for(
int cc = 0; cc < m_scrnSz; ++cc )
375 realT np = cc - 0.5 * m_scrnSz;
376 for(
int rr = 0; rr < m_scrnSz; ++rr )
378 realT mp = rr - 0.5 * m_scrnSz;
379 m_modes.image( n )( rr, cc ) =
386 this->setChangePoint();
397 if( m_turbAtmo ==
nullptr )
400 err::paramnotset,
"mx::AO::sim::turbSubHarmonic::screen",
"atmosphere is not set (m_turbAtmo is nullptr)" );
403 if( this->isChanged() )
406 "mx::AO::sim::turbSubHarmonic::screen",
407 "configuration has changed but not re-initialized" );
410 if( scrn.rows() != m_scrnSz || scrn.cols() != m_scrnSz )
412 mxThrowException(
err::sizeerr,
"mx::AO::sim::turbSubHarmonic::screen",
"input screen is not the right size" );
418 if( m_modes.rows() != scrn.rows() || m_modes.cols() != scrn.cols() || m_modes.planes() != m_noise.size() )
421 err::sizeerr,
"mx::AO::sim::turbSubHarmonic::screen",
"modes cube wrong size, call initGrid()." );
426 if( m_noise.size() != m_m.size() || m_noise.size() != m_n.size() || m_sqrtPSD.size() != m_noise.size() )
429 err::sizeerr,
"mx::AO::sim::turbSubHarmonic::screen",
"vectors not allocated, call initGrid()." );
434 for(
size_t n = 0; n < m_noise.size(); ++n )
436 m_noise[n] = 2 * m_turbAtmo->normVar();
439#pragma omp parallel for
440 for(
int cc = 0; cc < m_scrnSz; ++cc )
442 realT np = cc - 0.5 * m_scrnSz;
443 for(
int rr = 0; rr < m_scrnSz; ++rr )
445 realT mp = rr - 0.5 * m_scrnSz;
449 for(
unsigned n = 0; n < m_noise.size(); ++n )
451 scrn( rr, cc ) += m_noise[n] * m_modes.image( n )( rr, cc );
456 for(
unsigned n = 0; n < m_m.size(); ++n )
458 scrn( rr, cc ) += m_noise[n] * m_sqrtPSD[n] *