27#ifndef fourierTemporalPSD_hpp
28#define fourierTemporalPSD_hpp
42#include <gsl/gsl_integration.h>
43#include <gsl/gsl_errno.h>
48#include "../../math/constants.hpp"
103template <
typename realT>
130 realT absoluteTolerance,
131 realT relativeTolerance );
140 void write( std::ostream &output )
const;
144namespace fourierTemporalPSD_detail
148using gslWorkspaceAllocator = gsl_integration_workspace *(*)(
size_t );
151struct gslWorkspaceDeleter
154 void operator()( gsl_integration_workspace *workspace )
const noexcept
156 if( workspace !=
nullptr )
158 gsl_integration_workspace_free( workspace );
164using gslWorkspacePtr = std::unique_ptr<gsl_integration_workspace, gslWorkspaceDeleter>;
167inline bool isConvergenceStatus(
int status )
169 return status == GSL_EMAXITER || status == GSL_EROUND || status == GSL_ESING || status == GSL_EDIVERGE;
173inline error_t gslStatusToError(
int status )
175 if( status == GSL_ENOMEM )
177 return error_t::allocerr;
180 if( status == GSL_EDOM || status == GSL_EINVAL )
182 return error_t::invalidconfig;
185 return error_t::liberr;
189inline error_t applyPolicy(
int status, fourierTemporalPSDPolicy policy )
191 if( status == GSL_SUCCESS )
193 return error_t::noerror;
196 if( isConvergenceStatus( status ) )
198 return policy == fourierTemporalPSDPolicy::permissive ? error_t::noerror : error_t::liberr;
201 return gslStatusToError( status );
205inline std::mutex &gslErrorHandlerMutex()
207 static std::mutex mutex;
215class scopedGslErrorHandlerOff
219 scopedGslErrorHandlerOff() : m_lock( gslErrorHandlerMutex() ), m_previous( gsl_set_error_handler_off() )
224 scopedGslErrorHandlerOff(
const scopedGslErrorHandlerOff & ) =
delete;
227 scopedGslErrorHandlerOff &operator=(
const scopedGslErrorHandlerOff & ) =
delete;
230 ~scopedGslErrorHandlerOff()
232 static_cast<void>( gsl_set_error_handler( m_previous ) );
236 std::unique_lock<std::mutex> m_lock;
237 gsl_error_handler_t *m_previous{
nullptr };
243template <
typename realT>
251template <
typename realT>
257 realT absoluteTolerance,
258 realT relativeTolerance )
261 if( status == GSL_SUCCESS )
272 const realT requestedTolerance = std::max( std::abs( absoluteTolerance ), std::abs( relativeTolerance * result ) );
273 const realT toleranceRatio = requestedTolerance > 0 ? std::abs( absoluteError ) / requestedTolerance
274 : std::numeric_limits<realT>::infinity();
283template <
typename realT>
289 for(
const auto &[status, otherSummary] : other.
gslStatus )
292 summary.
count += otherSummary.count;
293 for(
const auto &[layer, count] : otherSummary.countByLayer )
307template <
typename realT>
313template <
typename realT>
317 for(
const auto &[status, summary] :
gslStatus )
319 output <<
" " << gsl_strerror( status ) <<
" (" << status <<
"): " << summary.count <<
", max absolute error "
320 << summary.maximumAbsoluteError <<
", max tolerance ratio " << summary.maximumToleranceRatio
321 <<
" at layer " << summary.worstLayer <<
", frequency " << summary.worstFrequency <<
", layers {";
322 bool firstLayer =
true;
323 for(
const auto &[layer, count] : summary.countByLayer )
329 output << layer <<
": " << count;
337template <
typename realT,
typename aosysT>
338realT
F_basic( realT kv,
void *params );
341template <
typename realT,
typename aosysT>
342realT
F_mod( realT kv,
void *params );
354template <
typename _realT,
typename aosysT>
376 bool m_strehlOG{
false };
377 bool m_uncorrectedOG{
false };
404 std::vector<realT> Jps;
405 std::vector<realT> Jms;
407 std::vector<realT> ms;
408 std::vector<realT> ns;
410 void initProjection()
450 fourierTemporalPSD_detail::gslWorkspaceAllocator allocator );
460 const std::vector<
realT> &freq,
520 std::vector<
realT> &freq,
547 std::vector<
realT> &PSD,
548 std::vector<
realT> &freq,
562 template <
bool m_parallel>
568 error_t multiLayerPSDImpl( std::vector<realT> &PSD,
569 std::vector<realT> &freq,
576 isParallel<true> parallel );
579 error_t multiLayerPSDImpl( std::vector<realT> &PSD,
580 std::vector<realT> &freq,
587 isParallel<false> parallel );
606 template <
bool parallel = true>
608 std::vector<realT> &PSD,
609 std::vector<realT> &freq,
647 const std::string &psdDir,
653 realT lpRegPrecision,
656 std::vector<realT> &mags,
657 int lifetimeTrials = 0,
659 bool ucLifeTs =
false,
661 bool writePSDs =
false,
662 bool writeXfer =
false
668 const std::string &psdDir,
669 const std::string &CvdPath,
672 std::vector<realT> &mags,
693 const std::string &dir
700 const std::string &dir,
709 std::vector<realT> &psd,
710 const std::string &dir,
718template <
typename realT,
typename aosysT>
725template <
typename realT,
typename aosysT>
733template <
typename realT,
typename aosysT>
755template <
typename realT,
typename aosysT>
764template <
typename realT,
typename aosysT>
775 "AO system aperture diameter must be finite and positive" );
778 auto &atmosphere =
m_aosys->atm;
779 const error_t atmosphereStatus = atmosphere.validate();
782 return atmosphereStatus;
785 const size_t layerCount = atmosphere.n_layers();
786 for(
size_t index = 0; index < layerCount; ++index )
788 if( atmosphere.layer_v_wind(
static_cast<int>( index ) ) <= 0 )
791 "Fourier temporal PSD layers require positive wind speed" );
795 if( layer_i < -1 || ( layer_i >= 0 &&
static_cast<size_t>( layer_i ) >= layerCount ) )
803template <
typename realT,
typename aosysT>
805 const std::vector<realT> &freq,
813 if( freq.empty() || PSD.size() != freq.size() )
816 "PSD and frequency vectors must have the same nonzero size" );
819 for(
size_t index = 0; index < freq.size(); ++index )
821 if( !
math::isFinite( freq[index] ) || freq[index] < 0 || ( index > 0 && freq[index] <= freq[index - 1] ) )
825 "frequency grid must be finite, nonnegative, and strictly increasing" );
833 "mode coordinates must be finite and frequency cutoff must be finite and nonnegative" );
836 if( p != -1 && p != 1 )
855 "GSL absolute tolerance must be positive and relative tolerance must be between zero and one" );
861 "turbulence boiling parameter must be finite and nonnegative" );
867 return atmosphereStatus;
878 "AO wavelengths must be positive and zenith angle must lie strictly between -pi/2 and pi/2" );
886 "AO spatial-filter limits must be finite and positive" );
892template <
typename realT,
typename aosysT>
898template <
typename realT,
typename aosysT>
904template <
typename realT,
typename aosysT>
910template <
typename realT,
typename aosysT>
916template <
typename realT,
typename aosysT>
919 realT ku, kv, vu, vv;
926 for(
size_t i = 0; i <
m_aosys->atm.n_layers(); ++i )
928 vu =
m_aosys->atm.layer_v_wind( i ) * cos(
m_aosys->atm.layer_dir( i ) );
929 vv =
m_aosys->atm.layer_v_wind( i ) * sin(
m_aosys->atm.layer_dir( i ) );
931 f = fabs( ku * vu + kv * vv );
939template <
typename realT,
typename aosysT>
941 std::vector<realT> &freq,
951 reportT &activeReport = report ==
nullptr ? localReport : *report;
952 activeReport.
clear();
960 fourierTemporalPSD_detail::scopedGslErrorHandlerOff handlerGuard;
964template <
typename realT,
typename aosysT>
966 std::vector<realT> &freq,
976 fmax = freq[freq.size() - 1];
982 "at least one exact frequency bin is required to initialize the PSD tail" );
989 realT cq = cos( q_wind );
990 realT sq = sin( q_wind );
992 realT scale = 2 * ( 1 / v_wind );
999 return workspaceStatus;
1004 params.
m_m = m * cq + n * sq;
1005 params.
m_n = -m * sq + n * cq;
1008 if(
m_aosys->spatialFilter_ku() < std::numeric_limits<realT>::max() ||
1009 m_aosys->spatialFilter_kv() < std::numeric_limits<realT>::max() )
1017 params.m_minCoeffVal = m_minCoeffVal;
1037 func.params = ¶ms;
1041 while( freq[i] <= fmax )
1043 params.
m_f = freq[i];
1048 const error_t integrationStatus = fourierTemporalPSD_detail::applyPolicy( ec, policy );
1051 if( !fourierTemporalPSD_detail::isConvergenceStatus( ec ) )
1054 std::string(
"gsl_integration_qagi failed: " ) +
1055 gsl_strerror( ec ) );
1058 returnStatus = integrationStatus;
1064 "gsl_integration_qagi returned a nonfinite result or error estimate" );
1067 PSD[i] = scale * result;
1070 if( i >= freq.size() )
1077 if( j == freq.size() )
1078 return returnStatus;
1081 constexpr size_t maximumTailAverageCount = 50;
1082 const size_t tailAverageCount = std::min( i, maximumTailAverageCount );
1084 for(
size_t k = tailAverageCount; k > 0; --k )
1087 PSD[i - k] * pow( freq[i - k] / freq[j],
m_aosys->atm.alpha( layer_i ) + 2 );
1089 PSD[j] /=
static_cast<realT>( tailAverageCount );
1092 if( j == freq.size() )
1093 return returnStatus;
1094 while( j < freq.size() )
1097 PSD[i - 1] * pow( freq[i - 1] / freq[j],
m_aosys->atm.alpha( layer_i ) + 2 );
1101 return returnStatus;
1104template <
typename realT,
typename aosysT>
1106 std::vector<realT> &freq,
1113 isParallel<true> parallel )
1115 static_cast<void>( parallel );
1117 const size_t layerCount = m_aosys->atm.n_layers();
1119 std::vector<reportT> layerReport( layerCount );
1124 std::vector<realT> single_PSD( freq.size() );
1127 for(
size_t i = 0; i < m_aosys->atm.n_layers(); ++i )
1129 std::fill( single_PSD.begin(), single_PSD.end(), 0 );
1131 singleLayerPSDImpl( single_PSD, freq, m, n,
static_cast<int>( i ), p, fmax, layerReport[i], policy );
1137 for(
size_t j = 0; j < freq.size(); ++j )
1139 PSD[j] += m_aosys->atm.layer_Cn2( i ) * single_PSD[j];
1146 for(
size_t i = 0; i < layerCount; ++i )
1148 report.merge( layerReport[i] );
1151 returnStatus = layerStatus[i];
1155 return returnStatus;
1158template <
typename realT,
typename aosysT>
1160 std::vector<realT> &freq,
1167 isParallel<false> parallel )
1169 static_cast<void>( parallel );
1172 std::vector<realT> single_PSD( freq.size() );
1175 for(
size_t i = 0; i < m_aosys->atm.n_layers(); ++i )
1177 std::fill( single_PSD.begin(), single_PSD.end(), 0 );
1178 reportT layerReport;
1180 singleLayerPSDImpl( single_PSD, freq, m, n,
static_cast<int>( i ), p, fmax, layerReport, policy );
1181 report.merge( layerReport );
1184 returnStatus = layerStatus;
1190 for(
size_t j = 0; j < freq.size(); ++j )
1192 PSD[j] += m_aosys->atm.layer_Cn2( i ) * single_PSD[j];
1197 return returnStatus;
1200template <
typename realT,
typename aosysT>
1201template <
bool parallel>
1203 std::vector<realT> &freq,
1212 reportT &activeReport = report ==
nullptr ? localReport : *report;
1213 activeReport.
clear();
1218 return validationStatus;
1222 for(
size_t j = 0; j < PSD.size(); ++j )
1230 fourierTemporalPSD_detail::scopedGslErrorHandlerOff handlerGuard;
1231 return multiLayerPSDImpl( PSD, freq, m, n, p, fmax, activeReport, policy, isParallel<parallel>() );
1234template <
typename realT,
typename aosysT>
1236 const std::string &dir,
int mnMax,
realT dFreq,
realT maxFreq,
realT fmax )
1248 "PSD grid extent and frequency controls must be finite and positive, with a nonnegative cutoff" );
1251 const realT sampleCount = maxFreq / dFreq;
1252 if( !
math::isFinite( sampleCount ) || sampleCount >
static_cast<realT>( std::numeric_limits<int>::max() ) )
1257 const std::vector<realT> validationFrequency{ 0 };
1258 const std::vector<realT> validationPsd{ 0 };
1260 validationFrequency,
1269 return validationStatus;
1272 std::vector<realT> freq;
1274 std::vector<sigproc::fourierModeDef> spf;
1281 int N = (int)( maxFreq / dFreq );
1282 if( N * dFreq < maxFreq )
1293 fn = dir +
'/' +
"params.txt";
1295 if( !fout.is_open() )
1300 fout <<
"#---------------------------\n";
1301 m_aosys->dumpAOSystem( fout );
1302 fout <<
"#---------------------------\n";
1303 fout <<
"# PSD Grid Parameters\n";
1304 fout <<
"# absTol " <<
_absTol <<
'\n';
1305 fout <<
"# relTol " <<
_relTol <<
'\n';
1306 fout <<
"# useBasis " <<
_useBasis <<
'\n';
1307 fout <<
"# makePSDGrid call:\n";
1308 fout <<
"# mnMax = " << mnMax <<
'\n';
1309 fout <<
"# dFreq = " << dFreq <<
'\n';
1310 fout <<
"# maxFreq = " << maxFreq <<
'\n';
1311 fout <<
"# fmax = " << fmax <<
'\n';
1312 fout <<
"#---------------------------\n";
1321 std::string psddir = dir +
"/psds";
1331 fn = psddir +
'/' +
"freq.binv";
1338 size_t nLoops = 0.5 * spf.size();
1345 std::vector<realT> PSD;
1352 for(
size_t i = 0; i < nLoops; ++i )
1371 fname = std::format(
"{}/psd_{}_{}.binv", psddir, m, n );
1384 for(
size_t index = 0; index < modeStatus.size(); ++index )
1388 return modeStatus[index];
1395template <
typename realT,
typename aosysT>
1397 const std::string &psdDir,
1402 realT lpRegPrecision,
1403 std::vector<realT> &mags,
1405 bool uncontrolledLifetimes,
1410 std::string dir = psdDir +
"/" + subDir;
1413 mkdir( dir.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH );
1416 std::string fn = dir +
'/' +
"params.txt";
1419 fout <<
"#---------------------------\n";
1420 m_aosys->dumpAOSystem( fout );
1421 fout <<
"#---------------------------\n";
1422 fout <<
"# Analysis Parameters\n";
1423 fout <<
"# mnMax = " << mnMax <<
'\n';
1424 fout <<
"# mnCon = " << mnCon <<
'\n';
1425 fout <<
"# lpNc = " << lpNc <<
'\n';
1426 fout <<
"# mags = ";
1427 for(
size_t i = 0; i < mags.size() - 1; ++i )
1428 fout << mags[i] <<
",";
1429 fout << mags[mags.size() - 1] <<
'\n';
1430 fout <<
"# lifetimeTrials = " << lifetimeTrials <<
'\n';
1431 fout <<
"# uncontrolledLifetimes = " << uncontrolledLifetimes <<
'\n';
1432 fout <<
"# writePSDs = " << std::boolalpha << writePSDs <<
'\n';
1433 fout <<
"# writeXfer = " << std::boolalpha << writeXfer <<
'\n';
1443 std::vector<sigproc::fourierModeDef> fms;
1446 size_t nModes = 0.5 * fms.size();
1448 Eigen::Array<
realT, -1, -1> gains, vars, speckleLifetimes, gains_lp, vars_lp, speckleLifetimes_lp;
1450 gains.resize( 2 * mnMax + 1, 2 * mnMax + 1 );
1451 vars.resize( 2 * mnMax + 1, 2 * mnMax + 1 );
1452 speckleLifetimes.resize( 2 * mnMax + 1, 2 * mnMax + 1 );
1454 gains( mnMax, mnMax ) = 0;
1455 vars( mnMax, mnMax ) = 0;
1456 speckleLifetimes( mnMax, mnMax ) = 0;
1458 gains_lp.resize( 2 * mnMax + 1, 2 * mnMax + 1 );
1459 vars_lp.resize( 2 * mnMax + 1, 2 * mnMax + 1 );
1460 speckleLifetimes_lp.resize( 2 * mnMax + 1, 2 * mnMax + 1 );
1462 gains_lp( mnMax, mnMax ) = 0;
1463 vars_lp( mnMax, mnMax ) = 0;
1464 speckleLifetimes_lp( mnMax, mnMax ) = 0;
1469 Eigen::Array<
realT, -1, -1> lpC;
1473 lpC.resize( nModes, lpNc );
1477 std::vector<realT> S_si, S_lp;
1481 for(
size_t s = 0; s < mags.size(); ++s )
1483 std::string psdOutDir = std::format(
"{}/outputPSDS_{}_si", dir, mags[s] );
1485 mkdir( psdOutDir.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH );
1489 std::string psdOutDir = std::format(
"{}/outputPSDS_{}_lp", dir, mags[s] );
1491 mkdir( psdOutDir.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH );
1501 for(
size_t s = 0; s < mags.size(); ++s )
1507 realT opticalGain{ 1.0 };
1520 std::cerr << S <<
"\n";
1522 for(
int s = 0; s < 4; ++s )
1527 std::cerr << S <<
"\n";
1541 realT localMag = mags[s];
1547 realT gopt_lp, var_lp;
1549 std::vector<realT> tfreq;
1550 std::vector<realT> tPSDp;
1554 std::vector<realT> tfreqHF;
1555 std::vector<realT> tPSDpHF;
1562 while( tfreq[imax] <= 0.5 * fs )
1565 if( imax > tfreq.size() - 1 )
1569 if( imax < tfreq.size() - 1 && tfreq[imax] <= 0.5 * fs * ( 1.0 + 1e-7 ) )
1576 tfreqHF.assign( tfreq.begin(), tfreq.end() );
1579 tfreq.erase( tfreq.begin() + imax, tfreq.end() );
1581 tPSDpPOL.resize( tfreq.size() );
1584 std::vector<realT> tPSDn;
1585 tPSDn.resize( tfreq.size() );
1607 std::vector<std::complex<realT>> ETFxn;
1608 std::vector<std::complex<realT>> NTFxn;
1610 if( lifetimeTrials > 0 )
1612 ETFxn.resize( tfreq.size() );
1613 NTFxn.resize( tfreq.size() );
1617 std::string tfOutFile = std::format(
"{}/outputTF_{}_si", dir, mags[s] );
1626 std::string tfOutFile = std::format(
"{}/outputTF_{}_lp", dir, mags[s] );
1640#pragma omp for schedule( dynamic, 5 )
1641 for(
size_t i = 0; i < nModes; ++i )
1650 gains( mnMax + m, mnMax + n ) = 0;
1651 gains( mnMax - m, mnMax - n ) = 0;
1653 gains_lp( mnMax + m, mnMax + n ) = 0;
1654 gains_lp( mnMax - m, mnMax - n ) = 0;
1656 vars( mnMax + m, mnMax + n ) = 0;
1657 vars( mnMax - m, mnMax - n ) = 0;
1659 vars_lp( mnMax + m, mnMax + n ) = 0;
1660 vars_lp( mnMax - m, mnMax - n ) = 0;
1661 speckleLifetimes( mnMax + m, mnMax + n ) = 0;
1662 speckleLifetimes( mnMax - m, mnMax - n ) = 0;
1663 speckleLifetimes_lp( mnMax + m, mnMax + n ) = 0;
1664 speckleLifetimes_lp( mnMax - m, mnMax - n ) = 0;
1679 tPSDpHF.assign( tPSDp.begin() + imax, tPSDp.end() );
1683 tPSDp.erase( tPSDp.begin() + imax, tPSDp.end() );
1690 if( m_uncorrectedOG )
1692 for(
size_t n = 0; n < tPSDp.size(); ++n )
1694 tPSDpPOL[n] = tPSDp[n] * pow( opticalGain, 2 );
1699 for(
size_t n = 0; n < tPSDp.size(); ++n )
1701 tPSDpPOL[n] = tPSDp[n];
1707 bool inside =
false;
1709 if(
m_aosys->circularLimit() )
1711 if( m * m + n * n <= mnCon * mnCon )
1716 if( fabs( m ) <= mnCon && fabs( n ) <= mnCon )
1728 m_aosys->beta_p( m, n ) / sqrt( opticalGain ),
1731 m_aosys->npix_wfs( (
size_t)0 ),
1733 m_aosys->ron_wfs( (
size_t)0 ) );
1739 var = go_si.
clVariance( tPSDp, tPSDn, gopt );
1748 analysisStatus.compare_exchange_strong( expected,
static_cast<int>( gainStatus ) );
1750 var = go_si.
clVariance( tPSDp, tPSDn, gopt );
1753 if( m_uncorrectedOG )
1755 gopt *= opticalGain;
1759 var = go_si.
clVariance( tPSDp, tPSDn, gopt );
1799 analysisStatus.compare_exchange_strong( expected,
static_cast<int>( rv ) );
1802 for(
int n = 0; n < lpNc; ++n )
1804 lpC( i, n ) = go_lp.
a( n );
1807 if( m_uncorrectedOG )
1809 go_lp.aScale( opticalGain );
1810 go_lp.bScale( opticalGain );
1811 gopt_lp *= opticalGain;
1814 var_lp = go_lp.
clVariance( tPSDp, tPSDn, gopt_lp );
1825 tPSDn.assign( tPSDn.size(), 0.0 );
1831 go_lp.
a( std::vector<realT>( { 1 } ) );
1832 go_lp.
b( std::vector<realT>( { 1 } ) );
1837 if( gopt > 0 && var > var0 )
1843 if( gopt_lp > gopt && var_lp > var )
1848 go_lp.
a( std::vector<realT>( { 1 } ) );
1849 go_lp.
b( std::vector<realT>( { 1 } ) );
1854 gains( mnMax + m, mnMax + n ) = gopt;
1855 gains( mnMax - m, mnMax - n ) = gopt;
1857 gains_lp( mnMax + m, mnMax + n ) = gopt_lp;
1858 gains_lp( mnMax - m, mnMax - n ) = gopt_lp;
1860 vars( mnMax + m, mnMax + n ) = var;
1861 vars( mnMax - m, mnMax - n ) = var;
1863 vars_lp( mnMax + m, mnMax + n ) = var_lp;
1864 vars_lp( mnMax - m, mnMax - n ) = var_lp;
1868 if( ( lifetimeTrials > 0 || writeXfer ) && ( uncontrolledLifetimes || inside ) )
1870 std::vector<realT> spfreq, sppsd;
1874 for(
size_t i = 0; i < tfreq.size(); ++i )
1876 ETFxn[i] = go_si.
clETF( i, gopt );
1877 NTFxn[i] = go_si.
clNTF( i, gopt );
1882 for(
size_t i = 0; i < tfreq.size(); ++i )
1891 std::string tfOutFile = std::format(
"{}/outputTF_{}_si", dir, mags[s] );
1894 std::string etfOutFile = std::format(
"{}/etf_{}_{}.binv", tfOutFile, m, n );
1899 std::string ntfOutFile = std::format(
"{}/ntf_{}_{}.binv", tfOutFile, m, n );
1906 std::string fOutFile = tfOutFile +
"freq.binv";
1911 if( lifetimeTrials > 0 )
1913 speckleAmpPSD( spfreq, sppsd, tfreq, tPSDp, ETFxn, tPSDn, NTFxn, lifetimeTrials );
1916 realT splifeT = 100.0;
1919 realT tau = pvm(
error, spfreq, sppsd, splifeT ) * ( splifeT ) / spvar;
1921 speckleLifetimes( mnMax + m, mnMax + n ) = tau;
1922 speckleLifetimes( mnMax - m, mnMax - n ) = tau;
1929 for(
size_t i = 0; i < tfreq.size(); ++i )
1931 ETFxn[i] = go_lp.
clETF( i, gopt_lp );
1932 NTFxn[i] = go_lp.
clNTF( i, gopt_lp );
1937 for(
size_t i = 0; i < tfreq.size(); ++i )
1946 std::string tfOutFile = std::format(
"{}/outputTF_{}_lp", dir, mags[s] );
1949 std::string etfOutFile = std::format(
"{}/etf_{}_{}.binv", tfOutFile, m, n );
1954 std::string ntfOutFile = std::format(
"{}/ntf_{}_{}.binv", tfOutFile, m, n );
1961 std::string fOutFile = tfOutFile +
"freq.binv";
1966 if( lifetimeTrials > 0 )
1968 speckleAmpPSD( spfreq, sppsd, tfreq, tPSDp, ETFxn, tPSDn, NTFxn, lifetimeTrials );
1971 realT splifeT = 100.0;
1974 realT tau = pvm(
error, spfreq, sppsd, splifeT ) * ( splifeT ) / spvar;
1976 speckleLifetimes_lp( mnMax + m, mnMax + n ) = tau;
1977 speckleLifetimes_lp( mnMax - m, mnMax - n ) = tau;
1986 std::string psdOutFile =
1987 std::format(
"{}/outputPSDs_{}_si/psd_{}_{}.binv", dir, mags[s], m, n );
1993 std::vector<realT> psdOut( tPSDp.size() + tPSDpHF.size() );
2000 for(
size_t i = 0; i < tfreq.size(); ++i )
2002 go_si.
clTF2( ETF, NTF, i, gopt );
2003 psdOut[i] = tPSDp[i] * ETF + tPSDn[i] * NTF;
2006 for(
size_t i = 0; i < tPSDpHF.size(); ++i )
2008 psdOut[tfreq.size() + i] = tPSDpHF[i];
2013 for(
size_t i = 0; i < tfreq.size(); ++i )
2015 psdOut[i] = tPSDp[i];
2018 for(
size_t i = 0; i < tPSDpHF.size(); ++i )
2020 psdOut[tfreq.size() + i] = tPSDpHF[i];
2028 psdOutFile = std::format(
"{}/outputPSDs_{}_si/freq.binv", dir, mags[s] );
2035 std::string psdOutFile =
2036 std::format(
"{}/outputPSDs_{}_lp/psd_{}_{}.binv", dir, mags[s], m, n );
2048 for(
size_t i = 0; i < tfreq.size(); ++i )
2050 go_lp.
clTF2( ETF, NTF, i, gopt_lp );
2051 psdOut[i] = tPSDp[i] * ETF + tPSDn[i] * NTF;
2053 for(
size_t i = 0; i < tPSDpHF.size(); ++i )
2055 psdOut[tfreq.size() + i] = tPSDpHF[i];
2060 for(
size_t i = 0; i < tfreq.size(); ++i )
2062 psdOut[i] = tPSDp[i];
2065 for(
size_t i = 0; i < tPSDpHF.size(); ++i )
2067 psdOut[tfreq.size() + i] = tPSDpHF[i];
2075 psdOutFile = std::format(
"{}/outputPSDs_{}_lp/freq.binv", dir, mags[s] );
2091 return analysisStatus.load();
2094 Eigen::Array<
realT, -1, -1> cim;
2097 std::string fn = std::format(
"{}/gainmap_{}_si.fits", dir, mags[s] );
2099 ff.
write( fn, gains );
2101 fn = std::format(
"{}/varmap_{}_si.fits", dir, mags[s] );
2103 ff.
write( fn, vars );
2107 realT Ssi = exp( -1 * cim.sum() );
2108 S_si.push_back( strehl );
2111 fn = std::format(
"{}/contrast_{}_si.fits", dir, mags[s] );
2113 ff.
write( fn, cim );
2115 if( lifetimeTrials > 0 )
2117 fn = std::format(
"{}/speckleLifetimes_{}_si.fits", dir, mags[s] );
2119 ff.
write( fn, speckleLifetimes );
2124 fn = std::format(
"{}/gainmap_{}_lp.fits", dir, mags[s] );
2126 ff.
write( fn, gains_lp );
2128 fn = std::format(
"{}/lpcmap_{}_lp.fits", dir, mags[s] );
2130 ff.
write( fn, lpC );
2132 fn = std::format(
"{}/varmap_{}_lp.fits", dir, mags[s] );
2134 ff.
write( fn, vars_lp );
2139 realT Slp = strehl * exp( -1 * cim.sum() ) /
2141 S_lp.push_back( Slp );
2144 fn = std::format(
"{}/contrast_{}_lp.fits", dir, mags[s] );
2146 ff.
write( fn, cim );
2148 if( lifetimeTrials > 0 )
2150 fn = std::format(
"{}/speckleLifetimes_{}_lp.fits", dir, mags[s] );
2152 ff.
write( fn, speckleLifetimes_lp );
2158 fn = dir +
"/strehl_si.txt";
2160 for(
size_t i = 0; i < mags.size(); ++i )
2162 fout << mags[i] <<
" " << S_si[i] <<
"\n";
2169 fn = dir +
"/strehl_lp.txt";
2171 for(
size_t i = 0; i < mags.size(); ++i )
2173 fout << mags[i] <<
" " << S_lp[i] <<
"\n";
2182template <
typename realT,
typename aosysT>
2184 const std::string &subDir,
2186 const std::string &psdDir,
2187 const std::string &CvdPath,
2190 std::vector<realT> &mags,
2195 std::string dir = psdDir +
"/" + subDir;
2198 mkdir( dir.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH );
2201 std::string fn = dir +
'/' +
"splife_params.txt";
2204 fout <<
"#---------------------------\n";
2205 m_aosys->dumpAOSystem( fout );
2206 fout <<
"#---------------------------\n";
2207 fout <<
"# Analysis Parameters\n";
2208 fout <<
"# mnMax = " << mnMax <<
'\n';
2209 fout <<
"# mnCon = " << mnCon <<
'\n';
2210 fout <<
"# mags = ";
2211 for(
size_t i = 0; i < mags.size() - 1; ++i )
2212 fout << mags[i] <<
",";
2213 fout << mags[mags.size() - 1] <<
'\n';
2214 fout <<
"# lifetimeTrials = " << lifetimeTrials <<
'\n';
2216 fout <<
"# writePSDs = " << std::boolalpha << writePSDs <<
'\n';
2225 std::vector<sigproc::fourierModeDef> fms;
2228 size_t nModes = 0.5 * fms.size();
2229 std::cerr <<
"nModes: " << nModes <<
" (" << fms.size() <<
")\n";
2231 Eigen::Array<
realT, -1, -1> speckleLifetimes;
2232 Eigen::Array<
realT, -1, -1> speckleLifetimes_lp;
2234 speckleLifetimes.resize( 2 * mnMax + 1, 2 * mnMax + 1 );
2235 speckleLifetimes( mnMax, mnMax ) = 0;
2237 speckleLifetimes_lp.resize( 2 * mnMax + 1, 2 * mnMax + 1 );
2238 speckleLifetimes_lp( mnMax, mnMax ) = 0;
2244 std::vector<realT> tfreq;
2245 std::vector<realT> tPSDp;
2246 std::vector<realT> tPSDn;
2247 std::vector<complexT> tETF;
2248 std::vector<complexT> tNTF;
2254 while( tfreq[imax] <= 0.5 * fs )
2257 if( imax > tfreq.size() - 1 )
2261 if( imax < tfreq.size() - 1 && tfreq[imax] <= 0.5 * fs * ( 1.0 + 1e-7 ) )
2264 tfreq.erase( tfreq.begin() + imax, tfreq.end() );
2267 tPSDn.resize( tfreq.size() );
2268 std::vector<std::vector<realT>> sqrtOPDPSD;
2269 sqrtOPDPSD.resize( nModes );
2271 std::vector<std::vector<realT>> opdPSD;
2272 opdPSD.resize( nModes );
2274 std::vector<realT> psd2sided;
2277 std::vector<realT> modeVar;
2278 modeVar.resize( nModes );
2284 for(
size_t i = 0; i < nModes; ++i )
2287 int m = fms[2 * i].m;
2288 int n = fms[2 * i].n;
2293 tPSDp.erase( tPSDp.begin() + imax, tPSDp.end() );
2300 opdPSD[i].resize( psd2sided.size() );
2301 sqrtOPDPSD[i].resize( psd2sided.size() );
2303 for(
size_t j = 0; j < psd2sided.size(); ++j )
2305 opdPSD[i][j] = psd2sided[j] * modeVar[i];
2306 sqrtOPDPSD[i][j] = sqrt( psd2sided[j] );
2310 size_t sz2Sided = psd2sided.size();
2312 std::vector<realT> freq2sided;
2313 freq2sided.resize( sz2Sided );
2316 tPSDp.resize( tfreq.size() );
2317 tETF.resize( tfreq.size() );
2318 tNTF.resize( tfreq.size() );
2320 std::vector<std::vector<realT>> sqrtNPSD;
2321 sqrtNPSD.resize( nModes );
2323 std::vector<realT> noiseVar;
2324 noiseVar.resize( nModes );
2326 std::vector<std::vector<complexT>> ETFsi;
2327 std::vector<std::vector<complexT>> ETFlp;
2328 ETFsi.resize( nModes );
2329 ETFlp.resize( nModes );
2331 std::vector<std::vector<complexT>> NTFsi;
2332 std::vector<std::vector<complexT>> NTFlp;
2333 NTFsi.resize( nModes );
2334 NTFlp.resize( nModes );
2336 std::string tfInFile;
2337 std::string etfInFile;
2338 std::string ntfInFile;
2342 ff.
read( Cvd, CvdPath );
2344 std::vector<std::complex<realT>> tPSDc, psd2sidedc;
2350 for(
size_t s = 0; s < mags.size(); ++s )
2355 for(
size_t i = 0; i < nModes; ++i )
2358 int m = fms[2 * i].m;
2359 int n = fms[2 * i].n;
2362 bool inside =
false;
2364 if(
m_aosys->circularLimit() )
2366 if( m * m + n * n <= mnCon * mnCon )
2371 if( fabs( m ) <= mnCon && fabs( n ) <= mnCon )
2380 m_aosys->npix_wfs( (
size_t)0 ),
2382 m_aosys->ron_wfs( (
size_t)0 ) );
2388 sqrtNPSD[i].resize( psd2sided.size() );
2389 for(
size_t j = 0; j < psd2sided.size(); ++j )
2390 sqrtNPSD[i][j] = sqrt( psd2sided[j] );
2392 ETFsi[i].resize( sz2Sided );
2393 ETFlp[i].resize( sz2Sided );
2394 NTFsi[i].resize( sz2Sided );
2395 NTFlp[i].resize( sz2Sided );
2399 tfInFile = std::format(
"{}/outputTF_{}_si", dir, mags[s] );
2402 etfInFile = std::format(
"{}/etf_{}_{}.binv", tfInFile, m, n );
2406 for(
size_t j = 0; j < psd2sidedc.size(); ++j )
2407 ETFsi[i][j] = psd2sidedc[j];
2409 ntfInFile = std::format(
"{}/ntf_{}_{}.binv", tfInFile, m, n );
2413 for(
size_t j = 0; j < psd2sidedc.size(); ++j )
2414 NTFsi[i][j] = psd2sidedc[j];
2416 tfInFile = std::format(
"{}/outputTF_{}_lp", dir, mags[s] );
2419 etfInFile = std::format(
"{}/etf_{}_{}.binv", tfInFile, m, n );
2423 for(
size_t j = 0; j < psd2sidedc.size(); ++j )
2424 ETFlp[i][j] = psd2sidedc[j];
2426 ntfInFile = std::format(
"{}/ntf_{}_{}.binv", tfInFile, m, n );
2430 for(
size_t j = 0; j < psd2sidedc.size(); ++j )
2431 NTFlp[i][j] = psd2sidedc[j];
2435 for(
int q = 0; q < ETFsi.size(); ++q )
2448 std::vector<std::vector<realT>> spPSDs;
2449 spPSDs.resize( nModes );
2450 for(
size_t pp = 0; pp < spPSDs.size(); ++pp )
2452 spPSDs[pp].resize( tavgPgram.
size() );
2453 for(
size_t nn = 0; nn < spPSDs[pp].size(); ++nn )
2457 std::vector<std::vector<realT>> spPSDslp;
2458 spPSDslp.resize( nModes );
2459 for(
size_t pp = 0; pp < spPSDslp.size(); ++pp )
2461 spPSDslp[pp].resize( tavgPgram.
size() );
2462 for(
size_t nn = 0; nn < spPSDslp[pp].size(); ++nn )
2463 spPSDslp[pp][nn] = 0;
2473 math::ft::fftT<realT, std::complex<realT>, 1, 0> fftF( sqrtOPDPSD[0].size() );
2477 std::vector<std::complex<realT>> tform1( sqrtOPDPSD[0].size() );
2478 std::vector<std::complex<realT>> tform2( sqrtOPDPSD[0].size() );
2479 std::vector<std::complex<realT>> Ntform1( sqrtOPDPSD[0].size() );
2480 std::vector<std::complex<realT>> Ntform2( sqrtOPDPSD[0].size() );
2482 std::vector<std::complex<realT>> tform1lp( sqrtOPDPSD[0].size() );
2483 std::vector<std::complex<realT>> tform2lp( sqrtOPDPSD[0].size() );
2484 std::vector<std::complex<realT>> Ntform1lp( sqrtOPDPSD[0].size() );
2485 std::vector<std::complex<realT>> Ntform2lp( sqrtOPDPSD[0].size() );
2488 sigproc::psdFilter<realT, 1> pfilt;
2489 pfilt.psdSqrt( &sqrtOPDPSD[0], tfreq[1] - tfreq[0] );
2492 sigproc::psdFilter<realT, 1> nfilt;
2493 nfilt.psdSqrt( &sqrtNPSD[0], tfreq[1] - tfreq[0] );
2496 std::vector<std::vector<realT>> hts;
2497 hts.resize( 2 * nModes );
2500 std::vector<std::vector<realT>> htsCorr;
2501 htsCorr.resize( 2 * nModes );
2503 for(
size_t pp = 0; pp < hts.size(); ++pp )
2505 hts[pp].resize( sqrtOPDPSD[0].size() );
2506 htsCorr[pp].resize( sqrtOPDPSD[0].size() );
2510 std::vector<realT> N_n;
2511 N_n.resize( sz2Sided );
2513 std::vector<realT> N_nm;
2514 N_nm.resize( sz2Sided );
2521 std::vector<realT> tpgram( avgPgram.
size() );
2525 spTS.resize( 2 * mnMax + 1, 2 * mnMax + 1, tform1.size() );
2528 spTSlp.resize( 2 * mnMax + 1, 2 * mnMax + 1, tform1.size() );
2532 for(
int zz = 0; zz < lifetimeTrials; ++zz )
2535 std::complex<realT>( ( tform1.size() ), 0 );
2540 for(
size_t pp = 0; pp < nModes; ++pp )
2543 for(
size_t nn = 0; nn < hts[2 * pp].size(); ++nn )
2545 hts[2 * pp][nn] = normVar;
2549 pfilt.psdSqrt( &sqrtOPDPSD[pp], tfreq[1] - tfreq[0] );
2552 pfilt( hts[2 * pp] );
2556 fftF( tform1.data(), hts[2 * pp].data() );
2559 for(
size_t nn = 0; nn < hts[2 * pp].size(); ++nn )
2560 tform1[nn] = tform1[nn] * scale;
2562 fftB( hts[2 * pp + 1].data(), tform1.data() );
2572 for(
size_t pp = 0; pp < hts.size(); ++pp )
2574 for(
size_t nn = 0; nn < hts[0].size(); ++nn )
2576 htsCorr[pp][nn] = 0;
2579 for(
size_t qq = 0; qq <= pp; ++qq )
2581 realT cvd = Cvd( qq, pp );
2582 realT *d1 = htsCorr[pp].data();
2583 realT *d2 = hts[qq].data();
2584 for(
size_t nn = 0; nn < hts[0].size(); ++nn )
2586 d1[nn] += d2[nn] * cvd;
2604 for(
size_t pp = 0; pp < nModes; ++pp )
2610 realT norm = sqrt( modeVar[pp] / var );
2611 for(
size_t nn = 0; nn < htsCorr[2 * pp].size(); ++nn )
2612 htsCorr[2 * pp][nn] *= norm;
2615 norm = sqrt( modeVar[pp] / var );
2616 for(
size_t nn = 0; nn < htsCorr[2 * pp + 1].size(); ++nn )
2617 htsCorr[2 * pp + 1][nn] *= norm;
2620 scale = std::complex<realT>( tform1.size(), 0 );
2625 for(
size_t pp = 0; pp < nModes; ++pp )
2630 fftF( tform1.data(), htsCorr[2 * pp].data() );
2631 fftF( tform2.data(), htsCorr[2 * pp + 1].data() );
2634 for(
int nn = 0; nn < sz2Sided; ++nn )
2642 pfilt.psdSqrt( &sqrtNPSD[pp], tfreq[1] - tfreq[0] );
2643 nfilt.filter( N_n );
2644 nfilt.filter( N_nm );
2648 realT norm = sqrt( noiseVar[pp] / Nactvar );
2649 for(
size_t q = 0; q < N_n.size(); ++q )
2651 for(
size_t q = 0; q < N_nm.size(); ++q )
2655 fftF( Ntform1.data(), N_n.data() );
2656 fftF( Ntform2.data(), N_nm.data() );
2659 for(
size_t mm = 0; mm < tform1.size(); ++mm )
2662 tform1lp[mm] = tform1[mm] * ETFlp[pp][mm] / scale;
2663 tform2lp[mm] = tform2[mm] * ETFlp[pp][mm] / scale;
2665 Ntform1lp[mm] = Ntform1[mm] * NTFlp[pp][mm] / scale;
2666 Ntform2lp[mm] = Ntform2[mm] * NTFlp[pp][mm] / scale;
2668 tform1[mm] *= ETFsi[pp][mm] / scale;
2669 tform2[mm] *= ETFsi[pp][mm] / scale;
2671 Ntform1[mm] *= NTFsi[pp][mm] / scale;
2672 Ntform2[mm] *= NTFsi[pp][mm] / scale;
2676 int m = fms[2 * pp].m;
2677 int n = fms[2 * pp].n;
2680 fftB( htsCorr[2 * pp].data(), tform1.data() );
2681 fftB( htsCorr[2 * pp + 1].data(), tform2.data() );
2682 fftB( N_n.data(), Ntform1.data() );
2683 fftB( N_nm.data(), Ntform2.data() );
2685 for(
int i = 0; i < hts[2 * pp].size(); ++i )
2687 realT h1 = htsCorr[2 * pp][i] + N_n[i];
2688 realT h2 = htsCorr[2 * pp + 1][i] + N_nm[i];
2690 spTS.
image( i )( mnMax + m, mnMax + n ) = ( pow( h1, 2 ) + pow( h2, 2 ) );
2691 spTS.
image( i )( mnMax - m, mnMax - n ) = spTS.
image( i )( mnMax + m, mnMax + n );
2694 fftB( htsCorr[2 * pp].data(), tform1lp.data() );
2695 fftB( htsCorr[2 * pp + 1].data(), tform2lp.data() );
2696 fftB( N_n.data(), Ntform1lp.data() );
2697 fftB( N_nm.data(), Ntform2lp.data() );
2699 for(
int i = 0; i < hts[2 * pp].size(); ++i )
2701 realT h1 = htsCorr[2 * pp][i] + N_n[i];
2702 realT h2 = htsCorr[2 * pp + 1][i] + N_nm[i];
2704 spTSlp.
image( i )( mnMax + m, mnMax + n ) = ( pow( h1, 2 ) + pow( h2, 2 ) );
2705 spTSlp.
image( i )( mnMax - m, mnMax - n ) = spTSlp.
image( i )( mnMax + m, mnMax + n );
2712 std::vector<realT> speckAmp( spTS.planes() );
2713 std::vector<realT> speckAmplp( spTS.planes() );
2715 for(
size_t pp = 0; pp < nModes; ++pp )
2717 int m = fms[2 * pp].m;
2718 int n = fms[2 * pp].n;
2722 for(
int i = 0; i < spTS.planes(); ++i )
2724 speckAmp[i] = spTS.
image( i )( mnMax + m, mnMax + n );
2725 speckAmplp[i] = spTSlp.
image( i )( mnMax + m, mnMax + n );
2728 mnlp += speckAmplp[i];
2730 mn /= speckAmp.size();
2731 mnlp /= speckAmplp.size();
2734 for(
int i = 0; i < speckAmp.size(); ++i )
2736 for(
int i = 0; i < speckAmplp.size(); ++i )
2737 speckAmplp[i] -= mnlp;
2740 avgPgram( tpgram, speckAmp );
2741 for(
size_t nn = 0; nn < spPSDs[pp].size(); ++nn )
2742 spPSDs[pp][nn] += tpgram[nn];
2744 avgPgram( tpgram, speckAmplp );
2745 for(
size_t nn = 0; nn < spPSDslp[pp].size(); ++nn )
2746 spPSDslp[pp][nn] += tpgram[nn];
2753 std::vector<realT> spFreq( spPSDs[0].size() );
2754 for(
size_t nn = 0; nn < spFreq.size(); ++nn )
2755 spFreq[nn] = tavgPgram[nn];
2758 taus.resize( 2 * mnMax + 1, 2 * mnMax + 1 );
2759 tauslp.resize( 2 * mnMax + 1, 2 * mnMax + 1 );
2762 std::vector<realT> clPSD;
2766 imc.resize( 2 * mnMax + 1, 2 * mnMax + 1, spPSDs[0].size() );
2767 imclp.resize( 2 * mnMax + 1, 2 * mnMax + 1, spPSDs[0].size() );
2768 clPSD.resize( sz2Sided );
2775 for(
size_t pp = 0; pp < nModes; ++pp )
2777 spPSDs[pp][0] = spPSDs[pp][1];
2778 spPSDslp[pp][0] = spPSDslp[pp][1];
2780 int m = fms[2 * pp].m;
2781 int n = fms[2 * pp].n;
2786 for(
size_t nn = 0; nn < spPSDs[pp].size(); ++nn )
2788 spPSDs[pp][nn] /= lifetimeTrials;
2791 for(
size_t nn = 0; nn < sz2Sided; ++nn )
2794 opdPSD[pp][nn] * norm( ETFsi[pp][nn] ) + pow( sqrtNPSD[pp][nn], 2 ) * norm( NTFsi[pp][nn] );
2801 for(
size_t nn = 0; nn < spPSDs[pp].size(); ++nn )
2803 spPSDs[pp][nn] *= var / pvar;
2804 imc.
image( nn )( mnMax + m, mnMax + n ) = spPSDs[pp][nn];
2805 imc.
image( nn )( mnMax - m, mnMax - n ) = spPSDs[pp][nn];
2809 for(
size_t nn = 0; nn < spPSDslp[pp].size(); ++nn )
2811 spPSDslp[pp][nn] /= lifetimeTrials;
2814 for(
size_t nn = 0; nn < sz2Sided; ++nn )
2817 opdPSD[pp][nn] * norm( ETFlp[pp][nn] ) + pow( sqrtNPSD[pp][nn], 2 ) * norm( NTFlp[pp][nn] );
2824 for(
size_t nn = 0; nn < spPSDslp[pp].size(); ++nn )
2826 spPSDslp[pp][nn] *= var / pvar;
2827 imclp.
image( nn )( mnMax + m, mnMax + n ) = spPSDslp[pp][nn];
2828 imclp.
image( nn )( mnMax - m, mnMax - n ) = spPSDslp[pp][nn];
2834 realT T = ( 1.0 / ( spFreq[1] - spFreq[0] ) ) * 10;
2836 realT tau = pvm(
error, spFreq, spPSDs[pp], T ) * ( T ) / var;
2837 taus( mnMax + m, mnMax + n ) = tau;
2838 taus( mnMax - m, mnMax - n ) = tau;
2842 tau = pvm(
error, spFreq, spPSDslp[pp], T ) * ( T ) / var;
2843 tauslp( mnMax + m, mnMax + n ) = tau;
2844 tauslp( mnMax - m, mnMax - n ) = tau;
2850 fn = std::format(
"{}/speckleLifetimes_{}_si.fits", dir, mags[s] );
2852 ff.
write( fn, taus );
2854 fn = std::format(
"{}/speckleLifetimes_{}_lp.fits", dir, mags[s] );
2856 ff.
write( fn, tauslp );
2860 fn = std::format(
"{}/specklePSDs_{}_si.fits", dir, mags[s] );
2862 ff.
write( fn, imc );
2864 fn = std::format(
"{}/speckleLifetimes_{}_lp.fits", dir, mags[s] );
2866 ff.
write( fn, imclp );
2874template <
typename realT,
typename aosysT>
2878 fn = dir +
"/psds/freq.binv";
2882template <
typename realT,
typename aosysT>
2886 fn = std::format(
"{}/psds/psd_{}_{}.binv", dir, m, n );
2891template <
typename realT,
typename aosysT>
2893 std::vector<realT> &freq, std::vector<realT> &psd,
const std::string &dir,
int m,
int n )
2905template <
typename realT,
typename aosysT>
2918 realT ku = f / v_wind;
2920 realT kp = sqrt( pow( ku + m / D, 2 ) + pow( kv + n / D, 2 ) );
2921 realT kpp = sqrt( pow( ku - m / D, 2 ) + pow( kv - n / D, 2 ) );
2927 realT Q = ( Q1 + p * Q2 );
2935template <
typename realT>
2937 realT &a, realT &b, realT &c, realT &d,
const realT &kv,
const realT &f,
const realT &Vu,
const realT &f0,
int pm )
2940 b = -( 3 * Vu * Vu * f + pm * f0 * f0 * f0 );
2942 d = -( f * f * f + pm * f0 * f0 * f0 * kv * kv );
2948template <
typename realT,
typename aosysT>
2960 realT f0 = Fp->
m_f0;
2970 realT dku = ku * Fp->
m_cq - kv * Fp->
m_sq;
2971 realT dkv = ku * Fp->
m_sq + kv * Fp->
m_cq;
2973 if( fabs( dku ) >= Fp->
m_aosys->spatialFilter_ku() )
2976 if( fabs( dkv ) >= Fp->
m_aosys->spatialFilter_kv() )
2980 realT kp = sqrt( pow( ku + m / D, 2 ) + pow( kv + n / D, 2 ) );
2981 realT kpp = sqrt( pow( ku - m / D, 2 ) + pow( kv - n / D, 2 ) );
2987 realT QQ = 2 * ( Jp * Jp + Jm * Jm );
2991 sqrt( pow( ku, 2 ) + pow( kv, 2 ) ),
3000 realT a, b, c, d, p, q;
3002 turbBoilCubic( a, b, c, d, kv, f, v_wind, f0, 1 );
3006 ku = t - b / ( 3 * a );
3011 realT dku = ku * Fp->
m_cq - kv * Fp->
m_sq;
3012 realT dkv = ku * Fp->
m_sq + kv * Fp->
m_cq;
3014 if( fabs( dku ) >= Fp->
m_aosys->spatialFilter_ku() )
3017 if( fabs( dkv ) >= Fp->
m_aosys->spatialFilter_kv() )
3021 realT kp = sqrt( pow( ku + m / D, 2 ) + pow( kv + n / D, 2 ) );
3022 realT kpp = sqrt( pow( ku - m / D, 2 ) + pow( kv - n / D, 2 ) );
3028 realT QQ = 2 * ( Jp * Jp + Jm * Jm );
3032 sqrt( pow( ku, 2 ) + pow( kv, 2 ) ),
3039 turbBoilCubic( a, b, c, d, kv, f, v_wind, f0, -1 );
3043 ku = t - b / ( 3 * a );
3048 realT dku = ku * Fp->
m_cq - kv * Fp->
m_sq;
3049 realT dkv = ku * Fp->
m_sq + kv * Fp->
m_cq;
3051 if( fabs( dku ) >= Fp->
m_aosys->spatialFilter_ku() )
3054 if( fabs( dkv ) >= Fp->
m_aosys->spatialFilter_kv() )
3058 kp = sqrt( pow( ku + m / D, 2 ) + pow( kv + n / D, 2 ) );
3059 kpp = sqrt( pow( ku - m / D, 2 ) + pow( kv - n / D, 2 ) );
3065 QQ = 2 * ( Jp * Jp + Jm * Jm );
3069 sqrt( pow( ku, 2 ) + pow( kv, 2 ) ),
3076 return 0.5 * ( P1 + P2 );
3083extern template struct fourierTemporalPSD<double, aoSystem<double, vonKarmanSpectrum<double>, std::ostream>>;
Utilities related to the Airy pattern point spread function.
Calculate and provide constants related to adaptive optics.
Spatial power spectra used in adaptive optics.
Declares and defines an analytical AO system.
A utility to read/write vectors of data from/to a binary file.
Provides a class to manage closed loop gain linear predictor determination.
Provides a class to manage closed loop gain optimization.
Class to manage interactions with a FITS file.
error_t read(dataT *data)
Read the contents of the FITS file into an array.
error_t write(const dataT *im, int d1, int d2, int d3, fitsHeader< verboseT > *head)
Write the contents of a raw array to the FITS file.
An image cube with an Eigen-like API.
Eigen::Map< Eigen::Array< dataT, Eigen::Dynamic, Eigen::Dynamic > > image(Index n)
Returns a 2D Eigen::Eigen::Map pointed at the specified image.
A class to track the number of iterations in an OMP parallelized loop.
void incrementAndOutputStatus()
Increment and output status.
void seed(typename ranengT::result_type seedval)
Set the seed of the random engine.
Calculate the average periodogram of a time-series.
size_t size()
Return the size of the periodogram.
std::vector< realT > & win()
Get a reference to the window vector.
Declarations of utilities for working with files.
Declares and defines a class to work with a FITS file.
Floating-point classification utilities that remain reliable under fast-math optimization.
#define WSZ
The size of the gsl_integration workspaces.
Functions for generating 2D Fourier modes.
@ modified
The modified Fourier basis from males_guyon_2018.
@ basic
The basic sine and cosine Fourier modes.
fourierTemporalPSDPolicy
Policy for handling GSL quadrature non-convergence statuses.
@ strict
Record every status and return an error if any integration does not converge.
@ permissive
Retain the best finite approximation and record the status.
int writeBinVector(const std::string &fname, std::vector< dataT > &vec)
Write a BinVector file to disk.
int readBinVector(std::vector< dataT > &vec, const std::string &fname)
Read a BinVector file from disk.
Eigen::Array< scalarT, -1, -1 > eigenImage
Definition of the eigenImage type, which is an alias for Eigen::Array.
error_t
The mxlib error codes.
@ noerror
No error has occurred.
@ sizeerr
A size was invalid or calculated incorrectly.
@ allocerr
An error occurred during memory allocation.
@ fileoerr
An error occurred while opening a file.
@ invalidconfig
A config setting was invalid.
@ filewerr
An error occurred while writing to a file.
@ invalidarg
An argument was invalid.
@ error
A general error has occurred.
@ liberr
An error was returned by a library.
error_t mxlib_error_report(const error_t &code, const std::string &expl, const std::source_location &loc=std::source_location::current())
Print a report to stderr given an mxlib error_t code and explanation and return the code.
error_t createDirectories(const std::string &path)
Create a directory or directories.
int fourierModeCoordinates(int &m, int &n, int &p, int i)
Calculate the (m,n,p) coordinates of a Fourier mode given its index.
int makeFourierModeFreqs_Rect(std::vector< fourierModeDef > &spf, int N)
Generate a rectangular spatial frequency grid.
@ backward
Specifies the backward transform.
T jinc(const T &x)
The Jinc function.
bool isFinite(realT value)
Test whether a floating-point value is finite, including under finite-math-only optimization.
constexpr T pi()
Get the value of pi.
constexpr T half_pi()
Get the value of pi/2.
realT F_basic(realT kv, void *params)
Worker function for GSL Integration for the basic sin/cos Fourier modes.
realT F_mod(realT kv, void *params)
Worker function for GSL Integration for the modified Fourier modes.
void wfsNoisePSD(std::vector< realT > &PSD, realT beta_p_k, realT Fg, realT tau, realT npx, realT Fb, realT ron)
Populate a vector with the PSD of measurement noise given WFS parameters.
void augment1SidedPSD(vectorTout &psdTwoSided, vectorTin &psdOneSided, bool addZeroFreq=false, typename vectorTin::value_type scale=0.5)
Augment a 1-sided PSD to standard 2-sided FFT form.
void augment1SidedPSDFreq(std::vector< T > &freqTwoSided, std::vector< T > &freqOneSided)
Augment a 1-sided frequency scale to standard FFT form.
realT psdVar(const std::vector< realT > &f, const std::vector< realT > &PSD, realT half=0.5)
Calculate the variance of a 1-D PSD.
int normPSD(std::vector< floatT > &psd, std::vector< floatT > &f, floatParamT normT, floatT fmin=std::numeric_limits< floatT >::min(), floatT fmax=std::numeric_limits< floatT >::max())
Normalize a 1-D PSD to have a given variance.
randomT< realT, std::mt19937_64, std::normal_distribution< realT > > normDistT
Alias for a standard normal random variate.
void hann(realT *filt, int N)
The Hann Window.
#define gmax(A, B)
max(A,B) - larger (most +ve) of two numbers (generic) (defined in the SOFA library sofam....
void vectorMeanSub(valueT *vec, size_t sz)
Subtract the mean from a vector.
void vectorScale(vectorT &vec, size_t N=0, typename vectorT::value_type scale=0, typename vectorT::value_type offset=0)
Fill in a vector with a regularly spaced scale.
valueT vectorVariance(const valueT *vec, size_t sz, valueT mean)
Calculate the variance of a vector relative to a supplied mean value.
Declares and defines the Jinc and Jinc2 functions.
Declarations of some libarary wide utilities.
Track iterations in an OMP parallelized looop.
Tools for calculating the variance of the mean of a PSD.
A utility to read in columns from a text file.
realT cubicRealRoot(const realT &p, const realT &q)
Calculate the real root for a depressed cubic with negative descriminant.
void cubicDepressed(realT &p, realT &q, const realT &a, const realT &b, const realT &c, const realT &d)
Convert a general cubic equation to depressed form.
Calculates the PSD of speckle intensity given a modified Fourier mode amplitude PSD.
int speckleAmpPSD(std::vector< realT > &spFreq, std::vector< realT > &spPSD, const std::vector< realT > &freq, const std::vector< realT > &fmPSD, const std::vector< std::complex< realT > > &fmXferFxn, const std::vector< realT > &nPSD, const std::vector< std::complex< realT > > &nXferFxn, int N, std::vector< realT > *vars=nullptr, std::vector< realT > *bins=nullptr, bool noPSD=false)
Calculate the PSD of the speckle intensity given the PSD of Fourier mode amplitude.
Utilities for working with strings.
Class to manage the calculation of linear predictor coefficients for a closed-loop AO system.
realT m_precision0
Initial regularization scale spacing in dB.
mx::error_t regularizeCoefficients(realT &gmax_lp, realT &gopt_lp, realT &var_lp, realT &min_sc, clGainOpt< realT > &go_lp, std::vector< realT > &PSDt, std::vector< realT > &PSDn, int Nc)
Regularize the PSD and calculate the associated LP coefficients.
A class to manage optimizing closed-loop gains.
void a(const std::vector< realT > &newA)
Set the vector of IIR coefficients.
complexT clNTF(int fi, realT g)
Return the closed loop noise transfer function (NTF) at frequency f for gain g.
void b(const std::vector< realT > &newB)
Set the vector of FIR coefficients.
realT clVariance(realT &varErr, realT &varNoise, const std::vector< realT > &PSDerr, const std::vector< realT > &PSDnoise, realT g)
Calculate the closed loop variance given open-loop PSDs and gain.
complexT clETF(int fi, realT g)
Return the closed loop error transfer function (ETF) at frequency f for gain g.
void f(realT *newF, size_t nF)
Set the vector of frequencies.
void clTF2(realT &ETF, realT &NTF, int fi, realT g)
Return the norm of the closed loop transfer functions at frequency f for gain g.
mx::error_t optGainOpenLoop(realT &gain, realT &var, const std::vector< realT > &PSDerr, const std::vector< realT > &PSDnoise, bool gridSearch, optGainReport *report=nullptr)
Return the optimum closed loop gain given an open loop PSD.
Summary of one GSL status code.
size_t count
Number of occurrences of this status.
realT maximumToleranceRatio
Largest error estimate relative to the requested tolerance.
realT maximumAbsoluteError
Largest GSL absolute-error estimate.
size_t worstLayer
Layer containing the largest tolerance ratio.
std::map< size_t, size_t > countByLayer
Number of occurrences in each atmospheric layer.
realT worstFrequency
Frequency containing the largest tolerance ratio.
Aggregated GSL quadrature diagnostics for a Fourier temporal PSD calculation.
void clear()
Reset all accumulated diagnostics.
size_t integrationsConverged
Number of quadrature calls returning GSL_SUCCESS.
size_t failureCount() const
Return the total number of non-successful integrations.
void write(std::ostream &output) const
Write a human-readable summary of the accumulated quadrature diagnostics.
void record(int status, size_t layer, realT frequency, realT result, realT absoluteError, realT absoluteTolerance, realT relativeTolerance)
Record one quadrature result.
size_t integrationsAttempted
Total number of quadrature calls.
std::map< int, statusSummary > gslStatus
Summaries keyed by the raw GSL status code.
void merge(const fourierTemporalPSDReport &other)
Merge another report into this report.
Class to manage the calculation of temporal PSDs of the Fourier modes in atmospheric turbulence.
error_t singleLayerPSDImpl(std::vector< realT > &PSD, std::vector< realT > &freq, realT m, realT n, int layer_i, int p, realT fmax, reportT &report, fourierTemporalPSDPolicy policy)
fourierTemporalPSD_detail::gslWorkspaceAllocator m_workspaceAllocator
int analyzePSDGrid(const std::string &subDir, const std::string &psdDir, int mnMax, int mnCon, realT gfixed, int lpNc, realT lpRegPrecision, std::vector< realT > &mags, int lifetimeTrials=0, bool ucLifeTs=false, bool writePSDs=false, bool writeXfer=false)
Analyze a PSD grid under closed-loop control.
fourierTemporalPSD(const fourierTemporalPSD &)=delete
Disallow copying unique workspace ownership.
int getGridPSD(std::vector< realT > &freq, std::vector< realT > &psd, const std::string &dir, int m, int n)
Get both the frequency scale and a single PSD from a PSD grid.
int getGridFreq(std::vector< realT > &freq, const std::string &dir)
Get the frequency scale for a PSD grid.
fourierTemporalPSDReport< realT > reportT
Quadrature report type used by this specialization.
int getGridPSD(std::vector< realT > &psd, const std::string &dir, int m, int n)
Get a single PSD from a PSD grid.
realT relTol()
Get the current relative tolerance.
error_t validateAtmosphere(int layer_i)
error_t validatePsdInputs(const std::vector< realT > &PSD, const std::vector< realT > &freq, realT m, realT n, int p, realT fmax, int layer_i, fourierTemporalPSDPolicy policy)
Eigen::Array< realT, -1, -1 > m_modeCoeffs
error_t singleLayerPSD(std::vector< realT > &PSD, std::vector< realT > &freq, realT m, realT n, int layer_i, int p, realT fmax=0, reportT *report=nullptr, fourierTemporalPSDPolicy policy=fourierTemporalPSDPolicy::permissive)
fourierTemporalPSD(fourierTemporalPSD &&) noexcept=default
Move workspace ownership and evaluator state.
fourierTemporalPSD_detail::gslWorkspacePtr m_workspace
fourierTemporalPSD & operator=(const fourierTemporalPSD &)=delete
Disallow copy assignment of unique workspace ownership.
_realT realT
The type for arithmetic.
std::complex< realT > complexT
The complex type for arithmetic.
error_t allocateWorkspace()
realT fastestPeak(int m, int n)
int intensityPSD(const std::string &subDir, const std::string &psdDir, const std::string &CvdPath, int mnMax, int mnCon, std::vector< realT > &mags, int lifetimeTrials, bool writePSDs)
error_t makePSDGrid(const std::string &dir, int mnMax, realT dFreq, realT maxFreq, realT fmax=0)
Calculate PSDs over a grid of spatial frequencies.
error_t multiLayerPSD(std::vector< realT > &PSD, std::vector< realT > &freq, realT m, realT n, int p, realT fmax=0, reportT *report=nullptr, fourierTemporalPSDPolicy policy=fourierTemporalPSDPolicy::permissive)
Calculate the temporal PSD for a Fourier mode in a multi-layer model.
realT absTol()
Get the current absolute tolerance.
fourierTemporalPSD()
Default c'tor.
Calculate the variance of the mean for a process given its PSD.
A utility to convert a wavefront variance map to an intensity image.
Header for the std::vector utilities.
Declares and defines a function to calculate the measurement noise PSD.