8#ifndef aoAtmosphere_hpp
9#define aoAtmosphere_hpp
18#include "../../mxlib.hpp"
19#include "../../mxError.hpp"
23#include "../../math/constants.hpp"
25#include "../../app/appConfigurator.hpp"
44template <
typename _realT>
116 realT
r_0(
const realT &lam );
122 void r_0(
const realT &r0,
162 realT
L_0(
const size_t &n );
167 void L_0(
const std::vector<realT> &L0 );
179 realT
l_0(
const size_t &n );
184 void l_0(
const std::vector<realT> &l0 );
220 void alpha(
const std::vector<realT> &alph );
244 void beta(
const std::vector<realT> &bet );
268 void beta_0(
const std::vector<realT> &bet );
283 size_t currentLayer();
285 void currentLayer(
size_t cl );
304 void layer_z(
const std::vector<realT> &layz );
544 realT
f_g( realT lam_sci );
595 template <
typename iosT>
619template <
typename realT>
624template <
typename realT>
627 size_t n = m_L_0.size();
629 if( m_l_0.size() != n )
631 mxError(
"aoAtmosphere",
MXE_SIZEERR,
"mismatched layer numbers (inner scale vs. outer scale)" );
635 if( m_layer_z.size() != n )
637 mxError(
"aoAtmosphere",
MXE_SIZEERR,
"mismatched layer numbers (layer_z vs. outer scale)" );
641 if( m_layer_Cn2.size() != n )
643 mxError(
"aoAtmosphere",
MXE_SIZEERR,
"mismatched layer numbers (layer_Cn2 vs. outer scale)" );
647 if( m_layer_dir.size() != n )
649 mxError(
"aoAtmosphere",
MXE_SIZEERR,
"mismatched layer numbers (layer_dir vs. outer scale)" );
653 if( m_layer_v_wind.size() != n )
655 mxError(
"aoAtmosphere",
MXE_SIZEERR,
"mismatched layer numbers (layer_v_wind vs. outer scale)" );
662template <
typename realT>
668template <
typename realT>
674template <
typename realT>
689template <
typename realT>
695template <
typename realT>
698 return m_layer_Cn2[n];
701template <
typename realT>
707template <
typename realT>
712 realT layer_norm = 0;
714 for(
size_t i = 0; i < m_layer_Cn2.size(); ++i )
716 layer_norm += cn2[i];
719 for(
size_t i = 0; i < m_layer_Cn2.size(); ++i )
720 m_layer_Cn2[i] = m_layer_Cn2[i] / layer_norm;
728 m_v_wind_updated =
false;
729 m_z_mean_updated =
false;
732template <
typename realT>
738template <
typename realT>
744template <
typename realT>
750template <
typename realT>
756template <
typename realT>
762template <
typename realT>
768template <
typename realT>
771 m_nonKolmogorov = nk;
774template <
typename realT>
777 return m_nonKolmogorov;
780template <
typename realT>
783 if( !m_nonKolmogorov )
793template <
typename realT>
796 m_nonKolmogorov =
true;
800template <
typename realT>
806template <
typename realT>
809 if( !m_nonKolmogorov )
820template <
typename realT>
823 m_nonKolmogorov =
true;
827template <
typename realT>
833template <
typename realT>
836 if( !m_nonKolmogorov )
846template <
typename realT>
849 m_nonKolmogorov =
true;
853template <
typename realT>
859template <
typename realT>
862 if( m_nonKolmogorov )
863 return m_alpha.size();
865 return m_layer_Cn2.size();
868template <
typename realT>
874template <
typename realT>
878 m_z_mean_updated =
false;
881template <
typename realT>
887template <
typename realT>
893template <
typename realT>
899template <
typename realT>
905template <
typename realT>
911template <
typename realT>
914 return m_layer_v_wind[n];
917template <
typename realT>
920 return m_layer_v_wind;
923template <
typename realT>
927 m_v_wind_updated =
false;
930template <
typename realT>
933 return m_layer_dir[n];
936template <
typename realT>
942template <
typename realT>
946 m_v_wind_updated =
false;
949template <
typename realT>
952 if( m_v_wind_updated ==
false )
957template <
typename realT>
960 if( m_v_wind_updated ==
false )
965template <
typename realT>
969 if( m_layer_v_wind.size() == 0 || m_layer_Cn2.size() == 0 )
973 m_v_wind_updated =
true;
982 for(
size_t i = 0; i < m_layer_Cn2.size(); ++i )
986 sin( m_layer_dir[i] );
988 cos( m_layer_dir[i] );
994 m_dir_wind = atan( s / c );
998 m_v_wind_updated =
true;
1001template <
typename realT>
1004 if( m_v_wind_updated ==
false )
1007 realT vw_old = m_v_wind;
1012 if( m_layer_v_wind.size() > 0 )
1014 for(
size_t i = 0; i < m_layer_v_wind.size(); ++i )
1016 m_layer_v_wind[i] = m_layer_v_wind[i] * ( vw / vw_old );
1021template <
typename realT>
1024 if( m_z_mean_updated ==
false )
1029template <
typename realT>
1032 if( m_layer_z.size() == 0 || m_layer_Cn2.size() == 0 )
1035 m_z_mean_updated =
true;
1041 for(
size_t i = 0; i < m_layer_Cn2.size(); ++i )
1048 m_z_mean_updated =
true;
1051template <
typename realT>
1054 if( m_z_mean_updated ==
false )
1057 realT zh_old = m_z_mean;
1062 if( m_layer_z.size() > 0 )
1064 for(
size_t i = 0; i < m_layer_z.size(); ++i )
1066 m_layer_z[i] = m_layer_z[i] * ( zm / zh_old );
1071template <
typename realT>
1076 for(
size_t i = 0; i < m_layer_Cn2.size(); ++i )
1078 c += m_layer_Cn2[i] * pow( cos(
math::pi<realT>() * k * k * lam_sci * m_layer_z[i] * secZ ), 2 );
1084template <
typename realT>
1089 for(
size_t i = 0; i < m_layer_Cn2.size(); ++i )
1091 c += m_layer_Cn2[i] * pow( ( cos(
math::pi<realT>() * f * f * lam_sci * m_layer_z[i] ) -
1099template <
typename realT>
1104 for(
size_t i = 0; i < m_layer_Cn2.size(); ++i )
1106 c += m_layer_Cn2[i] * pow( sin(
math::pi<realT>() * k * k * lam_sci * m_layer_z[i] * secZ ), 2 );
1111template <
typename realT>
1116 for(
size_t i = 0; i < m_layer_Cn2.size(); ++i )
1118 c += m_layer_Cn2[i] * pow( ( sin(
math::pi<realT>() * f * f * lam_sci * m_layer_z[i] ) -
1126template <
typename realT>
1129 realT ll2 =
static_cast<realT>( 1 ) / pow( lambda / 1e-6, 2 );
1131 return 1.0 + 8.34213e-5 + 0.0240603 / ( 130.0 - ll2 ) + 0.00015997 / ( 38.9 - ll2 );
1134template <
typename realT>
1138 realT sinZ = sqrt( 1.0 - pow( 1.0 / secZ, 2 ) );
1139 realT tanZ = sinZ * secZ;
1140 realT x0 = ( n_air( lambda_wfs ) - n_air( lambda_i ) ) * m_H * tanZ * secZ;
1143 for(
size_t i = 0; i < m_layer_Cn2.size(); ++i )
1145 x = x0 * ( 1 - exp( ( m_layer_z[i] + m_h_obs ) / m_H ) );
1146 c += m_layer_Cn2[i] * pow( cos(
math::pi<realT>() * k * k * lambda_i * m_layer_z[i] * secZ ), 2 ) *
1153template <
typename realT>
1156 realT r0lam = r_0( lam_sci );
1158 realT fwhm = 0.98 * ( lam_sci / r0lam );
1163template <
typename realT>
1166 realT r0lam = r_0( lam_sci );
1168 realT fwhm = 0.98 * ( lam_sci / r0lam );
1172 fwhm *= sqrt( 1 - 2.183 * pow( r0lam / L_0( 0 ), 0.356 ) );
1177template <
typename realT>
1180 return 0.428 * v_wind() / m_r_0;
1183template <
typename realT>
1189template <
typename realT>
1192 return 0.134 / f_g();
1195template <
typename realT>
1198 return 0.134 / f_g( lam_sci );
1201template <
typename realT>
1208template <
typename realT>
1211 layer_Cn2( { 0.2283, 0.0883, 0.0666, 0.1458, 0.3350, 0.1350 } );
1212 layer_z( { 500, 1000, 2000, 4000, 8000, 16000 } );
1213 layer_v_wind( { 10., 10., 10., 10., 10., 10. } );
1214 layer_dir( { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 } );
1221template <
typename realT>
1224 layer_Cn2( { 0.42, 0.029, 0.062, 0.16, 0.11, 0.10, 0.12 } );
1225 layer_z( { 250., 500., 1000., 2000., 4000., 8000., 16000. } );
1226 layer_v_wind( { 10.0, 10.0, 20.0, 20.0, 25.0, 30.0, 25.0 } );
1227 layer_dir( { 1.05, 1.05, 1.31, 1.31, 1.75, 1.92, 1.75 } );
1229 r_0( 0.16, 0.5e-6 );
1231 L_0( { 25.0, 25.0, 25.0, 25.0, 25.0, 25.0, 25.0 } );
1232 l_0( { 0.0, 0, 0, 0, 0, 0, 0 } );
1237template <
typename realT>
1241 L_0( std::vector<realT>( { L0 } ) );
1242 l_0( std::vector<realT>( { l0 } ) );
1243 layer_Cn2( std::vector<realT>( { 1 } ) );
1244 layer_z( std::vector<realT>( { lz } ) );
1245 layer_v_wind( std::vector<realT>( { vw } ) );
1246 layer_dir( std::vector<realT>( { dir } ) );
1249template <
typename realT>
1250template <
typename iosT>
1253 ios <<
"# Atmosphere Parameters:\n";
1254 ios <<
"# nonKolmogorov = " << std::boolalpha << nonKolmogorov() <<
'\n';
1255 ios <<
"# n_layers = " << n_layers() <<
'\n';
1257 if( !m_nonKolmogorov )
1259 ios <<
"# r_0 = " << r_0() <<
'\n';
1260 ios <<
"# lam_0 = " << lam_0() <<
'\n';
1261 ios <<
"# tau_0 = " << tau_0( lam_0() ) <<
'\n';
1262 ios <<
"# FWHM = " << fwhm( lam_0() ) <<
'\n';
1263 ios <<
"# layer_Cn2 = ";
1264 for(
size_t i = 0; i < n_layers() - 1; ++i )
1265 ios << layer_Cn2()[i] <<
", ";
1266 ios << layer_Cn2()[n_layers() - 1] <<
'\n';
1268 if( m_nonKolmogorov )
1270 ios <<
"# alpha = ";
1271 for(
size_t i = 0; i < n_layers() - 1; ++i )
1272 ios << alpha()[i] <<
", ";
1273 ios << alpha()[n_layers() - 1] <<
'\n';
1275 for(
size_t i = 0; i < n_layers() - 1; ++i )
1276 ios << beta()[i] <<
", ";
1277 ios << beta()[n_layers() - 1] <<
'\n';
1278 ios <<
"# beta_0 = ";
1279 for(
size_t i = 0; i < n_layers() - 1; ++i )
1280 ios << beta_0()[i] <<
", ";
1281 ios << beta_0()[n_layers() - 1] <<
'\n';
1285 for(
size_t i = 0; i < n_layers() - 1; ++i )
1286 ios << L_0()[i] <<
", ";
1287 ios << L_0()[n_layers() - 1] <<
'\n';
1289 for(
size_t i = 0; i < n_layers() - 1; ++i )
1290 ios << l_0()[i] <<
", ";
1291 ios << l_0()[n_layers() - 1] <<
'\n';
1293 ios <<
"# layer_v_wind = ";
1294 for(
size_t i = 0; i < n_layers() - 1; ++i )
1295 ios << layer_v_wind()[i] <<
", ";
1296 ios << layer_v_wind()[n_layers() - 1] <<
'\n';
1297 ios <<
"# layer_dir = ";
1298 for(
size_t i = 0; i < n_layers() - 1; ++i )
1299 ios << layer_dir()[i] <<
", ";
1300 ios << layer_dir()[n_layers() - 1] <<
'\n';
1301 ios <<
"# mean v_wind = " << v_wind() <<
'\n';
1302 ios <<
"# mean dir_wind = " << dir_wind() <<
'\n';
1304 if( !m_nonKolmogorov )
1306 ios <<
"# layer_z = ";
1307 for(
size_t i = 0; i < n_layers() - 1; ++i )
1308 ios << layer_z()[i] <<
", ";
1309 ios << layer_z()[n_layers() - 1] <<
'\n';
1310 ios <<
"# mean z = " << z_mean() <<
'\n';
1311 ios <<
"# h_obs = " << h_obs() <<
'\n';
1312 ios <<
"# H = " << H() <<
'\n';
1318template <
typename realT>
1321 using namespace mx::app;
1323 config.
add(
"atm.r_0",
"",
"atm.r_0", argType::Required,
"atm",
"r_0",
false,
"real",
"Fried's parameter [m]" );
1324 config.
add(
"atm.lam_0",
1332 "The reference wavlength for r_0 [m]" );
1334 "atm.L_0",
"",
"atm.L_0", argType::Required,
"atm",
"L_0",
false,
"vector<real>",
"Layer outer scales [m]" );
1336 "atm.l_0",
"",
"atm.l_0", argType::Required,
"atm",
"l_0",
false,
"vector<real>",
"Layer inner scales [m]" );
1337 config.
add(
"atm.layer_z",
1345 "layer heights [m]" );
1347 "atm.h_obs",
"",
"atm.h_obs", argType::Required,
"atm",
"h_obs",
false,
"real",
"height of observatory [m]" );
1348 config.
add(
"atm.H",
"",
"atm.H", argType::Required,
"atm",
"H",
false,
"real",
"atmospheric scale heights [m]" );
1349 config.
add(
"atm.layer_Cn2",
1357 "Layer Cn^2. Note that this does not set r_0." );
1358 config.
add(
"atm.layer_v_wind",
1366 "Layer wind speeds [m/s]" );
1367 config.
add(
"atm.layer_dir",
1375 "Layer wind directions [rad]" );
1376 config.
add(
"atm.v_wind",
1384 "Mean windspeed (5/3 momement), rescales layer speeds [m/s]" );
1385 config.
add(
"atm.tau_0",
1393 "AO time constant, sets v_wind and rescales layer speeds. [s]" );
1394 config.
add(
"atm.z_mean",
1402 "Mean layer height (5/3 momemnt), rescales layer heights [m/s]" );
1403 config.
add(
"atm.nonKolmogorov",
1405 "atm.nonKolmogorov",
1411 "Set to use a non-Kolmogorov PSD. See alpha and beta." );
1412 config.
add(
"atm.alpha",
1420 "Non-kolmogorov PSD exponent." );
1421 config.
add(
"atm.beta",
1429 "Non-kolmogorov PSD normalization." );
1430 config.
add(
"atm.beta_0",
1438 "Non-kolmogorov PSD constant." );
1441template <
typename realT>
1450 config( m_lam_0,
"atm.lam_0" );
1453 std::vector<realT> lcn2 = m_layer_Cn2;
1454 config( lcn2,
"atm.layer_Cn2" );
1455 if( config.
isSet(
"atm.layer_Cn2" ) )
1459 config( r0,
"atm.r_0" );
1460 if( config.
isSet(
"atm.r_0" ) )
1463 config( m_L_0,
"atm.L_0" );
1465 config( m_l_0,
"atm.l_0" );
1468 std::vector<realT> layz = m_layer_z;
1469 config( layz,
"atm.layer_z" );
1470 if( config.
isSet(
"atm.layer_z" ) )
1473 config( m_h_obs,
"atm.h_obs" );
1474 config( m_H,
"atm.H" );
1477 std::vector<realT> lvw = m_layer_v_wind;
1478 config( lvw,
"atm.layer_v_wind" );
1479 if( config.
isSet(
"atm.layer_v_wind" ) )
1480 layer_v_wind( lvw );
1483 std::vector<realT> ld = m_layer_dir;
1484 config( ld,
"atm.layer_dir" );
1485 if( config.
isSet(
"atm.layer_dir" ) )
1488 realT vw = m_v_wind;
1489 config( vw,
"atm.v_wind" );
1490 if( config.
isSet(
"atm.v_wind" ) )
1494 config( t0,
"atm.tau_0" );
1495 if( config.
isSet(
"atm.tau_0" ) )
1497 std::cerr <<
"setting tau_0 " << t0 <<
"\n";
1498 tau_0( t0, m_lam_0 );
1500 realT zm = m_z_mean;
1501 config( zm,
"atm.z_mean" );
1502 if( config.
isSet(
"atm.z_mean" ) )
1505 config( m_nonKolmogorov,
"atm.nonKolmogorov" );
1507 std::vector<realT> a = m_alpha;
1508 config( a,
"atm.alpha" );
1509 if( config.
isSet(
"atm.alpha" ) )
1512 std::vector<realT> b = m_beta;
1513 config( b,
"atm.beta" );
1514 if( config.
isSet(
"atm.beta" ) )
1517 std::vector<realT> b0 = m_beta_0;
1518 config( b0,
"atm.beta_0" );
1519 if( config.
isSet(
"atm.beta_0" ) )
Calculate and provide constants related to adaptive optics.
A class to specify atmosphere parameters and perform related calculations.
void beta(const std::vector< realT > &bet)
Set the vector of layer PSD normalizations.
std::vector< realT > m_beta_0
The PSD constant when in non-Kolmogorov mode.
realT r_0(const realT &lam)
Get the value of Fried's parameter r_0 at the specified wavelength.
realT dir_wind()
Get the weighted mean wind direction.
std::vector< realT > alpha()
Get the vector of PSD indices.
realT lam_0()
Get the current value of the reference wavelength.
std::vector< realT > l_0()
Get the vector of inner scales.
void loadLCO()
Load parameters corresponding to the median atmosphere of the GMT site survey at LCO.
void layer_z(const std::vector< realT > &layz)
Set the vector of layer heights.
std::vector< realT > layer_v_wind()
Get the vector of layer windspeeds.
realT v_wind_mean2()
Get the mean-squared wind speed.
realT X(realT k, realT lam_sci, realT secZ)
The fraction of the turbulence PSD in phase after Fresnel propagation.
std::vector< realT > m_beta
The PSD normalization when in non-Kolmogorov mode.
iosT & dumpAtmosphere(iosT &ios)
Output current parameters to a stream.
realT h_obs()
Get the height of the observatory.
realT l_0(const size_t &n)
Get the value of the inner scale for a single layer.
realT m_z_mean
averaged layer height
realT layer_dir(const int n)
Get the wind direction of a single layer.
realT m_v_wind
averaged windspeed
void beta_0(const std::vector< realT > &bet)
Set the vector of layer PSD constants.
realT L_0(const size_t &n)
Get the value of the outer scale for a single layer.
realT m_dir_wind
averaged direction
std::vector< realT > m_alpha
The PSD exponent when in non-Kolmogorov mode.
std::vector< realT > beta()
Get the vector of PSD normalizations.
realT dY(realT k, realT lam_sci, realT lam_wfs)
The differential fraction of the turbulence PSD in amplitude after Fresnel propagation.
realT tau_0()
Get tau_0 at the reference wavelength.
std::vector< realT > L_0()
Get the vector of outer scales.
void layer_v_wind(const std::vector< realT > &spd)
Set the vector of layer windspeeds.
std::vector< realT > layer_dir()
Get the vector of layer wind directions.
void h_obs(realT nh)
Set the height of the observatory.
void loadGuyon2005()
Load the default atmosphere model from Guyon (2005).
void nonKolmogorov(const bool &nk)
Set the value of m_nonKolmogorov.
void layer_dir(const std::vector< realT > &d)
Set the vector of layer wind directions.
realT m_H
The atmospheric scale height, in m.
void L_0(const std::vector< realT > &L0)
Set the vector of layer outer scales.
void loadConfig(app::appConfigurator &config)
Load the configuration of this class from a configurator.
void update_z_mean()
Recalculate m_z_mean.
realT fwhm(realT lam_sci)
_realT realT
The real floating type in which all calculations are performed.
bool m_nonKolmogorov
Flag indicating if non-Kolmogorov PSD parameters are used.
void alpha(const std::vector< realT > &alph)
Set the vector of layer PSD indices.
realT beta_0(const size_t &n)
Return the PSD constant for a single layer.
realT beta(const size_t &n)
Return the PSD normalization for a single layer.
realT fwhm0(realT lam_sci)
realT X_Z(realT k, realT lambda_sci, realT lambda_wfs, realT secZ)
void setupConfig(app::appConfigurator &config)
Setup the configurator to configure this class.
std::vector< realT > m_L_0
The outer scale, in m.
void r_0(const realT &r0, const realT &l0)
Set the value of Fried's parameter and the reference wavelength.
void H(realT nH)
Set the atmospheric scale height.
aoAtmosphere()
Constructor.
std::vector< realT > m_layer_dir
Vector of layer wind directions, in radians.
std::vector< realT > layer_Cn2()
Get the vector of layer strengths.
void l_0(const std::vector< realT > &l0)
Set the vector of layer inner scales.
realT f_g(realT lam_sci)
Get the greenwood frequency at a specified wavelength.
realT m_r_0
Fried's parameter, in m.
void tau_0(realT tau_0, realT lam_sci)
Scale v_wind so that tau_0 has the specified value at the specified wavelength.
realT H()
Get the atmospheric scale height.
bool nonKolmogorov()
Return the value of m_nonKolmogorov.
void setSingleLayer(realT r0, realT lam0, realT L0, realT l0, realT lz, realT vw, realT dir)
Set a single layer model.
realT v_wind()
Get the 5/3 moment weighted mean wind speed.
std::vector< realT > layer_z()
Get the vector layer heights.
void layer_Cn2(const std::vector< realT > &cn2, const realT l0=0)
Set the vector layer strengths, possibly calculating r_0.
realT layer_Cn2(const int n)
Get the strength of a single layer.
realT m_h_obs
Height of the observatory above sea level, in m.
realT alpha(const size_t &n)
Return the PSD index for a single layer.
std::vector< realT > m_l_0
The inner scale of each layer, in m.
realT Y(realT k, realT lam_sci, realT secZ)
The fraction of the turbulence PSD in amplitude after Fresnel propagation.
realT layer_v_wind(const int n)
Get the wind speed of a single layer.
realT f_g()
Get the greenwood frequency at the reference wavelength.
realT z_mean()
Get the weighted mean layer height.
int checkLayers()
Checks if layer vectors have consistent length.
std::vector< realT > m_layer_Cn2
Vector of layer strengths.
std::vector< realT > m_layer_z
Vector of layer heights, in m, above the observatory.
size_t n_layers()
Get the number of layers.
std::vector< realT > beta_0()
Get the vector of PSD constants.
bool m_v_wind_updated
whether or not m_v_wind has been updated after changes
realT r_0()
Get the value of Fried's parameter r_0 at the reference wavelength lam_0.
std::vector< realT > m_layer_v_wind
Vector of layer wind speeds, in m/s.
realT v_wind_mean()
Get the mean wind speed.
void z_mean(const realT &zm)
Set the weighted mean m_z_mean and renormalize the layer heights.
realT tau_0(realT lam_sci)
Get tau_0 at a specified wavelength.
void v_wind(const realT &vw)
Set the weighted mean m_v_wind and renormalize the layer wind speeds.
realT m_lam_0
Wavelength of Fried's parameter, in m.
bool m_z_mean_updated
whether or not m_z_mean has been updated after changes
realT dX(realT k, realT lam_sci, realT lam_wfs)
The differential fraction of the turbulence PSD in phase after Fresnel propagation.
realT layer_z(const size_t n)
Get the height of a single layer.
void update_v_wind()
Recalculate m_v_wind.
#define mxError(esrc, ecode, expl)
This reports an mxlib specific error.
constexpr floatT six_fifths()
Return 6/5 in the specified precision.
#define MXE_SIZEERR
A size was invalid or calculated incorrectly.
Class to manage a set of configurable values, and read their values from config/ini files and the com...
void add(const configTarget &tgt)
Add a configTarget.
bool isSet(const std::string &name, std::unordered_map< std::string, configTarget > &targets)
Check if a target has been set by the configuration.