Xyst test code coverage report
Current view: top level - Base - Data.hpp (source / functions) Hit Total Coverage
Commit: 5689ba12dc66a776d3d75f1ee48cc7d78eaa18dc Lines: 184 188 97.9 %
Date: 2024-11-22 19:17:03 Functions: 98 98 100.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 102 292 34.9 %

           Branch data     Line data    Source code
       1                 :            : // *****************************************************************************
       2                 :            : /*!
       3                 :            :   \file      src/Base/Data.hpp
       4                 :            :   \copyright 2012-2015 J. Bakosi,
       5                 :            :              2016-2018 Los Alamos National Security, LLC.,
       6                 :            :              2019-2021 Triad National Security, LLC.,
       7                 :            :              2022-2024 J. Bakosi
       8                 :            :              All rights reserved. See the LICENSE file for details.
       9                 :            :   \brief     Generic data storage with different memory layouts
      10                 :            :   \details   Generic data storage with different memory layouts. See also the
      11                 :            :     rationale discussed in the [design](layout.html) document.
      12                 :            : */
      13                 :            : // *****************************************************************************
      14                 :            : #ifndef Data_h
      15                 :            : #define Data_h
      16                 :            : 
      17                 :            : #include <array>
      18                 :            : #include <string>
      19                 :            : #include <cstdint>
      20                 :            : #include <vector>
      21                 :            : #include <set>
      22                 :            : #include <algorithm>
      23                 :            : 
      24                 :            : #include "Types.hpp"
      25                 :            : #include "Exception.hpp"
      26                 :            : 
      27                 :            : #include "NoWarning/pup_stl.hpp"
      28                 :            : 
      29                 :            : namespace tk {
      30                 :            : 
      31                 :            : //! Tags for selecting data layout policies
      32                 :            : const uint8_t UnkEqComp = 0;
      33                 :            : const uint8_t EqCompUnk = 1;
      34                 :            : 
      35                 :            : //! Zero-runtime-cost data-layout wrappers with type-based compile-time dispatch
      36                 :            : template< uint8_t Layout >
      37                 :            : class Data {
      38                 :            : 
      39                 :            :   private:
      40                 :            :     using ncomp_t = uint64_t;
      41                 :            : 
      42                 :            :   public:
      43                 :            :     //! Default constructor (required for Charm++ migration)
      44                 :      40622 :     explicit Data() : m_vec(), m_nunk(), m_nprop() {}
      45                 :            : 
      46                 :            :     //! Constructor
      47                 :            :     //! \param[in] nu Number of unknowns to allocate memory for
      48                 :            :     //! \param[in] np Total number of properties, i.e., scalar variables or
      49                 :            :     //!   components, per unknown
      50                 :      14251 :     explicit Data( ncomp_t nu, ncomp_t np ) :
      51         [ +  - ]:      14251 :       m_vec( nu*np ),
      52                 :      14251 :       m_nunk( nu ),
      53                 :      14251 :       m_nprop( np ) {}
      54                 :            : 
      55                 :            :     //! Const data access dispatch
      56                 :            :     //! \details Public interface to const-ref data access to a single real
      57                 :            :     //!   value. Use it as Data(p,c), where p is the unknown index, and c is
      58                 :            :     //!   the component index specifying the scalar equation within a system of
      59                 :            :     //!   equations. Requirement: component < nprop, unknown < nunk, enforced
      60                 :            :     //!   with an assert in DEBUG mode, see also the constructor.
      61                 :            :     //! \param[in] unknown Unknown index
      62                 :            :     //! \param[in] component Component index, i.e., position of a scalar within
      63                 :            :     //!   a system
      64                 :            :     //! \return Const reference to data of type tk::real
      65                 :            :     const tk::real&
      66                 : 6008401291 :     operator()( ncomp_t unknown, ncomp_t component ) const
      67                 : 6008401291 :     { return access( unknown, component, int2type< Layout >() ); }
      68                 :            : 
      69                 :            :     //! Non-const data access dispatch
      70                 :            :     //! \details Public interface to non-const-ref data access to a single real
      71                 :            :     //!   value. Use it as Data(p,c,o), where p is the unknown index, and c is
      72                 :            :     //!   the component index specifying the scalar equation within a system of
      73                 :            :     //!   equations. Requirement: component < nprop, unknown < nunk, enforced
      74                 :            :     //!   with an assert in DEBUG mode, see also the constructor.
      75                 :            :     //! \param[in] unknown Unknown index
      76                 :            :     //! \param[in] component Component index, i.e., position of a scalar within
      77                 :            :     //!   a system
      78                 :            :     //! \return Non-const reference to data of type tk::real
      79                 :            :     //! \see "Avoid Duplication in const and Non-const Member Function," and
      80                 :            :     //!   "Use const whenever possible," Scott Meyers, Effective C++, 3d ed.
      81                 :            :     tk::real&
      82                 : 3825186790 :     operator()( ncomp_t unknown, ncomp_t component ) {
      83                 :            :       return const_cast< tk::real& >(
      84                 :            :                static_cast< const Data& >( *this ).
      85                 : 3825186790 :                  operator()( unknown, component ) );
      86                 :            :     }
      87                 :            : 
      88                 :            :     //! Access to number of unknowns
      89                 :            :     //! \return Number of unknowns
      90                 :   35210451 :     ncomp_t nunk() const noexcept { return m_nunk; }
      91                 :            : 
      92                 :            :     //! Access to number of properties
      93                 :            :     //! \details This is the total number of scalar components per unknown
      94                 :            :     //! \return Number of propertes/unknown
      95                 :  192343370 :     ncomp_t nprop() const noexcept { return m_nprop; }
      96                 :            : 
      97                 :            :     //! Extract vector of unknowns given component
      98                 :            :     //! \details Requirement: component < nprop, enforced with an assert in
      99                 :            :     //!   DEBUG mode, see also the constructor.
     100                 :            :     //! \param[in] component Component index, i.e., position of a scalar within
     101                 :            :     //!   a system
     102                 :            :     //! \return A vector of unknowns given by component (length: nunk(), i.e.,
     103                 :            :     //!   the first constructor argument)
     104                 :            :     std::vector< tk::real >
     105                 :      26816 :     extract( ncomp_t component ) const {
     106         [ +  - ]:      26816 :       std::vector< tk::real > w( m_nunk );
     107 [ +  - ][ +  + ]:    5819369 :       for (ncomp_t i=0; i<m_nunk; ++i) w[i] = operator()( i, component );
     108                 :      26816 :       return w;
     109                 :          0 :     }
     110                 :            : 
     111                 :            :     //! Extract all components for unknown
     112                 :            :     //! \details Requirement: unknown < nunk, enforced with an assert in DEBUG
     113                 :            :     //!   mode, see also the constructor.
     114                 :            :     //! \param[in] unknown Index of unknown
     115                 :            :     //! \return A vector of components for a single unknown (length: nprop,
     116                 :            :     //!   i.e., the second constructor argument)
     117                 :            :     std::vector< tk::real >
     118                 :   11069924 :     operator[]( ncomp_t unknown ) const {
     119         [ +  - ]:   11069924 :       std::vector< tk::real > w( m_nprop );
     120 [ +  - ][ +  + ]:  102054971 :       for (ncomp_t i=0; i<m_nprop; ++i) w[i] = operator()( unknown, i );
     121                 :   11069924 :       return w;
     122                 :          0 :     }
     123                 :            : 
     124                 :            :     //! Extract (a copy of) four values of unknowns
     125                 :            :     //! \details Requirement: component < nprop, for all N[i] < nunk, enforced
     126                 :            :     //!   with an assert in DEBUG mode, see also the constructor.
     127                 :            :     //! \param[in] component Component index, i.e., position of a scalar within
     128                 :            :     //!   a system
     129                 :            :     //! \param[in] N Indices of the 4 unknowns
     130                 :            :     //! \return Array of the four values of component
     131                 :            :     std::array< tk::real, 4 >
     132                 :    6058952 :     extract( ncomp_t component, const std::array< ncomp_t, 4 >& N ) const {
     133                 :    6058952 :       auto p = cptr( component );
     134                 :    6058952 :       return {{ var(p,N[0]), var(p,N[1]), var(p,N[2]), var(p,N[3]) }};
     135                 :            :     }
     136                 :            : 
     137                 :            :     //! Const-ref accessor to underlying raw data as a std::vector
     138                 :            :     //! \return Constant reference to underlying raw data
     139                 :        126 :     const std::vector< tk::real >& vec() const { return m_vec; }
     140                 :            : 
     141                 :            :     //! Non-const-ref accessor to underlying raw data as a std::vector
     142                 :            :     //! \return Non-constant reference to underlying raw data
     143                 :         44 :     std::vector< tk::real >& vec() { return m_vec; }
     144                 :            : 
     145                 :            :     //! Compound operator-=
     146                 :            :     //! \param[in] rhs Data object to subtract
     147                 :            :     //! \return Reference to ourselves after subtraction
     148                 :          4 :     Data< Layout >& operator-= ( const Data< Layout >& rhs ) {
     149 [ -  + ][ -  - ]:          4 :       Assert( rhs.nunk() == m_nunk, "Incorrect number of unknowns" );
         [ -  - ][ -  - ]
     150 [ -  + ][ -  - ]:          4 :       Assert( rhs.nprop() == m_nprop, "Incorrect number of properties" );
         [ -  - ][ -  - ]
     151                 :          4 :       std::transform( rhs.vec().cbegin(), rhs.vec().cend(),
     152                 :            :                       m_vec.cbegin(), m_vec.begin(),
     153                 :         24 :                       []( tk::real s, tk::real d ){ return d-s; } );
     154                 :          4 :       return *this;
     155                 :            :     }
     156                 :            :     //! Operator -
     157                 :            :     //! \param[in] rhs Data object to subtract
     158                 :            :     //! \return Copy of Data object after rhs has been subtracted
     159                 :            :     //! \details Implemented in terms of compound operator-=
     160                 :          2 :     Data< Layout > operator- ( const Data< Layout >& rhs )
     161 [ +  - ][ +  - ]:          4 :     const { return Data< Layout >( *this ) -= rhs; }
                 [ +  - ]
     162                 :            : 
     163                 :            :     //! Compound operator+=
     164                 :            :     //! \param[in] rhs Data object to add
     165                 :            :     //! \return Reference to ourselves after addition
     166                 :          4 :     Data< Layout >& operator+= ( const Data< Layout >& rhs ) {
     167 [ -  + ][ -  - ]:          4 :       Assert( rhs.nunk() == m_nunk, "Incorrect number of unknowns" );
         [ -  - ][ -  - ]
     168 [ -  + ][ -  - ]:          4 :       Assert( rhs.nprop() == m_nprop, "Incorrect number of properties" );
         [ -  - ][ -  - ]
     169                 :          4 :       std::transform( rhs.vec().cbegin(), rhs.vec().cend(),
     170                 :            :                       m_vec.cbegin(), m_vec.begin(),
     171                 :         24 :                       []( tk::real s, tk::real d ){ return d+s; } );
     172                 :          4 :       return *this;
     173                 :            :     }
     174                 :            :     //! Operator +
     175                 :            :     //! \param[in] rhs Data object to add
     176                 :            :     //! \return Copy of Data object after rhs has been multiplied with
     177                 :            :     //! \details Implemented in terms of compound operator+=
     178                 :          2 :     Data< Layout > operator+ ( const Data< Layout >& rhs )
     179 [ +  - ][ +  - ]:          4 :     const { return Data< Layout >( *this ) += rhs; }
                 [ +  - ]
     180                 :            : 
     181                 :            :     //! Compound operator*= multiplying by another Data object item by item
     182                 :            :     //! \param[in] rhs Data object to multiply with
     183                 :            :     //! \return Reference to ourselves after multiplication
     184                 :          4 :     Data< Layout >& operator*= ( const Data< Layout >& rhs ) {
     185 [ -  + ][ -  - ]:          4 :       Assert( rhs.nunk() == m_nunk, "Incorrect number of unknowns" );
         [ -  - ][ -  - ]
     186 [ -  + ][ -  - ]:          4 :       Assert( rhs.nprop() == m_nprop, "Incorrect number of properties" );
         [ -  - ][ -  - ]
     187                 :          4 :       std::transform( rhs.vec().cbegin(), rhs.vec().cend(),
     188                 :            :                       m_vec.cbegin(), m_vec.begin(),
     189                 :         24 :                       []( tk::real s, tk::real d ){ return d*s; } );
     190                 :          4 :       return *this;
     191                 :            :     }
     192                 :            :     //! Operator * multiplying by another Data object item by item
     193                 :            :     //! \param[in] rhs Data object to multiply with
     194                 :            :     //! \return Copy of Data object after rhs has been multiplied with
     195                 :            :     //! \details Implemented in terms of compound operator*=
     196                 :          2 :     Data< Layout > operator* ( const Data< Layout >& rhs )
     197 [ +  - ][ +  - ]:          4 :     const { return Data< Layout >( *this ) *= rhs; }
                 [ +  - ]
     198                 :            : 
     199                 :            :     //! Compound operator*= multiplying all items by a scalar
     200                 :            :     //! \param[in] rhs Scalar to multiply with
     201                 :            :     //! \return Reference to ourselves after multiplication
     202                 :          6 :     Data< Layout >& operator*= ( tk::real rhs ) {
     203                 :            :       // cppcheck-suppress useStlAlgorithm
     204         [ +  + ]:         42 :       for (auto& v : m_vec) v *= rhs;
     205                 :          6 :       return *this;
     206                 :            :     }
     207                 :            :     //! Operator * multiplying all items by a scalar
     208                 :            :     //! \param[in] rhs Scalar to multiply with
     209                 :            :     //! \return Copy of Data object after rhs has been multiplied with
     210                 :            :     //! \details Implemented in terms of compound operator*=
     211                 :          2 :     Data< Layout > operator* ( tk::real rhs )
     212 [ +  - ][ +  - ]:          4 :     const { return Data< Layout >( *this ) *= rhs; }
     213                 :            : 
     214                 :            :     //! Compound operator/=
     215                 :            :     //! \param[in] rhs Data object to divide by
     216                 :            :     //! \return Reference to ourselves after division
     217                 :          4 :     Data< Layout >& operator/= ( const Data< Layout >& rhs ) {
     218 [ -  + ][ -  - ]:          4 :       Assert( rhs.nunk() == m_nunk, "Incorrect number of unknowns" );
         [ -  - ][ -  - ]
     219 [ -  + ][ -  - ]:          4 :       Assert( rhs.nprop() == m_nprop, "Incorrect number of properties" );
         [ -  - ][ -  - ]
     220                 :          4 :       std::transform( rhs.vec().cbegin(), rhs.vec().cend(),
     221                 :            :                       m_vec.cbegin(), m_vec.begin(),
     222                 :         24 :                       []( tk::real s, tk::real d ){ return d/s; } );
     223                 :          4 :       return *this;
     224                 :            :     }
     225                 :            :     //! Operator /
     226                 :            :     //! \param[in] rhs Data object to divide by
     227                 :            :     //! \return Copy of Data object after rhs has been divided by
     228                 :            :     //! \details Implemented in terms of compound operator/=
     229                 :          2 :     Data< Layout > operator/ ( const Data< Layout >& rhs )
     230 [ +  - ][ +  - ]:          4 :     const { return Data< Layout >( *this ) /= rhs; }
                 [ +  - ]
     231                 :            : 
     232                 :            :     //! Compound operator/= dividing all items by a scalar
     233                 :            :     //! \param[in] rhs Scalar to divide with
     234                 :            :     //! \return Reference to ourselves after division
     235                 :          4 :     Data< Layout >& operator/= ( tk::real rhs ) {
     236                 :            :       // cppcheck-suppress useStlAlgorithm
     237         [ +  + ]:         28 :       for (auto& v : m_vec) v /= rhs;
     238                 :          4 :       return *this;
     239                 :            :     }
     240                 :            :     //! Operator / dividing all items by a scalar
     241                 :            :     //! \param[in] rhs Scalar to divide with
     242                 :            :     //! \return Copy of Data object after rhs has been divided by
     243                 :            :     //! \details Implemented in terms of compound operator/=
     244                 :          2 :     Data< Layout > operator/ ( tk::real rhs )
     245 [ +  - ][ +  - ]:          4 :     const { return Data< Layout >( *this ) /= rhs; }
     246                 :            : 
     247                 :            :     //! Add new unknown at the end of the container
     248                 :            :     //! \param[in] prop Vector of properties to initialize the new unknown with
     249                 :          1 :     void push_back( const std::vector< tk::real >& prop )
     250                 :          1 :     { return push_back( prop, int2type< Layout >() ); }
     251                 :            : 
     252                 :            :     //! Resize data store to contain 'count' elements
     253                 :            :     //! \param[in] count Resize store to contain count * nprop elements
     254                 :            :     //! \param[in] value Value to initialize new data with (default: 0.0)
     255                 :            :     //! \note This works for both shrinking and enlarging, as this simply
     256                 :            :     //!   translates to std::vector::resize(). Note that count changes, nprop
     257                 :            :     //!   does not, see the private overload resize().
     258                 :          2 :     void resize( std::size_t count, tk::real value = 0.0 )
     259                 :          2 :     { resize( count, value, int2type< Layout >() ); }
     260                 :            : 
     261                 :            :     //! Resize data given number of unknowns and number of properties
     262                 :            :     //! \param[in] nu Number of unknowns to allocate memory for
     263                 :            :     //! \param[in] np Total number of properties, i.e., scalar variables or
     264                 :            :     //!   components, per unknown
     265                 :       6744 :     void resize( std::size_t nu, std::size_t np ) {
     266                 :       6744 :       m_vec.resize( nu * np );
     267                 :       6744 :       m_nunk = nu;
     268                 :       6744 :       m_nprop = np;
     269                 :       6744 :     }
     270                 :            : 
     271                 :            :     //! Remove a number of unknowns
     272                 :            :     //! \param[in] unknown Set of indices of unknowns to remove
     273                 :          3 :     void rm( const std::set< ncomp_t >& unknown ) {
     274                 :         25 :       auto remove = [ &unknown ]( std::size_t i ) -> bool {
     275 [ +  - ][ +  + ]:         11 :         if (unknown.find(i) != end(unknown)) return true;
     276                 :          6 :         return false;
     277                 :            :       };
     278                 :          3 :       std::size_t last = 0;
     279         [ +  + ]:          7 :       for(std::size_t i=0; i<m_nunk; ++i, ++last) {
     280 [ +  - ][ +  + ]:         11 :         while( remove(i) ) ++i;
     281         [ +  + ]:          6 :         if (i >= m_nunk) break;
     282         [ +  + ]:         11 :         for (ncomp_t p = 0; p<m_nprop; ++p)
     283                 :          7 :           m_vec[ last*m_nprop+p ] = m_vec[ i*m_nprop+p ];
     284                 :            :       }
     285         [ +  - ]:          3 :       m_vec.resize( last*m_nprop );
     286                 :          3 :       m_nunk -= unknown.size();
     287                 :          3 :     }
     288                 :            : 
     289                 :            :     //! Fill vector of unknowns with the same value
     290                 :            :     //! \details Requirement: component < nprop, enforced with an assert in
     291                 :            :     //!   DEBUG mode, see also the constructor.
     292                 :            :     //! \param[in] component Component index, i.e., position of a scalar within
     293                 :            :     //!   a system
     294                 :            :     //! \param[in] value Value to fill vector of unknowns with
     295                 :          4 :     inline void fill( ncomp_t component, tk::real value ) {
     296                 :          4 :       auto p = cptr( component );
     297         [ +  + ]:         16 :       for (ncomp_t i=0; i<m_nunk; ++i) var(p,i) = value;
     298                 :          4 :     }
     299                 :            : 
     300                 :            :     //! Fill full data storage with value
     301                 :            :     //! \param[in] value Value to fill data with
     302                 :     176009 :     void fill( tk::real value )
     303                 :     176009 :     { std::fill( begin(m_vec), end(m_vec), value ); }
     304                 :            : 
     305                 :            :     //! Check if vector of unknowns is empty
     306                 :            :     bool empty() const noexcept { return m_vec.empty(); }
     307                 :            : 
     308                 :            :     //! Layout name dispatch
     309                 :            :     //! \return The name of the data layout used
     310                 :          2 :     static std::string layout() { return layout( int2type< Layout >() ); }
     311                 :            : 
     312                 :            :     /** @name Pack/Unpack: Serialize Data object for Charm++ */
     313                 :            :     ///@{
     314                 :            :     //! \brief Pack/Unpack serialize member function
     315                 :            :     //! \param[in,out] p Charm++'s PUP::er serializer object reference
     316                 :            :     // cppcheck-suppress constParameter
     317                 :      60541 :     void pup( PUP::er &p ) {
     318                 :      60541 :       p | m_vec;
     319                 :      60541 :       p | m_nunk;
     320                 :      60541 :       p | m_nprop;
     321                 :      60541 :     }
     322                 :            :     //! \brief Pack/Unpack serialize operator|
     323                 :            :     //! \param[in,out] p Charm++'s PUP::er serializer object reference
     324                 :            :     //! \param[in,out] d DataLyaout object reference
     325                 :      60541 :     friend void operator|( PUP::er& p, Data& d ) { d.pup(p); }
     326                 :            :     //@}
     327                 :            : 
     328                 :            :   private:
     329                 :            :     //! Transform a compile-time uint8_t into a type, used for dispatch
     330                 :            :     //! \see A. Alexandrescu, Modern C++ Design: Generic Programming and Design
     331                 :            :     //!   Patterns Applied, Addison-Wesley Professional, 2001.
     332                 :            :     template< uint8_t m > struct int2type { enum { value = m }; };
     333                 :            : 
     334                 :            :     //! Const ptr to physical variable access dispatch
     335                 :            :     //! \details Public interface to the first half of a physical variable
     336                 :            :     //!   access. cptr() and var() are two member functions intended to be used
     337                 :            :     //!   together in case when component would be expensive to compute for data
     338                 :            :     //!   access via the function call operator, i.e., cptr(), can be used to
     339                 :            :     //!   pre-compute part of the address, which returns a pointer and var() can
     340                 :            :     //!   be used to finish the data access using the pointer returned by
     341                 :            :     //!   cptr(). In other words, cptr() returns part of the address known based
     342                 :            :     //!   on component and intended to be used in a setup phase. Then var()
     343                 :            :     //!   takes this partial address and finishes the address calculation given
     344                 :            :     //!   the unknown id. Thus the following two data accesses are equivalent
     345                 :            :     //!   (modulo constness):
     346                 :            :     //!   * real& value = operator()( unk, comp ); and
     347                 :            :     //!   * const real* p = cptr( comp ); and
     348                 :            :     //!     const real& value = var( p, unk ); or real& value = var( p, unk );
     349                 :            :     //!   Requirement: component < nprop, enforced with an assert in DEBUG mode,
     350                 :            :     //!   see also the constructor.
     351                 :            :     //! \param[in] component Component index, i.e., position of a scalar within
     352                 :            :     //!   a system
     353                 :            :     //! \return Pointer to data of type tk::real for use with var()
     354                 :            :     const tk::real*
     355                 :    6058956 :     cptr( ncomp_t component ) const
     356                 :    6058956 :     { return cptr( component, int2type< Layout >() ); }
     357                 :            : 
     358                 :            :     //! Const-ref data-access dispatch
     359                 :            :     //! \details Public interface to the second half of a physical variable
     360                 :            :     //!   access. cptr() and var() are two member functions intended to be used
     361                 :            :     //!   together in case when component would be expensive to compute for data
     362                 :            :     //!   access via the function call operator, i.e., cptr(), can be used to
     363                 :            :     //!   pre-compute part of the address, which returns a pointer and var() can
     364                 :            :     //!   be used to finish the data access using the pointer returned by
     365                 :            :     //!   cptr(). In other words, cptr() returns part of the address known based
     366                 :            :     //!   on component and intended to be used in a setup phase. Then var()
     367                 :            :     //!   takes this partial address and finishes the address calculation given
     368                 :            :     //!   the unknown id. Thus the following two data accesses are equivalent
     369                 :            :     //!   (modulo constness):
     370                 :            :     //!   * real& value = operator()( unk, comp ); and
     371                 :            :     //!   * const real* p = cptr( comp ); and
     372                 :            :     //!     const real& value = var( p, unk ); or real& value = var( p, unk );
     373                 :            :     //!   Requirement: unknown < nunk, enforced with an assert in DEBUG mode,
     374                 :            :     //!   see also the constructor.
     375                 :            :     //! \param[in] pt Pointer to data of type tk::real as returned from cptr()
     376                 :            :     //! \param[in] unknown Unknown index
     377                 :            :     //! \return Const reference to data of type tk::real
     378                 :            :     const tk::real&
     379                 :   24235820 :     var( const tk::real* pt, ncomp_t unknown ) const
     380                 :   24235820 :     { return var( pt, unknown, int2type< Layout >() ); }
     381                 :            : 
     382                 :            :     //! Non-const-ref data-access dispatch
     383                 :            :     //! \details Public interface to the second half of a physical variable
     384                 :            :     //!   access. cptr() and var() are two member functions intended to be used
     385                 :            :     //!   together in case when component would be expensive to compute for data
     386                 :            :     //!   access via the function call operator, i.e., cptr(), can be used to
     387                 :            :     //!   pre-compute part of the address, which returns a pointer and var() can
     388                 :            :     //!   be used to finish the data access using the pointer returned by
     389                 :            :     //!   cptr(). In other words, cptr() returns part of the address known based
     390                 :            :     //!   on component and intended to be used in a setup phase. Then var()
     391                 :            :     //!   takes this partial address and finishes the address calculation given
     392                 :            :     //!   the unknown id. Thus the following two data accesses are equivalent
     393                 :            :     //!   (modulo constness):
     394                 :            :     //!   * real& value = operator()( unk, comp ); and
     395                 :            :     //!   * const real* p = cptr( comp ); and
     396                 :            :     //!     const real& value = var( p, unk ); or real& value = var( p, unk );
     397                 :            :     //!   Requirement: unknown < nunk, enforced with an assert in DEBUG mode,
     398                 :            :     //!   see also the constructor.
     399                 :            :     //! \param[in] pt Pointer to data of type tk::real as returned from cptr()
     400                 :            :     //! \param[in] unknown Unknown index
     401                 :            :     //! \return Non-const reference to data of type tk::real
     402                 :            :     //! \see "Avoid Duplication in const and Non-const Member Function," and
     403                 :            :     //!   "Use const whenever possible," Scott Meyers, Effective C++, 3d ed.
     404                 :            :     tk::real&
     405                 :         12 :     var( const tk::real* pt, ncomp_t unknown ) {
     406                 :            :       return const_cast< tk::real& >(
     407                 :         12 :                static_cast< const Data& >( *this ).var( pt, unknown ) );
     408                 :            :     }
     409                 :            : 
     410                 :            :     //! Overloads for the various const data accesses
     411                 :            :     //! \details Requirement: component < nprop, unknown < nunk, enforced with
     412                 :            :     //!   an assert in DEBUG mode, see also the constructor.
     413                 :            :     //! \param[in] unknown Unknown index
     414                 :            :     //! \param[in] component Component index, i.e., position of a scalar within
     415                 :            :     //!   a system
     416                 :            :     //! \return Const reference to data of type tk::real
     417                 :            :     //! \see A. Alexandrescu, Modern C++ Design: Generic Programming and Design
     418                 :            :     //!   Patterns Applied, Addison-Wesley Professional, 2001.
     419                 :            :     const tk::real&
     420                 : 6008400916 :     access( ncomp_t unknown, ncomp_t component, int2type< UnkEqComp > ) const {
     421 [ +  + ][ +  - ]: 6008400916 :       Assert( component < m_nprop,
         [ +  - ][ +  - ]
     422                 :            :               "Out-of-bounds access: component < number of properties" );
     423 [ +  + ][ +  - ]: 6008400910 :       Assert( unknown < m_nunk,
         [ +  - ][ +  - ]
     424                 :            :               "Out-of-bounds access: unknown < number of unknowns" );
     425                 : 6008400902 :       return m_vec[ unknown*m_nprop + component ];
     426                 :            :     }
     427                 :            :     const tk::real&
     428                 :        375 :     access( ncomp_t unknown, ncomp_t component, int2type< EqCompUnk > ) const {
     429 [ +  + ][ +  - ]:        375 :       Assert( component < m_nprop,
         [ +  - ][ +  - ]
     430                 :            :               "Out-of-bounds access: component < number of properties" );
     431 [ +  + ][ +  - ]:        369 :       Assert( unknown < m_nunk,
         [ +  - ][ +  - ]
     432                 :            :               "Out-of-bounds access: unknown < number of unknowns" );
     433                 :        362 :       return m_vec[ component*m_nunk + unknown ];
     434                 :            :     }
     435                 :            : 
     436                 :            :     // Overloads for the various const ptr to physical variable accesses
     437                 :            :     //! \details Requirement: component < nprop, unknown < nunk, enforced with
     438                 :            :     //!   an assert in DEBUG mode, see also the constructor.
     439                 :            :     //! \param[in] component Component index, i.e., position of a scalar within
     440                 :            :     //!   a system
     441                 :            :     //! \return Pointer to data of type tk::real for use with var()
     442                 :            :     //! \see A. Alexandrescu, Modern C++ Design: Generic Programming and Design
     443                 :            :     //!   Patterns Applied, Addison-Wesley Professional, 2001.
     444                 :            :     const tk::real*
     445                 :    6058952 :     cptr( ncomp_t component, int2type< UnkEqComp > ) const {
     446 [ -  + ][ -  - ]:    6058952 :       Assert( component < m_nprop,
         [ -  - ][ -  - ]
     447                 :            :               "Out-of-bounds access: component < number of properties" );
     448                 :    6058952 :       return m_vec.data() + component;
     449                 :            :     }
     450                 :            :     const tk::real*
     451                 :          4 :     cptr( ncomp_t component, int2type< EqCompUnk > ) const {
     452 [ -  + ][ -  - ]:          4 :       Assert( component < m_nprop,
         [ -  - ][ -  - ]
     453                 :            :               "Out-of-bounds access: component < number of properties" );
     454                 :          4 :       return m_vec.data() + component*m_nunk;
     455                 :            :     }
     456                 :            : 
     457                 :            :     // Overloads for the various const physical variable accesses
     458                 :            :     //!   Requirement: unknown < nunk, enforced with an assert in DEBUG mode,
     459                 :            :     //!   see also the constructor.
     460                 :            :     //! \param[in] pt Pointer to data of type tk::real as returned from cptr()
     461                 :            :     //! \param[in] unknown Unknown index
     462                 :            :     //! \return Const reference to data of type tk::real
     463                 :            :     //! \see A. Alexandrescu, Modern C++ Design: Generic Programming and Design
     464                 :            :     //!   Patterns Applied, Addison-Wesley Professional, 2001.
     465                 :            :     inline const tk::real&
     466                 :   24235806 :     var( const tk::real* const pt, ncomp_t unknown, int2type< UnkEqComp > )
     467                 :            :     const {
     468 [ -  + ][ -  - ]:   24235806 :       Assert( unknown < m_nunk, "Out-of-bounds access: unknown < number of "
         [ -  - ][ -  - ]
     469                 :            :               "unknowns" );
     470                 :   24235806 :       return *(pt + unknown*m_nprop);
     471                 :            :     }
     472                 :            :     inline const tk::real&
     473                 :         14 :     var( const tk::real* const pt, ncomp_t unknown, int2type< EqCompUnk > )
     474                 :            :     const {
     475 [ -  + ][ -  - ]:         14 :       Assert( unknown < m_nunk, "Out-of-bounds access: unknown < number of "
         [ -  - ][ -  - ]
     476                 :            :               "unknowns" );
     477                 :         14 :       return *(pt + unknown);
     478                 :            :     }
     479                 :            : 
     480                 :            :     //! Add new unknown
     481                 :            :     //! \param[in] prop Vector of properties to initialize the new unknown with
     482                 :            :     //! \note Only the UnkEqComp overload is provided as this operation would be
     483                 :            :     //!   too inefficient with the EqCompUnk data layout.
     484                 :          1 :     void push_back( const std::vector< tk::real >& prop, int2type< UnkEqComp > )
     485                 :            :     {
     486 [ -  + ][ -  - ]:          1 :       Assert( prop.size() == m_nprop, "Incorrect number of properties" );
         [ -  - ][ -  - ]
     487                 :          1 :       m_vec.resize( (m_nunk+1) * m_nprop );
     488                 :          1 :       ncomp_t u = m_nunk;
     489                 :          1 :       ++m_nunk;
     490         [ +  + ]:          3 :       for (ncomp_t i=0; i<m_nprop; ++i) operator()( u, i ) = prop[i];
     491                 :          1 :     }
     492                 :            : 
     493                 :            :     void push_back( const std::vector< tk::real >&, int2type< EqCompUnk > )
     494                 :            :     { Throw( "Not implented. It would be inefficient" ); }
     495                 :            : 
     496                 :            :     //! Resize data store to contain 'count' elements
     497                 :            :     //! \param[in] count Resize store to contain 'count' elements
     498                 :            :     //! \param[in] value Value to initialize new data with
     499                 :            :     //! \note Only the UnkEqComp overload is provided as this operation would be
     500                 :            :     //!   too inefficient with the EqCompUnk data layout.
     501                 :            :     //! \note This works for both shrinking and enlarging, as this simply
     502                 :            :     //!   translates to std::vector::resize().
     503                 :          2 :     void resize( std::size_t count, tk::real value, int2type< UnkEqComp > ) {
     504                 :          2 :       m_vec.resize( count * m_nprop, value );
     505                 :          2 :       m_nunk = count;
     506                 :          2 :     }
     507                 :            : 
     508                 :            :     void resize( std::size_t, tk::real, int2type< EqCompUnk > ) {
     509                 :            :       Throw( "Not implemented. It would be inefficient" );
     510                 :            :     }
     511                 :            : 
     512                 :            :     // Overloads for the name-queries of data lauouts
     513                 :            :     //! \return The name of the data layout used
     514                 :            :     //! \see A. Alexandrescu, Modern C++ Design: Generic Programming and Design
     515                 :            :     //!   Patterns Applied, Addison-Wesley Professional, 2001.
     516                 :          1 :     static std::string layout( int2type< UnkEqComp > )
     517         [ +  - ]:          1 :     { return "unknown-major"; }
     518                 :          1 :     static std::string layout( int2type< EqCompUnk > )
     519         [ +  - ]:          1 :     { return "equation-major"; }
     520                 :            : 
     521                 :            :     std::vector< tk::real > m_vec;      //!< Data pointer
     522                 :            :     ncomp_t m_nunk;                     //!< Number of unknowns
     523                 :            :     ncomp_t m_nprop;                    //!< Number of properties/unknown
     524                 :            : };
     525                 :            : 
     526                 :            : //! Operator * multiplying all items by a scalar from the left
     527                 :            : //! \param[in] lhs Scalar to multiply with
     528                 :            : //! \param[in] rhs Date object to multiply
     529                 :            : //! \return New Data object with all items multipled with lhs
     530                 :            : template< uint8_t Layout >
     531                 :          2 : Data< Layout > operator* ( tk::real lhs, const Data< Layout >& rhs ) {
     532 [ +  - ][ +  - ]:          4 :   return Data< Layout >( rhs ) *= lhs;
     533                 :            : }
     534                 :            : 
     535                 :            : //! Operator min between two Data objects
     536                 :            : //! \param[in] a 1st Data object
     537                 :            : //! \param[in] b 2nd Data object
     538                 :            : //! \return New Data object containing the minimum of all values for each
     539                 :            : //!   value in _a_ and _b_
     540                 :            : //! \note The Data objects _a_ and _b_ must have the same number of
     541                 :            : //!   unknowns and properties.
     542                 :            : //! \note As opposed to std::min, this function creates and returns a new object
     543                 :            : //!   instead of returning a reference to one of the operands.
     544                 :            : template< uint8_t Layout >
     545                 :          2 : Data< Layout > min( const Data< Layout >& a, const Data< Layout >& b ) {
     546 [ -  + ][ -  - ]:          2 :   Assert( a.nunk() == b.nunk(), "Number of unknowns unequal" );
         [ -  - ][ -  - ]
     547 [ -  + ][ -  - ]:          2 :   Assert( a.nprop() == b.nprop(), "Number of properties unequal" );
         [ -  - ][ -  - ]
     548                 :          2 :   Data< Layout > r( a.nunk(), a.nprop() );
     549         [ +  - ]:          4 :   std::transform( a.vec().cbegin(), a.vec().cend(),
     550                 :          4 :                   b.vec().cbegin(), r.vec().begin(),
     551                 :         12 :                   []( tk::real s, tk::real d ){ return std::min(s,d); } );
     552                 :            : 
     553                 :          2 :   return r;
     554                 :          0 : }
     555                 :            : 
     556                 :            : //! Operator max between two Data objects
     557                 :            : //! \param[in] a 1st Data object
     558                 :            : //! \param[in] b 2nd Data object
     559                 :            : //! \return New Data object containing the maximum of all values for each
     560                 :            : //!   value in _a_ and _b_
     561                 :            : //! \note The Data objects _a_ and _b_ must have the same number of
     562                 :            : //!   unknowns and properties.
     563                 :            : //! \note As opposed to std::max, this function creates and returns a new object
     564                 :            : //!   instead of returning a reference to one of the operands.
     565                 :            : template< uint8_t Layout >
     566                 :          2 : Data< Layout > max( const Data< Layout >& a, const Data< Layout >& b ) {
     567 [ -  + ][ -  - ]:          2 :   Assert( a.nunk() == b.nunk(), "Number of unknowns unequal" );
         [ -  - ][ -  - ]
     568 [ -  + ][ -  - ]:          2 :   Assert( a.nprop() == b.nprop(), "Number of properties unequal" );
         [ -  - ][ -  - ]
     569                 :          2 :   Data< Layout > r( a.nunk(), a.nprop() );
     570         [ +  - ]:          4 :   std::transform( a.vec().cbegin(), a.vec().cend(),
     571                 :          4 :                   b.vec().cbegin(), r.vec().begin(),
     572                 :         12 :                   []( tk::real s, tk::real d ){ return std::max(s,d); } );
     573                 :          2 :   return r;
     574                 :          0 : }
     575                 :            : 
     576                 :            : //! Operator == between two Data objects
     577                 :            : //! \param[in] lhs Data object to compare
     578                 :            : //! \param[in] rhs Data object to compare
     579                 :            : //! \return True if all entries are equal up to epsilon
     580                 :            : template< uint8_t Layout >
     581                 :          8 : bool operator== ( const Data< Layout >& lhs, const Data< Layout >& rhs ) {
     582 [ -  + ][ -  - ]:          8 :   Assert( rhs.nunk() == lhs.nunk(), "Incorrect number of unknowns" );
         [ -  - ][ -  - ]
     583 [ -  + ][ -  - ]:          8 :   Assert( rhs.nprop() == lhs.nprop(), "Incorrect number of properties" );
         [ -  - ][ -  - ]
     584                 :          8 :   auto l = lhs.vec().cbegin();
     585                 :          8 :   auto r = rhs.vec().cbegin();
     586         [ +  + ]:         32 :   while (l != lhs.vec().cend()) {
     587         [ +  + ]:         28 :     if (std::abs(*l - *r) > std::numeric_limits< tk::real >::epsilon())
     588                 :          4 :      return false;
     589                 :         24 :     ++l; ++r;
     590                 :            :   }
     591                 :          4 :   return true;
     592                 :            : }
     593                 :            : 
     594                 :            : //! Operator != between two Data objects
     595                 :            : //! \param[in] lhs Data object to compare
     596                 :            : //! \param[in] rhs Data object to compare
     597                 :            : //! \return True if all entries are unequal up to epsilon
     598                 :            : template< uint8_t Layout >
     599                 :          4 : bool operator!= ( const Data< Layout >& lhs, const Data< Layout >& rhs )
     600                 :          4 : { return !(lhs == rhs); }
     601                 :            : 
     602                 :            : //! Compute the maximum difference between the elements of two Data objects
     603                 :            : //! \param[in] lhs 1st Data object
     604                 :            : //! \param[in] rhs 2nd Data object
     605                 :            : //! \return The index, i.e., the raw position, of and the largest absolute value
     606                 :            : //!   of the difference between all corresponding elements of _lhs_ and _rhs_.
     607                 :            : //! \details The position returned is the position in the underlying raw data
     608                 :            : //!   structure, independent of components. If lhs == rhs with precision
     609                 :            : //!   std::numeric_limits< tk::real >::epsilon(), a pair of (0,0.0) is returned.
     610                 :            : //! \note The Data objects _lhs_ and _rhs_ must have the same number of
     611                 :            : //!   unknowns and properties.
     612                 :            : template< uint8_t Layout >
     613                 :            : std::pair< std::size_t, tk::real >
     614                 :          4 : maxdiff( const Data< Layout >& lhs, const Data< Layout >& rhs ) {
     615 [ -  + ][ -  - ]:          4 :   Assert( lhs.nunk() == rhs.nunk(), "Number of unknowns unequal" );
         [ -  - ][ -  - ]
     616 [ -  + ][ -  - ]:          4 :   Assert( lhs.nprop() == rhs.nprop(), "Number of properties unequal" );
         [ -  - ][ -  - ]
     617                 :          4 :   auto l = lhs.vec().cbegin();
     618                 :          4 :   auto r = rhs.vec().cbegin();
     619                 :          4 :   std::pair< std::size_t, tk::real > m( 0, std::abs(*l - *r) );
     620                 :          4 :   ++l; ++r;
     621         [ +  + ]:         24 :   while (l != lhs.vec().cend()) {
     622                 :         20 :     const auto d = std::abs(*l - *r);
     623 [ +  + ][ +  - ]:         20 :     if (d > m.second) m = { std::distance(lhs.vec().cbegin(),l), d };
     624                 :         20 :     ++l; ++r;
     625                 :            :   }
     626                 :          4 :   return m;
     627                 :            : }
     628                 :            : 
     629                 :            : } // tk::
     630                 :            : 
     631                 :            : #endif // Data_h

Generated by: LCOV version 1.16