Quinoa regression test code coverage report
Current view: top level - DiffEq - InitPolicy.hpp (source / functions) Hit Total Coverage
Commit: Quinoa_v0.3-957-gb4f0efae0 Lines: 52 62 83.9 %
Date: 2021-11-09 13:40:20 Functions: 6 90 6.7 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 52 104 50.0 %

           Branch data     Line data    Source code
       1                 :            : // *****************************************************************************
       2                 :            : /*!
       3                 :            :   \file      src/DiffEq/InitPolicy.hpp
       4                 :            :   \copyright 2012-2015 J. Bakosi,
       5                 :            :              2016-2018 Los Alamos National Security, LLC.,
       6                 :            :              2019-2021 Triad National Security, LLC.
       7                 :            :              All rights reserved. See the LICENSE file for details.
       8                 :            :   \brief     Initialization policies
       9                 :            :   \details   This file defines initialization policy classes. As opposed to
      10                 :            :     coefficients policies, see, e.g., DiffEq/BetaCoeffPolicy.h, initialization
      11                 :            :     policies are not SDE-specific -- at least at this time.
      12                 :            : 
      13                 :            :     General requirements on initialization policy classes:
      14                 :            : 
      15                 :            :     - Must define the member function _init_, which is used to do the
      16                 :            :       initialization. Required signature:
      17                 :            :       \code{.cpp}
      18                 :            :         template< class eq >
      19                 :            :         static void init( const ctr::InputDeck& deck,
      20                 :            :                           const tk::RNG& rng,
      21                 :            :                           int stream,
      22                 :            :                           tk::Particles& particles,
      23                 :            :                           tk::ctr::ncomp_t e,
      24                 :            :                           tk::ctr::ncomp_t ncomp,
      25                 :            :                           tk::ctr::ncomp_t offset );
      26                 :            :       \endcode
      27                 :            :       where _deck_ is the input deck from which configuration is read, _rng_ is
      28                 :            :       a reference to a random number generator to use, _stream_ is the thread
      29                 :            :       (or stream) id, _particles_ denotes the particle properties array to be
      30                 :            :       initialized, _e_ is the component index selecting which equation is to be
      31                 :            :       initialized in the system, _ncomp_ is the total number of equations in the
      32                 :            :       system, and _offset_ is the offset in the particle array at which
      33                 :            :       initialization should be done.
      34                 :            : 
      35                 :            :     - Must define the static function _type()_, returning the enum value of the
      36                 :            :       policy option. Example:
      37                 :            :       \code{.cpp}
      38                 :            :         static ctr::InitPolicyType type() noexcept {
      39                 :            :           return ctr::InitPolicyType::RAW;
      40                 :            :         }
      41                 :            :       \endcode
      42                 :            :       which returns the enum value of the option from the underlying option
      43                 :            :       class, collecting all possible options for initialization policies.
      44                 :            : */
      45                 :            : // *****************************************************************************
      46                 :            : #ifndef InitPolicy_h
      47                 :            : #define InitPolicy_h
      48                 :            : 
      49                 :            : #include <algorithm>
      50                 :            : #include <cfenv>
      51                 :            : 
      52                 :            : #include <brigand/sequences/list.hpp>
      53                 :            : 
      54                 :            : #ifdef HAS_MKL
      55                 :            :   #include <mkl_lapacke.h>
      56                 :            : #else
      57                 :            :   #include <lapacke.h>
      58                 :            : #endif
      59                 :            : 
      60                 :            : #include "Macro.hpp"
      61                 :            : #include "Types.hpp"
      62                 :            : #include "Particles.hpp"
      63                 :            : #include "Walker/Options/InitPolicy.hpp"
      64                 :            : #include "Walker/InputDeck/InputDeck.hpp"
      65                 :            : #include "RNG.hpp"
      66                 :            : 
      67                 :            : namespace walker {
      68                 :            : 
      69                 :            : //! Raw initialization policy: leave memory uninitialized
      70                 :            : struct InitRaw {
      71                 :            : 
      72                 :            :   //! Do not initialize particle properties
      73                 :            :   template< class eq >
      74                 :            :   static void init( const ctr::InputDeck&,
      75                 :            :                     const tk::RNG&,
      76                 :            :                     int,
      77                 :            :                     tk::Particles&,
      78                 :            :                     tk::ctr::ncomp_t,
      79                 :            :                     tk::ctr::ncomp_t,
      80                 :            :                     tk::ctr::ncomp_t ) {}
      81                 :            : 
      82                 :            :   static ctr::InitPolicyType type() noexcept
      83                 :            :   { return ctr::InitPolicyType::RAW; }
      84                 :            : };
      85                 :            : 
      86                 :            : //! Zero initialization policy: zero particle properties
      87                 :            : struct InitZero {
      88                 :            : 
      89                 :            :   //! Initialize particle properties as zero
      90                 :            :   template< class eq >
      91                 :            :   static void init( const ctr::InputDeck&,
      92                 :            :                     const tk::RNG&,
      93                 :            :                     int,
      94                 :            :                     tk::Particles& particles,
      95                 :            :                     tk::ctr::ncomp_t,
      96                 :            :                     tk::ctr::ncomp_t,
      97                 :            :                     tk::ctr::ncomp_t )
      98                 :            :   {
      99                 :            :     particles.fill( 0.0 );
     100                 :            :   }
     101                 :            : 
     102                 :            :   static ctr::InitPolicyType type() noexcept
     103                 :            :   { return ctr::InitPolicyType::ZERO; }
     104                 :            : };
     105                 :            : 
     106                 :            : //! Delta initialization policy: put in delta-spikes as the joint PDF
     107                 :            : struct InitDelta {
     108                 :            : 
     109                 :            :   //! Initialize particle properties a joint delta
     110                 :            :   template< class eq >
     111         [ -  + ]:         47 :   static void init( const ctr::InputDeck& deck,
     112                 :            :                     const tk::RNG&,
     113                 :            :                     int,
     114                 :            :                     tk::Particles& particles,
     115                 :            :                     tk::ctr::ncomp_t e,
     116                 :            :                     tk::ctr::ncomp_t ncomp,
     117                 :            :                     tk::ctr::ncomp_t offset )
     118                 :            :   {
     119                 :            :     using ncomp_t = tk::ctr::ncomp_t;
     120                 :            : 
     121                 :            :     const auto& spike =
     122                 :            :       deck.template get< tag::param, eq, tag::init, tag::spike >().at(e);
     123                 :            : 
     124                 :            :     // use only the first ncomp spikes if there are more than the equation is
     125                 :            :     // configured for
     126         [ -  + ]:         47 :     const ncomp_t size = std::min( ncomp, spike.size() );
     127                 :            : 
     128         [ +  + ]:        282 :     for (ncomp_t c=0; c<size; ++c) {
     129                 :            :       const auto& sc = spike[c];        // vector of spikes for component c
     130                 :            : 
     131                 :            :       ncomp_t i = 0;
     132         [ +  + ]:        705 :       for (ncomp_t s=0; s<sc.size(); s+=2) {
     133                 :            :         // compute number of samples to be set at relative probability height
     134                 :        470 :         const auto npar =
     135                 :            :           static_cast< ncomp_t >(
     136                 :        470 :             static_cast< tk::real >( particles.nunk() ) * sc[s+1] );
     137                 :            :         // assign sample values
     138         [ +  + ]:      20270 :         for (ncomp_t p=0; p<npar; ++p) particles( i+p, c, offset ) = sc[s];
     139                 :        470 :         i += npar;
     140                 :            :       }
     141                 :            :     }
     142                 :         47 :   }
     143                 :            : 
     144                 :            :   static ctr::InitPolicyType type() noexcept
     145                 :            :   { return ctr::InitPolicyType::JOINTDELTA; }
     146                 :            : };
     147                 :            : 
     148                 :            : //! Beta initialization policy: generate samples from a joint beta PDF
     149                 :            : struct InitBeta {
     150                 :            : 
     151                 :            :   //! Initialize particle properties by sampling from a joint beta distribution
     152                 :            :   template< class eq >
     153         [ -  + ]:         51 :   static void init( const ctr::InputDeck& deck,
     154                 :            :                     const tk::RNG& rng,
     155                 :            :                     int stream,
     156                 :            :                     tk::Particles& particles,
     157                 :            :                     tk::ctr::ncomp_t e,
     158                 :            :                     tk::ctr::ncomp_t ncomp,
     159                 :            :                     tk::ctr::ncomp_t offset )
     160                 :            :   {
     161                 :            :     using ncomp_t = tk::ctr::ncomp_t;
     162                 :            : 
     163                 :            :     const auto& betapdf =
     164                 :            :       deck.template get< tag::param, eq, tag::init, tag::betapdf >().at(e);
     165                 :            : 
     166                 :            :     // use only the first ncomp betapdfs if there are more than the equation is
     167                 :            :     // configured for
     168         [ -  + ]:         51 :     const ncomp_t size = std::min( ncomp, betapdf.size() );
     169                 :            : 
     170                 :            :     const auto eps = std::numeric_limits< tk::real >::epsilon();
     171                 :            : 
     172         [ +  + ]:        306 :     for (ncomp_t c=0; c<size; ++c) {
     173                 :            :       // get vector of betapdf parameters for component c
     174                 :        255 :       const auto& bc = betapdf[c];
     175                 :            : 
     176         [ +  + ]:        510 :       for (ncomp_t s=0; s<bc.size(); s+=4) {
     177                 :            :         // generate beta random numbers for all particles using parameters in bc
     178         [ +  + ]:    1520255 :         for (ncomp_t p=0; p<particles.nunk(); ++p) {
     179                 :    1520000 :           rng.beta( stream, 1, bc[s], bc[s+1], bc[s+2], bc[s+3],
     180                 :            :                     &particles( p, c, offset ) );
     181                 :            :           auto& v = particles( p, c, offset );
     182         [ +  + ]:    1520000 :           if (v < eps) v = eps;
     183         [ +  + ]:    1520000 :           if (v > 1.0-eps) v = 1.0-eps;
     184                 :            :         }
     185                 :            :       }
     186                 :            :     }
     187                 :            : 
     188                 :         51 :   }
     189                 :            : 
     190                 :            :   static ctr::InitPolicyType type() noexcept
     191                 :            :   { return ctr::InitPolicyType::JOINTBETA; }
     192                 :            : };
     193                 :            : 
     194                 :            : //! Gaussian initialization policy: generate samples from a joint Gaussian PDF
     195                 :            : //! \note No correlations supported. For correlations, see jointCorrGaussian
     196                 :            : struct InitGaussian {
     197                 :            : 
     198                 :            :   //! Initialize particle properties by sampling from independent Gaussians
     199                 :            :   template< class eq >
     200         [ -  + ]:        184 :   static void init( const ctr::InputDeck& deck,
     201                 :            :                     const tk::RNG& rng,
     202                 :            :                     int stream,
     203                 :            :                     tk::Particles& particles,
     204                 :            :                     tk::ctr::ncomp_t e,
     205                 :            :                     tk::ctr::ncomp_t ncomp,
     206                 :            :                     tk::ctr::ncomp_t offset )
     207                 :            :   {
     208                 :            :     using ncomp_t = tk::ctr::ncomp_t;
     209                 :            : 
     210                 :            :     const auto& gaussian =
     211                 :            :       deck.template get< tag::param, eq, tag::init, tag::gaussian >().at(e);
     212                 :            : 
     213                 :            :     // use only the first ncomp gaussian if there are more than the equation is
     214                 :            :     // configured for
     215         [ -  + ]:        184 :     const ncomp_t size = std::min( ncomp, gaussian.size() );
     216                 :            : 
     217         [ +  + ]:        736 :     for (ncomp_t c=0; c<size; ++c) {
     218                 :            :       // get vector of gaussian pdf parameters for component c
     219                 :        552 :       const auto& gc = gaussian[c];
     220                 :            : 
     221         [ +  + ]:       1104 :       for (ncomp_t s=0; s<gc.size(); s+=2) {
     222                 :            :         // generate Gaussian random numbers for all particles using parameters
     223         [ +  + ]:    2670552 :         for (ncomp_t p=0; p<particles.nunk(); ++p) {
     224                 :            :           auto& par = particles( p, c, offset );
     225                 :            :           // sample from Gaussian with zero mean and unit variance
     226                 :            :           rng.gaussian( stream, 1, &par );
     227                 :            :           // scale to given mean and variance
     228                 :    2670000 :           par = par * sqrt(gc[s+1]) + gc[s];
     229                 :            :         }
     230                 :            :       }
     231                 :            :     }
     232                 :            : 
     233                 :        184 :   }
     234                 :            : 
     235                 :            :   static ctr::InitPolicyType type() noexcept
     236                 :            :   { return ctr::InitPolicyType::JOINTGAUSSIAN; }
     237                 :            : };
     238                 :            : 
     239                 :            : //! \brief Gaussian initialization policy: generate samples from a joint
     240                 :            : //!   correlated Gaussian PDF
     241                 :            : struct InitCorrGaussian {
     242                 :            : 
     243                 :            :   //! Initialize particle properties by sampling from a joint Gaussian
     244                 :            :   template< class eq >
     245         [ -  - ]:          0 :   static void init( const ctr::InputDeck& deck,
     246                 :            :                     const tk::RNG& rng,
     247                 :            :                     int stream,
     248                 :            :                     tk::Particles& particles,
     249                 :            :                     tk::ctr::ncomp_t e,
     250                 :            :                     tk::ctr::ncomp_t ncomp,
     251                 :            :                     tk::ctr::ncomp_t offset )
     252                 :            :   {
     253                 :            :     using ncomp_t = tk::ctr::ncomp_t;
     254                 :            : 
     255                 :            :     const auto& mean =
     256                 :            :       deck.template get< tag::param, eq, tag::init, tag::mean >().at(e);
     257                 :            :     Assert( mean.size() == ncomp, "Size mismatch" );
     258                 :            :     const auto& cov_ =
     259                 :            :       deck.template get< tag::param, eq, tag::init, tag::cov >().at(e);
     260                 :            :     Assert( cov_.size() == ncomp*(ncomp+1)/2, "Size mismatch" );
     261                 :            : 
     262                 :            :     // Compute covariance matrix using Cholesky-decompositionm, see Intel MKL
     263                 :            :     // example: vdrnggaussianmv.c, and UnitTest/tests/RNG/TestRNG.h
     264                 :          0 :     auto cov = cov_;
     265                 :          0 :     lapack_int n = static_cast< lapack_int >( ncomp );
     266                 :            :     #ifndef NDEBUG
     267                 :            :     lapack_int info =
     268                 :            :     #endif
     269         [ -  - ]:          0 :       LAPACKE_dpptrf( LAPACK_ROW_MAJOR, 'U', n, cov.data() );
     270                 :            :     Assert( info == 0, "Error in Cholesky-decomposition" );
     271                 :            : 
     272                 :            :     // Generate multi-variate Gaussian random numbers for all particles with
     273                 :            :     // means and covariance matrix given by user
     274         [ -  - ]:          0 :     for (ncomp_t p=0; p<particles.nunk(); ++p) {
     275 [ -  - ][ -  - ]:          0 :       std::vector< double > r( ncomp );
     276         [ -  - ]:          0 :       rng.gaussianmv( stream, 1, ncomp, mean.data(), cov.data(), r.data() );
     277         [ -  - ]:          0 :       for (ncomp_t c=0; c<ncomp; ++c)
     278                 :          0 :         particles( p, c, offset ) = r[c];
     279                 :            :     }
     280                 :          0 :   }
     281                 :            : 
     282                 :            :   static ctr::InitPolicyType type() noexcept
     283                 :            :   { return ctr::InitPolicyType::JOINTCORRGAUSSIAN; }
     284                 :            : };
     285                 :            : 
     286                 :            : 
     287                 :            : //! Gamma initialization policy: generate samples from a joint gamma PDF
     288                 :            : struct InitGamma {
     289                 :            : 
     290                 :            :   //! Initialize particle properties by sampling from a joint gamma distribution
     291                 :            :   template< class eq >
     292         [ -  + ]:         90 :   static void init( const ctr::InputDeck& deck,
     293                 :            :                     const tk::RNG& rng,
     294                 :            :                     int stream,
     295                 :            :                     tk::Particles& particles,
     296                 :            :                     tk::ctr::ncomp_t e,
     297                 :            :                     tk::ctr::ncomp_t ncomp,
     298                 :            :                     tk::ctr::ncomp_t offset )
     299                 :            :   {
     300                 :            :     using ncomp_t = tk::ctr::ncomp_t;
     301                 :            : 
     302                 :            :     const auto& gamma =
     303                 :            :       deck.template get< tag::param, eq, tag::init, tag::gamma >().at(e);
     304                 :            : 
     305                 :            :     // use only the first ncomp gamma if there are more than the equation is
     306                 :            :     // configured for
     307         [ -  + ]:         90 :     const ncomp_t size = std::min( ncomp, gamma.size() );
     308                 :            : 
     309         [ +  + ]:        180 :     for (ncomp_t c=0; c<size; ++c) {
     310                 :            :       // get vector of gamma pdf parameters for component c
     311                 :         90 :       const auto& gc = gamma[c];
     312                 :            :       // generate gamma random numbers for all particles using parameters in gc
     313         [ +  + ]:        180 :       for (ncomp_t s=0; s<gc.size(); s+=2)
     314         [ +  + ]:     420090 :         for (ncomp_t p=0; p<particles.nunk(); ++p)
     315                 :     420000 :           rng.gamma( stream, 1, gc[s], gc[s+1], &particles( p, c, offset ) );
     316                 :            :     }
     317                 :            : 
     318                 :         90 :   }
     319                 :            : 
     320                 :            :   static ctr::InitPolicyType type() noexcept
     321                 :            :   { return ctr::InitPolicyType::JOINTGAMMA; }
     322                 :            : };
     323                 :            : 
     324                 :            : //! Dirichlet initialization policy: generate samples from a Dirichlet PDF
     325                 :            : struct InitDirichlet {
     326                 :            : 
     327                 :            :   //! Initialize particle properties by sampling from a Dirichlet distribution
     328                 :            :   //! \see https://en.wikipedia.org/wiki/Dirichlet_distribution#Random_number_generation
     329                 :            :   template< class eq >
     330         [ -  + ]:         32 :   static void init( const ctr::InputDeck& deck,
     331                 :            :                     const tk::RNG& rng,
     332                 :            :                     int stream,
     333                 :            :                     tk::Particles& particles,
     334                 :            :                     tk::ctr::ncomp_t e,
     335                 :            :                     [[ maybe_unused ]] tk::ctr::ncomp_t ncomp,
     336                 :            :                     tk::ctr::ncomp_t offset )
     337                 :            :   {
     338                 :            :     using ncomp_t = tk::ctr::ncomp_t;
     339                 :            : 
     340                 :            :     const auto& dir =
     341                 :            :       deck.template get< tag::param, eq, tag::init, tag::dirichlet >().at(e);
     342                 :            :     Assert( dir.size() == ncomp+1, "Size mismatch" );
     343                 :         32 :     std::vector< tk::real > Y( dir.size() );
     344                 :            : 
     345         [ +  + ]:     400032 :     for (ncomp_t p=0; p<particles.nunk(); ++p) {
     346                 :            :       // Generate N gamma-distributed random numbers with prescribed shape and
     347                 :            :       // unit scale scale parameters.
     348         [ +  + ]:    1600000 :       for (std::size_t c=0; c<ncomp+1; ++c) {
     349         [ +  - ]:    1200000 :         rng.gamma( stream, 1, dir[c], 1.0, Y.data()+c );
     350                 :            :       }
     351                 :            : 
     352                 :            :       fenv_t fe;
     353                 :     400000 :       feholdexcept( &fe );
     354                 :            : 
     355                 :            :       auto Ysum = std::accumulate( begin(Y), end(Y), 0.0 );
     356                 :            : 
     357                 :            :       // Assign N=K+1 particle values by dividing the gamma-distributed numbers
     358                 :            :       // by the sum of the N vlues, which yields a Dirichlet distribution. Note
     359                 :            :       // that we also store the Nth value.
     360         [ +  + ]:    1600000 :       for (std::size_t c=0; c<ncomp+1; ++c) {
     361                 :    1200000 :         auto y = Y[c] / Ysum;
     362 [ +  - ][ -  + ]:    1200000 :         if (y < 0.0 || y > 1.0) Throw( "Dirichlet samples out of bounds" );
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
     363                 :    1200000 :         particles( p, c, offset ) = y;
     364                 :            :       }
     365                 :            : 
     366                 :     400000 :       feclearexcept( FE_UNDERFLOW );
     367                 :     400000 :       feupdateenv( &fe );
     368                 :            :     }
     369                 :            : 
     370                 :            :     // Verify boundedness of all ncomp+1 (=N=K+1) scalars
     371         [ +  + ]:     400032 :     for (ncomp_t p=0; p<particles.nunk(); ++p) {
     372         [ +  + ]:    1600000 :       for (ncomp_t i=0; i<ncomp+1; ++i) {
     373                 :    1200000 :         auto y = particles( p, i, offset );
     374 [ +  - ][ -  + ]:    1200000 :         if (y < 0.0 || y > 1.0) Throw( "IC Dirichlet sample Y out of bounds" );
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
     375                 :            :       }
     376                 :            :     }
     377                 :         32 :   }
     378                 :            : 
     379                 :            :   static ctr::InitPolicyType type() noexcept
     380                 :            :   { return ctr::InitPolicyType::JOINTDIRICHLET; }
     381                 :            : };
     382                 :            : 
     383                 :            : //! List of all initialization policies
     384                 :            : using InitPolicies = brigand::list< InitRaw
     385                 :            :                                   , InitZero
     386                 :            :                                   , InitDelta
     387                 :            :                                   , InitBeta
     388                 :            :                                   , InitGaussian
     389                 :            :                                   , InitCorrGaussian
     390                 :            :                                   , InitGamma
     391                 :            :                                   , InitDirichlet
     392                 :            :                                   >;
     393                 :            : 
     394                 :            : } // walker::
     395                 :            : 
     396                 :            : #endif // InitPolicy_h

Generated by: LCOV version 1.14