LCOV - code coverage report
Current view: top level - include/ao/analysis - aoPSDs.hpp (source / functions) Coverage Total Hit
Test: mxlib Lines: 61.1 % 113 69
Test Date: 2026-08-30 22:23:37 Functions: 70.6 % 17 12

            Line data    Source code
       1              : /** \file aoPSDs.hpp
       2              :  * \author Jared R. Males (jaredmales@gmail.com)
       3              :  * \brief Spatial power spectra used in adaptive optics.
       4              :  * \ingroup mxAO_files
       5              :  *
       6              :  */
       7              : 
       8              : //***********************************************************************//
       9              : // Copyright 2016-2018 Jared R. Males (jaredmales@gmail.com)
      10              : //
      11              : // This file is part of mxlib.
      12              : //
      13              : // mxlib is free software: you can redistribute it and/or modify
      14              : // it under the terms of the GNU General Public License as published by
      15              : // the Free Software Foundation, either version 3 of the License, or
      16              : // (at your option) any later version.
      17              : //
      18              : // mxlib is distributed in the hope that it will be useful,
      19              : // but WITHOUT ANY WARRANTY; without even the implied warranty of
      20              : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      21              : // GNU General Public License for more details.
      22              : //
      23              : // You should have received a copy of the GNU General Public License
      24              : // along with mxlib.  If not, see <http://www.gnu.org/licenses/>.
      25              : //***********************************************************************//
      26              : 
      27              : #ifndef aoPSDs_hpp
      28              : #define aoPSDs_hpp
      29              : 
      30              : #include <string>
      31              : 
      32              : #include "../../mxlib.hpp"
      33              : #include "../../math/constants.hpp"
      34              : #include "../../math/func/jinc.hpp"
      35              : 
      36              : #include "aoConstants.hpp"
      37              : 
      38              : #include "aoAtmosphere.hpp"
      39              : 
      40              : namespace mx
      41              : {
      42              : namespace AO
      43              : {
      44              : namespace analysis
      45              : {
      46              : 
      47              : namespace PSDComponent
      48              : {
      49              : /// Enum to specify which component of the PSD to calcualte
      50              : enum
      51              : {
      52              :     phase,        ///< The phase or OPD
      53              :     amplitude,    ///< The amplitude
      54              :     dispPhase,    ///< The phase component of dispersive anisoplanatism
      55              :     dispAmplitude ///< The amplitude component of dispersive anisoplanatism
      56              : };
      57              : 
      58              : std::string compName( int cc );
      59              : 
      60              : int compNum( const std::string &name );
      61              : } // namespace PSDComponent
      62              : 
      63              : /// Manage calculations using the von Karman spatial power spectrum.
      64              : /** This very general PSD has the form
      65              :   *
      66              :   * \f[
      67              :     \mathcal{P}(k) = \frac{\beta}{ ( k^2 + k_0^2) ^{\alpha/2}}
      68              :     \f]
      69              :   *
      70              :   * Where \f$ k \f$ is spatial frequency, \f$ \beta \f$ is a normalization constant, and outer scale \f$ L_0 \f$ is
      71              :   included via \f$ k_0 = 1/L_0 \f$.
      72              :   * For \f$ L_0 \rightarrow \infty \f$ this becomes a simple power law with index \f$ \alpha \f$.
      73              :   *
      74              :   * For atmospheric turbulence \f$ \alpha = 11/3 \f$ and the normalization is
      75              :   \f[
      76              :   \beta = \frac{\mathcal{A}_p}{r_0^{5/3}}
      77              :   \f]
      78              :   * where \f$ A_p  = 0.0218...\f$  (see \ref mx::AO::constants::a_PSD ).
      79              :   *
      80              :   * \ingroup mxAOAnalytic
      81              :   */
      82              : template <typename realT>
      83              : struct vonKarmanSpectrum
      84              : {
      85              :     typedef verbose::d verboseT;
      86              : 
      87              :   protected:
      88              :     bool m_subPiston{ true }; ///< flag controlling whether piston is subtracted from the PSD.  Default is true.
      89              :     bool m_subTipTilt{
      90              :         false };              ///< flag controlling whether tip and tilt are subtracted from the PSD.  Default is false.
      91              : 
      92              :     bool m_scintillation{ false };          ///< flag controlling whether or not scintillation is included
      93              :     int m_component{ PSDComponent::phase }; ///< If m_scintillation is true, this controls whether phase (0), amplitude
      94              :                                             ///< (1), or dispersive contrast (2) is returned.
      95              : 
      96              :     realT m_D{ 1.0 }; ///< Diameter used for piston and tip/tilt subtraction, in m. Default is 1 m.
      97              : 
      98              :     const char *m_id = "von Karman";
      99              : 
     100              :     // realT m_alpha {eleven_thirds<realT>()}; ///< The power-law index, 11/3 for Kolmogorov
     101              : 
     102              :   public:
     103              :     /// Default Constructor
     104              :     vonKarmanSpectrum();
     105              : 
     106              :     /// Constructor specifying the parameters
     107              :     /**
     108              :      */
     109              :     vonKarmanSpectrum( bool subP, ///< [in] is the value of m_subPiston.
     110              :                        bool subT, ///< [in] is the value of m_subTipTilt.
     111              :                        realT D    ///< [in] is the value of m_D.
     112              :     );
     113              : 
     114              :     /// Get the value of m_subPiston
     115              :     /**
     116              :      * \returns m_subPiston
     117              :      */
     118              :     bool subPiston();
     119              : 
     120              :     /// Set the value of m_subPiston
     121              :     /**
     122              :      */
     123              :     void subPiston( bool sp /**< [in] is the new value of m_subPiston */ );
     124              : 
     125              :     /// Get the value of m_subTipTilt
     126              :     /**
     127              :      * \returns the value of m_subTipTilt.
     128              :      */
     129              :     bool subTipTilt();
     130              : 
     131              :     /// Set the value of the m_subTipTilt flag.
     132              :     /**
     133              :      */
     134              :     void subTipTilt( bool st /**< [in] the new value of m_subTipTilt.*/ );
     135              : 
     136              :     /// Get the value of m_scintillation
     137              :     /**
     138              :      * \returns m_scintillation
     139              :      */
     140              :     bool scintillation();
     141              : 
     142              :     /// Set the value of m_scintillation
     143              :     /**
     144              :      */
     145              :     void scintillation( bool sc /**< [in] the new value of m_scintillation*/ );
     146              : 
     147              :     /// Get the value of m_component
     148              :     /**
     149              :      * \returns m_component
     150              :      */
     151              :     int component();
     152              : 
     153              :     /// Set the value of m_component
     154              :     /**
     155              :      */
     156              :     int component( int cc /**< [in] the new value of m_component */ );
     157              : 
     158              :     /// Get the value of the diameter m_D.
     159              :     /**
     160              :      * \returns the current value of m_D, the diameter in m.
     161              :      */
     162              :     realT D();
     163              : 
     164              :     /// Set the aperture diameter
     165              :     /**
     166              :      */
     167              :     void D( realT nd /**< [in] the new diameter in m */ );
     168              : 
     169              :     /// Get the value of the PSD at spatial frequency k and a zenith distance.
     170              :     /**
     171              :      * \returns the von Karman PSD at the specified spatial frequency.
     172              :      * \returns -1 if an error occurs.
     173              :      *
     174              :      */
     175              :     template <class psdParamsT>
     176              :     realT operator()( psdParamsT &par, ///< [in] gives the PSD parameters.
     177              :                       size_t layer_i,
     178              :                       realT k,         ///< [in] is the spatial frequency in m^-1.
     179              :                       realT sec_zeta   ///< [in] is the secant of the zenith distance.
     180              :     );
     181              : 
     182              :     /// Get the value of the PSD at spatial frequency k and wavelength lambda, and a zenith distance, with a WFS at a
     183              :     /// different wavelength
     184              :     /**
     185              :      *
     186              :      * \returns the von Karman PSD at the specified spatial frequency for the specified wavelength.
     187              :      * \returns -1 if an error occurs.
     188              :      */
     189              :     template <class psdParamsT>
     190              :     realT operator()( psdParamsT &par,  ///< [in] gives the PSD parameters.
     191              :                       size_t layer_i,
     192              :                       realT k,          ///< [in] is the spatial frequency in m^-1.
     193              :                       realT lambda,     ///< [in] is the observation wavelength in m
     194              :                       realT lambda_wfs, ///< [in] is the wavefront measurement wavelength in m
     195              :                       realT secZeta     ///< [in] is the secant of the zenith distance
     196              :     );
     197              : 
     198              :     /// Get the fitting error for an actuator spacing d.
     199              :     /**
     200              :      * \todo generatlize for different alpha and beta
     201              :      *
     202              :      * \param atm gives the atmosphere parameters r_0 and L_0
     203              :      * \param d is the actuator spacing in m
     204              :      */
     205              :     // realT fittingError(aoAtmosphere<realT> &atm, realT d);
     206              : 
     207              :     template <typename iosT>
     208              :     iosT &dumpPSD( iosT &ios );
     209              : 
     210              :     /// Setup the configurator to configure this class
     211              :     void setupConfig( app::appConfigurator &config /**< [in] the app::configurator object*/ );
     212              : 
     213              :     /// Load the configuration of this class from a configurator
     214              :     void loadConfig( app::appConfigurator &config /**< [in] the app::configurator object*/ );
     215              : };
     216              : 
     217              : template <typename realT>
     218           52 : vonKarmanSpectrum<realT>::vonKarmanSpectrum()
     219              : {
     220           52 : }
     221              : 
     222              : template <typename realT>
     223            0 : vonKarmanSpectrum<realT>::vonKarmanSpectrum( bool subP, // [in] is the value of m_subPiston.
     224              :                                              bool subT, // [in] is the value of m_subTipTilt.
     225              :                                              realT D    // [in] is the diameter
     226            0 : )
     227              : {
     228            0 :     m_subPiston = subP;
     229            0 :     m_subTipTilt = subT;
     230            0 :     m_D = D;
     231            0 : }
     232              : 
     233              : template <typename realT>
     234        41076 : bool vonKarmanSpectrum<realT>::subPiston()
     235              : {
     236        41076 :     return m_subPiston;
     237              : }
     238              : 
     239              : template <typename realT>
     240            0 : void vonKarmanSpectrum<realT>::subPiston( bool sp /* [in] is the new value of m_subPiston */ )
     241              : {
     242            0 :     m_subPiston = sp;
     243            0 : }
     244              : 
     245              : template <typename realT>
     246        41076 : bool vonKarmanSpectrum<realT>::subTipTilt()
     247              : {
     248        41076 :     return m_subTipTilt;
     249              : }
     250              : 
     251              : template <typename realT>
     252            0 : void vonKarmanSpectrum<realT>::subTipTilt( bool st /* [in] the new value of m_subTipTilt */ )
     253              : {
     254            0 :     m_subTipTilt = st;
     255            0 : }
     256              : 
     257              : template <typename realT>
     258            4 : bool vonKarmanSpectrum<realT>::scintillation()
     259              : {
     260            4 :     return m_scintillation;
     261              : }
     262              : 
     263              : template <typename realT>
     264            0 : void vonKarmanSpectrum<realT>::scintillation( bool sc /* [in] the new value of m_scintillation */ )
     265              : {
     266            0 :     m_scintillation = sc;
     267            0 : }
     268              : 
     269              : template <typename realT>
     270            4 : int vonKarmanSpectrum<realT>::component()
     271              : {
     272            4 :     return m_component;
     273              : }
     274              : 
     275              : template <typename realT>
     276           14 : int vonKarmanSpectrum<realT>::component( int cc /* [in] the new value of m_component */ )
     277              : {
     278           14 :     if( cc != PSDComponent::phase && cc != PSDComponent::amplitude && cc != PSDComponent::dispPhase &&
     279              :         cc != PSDComponent::dispAmplitude )
     280              :     {
     281            0 :         internal::mxlib_error_report<verboseT>( error_t::invalidarg, "Unknown component" );
     282              :         //        mxError( "vonKarmanSpectrum::component", MXE_INVALIDARG, "Unknown component" );
     283            0 :         return -1;
     284              :     }
     285              : 
     286           14 :     m_component = cc;
     287           14 :     return 0;
     288              : }
     289              : 
     290              : template <typename realT>
     291            4 : realT vonKarmanSpectrum<realT>::D()
     292              : {
     293            4 :     return m_D;
     294              : }
     295              : 
     296              : template <typename realT>
     297           39 : void vonKarmanSpectrum<realT>::D( realT nd /**< [in] the new diameter in m */ )
     298              : {
     299           39 :     m_D = nd;
     300           39 : }
     301              : 
     302              : template <typename realT>
     303              : template <class psdParamsT>
     304        96450 : realT vonKarmanSpectrum<realT>::operator()( psdParamsT &par, //< [in] gives the PSD parameters.
     305              :                                             size_t layer_i,
     306              :                                             realT k,         // [in] is the spatial frequency in m^-1.
     307              :                                             realT sec_zeta   // [in] is the secant of the zenith distance.
     308              : )
     309              : {
     310              :     realT k02;
     311              : 
     312              :     ///\todo this needs to handle layers with different L_0
     313        96450 :     if( par.L_0( layer_i ) > 0 )
     314              :     {
     315        96180 :         k02 = ( 1 ) / ( par.L_0( layer_i ) * par.L_0( layer_i ) );
     316              :     }
     317              :     else
     318          270 :         k02 = 0;
     319              : 
     320        96450 :     if( k02 == 0 && k == 0 )
     321              :     {
     322            0 :         return 0;
     323              :     }
     324              : 
     325              :     realT Ppiston, Ptiptilt;
     326              : 
     327        96450 :     if( ( m_subPiston || m_subTipTilt ) )
     328              :     {
     329        96450 :         if( m_D == 0 )
     330              :         {
     331            0 :             internal::mxlib_error_report<verboseT>( error_t::paramnotset,
     332            0 :                                                     "Diameter D not set for Piston and/or TT subtraction." );
     333              : 
     334              :             // mxError( "aoAtmosphere", MXE_PARAMNOTSET, "Diameter D not set for Piston and/or TT subtraction." );
     335            0 :             return -1;
     336              :         }
     337        96450 :         if( m_subPiston )
     338              :         {
     339        96450 :             Ppiston = pow( 2 * math::func::jinc( math::pi<realT>() * k * m_D ), 2 );
     340              :         }
     341              :         else
     342            0 :             Ppiston = 0;
     343              : 
     344        96450 :         if( m_subTipTilt )
     345              :         {
     346            0 :             Ptiptilt = pow( 4 * math::func::jincN( 2, math::pi<realT>() * k * m_D ), 2 );
     347              :         }
     348              :         else
     349        96450 :             Ptiptilt = 0;
     350              :     }
     351              :     else
     352              :     {
     353            0 :         Ppiston = 0;
     354            0 :         Ptiptilt = 0;
     355              :     }
     356              : 
     357        96450 :     return ( par.beta( layer_i ) * pow( k * k + k02, -1 * par.alpha( layer_i ) / 2 ) + par.beta_0( layer_i ) ) *
     358        96450 :            ( 1.0 - Ppiston - Ptiptilt ) * sec_zeta;
     359              : }
     360              : 
     361              : template <typename realT>
     362              : template <class psdParamsT>
     363            0 : realT vonKarmanSpectrum<realT>::operator()(
     364              :     psdParamsT &par,  // [in] gives the PSD parameters.
     365              :     size_t layer_i,
     366              :     realT k,          // [in] is the spatial frequency in m^-1.
     367              :     realT lambda,     // [in] is the observation wavelength in m.  Not used if par.nonKolmogorov==true
     368              :     realT lambda_wfs, // [in] is the wavefront measurement wavelength in m. Only used if m_scintillation==true.
     369              :     realT secZeta     // [in] is the secant of the zenith distance.
     370              : )
     371              : {
     372            0 :     realT psd = operator()( par, layer_i, k, secZeta );
     373              : 
     374            0 :     if( par.nonKolmogorov() == false )
     375              :     {
     376            0 :         psd *= pow( par.lam_0() / lambda, 2 );
     377              :     }
     378              : 
     379            0 :     if( psd < 0 )
     380            0 :         return -1;
     381              : 
     382            0 :     if( m_scintillation )
     383              :     {
     384            0 :         if( m_component == PSDComponent::phase )
     385              :         {
     386            0 :             psd *= ( par.X( k, lambda, secZeta ) );
     387              :         }
     388            0 :         else if( m_component == PSDComponent::amplitude )
     389              :         {
     390            0 :             psd *= ( par.Y( k, lambda, secZeta ) );
     391              :         }
     392            0 :         else if( m_component == PSDComponent::dispPhase )
     393              :         {
     394            0 :             psd *= ( par.X_Z( k, lambda, lambda_wfs, secZeta ) );
     395              :         }
     396            0 :         else if( m_component == PSDComponent::dispAmplitude )
     397              :         {
     398            0 :             internal::mxlib_error_report<verboseT>( error_t::notimpl, "Dispersive-aniso amplitude not implemented" );
     399              :             // mxError( "vonKarmanSpectrum::operator()", MXE_NOTIMPL, "Dispersive-aniso amplitude not implemented" );
     400            0 :             return 0;
     401              :         }
     402              :         else
     403              :         {
     404            0 :             internal::mxlib_error_report<verboseT>( error_t::invalidarg, "Invalid component specified" );
     405              :             // mxError( "vonKarmanSpectrum::operator()", MXE_INVALIDARG, "Invalid component specified" );
     406            0 :             return 0;
     407              :         }
     408              :     }
     409              : 
     410            0 :     return psd;
     411              : }
     412              : 
     413              : /*template< typename realT>
     414              : realT vonKarmanSpectrum<realT>::fittingError(aoAtmosphere<realT> &atm, realT d)
     415              : {
     416              :    realT k0;
     417              :    if(atm.L_0(0) > 0)
     418              :    {
     419              :       k0 = 1/ (atm.L_0(0)*atm.L_0(0));
     420              :    }
     421              :    else k0 = 0;
     422              : 
     423              :    return (math::pi<realT>() * math::six_fifths<realT>())* constants::a_PSD<realT>()/ pow(atm.r_0(),
     424              : math::five_thirds<realT>()) * (1./pow( pow(0.5/d,2) + k0, math::five_sixths<realT>()));
     425              : }*/
     426              : 
     427              : template <typename realT>
     428              : template <typename iosT>
     429            1 : iosT &vonKarmanSpectrum<realT>::dumpPSD( iosT &ios )
     430              : {
     431            1 :     ios << "# PSD Parameters:" << '\n';
     432            1 :     ios << "#    ID = " << m_id << '\n';
     433            1 :     ios << "#    D = " << m_D << '\n';
     434            1 :     ios << "#    subPiston = " << std::boolalpha << m_subPiston << '\n';
     435            1 :     ios << "#    subTipTilt = " << std::boolalpha << m_subTipTilt << '\n';
     436            1 :     ios << "#    Scintillation = " << std::boolalpha << m_scintillation << '\n';
     437            1 :     ios << "#    Component = " << PSDComponent::compName( m_component ) << '\n';
     438            1 :     return ios;
     439              : }
     440              : 
     441              : template <typename realT>
     442           14 : void vonKarmanSpectrum<realT>::setupConfig( app::appConfigurator &config )
     443              : {
     444              :     using namespace mx::app;
     445              : 
     446           14 :     config.add( "psd.D",
     447           28 :                 "",
     448           28 :                 "psd.D",
     449              :                 argType::Required,
     450           28 :                 "psd",
     451           28 :                 "D",
     452              :                 false,
     453           28 :                 "real",
     454           42 :                 "Aperture diameter.  Used for piston and tip/tilt subtraction." );
     455          196 :     config.add( "psd.subPiston", "", "psd.subPiston", argType::Required, "psd", "subPiston", false, "real", "" );
     456          196 :     config.add( "psd.subTipTilt", "", "psd.subTipTilt", argType::Required, "psd", "subTipTilt", false, "real", "" );
     457           14 :     config.add( "psd.scintillation",
     458           28 :                 "",
     459           28 :                 "psd.scintillation",
     460              :                 argType::Required,
     461           28 :                 "psd",
     462           28 :                 "scintillation",
     463              :                 false,
     464           28 :                 "real",
     465           42 :                 "" );
     466          182 :     config.add( "psd.component", "", "psd.component", argType::Required, "psd", "component", false, "real", "" );
     467           14 : }
     468              : 
     469              : template <typename realT>
     470           14 : void vonKarmanSpectrum<realT>::loadConfig( app::appConfigurator &config )
     471              : {
     472              :     // Here "has side effecs" means that the set function does more than simply copy the value.
     473              : 
     474           28 :     config( m_D, "psd.D" );
     475           28 :     config( m_subPiston, "psd.subPiston" );
     476           28 :     config( m_subTipTilt, "psd.subTipTilt" );
     477           14 :     config( m_scintillation, "psd.scintillation" );
     478              : 
     479           14 :     std::string cn = PSDComponent::compName( m_component );
     480           14 :     config( cn, "psd.component" );
     481           14 :     component( PSDComponent::compNum( cn ) );
     482           14 : }
     483              : 
     484              : extern template struct vonKarmanSpectrum<float>;
     485              : 
     486              : extern template struct vonKarmanSpectrum<double>;
     487              : 
     488              : extern template struct vonKarmanSpectrum<long double>;
     489              : 
     490              : #ifdef HASQUAD
     491              : extern template struct vonKarmanSpectrum<__float128>;
     492              : #endif
     493              : 
     494              : } // namespace analysis
     495              : } // namespace AO
     496              : } // namespace mx
     497              : 
     498              : #endif // aoPSDs_hpp
        

Generated by: LCOV version 2.0-1