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