GEOS
wrapperHelpers.hpp
Go to the documentation of this file.
1 /*
2  * ------------------------------------------------------------------------------------------------------------
3  * SPDX-License-Identifier: LGPL-2.1-only
4  *
5  * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC
6  * Copyright (c) 2018-2024 TotalEnergies
7  * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University
8  * Copyright (c) 2023-2024 Chevron
9  * Copyright (c) 2019- GEOS/GEOSX Contributors
10  * All rights reserved
11  *
12  * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details.
13  * ------------------------------------------------------------------------------------------------------------
14  */
15 
20 #ifndef GEOS_DATAREPOSITORY_WRAPPERHELPERS_HPP_
21 #define GEOS_DATAREPOSITORY_WRAPPERHELPERS_HPP_
22 
23 
25 #define RESTART_TYPE_LOGGING 0
26 
27 // Source includes
28 #include "BufferOps.hpp"
29 #include "BufferOpsDevice.hpp"
30 #include "DefaultValue.hpp"
31 #include "ConduitRestart.hpp"
32 #include "common/DataTypes.hpp"
33 #include "common/GeosxMacros.hpp"
34 #include "common/Span.hpp"
35 #include "codingUtilities/traits.hpp"
36 #include "LvArray/src/system.hpp"
37 
38 #if defined(GEOS_USE_PYGEOSX)
39 #include "LvArray/src/python/python.hpp"
40 #endif
41 
42 // TPL includes
43 #include <conduit.hpp>
44 
45 // System includes
46 #include <cstring>
47 
48 #if RESTART_TYPE_LOGGING
49 #include <unordered_set>
50 #endif
51 
52 namespace geos
53 {
54 namespace dataRepository
55 {
56 namespace wrapperHelpers
57 {
58 namespace internal
59 {
60 
61 inline void logOutputType( string const & typeString, string const & msg )
62 {
63 #if RESTART_TYPE_LOGGING
64  static std::unordered_set< string > m_types;
65 
66  if( !m_types.count( typeString ) )
67  {
68  m_types.insert( typeString );
69  GEOS_LOG( msg << typeString );
70  }
71 #else
72  GEOS_DEBUG_VAR( typeString );
73  GEOS_DEBUG_VAR( msg );
74 #endif
75 }
76 
77 template< typename T, typename ... INDICES >
78 string getIndicesToComponent( T const &, int const component, INDICES const ... existingIndices )
79 {
80  GEOS_ERROR_IF_NE( component, 0 );
81  return LvArray::indexing::getIndexString( existingIndices ... );
82 }
83 
84 template< typename ... INDICES >
85 string getIndicesToComponent( R1Tensor const &, int const component, INDICES const ... existingIndices )
86 { return LvArray::indexing::getIndexString( existingIndices ..., component ); }
87 
88 template< typename T >
89 T const * getPointerToComponent( T const & var, int const component )
90 {
91  GEOS_ERROR_IF_NE( component, 0 );
92  return &var;
93 }
94 
95 inline
96 real64 const * getPointerToComponent( R1Tensor const & var, int const component )
97 {
98  GEOS_ERROR_IF_GE( component, 3 );
99  return &var[ component ];
100 }
101 
102 } // namespace internal
103 
104 template< typename T >
105 class ArrayDimLabels
106 {
107 public:
108 
109  void set( integer const, Span< string const > )
110  {
111  GEOS_ERROR( "Dimension labels are only available in Array wrappers" );
112  }
113 
114  Span< string const > get( integer const ) const
115  {
116  GEOS_ERROR( "Dimension labels are only available in Array wrappers" );
117  return {};
118  }
119 };
120 
121 template< typename T, int NDIM, typename PERM >
122 class ArrayDimLabels< Array< T, NDIM, PERM > >
123 {
124 public:
125 
126  void set( integer const dim, Span< string const > labels )
127  {
128  GEOS_ERROR_IF_LT( dim, 0 );
129  GEOS_ERROR_IF_GE( dim, NDIM );
130  m_values[dim].resize( labels.size() );
131  std::copy( labels.begin(), labels.end(), m_values[dim].begin() );
132  }
133 
134  Span< string const > get( integer const dim ) const
135  {
136  GEOS_ERROR_IF_LT( dim, 0 );
137  GEOS_ERROR_IF_GE( dim, NDIM );
138  return { m_values[dim].begin(), m_values[dim].end() };
139  }
140 
141 private:
142 
143  string_array m_values[NDIM]{};
144 };
145 
146 template< typename T >
147 inline std::enable_if_t< traits::HasMemberFunction_size< T >, size_t >
148 size( T const & value )
149 { return value.size(); }
150 
151 template< typename T >
152 inline std::enable_if_t< !traits::HasMemberFunction_size< T >, size_t >
153 size( T const & GEOS_UNUSED_PARAM( value ) )
154 { return 1; }
155 
156 
157 inline char *
158 dataPtr( string & var )
159 { return const_cast< char * >( var.data() ); }
160 
161 inline char *
162 dataPtr( Path & var )
163 { return const_cast< char * >( var.data() ); }
164 
165 template< typename T >
166 inline std::enable_if_t< traits::HasMemberFunction_data< T >, typename traits::Pointer< T > >
167 dataPtr( T & value )
168 { return value.data(); }
169 
170 template< typename T >
171 inline std::enable_if_t< !traits::HasMemberFunction_data< T >, typename traits::Pointer< T > >
172 dataPtr( T & value )
173 { return &value; }
174 
175 template< class T >
176 inline typename traits::ConstPointer< T >
177 dataPtr( T const & value )
178 { return dataPtr( const_cast< T & >( value ) ); }
179 
180 
181 template< typename T >
182 inline std::enable_if_t< traits::HasMemberFunction_resize< T > >
183 resize( T & value, localIndex const newSize )
184 { value.resize( newSize ); }
185 
186 template< typename T >
187 inline std::enable_if_t< !traits::HasMemberFunction_resize< T > >
188 resize( T & GEOS_UNUSED_PARAM( value ),
189  localIndex const GEOS_UNUSED_PARAM( newSize ) )
190 {}
191 
192 template< typename T >
193 inline void
194 resizeDefault( T & value,
195  localIndex const newSize,
196  DefaultValue< T > const & defaultValue,
197  string const & )
198 { value.resizeDefault( newSize, defaultValue.value ); }
199 
200 
201 
202 template< typename T, int NDIM, typename PERMUTATION >
203 inline void
204 resizeDimensions( Array< T, NDIM, PERMUTATION > & value, int num_dims, localIndex const * const dims )
205 { value.resize( num_dims, dims ); }
206 
207 template< typename T >
208 inline void
209 resizeDimensions( T & value, int num_dims, localIndex const * const dims )
210 {
211  if( num_dims != 1 )
212  {
213  GEOS_ERROR( "Data is not multidimensional" );
214  return;
215  }
216  resize( value, dims[ 0 ] );
217 }
218 
219 
220 template< typename T >
221 inline localIndex
222 byteSizeOfElement()
223 { return sizeof( *dataPtr( std::declval< T >() ) ); }
224 
225 
226 template< typename T >
227 inline size_t
228 byteSize( T const & value )
229 { return wrapperHelpers::size( value ) * byteSizeOfElement< T >(); }
230 
231 
232 template< typename T >
233 inline localIndex
234 numElementsFromByteSize( localIndex const byteSize )
235 {
236  GEOS_ERROR_IF_NE( byteSize % byteSizeOfElement< T >(), 0 );
237  return byteSize / byteSizeOfElement< T >();
238 }
239 
240 
241 template< typename T >
242 std::enable_if_t< traits::HasMemberFunction_reserve< T > >
243 reserve( T & value, localIndex const newCapacity )
244 { value.reserve( newCapacity ); }
245 
246 template< typename T >
247 std::enable_if_t< !traits::HasMemberFunction_reserve< T > >
248 reserve( T & GEOS_UNUSED_PARAM( value ), localIndex const GEOS_UNUSED_PARAM( newCapacity ) )
249 {}
250 
251 
252 template< typename T >
253 std::enable_if_t< traits::HasMemberFunction_capacity< T const >, localIndex >
254 capacity( T const & value )
255 { return value.capacity(); }
256 
257 template< typename T >
258 std::enable_if_t< !traits::HasMemberFunction_capacity< T const >, localIndex >
259 capacity( T const & value )
260 { return wrapperHelpers::size( value ); }
261 
262 
263 
264 template< typename T >
265 std::enable_if_t< traits::HasMemberFunction_setName< T > >
266 setName( T & value, string const & name )
267 { value.setName( name ); }
268 
269 template< typename T >
270 std::enable_if_t< !traits::HasMemberFunction_setName< T > >
271 setName( T & GEOS_UNUSED_PARAM( value ), string const & GEOS_UNUSED_PARAM( name ) )
272 {}
273 
274 template< typename T >
275 std::enable_if_t< traits::HasMemberFunction_move< T > >
276 move( T & value, LvArray::MemorySpace const space, bool const touch )
277 { value.move( space, touch ); }
278 
279 template< typename T >
280 std::enable_if_t< !traits::HasMemberFunction_move< T > >
281 move( T & GEOS_UNUSED_PARAM( value ),
282  LvArray::MemorySpace const GEOS_UNUSED_PARAM( space ),
283  bool const GEOS_UNUSED_PARAM( touch ) )
284 {}
285 
286 // This is for an object that needs to be packed.
287 template< typename T >
288 std::enable_if_t< !bufferOps::can_memcpy< typename traits::Pointer< T > > >
289 pushDataToConduitNode( T const & var, conduit::Node & node )
290 {
291  internal::logOutputType( LvArray::system::demangleType( var ), "Packing for output: " );
292 
293  // Get the number of bytes in the packed object.
294  localIndex const byteSize = bufferOps::PackSize( var );
295 
296  // Create a conduit data type that describes the array.
297  conduit::DataType const dtype( conduitTypeInfo< buffer_unit_type >::id, byteSize );
298 
299  // Allocate the array in the "__values__" child.
300  conduit::Node & valuesNode = node[ "__values__" ];
301  valuesNode.set( dtype );
302 
303  // Get the pointer to the array and pack the object into it.
304  buffer_unit_type * buffer = valuesNode.value();
305  bufferOps::Pack< true >( buffer, var );
306 }
307 
308 // This is for an object that needs to be packed.
309 template< typename T >
310 std::enable_if_t< !bufferOps::can_memcpy< typename traits::Pointer< T > > >
311 pullDataFromConduitNode( T & var, conduit::Node const & node )
312 {
313  conduit::Node const & valuesNode = node.fetch_existing( "__values__" );
314 
315  // Get the number of bytes in the array and a pointer to the array.
316  localIndex const byteSize = valuesNode.dtype().number_of_elements();
317  buffer_unit_type const * buffer = valuesNode.value();
318 
319  // Unpack the object from the array.
320  localIndex const bytesRead = bufferOps::Unpack( buffer, var );
321  GEOS_ERROR_IF_NE( bytesRead, byteSize );
322 }
323 
324 // This is for an string since the type of char is different on different platforms :(.
325 inline
326 void
327 pushDataToConduitNode( string const & var, conduit::Node & node )
328 {
329  internal::logOutputType( LvArray::system::demangleType( var ), "Output via external pointer: " );
330 
331  constexpr int conduitTypeID = conduitTypeInfo< signed char >::id;
332  conduit::DataType const dtype( conduitTypeID, var.size() );
333 
334  signed char * const ptr = const_cast< signed char * >( reinterpret_cast< signed char const * >( var.data() ) );
335  node[ "__values__" ].set_external( dtype, ptr );
336 }
337 
338 // This is for Path since it derives from string. See overload for string.
339 inline
340 void
341 pushDataToConduitNode( Path const & var, conduit::Node & node )
342 {
343  pushDataToConduitNode( static_cast< string const & >(var), node );
344 }
345 
346 // This is for an object that doesn't need to be packed but isn't an LvArray.
347 template< typename T >
348 std::enable_if_t< bufferOps::can_memcpy< typename traits::Pointer< T > > >
349 pushDataToConduitNode( T const & var, conduit::Node & node )
350 {
351  internal::logOutputType( LvArray::system::demangleType( var ), "Output via external pointer: " );
352 
353  constexpr int conduitTypeID = conduitTypeInfo< typename traits::Pointer< T > >::id;
354  constexpr int sizeofConduitType = conduitTypeInfo< typename traits::Pointer< T > >::sizeOfConduitType;
355  localIndex const numBytes = byteSize( var );
356  conduit::DataType const dtype( conduitTypeID, numBytes / sizeofConduitType );
357 
358  void * const ptr = const_cast< void * >( static_cast< void const * >( dataPtr( var ) ) );
359  node[ "__values__" ].set_external( dtype, ptr );
360 }
361 
362 // This is for an object that doesn't need to be packed but isn't an LvArray or a SortedArray.
363 template< typename T >
364 std::enable_if_t< bufferOps::can_memcpy< typename traits::Pointer< T > > >
365 pullDataFromConduitNode( T & var, conduit::Node const & node )
366 {
367  conduit::Node const & valuesNode = node.fetch_existing( "__values__" );
368 
369  localIndex const byteSize = LvArray::integerConversion< localIndex >( valuesNode.dtype().strided_bytes() );
370  localIndex const numElements = numElementsFromByteSize< T >( byteSize );
371 
372  resize( var, numElements );
373 
374  std::memcpy( dataPtr( var ), valuesNode.data_ptr(), byteSize );
375 }
376 
377 // This is for a SortedArray that doesn't need to be packed.
378 template< typename T >
379 std::enable_if_t< bufferOps::can_memcpy< T > >
380 pullDataFromConduitNode( SortedArray< T > & var, conduit::Node const & node )
381 {
382  conduit::Node const & valuesNode = node.fetch_existing( "__values__" );
383 
384  localIndex const byteSize = LvArray::integerConversion< localIndex >( valuesNode.dtype().strided_bytes() );
385  localIndex const numElements = numElementsFromByteSize< T >( byteSize );
386 
387  T const * const values = reinterpret_cast< T const * >( valuesNode.data_ptr() );
388  var.insert( values, values + numElements );
389 }
390 
391 
392 // This is an LvArray that doesn't need to be packed.
393 template< typename T, int NDIM, typename PERMUTATION >
394 std::enable_if_t< bufferOps::can_memcpy< T > >
395 pushDataToConduitNode( Array< T, NDIM, PERMUTATION > const & var,
396  conduit::Node & node )
397 {
398  internal::logOutputType( LvArray::system::demangleType( var ), "Output array via external pointer: " );
399 
400  // Push the data into conduit
401  constexpr int conduitTypeID = conduitTypeInfo< T >::id;
402  constexpr int sizeofConduitType = conduitTypeInfo< T >::sizeOfConduitType;
403  conduit::DataType const dtype( conduitTypeID, var.size() * sizeof( T ) / sizeofConduitType );
404  void * const ptr = const_cast< void * >( static_cast< void const * >( var.data() ) );
405  node[ "__values__" ].set_external( dtype, ptr );
406 
407  // Create a copy of the dimensions
408  camp::idx_t temp[ NDIM + 1 ];
409  for( int i = 0; i < NDIM; ++i )
410  {
411  temp[ i ] = var.size( i );
412  }
413 
414  // If T is something like a Tensor than there is an extra implicit dimension.
415  constexpr int const implicitDimensionLength = conduitTypeInfo< T >::numConduitValues;
416  constexpr bool const hasImplicitDimension = implicitDimensionLength != 1;
417  constexpr int totalNumDimensions = NDIM + hasImplicitDimension;
418  if( hasImplicitDimension )
419  {
420  temp[ NDIM ] = implicitDimensionLength;
421  }
422 
423  // push the dimensions into the node
424  conduit::DataType const dimensionType( conduitTypeInfo< camp::idx_t >::id, totalNumDimensions );
425  node[ "__dimensions__" ].set( dimensionType, temp );
426 
427  // Create a copy of the permutation
428  constexpr std::array< camp::idx_t, NDIM > const perm = RAJA::as_array< PERMUTATION >::get();
429  for( int i = 0; i < NDIM; ++i )
430  {
431  temp[ i ] = perm[ i ];
432  }
433 
434  if( hasImplicitDimension )
435  {
436  temp[ NDIM ] = NDIM;
437  }
438 
439  node[ "__permutation__" ].set( dimensionType, temp );
440 }
441 
442 // This is an LvArray that doesn't need to be packed.
443 template< typename T, int NDIM, typename PERMUTATION >
444 std::enable_if_t< bufferOps::can_memcpy< T > >
445 pullDataFromConduitNode( Array< T, NDIM, PERMUTATION > & var,
446  conduit::Node const & node )
447 {
448  // Get the number of dimensions written out, accounting for an implicit dimension and the permutation.
449  constexpr int const implicitDimensionLength = conduitTypeInfo< T >::numConduitValues;
450  constexpr bool const hasImplicitDimension = implicitDimensionLength != 1;
451  constexpr int totalNumDimensions = NDIM + hasImplicitDimension;
452 
453  // Check that the permutations match.
454  conduit::Node const & permutationNode = node.fetch_existing( "__permutation__" );
455  GEOS_ERROR_IF_NE( permutationNode.dtype().number_of_elements(), totalNumDimensions );
456 
457  constexpr std::array< camp::idx_t, NDIM > const perm = RAJA::as_array< PERMUTATION >::get();
458  camp::idx_t const * const permFromConduit = permutationNode.value();
459  for( int i = 0; i < NDIM; ++i )
460  {
461  GEOS_ERROR_IF_NE_MSG( permFromConduit[ i ], perm[ i ],
462  "The permutation of the data in conduit and the provided Array don't match." );
463  }
464 
465  if( hasImplicitDimension )
466  {
467  GEOS_ERROR_IF_NE_MSG( permFromConduit[ NDIM ], NDIM,
468  "The permutation of the data in conduit and the provided Array don't match." );
469  }
470 
471  // Now pull out the dimensions and resize the array.
472  conduit::Node const & dimensionNode = node.fetch_existing( "__dimensions__" );
473  GEOS_ERROR_IF_NE( dimensionNode.dtype().number_of_elements(), totalNumDimensions );
474  camp::idx_t const * const dims = dimensionNode.value();
475 
476  if( hasImplicitDimension )
477  {
478  GEOS_ERROR_IF_NE( dims[ NDIM ], implicitDimensionLength );
479  }
480 
481  var.resize( NDIM, dims );
482 
483  // Finally memcpy
484  conduit::Node const & valuesNode = node.fetch_existing( "__values__" );
485  localIndex numBytesFromArray = var.size() * sizeof( T );
486  GEOS_ERROR_IF_NE( numBytesFromArray, valuesNode.dtype().strided_bytes() );
487  std::memcpy( var.data(), valuesNode.data_ptr(), numBytesFromArray );
488 }
489 
490 
491 
492 template< typename T, typename INDEX_TYPE >
493 std::enable_if_t< bufferOps::can_memcpy< T > >
494 pushDataToConduitNode( ArrayOfArrays< T, INDEX_TYPE > const & var2,
495  conduit::Node & node )
496 {
497  ArrayOfArraysView< T const, INDEX_TYPE > const & var = var2.toViewConst();
498  internal::logOutputType( LvArray::system::demangleType( var ), "Output array via external pointer: " );
499 
500  // ArrayOfArrays::m_numArrays
501  INDEX_TYPE const numArrays = var.size();
502  conduit::DataType const numArraysType( conduitTypeInfo< INDEX_TYPE >::id, 1 );
503  node[ "__numberOfArrays__" ].set( numArraysType, const_cast< void * >( static_cast< void const * >(&numArrays) ) );
504 
505  // ArrayOfArrays::m_offsets
506  INDEX_TYPE const * const offsets = var.getOffsets();
507  conduit::DataType const offsetsType( conduitTypeInfo< INDEX_TYPE >::id, numArrays+1 );
508  node[ "__offsets__" ].set_external( offsetsType, const_cast< void * >( static_cast< void const * >( offsets ) ) );
509 
510  // ArrayOfArrays::m_sizes
511  INDEX_TYPE const * const sizes = var.getSizes();
512  conduit::DataType const sizesType( conduitTypeInfo< INDEX_TYPE >::id, numArrays );
513  node[ "__sizes__" ].set_external( sizesType, const_cast< void * >( static_cast< void const * >( sizes ) ) );
514 
515  // **** WARNING: alters the uninitialized values in the ArrayOfArrays ****
516  T * const values = const_cast< T * >(var.getValues());
517  for( INDEX_TYPE i = 0; i < numArrays; ++i )
518  {
519  INDEX_TYPE const curOffset = offsets[ i ];
520  INDEX_TYPE const nextOffset = offsets[ i + 1 ];
521  for( INDEX_TYPE j = curOffset + var.sizeOfArray( i ); j < nextOffset; ++j )
522  {
523  if constexpr ( std::is_arithmetic< T >::value )
524  {
525  values[ j ] = 0;
526  }
527  else
528  {
529  values[ j ] = T();
530  }
531  }
532  }
533 
534  constexpr int conduitTypeID = conduitTypeInfo< T >::id;
535  constexpr int sizeofConduitType = conduitTypeInfo< T >::sizeOfConduitType;
536  conduit::DataType const dtype( conduitTypeID, offsets[numArrays] * sizeof( T ) / sizeofConduitType );
537 
538  // Push the data into conduit
539  node[ "__values__" ].set_external( dtype, values );
540 }
541 
542 template< typename T, typename INDEX_TYPE >
543 std::enable_if_t< bufferOps::can_memcpy< T > >
544 pullDataFromConduitNode( ArrayOfArrays< T, INDEX_TYPE > & var,
545  conduit::Node const & node )
546 {
547 
548  // numArrays node
549  conduit::Node const & numArraysNode = node.fetch_existing( "__numberOfArrays__" );
550  INDEX_TYPE const * const numArrays = numArraysNode.value();
551 
552  // offsets node
553  conduit::Node const & offsetsNode = node.fetch_existing( "__offsets__" );
554  conduit::DataType const & offsetsDataType = offsetsNode.dtype();
555  INDEX_TYPE const * const offsets = offsetsNode.value();
556  INDEX_TYPE const sizeOffsets = offsetsDataType.number_of_elements();
557 
558  // sizes node
559  conduit::Node const & sizesNode = node.fetch_existing( "__sizes__" );
560  conduit::DataType const & sizesDataType = sizesNode.dtype();
561  INDEX_TYPE const * const sizes = sizesNode.value();
562  INDEX_TYPE const sizeSizes = sizesDataType.number_of_elements();
563 
564  // Check that the numArrays, sizes and offsets are consistent.
565  GEOS_ERROR_IF_NE( *numArrays, sizeSizes );
566  GEOS_ERROR_IF_NE( *numArrays+1, sizeOffsets );
567 
568  // values node
569  conduit::Node const & valuesNode = node.fetch_existing( "__values__" );
570  conduit::DataType const & valuesDataType = valuesNode.dtype();
571  const INDEX_TYPE valuesSize = valuesDataType.number_of_elements();
572 
573  // should preallocate var.m_values with estimated sizes
574  INDEX_TYPE const arraySizeEstimate = (*numArrays)==0 ? 0 : valuesSize / (*numArrays);
575  var.resize( *numArrays, arraySizeEstimate );
576  var.reserveValues( valuesSize );
577 
578  // correctly set the sizes and capacities of each sub-array
579  localIndex allocatedSize = 0;
580  for( INDEX_TYPE i = 0; i < *numArrays; ++i )
581  {
582  INDEX_TYPE const arrayAllocation = offsets[i+1] - offsets[i];
583  var.setCapacityOfArray( i, arrayAllocation );
584  var.resizeArray( i, sizes[ i ] );
585  allocatedSize += arrayAllocation;
586  }
587 
588  // make sure that the allocated size is the same as the number of values read
589  GEOS_ERROR_IF_NE( valuesSize, allocatedSize );
590 
591  // make sure the allocatedSize is consistent wit the last offset
592  GEOS_ERROR_IF_NE( allocatedSize, offsets[sizeOffsets-1] );
593 
594  // get a view because the ArrayOfArraysView data accessors are protected
595  ArrayOfArraysView< T const, INDEX_TYPE > const & varView = var.toViewConst();
596  INDEX_TYPE const * const varOffsets = varView.getOffsets();
597  INDEX_TYPE const * const varSizes = varView.getSizes();
598 
599  // check that the offsets that are read are the same as the ones that were allocated
600  GEOS_ERROR_IF_NE( varOffsets[0], offsets[0] );
601 
602  // check each subarray has the identical capacity and size
603  for( INDEX_TYPE i = 0; i<*numArrays; ++i )
604  {
605  GEOS_ERROR_IF_NE( varOffsets[i+1], offsets[i+1] );
606  GEOS_ERROR_IF_NE( varSizes[i], sizes[i] );
607  }
608 
609  // copy the values
610  localIndex numBytesFromArray = allocatedSize * sizeof( T );
611  GEOS_ERROR_IF_NE( numBytesFromArray, valuesDataType.strided_bytes() );
612  std::memcpy( const_cast< T * >(varView.getValues()), valuesNode.data_ptr(), numBytesFromArray );
613 }
614 
615 
616 
617 template< typename T >
618 void pushDataToConduitNode( InterObjectRelation< T > const & var,
619  conduit::Node & node )
620 {return pushDataToConduitNode( var.base(), node ); }
621 
622 template< typename T >
623 void pullDataFromConduitNode( InterObjectRelation< T > & var,
624  conduit::Node const & node )
625 { return pullDataFromConduitNode( var.base(), node ); }
626 
627 
629 template< typename T, int NDIM, int USD >
630 std::enable_if_t< std::is_arithmetic< T >::value || traits::is_tensorT< T > >
631 addBlueprintField( ArrayView< T const, NDIM, USD > const & var,
632  conduit::Node & fields,
633  string const & fieldName,
634  string const & topology,
635  stdVector< string > const & componentNames )
636 {
637  GEOS_ERROR_IF_LE( var.size(), 0 );
638 
639  using ConduitType = typename conduitTypeInfo< T >::type;
640  constexpr int conduitTypeID = conduitTypeInfo< T >::id;
641  constexpr int numComponentsPerValue = conduitTypeInfo< T >::numConduitValues;
642 
643  localIndex const totalNumberOfComponents = numComponentsPerValue * var.size() / var.size( 0 );
644  if( !componentNames.empty() )
645  {
646  GEOS_ERROR_IF_NE( localIndex( componentNames.size() ), totalNumberOfComponents );
647  }
648 
649  var.move( hostMemorySpace, false );
650 
651  conduit::DataType dtype( conduitTypeID, var.size( 0 ) );
652  dtype.set_stride( sizeof( ConduitType ) * numComponentsPerValue * var.strides()[ 0 ] );
653 
654  localIndex curComponent = 0;
655  LvArray::forValuesInSliceWithIndices( var[ 0 ], [&fields, &fieldName, &topology, &componentNames, totalNumberOfComponents, &dtype, &curComponent]
656  ( T const & val, auto const ... indices )
657  {
658  for( int i = 0; i < numComponentsPerValue; ++i )
659  {
660  string name;
661  if( totalNumberOfComponents == 1 )
662  {
663  name = fieldName;
664  }
665  else if( componentNames.empty() )
666  {
667  string indexString = internal::getIndicesToComponent( val, i, indices ... );
668  indexString.erase( indexString.begin() );
669  indexString.pop_back();
670  indexString.pop_back();
671  name = fieldName + indexString;
672  }
673  else
674  {
675  name = componentNames[ curComponent++ ];
676  }
677 
678  conduit::Node & field = fields[ name ];
679  field[ "association" ] = "element";
680  field[ "volume_dependent" ] = "false";
681  field[ "topology" ] = topology;
682 
683  void const * pointer = internal::getPointerToComponent( val, i );
684  field[ "values" ].set_external( dtype, const_cast< void * >( pointer ) );
685  }
686  } );
687 }
688 
689 template< typename T >
690 void addBlueprintField( T const &,
691  conduit::Node & fields,
692  string const &,
693  string const &,
694  stdVector< string > const & )
695 {
696  GEOS_ERROR( "Cannot create a mcarray out of " << LvArray::system::demangleType< T >() <<
697  "\nWas trying to write it to " << fields.path() );
698  GEOS_UNUSED_VAR( fields );
699 }
700 
701 template< typename T, int NDIM, int USD >
702 std::enable_if_t< std::is_arithmetic< T >::value || traits::is_tensorT< T > >
703 populateMCArray( ArrayView< T const, NDIM, USD > const & var,
704  conduit::Node & node,
705  stdVector< string > const & componentNames )
706 {
707  GEOS_ERROR_IF_LE( var.size(), 0 );
708 
709  using ConduitType = typename conduitTypeInfo< T >::type;
710  constexpr int conduitTypeID = conduitTypeInfo< T >::id;
711  constexpr int numComponentsPerValue = conduitTypeInfo< T >::numConduitValues;
712 
713  if( !componentNames.empty() )
714  {
715  GEOS_ERROR_IF_NE( localIndex( componentNames.size() ), numComponentsPerValue * var.size() / var.size( 0 ) );
716  }
717 
718  var.move( hostMemorySpace, false );
719 
720  conduit::DataType dtype( conduitTypeID, var.size( 0 ) );
721  dtype.set_stride( sizeof( ConduitType ) * numComponentsPerValue * var.strides()[ 0 ] );
722 
723  localIndex curComponent = 0;
724  LvArray::forValuesInSliceWithIndices( var[ 0 ], [&componentNames, &node, &dtype, &curComponent]
725  ( T const & val, auto const ... indices )
726  {
727  for( int i = 0; i < numComponentsPerValue; ++i )
728  {
729  string const name = componentNames.empty() ? internal::getIndicesToComponent( val, i, indices ... ) :
730  componentNames[ curComponent++ ];
731 
732  void const * pointer = internal::getPointerToComponent( val, i );
733  node[ name ].set_external( dtype, const_cast< void * >( pointer ) );
734  }
735  } );
736 }
737 
738 template< typename T >
739 void populateMCArray( T const &,
740  conduit::Node & node,
741  stdVector< string > const & )
742 {
743  GEOS_ERROR( "Cannot create a mcarray out of " << LvArray::system::demangleType< T >() <<
744  "\nWas trying to write it to " << node.path() );
745  GEOS_UNUSED_VAR( node );
746 }
747 
748 template< typename T >
749 std::enable_if_t< std::is_arithmetic< T >::value, std::unique_ptr< Array< T, 1 > > >
750 averageOverSecondDim( ArrayView< T const, 1, 0 > const & var )
751 {
752  std::unique_ptr< Array< T, 1 > > ret = std::make_unique< Array< T, 1 > >();
753 
754  ret->resize( var.size() );
755  ret->template setValues< serialPolicy >( var );
756 
757  return ret;
758 }
759 
760 template< typename T, int NDIM, int USD >
761 std::enable_if_t< std::is_arithmetic< T >::value, std::unique_ptr< Array< T, NDIM - 1 > > >
762 averageOverSecondDim( ArrayView< T const, NDIM, USD > const & var )
763 {
764  std::unique_ptr< Array< T, NDIM - 1 > > ret = std::make_unique< Array< T, NDIM - 1 > >();
765 
766  localIndex newDims[ NDIM - 1 ];
767  newDims[ 0 ] = var.size( 0 );
768  for( int i = 2; i < NDIM; ++i )
769  {
770  newDims[ i - 1 ] = var.size( i );
771  }
772 
773  ret->resize( NDIM - 1, newDims );
774 
775  ArrayView< T, NDIM - 1 > const & output = *ret;
776 
777  localIndex const numSamples = var.size( 1 );
778  forAll< serialPolicy >( var.size( 0 ), [var, numSamples, &output] ( localIndex const i )
779  {
780  LvArray::sumOverFirstDimension( var[ i ], output[ i ] );
781 
782  LvArray::forValuesInSlice( output[ i ], [numSamples] ( T & val )
783  {
784  val /= numSamples;
785  } );
786  } );
787 
788  return ret;
789 }
790 
791 template< typename T >
792 std::unique_ptr< int > averageOverSecondDim( T const & )
793 {
794  GEOS_ERROR( "Cannot average over the second dimension of " << LvArray::system::demangleType< T >() );
795  return std::unique_ptr< int >( nullptr );
796 }
797 
798 template< typename T, int NDIM, int USD >
799 int numArrayDims( ArrayView< T const, NDIM, USD > const & GEOS_UNUSED_PARAM( var ) )
800 {
801  return NDIM;
802 }
803 
804 template< typename T >
805 int numArrayDims( stdVector< T > const & GEOS_UNUSED_PARAM( var ) )
806 {
807  return 1;
808 }
809 
810 template< typename T >
811 int numArrayDims( T const & GEOS_UNUSED_PARAM( var ) )
812 {
813  return 0;
814 }
815 
816 template< typename T, int NDIM, int USD >
817 localIndex numArrayComp( ArrayView< T const, NDIM, USD > const & var )
818 {
819  return LvArray::indexing::multiplyAll< NDIM - 1 >( var.dims() + 1 );
820 }
821 
822 template< typename T >
823 localIndex numArrayComp( ArrayView< T const, 1, 0 > const & GEOS_UNUSED_PARAM( var ) )
824 {
825  return 1;
826 }
827 
828 template< typename T >
829 localIndex numArrayComp( T const & GEOS_UNUSED_PARAM( var ) )
830 {
831  return 0;
832 }
833 
834 template< bool DO_PACKING, typename T, typename IDX >
835 inline std::enable_if_t< bufferOps::is_packable_by_index< T >, localIndex >
836 PackByIndex( buffer_unit_type * & buffer, T & var, IDX & idx )
837 { return bufferOps::PackByIndex< DO_PACKING >( buffer, var, idx ); }
838 
839 template< bool DO_PACKING, typename T, typename IDX >
840 inline std::enable_if_t< !bufferOps::is_packable_by_index< T >, localIndex >
841 PackByIndex( buffer_unit_type * &, T &, IDX & )
842 {
843  GEOS_ERROR( "Trying to pack data type (" << LvArray::system::demangleType< T >() << ") by index. Operation not supported." );
844  return 0;
845 }
846 
847 template< typename T, typename IDX >
848 inline std::enable_if_t< bufferOps::is_packable_by_index< T >, localIndex >
849 UnpackByIndex( buffer_unit_type const * & buffer, T & var, IDX & idx )
850 { return bufferOps::UnpackByIndex( buffer, var, idx ); }
851 
852 template< typename T, typename IDX >
853 inline std::enable_if_t< !bufferOps::is_packable_by_index< T >, localIndex >
854 UnpackByIndex( buffer_unit_type const * &, T &, IDX & )
855 {
856  GEOS_ERROR( "Trying to unpack data type (" << LvArray::system::demangleType< T >() << ") by index. Operation not supported." );
857  return 0;
858 }
859 
860 
861 template< bool DO_PACKING, typename T >
862 inline std::enable_if_t< bufferOps::is_container< T > || bufferOps::can_memcpy< T >, localIndex >
863 PackDevice( buffer_unit_type * & buffer, T const & var, parallelDeviceEvents & events )
864 { return bufferOps::PackDevice< DO_PACKING >( buffer, var, events ); }
865 
866 
867 template< bool DO_PACKING, typename T >
868 inline std::enable_if_t< !bufferOps::is_container< T > && !bufferOps::can_memcpy< T >, localIndex >
869 PackDevice( buffer_unit_type * &, T const &, parallelDeviceEvents & )
870 {
871  GEOS_ERROR( "Trying to pack data type (" << LvArray::system::demangleType< T >() << ") on device. Operation not supported." );
872  return 0;
873 }
874 
875 template< bool DO_PACKING, typename T, typename IDX >
876 inline std::enable_if_t< bufferOps::is_container< T >, localIndex >
877 PackByIndexDevice( buffer_unit_type * & buffer, T const & var, IDX & idx, parallelDeviceEvents & events )
878 { return bufferOps::PackByIndexDevice< DO_PACKING >( buffer, var, idx, events ); }
879 
880 template< bool DO_PACKING, typename T, typename IDX >
881 inline std::enable_if_t< !bufferOps::is_container< T >, localIndex >
882 PackByIndexDevice( buffer_unit_type * &, T const &, IDX &, parallelDeviceEvents & )
883 {
884  GEOS_ERROR( "Trying to pack data type (" << LvArray::system::demangleType< T >() << ") by index on device. Operation not supported." );
885  return 0;
886 }
887 
888 template< typename T >
889 inline std::enable_if_t< bufferOps::is_container< T >, localIndex >
890 UnpackDevice( buffer_unit_type const * & buffer, T const & var, parallelDeviceEvents & events )
891 { return bufferOps::UnpackDevice( buffer, var, events ); }
892 
893 template< typename T >
894 inline std::enable_if_t< !bufferOps::is_container< T >, localIndex >
895 UnpackDevice( buffer_unit_type const * &, T const &, parallelDeviceEvents & )
896 {
897  GEOS_ERROR( "Trying to unpack data type (" << LvArray::system::demangleType< T >() << ") on device. Operation not supported." );
898  return 0;
899 }
900 
901 template< typename T, typename IDX >
902 inline std::enable_if_t< bufferOps::is_container< T >, localIndex >
903 UnpackByIndexDevice( buffer_unit_type const * & buffer, T const & var, IDX & idx, parallelDeviceEvents & events, MPI_Op op=MPI_REPLACE )
904 { return bufferOps::UnpackByIndexDevice( buffer, var, idx, events, op ); }
905 
906 template< typename T, typename IDX >
907 inline std::enable_if_t< !bufferOps::is_container< T >, localIndex >
908 UnpackByIndexDevice( buffer_unit_type const * &, T &, IDX &, parallelDeviceEvents &, MPI_Op )
909 {
910  GEOS_ERROR( "Trying to unpack data type (" << LvArray::system::demangleType< T >() << ") by index on device. Operation not supported." );
911  return 0;
912 }
913 
914 
915 template< bool DO_PACKING, typename T >
917 PackDataDevice( buffer_unit_type * & buffer, T const & var, parallelDeviceEvents & events )
918 { return bufferOps::PackDataDevice< DO_PACKING >( buffer, var, events ); }
919 
920 template< bool DO_PACKING, typename T, typename IDX >
921 inline std::enable_if_t< bufferOps::is_container< T >, localIndex >
922 PackDataByIndexDevice( buffer_unit_type * & buffer, T const & var, IDX & idx, parallelDeviceEvents & events )
923 { return bufferOps::PackDataByIndexDevice< DO_PACKING >( buffer, var, idx, events ); }
924 
925 template< bool DO_PACKING, typename T, typename IDX >
926 inline std::enable_if_t< !bufferOps::is_container< T >, localIndex >
927 PackDataByIndexDevice( buffer_unit_type * &, T const &, IDX &, parallelDeviceEvents & )
928 {
929  GEOS_ERROR( "Trying to pack data type (" << LvArray::system::demangleType< T >() << ") by index on device. Operation not supported." );
930  return 0;
931 }
932 
933 template< typename T >
934 inline std::enable_if_t< bufferOps::is_container< T >, localIndex >
935 UnpackDataDevice( buffer_unit_type const * & buffer, T const & var, parallelDeviceEvents & events )
936 { return bufferOps::UnpackDataDevice( buffer, var, events ); }
937 
938 template< typename T >
939 inline std::enable_if_t< !bufferOps::is_container< T >, localIndex >
940 UnpackDataDevice( buffer_unit_type const * &, T const &, parallelDeviceEvents & )
941 {
942  GEOS_ERROR( "Trying to unpack data type (" << LvArray::system::demangleType< T >() << ") on device. Operation not supported." );
943  return 0;
944 }
945 
946 template< typename T, typename IDX >
947 inline std::enable_if_t< bufferOps::is_container< T >, localIndex >
948 UnpackDataByIndexDevice( buffer_unit_type const * & buffer, T const & var, IDX & idx, parallelDeviceEvents & events, MPI_Op op )
949 { return bufferOps::UnpackDataByIndexDevice( buffer, var, idx, events, op ); }
950 
951 template< typename T, typename IDX >
952 inline std::enable_if_t< !bufferOps::is_container< T >, localIndex >
953 UnpackDataByIndexDevice( buffer_unit_type const * &, T const &, IDX &, parallelDeviceEvents &, MPI_Op )
954 {
955  GEOS_ERROR( "Trying to unpack data type (" << LvArray::system::demangleType< T >() << ") by index on device. Operation not supported." );
956  return 0;
957 }
958 
959 #if defined(GEOS_USE_PYGEOSX)
960 
961 template< typename T >
962 inline std::enable_if_t< LvArray::python::CanCreate< T >, PyObject * >
963 createPythonObject( T & object )
964 { return LvArray::python::create( object ); }
965 
966 template< typename T >
967 inline std::enable_if_t< !LvArray::python::CanCreate< T >, PyObject * >
968 createPythonObject( T & )
969 { return nullptr; }
970 
971 #endif
972 
973 } // namespace wrapperHelpers
974 } // namespace dataRepository
975 } // namespace geos
976 
977 #undef RESTART_TYPE_LOGGING
978 
979 #endif // GEOS_DATAREPOSITORY_WRAPPERHELPERS_HPP_
#define GEOS_UNUSED_VAR(...)
Mark an unused variable and silence compiler warnings.
Definition: GeosxMacros.hpp:84
#define GEOS_DEBUG_VAR(...)
Mark a debug variable and silence compiler warnings.
Definition: GeosxMacros.hpp:87
#define GEOS_UNUSED_PARAM(X)
Mark an unused argument and silence compiler warnings.
Definition: GeosxMacros.hpp:72
#define GEOS_ERROR_IF_LE(lhs, rhs)
Raise a hard error if one value compares less than or equal to the other.
Definition: Logger.hpp:387
#define GEOS_ERROR_IF_LT(lhs, rhs)
Raise a hard error if one value compares less than the other.
Definition: Logger.hpp:355
#define GEOS_ERROR_IF_GE(lhs, rhs)
Raise a hard error if one value compares greater than or equal to the other.
Definition: Logger.hpp:323
#define GEOS_LOG(...)
Log a message on screen.
Definition: Logger.hpp:40
#define GEOS_ERROR(msg)
Raise a hard error and terminate the program.
Definition: Logger.hpp:157
#define GEOS_ERROR_IF_NE(lhs, rhs)
Raise a hard error if two values are not equal.
Definition: Logger.hpp:259
#define GEOS_ERROR_IF_NE_MSG(lhs, rhs, msg)
Raise a hard error if two values are not equal.
Definition: Logger.hpp:243
stdVector< string > string_array
A 1-dimensional array of geos::string types.
Definition: DataTypes.hpp:401
LvArray::Array< T, NDIM, PERMUTATION, localIndex, LvArray::ChaiBuffer > Array
Multidimensional array type. See LvArray:Array for details.
Definition: DataTypes.hpp:150
std::set< T > set
A set of local indices.
Definition: DataTypes.hpp:271
double real64
64-bit floating point type.
Definition: DataTypes.hpp:98
GEOS_LOCALINDEX_TYPE localIndex
Local index type (for indexing objects within an MPI partition).
Definition: DataTypes.hpp:84
std::int32_t integer
Signed integer type.
Definition: DataTypes.hpp:81
Tensor< real64, 3 > R1Tensor
Alias for a local (stack-based) rank-1 tensor type.
Definition: DataTypes.hpp:174
signed char buffer_unit_type
Type stored in communication buffers.
Definition: DataTypes.hpp:117
LvArray::ArrayView< T, NDIM, USD, localIndex, LvArray::ChaiBuffer > ArrayView
Multidimensional array view type. See LvArray:ArrayView for details.
Definition: DataTypes.hpp:156