8#ifndef aoAtmosphere_hpp
9#define aoAtmosphere_hpp
18#include "../../mxlib.hpp"
22#include "../../math/constants.hpp"
24#include "../../app/appConfigurator.hpp"
43template <
typename _realT>
115 realT
r_0(
const realT &lam );
121 void r_0(
const realT &r0,
161 realT
L_0(
const size_t &n );
166 void L_0(
const std::vector<realT> &L0 );
178 realT
l_0(
const size_t &n );
183 void l_0(
const std::vector<realT> &l0 );
219 void alpha(
const std::vector<realT> &alph );
243 void beta(
const std::vector<realT> &bet );
267 void beta_0(
const std::vector<realT> &bet );
282 size_t currentLayer();
284 void currentLayer(
size_t cl );
303 void layer_z(
const std::vector<realT> &layz );
543 realT
f_g( realT lam_sci );
594 template <
typename iosT>
618template <
typename realT>
623template <
typename realT>
626 size_t n = m_L_0.size();
628 if( m_l_0.size() != n )
634 if( m_layer_z.size() != n )
640 if( m_layer_Cn2.size() != n )
646 if( m_layer_dir.size() != n )
652 if( m_layer_v_wind.size() != n )
661template <
typename realT>
667template <
typename realT>
673template <
typename realT>
688template <
typename realT>
694template <
typename realT>
697 return m_layer_Cn2[n];
700template <
typename realT>
706template <
typename realT>
711 realT layer_norm = 0;
713 for(
size_t i = 0; i < m_layer_Cn2.size(); ++i )
715 layer_norm += cn2[i];
718 for(
size_t i = 0; i < m_layer_Cn2.size(); ++i )
719 m_layer_Cn2[i] = m_layer_Cn2[i] / layer_norm;
727 m_v_wind_updated =
false;
728 m_z_mean_updated =
false;
731template <
typename realT>
737template <
typename realT>
743template <
typename realT>
749template <
typename realT>
755template <
typename realT>
761template <
typename realT>
767template <
typename realT>
770 m_nonKolmogorov = nk;
773template <
typename realT>
776 return m_nonKolmogorov;
779template <
typename realT>
782 if( !m_nonKolmogorov )
792template <
typename realT>
795 m_nonKolmogorov =
true;
799template <
typename realT>
805template <
typename realT>
808 if( !m_nonKolmogorov )
819template <
typename realT>
822 m_nonKolmogorov =
true;
826template <
typename realT>
832template <
typename realT>
835 if( !m_nonKolmogorov )
845template <
typename realT>
848 m_nonKolmogorov =
true;
852template <
typename realT>
858template <
typename realT>
861 if( m_nonKolmogorov )
862 return m_alpha.size();
864 return m_layer_Cn2.size();
867template <
typename realT>
873template <
typename realT>
877 m_z_mean_updated =
false;
880template <
typename realT>
886template <
typename realT>
892template <
typename realT>
898template <
typename realT>
904template <
typename realT>
910template <
typename realT>
913 return m_layer_v_wind[n];
916template <
typename realT>
919 return m_layer_v_wind;
922template <
typename realT>
926 m_v_wind_updated =
false;
929template <
typename realT>
932 return m_layer_dir[n];
935template <
typename realT>
941template <
typename realT>
945 m_v_wind_updated =
false;
948template <
typename realT>
951 if( m_v_wind_updated ==
false )
956template <
typename realT>
959 if( m_v_wind_updated ==
false )
964template <
typename realT>
968 if( m_layer_v_wind.size() == 0 || m_layer_Cn2.size() == 0 )
972 m_v_wind_updated =
true;
981 for(
size_t i = 0; i < m_layer_Cn2.size(); ++i )
985 sin( m_layer_dir[i] );
987 cos( m_layer_dir[i] );
993 m_dir_wind = atan( s / c );
997 m_v_wind_updated =
true;
1000template <
typename realT>
1003 if( m_v_wind_updated ==
false )
1006 realT vw_old = m_v_wind;
1011 if( m_layer_v_wind.size() > 0 )
1013 for(
size_t i = 0; i < m_layer_v_wind.size(); ++i )
1015 m_layer_v_wind[i] = m_layer_v_wind[i] * ( vw / vw_old );
1020template <
typename realT>
1023 if( m_z_mean_updated ==
false )
1028template <
typename realT>
1031 if( m_layer_z.size() == 0 || m_layer_Cn2.size() == 0 )
1034 m_z_mean_updated =
true;
1040 for(
size_t i = 0; i < m_layer_Cn2.size(); ++i )
1047 m_z_mean_updated =
true;
1050template <
typename realT>
1053 if( m_z_mean_updated ==
false )
1056 realT zh_old = m_z_mean;
1061 if( m_layer_z.size() > 0 )
1063 for(
size_t i = 0; i < m_layer_z.size(); ++i )
1065 m_layer_z[i] = m_layer_z[i] * ( zm / zh_old );
1070template <
typename realT>
1075 for(
size_t i = 0; i < m_layer_Cn2.size(); ++i )
1077 c += m_layer_Cn2[i] * pow( cos(
math::pi<realT>() * k * k * lam_sci * m_layer_z[i] * secZ ), 2 );
1083template <
typename realT>
1088 for(
size_t i = 0; i < m_layer_Cn2.size(); ++i )
1090 c += m_layer_Cn2[i] * pow( ( cos(
math::pi<realT>() * f * f * lam_sci * m_layer_z[i] ) -
1098template <
typename realT>
1103 for(
size_t i = 0; i < m_layer_Cn2.size(); ++i )
1105 c += m_layer_Cn2[i] * pow( sin(
math::pi<realT>() * k * k * lam_sci * m_layer_z[i] * secZ ), 2 );
1110template <
typename realT>
1115 for(
size_t i = 0; i < m_layer_Cn2.size(); ++i )
1117 c += m_layer_Cn2[i] * pow( ( sin(
math::pi<realT>() * f * f * lam_sci * m_layer_z[i] ) -
1125template <
typename realT>
1128 realT ll2 =
static_cast<realT>( 1 ) / pow( lambda / 1e-6, 2 );
1130 return 1.0 + 8.34213e-5 + 0.0240603 / ( 130.0 - ll2 ) + 0.00015997 / ( 38.9 - ll2 );
1133template <
typename realT>
1137 realT sinZ = sqrt( 1.0 - pow( 1.0 / secZ, 2 ) );
1138 realT tanZ = sinZ * secZ;
1139 realT x0 = ( n_air( lambda_wfs ) - n_air( lambda_i ) ) * m_H * tanZ * secZ;
1142 for(
size_t i = 0; i < m_layer_Cn2.size(); ++i )
1144 x = x0 * ( 1 - exp( ( m_layer_z[i] + m_h_obs ) / m_H ) );
1145 c += m_layer_Cn2[i] * pow( cos(
math::pi<realT>() * k * k * lambda_i * m_layer_z[i] * secZ ), 2 ) *
1152template <
typename realT>
1155 realT r0lam = r_0( lam_sci );
1157 realT fwhm = 0.98 * ( lam_sci / r0lam );
1162template <
typename realT>
1165 realT r0lam = r_0( lam_sci );
1167 realT fwhm = 0.98 * ( lam_sci / r0lam );
1171 fwhm *= sqrt( 1 - 2.183 * pow( r0lam / L_0( 0 ), 0.356 ) );
1176template <
typename realT>
1179 return 0.428 * v_wind() / m_r_0;
1182template <
typename realT>
1188template <
typename realT>
1191 return 0.134 / f_g();
1194template <
typename realT>
1197 return 0.134 / f_g( lam_sci );
1200template <
typename realT>
1207template <
typename realT>
1210 layer_Cn2( { 0.2283, 0.0883, 0.0666, 0.1458, 0.3350, 0.1350 } );
1211 layer_z( { 500, 1000, 2000, 4000, 8000, 16000 } );
1212 layer_v_wind( { 10., 10., 10., 10., 10., 10. } );
1213 layer_dir( { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 } );
1220template <
typename realT>
1223 layer_Cn2( { 0.42, 0.029, 0.062, 0.16, 0.11, 0.10, 0.12 } );
1224 layer_z( { 250., 500., 1000., 2000., 4000., 8000., 16000. } );
1225 layer_v_wind( { 10.0, 10.0, 20.0, 20.0, 25.0, 30.0, 25.0 } );
1226 layer_dir( { 1.05, 1.05, 1.31, 1.31, 1.75, 1.92, 1.75 } );
1228 r_0( 0.16, 0.5e-6 );
1230 L_0( { 25.0, 25.0, 25.0, 25.0, 25.0, 25.0, 25.0 } );
1231 l_0( { 0.0, 0, 0, 0, 0, 0, 0 } );
1236template <
typename realT>
1240 L_0( std::vector<realT>( { L0 } ) );
1241 l_0( std::vector<realT>( { l0 } ) );
1242 layer_Cn2( std::vector<realT>( { 1 } ) );
1243 layer_z( std::vector<realT>( { lz } ) );
1244 layer_v_wind( std::vector<realT>( { vw } ) );
1245 layer_dir( std::vector<realT>( { dir } ) );
1248template <
typename realT>
1249template <
typename iosT>
1252 ios <<
"# Atmosphere Parameters:\n";
1253 ios <<
"# nonKolmogorov = " << std::boolalpha << nonKolmogorov() <<
'\n';
1254 ios <<
"# n_layers = " << n_layers() <<
'\n';
1256 if( !m_nonKolmogorov )
1258 ios <<
"# r_0 = " << r_0() <<
'\n';
1259 ios <<
"# lam_0 = " << lam_0() <<
'\n';
1260 ios <<
"# tau_0 = " << tau_0( lam_0() ) <<
'\n';
1261 ios <<
"# FWHM = " << fwhm( lam_0() ) <<
'\n';
1262 ios <<
"# layer_Cn2 = ";
1263 for(
size_t i = 0; i < n_layers() - 1; ++i )
1264 ios << layer_Cn2()[i] <<
", ";
1265 ios << layer_Cn2()[n_layers() - 1] <<
'\n';
1267 if( m_nonKolmogorov )
1269 ios <<
"# alpha = ";
1270 for(
size_t i = 0; i < n_layers() - 1; ++i )
1271 ios << alpha()[i] <<
", ";
1272 ios << alpha()[n_layers() - 1] <<
'\n';
1274 for(
size_t i = 0; i < n_layers() - 1; ++i )
1275 ios << beta()[i] <<
", ";
1276 ios << beta()[n_layers() - 1] <<
'\n';
1277 ios <<
"# beta_0 = ";
1278 for(
size_t i = 0; i < n_layers() - 1; ++i )
1279 ios << beta_0()[i] <<
", ";
1280 ios << beta_0()[n_layers() - 1] <<
'\n';
1284 for(
size_t i = 0; i < n_layers() - 1; ++i )
1285 ios << L_0()[i] <<
", ";
1286 ios << L_0()[n_layers() - 1] <<
'\n';
1288 for(
size_t i = 0; i < n_layers() - 1; ++i )
1289 ios << l_0()[i] <<
", ";
1290 ios << l_0()[n_layers() - 1] <<
'\n';
1292 ios <<
"# layer_v_wind = ";
1293 for(
size_t i = 0; i < n_layers() - 1; ++i )
1294 ios << layer_v_wind()[i] <<
", ";
1295 ios << layer_v_wind()[n_layers() - 1] <<
'\n';
1296 ios <<
"# layer_dir = ";
1297 for(
size_t i = 0; i < n_layers() - 1; ++i )
1298 ios << layer_dir()[i] <<
", ";
1299 ios << layer_dir()[n_layers() - 1] <<
'\n';
1300 ios <<
"# mean v_wind = " << v_wind() <<
'\n';
1301 ios <<
"# mean dir_wind = " << dir_wind() <<
'\n';
1303 if( !m_nonKolmogorov )
1305 ios <<
"# layer_z = ";
1306 for(
size_t i = 0; i < n_layers() - 1; ++i )
1307 ios << layer_z()[i] <<
", ";
1308 ios << layer_z()[n_layers() - 1] <<
'\n';
1309 ios <<
"# mean z = " << z_mean() <<
'\n';
1310 ios <<
"# h_obs = " << h_obs() <<
'\n';
1311 ios <<
"# H = " << H() <<
'\n';
1317template <
typename realT>
1320 using namespace mx::app;
1322 config.
add(
"atm.r_0",
"",
"atm.r_0", argType::Required,
"atm",
"r_0",
false,
"real",
"Fried's parameter [m]" );
1323 config.
add(
"atm.lam_0",
1331 "The reference wavlength for r_0 [m]" );
1333 "atm.L_0",
"",
"atm.L_0", argType::Required,
"atm",
"L_0",
false,
"vector<real>",
"Layer outer scales [m]" );
1335 "atm.l_0",
"",
"atm.l_0", argType::Required,
"atm",
"l_0",
false,
"vector<real>",
"Layer inner scales [m]" );
1336 config.
add(
"atm.layer_z",
1344 "layer heights [m]" );
1346 "atm.h_obs",
"",
"atm.h_obs", argType::Required,
"atm",
"h_obs",
false,
"real",
"height of observatory [m]" );
1347 config.
add(
"atm.H",
"",
"atm.H", argType::Required,
"atm",
"H",
false,
"real",
"atmospheric scale heights [m]" );
1348 config.
add(
"atm.layer_Cn2",
1356 "Layer Cn^2. Note that this does not set r_0." );
1357 config.
add(
"atm.layer_v_wind",
1365 "Layer wind speeds [m/s]" );
1366 config.
add(
"atm.layer_dir",
1374 "Layer wind directions [rad]" );
1375 config.
add(
"atm.v_wind",
1383 "Mean windspeed (5/3 momement), rescales layer speeds [m/s]" );
1384 config.
add(
"atm.tau_0",
1392 "AO time constant, sets v_wind and rescales layer speeds. [s]" );
1393 config.
add(
"atm.z_mean",
1401 "Mean layer height (5/3 momemnt), rescales layer heights [m/s]" );
1402 config.
add(
"atm.nonKolmogorov",
1404 "atm.nonKolmogorov",
1410 "Set to use a non-Kolmogorov PSD. See alpha and beta." );
1411 config.
add(
"atm.alpha",
1419 "Non-kolmogorov PSD exponent." );
1420 config.
add(
"atm.beta",
1428 "Non-kolmogorov PSD normalization." );
1429 config.
add(
"atm.beta_0",
1437 "Non-kolmogorov PSD constant." );
1440template <
typename realT>
1449 config( m_lam_0,
"atm.lam_0" );
1452 std::vector<realT> lcn2 = m_layer_Cn2;
1453 config( lcn2,
"atm.layer_Cn2" );
1454 if( config.
isSet(
"atm.layer_Cn2" ) )
1458 config( r0,
"atm.r_0" );
1459 if( config.
isSet(
"atm.r_0" ) )
1462 config( m_L_0,
"atm.L_0" );
1464 config( m_l_0,
"atm.l_0" );
1467 std::vector<realT> layz = m_layer_z;
1468 config( layz,
"atm.layer_z" );
1469 if( config.
isSet(
"atm.layer_z" ) )
1472 config( m_h_obs,
"atm.h_obs" );
1473 config( m_H,
"atm.H" );
1476 std::vector<realT> lvw = m_layer_v_wind;
1477 config( lvw,
"atm.layer_v_wind" );
1478 if( config.
isSet(
"atm.layer_v_wind" ) )
1479 layer_v_wind( lvw );
1482 std::vector<realT> ld = m_layer_dir;
1483 config( ld,
"atm.layer_dir" );
1484 if( config.
isSet(
"atm.layer_dir" ) )
1487 realT vw = m_v_wind;
1488 config( vw,
"atm.v_wind" );
1489 if( config.
isSet(
"atm.v_wind" ) )
1493 config( t0,
"atm.tau_0" );
1494 if( config.
isSet(
"atm.tau_0" ) )
1496 std::cerr <<
"setting tau_0 " << t0 <<
"\n";
1497 tau_0( t0, m_lam_0 );
1499 realT zm = m_z_mean;
1500 config( zm,
"atm.z_mean" );
1501 if( config.
isSet(
"atm.z_mean" ) )
1504 config( m_nonKolmogorov,
"atm.nonKolmogorov" );
1506 std::vector<realT> a = m_alpha;
1507 config( a,
"atm.alpha" );
1508 if( config.
isSet(
"atm.alpha" ) )
1511 std::vector<realT> b = m_beta;
1512 config( b,
"atm.beta" );
1513 if( config.
isSet(
"atm.beta" ) )
1516 std::vector<realT> b0 = m_beta_0;
1517 config( b0,
"atm.beta_0" );
1518 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.
@ sizeerr
A size was invalid or calculated incorrectly.
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.
constexpr floatT six_fifths()
Return 6/5 in the specified precision.
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.