GEOS
StatisticsAggregatorBaseHelpers.hpp
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 
16 #include "mesh/MeshBody.hpp"
18 
19 #include "LvArray/src/math.hpp"
20 #include "common/DataTypes.hpp"
21 #include "common/format/Format.hpp"
23 #include "common/logger/Logger.hpp"
25 #include "dataRepository/Group.hpp"
27 #include "mesh/CellElementSubRegion.hpp"
29 #include "mesh/MeshLevel.hpp"
30 
31 namespace geos
32 {
33 
34 inline RegionStatisticsBase::RegionStatisticsBase( string const & targetName,
35  dataRepository::Group * const parent,
36  bool const statsOutputEnabled ):
37  dataRepository::Group( targetName, parent ),
38  m_time( std::numeric_limits< double >::lowest() )
39 {
40  Group::setRestartFlags( statsOutputEnabled ?
43 
44  // TODO : registerWrappers to store results in HDF5 (but need repairing of 1D HDF5 outputs)
45 }
46 
47 template< typename Impl >
49  dataRepository::Group & meshBodies,
50  bool const statsOutputEnabled ):
51  m_ownerDataContext( ownerDataContext ),
52  m_statsOutputEnabled( statsOutputEnabled ),
53  m_meshBodies( meshBodies )
54 {}
55 
56 template< typename Impl >
57 void
59 {
60  solver.forDiscretizationOnMeshTargets( m_meshBodies, [&] ( string const & meshBodyName,
61  MeshLevel & mesh,
62  string_array const & regionNames )
63  {
64  // getting the container of all requesters statistics groups (can be already initialized)
65  dataRepository::Group * meshStatsGroup = mesh.getGroupPointer( ViewKeys::statisticsString() );
66  if( meshStatsGroup == nullptr )
67  meshStatsGroup = &mesh.registerGroup( ViewKeys::statisticsString() );
68 
69  // registering the container of instance statistics groups (must be unique for this instance)
70  string const & ownerName = getOwnerName();
71  GEOS_ERROR_IF_NE_MSG( meshStatsGroup->hasGroup( ownerName ), false,
72  GEOS_FMT( "A statistics aggregator have already been requested for '{}'.",
73  ownerName ),
74  m_ownerDataContext );
75  meshStatsGroup->registerGroup( ownerName );
76 
77  // remembering the path of this discretization
78  MeshBody const & body = m_meshBodies.getGroup< MeshBody >( meshBodyName );
79  DiscretizationGroupPath const path {
80  /* .m_meshBody = */ body.getIndexInParent(),
81  /* .m_meshLevel = */ mesh.getIndexInParent(),
82  /* .m_regionNames = */ regionNames,
83  };
84  m_discretizationsPaths.push_back( path );
85  } );
86 }
87 
88 template< typename Impl >
89 void
91 {
92  integer regionCount = 0;
93  integer subRegionCount = 0;
94 
95  for( auto const & path : m_discretizationsPaths )
96  {
97  MeshLevel & mesh = getMeshLevel( path );
98  ElementRegionManager & elemManager = mesh.getElemManager();
99  dataRepository::Group & statisticsGroup = getInstanceStatisticsGroup( mesh );
100  StatsGroupType & meshRegionsStats = registerStatsFunc( statisticsGroup,
101  ViewKeys::regionsStatisticsString() );
102 
103  for( size_t i = 0; i < path.m_regionNames.size(); ++i )
104  {
105  CellElementRegion & region = elemManager.getRegion< CellElementRegion >( path.m_regionNames[i] );
106  StatsGroupType & regionStats = registerStatsFunc( meshRegionsStats,
107  region.getName() );
108 
109  region.forElementSubRegions< CellElementSubRegion >( [&] ( CellElementSubRegion & subRegion )
110  {
111  registerStatsFunc( regionStats,
112  subRegion.getName() );
113  ++subRegionCount;
114  } );
115  ++regionCount;
116  }
117  }
118 
119  GEOS_ERROR_IF( regionCount == 0 || subRegionCount == 0,
120  GEOS_FMT( "Missing region for computing statistics:\n- {} regions,\n- {} sub-regions.",
121  getOwnerName(), regionCount, subRegionCount ),
122  m_ownerDataContext );
123 
124  m_regionStatsState.m_isEnabled = true;
125  m_regionStatsState.m_isDirty = true;
126 }
127 
128 template< typename Impl >
129 void
130 StatsAggregatorBase< Impl >::forRegionStatistics( RegionStatsFunc< MeshLevel > const & func ) const
131 {
132  for( auto const & path : m_discretizationsPaths )
133  {
134  MeshLevel & mesh = getMeshLevel( path );
135  StatsGroupType & meshRegionsStats = getRegionsStatistics( mesh );
136 
137  func( mesh, meshRegionsStats );
138  }
139 }
140 
141 template< typename Impl >
142 void
143 StatsAggregatorBase< Impl >::forRegionStatistics( MeshLevel & mesh,
144  StatsGroupType & meshRegionsStatistics,
145  RegionStatsFunc< CellElementRegion > const & func ) const
146 {
147  ElementRegionManager & elemManager = mesh.getElemManager();
148  meshRegionsStatistics.template forSubGroups< StatsGroupType >( [&] ( StatsGroupType & regionStatistics )
149  {
150  string_view targetName = regionStatistics.getTargetName();
151  CellElementRegion & region = elemManager.getRegion< CellElementRegion >( string( targetName ) );
152 
153  func( region, regionStatistics );
154  } );
155 }
156 
157 template< typename Impl >
158 void
160  StatsGroupType & regionStatistics,
161  RegionStatsFunc< CellElementSubRegion > const & func ) const
162 {
163  regionStatistics.template forSubGroups< StatsGroupType >( [&] ( StatsGroupType & subRegionStatistics )
164  {
165  string_view targetName = subRegionStatistics.getTargetName();
166  CellElementSubRegion & subRegion = region.getSubRegion< CellElementSubRegion >( string( targetName ) );
167  func( subRegion, subRegionStatistics );
168  } );
169 }
170 
171 template< typename Impl >
172 bool
173 StatsAggregatorBase< Impl >::isComputed( real64 const timeRequest, StatsGroupType const & stats )
174 {
175  real64 const timePrecisionScale = LvArray::math::max( LvArray::math::abs( timeRequest ),
176  LvArray::math::abs( stats.m_time ) );
177  static constexpr real64 timeRelTol = 1.0e-12;
178 
179  return
180  !m_regionStatsState.m_isDirty &&
181  LvArray::math::abs( timeRequest - stats.m_time ) < timeRelTol * timePrecisionScale;
182 }
183 
184 template< typename Impl >
185 void
187 {
188  m_regionStatsState.m_isDirty = true;
189 }
190 
191 template< typename Impl >
192 bool
194 {
196 
197  m_warnings.clear();
198 
199  // computation of sub region stats
200  forRegionStatistics( [&, timeRequest] ( MeshLevel & mesh, StatsGroupType & meshRegionsStats )
201  {
202  forRegionStatistics( mesh,
203  meshRegionsStats,
204  [&, timeRequest] ( CellElementRegion & region, StatsGroupType & regionStats )
205  {
206  forRegionStatistics( region,
207  regionStats,
208  [&, timeRequest] ( CellElementSubRegion & subRegion, StatsGroupType & subRegionStats )
209  {
210  initStats( subRegionStats, timeRequest );
211  computeSubRegionRankStats( subRegion, subRegionStats );
212  } );
213  } );
214  } );
215 
216  // aggregation of computations from the sub regions
217  forRegionStatistics( [&, timeRequest] ( MeshLevel & mesh, StatsGroupType & meshRegionsStats )
218  {
219  initStats( meshRegionsStats, timeRequest );
220 
221  forRegionStatistics( mesh,
222  meshRegionsStats,
223  [&, timeRequest] ( CellElementRegion & region, StatsGroupType & regionStats )
224  {
225  initStats( regionStats, timeRequest );
226 
227  forRegionStatistics( region,
228  regionStats,
229  [&] ( CellElementSubRegion &, StatsGroupType & subRegionStats )
230  {
231  aggregateStats( regionStats, subRegionStats );
232 
233  mpiAggregateStats( subRegionStats );
234  postAggregateStats( subRegionStats );
235  } );
236 
237  aggregateStats( meshRegionsStats, regionStats );
238 
239  mpiAggregateStats( regionStats );
240  postAggregateStats( regionStats );
241  } );
242 
243  mpiAggregateStats( meshRegionsStats );
244  postAggregateStats( meshRegionsStats );
245  } );
246 
247  m_regionStatsState.m_isDirty = false;
248 
249  return true;
250 }
251 
252 template< typename Impl >
253 MeshLevel &
255 {
256  MeshBody & body = m_meshBodies.getGroup< MeshBody >( path.m_meshBody );
257  MeshLevel & mesh = body.getMeshLevel( path.m_meshLevel );
258  return mesh;
259 }
260 
261 template< typename Impl >
264 {
265  // considering everything is initialized, or else, crash gracefully
266  dataRepository::Group & meshStatsGroup = mesh.getGroup( ViewKeys::statisticsString() );
267  dataRepository::Group & instanceStatisticsGroup = meshStatsGroup.getGroup( getOwnerName() );
268  return instanceStatisticsGroup;
269 }
270 
271 template< typename Impl >
272 typename StatsAggregatorBase< Impl >::StatsGroupType &
273 StatsAggregatorBase< Impl >::
274 getRegionsStatistics( MeshLevel & mesh ) const
275 {
276  // considering everything is initialized, or else, crash gracefully
277  dataRepository::Group & instanceStatisticsGroup = getInstanceStatisticsGroup( mesh );
278  return instanceStatisticsGroup.getGroup< StatsGroupType >( ViewKeys::regionsStatisticsString() );
279 }
280 
281 template< typename Impl >
282 typename StatsAggregatorBase< Impl >::StatsGroupType &
284  string_view regionName ) const
285 {
286  StatsGroupType & meshRegionsStats = getRegionsStatistics( mesh );
287  StatsGroupType * const stats = meshRegionsStats.template getGroupPointer< StatsGroupType >( string( regionName ) );
288  GEOS_THROW_IF( stats == nullptr,
289  GEOS_FMT( "Region '{}' not found to get region statistics, is it a target of the reservoir solver?\n"
290  "Available target regions:\n- {}",
291  regionName, stringutilities::join( meshRegionsStats.getSubGroupsNames(), "\n- " ) ),
292  InputError, m_ownerDataContext );
293  return *stats;
294 }
295 
296 } /* namespace geos */
#define GEOS_ERROR_IF(COND,...)
Conditionally raise a hard error and terminate the program.
Definition: Logger.hpp:217
#define GEOS_ERROR_IF_NE_MSG(lhs, rhs,...)
Raise a hard error if two values are not equal.
Definition: Logger.hpp:472
#define GEOS_THROW_IF(COND, MSG,...)
Conditionally raise a hard error and terminate the program.
Definition: Logger.hpp:308
#define GEOS_MARK_FUNCTION
Mark function with both Caliper and NVTX if enabled.
void forElementSubRegions(LAMBDA &&lambda) const
Apply a lambda to all subregions.
SUBREGIONTYPE const & getSubRegion(KEY_TYPE const &key) const
Get a reference to a subregion.
The ElementRegionManager class provides an interface to ObjectManagerBase in order to manage ElementR...
T const & getRegion(KEY_TYPE const &key) const
Get a element region.
The class is used to manage mesh body.
Definition: MeshBody.hpp:36
MeshLevel & getMeshLevel(T const &level) const
Get a reference to a MeshLevel.
Definition: MeshBody.hpp:100
Class facilitating the representation of a multi-level discretization of a MeshBody.
Definition: MeshLevel.hpp:42
ElementRegionManager const & getElemManager() const
Get the element region manager.
Definition: MeshLevel.hpp:207
RegionStatisticsBase(string const &targetName, dataRepository::Group *const parent, bool statsOutputEnabled)
Construct a new Region Statistics Base object.
Reponsible of computing physical statistics over the grid, registering the result in the data reposit...
void initStatisticsAggregation(SolverType &solver)
Enable the computation of any statistics, initialize data structure to collect them....
std::function< StatsGroupType &(dataRepository::Group &, string const &) > RegionStatsRegisterFunc
A functor that can be used to register a statistics Group instance. Parameters:
StatsAggregatorBase(dataRepository::DataContext const &ownerDataContext, dataRepository::Group &meshBodies, bool statsOutputEnabled)
Construct a new Stats Aggregator object.
void setDirty()
set the statistics as dirty, ensuring isComputed() will be false until the next computation.
MeshLevel & getMeshLevel(DiscretizationGroupPath const &path) const
std::function< void(OwnerType &, StatsGroupType &) > RegionStatsFunc
Standard function signature for any functor that applies on statistics group instances (StatsGroupTyp...
StatsGroupType & getRegionStatistics(MeshLevel &mesh, string_view regionName) const
bool isComputed(real64 const timeRequest, StatsGroupType const &stats)
void enableRegionStatisticsAggregation(RegionStatsRegisterFunc &&registerStatsFunc)
Enable the computation of region statistics, initialize data structure to collect them....
bool computeRegionsStatistics(real64 const timeRequest)
Compute statistics on the mesh discretizations (average field pressure, etc) Results are reduced on r...
T * getGroupPointer(KEY const &key)
Return a pointer to a sub-group of the current Group.
Definition: Group.hpp:299
localIndex getIndexInParent() const
Get the group's index within its parent group.
Definition: Group.hpp:1391
T & registerGroup(string const &name, std::unique_ptr< T > newObject)
Register a new Group as a sub-group of current Group.
Definition: Group.hpp:200
void setRestartFlags(RestartFlags flags)
Set flags that control restart output of this group.
Definition: Group.hpp:1428
string const & getName() const
Get group name.
Definition: Group.hpp:1329
T & getGroup(KEY const &key)
Return a reference to a sub-group of the current Group.
Definition: Group.hpp:318
bool hasGroup(string const &name) const
Check whether a sub-group exists.
Definition: Group.hpp:405
@ WRITE_AND_READ
Write and read from restart.
@ NO_WRITE
Do not write into restart.
stdVector< string > string_array
A 1-dimensional array of geos::string types.
Definition: DataTypes.hpp:361
std::string string
String type.
Definition: DataTypes.hpp:90
double real64
64-bit floating point type.
Definition: DataTypes.hpp:98
int integer
Signed integer type.
Definition: DataTypes.hpp:81
std::string_view string_view
String type.
Definition: DataTypes.hpp:93
Exception class used to report errors in user input.