mxlib
c++ tools for analyzing astronomical data and other tasks by Jared R. Males. [git repo]
Loading...
Searching...
No Matches
aoAtmosphere.hpp
Go to the documentation of this file.
1/** \file aoAtmosphere.hpp
2 * \author Jared R. Males (jaredmales@gmail.com)
3 * \brief Provides a class to specify atmosphere parameters.
4 * \ingroup mxAO_files
5 *
6 */
7
8#ifndef aoAtmosphere_hpp
9#define aoAtmosphere_hpp
10
11#include <iostream>
12#include <numeric>
13#include <cmath>
14#include <cstdlib>
15#include <vector>
16#include <algorithm>
17
18#include "../../mxlib.hpp"
19
20#include "aoConstants.hpp"
21
22#include "../../math/constants.hpp"
23
24#include "../../app/appConfigurator.hpp"
25
26namespace mx
27{
28namespace AO
29{
30namespace analysis
31{
32
33/// A class to specify atmosphere parameters and perform related calculations.
34/**
35 * \todo layer outer scales need work
36 * \todo layer PSD params isn't finished. Need to push that to PSD itself, and manage things like wavelength
37 * dependence.
38 *
39 * \tparam realT is the real floating type in which all calculations are performed.
40 *
41 * \ingroup mxAOAnalytic
42 */
43template <typename _realT>
45{
46 public:
47 typedef _realT realT; ///< The real floating type in which all calculations are performed.
48
49 /// Constructor
51
52 protected:
53 realT m_r_0; ///< Fried's parameter, in m
54
55 realT m_lam_0{ 0.5e-6 }; ///< Wavelength of Fried's parameter, in m
56
57 std::vector<realT> m_layer_Cn2; ///< Vector of layer strengths.
58
59 std::vector<realT> m_L_0; ///< The outer scale, in m
60
61 std::vector<realT> m_l_0; ///< The inner scale of each layer, in m
62
63 bool m_nonKolmogorov{ false }; ///< Flag indicating if non-Kolmogorov PSD parameters are used.
64
65 std::vector<realT> m_beta{ 1 }; ///< The PSD normalization when in non-Kolmogorov mode.
66
67 std::vector<realT> m_alpha{ 0 }; ///< The PSD exponent when in non-Kolmogorov mode.
68
69 std::vector<realT> m_beta_0{ 0 }; ///< The PSD constant when in non-Kolmogorov mode.
70
71 std::vector<realT> m_layer_z; ///< Vector of layer heights, in m, above the observatory.
72
73 realT m_h_obs{ 0 }; ///< Height of the observatory above sea level, in m.
74
75 realT m_H{ 8000 }; ///< The atmospheric scale height, in m.
76
77 std::vector<realT> m_layer_v_wind; ///< Vector of layer wind speeds, in m/s.
78
79 std::vector<realT> m_layer_dir; ///< Vector of layer wind directions, in radians.
80
81 bool m_v_wind_updated{ false }; ///< whether or not m_v_wind has been updated after changes
82
83 realT m_v_wind; ///< \f$ C_n^2 \f$ averaged windspeed
84
85 realT m_dir_wind; ///< \f$ C_n^2 \f$ averaged direction
86
87 bool m_z_mean_updated{ false }; ///< whether or not m_z_mean has been updated after changes
88
89 realT m_z_mean; ///< \f$ C_n^2 \f$ averaged layer height
90
91 /// Checks if layer vectors have consistent length.
92 /**
93 * \returns 0 if all layer vectors are the same length
94 * \returns -1 if not, and prints an error.
95 */
97
98 public:
99 /** \name PSD Parameters
100 * @{
101 */
102
103 /// Get the value of Fried's parameter r_0 at the reference wavelength lam_0.
104 /**
105 * \returns the curret value of m_r_0, in m.
106 */
107 realT r_0();
108
109 /// Get the value of Fried's parameter r_0 at the specified wavelength.
110 /**
111 * \note This does not set the value of r_0.
112 *
113 * \returns the current value of m_r_0 * pow(lam, 6/5), in m.
114 */
115 realT r_0( const realT &lam /**< [in] the wavelength, in m, at which to calculate r_0*/ );
116
117 /// Set the value of Fried's parameter and the reference wavelength.
118 /** If the provided reference wavelength is <=0, then 0.5 microns is used.
119 *
120 */
121 void r_0( const realT &r0, ///< [in] is the new value of r_0, m
122 const realT &l0 ///< [in] is the new value of lam_0 (in m), if 0 then 0.5e-6 is the default.
123 );
124
125 /// Get the current value of the reference wavelength.
126 /** This is the wavelength at which r_0 is specified.
127 *
128 * \returns the current value of m_lam_0, in m.
129 */
130 realT lam_0();
131
132 /// Get the strength of a single layer.
133 /**
134 * \returns the value of m_layer_Cn2[n].
135 */
136 realT layer_Cn2( const int n /**< [in] specifies the layer. */ );
137
138 /// Get the vector of layer strengths.
139 /**
140 * \returns a copy of the vector of layer strengths: m_layer_Cn2.
141 */
142 std::vector<realT> layer_Cn2();
143
144 /// Set the vector layer strengths, possibly calculating r_0.
145 /**
146 * If a reference wavelength is specified (l0 > 0), then r_0 is set from the layer strengths
147 * according to
148 *
149 * Regardless of what units the strengths are specified in, they are stored normalized so that
150 * \f$ \sum_n C_n^2 = 1 \f$.
151 *
152 */
153 void layer_Cn2( const std::vector<realT> &cn2, ///< [in] is a vector containing the layer strengths
154 const realT l0 = 0 ///< [in] [optional] if l0 > 0, then r_0 is set from the layer strengths.
155 );
156
157 /// Get the value of the outer scale for a single layer.
158 /**
159 * \returns the current value of m_L_0[n], in m.
160 */
161 realT L_0( const size_t &n );
162
163 /// Set the vector of layer outer scales.
164 /**
165 */
166 void L_0( const std::vector<realT> &L0 /**< [in] is the new vector of outer scales, in m */ );
167
168 /// Get the vector of outer scales.
169 /**
170 * \returns a copy of the vector of layer outer scales, in m
171 */
172 std::vector<realT> L_0();
173
174 /// Get the value of the inner scale for a single layer.
175 /**
176 * \returns the current value of m_l_0[n], in m.
177 */
178 realT l_0( const size_t &n );
179
180 /// Set the vector of layer inner scales.
181 /**
182 */
183 void l_0( const std::vector<realT> &l0 /**< [in] is the new vector of inner scales, in m*/ );
184
185 /// Get the vector of inner scales.
186 /**
187 * \returns a copy of the vector of layer inner scales, in m
188 */
189 std::vector<realT> l_0();
190
191 /// Set the value of m_nonKolmogorov
192 /** This flag indicates if non-Kolmogorov turbulence is being modeled.
193 */
194 void nonKolmogorov( const bool &nk /**< [in] the value of m_nonKolmogorov*/ );
195
196 /// Return the value of m_nonKolmogorov
197 /** This flag indicates if non-Kolmogorov turbulence is being modeled.
198 *
199 * \returns the current value of m_nonKolmogorov
200 */
202
203 /// Return the PSD index for a single layer.
204 /** Satifies the requirements of psdParamsT.
205 *
206 * If m_nonKolmogorov is false, this returns
207 * \[
208 \alpha = \frac{11}{3}
209 \]
210 * Otherwise it returns the current value of m_alpha[n].
211 *
212 * \returns the PSD index.
213 */
214 realT alpha( const size_t &n );
215
216 /// Set the vector of layer PSD indices.
217 /**
218 */
219 void alpha( const std::vector<realT> &alph /**< [in] is the new vector of PSD indices*/ );
220
221 /// Get the vector of PSD indices.
222 /**
223 * \returns a copy of the vector of PSD indices
224 */
225 std::vector<realT> alpha();
226
227 /// Return the PSD normalization for a single layer.
228 /** Satifies the requirements of psdParamsT.
229 *
230 * If m_nonKolmogorov is false, this returns
231 * \[
232 \beta = \frac{0.0218}{r_0^{5/3}}
233 \]
234 * Otherwise it returns the current value of m_beta[n].
235 *
236 * \returns the PSD normalization.
237 */
238 realT beta( const size_t &n );
239
240 /// Set the vector of layer PSD normalizations.
241 /**
242 */
243 void beta( const std::vector<realT> &bet /**< [in] is the new vector of PSD normalizations*/ );
244
245 /// Get the vector of PSD normalizations.
246 /**
247 * \returns a copy of the vector of PSD normalizations
248 */
249 std::vector<realT> beta();
250
251 /// Return the PSD constant for a single layer.
252 /** Satifies the requirements of psdParamsT.
253 *
254 * If m_nonKolmogorov is false, this returns
255 * \[
256 \beta_0 = 0
257 \]
258 * Otherwise it returns the current value of m_beta_0[n].
259 *
260 * \returns the PSD constant.
261 */
262 realT beta_0( const size_t &n );
263
264 /// Set the vector of layer PSD constants.
265 /**
266 */
267 void beta_0( const std::vector<realT> &bet /**< [in] is the new vector of PSD constants*/ );
268
269 /// Get the vector of PSD constants.
270 /**
271 * \returns a copy of the vector of PSD constants
272 */
273 std::vector<realT> beta_0();
274
275 /// Get the number of layers
276 /**
277 * \returns the size of the m_layer_Cn2 vector if m_nonKolmogrov==false
278 * \returns the size of the m_alpha vector if m_nonKolmogrov==true
279 */
280 size_t n_layers();
281
282 size_t currentLayer();
283
284 void currentLayer( size_t cl );
285
286 /// @}
287
288 /// Get the height of a single layer.
289 /**
290 * \returns the height of layer n, in m.
291 */
292 realT layer_z( const size_t n /**< [in] specifies the layer. */ );
293
294 /// Get the vector layer heights.
295 /**
296 * \returns a copy of the vector of layer heights:m_layer_z, in m.
297 */
298 std::vector<realT> layer_z();
299
300 /// Set the vector of layer heights.
301 /**
302 */
303 void layer_z( const std::vector<realT> &layz /**< [in] new vector of layer heights, in m. */ );
304
305 /// Get the height of the observatory.
306 /**
307 * \return the current value of m_h_obs, in m.
308 */
309 realT h_obs();
310
311 /// Set the height of the observatory.
312 /**
313 */
314 void h_obs( realT nh /**< [in] the new height of the observatory [m] */ );
315
316 /// Get the atmospheric scale height.
317 /**
318 * \returns the current value of m_H, in m.
319 */
320 realT H();
321
322 /// Set the atmospheric scale height.
323 /**
324 */
325 void H( realT nH /**< [in] the new value of m_H [m] */ );
326
327 /// Get the wind speed of a single layer.
328 /**
329 * \returns the value of m_layer_v_wind[n].
330 */
331 realT layer_v_wind( const int n /**< [in] specifies the layer. */ );
332
333 /// Get the vector of layer windspeeds
334 /**
335 * \returns a copy of the vector of layer windspeeds: m_layer_v_wind.
336 */
337 std::vector<realT> layer_v_wind();
338
339 /// Set the vector of layer windspeeds.
340 /**
341 * \param
342 */
343 void layer_v_wind( const std::vector<realT> &spd /**< [in] the new vector, which is copied to m_layer_v_wind. */ );
344
345 /// Get the wind direction of a single layer.
346 /**
347 * \returns the value of m_layer_dir[n], which is the wind direction in that layer in radians.
348 */
349 realT layer_dir( const int n /**< [in] specifies the layer. */ );
350
351 /// Get the vector of layer wind directions
352 /**
353 * \returns a copy of the vector of layer wind directions: m_layer_dir.
354 */
355 std::vector<realT> layer_dir();
356
357 /// Set the vector of layer wind directions.
358 /**
359 * \param
360 */
361 void layer_dir( const std::vector<realT>
362 &d /**< [in] the new vector of wind directions in radians, which is copied to m_layer_dir. */ );
363
364 /// Get the 5/3 moment weighted mean wind speed
365 /** Returns the weighted mean wind speed according to the 5/3's turbulence moment. This is defined as
366 *
367 \f[
368 \bar{v} = \left[\sum_i C_N^2(z_i) v_i^{5/3} \right]^{3/5}
369 \f]
370 * See Hardy (1998) Section 3.3.6. \cite hardy_1998.
371 *
372 * This is only re-calculated if either m_layer_Cn2 or m_layer_v_wind is changed, otherwise this just
373 * returns the value of m_v_wind.
374 *
375 * \returns the current value of m_v_wind.
376 */
377 realT v_wind();
378
379 /// Get the mean wind speed
380 /** Returns the weighted mean wind speed according to the 5/3's turbulence moment. This is defined as
381 *
382 \f[
383 \bar{v} = \sum_i C_N^2(z_i) v_i
384 \f]
385 * See Hardy (1998) Section 3.3.6. \cite hardy_1998.
386 *
387 * This is only re-calculated if either m_layer_Cn2 or m_layer_v_wind is changed, otherwise this just
388 * returns the value of m_v_wind.
389 *
390 * \returns the current value of m_v_wind.
391 */
393
394 /// Get the mean-squared wind speed
396
397 realT v_max()
398 {
399 auto max = std::max_element( std::begin( m_layer_v_wind ), std::end( m_layer_v_wind ) );
400
401 return *max;
402 }
403
404 /// Get the weighted mean wind direction
405 /** Returns the weighted mean wind direction according to the 5/3's turbulence moment. This is defined as
406 *
407 \f[
408 \bar{\theta} = \left[\sum_i C_N^2(z_i) \theta_i^{5/3} \right]^{3/5}
409 \f]
410 * See Hardy (1998) Section 3.3.6. \cite hardy_1998.
411 *
412 * This is only re-calculated if either m_layer_Cn2 or m_layer_v_wind is changed, otherwise this just
413 * returns the value of m_dir_wind.
414 *
415 * \returns the current value of m_dir_wind.
416 */
417 realT dir_wind();
418
419 protected:
420 /// Recalculate m_v_wind
421 /** Called by v_wind() whenever m_v_wind_updated is true.
422 *
423 * \todo handle dir_wind averaging across 0/2pi
424 */
426
427 public:
428 /// Set the weighted mean m_v_wind and renormalize the layer wind speeds
429 /** Calling this function changes the values of m_layer_v_wind so that the
430 * Layer averaged 5/3 \f$C_n^2\f$ moment of wind speed is the new value specified by vw.
431 *
432 */
433 void v_wind( const realT &vw /**< [in] the new value of m_v_wind. */ );
434
435 /// Get the weighted mean layer height
436 /** Returns the weighted layer height according to the 5/3's turbulence moment. This is defined as
437 \f[
438 \bar{z} = \left[\sum_i C_N^2(z_i) z_i^{5/3} \right]^{3/5}
439 \f]
440 * See Hardy (1998) Section 3.3.6 and 3.7.2. \cite hardy_1998.
441 *
442 * This is only re-calculated if either m_layer_Cn2 orm_layer_z is changed, otherwise this just
443 * returns the value of m_z_mean.
444 *
445 * \returns the current value of m_z_mean.
446 */
447 realT z_mean();
448
449 protected:
450 /// Recalculate m_z_mean
451 /** Called by z_mean() whenever m_z_mean_updated is true.
452 */
454
455 public:
456 /// Set the weighted mean m_z_mean and renormalize the layer heights
457 /** Calling this function changes the values ofm_layer_z so that the
458 * Layer averaged 5/3 \f$C_n^2\f$ moment of the height is the new value specified.
459 *
460 */
461 void z_mean( const realT &zm /**< [in] is the new value of m_v_wind. */ );
462
463 /// The fraction of the turbulence PSD in phase after Fresnel propagation.
464 /** See Equation (14) of Guyon (2005) \cite guyon_2005.
465 *
466 * \returns the value of the X function.
467 */
468 realT X( realT k, ///< [in] the spatial frequency, in inverse meters.
469 realT lam_sci, ///< [in] is the science observation wavelength.
470 realT secZ ///< [in] is the secant of the zenith distance.
471 );
472
473 /// The differential fraction of the turbulence PSD in phase after Fresnel propagation.
474 /** See Equation (25) of Guyon (2005) \cite guyon_2005.
475 *
476 * \returns the value of the dX function.
477 */
478 realT dX( realT k, ///< [in] the spatial frequency, in inverse meters.
479 realT lam_sci, ///< [in] is the science observation wavelength.
480 realT lam_wfs ///< [in] is the wavefront sensor wavelength.
481 );
482
483 /// The fraction of the turbulence PSD in amplitude after Fresnel propagation.
484 /** See Equation (15) of Guyon (2005) \cite guyon_2005.
485 *
486 * \returns the value of the Y function.
487 */
488 realT Y( realT k, ///< [in] the spatial frequency, in inverse meters.
489 realT lam_sci, ///< [in] is the science observation wavelength.
490 realT secZ ///< [in] is the secant of the zenith distance.
491 );
492
493 /// The differential fraction of the turbulence PSD in amplitude after Fresnel propagation.
494 /** See Equation (27) of Guyon (2005) \cite guyon_2005.
495 *
496 * \returns the value of the dY function.
497 */
498 realT dY( realT k, ///< [in] the spatial frequency, in inverse meters.
499 realT lam_sci, ///< [in] is the science observation wavelength.
500 realT lam_wfs ///< [in] is the wavefront sensor wavelength.
501 );
502
503 realT n_air( realT lam /**< [in]The wavelength*/ );
504
505 realT X_Z( realT k, ///< [in] the spatial frequency, in inverse meters
506 realT lambda_sci, ///< [in] is the science observation wavelength.
507 realT lambda_wfs, ///< [in] is the wavefront sensor wavelength.
508 realT secZ ///< [in] is the secant of the zenith distance.
509 );
510
511 /// Calculate the full-width at half-maximum of a seeing limited image for this atmosphere for a small telescope
512 /// (ignoring L_0)
513 /** Calculate the FWHM of a seeing limited image with the current parameters according to Floyd et al. (2010) \cite
514 floyd_2010 \f[ \epsilon_0 = 0.98\frac{\lambda_{sci}}{r_0(\lambda_sci)}. \f]
515 *
516 * \returns the value of the FWHM for the current atmosphere parameters.
517 */
518 realT fwhm0( realT lam_sci /**< [in] the wavelength of the science observation. */ );
519
520 /// Calculate the full-width at half-maximum of a seeing limited image for this atmosphere for a large telescope
521 /// (including L_0)
522 /** Calculate the FWHM of a seeing limited image with the current parameters according to Floyd et al. (2010) \cite
523 floyd_2010 \f[ \epsilon_0 = 0.98\frac{\lambda_{sci}}{r_0(\lambda_sci)}. \f]
524 * If there is an outer scale (_L_0 > 0), then a correction is applied according to Tokovinin (2002) \cite
525 tokovinin_2002 \f[ \left( \frac{\epsilon_{vK}}{\epsilon_0}\right)^2 = 1 - 2.183\left(
526 \frac{r_0(\lambda_{sci}}{L_0}\right)^{0.356} \f]
527 *
528 *
529 * \returns the value of the FWHM (\f$ \epsilon_{0/vK} \f$) for the current atmosphere parameters.
530 */
531 realT fwhm( realT lam_sci /**< [in] the wavelength of the science observation. */ );
532
533 /// Get the greenwood frequency at the reference wavelength
534 /**
535 * \todo derive full value of the constant
536 */
537 realT f_g();
538
539 /// Get the greenwood frequency at a specified wavelength
540 /**
541 *
542 */
543 realT f_g( realT lam_sci /**< [in] the wavelength of the science observation. */ );
544
545 /// Get tau_0 at the reference wavelength
546 /**
547 * \todo derive full value of the constant
548 */
549 realT tau_0();
550
551 /// Get tau_0 at a specified wavelength.
552 /**
553 *
554 */
555 realT tau_0( realT lam_sci /**< [in] the wavelength of the science observation. */ );
556
557 /// Scale v_wind so that tau_0 has the specified value at the specified wavelength.
558 /** Does not modify r_0.
559 */
560 void tau_0( realT tau_0, ///< [in] the desired tau_0
561 realT lam_sci ///< [in] the wavelength of the science observation.
562 );
563
564 /// Load the default atmosphere model from Guyon (2005).
565 /** Sets the parameters from Table 4 of Guyon (2005) \cite guyon_2005.
566 */
568
569 /// Load parameters corresponding to the median atmosphere of the GMT site survey at LCO.
570 /**
571 */
572 void loadLCO();
573
574 /// Set a single layer model.
575 /** Sets all layer vectors to size=1 and populates their fields based on these arguments.
576 *
577 */
578 void setSingleLayer( realT r0, ///< [in] is the new value of r_0
579 realT lam0, ///< [in] is the new value of lam_0, if 0 then 0.5 microns is the default.
580 realT L0, ///< [in] the new outer scale
581 realT l0, ///< [in] the new inner scale
582 realT lz, ///< [in] the layer height
583 realT vw, ///< [in] the layer wind-speed
584 realT dir ///< [in] the layer wind direction.
585 );
586
587 /// Output current parameters to a stream
588 /** Prints a formatted list of all current parameters.
589 *
590 * \tparam iosT is a std::ostream-like type.
591 *
592 * \todo update for new vector components (L_0, etc.)
593 */
594 template <typename iosT>
595 iosT &dumpAtmosphere( iosT &ios /**< [in] a std::ostream-like stream. */ );
596
597 /// \name mx::application support
598 /** @{
599 */
600
601 /// Setup the configurator to configure this class
602 /**
603 * Tests:
604 * - Loading aoAtmosphere config settings \ref tests_ao_analysis_aoAtmosphere_config "[test doc]"
605 */
606 void setupConfig( app::appConfigurator &config /**< [in] the app::configurator object*/ );
607
608 /// Load the configuration of this class from a configurator
609 /**
610 * Tests:
611 * - Loading aoAtmosphere config settings \ref tests_ao_analysis_aoAtmosphere_config "[test doc]"
612 */
613 void loadConfig( app::appConfigurator &config /**< [in] the app::configurator object*/ );
614
615 /// @}
616};
617
618template <typename realT>
622
623template <typename realT>
625{
626 size_t n = m_L_0.size();
627
628 if( m_l_0.size() != n )
629 {
630 internal::mxlib_error_report(error_t::sizeerr,"mismatched layer numbers (inner scale vs. outer scale)");
631 return -1;
632 }
633
634 if( m_layer_z.size() != n )
635 {
636 internal::mxlib_error_report(error_t::sizeerr,"mismatched layer numbers (layer_z vs. outer scale)");
637 return -1;
638 }
639
640 if( m_layer_Cn2.size() != n )
641 {
642 internal::mxlib_error_report(error_t::sizeerr,"mismatched layer numbers (layer_Cn2 vs. outer scale)" );
643 return -1;
644 }
645
646 if( m_layer_dir.size() != n )
647 {
648 internal::mxlib_error_report(error_t::sizeerr,"mismatched layer numbers (layer_dir vs. outer scale)");
649 return -1;
650 }
651
652 if( m_layer_v_wind.size() != n )
653 {
654 internal::mxlib_error_report(error_t::sizeerr,"mismatched layer numbers (layer_v_wind vs. outer scale)");
655 return -1;
656 }
657
658 return 0;
659}
660
661template <typename realT>
663{
664 return m_r_0;
665}
666
667template <typename realT>
669{
670 return m_r_0 * pow( lam / m_lam_0, math::six_fifths<realT>() );
671}
672
673template <typename realT>
674void aoAtmosphere<realT>::r_0( const realT &r0, const realT &l0 )
675{
676 m_r_0 = r0;
677
678 if( l0 > 0 )
679 {
680 m_lam_0 = l0;
681 }
682 else
683 {
684 m_lam_0 = 0.5e-6;
685 }
686}
687
688template <typename realT>
690{
691 return m_lam_0;
692}
693
694template <typename realT>
696{
697 return m_layer_Cn2[n];
698}
699
700template <typename realT>
702{
703 return m_layer_Cn2;
704}
705
706template <typename realT>
707void aoAtmosphere<realT>::layer_Cn2( const std::vector<realT> &cn2, const realT l0 )
708{
709 m_layer_Cn2 = cn2;
710
711 realT layer_norm = 0;
712
713 for( size_t i = 0; i < m_layer_Cn2.size(); ++i )
714 {
715 layer_norm += cn2[i];
716 }
717
718 for( size_t i = 0; i < m_layer_Cn2.size(); ++i )
719 m_layer_Cn2[i] = m_layer_Cn2[i] / layer_norm;
720
721 if( l0 > 0 )
722 {
723 m_r_0 = 1.0 / pow( layer_norm * 5.520e13, math::three_fifths<realT>() );
724 m_lam_0 = l0;
725 }
726
727 m_v_wind_updated = false;
728 m_z_mean_updated = false;
729}
730
731template <typename realT>
733{
734 return m_L_0[n];
735}
736
737template <typename realT>
738void aoAtmosphere<realT>::L_0( const std::vector<realT> &L_0 )
739{
740 m_L_0 = L_0;
741}
742
743template <typename realT>
744std::vector<realT> aoAtmosphere<realT>::L_0()
745{
746 return m_L_0;
747}
748
749template <typename realT>
751{
752 return m_l_0[n];
753}
754
755template <typename realT>
756void aoAtmosphere<realT>::l_0( const std::vector<realT> &l_0 )
757{
758 m_l_0 = l_0;
759}
760
761template <typename realT>
762std::vector<realT> aoAtmosphere<realT>::l_0()
763{
764 return m_l_0;
765}
766
767template <typename realT>
769{
770 m_nonKolmogorov = nk;
771}
772
773template <typename realT>
775{
776 return m_nonKolmogorov;
777}
778
779template <typename realT>
781{
782 if( !m_nonKolmogorov )
783 {
785 }
786 else
787 {
788 return m_alpha[n];
789 }
790}
791
792template <typename realT>
793void aoAtmosphere<realT>::alpha( const std::vector<realT> &alph )
794{
795 m_nonKolmogorov = true;
796 m_alpha = alph;
797}
798
799template <typename realT>
800std::vector<realT> aoAtmosphere<realT>::alpha()
801{
802 return m_alpha;
803}
804
805template <typename realT>
807{
808 if( !m_nonKolmogorov )
809 {
810 return constants::a_PSD<realT>() * pow( m_r_0, -math::five_thirds<realT>() );
811 ;
812 }
813 else
814 {
815 return m_beta[n];
816 }
817}
818
819template <typename realT>
820void aoAtmosphere<realT>::beta( const std::vector<realT> &bet )
821{
822 m_nonKolmogorov = true;
823 m_beta = bet;
824}
825
826template <typename realT>
827std::vector<realT> aoAtmosphere<realT>::beta()
828{
829 return m_beta;
830}
831
832template <typename realT>
834{
835 if( !m_nonKolmogorov )
836 {
837 return 0;
838 }
839 else
840 {
841 return m_beta_0[n];
842 }
843}
844
845template <typename realT>
846void aoAtmosphere<realT>::beta_0( const std::vector<realT> &bet )
847{
848 m_nonKolmogorov = true;
849 m_beta_0 = bet;
850}
851
852template <typename realT>
853std::vector<realT> aoAtmosphere<realT>::beta_0()
854{
855 return m_beta_0;
856}
857
858template <typename realT>
860{
861 if( m_nonKolmogorov )
862 return m_alpha.size();
863 else
864 return m_layer_Cn2.size();
865}
866
867template <typename realT>
869{
870 return m_layer_z[n];
871}
872
873template <typename realT>
874void aoAtmosphere<realT>::layer_z( const std::vector<realT> &z )
875{
876 m_layer_z = z;
877 m_z_mean_updated = false;
878}
879
880template <typename realT>
882{
883 return m_layer_z;
884}
885
886template <typename realT>
888{
889 return m_h_obs;
890}
891
892template <typename realT>
894{
895 m_h_obs = nh;
896}
897
898template <typename realT>
900{
901 return m_H;
902}
903
904template <typename realT>
906{
907 m_H = nH;
908}
909
910template <typename realT>
912{
913 return m_layer_v_wind[n];
914}
915
916template <typename realT>
918{
919 return m_layer_v_wind;
920}
921
922template <typename realT>
923void aoAtmosphere<realT>::layer_v_wind( const std::vector<realT> &v )
924{
925 m_layer_v_wind = v;
926 m_v_wind_updated = false;
927}
928
929template <typename realT>
931{
932 return m_layer_dir[n];
933}
934
935template <typename realT>
937{
938 return m_layer_dir;
939}
940
941template <typename realT>
942void aoAtmosphere<realT>::layer_dir( const std::vector<realT> &dir )
943{
944 m_layer_dir = dir;
945 m_v_wind_updated = false;
946}
947
948template <typename realT>
950{
951 if( m_v_wind_updated == false )
952 update_v_wind();
953 return m_v_wind;
954}
955
956template <typename realT>
958{
959 if( m_v_wind_updated == false )
960 update_v_wind();
961 return m_dir_wind;
962}
963
964template <typename realT>
966{
967
968 if( m_layer_v_wind.size() == 0 || m_layer_Cn2.size() == 0 )
969 {
970 m_v_wind = 0;
971 m_dir_wind = 0;
972 m_v_wind_updated = true;
973 return;
974 }
975
976 m_v_wind = 0;
977
978 realT s = 0;
979 realT c = 0;
980
981 for( size_t i = 0; i < m_layer_Cn2.size(); ++i )
982 {
983 m_v_wind += m_layer_Cn2[i] * pow( m_layer_v_wind[i], math::five_thirds<realT>() );
984 s += pow( m_layer_v_wind[i], math::five_thirds<realT>() ) *
985 sin( m_layer_dir[i] ); // pow( sin(m_layer_dir[i]), math::five_thirds<realT>() );
986 c += pow( m_layer_v_wind[i], math::five_thirds<realT>() ) *
987 cos( m_layer_dir[i] ); // pow( cos(m_layer_dir[i]), math::five_thirds<realT>() );
988 }
989
990 m_v_wind = pow( m_v_wind, math::three_fifths<realT>() );
991
992 // m_dir_wind = atan(pow(s, math::three_fifths<realT>()) / pow(c, math::three_fifths<realT>()));
993 m_dir_wind = atan( s / c );
994 if( m_dir_wind < 0 )
995 m_dir_wind += math::pi<realT>();
996
997 m_v_wind_updated = true;
998}
999
1000template <typename realT>
1002{
1003 if( m_v_wind_updated == false )
1004 update_v_wind();
1005
1006 realT vw_old = m_v_wind;
1007
1008 m_v_wind = vw;
1009
1010 // Now update the layers if needed
1011 if( m_layer_v_wind.size() > 0 )
1012 {
1013 for( size_t i = 0; i < m_layer_v_wind.size(); ++i )
1014 {
1015 m_layer_v_wind[i] = m_layer_v_wind[i] * ( vw / vw_old );
1016 }
1017 }
1018}
1019
1020template <typename realT>
1022{
1023 if( m_z_mean_updated == false )
1024 update_z_mean();
1025 return m_z_mean;
1026}
1027
1028template <typename realT>
1030{
1031 if( m_layer_z.size() == 0 || m_layer_Cn2.size() == 0 )
1032 {
1033 m_z_mean = 0;
1034 m_z_mean_updated = true;
1035 return;
1036 }
1037
1038 m_z_mean = 0;
1039
1040 for( size_t i = 0; i < m_layer_Cn2.size(); ++i )
1041 {
1042 m_z_mean += m_layer_Cn2[i] * pow( m_layer_z[i], math::five_thirds<realT>() );
1043 }
1044
1045 m_z_mean = pow( m_z_mean, math::three_fifths<realT>() );
1046
1047 m_z_mean_updated = true;
1048}
1049
1050template <typename realT>
1052{
1053 if( m_z_mean_updated == false )
1054 update_z_mean();
1055
1056 realT zh_old = m_z_mean;
1057
1058 m_z_mean = zm;
1059
1060 // Now update the layers if needed
1061 if( m_layer_z.size() > 0 )
1062 {
1063 for( size_t i = 0; i < m_layer_z.size(); ++i )
1064 {
1065 m_layer_z[i] = m_layer_z[i] * ( zm / zh_old );
1066 }
1067 }
1068}
1069
1070template <typename realT>
1072{
1073 realT c = 0;
1074
1075 for( size_t i = 0; i < m_layer_Cn2.size(); ++i )
1076 {
1077 c += m_layer_Cn2[i] * pow( cos( math::pi<realT>() * k * k * lam_sci * m_layer_z[i] * secZ ), 2 );
1078 }
1079
1080 return c;
1081}
1082
1083template <typename realT>
1085{
1086 realT c = 0;
1087
1088 for( size_t i = 0; i < m_layer_Cn2.size(); ++i )
1089 {
1090 c += m_layer_Cn2[i] * pow( ( cos( math::pi<realT>() * f * f * lam_sci * m_layer_z[i] ) -
1091 cos( math::pi<realT>() * f * f * lam_wfs * m_layer_z[i] ) ),
1092 2 );
1093 }
1094
1095 return c;
1096}
1097
1098template <typename realT>
1100{
1101 realT c = 0;
1102
1103 for( size_t i = 0; i < m_layer_Cn2.size(); ++i )
1104 {
1105 c += m_layer_Cn2[i] * pow( sin( math::pi<realT>() * k * k * lam_sci * m_layer_z[i] * secZ ), 2 );
1106 }
1107 return c;
1108}
1109
1110template <typename realT>
1112{
1113 realT c = 0;
1114
1115 for( size_t i = 0; i < m_layer_Cn2.size(); ++i )
1116 {
1117 c += m_layer_Cn2[i] * pow( ( sin( math::pi<realT>() * f * f * lam_sci * m_layer_z[i] ) -
1118 sin( math::pi<realT>() * f * f * lam_wfs * m_layer_z[i] ) ),
1119 2 );
1120 }
1121
1122 return c;
1123}
1124
1125template <typename realT>
1127{
1128 realT ll2 = static_cast<realT>( 1 ) / pow( lambda / 1e-6, 2 );
1129
1130 return 1.0 + 8.34213e-5 + 0.0240603 / ( 130.0 - ll2 ) + 0.00015997 / ( 38.9 - ll2 );
1131}
1132
1133template <typename realT>
1134realT aoAtmosphere<realT>::X_Z( realT k, realT lambda_i, realT lambda_wfs, realT secZ )
1135{
1136 realT c = 0;
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;
1140 realT x;
1141
1142 for( size_t i = 0; i < m_layer_Cn2.size(); ++i )
1143 {
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 ) *
1146 pow( sin( math::pi<realT>() * x * k * cos( 0. * 3.14 / 180. ) ), 2 );
1147 }
1148
1149 return 4 * c;
1150}
1151
1152template <typename realT>
1154{
1155 realT r0lam = r_0( lam_sci );
1156
1157 realT fwhm = 0.98 * ( lam_sci / r0lam );
1158
1159 return fwhm;
1160}
1161
1162template <typename realT>
1164{
1165 realT r0lam = r_0( lam_sci );
1166
1167 realT fwhm = 0.98 * ( lam_sci / r0lam );
1168
1169 ///\todo this needs to handle layers with different L_0
1170 if( L_0( 0 ) > 0 )
1171 fwhm *= sqrt( 1 - 2.183 * pow( r0lam / L_0( 0 ), 0.356 ) );
1172
1173 return fwhm;
1174}
1175
1176template <typename realT>
1178{
1179 return 0.428 * v_wind() / m_r_0;
1180}
1181
1182template <typename realT>
1184{
1185 return 0.428 * pow( m_lam_0 / lam_sci, math::six_fifths<realT>() ) * v_wind() / m_r_0;
1186}
1187
1188template <typename realT>
1190{
1191 return 0.134 / f_g();
1192}
1193
1194template <typename realT>
1196{
1197 return 0.134 / f_g( lam_sci );
1198}
1199
1200template <typename realT>
1202{
1203 realT vw = ( 0.134 / tau_0 ) / 0.428 * m_r_0 * pow( lam_sci / m_lam_0, math::six_fifths<realT>() );
1204 v_wind( vw );
1205}
1206
1207template <typename realT>
1209{
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 } );
1214
1215 r_0( 0.2, 0.5e-6 );
1216
1217 h_obs( 4200 );
1218}
1219
1220template <typename realT>
1222{
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 } );
1227
1228 r_0( 0.16, 0.5e-6 );
1229
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 } );
1232
1233 h_obs( 2400 );
1234}
1235
1236template <typename realT>
1238{
1239 r_0( r0, lam0 );
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 } ) );
1246}
1247
1248template <typename realT>
1249template <typename iosT>
1251{
1252 ios << "# Atmosphere Parameters:\n";
1253 ios << "# nonKolmogorov = " << std::boolalpha << nonKolmogorov() << '\n';
1254 ios << "# n_layers = " << n_layers() << '\n';
1255
1256 if( !m_nonKolmogorov )
1257 {
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';
1266 }
1267 if( m_nonKolmogorov )
1268 {
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';
1273 ios << "# beta = ";
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';
1281 }
1282
1283 ios << "# L_0 = ";
1284 for( size_t i = 0; i < n_layers() - 1; ++i )
1285 ios << L_0()[i] << ", ";
1286 ios << L_0()[n_layers() - 1] << '\n';
1287 ios << "# l_0 = ";
1288 for( size_t i = 0; i < n_layers() - 1; ++i )
1289 ios << l_0()[i] << ", ";
1290 ios << l_0()[n_layers() - 1] << '\n';
1291
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';
1302
1303 if( !m_nonKolmogorov )
1304 {
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';
1312 }
1313
1314 return ios;
1315}
1316
1317template <typename realT>
1319{
1320 using namespace mx::app;
1321
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",
1324 "",
1325 "atm.lam_0",
1326 argType::Required,
1327 "atm",
1328 "lam_0",
1329 false,
1330 "real",
1331 "The reference wavlength for r_0 [m]" );
1332 config.add(
1333 "atm.L_0", "", "atm.L_0", argType::Required, "atm", "L_0", false, "vector<real>", "Layer outer scales [m]" );
1334 config.add(
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",
1337 "",
1338 "atm.layer_z",
1339 argType::Required,
1340 "atm",
1341 "layer_z",
1342 false,
1343 "vector<real>",
1344 "layer heights [m]" );
1345 config.add(
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",
1349 "",
1350 "atm.layer_Cn2",
1351 argType::Required,
1352 "atm",
1353 "layer_Cn2",
1354 false,
1355 "vector<real>",
1356 "Layer Cn^2. Note that this does not set r_0." );
1357 config.add( "atm.layer_v_wind",
1358 "",
1359 "atm.layer_v_wind",
1360 argType::Required,
1361 "atm",
1362 "layer_v_wind",
1363 false,
1364 "vector<real>",
1365 "Layer wind speeds [m/s]" );
1366 config.add( "atm.layer_dir",
1367 "",
1368 "atm.layer_dir",
1369 argType::Required,
1370 "atm",
1371 "layer_dir",
1372 false,
1373 "vector<real>",
1374 "Layer wind directions [rad]" );
1375 config.add( "atm.v_wind",
1376 "",
1377 "atm.v_wind",
1378 argType::Required,
1379 "atm",
1380 "v_wind",
1381 false,
1382 "real",
1383 "Mean windspeed (5/3 momement), rescales layer speeds [m/s]" );
1384 config.add( "atm.tau_0",
1385 "",
1386 "atm.tau_0",
1387 argType::Required,
1388 "atm",
1389 "tau_0",
1390 false,
1391 "real",
1392 "AO time constant, sets v_wind and rescales layer speeds. [s]" );
1393 config.add( "atm.z_mean",
1394 "",
1395 "atm.z_mean",
1396 argType::Required,
1397 "atm",
1398 "z_mean",
1399 false,
1400 "real",
1401 "Mean layer height (5/3 momemnt), rescales layer heights [m/s]" );
1402 config.add( "atm.nonKolmogorov",
1403 "",
1404 "atm.nonKolmogorov",
1405 argType::Required,
1406 "atm",
1407 "nonKolmogorov",
1408 false,
1409 "bool",
1410 "Set to use a non-Kolmogorov PSD. See alpha and beta." );
1411 config.add( "atm.alpha",
1412 "",
1413 "atm.alpha",
1414 argType::Required,
1415 "atm",
1416 "alpha",
1417 false,
1418 "vector<real>",
1419 "Non-kolmogorov PSD exponent." );
1420 config.add( "atm.beta",
1421 "",
1422 "atm.beta",
1423 argType::Required,
1424 "atm",
1425 "beta",
1426 false,
1427 "vector<real>",
1428 "Non-kolmogorov PSD normalization." );
1429 config.add( "atm.beta_0",
1430 "",
1431 "atm.beta_0",
1432 argType::Required,
1433 "atm",
1434 "beta_0",
1435 false,
1436 "vector<real>",
1437 "Non-kolmogorov PSD constant." );
1438}
1439
1440template <typename realT>
1442{
1443 // Here "has side effecs" means that the set function does more than simply copy the value.
1444
1445 // The order of lam_0, Cn2, and r_0 is so that r_0 overrides the value set with Cn2 if lam_0 != 0.
1446 // lam_0 comes first because it calibrates r0 and Cn2
1447
1448 // lam_0
1449 config( m_lam_0, "atm.lam_0" );
1450
1451 // layer_Cn2
1452 std::vector<realT> lcn2 = m_layer_Cn2;
1453 config( lcn2, "atm.layer_Cn2" );
1454 if( config.isSet( "atm.layer_Cn2" ) )
1455 layer_Cn2( lcn2 );
1456
1457 realT r0 = r_0();
1458 config( r0, "atm.r_0" );
1459 if( config.isSet( "atm.r_0" ) )
1460 r_0( r0, m_lam_0 );
1461
1462 config( m_L_0, "atm.L_0" );
1463
1464 config( m_l_0, "atm.l_0" );
1465
1466 // Has side effects:
1467 std::vector<realT> layz = m_layer_z;
1468 config( layz, "atm.layer_z" ); // Do this no matter what to record source
1469 if( config.isSet( "atm.layer_z" ) )
1470 layer_z( layz ); // but only call this if changed
1471
1472 config( m_h_obs, "atm.h_obs" );
1473 config( m_H, "atm.H" );
1474
1475 // Has side effects:
1476 std::vector<realT> lvw = m_layer_v_wind;
1477 config( lvw, "atm.layer_v_wind" ); // Do this no matter what to record source
1478 if( config.isSet( "atm.layer_v_wind" ) )
1479 layer_v_wind( lvw ); // but only call this if changed
1480
1481 // Has side effects:
1482 std::vector<realT> ld = m_layer_dir;
1483 config( ld, "atm.layer_dir" ); // Do this no matter what to record source
1484 if( config.isSet( "atm.layer_dir" ) )
1485 layer_dir( ld ); // but only call this if changed
1486
1487 realT vw = m_v_wind;
1488 config( vw, "atm.v_wind" ); // Do this no matter what to record source
1489 if( config.isSet( "atm.v_wind" ) )
1490 v_wind( vw ); // but only call this if changed
1491
1492 realT t0 = tau_0();
1493 config( t0, "atm.tau_0" ); // Do this no matter what to record source
1494 if( config.isSet( "atm.tau_0" ) )
1495 {
1496 std::cerr << "setting tau_0 " << t0 << "\n";
1497 tau_0( t0, m_lam_0 ); // but only call this if changed
1498 }
1499 realT zm = m_z_mean;
1500 config( zm, "atm.z_mean" ); // Do this no matter what to record source
1501 if( config.isSet( "atm.z_mean" ) )
1502 z_mean( zm ); // but only call this if changed
1503
1504 config( m_nonKolmogorov, "atm.nonKolmogorov" );
1505
1506 std::vector<realT> a = m_alpha;
1507 config( a, "atm.alpha" );
1508 if( config.isSet( "atm.alpha" ) )
1509 alpha( a ); // this sets m_nonKolmogorov
1510
1511 std::vector<realT> b = m_beta;
1512 config( b, "atm.beta" );
1513 if( config.isSet( "atm.beta" ) )
1514 beta( b ); // this sets m_nonKolmogorov
1515
1516 std::vector<realT> b0 = m_beta_0;
1517 config( b0, "atm.beta_0" );
1518 if( config.isSet( "atm.beta_0" ) )
1519 beta_0( b0 ); // this sets m_nonKolmogorov
1520}
1521
1522extern template class aoAtmosphere<float>;
1523
1524extern template class aoAtmosphere<double>;
1525
1526extern template class aoAtmosphere<long double>;
1527
1528#ifdef HASQUAD
1529extern template class aoAtmosphere<__float128>;
1530#endif
1531
1532} // namespace analysis
1533} // namespace AO
1534} // namespace mx
1535
1536#endif // aoAtmosphere_hpp
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 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 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.
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.
Definition error.hpp:331
constexpr floatT six_fifths()
Return 6/5 in the specified precision.
The mxlib c++ namespace.
Definition mxlib.hpp:37
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.