From cd677685e9a3662ba44b151b3d4e189cafdeaaac Mon Sep 17 00:00:00 2001 From: Tom Byer <149726499+tjb-ltk@users.noreply.github.com> Date: Tue, 23 Sep 2025 10:38:11 -0700 Subject: [PATCH 01/28] change validation for region statistics for by resvol constraint --- .../wells/CompositionalMultiphaseWell.cpp | 39 +++++++++---------- .../wells/CompositionalMultiphaseWell.hpp | 6 +-- .../fluidFlow/wells/SinglePhaseWell.cpp | 34 ++++++++-------- .../fluidFlow/wells/SinglePhaseWell.hpp | 8 ++-- .../fluidFlow/wells/WellSolverBase.cpp | 7 ++-- .../fluidFlow/wells/WellSolverBase.hpp | 3 +- 6 files changed, 50 insertions(+), 47 deletions(-) diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp index 14537f0d999..483ac3c5d3c 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp @@ -453,17 +453,7 @@ void CompositionalMultiphaseWell::validateWellConstraints( real64 const & time_n GEOS_FMT( "{}: Region {} is not a target of the reservoir solver and cannot be used for referenceReservoirRegion in WellControl {}.", getDataContext(), regionName, wellControls.getName() ) ); - ElementRegionBase const & region = elemManager.getRegion( wellControls.referenceReservoirRegion()); - // Check if regions statistics are being computed - GEOS_ERROR_IF( !region.hasWrapper( CompositionalMultiphaseStatistics::catalogName()), - GEOS_FMT( "{}: No region average quantities computed. WellControl {} referenceReservoirRegion field requires CompositionalMultiphaseStatistics to be configured for region {} ", - getDataContext(), wellControls.getName(), regionName )); - - CompositionalMultiphaseStatistics::RegionStatistics const & stats = region.getReference< CompositionalMultiphaseStatistics::RegionStatistics >( - CompositionalMultiphaseStatistics::regionStatisticsName() ); - wellControls.setRegionAveragePressure( stats.averagePressure ); - wellControls.setRegionAverageTemperature( stats.averageTemperature ); } } string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString()); @@ -682,7 +672,7 @@ void CompositionalMultiphaseWell::updateBHPForConstraint( WellElementSubRegion & } -void CompositionalMultiphaseWell::updateVolRatesForConstraint( WellElementSubRegion & subRegion ) +void CompositionalMultiphaseWell::updateVolRatesForConstraint( ElementRegionManager const & elemManager, WellElementSubRegion & subRegion ) { GEOS_MARK_FUNCTION; @@ -737,8 +727,16 @@ void CompositionalMultiphaseWell::updateVolRatesForConstraint( WellElementSubReg } else { + ElementRegionBase const & region = elemManager.getRegion( wellControls.referenceReservoirRegion()); + CompositionalMultiphaseStatistics::RegionStatistics const & stats = region.getReference< CompositionalMultiphaseStatistics::RegionStatistics >( + CompositionalMultiphaseStatistics::regionStatisticsName() ); + wellControls.setRegionAveragePressure( stats.averagePressure ); + wellControls.setRegionAverageTemperature( stats.averageTemperature ); + GEOS_ERROR_IF( stats.averagePressure <= 0.0, + GEOS_FMT( "{}: No region average quantities computed. WellControl {} referenceReservoirRegion field requires CompositionalMultiphaseStatistics to be configured for region {} ", + getDataContext(), wellControls.getName(), wellControls.referenceReservoirRegion() )); // If flashPressure is not set by region the value is defaulted to -1 and indicates to use top segment conditions - flashPressure = wellControls.getRegionAveragePressure(); + flashPressure = stats.averagePressure; if( flashPressure < 0.0 ) { // region name not set, use segment conditions @@ -1004,13 +1002,14 @@ void CompositionalMultiphaseWell::updateState( DomainPartition & domain ) MeshLevel & mesh, string_array const & regionNames ) { - mesh.getElemManager().forElementSubRegions< WellElementSubRegion >( regionNames, [&]( localIndex const, - WellElementSubRegion & subRegion ) + ElementRegionManager & elemManager = mesh.getElemManager(); + elemManager.forElementSubRegions< WellElementSubRegion >( regionNames, [&]( localIndex const, + WellElementSubRegion & subRegion ) { WellControls & wellControls = getWellControls( subRegion ); if( wellControls.getWellStatus() == WellControls::Status::OPEN ) { - real64 const maxRegionPhaseVolFrac = updateSubRegionState( subRegion ); + real64 const maxRegionPhaseVolFrac = updateSubRegionState( elemManager, subRegion ); maxPhaseVolFrac = LvArray::math::max( maxRegionPhaseVolFrac, maxPhaseVolFrac ); } } ); @@ -1023,14 +1022,14 @@ void CompositionalMultiphaseWell::updateState( DomainPartition & domain ) } -real64 CompositionalMultiphaseWell::updateSubRegionState( WellElementSubRegion & subRegion ) +real64 CompositionalMultiphaseWell::updateSubRegionState( ElementRegionManager const & elemManager, WellElementSubRegion & subRegion ) { // update properties updateGlobalComponentFraction( subRegion ); // update volumetric rates for the well constraints // note: this must be called before updateFluidModel - updateVolRatesForConstraint( subRegion ); + updateVolRatesForConstraint( elemManager, subRegion ); // update densities, phase fractions, phase volume fractions @@ -1148,7 +1147,7 @@ void CompositionalMultiphaseWell::initializeWells( DomainPartition & domain, rea wellElemCompDens ); // 5) Recompute the pressure-dependent properties - updateSubRegionState( subRegion ); + updateSubRegionState( elemManager, subRegion ); // 6) Estimate the well rates // TODO: initialize rates using perforation rates @@ -1954,7 +1953,7 @@ void CompositionalMultiphaseWell::resetStateToBeginningOfStep( DomainPartition & if( wellControls.isWellOpen( ) ) { - updateSubRegionState( subRegion ); + updateSubRegionState( elemManager, subRegion ); } } ); } ); @@ -2148,7 +2147,7 @@ void CompositionalMultiphaseWell::implicitStepSetup( real64 const & time_n, validateWellConstraints( time_n, dt, subRegion, elemManager ); - updateSubRegionState( subRegion ); + updateSubRegionState( elemManager, subRegion ); } } ) ; diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.hpp index fd874ec5a0e..819beafa0d8 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.hpp @@ -140,10 +140,10 @@ class CompositionalMultiphaseWell : public WellSolverBase /** * @brief Recompute the volumetric rates that are used in the well constraints + * @param elemManager the well region manager containing the well * @param subRegion the well subregion containing all the primary and dependent fields - * @param targetIndex the targetIndex of the subRegion */ - void updateVolRatesForConstraint( WellElementSubRegion & subRegion ); + void updateVolRatesForConstraint( ElementRegionManager const & elemManager, WellElementSubRegion & subRegion ); /** * @brief Recompute the current BHP pressure @@ -185,7 +185,7 @@ class CompositionalMultiphaseWell : public WellSolverBase */ virtual void updateState( DomainPartition & domain ) override; - virtual real64 updateSubRegionState( WellElementSubRegion & subRegion ) override; + virtual real64 updateSubRegionState( ElementRegionManager const & elemManager, WellElementSubRegion & subRegion ) override; virtual string wellElementDofName() const override { return viewKeyStruct::dofFieldString(); } diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.cpp index 4d49a5062e4..9db9bb4ce88 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.cpp @@ -164,16 +164,6 @@ void SinglePhaseWell::validateWellConstraints( real64 const & time_n, GEOS_FMT( "{}: Region {} is not a target of the reservoir solver and cannot be used for referenceReservoirRegion in WellControl {}.", getDataContext(), regionName, wellControls.getName() ) ); - ElementRegionBase const & region = elemManager.getRegion( wellControls.referenceReservoirRegion() ); - - // Check if regions statistics are being computed - GEOS_ERROR_IF( !region.hasWrapper( SinglePhaseStatistics::catalogName()), - GEOS_FMT( "{}: No region average quantities computed. WellControl {} referenceReservoirRegion field requires SinglePhaseStatistics to be configured for region {} ", - getDataContext(), wellControls.getName(), regionName )); - - SinglePhaseStatistics::RegionStatistics const & stats = region.getReference< SinglePhaseStatistics::RegionStatistics >( SinglePhaseStatistics::regionStatisticsName() ); - wellControls.setRegionAveragePressure( stats.averagePressure ); - wellControls.setRegionAverageTemperature( stats.averageTemperature ); } } WellControls::Control currentControl = wellControls.getControl(); @@ -262,7 +252,7 @@ void SinglePhaseWell::updateBHPForConstraint( WellElementSubRegion & subRegion ) } -void SinglePhaseWell::updateVolRateForConstraint( WellElementSubRegion & subRegion ) +void SinglePhaseWell::updateVolRateForConstraint( ElementRegionManager const & elemManager, WellElementSubRegion & subRegion ) { GEOS_MARK_FUNCTION; @@ -303,8 +293,18 @@ void SinglePhaseWell::updateVolRateForConstraint( WellElementSubRegion & subRegi } else { + ElementRegionBase const & region = elemManager.getRegion( wellControls.referenceReservoirRegion() ); + + // Check if regions statistics are being computed + SinglePhaseStatistics::RegionStatistics const & stats = region.getReference< SinglePhaseStatistics::RegionStatistics >( SinglePhaseStatistics::regionStatisticsName() ); + GEOS_ERROR_IF( stats.averagePressure <= 0.0, + GEOS_FMT( "{}: No region average quantities computed. WellControl {} referenceReservoirRegion field requires SinglePhaseStatistics to be configured for region {} ", + getDataContext(), wellControls.getName(), wellControls.referenceReservoirRegion() )); + wellControls.setRegionAveragePressure( stats.averagePressure ); + wellControls.setRegionAverageTemperature( stats.averageTemperature ); + // use region conditions - flashPressure = wellControls.getRegionAveragePressure(); + flashPressure = stats.averagePressure; if( flashPressure < 0.0 ) { // use segment conditions @@ -401,11 +401,11 @@ void SinglePhaseWell::updateFluidModel( WellElementSubRegion & subRegion ) const } ); } -real64 SinglePhaseWell::updateSubRegionState( WellElementSubRegion & subRegion ) +real64 SinglePhaseWell::updateSubRegionState( ElementRegionManager const & elemManager, WellElementSubRegion & subRegion ) { // update volumetric rates for the well constraints // Warning! This must be called before updating the fluid model - updateVolRateForConstraint( subRegion ); + updateVolRateForConstraint( elemManager, subRegion ); // update density in the well elements updateFluidModel( subRegion ); @@ -491,7 +491,7 @@ void SinglePhaseWell::initializeWells( DomainPartition & domain, real64 const & // 4) Recompute the pressure-dependent properties // Note: I am leaving that here because I would like to use the perforationRates (computed in UpdateState) // to better initialize the rates - updateSubRegionState( subRegion ); + updateSubRegionState( elemManager, subRegion ); string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() ); SingleFluidBase & fluid = subRegion.getConstitutiveModel< SingleFluidBase >( fluidName ); @@ -1152,7 +1152,7 @@ void SinglePhaseWell::resetStateToBeginningOfStep( DomainPartition & domain ) subRegion.getField< well::connectionRate_n >(); connRate.setValues< parallelDevicePolicy<> >( connRate_n ); - updateSubRegionState( subRegion ); + updateSubRegionState( elemManager, subRegion ); } ); } ); } @@ -1194,7 +1194,7 @@ void SinglePhaseWell::implicitStepSetup( real64 const & time, validateWellConstraints( time, dt, subRegion, elemManager ); - updateSubRegionState( subRegion ); + updateSubRegionState( elemManager, subRegion ); } ); } ); } diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.hpp index 7bfeb996aa4..ac73a4a3c76 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.hpp @@ -140,9 +140,10 @@ class SinglePhaseWell : public WellSolverBase /** * @brief Recompute the volumetric rate that are used in the well constraints + * @param elemManager the well region manager * @param subRegion the well subregion containing all the primary and dependent fields */ - virtual void updateVolRateForConstraint( WellElementSubRegion & subRegion ); + virtual void updateVolRateForConstraint( ElementRegionManager const & elemManager, WellElementSubRegion & subRegion ); /** * @brief Recompute the BHP pressure that is used in the well constraints @@ -164,10 +165,11 @@ class SinglePhaseWell : public WellSolverBase real64 const & dt, DomainPartition & domain ) override; /** - * @brief Recompute all dependent quantities from primary variables (including constitutive models) on the well + * @brief Recompute all dependent quantities from primary variables (including constitutive models) + * @param elemManager the elemManager containing the well * @param subRegion the well subRegion containing the well elements and their associated fields */ - virtual real64 updateSubRegionState( WellElementSubRegion & subRegion ) override; + virtual real64 updateSubRegionState( ElementRegionManager const & elemManager, WellElementSubRegion & subRegion ) override; /** * @brief function to assemble the linear system matrix and rhs diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.cpp index e470984d7cd..f5136ffb70d 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.cpp @@ -305,9 +305,10 @@ void WellSolverBase::updateState( DomainPartition & domain ) MeshLevel & mesh, string_array const & regionNames ) { - mesh.getElemManager().forElementSubRegions< WellElementSubRegion >( regionNames, [&]( localIndex const, - WellElementSubRegion & subRegion ) - { updateSubRegionState( subRegion ); } ); + ElementRegionManager & elemManager = mesh.getElemManager(); + elemManager.forElementSubRegions< WellElementSubRegion >( regionNames, [&]( localIndex const, + WellElementSubRegion & subRegion ) + { updateSubRegionState( elemManager, subRegion ); } ); } ); } diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.hpp index a8159378b50..d7634be8b1c 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.hpp @@ -250,9 +250,10 @@ class WellSolverBase : public PhysicsSolverBase /** * @brief Recompute all dependent quantities from primary variables (including constitutive models) + * @param elemManager the elemManager containing the well * @param subRegion the well subRegion containing the well elements and their associated fields */ - virtual real64 updateSubRegionState( WellElementSubRegion & subRegion ) = 0; + virtual real64 updateSubRegionState( ElementRegionManager const & elemManager, WellElementSubRegion & subRegion ) = 0; /** * @brief Recompute the perforation rates for all the wells From 5ced2b7b9cb84cc2231c5a981740cc954a7ad1f5 Mon Sep 17 00:00:00 2001 From: Tom Byer <149726499+tjb-ltk@users.noreply.github.com> Date: Tue, 23 Sep 2025 10:53:06 -0700 Subject: [PATCH 02/28] rel mode compile fix --- .../fluidFlow/wells/CompositionalMultiphaseWell.cpp | 5 ++--- .../fluidFlow/wells/CompositionalMultiphaseWell.hpp | 3 +-- .../physicsSolvers/fluidFlow/wells/SinglePhaseWell.cpp | 5 ++--- .../physicsSolvers/fluidFlow/wells/SinglePhaseWell.hpp | 4 +--- .../physicsSolvers/fluidFlow/wells/WellSolverBase.cpp | 2 +- .../physicsSolvers/fluidFlow/wells/WellSolverBase.hpp | 3 +-- 6 files changed, 8 insertions(+), 14 deletions(-) diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp index 483ac3c5d3c..fad2d34b505 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp @@ -427,8 +427,7 @@ void CompositionalMultiphaseWell::validateInjectionStreams( WellElementSubRegion void CompositionalMultiphaseWell::validateWellConstraints( real64 const & time_n, real64 const & GEOS_UNUSED_PARAM( dt ), - WellElementSubRegion const & subRegion, - ElementRegionManager const & elemManager ) + WellElementSubRegion const & subRegion ) { WellControls & wellControls = getWellControls( subRegion ); if( !wellControls.useSurfaceConditions() ) @@ -2145,7 +2144,7 @@ void CompositionalMultiphaseWell::implicitStepSetup( real64 const & time_n, MultiFluidBase const & fluid = getConstitutiveModel< MultiFluidBase >( subRegion, fluidName ); fluid.saveConvergedState(); - validateWellConstraints( time_n, dt, subRegion, elemManager ); + validateWellConstraints( time_n, dt, subRegion ); updateSubRegionState( elemManager, subRegion ); } diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.hpp index 819beafa0d8..38311177552 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.hpp @@ -345,8 +345,7 @@ class CompositionalMultiphaseWell : public WellSolverBase */ virtual void validateWellConstraints( real64 const & time_n, real64 const & dt, - WellElementSubRegion const & subRegion, - ElementRegionManager const & elemManager ) override; + WellElementSubRegion const & subRegion ) override; /** * @brief Create well separator diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.cpp index 9db9bb4ce88..943c81677ce 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.cpp @@ -140,8 +140,7 @@ string SinglePhaseWell::resElementDofName() const void SinglePhaseWell::validateWellConstraints( real64 const & time_n, real64 const & GEOS_UNUSED_PARAM( dt ), - WellElementSubRegion const & subRegion, - ElementRegionManager const & elemManager ) + WellElementSubRegion const & subRegion ) { WellControls & wellControls = getWellControls( subRegion ); if( !wellControls.useSurfaceConditions() ) @@ -1192,7 +1191,7 @@ void SinglePhaseWell::implicitStepSetup( real64 const & time, getConstitutiveModel< SingleFluidBase >( subRegion, subRegion.getReference< string >( viewKeyStruct::fluidNamesString() ) ); fluid.saveConvergedState(); - validateWellConstraints( time, dt, subRegion, elemManager ); + validateWellConstraints( time, dt, subRegion ); updateSubRegionState( elemManager, subRegion ); } ); diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.hpp index ac73a4a3c76..8c07e223fb7 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.hpp @@ -292,12 +292,10 @@ class SinglePhaseWell : public WellSolverBase * @param time_n the time at the beginning of the time step * @param dt the time step dt * @param subRegion the well subRegion - * @param elemManager the element manager */ virtual void validateWellConstraints( real64 const & time_n, real64 const & dt, - WellElementSubRegion const & subRegion, - ElementRegionManager const & elemManager ) override; + WellElementSubRegion const & subRegion ) override; }; diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.cpp index f5136ffb70d..bba04073fbd 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.cpp @@ -159,7 +159,7 @@ void WellSolverBase::initializePostSubGroups() [&]( localIndex const, WellElementSubRegion & subRegion ) { - validateWellConstraints( 0, 0, subRegion, elemManager ); + validateWellConstraints( 0, 0, subRegion ); // validate perforation status table PerforationData & perforationData = *subRegion.getPerforationData(); diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.hpp index d7634be8b1c..04fe58112b4 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.hpp @@ -321,8 +321,7 @@ class WellSolverBase : public PhysicsSolverBase */ virtual void validateWellConstraints( real64 const & time_n, real64 const & dt, - WellElementSubRegion const & subRegion, - ElementRegionManager const & elemManager ) = 0; + WellElementSubRegion const & subRegion ) = 0; virtual void printRates( real64 const & time_n, real64 const & dt, From b2cbc13cec17710960dc323cb06b0880517831aa Mon Sep 17 00:00:00 2001 From: Tom Byer <149726499+tjb-ltk@users.noreply.github.com> Date: Tue, 23 Sep 2025 13:45:49 -0700 Subject: [PATCH 03/28] check if reference region defined --- .../wells/CompositionalMultiphaseWell.cpp | 21 +++++++++------- .../fluidFlow/wells/SinglePhaseWell.cpp | 24 ++++++++++--------- 2 files changed, 25 insertions(+), 20 deletions(-) diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp index fad2d34b505..1493279b08a 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp @@ -726,16 +726,19 @@ void CompositionalMultiphaseWell::updateVolRatesForConstraint( ElementRegionMana } else { - ElementRegionBase const & region = elemManager.getRegion( wellControls.referenceReservoirRegion()); - CompositionalMultiphaseStatistics::RegionStatistics const & stats = region.getReference< CompositionalMultiphaseStatistics::RegionStatistics >( - CompositionalMultiphaseStatistics::regionStatisticsName() ); - wellControls.setRegionAveragePressure( stats.averagePressure ); - wellControls.setRegionAverageTemperature( stats.averageTemperature ); - GEOS_ERROR_IF( stats.averagePressure <= 0.0, - GEOS_FMT( "{}: No region average quantities computed. WellControl {} referenceReservoirRegion field requires CompositionalMultiphaseStatistics to be configured for region {} ", - getDataContext(), wellControls.getName(), wellControls.referenceReservoirRegion() )); + if( wellControls.referenceReservoirRegion() != "" ) + { + ElementRegionBase const & region = elemManager.getRegion( wellControls.referenceReservoirRegion()); + CompositionalMultiphaseStatistics::RegionStatistics const & stats = region.getReference< CompositionalMultiphaseStatistics::RegionStatistics >( + CompositionalMultiphaseStatistics::regionStatisticsName() ); + wellControls.setRegionAveragePressure( stats.averagePressure ); + wellControls.setRegionAverageTemperature( stats.averageTemperature ); + GEOS_ERROR_IF( stats.averagePressure <= 0.0, + GEOS_FMT( "{}: No region average quantities computed. WellControl {} referenceReservoirRegion field requires CompositionalMultiphaseStatistics to be configured for region {} ", + getDataContext(), wellControls.getName(), wellControls.referenceReservoirRegion() )); + } // If flashPressure is not set by region the value is defaulted to -1 and indicates to use top segment conditions - flashPressure = stats.averagePressure; + flashPressure = wellControls.getRegionAveragePressure(); if( flashPressure < 0.0 ) { // region name not set, use segment conditions diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.cpp index 943c81677ce..60f09a7f1a7 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.cpp @@ -292,18 +292,20 @@ void SinglePhaseWell::updateVolRateForConstraint( ElementRegionManager const & e } else { - ElementRegionBase const & region = elemManager.getRegion( wellControls.referenceReservoirRegion() ); - - // Check if regions statistics are being computed - SinglePhaseStatistics::RegionStatistics const & stats = region.getReference< SinglePhaseStatistics::RegionStatistics >( SinglePhaseStatistics::regionStatisticsName() ); - GEOS_ERROR_IF( stats.averagePressure <= 0.0, - GEOS_FMT( "{}: No region average quantities computed. WellControl {} referenceReservoirRegion field requires SinglePhaseStatistics to be configured for region {} ", - getDataContext(), wellControls.getName(), wellControls.referenceReservoirRegion() )); - wellControls.setRegionAveragePressure( stats.averagePressure ); - wellControls.setRegionAverageTemperature( stats.averageTemperature ); - + if( wellControls.referenceReservoirRegion() != "" ) + { + ElementRegionBase const & region = elemManager.getRegion( wellControls.referenceReservoirRegion() ); + + // Check if regions statistics are being computed + SinglePhaseStatistics::RegionStatistics const & stats = region.getReference< SinglePhaseStatistics::RegionStatistics >( SinglePhaseStatistics::regionStatisticsName() ); + GEOS_ERROR_IF( stats.averagePressure <= 0.0, + GEOS_FMT( "{}: No region average quantities computed. WellControl {} referenceReservoirRegion field requires SinglePhaseStatistics to be configured for region {} ", + getDataContext(), wellControls.getName(), wellControls.referenceReservoirRegion() )); + wellControls.setRegionAveragePressure( stats.averagePressure ); + wellControls.setRegionAverageTemperature( stats.averageTemperature ); + } // use region conditions - flashPressure = stats.averagePressure; + flashPressure = wellControls.getRegionAveragePressure(); if( flashPressure < 0.0 ) { // use segment conditions From 7771fbe69877b0a7e6eb3cd06c9cebc0d02089e0 Mon Sep 17 00:00:00 2001 From: MelReyCG Date: Tue, 2 Dec 2025 10:53:54 +0100 Subject: [PATCH 04/28] =?UTF-8?q?=F0=9F=9A=A7=20wip=201?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/CompositionalMultiphaseStatist.plantuml | 86 +++++ ...ew2CompositionalMultiphaseStatist.plantuml | 83 +++++ ...ew3CompositionalMultiphaseStatist.plantuml | 115 +++++++ ...ew4CompositionalMultiphaseStatist.plantuml | 115 +++++++ ...NewCompositionalMultiphaseStatist.plantuml | 119 +++++++ .../physicsSolvers/fluidFlow/CMakeLists.txt | 6 +- ...itionalMultiphaseStatisticsAggregator.cpp} | 220 +++--------- ...sitionalMultiphaseStatisticsAggregator.hpp | 188 ++++++++++ .../CompositionalMultiphaseStatisticsTask.cpp | 320 ++++++++++++++++++ ...CompositionalMultiphaseStatisticsTask.hpp} | 114 +++---- 10 files changed, 1119 insertions(+), 247 deletions(-) create mode 100644 src/CompositionalMultiphaseStatist.plantuml create mode 100644 src/New2CompositionalMultiphaseStatist.plantuml create mode 100644 src/New3CompositionalMultiphaseStatist.plantuml create mode 100644 src/New4CompositionalMultiphaseStatist.plantuml create mode 100644 src/NewCompositionalMultiphaseStatist.plantuml rename src/coreComponents/physicsSolvers/fluidFlow/{CompositionalMultiphaseStatistics.cpp => CompositionalMultiphaseStatisticsAggregator.cpp} (69%) create mode 100644 src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsAggregator.hpp create mode 100644 src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsTask.cpp rename src/coreComponents/physicsSolvers/fluidFlow/{CompositionalMultiphaseStatistics.hpp => CompositionalMultiphaseStatisticsTask.hpp} (56%) diff --git a/src/CompositionalMultiphaseStatist.plantuml b/src/CompositionalMultiphaseStatist.plantuml new file mode 100644 index 00000000000..4133442d469 --- /dev/null +++ b/src/CompositionalMultiphaseStatist.plantuml @@ -0,0 +1,86 @@ + + +class Group #text:00000060 +class ExecutableGroup #text:00000060 +class TaskBase #text:00000060 +class FieldStatisticsBase #text:00000060 +class ObjectManagerBase #text:00000060 +class ElementSubRegionBase #text:00000060 +class ElementSubRegionBase #text:00000060 +class WellSolverBase #text:00000060 +class PhysicsSolverBase #text:00000060 + +class FieldStatisticsBase< SOLVER_T > #text:00000060 { + string m_solverName (user input : "solverName") + string m_outputDir (user input : "outputDir") + bool m_writeCSV (user input : "writeCSV") +} + +Group <|-- ExecutableGroup +ExecutableGroup <|-- TaskBase +TaskBase <|-- FieldStatisticsBase + +Group <|-- ObjectManagerBase +ObjectManagerBase <|-- ElementSubRegionBase +ElementSubRegionBase <|-- CellElementRegion + +WellSolverBase <|-- CompositionalMultiphaseWell +PhysicsSolverBase <|-- WellSolverBase +ExecutableGroup <|-- PhysicsSolverBase + +class CompositionalMultiphaseStatistics { + m_computeCFLNumbers (user input: "computeCFLNumbers") + m_computeRegionStatistics (user input: "computeRegionStatistics") + m_relpermThreshold (user input: "relpermThreshold") + -- + void postInputInitialization() override + void registerDataOnMesh( Group & meshBodies ) override + void execute( time_n, dt, [...], domain ) + void computeRegionStatistics( time, meshLevel, regionNames ) + void computeCFLNumbers( time, dt, domainPartition ) +} +FieldStatisticsBase <|-- CompositionalMultiphaseStatistics : SOLVER_T = CompositionalMultiphaseBase + + +class RegionStatistics { + real64 averagePressure + real64 minPressure + real64 maxPressure + + real64 minDeltaPressure + real64 maxDeltaPressure + + real64 averageTemperature + real64 minTemperature + real64 maxTemperature + + real64 totalPoreVolume + real64 totalUncompactedPoreVolume + array1d phasePoreVolume + + array1d phaseMass + array1d trappedPhaseMass + array1d immobilePhaseMass + array2d componentMass +} +note left of RegionStatistics + Also exists in single-phase version with: + real64 averagePressure + real64 minPressure + real64 maxPressure + + real64 minDeltaPressure + real64 maxDeltaPressure + + real64 averageTemperature + real64 minTemperature + real64 maxTemperature + + real64 totalPoreVolume + real64 totalUncompactedPoreVolume + + real64 totalMass +end note +CompositionalMultiphaseStatistics ....> RegionStatistics : "instanciate\n&\ncomputes\n&\nreads data from" +CompositionalMultiphaseWell ....> RegionStatistics : "reads data\nfrom" +CellElementRegion *--l--> RegionStatistics : ""regionStatistics"\nWrapper" diff --git a/src/New2CompositionalMultiphaseStatist.plantuml b/src/New2CompositionalMultiphaseStatist.plantuml new file mode 100644 index 00000000000..f4449422be1 --- /dev/null +++ b/src/New2CompositionalMultiphaseStatist.plantuml @@ -0,0 +1,83 @@ + + +class Group #text:00000060 +class ExecutableGroup #text:00000060 +class TaskBase #text:00000060 +class FieldStatisticsBase #text:00000060 +class ObjectManagerBase #text:00000060 +class ElementSubRegionBase #text:00000060 +class ElementSubRegionBase #text:00000060 +class WellSolverBase #text:00000060 +class PhysicsSolverBase #text:00000060 + +class FieldStatisticsBase< SOLVER_T > #text:00000060 { + string m_solverName (user input : "solverName") + string m_outputDir (user input : "outputDir") + bool m_writeCSV (user input : "writeCSV") +} + +Group <|-- ExecutableGroup +ExecutableGroup <|-- TaskBase +TaskBase <|-- FieldStatisticsBase + +Group <|-- ObjectManagerBase +ObjectManagerBase <|-- ElementSubRegionBase +ElementSubRegionBase <|-- CellElementRegion + +WellSolverBase <|-- CompositionalMultiphaseWell +PhysicsSolverBase <|-- WellSolverBase +ExecutableGroup <|-- PhysicsSolverBase + +class CompositionalMultiphaseStatisticsTask #text:Green { + bool m_computeCFLNumbers (wrapper: "computeCFLNumbers") + bool m_computeRegionStatistics (wrapper: "computeRegionStatistics") + float m_relpermThreshold (wrapper: "relpermThreshold") + -- + void postInputInitialization() override + void execute( time_n, dt, [...], domain ) +} +note bottom of CompositionalMultiphaseStatisticsTask + User defined executable task for + statistics computation & output +end note +FieldStatisticsBase <|-- CompositionalMultiphaseStatisticsTask : SOLVER_T = CompositionalMultiphaseBase + +class CompositionalMultiphaseStatisticsAggregator #text:Green { + void registerDataOnMesh( Group & meshBodies ) override + void computeRegionStatistics( time, meshLevel, regionNames ) + void computeCFLNumbers( time, dt, domainPartition, m_relpermThreshold ) + void forRegionStatstics( functor ) +} +note bottom of CompositionalMultiphaseStatisticsAggregator + Generated sub-group for instanciating + RegionStatistics over the regions & + doing statistics computation. +end note +CompositionalMultiphaseStatisticsTask *---> CompositionalMultiphaseStatisticsAggregator : "contains one" +CompositionalMultiphaseWell *---> CompositionalMultiphaseStatisticsAggregator : "contains one" + +class RegionStatistics { + real64 averagePressure + real64 minPressure + real64 maxPressure + + real64 minDeltaPressure + real64 maxDeltaPressure + + real64 averageTemperature + real64 minTemperature + real64 maxTemperature + + real64 totalPoreVolume + real64 totalUncompactedPoreVolume + array1d phasePoreVolume + + array1d phaseMass + array1d trappedPhaseMass + array1d immobilePhaseMass + array2d componentMass +} +CompositionalMultiphaseStatisticsAggregator ...> RegionStatistics : "instanciate\n&\ncomputes" +CompositionalMultiphaseStatisticsTask ..> RegionStatistics : "reads data\nfrom" +CompositionalMultiphaseWell ...> RegionStatistics : "reads data\nfrom" +CellElementRegion *--l--> RegionStatistics : ""regionStatistics"\nWrapper" diff --git a/src/New3CompositionalMultiphaseStatist.plantuml b/src/New3CompositionalMultiphaseStatist.plantuml new file mode 100644 index 00000000000..e41f9e36ca1 --- /dev/null +++ b/src/New3CompositionalMultiphaseStatist.plantuml @@ -0,0 +1,115 @@ + + +class Group #text:00000060 +class ExecutableGroup #text:00000060 +class TaskBase #text:00000060 +class FieldStatisticsBase #text:00000060 +class ObjectManagerBase #text:00000060 +class ElementSubRegionBase #text:00000060 +class ElementSubRegionBase #text:00000060 +class WellSolverBase #text:00000060 +class PhysicsSolverBase #text:00000060 + +class FieldStatisticsBase< SOLVER_T > #text:00000060 { + string m_solverName (user input : "solverName") + string m_outputDir (user input : "outputDir") + bool m_writeCSV (user input : "writeCSV") +} + +Group <|-- ExecutableGroup +ExecutableGroup <|-- TaskBase +TaskBase <|-- FieldStatisticsBase + +Group <|-- ObjectManagerBase +ObjectManagerBase <|-- ElementSubRegionBase +ElementSubRegionBase <|-- CellElementRegion + +WellSolverBase <|-- CompositionalMultiphaseWell +PhysicsSolverBase <|-- WellSolverBase +ExecutableGroup <|-- PhysicsSolverBase + +class CompositionalMultiphaseStatisticsTask #text:Green { + bool m_computeCFLNumbers (wrapper: "computeCFLNumbers") + bool m_computeRegionStatistics (wrapper: "computeRegionStatistics") + float m_relpermThreshold (wrapper: "relpermThreshold") + -- + void postInputInitialization() override + void execute( time_n, dt, [...], domain ) +} +note bottom of CompositionalMultiphaseStatisticsTask + User defined executable task for + statistics computation & output +end note +FieldStatisticsBase <|-- CompositionalMultiphaseStatisticsTask : SOLVER_T = CompositionalMultiphaseBase + +class CompositionalMultiphaseStatisticsAggregator #text:Green { + void registerDataOnMesh( Group & meshBodies ) override + void computeRegionStatistics( time, meshLevel, regionNames ) + void computeCFLNumbers( time, dt, domainPartition, m_relpermThreshold ) + void forRegionStatstics( functor ) +} +note bottom of CompositionalMultiphaseStatisticsAggregator + Generated sub-group for instanciating + RegionStatistics over the regions & + doing statistics computation. +end note +CompositionalMultiphaseStatisticsTask *---> CompositionalMultiphaseStatisticsAggregator : "contains one" +CompositionalMultiphaseWell *---> CompositionalMultiphaseStatisticsAggregator : "contains one" + +class RegionStatistics #text:Green { +} +note bottom of RegionStatistics + May be removed in favor of direct statistics +end note +CompositionalMultiphaseStatisticsAggregator ...> RegionStatistics : "instanciate\n&\ncomputes" +CompositionalMultiphaseStatisticsTask ..> RegionStatistics : "reads data\nfrom" +CompositionalMultiphaseWell ...> RegionStatistics : "reads data\nfrom" +CellElementRegion *-l--> RegionStatistics : "'regionStatistics' wrapper" + +class PressureStatistics #text:Green { + real64 averagePressure + real64 minPressure + real64 maxPressure + real64 minDeltaPressure + real64 maxDeltaPressure +} +RegionStatistics *--> PressureStatistics : "generated wrapper\n"pressure"" +PressureStatistics [PressureStatistics] --> RegionStatisticsType : "implements" + +class TemperatureStatistics #text:Green { + real64 averageTemperature + real64 minTemperature + real64 maxTemperature +} +RegionStatistics *--> TemperatureStatistics : "generated wrapper\n"temperature"" +TemperatureStatistics [TemperatureStatistics] --> RegionStatisticsType : "implements" + +class PoreVolumeStatistics #text:Green { + real64 totalPoreVolume + real64 totalUncompactedPoreVolume + array1d phasePoreVolume +} +RegionStatistics *--> PoreVolumeStatistics : "generated wrapper\n"poreVolume"" +PoreVolumeStatistics [PoreVolumeStatistics] --> RegionStatisticsType : "implements" + +class MassStatistics #text:Green { + array1d phaseMass + array1d trappedPhaseMass + array1d immobilePhaseMass + array2d componentMass +} +RegionStatistics *--> MassStatistics : "generated wrapper\n"mass"" +MassStatistics [MassStatistics] --> RegionStatisticsType : "implements" + +interface RegionStatisticsType < STATS_TYPE > #text:Green { + void init() + void setKernelViews( RegionStatisticsKernelViews< STATS_TYPE > & views ) + HOST_DEVICE void collectElementStats( RegionStatisticsKernelViews< STATS_TYPE > const & views ) + void kernelReduce() + void mpiReduce() +} + +class STATS_TYPE::KernelViews < STATS_TYPE > #text:Green { + ( structure of views necessary for collectElementStats() ) +} +RegionStatisticsType [STATS_TYPE] ..> STATS_TYPE::KernelViews \ No newline at end of file diff --git a/src/New4CompositionalMultiphaseStatist.plantuml b/src/New4CompositionalMultiphaseStatist.plantuml new file mode 100644 index 00000000000..8c64115b7a4 --- /dev/null +++ b/src/New4CompositionalMultiphaseStatist.plantuml @@ -0,0 +1,115 @@ + + +class Group #text:00000060 +class ExecutableGroup #text:00000060 +class TaskBase #text:00000060 +class FieldStatisticsBase #text:00000060 +class ObjectManagerBase #text:00000060 +class ElementSubRegionBase #text:00000060 +class ElementSubRegionBase #text:00000060 +class WellSolverBase #text:00000060 +class PhysicsSolverBase #text:00000060 + +class FieldStatisticsBase< SOLVER_T > #text:00000060 { + string m_solverName (user input : "solverName") + string m_outputDir (user input : "outputDir") + bool m_writeCSV (user input : "writeCSV") +} + +Group <|-- ExecutableGroup +ExecutableGroup <|-- TaskBase +TaskBase <|-- FieldStatisticsBase + +Group <|-- ObjectManagerBase +ObjectManagerBase <|-- ElementSubRegionBase +ElementSubRegionBase <|-- CellElementRegion + +WellSolverBase <|-- CompositionalMultiphaseWell +PhysicsSolverBase <|-- WellSolverBase +ExecutableGroup <|-- PhysicsSolverBase + +class CompositionalMultiphaseStatisticsTask #text:Green { + bool m_computeCFLNumbers (wrapper: "computeCFLNumbers") + bool m_computeRegionStatistics (wrapper: "computeRegionStatistics") + float m_relpermThreshold (wrapper: "relpermThreshold") + -- + void postInputInitialization() override + void execute( time_n, dt, [...], domain ) +} +note bottom of CompositionalMultiphaseStatisticsTask + User defined executable task for + statistics computation & output +end note +FieldStatisticsBase <|-- CompositionalMultiphaseStatisticsTask : SOLVER_T = CompositionalMultiphaseBase + +class CompositionalMultiphaseStatisticsAggregator #text:Green { + void registerDataOnMesh( Group & meshBodies ) override + void computeRegionStatistics( time, meshLevel, regionNames ) + void computeCFLNumbers( time, dt, domainPartition, m_relpermThreshold ) + void forRegionStatstics( functor ) +} +note bottom of CompositionalMultiphaseStatisticsAggregator + Generated sub-group for instanciating + RegionStatistics over the regions & + doing statistics computation. +end note +CompositionalMultiphaseStatisticsTask *---> CompositionalMultiphaseStatisticsAggregator : "contains one" +CompositionalMultiphaseWell *---> CompositionalMultiphaseStatisticsAggregator : "contains one" + +class RegionStatisticsData #text:Green { +} +note left of RegionStatisticsData + May be removed in favor of direct statistics +end note +CompositionalMultiphaseStatisticsAggregator ...> RegionStatisticsData : "instanciate\n&\ncomputes" +CompositionalMultiphaseStatisticsTask ..> RegionStatisticsData : "reads data\nfrom" +CompositionalMultiphaseWell ...> RegionStatisticsData : "reads data\nfrom" +CellElementRegion *-l--> RegionStatisticsData : "'regionStatistics' wrapper" + +class PressureStatistics #text:Green { + real64 averagePressure + real64 minPressure + real64 maxPressure + real64 minDeltaPressure + real64 maxDeltaPressure +} +RegionStatisticsData *--> PressureStatistics : "generated wrapper\n"pressure"" +PressureStatistics [PressureStatistics] --> RegionStatisticsType : "implements" + +class TemperatureStatistics #text:Green { + real64 averageTemperature + real64 minTemperature + real64 maxTemperature +} +RegionStatisticsData *--> TemperatureStatistics : "generated wrapper\n"temperature"" +TemperatureStatistics [TemperatureStatistics] --> RegionStatisticsType : "implements" + +class PoreVolumeStatistics #text:Green { + real64 totalPoreVolume + real64 totalUncompactedPoreVolume + array1d phasePoreVolume +} +RegionStatisticsData *--> PoreVolumeStatistics : "generated wrapper\n"poreVolume"" +PoreVolumeStatistics [PoreVolumeStatistics] --> RegionStatisticsType : "implements" + +class MassStatistics #text:Green { + array1d phaseMass + array1d trappedPhaseMass + array1d immobilePhaseMass + array2d componentMass +} +RegionStatisticsData *--> MassStatistics : "generated wrapper\n"mass"" +MassStatistics [MassStatistics] --> RegionStatisticsType : "implements" + +interface RegionStatisticsType < STATS_TYPE > #text:Green { + void init() + void setKernelViews( RegionStatisticsKernelViews< STATS_TYPE > & views ) + HOST_DEVICE void collectElementStats( RegionStatisticsKernelViews< STATS_TYPE > const & views ) + void kernelReduce() + void mpiReduce() +} + +class STATS_TYPE::KernelViews < STATS_TYPE > #text:Green { + ( structure of views necessary for collectElementStats() ) +} +RegionStatisticsType [STATS_TYPE] ..> STATS_TYPE::KernelViews \ No newline at end of file diff --git a/src/NewCompositionalMultiphaseStatist.plantuml b/src/NewCompositionalMultiphaseStatist.plantuml new file mode 100644 index 00000000000..782ff4b0263 --- /dev/null +++ b/src/NewCompositionalMultiphaseStatist.plantuml @@ -0,0 +1,119 @@ + + +class Group #text:00000060 +class ExecutableGroup #text:00000060 +class TaskBase #text:00000060 +class FieldStatisticsBase #text:00000060 +class ObjectManagerBase #text:00000060 +class ElementSubRegionBase #text:00000060 +class ElementSubRegionBase #text:00000060 +class WellSolverBase #text:00000060 +class PhysicsSolverBase #text:00000060 + +class FieldStatisticsBase< SOLVER_T > #text:00000060 { + string m_solverName (user input : "solverName") + string m_outputDir (user input : "outputDir") + bool m_writeCSV (user input : "writeCSV") +} + +Group <|-- ExecutableGroup +ExecutableGroup <|-- TaskBase +TaskBase <|-- FieldStatisticsBase + +Group <|-- ObjectManagerBase +ObjectManagerBase <|-- ElementSubRegionBase +ElementSubRegionBase <|-- CellElementRegion + +WellSolverBase <|-- CompositionalMultiphaseWell +WellSolverBase <|-- SinglePhaseWell +PhysicsSolverBase <|-- WellSolverBase +ExecutableGroup <|-- PhysicsSolverBase + +class CompositionalMultiphaseStatistics { + m_computeCFLNumbers (user input: "computeCFLNumbers") + m_computeRegionStatistics (user input: "computeRegionStatistics") + m_relpermThreshold (user input: "relpermThreshold") + -- + void postInputInitialization() override + void registerDataOnMesh( Group & meshBodies ) override + + void computeRegionStatistics( time, meshLevel, regionNames ) + void computeCFLNumbers( time, dt, domainPartition ) +} +FieldStatisticsBase <|-- CompositionalMultiphaseStatistics : SOLVER_T = CompositionalMultiphaseBase + + +class RegionStatistics { + real64 dataTime + ---- + void computeRegionStatistics< STATS_TYPES... >() +} +RegionStatistics <..l.. CompositionalMultiphaseStatistics +CellElementRegion *--> RegionStatistics : "Generated Group\nregionStatistics" + +note right of RegionStatistics::dataTime + Added to keep track if stats has + been computed for the current time. + To be aware that stats are computer + after solver computation, "dataTime" + must be //timeStep + dt// (taking + into account the //dt// of cuts). +end note + + +class PressureStatistics #text:Green { + real64 averagePressure + real64 minPressure + real64 maxPressure + real64 minDeltaPressure + real64 maxDeltaPressure +} +RegionStatistics *--> PressureStatistics : "Lazily Generated Wrapper\npressure" +PressureStatistics [PressureStatistics] --> RegionStatisticsType : "implements" + +class TemperatureStatistics #text:Green { + real64 averageTemperature + real64 minTemperature + real64 maxTemperature +} +RegionStatistics *--> TemperatureStatistics : "Lazily Generated Wrapper\ntemperature" +TemperatureStatistics [TemperatureStatistics] --> RegionStatisticsType : "implements" + +class PoreVolumeStatistics #text:Green { + real64 totalPoreVolume + real64 totalUncompactedPoreVolume + array1d phasePoreVolume +} +RegionStatistics *--> PoreVolumeStatistics : "Lazily Generated Wrapper\nporeVolume" +PoreVolumeStatistics [PoreVolumeStatistics] --> RegionStatisticsType : "implements" + +class MassStatistics #text:Green { + array1d phaseMass + array1d trappedPhaseMass + array1d immobilePhaseMass + array2d componentMass +} +RegionStatistics *--> MassStatistics : "Lazily Generated Wrapper\nmass" +MassStatistics [MassStatistics] --> RegionStatisticsType : "implements" + +class CFLNumbers #text:Green { + array1d phaseMass + array1d trappedPhaseMass + array1d immobilePhaseMass + array2d componentMass +} +RegionStatistics *--> CFLNumbers : "Lazily Generated Wrapper\ncflNumbers" +CFLNumbers [CFLNumbers] --> RegionStatisticsType : "implements" + +interface RegionStatisticsType < STATS_TYPE > #text:Green { + void init() + void setKernelViews( RegionStatisticsKernelViews< STATS_TYPE > & views ) + HOST_DEVICE void collectElementStats( RegionStatisticsKernelViews< STATS_TYPE > const & views ) + void kernelReduce() + void mpiReduce() +} + +class STATS_TYPE::KernelViews < STATS_TYPE > #text:Green { + ( structure of views necessary for collectElementStats() ) +} +RegionStatisticsType [STATS_TYPE] ..> STATS_TYPE::KernelViews \ No newline at end of file diff --git a/src/coreComponents/physicsSolvers/fluidFlow/CMakeLists.txt b/src/coreComponents/physicsSolvers/fluidFlow/CMakeLists.txt index 28ffa57e587..ebfeb403a4f 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/CMakeLists.txt +++ b/src/coreComponents/physicsSolvers/fluidFlow/CMakeLists.txt @@ -22,7 +22,8 @@ set( fluidFlowSolvers_headers FlowSolverBaseFields.hpp CompositionalMultiphaseBase.hpp CompositionalMultiphaseBaseFields.hpp - CompositionalMultiphaseStatistics.hpp + CompositionalMultiphaseStatisticsAggregator.hpp + CompositionalMultiphaseStatisticsTask.hpp CompositionalMultiphaseFVM.hpp CompositionalMultiphaseHybridFVM.hpp CompositionalMultiphaseUtilities.hpp @@ -129,7 +130,8 @@ set( fluidFlowSolvers_headers set( fluidFlowSolvers_sources CompositionalMultiphaseBase.cpp CompositionalMultiphaseFVM.cpp - CompositionalMultiphaseStatistics.cpp + CompositionalMultiphaseStatisticsAggregator.cpp + CompositionalMultiphaseStatisticsTask.cpp CompositionalMultiphaseHybridFVM.cpp ImmiscibleMultiphaseFlow.cpp ReactiveCompositionalMultiphaseOBL.cpp diff --git a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatistics.cpp b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsAggregator.cpp similarity index 69% rename from src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatistics.cpp rename to src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsAggregator.cpp index ed8d8e5eb80..13d4fc78b9c 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatistics.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsAggregator.cpp @@ -17,78 +17,36 @@ * @file CompositionalMultiphaseStatistics.cpp */ -#include "CompositionalMultiphaseStatistics.hpp" +#include "CompositionalMultiphaseStatisticsAggregator.hpp" -#include "mesh/DomainPartition.hpp" -#include "constitutive/fluid/multifluid/MultiFluidBase.hpp" -#include "constitutive/relativePermeability/RelativePermeabilityBase.hpp" -#include "constitutive/solid/CoupledSolidBase.hpp" -#include "physicsSolvers/LogLevelsInfo.hpp" -#include "physicsSolvers/fluidFlow/LogLevelsInfo.hpp" +#include "common/logger/Logger.hpp" #include "physicsSolvers/fluidFlow/CompositionalMultiphaseBase.hpp" -#include "physicsSolvers/fluidFlow/CompositionalMultiphaseBaseFields.hpp" -#include "physicsSolvers/fluidFlow/CompositionalMultiphaseHybridFVM.hpp" -#include "physicsSolvers/fluidFlow/FlowSolverBaseFields.hpp" #include "physicsSolvers/fluidFlow/kernels/compositional/StatisticsKernel.hpp" -#include "common/format/table/TableData.hpp" -#include "common/format/table/TableFormatter.hpp" -#include "common/format/table/TableLayout.hpp" +#include "physicsSolvers/LogLevelsInfo.hpp" +#include "constitutive/relativePermeability/RelativePermeabilityBase.hpp" +#include namespace geos { -using namespace constitutive; -using namespace fields; -using namespace dataRepository; - -CompositionalMultiphaseStatistics::CompositionalMultiphaseStatistics( const string & name, - Group * const parent ): - Base( name, parent ), - m_computeCFLNumbers( 0 ), - m_computeRegionStatistics( 1 ) +namespace compositionalMultiphaseStatistics { - registerWrapper( viewKeyStruct::computeCFLNumbersString(), &m_computeCFLNumbers ). - setApplyDefaultValue( 0 ). - setInputFlag( InputFlags::OPTIONAL ). - setDescription( "Flag to decide whether CFL numbers are computed or not" ); - - registerWrapper( viewKeyStruct::computeRegionStatisticsString(), &m_computeRegionStatistics ). - setApplyDefaultValue( 1 ). - setInputFlag( InputFlags::OPTIONAL ). - setDescription( "Flag to decide whether region statistics are computed or not" ); - - registerWrapper( viewKeyStruct::relpermThresholdString(), &m_relpermThreshold ). - setApplyDefaultValue( 1e-6 ). - setInputFlag( InputFlags::OPTIONAL ). - setDescription( "Flag to decide whether a phase is considered mobile (when the relperm is above the threshold) or immobile (when the relperm is below the threshold) in metric 2" ); - - addLogLevel< logInfo::CFL >(); - addLogLevel< logInfo::Statistics >(); -} -void CompositionalMultiphaseStatistics::postInputInitialization() -{ - Base::postInputInitialization(); +using namespace constitutive; +// using namespace fields; +using namespace dataRepository; - if( dynamicCast< CompositionalMultiphaseHybridFVM * >( m_solver ) && m_computeCFLNumbers != 0 ) - { - GEOS_THROW( GEOS_FMT( "{} {}: the option to compute CFL numbers is incompatible with CompositionalMultiphaseHybridFVM", - catalogName(), getDataContext() ), - InputError ); - } -} +StatsAggregator::StatsAggregator(): + m_params(), + m_cflStats(), + m_isRegionStatsEnabled( false ), + m_isCFLNumberEnabled( false ) +{} -void CompositionalMultiphaseStatistics::registerDataOnMesh( Group & meshBodies ) +void StatsAggregator::enableRegionStatistics( dataRepository::Group & meshBodies ) { - // the fields have to be registered in "registerDataOnMesh" (and not later) - // otherwise they cannot be targeted by TimeHistory - - // for now, this guard is needed to avoid breaking the xml schema generation - if( m_solver == nullptr ) - { - return; - } + GEOS_ASSERT_NE( m_solver, nullptr ); m_solver->forDiscretizationOnMeshTargets( meshBodies, [&] ( string const &, MeshLevel & mesh, @@ -99,126 +57,36 @@ void CompositionalMultiphaseStatistics::registerDataOnMesh( Group & meshBodies ) integer const numPhases = m_solver->numFluidPhases(); integer const numComps = m_solver->numFluidComponents(); - // if we have to report region statistics, we have to register them first here - if( m_computeRegionStatistics ) + for( size_t i = 0; i < regionNames.size(); ++i ) { - for( size_t i = 0; i < regionNames.size(); ++i ) - { - ElementRegionBase & region = elemManager.getRegion( regionNames[i] ); - - region.registerWrapper< RegionStatistics >( viewKeyStruct::regionStatisticsString() ). - setRestartFlags( RestartFlags::NO_WRITE ); - region.excludeWrappersFromPacking( { viewKeyStruct::regionStatisticsString() } ); - RegionStatistics & stats = region.getReference< RegionStatistics >( viewKeyStruct::regionStatisticsString() ); - - stats.phasePoreVolume.resizeDimension< 0 >( numPhases ); - stats.phaseMass.resizeDimension< 0 >( numPhases ); - stats.trappedPhaseMass.resizeDimension< 0 >( numPhases ); - stats.immobilePhaseMass.resizeDimension< 0 >( numPhases ); - stats.componentMass.resizeDimension< 0, 1 >( numPhases, numComps ); - - if( m_writeCSV > 0 && MpiWrapper::commRank() == 0 ) - { - auto addStatsValue = []( std::ostringstream & pstatsLayout, TableLayout & ptableLayout, - string const & description, string_view punit, - integer pnumPhases, integer pnumComps = 0 ) - { - for( int ip = 0; ip < pnumPhases; ++ip ) - { - if( pnumComps == 0 ) - { - pstatsLayout << description << " (phase " << ip << ") [" << punit << "]"; - } - else - { - for( int ic = 0; ic < pnumComps; ++ic ) - { - pstatsLayout << description << " (component " << ic << " / phase " << ip << ") [" << punit << "]"; - if( ic == 0 ) - { - pstatsLayout << ","; - } - } - } - if( ip == 0 ) - { - pstatsLayout << ","; - } - } - - ptableLayout.addColumn( pstatsLayout.str()); - pstatsLayout.str( "" ); - }; - - string_view massUnit = units::getSymbol( m_solver->getMassUnit() ); - - TableLayout tableLayout( { - TableLayout::Column().setName( "Time [s]" ), - TableLayout::Column().setName( "Min pressure [Pa]" ), - TableLayout::Column().setName( "Average pressure [Pa]" ), - TableLayout::Column().setName( "Max pressure [Pa]" ), - TableLayout::Column().setName( "Min delta pressure [Pa]" ), - TableLayout::Column().setName( "Max delta pressure [Pa]" ), - TableLayout::Column().setName( "Min temperature [Pa]" ), - TableLayout::Column().setName( "Average temperature [Pa]" ), - TableLayout::Column().setName( "Max temperature [Pa]" ), - TableLayout::Column().setName( "Total dynamic pore volume [rm^3]" ), - } ); - - std::ostringstream statsLayout; - addStatsValue( statsLayout, tableLayout, "Phase dynamic pore volume", "rm^3", numPhases ); - addStatsValue( statsLayout, tableLayout, "Phase mass", massUnit, numPhases ); - addStatsValue( statsLayout, tableLayout, "Trapped phase mass (metric 1)", massUnit, numPhases ); - addStatsValue( statsLayout, tableLayout, "Non-trapped phase mass (metric 1)", massUnit, numPhases ); - addStatsValue( statsLayout, tableLayout, "Immobile phase mass (metric 2)", massUnit, numPhases ); - addStatsValue( statsLayout, tableLayout, "Mobile phase mass (metric 2)", massUnit, numPhases ); - addStatsValue( statsLayout, tableLayout, "Component mass", massUnit, numPhases, numComps ); - - std::ofstream outputFile( m_outputDir + "/" + regionNames[i] + ".csv" ); - TableCSVFormatter csvFormatter( tableLayout ); - outputFile << csvFormatter.headerToString(); - } - } + ElementRegionBase & region = elemManager.getRegion( regionNames[i] ); + + region.registerWrapper< RegionStatistics >( viewKeyStruct::regionStatisticsString() ). + setRestartFlags( RestartFlags::NO_WRITE ); + region.excludeWrappersFromPacking( { viewKeyStruct::regionStatisticsString() } ); + RegionStatistics & stats = region.getReference< RegionStatistics >( viewKeyStruct::regionStatisticsString() ); + + stats.phasePoreVolume.resizeDimension< 0 >( numPhases ); + stats.phaseMass.resizeDimension< 0 >( numPhases ); + stats.trappedPhaseMass.resizeDimension< 0 >( numPhases ); + stats.immobilePhaseMass.resizeDimension< 0 >( numPhases ); + stats.componentMass.resizeDimension< 0, 1 >( numPhases, numComps ); } } ); - - // if we have to compute CFL numbers later, we need to register additional variables - if( m_computeCFLNumbers ) - { - m_solver->registerDataForCFL( meshBodies ); - } + m_isRegionStatsEnabled = true; } -bool CompositionalMultiphaseStatistics::execute( real64 const time_n, - real64 const dt, - integer const GEOS_UNUSED_PARAM( cycleNumber ), - integer const GEOS_UNUSED_PARAM( eventCounter ), - real64 const GEOS_UNUSED_PARAM( eventProgress ), - DomainPartition & domain ) +void StatsAggregator::enableCFLStatistics( dataRepository::Group & meshBodies ) { - m_solver->forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, - MeshLevel & mesh, - string_array const & regionNames ) - { - if( m_computeRegionStatistics ) - { - // current time is time_n + dt - computeRegionStatistics( time_n + dt, mesh, regionNames ); - } - } ); + GEOS_ASSERT_NE( m_solver, nullptr ); - if( m_computeCFLNumbers ) - { - // current time is time_n + dt - computeCFLNumbers( time_n + dt, dt, domain ); - } - - return false; + m_solver->registerDataForCFL( meshBodies ); + m_isCFLNumberEnabled = true; } -void CompositionalMultiphaseStatistics::computeRegionStatistics( real64 const time, - MeshLevel & mesh, - string_array const & regionNames ) const +void StatsAggregator::computeDiscretizationStatistics( real64 const time, + MeshLevel & mesh, + string_array const & regionNames ) const { GEOS_MARK_FUNCTION; @@ -260,11 +128,11 @@ void CompositionalMultiphaseStatistics::computeRegionStatistics( real64 const ti arrayView1d< integer const > const elemGhostRank = subRegion.ghostRank(); arrayView1d< real64 const > const volume = subRegion.getElementVolume(); - arrayView1d< real64 const > const pres = subRegion.getField< flow::pressure >(); - arrayView1d< real64 const > const temp = subRegion.getField< flow::temperature >(); + arrayView1d< real64 const > const pres = subRegion.getField< fields::flow::pressure >(); + arrayView1d< real64 const > const temp = subRegion.getField< fields::flow::temperature >(); arrayView2d< real64 const, compflow::USD_PHASE > const phaseVolFrac = - subRegion.getField< flow::phaseVolumeFraction >(); - arrayView1d< real64 const > const deltaPres = subRegion.getField< flow::deltaPressure >(); + subRegion.getField< fields::flow::phaseVolumeFraction >(); + arrayView1d< real64 const > const deltaPres = subRegion.getField< fields::flow::deltaPressure >(); Group const & constitutiveModels = subRegion.getGroup( ElementSubRegionBase::groupKeyStruct::constitutiveModelsString() ); @@ -306,7 +174,7 @@ void CompositionalMultiphaseStatistics::computeRegionStatistics( real64 const ti launch< parallelDevicePolicy<> >( subRegion.size(), numComps, numPhases, - m_relpermThreshold, + m_params.m_relpermThreshold, elemGhostRank, volume, pres, @@ -553,4 +421,6 @@ REGISTER_CATALOG_ENTRY( TaskBase, CompositionalMultiphaseStatistics, string const &, dataRepository::Group * const ) +} /* namespace compositionalMultiphaseStatistics */ + } /* namespace geos */ diff --git a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsAggregator.hpp b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsAggregator.hpp new file mode 100644 index 00000000000..419a7e6d35f --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsAggregator.hpp @@ -0,0 +1,188 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file CompositionalMultiphaseStatistics.hpp + */ + +#ifndef SRC_CORECOMPONENTS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONALMULTIPHASESTATISTICSAGGREGATOR_HPP_ +#define SRC_CORECOMPONENTS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONALMULTIPHASESTATISTICSAGGREGATOR_HPP_ + +#include "dataRepository/Group.hpp" +#include "mesh/DomainPartition.hpp" +#include "mesh/MeshLevel.hpp" + +namespace geos +{ + +class CompositionalMultiphaseBase; + +namespace compositionalMultiphaseStatistics +{ + +struct AggregatorParameters +{ + /// Threshold to decide whether a phase is considered "mobile" or not + real64 m_relpermThreshold; + + // TODO: add other params like views and stuff +}; + +struct RegionStatistics +{ + /// Time of statistics computation + real64 time; + + /// average region pressure + real64 averagePressure; + /// minimum region pressure + real64 minPressure; + /// maximum region pressure + real64 maxPressure; + + /// minimum region delta pressure + real64 minDeltaPressure; + /// maximum region delta pressure + real64 maxDeltaPressure; + + /// average region temperature + real64 averageTemperature; + /// minimum region temperature + real64 minTemperature; + /// maximum region temperature + real64 maxTemperature; + + /// total region pore volume + real64 totalPoreVolume; + /// total region uncompacted pore volume + real64 totalUncompactedPoreVolume; + /// phase region phase pore volume + array1d< real64 > phasePoreVolume; + + /// region phase mass (trapped and non-trapped, immobile and mobile) + array1d< real64 > phaseMass; + /// trapped region phase mass + array1d< real64 > trappedPhaseMass; + /// immobile region phase mass + array1d< real64 > immobilePhaseMass; + /// region component mass + array2d< real64 > componentMass; + + // TODO: -> split to struct PressureStats...MassStats: + // - VKS for struct name ("pressureStats"..."massStats") + // - current RegionStatistics struct bits +}; + +struct CFLStatistics +{ + /// Time of statistics computation + real64 time; + + /// Maximum Courant Friedrichs Lewy number in the grid for each phase + real64 maxPhaseCFL; + + /// Maximum Courant-Friedrichs-Lewy number in the grid for each component + real64 maxCompCFL; +}; + +class StatsAggregator +{ +public: + + struct viewKeyStruct + { + /// String for the region statistics + constexpr static char const * regionStatisticsString() { return "regionStatistics"; } + }; + + using RegionFunctor = std::function< void (string, RegionStatistics const &) >; + + StatsAggregator(); + + /** + * @brief Set the reference flow solver object to retrieve: + - the simulated regions, + - fields for statistics computation. + * @param solver The reference flow solver + */ + void setFlowSolver( CompositionalMultiphaseBase & solver ) + { m_solver = &solver; } + + // void forDiscretizations( DomainPartition const &, + // std::function< void(MeshLevel const &, + // string_array const & regionNames) > functor ) const; + + // void forRegionStatistics( DomainPartition const &, + // MeshLevel const & mesh, + // RegionFunctor functor ) const; + + /** + * @brief Register the results structs & wrappers so they will be targeted by TimeHistory output + * @note Must be called in "registerDataOnMesh" initialization phase + * @param solver The flow solver + * @param meshBodies The Group containing the MeshBody objects + */ + void enableRegionStatistics( dataRepository::Group & meshBodies ); + + /** + * @brief Register the results structs & wrappers so they will be targeted by TimeHistory output + * @note Must be called in "registerDataOnMesh" initialization phase + * @param solver The flow solver + * @param meshBodies The Group containing the MeshBody objects + */ + void enableCFLStatistics( dataRepository::Group & meshBodies ); + + /** + * @brief Compute some statistics on a given mesh discretization (average field pressure, etc) + * @param[in] time current time + * @param[in] mesh the mesh level object + * @param[in] regionNames the array of target region names + */ + void computeDiscretizationStatistics( real64 const time, + MeshLevel & mesh, + string_array const & regionNames ) const; + + /** + * @brief Compute CFL numbers + * @param[in] time current time + * @param[in] dt the time step size + * @param[in] domain the domain partition + */ + void computeCFLNumbers( real64 const time, + real64 const dt, + DomainPartition & domain ) const; + + CFLStatistics const & getCFLStatistics() const + { return m_cflStats; } + +private: + + CompositionalMultiphaseBase * m_solver; + + AggregatorParameters m_params; + + CFLStatistics m_cflStats; + + bool m_isRegionStatsEnabled; + + bool m_isCFLNumberEnabled; + +}; + +} /* namespace compositionalMultiphaseStatistics */ + +} /* namespace geos */ + +#endif /* SRC_CORECOMPONENTS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONALMULTIPHASESTATISTICSAGGREGATOR_HPP_ */ diff --git a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsTask.cpp b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsTask.cpp new file mode 100644 index 00000000000..b3d6a6b59b8 --- /dev/null +++ b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsTask.cpp @@ -0,0 +1,320 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file CompositionalMultiphaseStatistics.cpp + */ + +#include "CompositionalMultiphaseStatisticsTask.hpp" + +#include "common/DataTypes.hpp" +#include "common/StdContainerWrappers.hpp" +#include "common/format/Format.hpp" +#include "mesh/DomainPartition.hpp" +#include "constitutive/fluid/multifluid/MultiFluidBase.hpp" +#include "constitutive/relativePermeability/RelativePermeabilityBase.hpp" +#include "constitutive/solid/CoupledSolidBase.hpp" +#include "physicsSolvers/LogLevelsInfo.hpp" +#include "physicsSolvers/fluidFlow/CompositionalMultiphaseBase.hpp" +#include "physicsSolvers/fluidFlow/CompositionalMultiphaseBaseFields.hpp" +#include "physicsSolvers/fluidFlow/CompositionalMultiphaseHybridFVM.hpp" +#include "physicsSolvers/fluidFlow/FlowSolverBaseFields.hpp" +#include "common/format/table/TableData.hpp" +#include "common/format/table/TableFormatter.hpp" +#include "common/format/table/TableLayout.hpp" +#include + + +namespace geos +{ + +using namespace constitutive; +using namespace fields; +using namespace dataRepository; + +namespace compositionalMultiphaseStatistics +{ + +StatsTask::StatsTask( const string & name, Group * const parent ): + Base( name, parent ), + m_aggregator(), + m_computeCFLNumbers( 0 ), + m_computeRegionStatistics( 1 ) +{ + registerWrapper( viewKeyStruct::computeCFLNumbersString(), &m_computeCFLNumbers ). + setApplyDefaultValue( 0 ). + setInputFlag( InputFlags::OPTIONAL ). + setDescription( "Flag to decide whether CFL numbers are computed or not" ); + + registerWrapper( viewKeyStruct::computeRegionStatisticsString(), &m_computeRegionStatistics ). + setApplyDefaultValue( 1 ). + setInputFlag( InputFlags::OPTIONAL ). + setDescription( "Flag to decide whether region statistics are computed or not" ); + + registerWrapper( viewKeyStruct::relpermThresholdString(), &m_relpermThreshold ). + setApplyDefaultValue( 1e-6 ). + setInputFlag( InputFlags::OPTIONAL ). + setDescription( "Flag to decide whether a phase is considered mobile (when the relperm is above the threshold) or immobile (when the relperm is below the threshold) in metric 2" ); + + addLogLevel< logInfo::CFL >(); + addLogLevel< logInfo::Statistics >(); +} + +void StatsTask::postInputInitialization() +{ + Base::postInputInitialization(); + + m_aggregator.setFlowSolver( *m_solver ); + + if( dynamicCast< CompositionalMultiphaseHybridFVM * >( m_solver ) && m_computeCFLNumbers != 0 ) + { + GEOS_THROW( GEOS_FMT( "{} {}: the option to compute CFL numbers is incompatible with CompositionalMultiphaseHybridFVM", + catalogName(), getDataContext() ), + InputError ); + } +} + +void StatsTask::registerDataOnMesh( Group & meshBodies ) +{ + // for now, this guard is needed to avoid breaking the xml schema generation + if( m_solver == nullptr ) + { + return; + } + + prepareFluidMetaData(); + + if( m_computeRegionStatistics ) + m_aggregator.enableRegionStatistics( meshBodies ); + + // if we have to compute CFL numbers later, we need to register additional variables + if( m_computeCFLNumbers ) + m_solver->registerDataForCFL( meshBodies ); + + m_solver->forDiscretizationOnMeshTargets( meshBodies, [&] ( string const &, + MeshLevel & mesh, + string_array const & regionNames ) + { + prepareLogTableLayouts( mesh.getName() ); + prepareCsvTableLayouts( mesh.getName() ); + } ); +} + +void StatsTask::prepareFluidMetaData() +{ + ConstitutiveManager const & constitutiveManager = this->getGroupByPath< ConstitutiveManager >( "/Problem/domain/Constitutive" ); + MultiFluidBase const & fluid = constitutiveManager.getGroup< MultiFluidBase >( m_solver->referenceFluidModelName() ); + + m_fluid.m_numPhases = fluid.numFluidPhases(); + m_fluid.m_numComps = fluid.numFluidComponents(); + + m_fluid.m_phaseNames = fluid.phaseNames(); + m_fluid.m_compNames = fluid.componentNames(); + + m_fluid.m_phaseCompNames.resize( + m_fluid.m_numPhases, + stdVector< string >( m_fluid.m_numComps, {} ) ); + + for( int ip = 0; ip < m_fluid.m_numPhases; ++ip ) + for( int ic = 0; ic < m_fluid.m_numComps; ++ic ) + m_fluid.m_phaseCompNames[ip][ic] = GEOS_FMT( "{}/{}", m_fluid.m_phaseNames[ip], m_fluid.m_compNames[ic] ); +} + +void StatsTask::prepareLogTableLayouts( string_view meshName ) +{ + // only output from rank 0 + if( MpiWrapper::commRank() != 0 ) + return; + + TableLayout const tableLayout = TableLayout() + .setTitle( GEOS_FMT( "{}: mesh {}", getName(), meshName ) ); + + m_csvFormatters.emplace( meshName, std::make_unique< TableTextFormatter >( tableLayout ) ); +} + +void StatsTask::prepareCsvTableLayouts( string_view meshName ) +{ + // only output from rank 0 + if( MpiWrapper::commRank() != 0 || !m_writeCSV ) + return; + + integer const numPhases = m_solver->numFluidPhases(); + integer const numComps = m_solver->numFluidComponents(); + + auto addPhaseColumns = []( TableLayout & ptableLayout, string const & description, string_view punit, + integer pnumPhases ) + { + for( int ip = 0; ip < pnumPhases; ++ip ) + ptableLayout.addColumn( GEOS_FMT( "{} (phase {}) [{}]", + description, ip, punit ) ); + }; + auto addPhaseCompColumns = []( TableLayout & ptableLayout, string const & description, string_view punit, + integer pnumPhases, integer pnumComps ) + { + for( int ip = 0; ip < pnumPhases; ++ip ) + for( int ic = 0; ic < pnumComps; ++ic ) + ptableLayout.addColumn( GEOS_FMT( "{} (component {} / phase {}) [{}]", + description, ic, ip, punit ) ); + }; + + string_view massUnit = units::getSymbol( m_solver->getMassUnit() ); + + TableLayout tableLayout( { + TableLayout::Column().setName( "Time [s]" ), + TableLayout::Column().setName( "Region" ), // TODO : mention this change in PR description + TableLayout::Column().setName( "Min pressure [Pa]" ), + TableLayout::Column().setName( "Average pressure [Pa]" ), + TableLayout::Column().setName( "Max pressure [Pa]" ), + TableLayout::Column().setName( "Min delta pressure [Pa]" ), + TableLayout::Column().setName( "Max delta pressure [Pa]" ), + TableLayout::Column().setName( "Min temperature [Pa]" ), + TableLayout::Column().setName( "Average temperature [Pa]" ), + TableLayout::Column().setName( "Max temperature [Pa]" ), + TableLayout::Column().setName( "Total dynamic pore volume [rm^3]" ), + } ); + addPhaseColumns( tableLayout, "Phase dynamic pore volume", "rm^3", numPhases ); + addPhaseColumns( tableLayout, "Phase mass", massUnit, numPhases ); + addPhaseColumns( tableLayout, "Trapped phase mass (metric 1)", massUnit, numPhases ); + addPhaseColumns( tableLayout, "Non-trapped phase mass (metric 1)", massUnit, numPhases ); + addPhaseColumns( tableLayout, "Immobile phase mass (metric 2)", massUnit, numPhases ); + addPhaseColumns( tableLayout, "Mobile phase mass (metric 2)", massUnit, numPhases ); + addPhaseCompColumns( tableLayout, "Component mass", massUnit, numPhases, numComps ); + + auto csvFormatter = std::make_unique< TableCSVFormatter >( tableLayout ); + m_csvFormatters.emplace( meshName, std::move( csvFormatter ) ); + + // output CSV header + std::ofstream outputFile( GEOS_FMT( "{}/{}.csv", m_outputDir, meshName )); + outputFile << csvFormatter->headerToString(); + GEOS_LOG( GEOS_FMT( "table {} : {}", meshName, csvFormatter->headerToString() ) ); // TODO : remove this log +} + +bool StatsTask::execute( real64 const time_n, + real64 const dt, + integer const GEOS_UNUSED_PARAM( cycleNumber ), + integer const GEOS_UNUSED_PARAM( eventCounter ), + real64 const GEOS_UNUSED_PARAM( eventProgress ), + DomainPartition & domain ) +{ + // current time is time_n + dt. TODO: verify implication of events ordering in 'time_n+dt' validity + real64 statsTime = time_n + dt; + + m_solver->forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, + MeshLevel & mesh, + string_array const & regionNames ) + { + if( m_computeRegionStatistics ) + { + m_aggregator.computeRegionsStatistics( statsTime, mesh, regionNames ); + outputLogStats( statsTime, mesh, regionNames ); + outputCsvStats( statsTime, mesh, regionNames ); + } + } ); + + if( m_computeCFLNumbers ) + m_aggregator.computeCFLNumbers( statsTime, dt, domain ); + + return false; +} + +void StatsTask::outputLogStats( real64 const statsTime, + MeshLevel & mesh, + string_array const & regionNames ) +{ + auto const formatterIter = m_logFormatters.find( mesh.getName()); + if( formatterIter==m_logFormatters.end()) + return; + + TableFormatter const & formatter = *formatterIter->second; + TableData tableData; + static constexpr auto merge = CellType::MergeNext; + + tableData.addRow( "Statistics time", merge, merge, statsTime ); + forRegionStatistics( []( string_view regionName, RegionStatistics const & stats ) + { + string_view massUnit = units::getSymbol( m_solver->getMassUnit() ); + string_view pressureUnit = units::getSymbol( units::Pressure ); + string_view tempUnit = units::getSymbol( units::Temperature ); + string_view resVolUnit = "rm3"; + + tableData.addRow( merge, merge, merge, "" ); + + tableData.addSeparator(); + tableData.addRow( merge, merge, merge, GEOS_FMT( "Region '{}'", regionName ) ); + tableData.addRow( "statistics", "min", "average", "max" ); + tableData.addSeparator(); + + tableData.addRow( GEOS_FMT( "Pressure [{}]", pressureUnit ), + stats.minPressure, stats.averagePressure, stats.maxPressure ); + tableData.addRow( GEOS_FMT( "Delta pressure [{}]", pressureUnit ), + stats.minDeltaPressure, "/", stats.maxDeltaPressure ); + tableData.addRow( GEOS_FMT( "Temperature [{}]", tempUnit ), + stats.minTemperature, stats.averageTemperature, stats.maxTemperature ); + + tableData.addSeparator(); + + tableData.addRow( GEOS_FMT( "Total dynamic pore volume [{}]", resVolUnit ), CellType::MergeNext, CellType::MergeNext, stats.totalPoreVolume ); + tableData.addRow( GEOS_FMT( "Phase dynamic pore volume [{}]", resVolUnit ), + stringutilities::joinLambda( phaseNames, "\n", []( auto data ) { return data[0]; } ), + CellType::MergeNext, + stringutilities::joinLambda( stats.phasePoreVolume, "\n", []( auto data ) { return data[0]; } ) ); + + tableData.addSeparator(); + + tableData.addRow( GEOS_FMT( "Phase mass [{}]", massUnit ), + stringutilities::joinLambda( phaseNames, "\n", []( auto data ) { return data[0]; } ), + CellType::MergeNext, + stringutilities::joinLambda( stats.phaseMass, "\n", []( auto data ) { return data[0]; } ) ); + + tableData.addSeparator(); + + tableData.addRow( GEOS_FMT( "Trapped phase mass (metric 1) [{}]", massUnit ), + stringutilities::joinLambda( phaseNames, "\n", []( auto value ) { return value[0]; } ), + CellType::MergeNext, + stringutilities::joinLambda( stats.trappedPhaseMass, "\n", []( auto value ) { return value[0]; } ) ); + tableData.addRow( GEOS_FMT( "Non-trapped phase mass (metric 1) [{}]", massUnit ), + stringutilities::joinLambda( phaseNames, "\n", []( auto value ) { return value[0]; } ), + CellType::MergeNext, + stringutilities::joinLambda( nonTrappedPhaseMass, "\n", []( auto value ) { return value[0]; } ) ); + + tableData.addSeparator(); + + tableData.addRow( GEOS_FMT( "Immobile phase mass (metric 2) [{}]", massUnit ), + stringutilities::joinLambda( phaseNames, "\n", []( auto value ) { return value[0]; } ), + CellType::MergeNext, + stringutilities::joinLambda( stats.immobilePhaseMass, "\n", []( auto value ) { return value[0]; } ) ); + tableData.addRow( GEOS_FMT( "Mobile phase mass (metric 2) [{}]", massUnit ), + stringutilities::joinLambda( phaseNames, "\n", []( auto value ) { return value[0]; } ), + CellType::MergeNext, + stringutilities::joinLambda( mobilePhaseMass, "\n", []( auto value ) { return value[0]; } ) ); + + tableData.addSeparator(); + + tableData.addRow( GEOS_FMT( "Component mass [{}]", massUnit ), + stringutilities::join( phaseCompName, '\n' ), + CellType::MergeNext, + stringutilities::join( massValues, '\n' ) ); + + tableData.addSeparator(); + } ); +} + +} /* namespace compositionalMultiphaseStatistics */ + +REGISTER_CATALOG_ENTRY( TaskBase, + compositionalMultiphaseStatistics::StatsTask, + string const &, dataRepository::Group * const ) + +} /* namespace geos */ diff --git a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatistics.hpp b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsTask.hpp similarity index 56% rename from src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatistics.hpp rename to src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsTask.hpp index dbe275b7b6f..78fb07eac3e 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatistics.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsTask.hpp @@ -17,22 +17,29 @@ * @file CompositionalMultiphaseStatistics.hpp */ -#ifndef SRC_CORECOMPONENTS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONALMULTIPHASESTATISTICS_HPP_ -#define SRC_CORECOMPONENTS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONALMULTIPHASESTATISTICS_HPP_ +#ifndef SRC_CORECOMPONENTS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONALMULTIPHASESTATISTICSTASK_HPP_ +#define SRC_CORECOMPONENTS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONALMULTIPHASESTATISTICSTASK_HPP_ +#include "common/DataTypes.hpp" +#include "common/format/table/TableFormatter.hpp" +#include "common/format/table/TableLayout.hpp" #include "physicsSolvers/FieldStatisticsBase.hpp" +#include "physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsAggregator.hpp" namespace geos { class CompositionalMultiphaseBase; +namespace compositionalMultiphaseStatistics +{ + /** - * @class CompositionalMultiphaseStatistics + * @class CompositionalMultiphaseStatistics::Task * * Task class allowing for the computation of aggregate statistics in compositional multiphase simulations */ -class CompositionalMultiphaseStatistics : public FieldStatisticsBase< CompositionalMultiphaseBase > +class StatsTask : public FieldStatisticsBase< CompositionalMultiphaseBase > { public: @@ -41,16 +48,11 @@ class CompositionalMultiphaseStatistics : public FieldStatisticsBase< Compositio * @param[in] name the name of the task coming from the xml * @param[in] parent the parent group of the task */ - CompositionalMultiphaseStatistics( const string & name, - Group * const parent ); + StatsTask( const string & name, dataRepository::Group * const parent ); /// Accessor for the catalog name static string catalogName() { return "CompositionalMultiphaseStatistics"; } - /// Accessor for the region statistics catalog name - static string regionStatisticsName() { return "regionStatistics"; } - - /** * @defgroup Tasks Interface Functions * @@ -67,43 +69,6 @@ class CompositionalMultiphaseStatistics : public FieldStatisticsBase< Compositio /**@}*/ - struct RegionStatistics - { - /// average region pressure - real64 averagePressure; - /// minimum region pressure - real64 minPressure; - /// maximum region pressure - real64 maxPressure; - - /// minimum region delta pressure - real64 minDeltaPressure; - /// maximum region delta pressure - real64 maxDeltaPressure; - - /// average region temperature - real64 averageTemperature; - /// minimum region temperature - real64 minTemperature; - /// maximum region temperature - real64 maxTemperature; - - /// total region pore volume - real64 totalPoreVolume; - /// total region uncompacted pore volume - real64 totalUncompactedPoreVolume; - /// phase region phase pore volume - array1d< real64 > phasePoreVolume; - - /// region phase mass (trapped and non-trapped, immobile and mobile) - array1d< real64 > phaseMass; - /// trapped region phase mass - array1d< real64 > trappedPhaseMass; - /// immobile region phase mass - array1d< real64 > immobilePhaseMass; - /// region component mass - array2d< real64 > componentMass; - }; private: using Base = FieldStatisticsBase< CompositionalMultiphaseBase >; @@ -117,37 +82,36 @@ class CompositionalMultiphaseStatistics : public FieldStatisticsBase< Compositio constexpr static char const * computeCFLNumbersString() { return "computeCFLNumbers"; } /// String for the flag deciding the computation of the region statistics constexpr static char const * computeRegionStatisticsString() { return "computeRegionStatistics"; } - /// String for the region statistics - constexpr static char const * regionStatisticsString() { return "regionStatistics"; } /// String for the relperm threshold constexpr static char const * relpermThresholdString() { return "relpermThreshold"; } }; + void postInputInitialization() override; - /** - * @brief Compute some statistics on the reservoir (average field pressure, etc) - * @param[in] time current time - * @param[in] mesh the mesh level object - * @param[in] regionNames the array of target region names - */ - void computeRegionStatistics( real64 const time, - MeshLevel & mesh, - string_array const & regionNames ) const; + void registerDataOnMesh( Group & meshBodies ) override; - /** - * @brief Compute CFL numbers - * @param[in] time current time - * @param[in] dt the time step size - * @param[in] domain the domain partition - */ - void computeCFLNumbers( real64 const time, - real64 const dt, - DomainPartition & domain ) const; + void prepareFluidMetaData(); - void postInputInitialization() override; + void prepareLogTableLayouts( string_view tableName ); - void registerDataOnMesh( Group & meshBodies ) override; + void prepareCsvTableLayouts( string_view tableName ); + + void outputLogStats( real64 statsTime, + MeshLevel & mesh, + string_array const & regionNames ); + + void outputCsvStats( real64 statsTime, + MeshLevel & mesh, + string_array const & regionNames ); + + /// For each discretization (MeshLevel name), table formatter for log output. + stdMap< string, std::unique_ptr< TableFormatter > > m_logFormatters; + + /// For each discretization (MeshLevel name), table formatter for csv output. + stdMap< string, std::unique_ptr< TableFormatter > > m_csvFormatters; + + StatsAggregator m_aggregator; /// Flag to decide whether CFL numbers are computed or not integer m_computeCFLNumbers; @@ -158,9 +122,19 @@ class CompositionalMultiphaseStatistics : public FieldStatisticsBase< Compositio /// Threshold to decide whether a phase is considered "mobile" or not real64 m_relpermThreshold; + struct FluidMetaData + { + integer m_numPhases; + integer m_numComps; + stdVector< string > m_phaseNames; + stdVector< string > m_compNames; + stdVector< stdVector< string > > m_phaseCompNames; + } m_fluid; + }; +} /* namespace compositionalMultiphaseStatistics */ } /* namespace geos */ -#endif /* SRC_CORECOMPONENTS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONALMULTIPHASESTATISTICS_HPP_ */ +#endif /* SRC_CORECOMPONENTS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONALMULTIPHASESTATISTICSTASK_HPP_ */ From 37d75e5a193dd5a6d16ac6f44d186ede1c903777 Mon Sep 17 00:00:00 2001 From: MelReyCG Date: Tue, 2 Dec 2025 10:54:12 +0100 Subject: [PATCH 05/28] =?UTF-8?q?=F0=9F=9A=A7wip=202?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...sitionalMultiphaseStatisticsAggregator.cpp | 32 +++++++-------- ...sitionalMultiphaseStatisticsAggregator.hpp | 34 ++++++++++----- .../CompositionalMultiphaseStatisticsTask.cpp | 41 ++++++++++--------- 3 files changed, 62 insertions(+), 45 deletions(-) diff --git a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsAggregator.cpp b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsAggregator.cpp index 13d4fc78b9c..e459eb9b10d 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsAggregator.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsAggregator.cpp @@ -46,7 +46,10 @@ StatsAggregator::StatsAggregator(): void StatsAggregator::enableRegionStatistics( dataRepository::Group & meshBodies ) { - GEOS_ASSERT_NE( m_solver, nullptr ); + GEOS_ERROR_IF_EQ_MSG( m_solver, nullptr, "Flow solver must be set." ); + + integer const numPhases = m_solver->numFluidPhases(); + integer const numComps = m_solver->numFluidComponents(); m_solver->forDiscretizationOnMeshTargets( meshBodies, [&] ( string const &, MeshLevel & mesh, @@ -54,9 +57,6 @@ void StatsAggregator::enableRegionStatistics( dataRepository::Group & meshBodies { ElementRegionManager & elemManager = mesh.getElemManager(); - integer const numPhases = m_solver->numFluidPhases(); - integer const numComps = m_solver->numFluidComponents(); - for( size_t i = 0; i < regionNames.size(); ++i ) { ElementRegionBase & region = elemManager.getRegion( regionNames[i] ); @@ -69,7 +69,9 @@ void StatsAggregator::enableRegionStatistics( dataRepository::Group & meshBodies stats.phasePoreVolume.resizeDimension< 0 >( numPhases ); stats.phaseMass.resizeDimension< 0 >( numPhases ); stats.trappedPhaseMass.resizeDimension< 0 >( numPhases ); + stats.nonTrappedPhaseMass.resizeDimension< 0 >( numPhases ); stats.immobilePhaseMass.resizeDimension< 0 >( numPhases ); + stats.mobilePhaseMass.resizeDimension< 0 >( numPhases ); stats.componentMass.resizeDimension< 0, 1 >( numPhases, numComps ); } } ); @@ -78,15 +80,15 @@ void StatsAggregator::enableRegionStatistics( dataRepository::Group & meshBodies void StatsAggregator::enableCFLStatistics( dataRepository::Group & meshBodies ) { - GEOS_ASSERT_NE( m_solver, nullptr ); + GEOS_ERROR_IF_EQ_MSG( m_solver, nullptr, "Flow solver must be set." ); m_solver->registerDataForCFL( meshBodies ); m_isCFLNumberEnabled = true; } -void StatsAggregator::computeDiscretizationStatistics( real64 const time, - MeshLevel & mesh, - string_array const & regionNames ) const +bool StatsAggregator::computeRegionsStatistics( real64 const time, + MeshLevel & mesh, + string_array const & regionNames ) const { GEOS_MARK_FUNCTION; @@ -117,7 +119,9 @@ void StatsAggregator::computeDiscretizationStatistics( real64 const time, stats.phaseMass.setValues< serialPolicy >( 0.0 ); stats.trappedPhaseMass.setValues< serialPolicy >( 0.0 ); + stats.nonTrappedPhaseMass.setValues< serialPolicy >( 0.0 ); stats.immobilePhaseMass.setValues< serialPolicy >( 0.0 ); + stats.mobilePhaseMass.setValues< serialPolicy >( 0.0 ); stats.componentMass.setValues< serialPolicy >( 0.0 ); } @@ -289,18 +293,14 @@ void StatsAggregator::computeDiscretizationStatistics( real64 const time, stats.averagePressure = 0.0; stats.averageTemperature = 0.0; GEOS_LOG_LEVEL_RANK_0( logInfo::Statistics, - GEOS_FMT( "{}, {}: Cannot compute average pressure because region pore volume is zero.", - getName(), regionNames[i] ) ); + GEOS_FMT( "Cannot compute average pressure because region pore volume is zero in region '{}'.", + regionNames[i] ) ); } - - // helpers to report statistics - array1d< real64 > nonTrappedPhaseMass( numPhases ); - array1d< real64 > mobilePhaseMass( numPhases ); for( integer ip = 0; ip < numPhases; ++ip ) { - nonTrappedPhaseMass[ip] = stats.phaseMass[ip] - stats.trappedPhaseMass[ip]; - mobilePhaseMass[ip] = stats.phaseMass[ip] - stats.immobilePhaseMass[ip]; + stats.nonTrappedPhaseMass[ip] = stats.phaseMass[ip] - stats.trappedPhaseMass[ip]; + stats.mobilePhaseMass[ip] = stats.phaseMass[ip] - stats.immobilePhaseMass[ip]; } string_view massUnit = units::getSymbol( m_solver->getMassUnit() ); diff --git a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsAggregator.hpp b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsAggregator.hpp index 419a7e6d35f..3735f197efe 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsAggregator.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsAggregator.hpp @@ -20,6 +20,7 @@ #ifndef SRC_CORECOMPONENTS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONALMULTIPHASESTATISTICSAGGREGATOR_HPP_ #define SRC_CORECOMPONENTS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONALMULTIPHASESTATISTICSAGGREGATOR_HPP_ +#include "common/StdContainerWrappers.hpp" #include "dataRepository/Group.hpp" #include "mesh/DomainPartition.hpp" #include "mesh/MeshLevel.hpp" @@ -75,8 +76,12 @@ struct RegionStatistics array1d< real64 > phaseMass; /// trapped region phase mass array1d< real64 > trappedPhaseMass; + /// non-trapped region phase mass + array1d< real64 > nonTrappedPhaseMass; /// immobile region phase mass array1d< real64 > immobilePhaseMass; + /// mobile region phase mass + array1d< real64 > mobilePhaseMass; /// region component mass array2d< real64 > componentMass; @@ -107,7 +112,7 @@ class StatsAggregator constexpr static char const * regionStatisticsString() { return "regionStatistics"; } }; - using RegionFunctor = std::function< void (string, RegionStatistics const &) >; + using RegionFunctor = std::function< void (string_view, RegionStatistics const &) >; StatsAggregator(); @@ -124,14 +129,14 @@ class StatsAggregator // std::function< void(MeshLevel const &, // string_array const & regionNames) > functor ) const; - // void forRegionStatistics( DomainPartition const &, - // MeshLevel const & mesh, - // RegionFunctor functor ) const; + void forRegionStatistics( DomainPartition const &, + MeshLevel const & mesh, + RegionFunctor functor ) const; /** - * @brief Register the results structs & wrappers so they will be targeted by TimeHistory output + * @brief Enable the computation of region statistics, initialize data structure to collect them. + * Register the resulting data wrappers so they will be targeted by TimeHistory output * @note Must be called in "registerDataOnMesh" initialization phase - * @param solver The flow solver * @param meshBodies The Group containing the MeshBody objects */ void enableRegionStatistics( dataRepository::Group & meshBodies ); @@ -139,20 +144,21 @@ class StatsAggregator /** * @brief Register the results structs & wrappers so they will be targeted by TimeHistory output * @note Must be called in "registerDataOnMesh" initialization phase - * @param solver The flow solver * @param meshBodies The Group containing the MeshBody objects */ void enableCFLStatistics( dataRepository::Group & meshBodies ); /** * @brief Compute some statistics on a given mesh discretization (average field pressure, etc) + * Results are reduced on rank 0, and broadcasted over all ranks. * @param[in] time current time * @param[in] mesh the mesh level object * @param[in] regionNames the array of target region names + * return false if */ - void computeDiscretizationStatistics( real64 const time, - MeshLevel & mesh, - string_array const & regionNames ) const; + bool computeRegionsStatistics( real64 const time, + MeshLevel & mesh, + string_array const & regionNames ) const; /** * @brief Compute CFL numbers @@ -167,6 +173,12 @@ class StatsAggregator CFLStatistics const & getCFLStatistics() const { return m_cflStats; } + CompositionalMultiphaseBase const * getSolver() const + { return m_solver; } + + stdVector< string_view > const & getIssues() const + { return m_issues; } + private: CompositionalMultiphaseBase * m_solver; @@ -175,6 +187,8 @@ class StatsAggregator CFLStatistics m_cflStats; + stdVector< string_view > m_issues; + bool m_isRegionStatsEnabled; bool m_isCFLNumberEnabled; diff --git a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsTask.cpp b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsTask.cpp index b3d6a6b59b8..608e57fe9b9 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsTask.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsTask.cpp @@ -27,6 +27,7 @@ #include "constitutive/relativePermeability/RelativePermeabilityBase.hpp" #include "constitutive/solid/CoupledSolidBase.hpp" #include "physicsSolvers/LogLevelsInfo.hpp" +#include "physicsSolvers/fluidFlow/LogLevelsInfo.hpp" #include "physicsSolvers/fluidFlow/CompositionalMultiphaseBase.hpp" #include "physicsSolvers/fluidFlow/CompositionalMultiphaseBaseFields.hpp" #include "physicsSolvers/fluidFlow/CompositionalMultiphaseHybridFVM.hpp" @@ -233,7 +234,7 @@ void StatsTask::outputLogStats( real64 const statsTime, MeshLevel & mesh, string_array const & regionNames ) { - auto const formatterIter = m_logFormatters.find( mesh.getName()); + auto const formatterIter = m_logFormatters.find( mesh.getName() ); if( formatterIter==m_logFormatters.end()) return; @@ -241,13 +242,15 @@ void StatsTask::outputLogStats( real64 const statsTime, TableData tableData; static constexpr auto merge = CellType::MergeNext; + string_view massUnit = units::getSymbol( m_aggregator.getSolver()->getMassUnit() ); + string_view pressureUnit = units::getSymbol( units::Pressure ); + string_view tempUnit = units::getSymbol( units::Temperature ); + string_view resVolUnit = units::getSymbol( units::ReservoirVolume ); + tableData.addRow( "Statistics time", merge, merge, statsTime ); - forRegionStatistics( []( string_view regionName, RegionStatistics const & stats ) + m_aggregator.forRegionStatistics( MeshLevel & mesh, + [&]( string_view regionName, RegionStatistics const & stats ) { - string_view massUnit = units::getSymbol( m_solver->getMassUnit() ); - string_view pressureUnit = units::getSymbol( units::Pressure ); - string_view tempUnit = units::getSymbol( units::Temperature ); - string_view resVolUnit = "rm3"; tableData.addRow( merge, merge, merge, "" ); @@ -267,54 +270,54 @@ void StatsTask::outputLogStats( real64 const statsTime, tableData.addRow( GEOS_FMT( "Total dynamic pore volume [{}]", resVolUnit ), CellType::MergeNext, CellType::MergeNext, stats.totalPoreVolume ); tableData.addRow( GEOS_FMT( "Phase dynamic pore volume [{}]", resVolUnit ), - stringutilities::joinLambda( phaseNames, "\n", []( auto data ) { return data[0]; } ), + stringutilities::joinLambda( m_fluid.m_phaseNames, "\n", []( auto data ) { return data[0]; } ), CellType::MergeNext, stringutilities::joinLambda( stats.phasePoreVolume, "\n", []( auto data ) { return data[0]; } ) ); tableData.addSeparator(); tableData.addRow( GEOS_FMT( "Phase mass [{}]", massUnit ), - stringutilities::joinLambda( phaseNames, "\n", []( auto data ) { return data[0]; } ), + stringutilities::joinLambda( m_fluid.m_phaseNames, "\n", []( auto data ) { return data[0]; } ), CellType::MergeNext, stringutilities::joinLambda( stats.phaseMass, "\n", []( auto data ) { return data[0]; } ) ); tableData.addSeparator(); tableData.addRow( GEOS_FMT( "Trapped phase mass (metric 1) [{}]", massUnit ), - stringutilities::joinLambda( phaseNames, "\n", []( auto value ) { return value[0]; } ), + stringutilities::joinLambda( m_fluid.m_phaseNames, "\n", []( auto value ) { return value[0]; } ), CellType::MergeNext, stringutilities::joinLambda( stats.trappedPhaseMass, "\n", []( auto value ) { return value[0]; } ) ); tableData.addRow( GEOS_FMT( "Non-trapped phase mass (metric 1) [{}]", massUnit ), - stringutilities::joinLambda( phaseNames, "\n", []( auto value ) { return value[0]; } ), + stringutilities::joinLambda( m_fluid.m_phaseNames, "\n", []( auto value ) { return value[0]; } ), CellType::MergeNext, - stringutilities::joinLambda( nonTrappedPhaseMass, "\n", []( auto value ) { return value[0]; } ) ); + stringutilities::joinLambda( stats.nonTrappedPhaseMass, "\n", []( auto value ) { return value[0]; } ) ); tableData.addSeparator(); tableData.addRow( GEOS_FMT( "Immobile phase mass (metric 2) [{}]", massUnit ), - stringutilities::joinLambda( phaseNames, "\n", []( auto value ) { return value[0]; } ), + stringutilities::joinLambda( m_fluid.m_phaseNames, "\n", []( auto value ) { return value[0]; } ), CellType::MergeNext, stringutilities::joinLambda( stats.immobilePhaseMass, "\n", []( auto value ) { return value[0]; } ) ); tableData.addRow( GEOS_FMT( "Mobile phase mass (metric 2) [{}]", massUnit ), - stringutilities::joinLambda( phaseNames, "\n", []( auto value ) { return value[0]; } ), + stringutilities::joinLambda( m_fluid.m_phaseNames, "\n", []( auto value ) { return value[0]; } ), CellType::MergeNext, - stringutilities::joinLambda( mobilePhaseMass, "\n", []( auto value ) { return value[0]; } ) ); + stringutilities::joinLambda( stats.mobilePhaseMass, "\n", []( auto value ) { return value[0]; } ) ); tableData.addSeparator(); tableData.addRow( GEOS_FMT( "Component mass [{}]", massUnit ), - stringutilities::join( phaseCompName, '\n' ), + stringutilities::join( m_fluid.m_phaseCompNames, '\n' ), CellType::MergeNext, - stringutilities::join( massValues, '\n' ) ); + stringutilities::join( stats.componentMass, '\n' ) ); tableData.addSeparator(); } ); } -} /* namespace compositionalMultiphaseStatistics */ - REGISTER_CATALOG_ENTRY( TaskBase, - compositionalMultiphaseStatistics::StatsTask, + StatsTask, string const &, dataRepository::Group * const ) +} /* namespace compositionalMultiphaseStatistics */ + } /* namespace geos */ From 239ff243eabac0a3f04abba2757e811d983b81da Mon Sep 17 00:00:00 2001 From: MelReyCG Date: Tue, 2 Dec 2025 11:47:13 +0100 Subject: [PATCH 06/28] =?UTF-8?q?=F0=9F=9A=A7=20applying=20merge=20change?= =?UTF-8?q?=20to=20task=20component?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../CompositionalMultiphaseStatisticsTask.cpp | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsTask.cpp b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsTask.cpp index 608e57fe9b9..bf340da9478 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsTask.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsTask.cpp @@ -173,19 +173,19 @@ void StatsTask::prepareCsvTableLayouts( string_view meshName ) string_view massUnit = units::getSymbol( m_solver->getMassUnit() ); TableLayout tableLayout( { - TableLayout::Column().setName( "Time [s]" ), - TableLayout::Column().setName( "Region" ), // TODO : mention this change in PR description - TableLayout::Column().setName( "Min pressure [Pa]" ), - TableLayout::Column().setName( "Average pressure [Pa]" ), - TableLayout::Column().setName( "Max pressure [Pa]" ), - TableLayout::Column().setName( "Min delta pressure [Pa]" ), - TableLayout::Column().setName( "Max delta pressure [Pa]" ), - TableLayout::Column().setName( "Min temperature [Pa]" ), - TableLayout::Column().setName( "Average temperature [Pa]" ), - TableLayout::Column().setName( "Max temperature [Pa]" ), - TableLayout::Column().setName( "Total dynamic pore volume [rm^3]" ), - } ); - addPhaseColumns( tableLayout, "Phase dynamic pore volume", "rm^3", numPhases ); + TableLayout::Column().setName( GEOS_FMT( "Time [{}]", units::getSymbol( units::Unit::Time ))), + TableLayout::Column().setName( "Region" ), // TODO : mention this change in PR description + TableLayout::Column().setName( GEOS_FMT( "Min pressure [{}]", units::getSymbol( units::Unit::Pressure ))), + TableLayout::Column().setName( GEOS_FMT( "Average pressure [{}]", units::getSymbol( units::Unit::Pressure )) ), + TableLayout::Column().setName( GEOS_FMT( "Max pressure [{}]", units::getSymbol( units::Unit::Pressure ) ) ), + TableLayout::Column().setName( GEOS_FMT( "Min delta pressure [{}]", units::getSymbol( units::Unit::Pressure ))), + TableLayout::Column().setName( GEOS_FMT( "Max delta pressure [{}]", units::getSymbol( units::Unit::Pressure ))), + TableLayout::Column().setName( GEOS_FMT( "Min temperature [{}]", units::getSymbol( units::Unit::Temperature ) )), + TableLayout::Column().setName( GEOS_FMT( "Average temperature [{}]", units::getSymbol( units::Unit::Temperature ) )), + TableLayout::Column().setName( GEOS_FMT( "Max temperature [{}]", units::getSymbol( units::Unit::Temperature ) )), + TableLayout::Column().setName( GEOS_FMT( "Total dynamic pore volume [{}]", units::getSymbol( units::Unit::ReservoirVolume ) )), + } ); + addPhaseColumns( tableLayout, "Phase dynamic pore volume", units::getSymbol( units::Unit::ReservoirVolume ) ), numPhases ); addPhaseColumns( tableLayout, "Phase mass", massUnit, numPhases ); addPhaseColumns( tableLayout, "Trapped phase mass (metric 1)", massUnit, numPhases ); addPhaseColumns( tableLayout, "Non-trapped phase mass (metric 1)", massUnit, numPhases ); From 9ff68f48d22757fa531d7905af795221eced80d8 Mon Sep 17 00:00:00 2001 From: MelReyCG Date: Tue, 9 Dec 2025 11:22:36 +0100 Subject: [PATCH 07/28] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20uncoupling=20regions?= =?UTF-8?q?=20and=20statistics=20data=20storage=20(WIP,=20data=20could=20b?= =?UTF-8?q?e=20stored=20in=20an=20uncoupled=20place)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/format/table/TableFormatter.hpp | 6 + ...sitionalMultiphaseStatisticsAggregator.cpp | 313 +++++++----------- ...sitionalMultiphaseStatisticsAggregator.hpp | 112 ++++--- .../CompositionalMultiphaseStatisticsTask.cpp | 122 +++++-- .../CompositionalMultiphaseStatisticsTask.hpp | 8 +- .../wells/CompositionalMultiphaseWell.cpp | 33 +- 6 files changed, 319 insertions(+), 275 deletions(-) diff --git a/src/coreComponents/common/format/table/TableFormatter.hpp b/src/coreComponents/common/format/table/TableFormatter.hpp index c2035bc2a1c..e73927a9b2d 100644 --- a/src/coreComponents/common/format/table/TableFormatter.hpp +++ b/src/coreComponents/common/format/table/TableFormatter.hpp @@ -57,6 +57,12 @@ class TableFormatter TableErrorListing & getErrorsList() const { return *m_errors; } + /** + * @return The prepared table layout + */ + PreparedTableLayout const & getLayout() const + { return m_tableLayout; } + protected: /// Layout for a table diff --git a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsAggregator.cpp b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsAggregator.cpp index e459eb9b10d..c2a923a4b0f 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsAggregator.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsAggregator.cpp @@ -19,6 +19,8 @@ #include "CompositionalMultiphaseStatisticsAggregator.hpp" +#include "common/DataTypes.hpp" +#include "common/format/Format.hpp" #include "common/logger/Logger.hpp" #include "physicsSolvers/fluidFlow/CompositionalMultiphaseBase.hpp" #include "physicsSolvers/fluidFlow/kernels/compositional/StatisticsKernel.hpp" @@ -39,43 +41,49 @@ using namespace dataRepository; StatsAggregator::StatsAggregator(): m_params(), - m_cflStats(), m_isRegionStatsEnabled( false ), m_isCFLNumberEnabled( false ) {} -void StatsAggregator::enableRegionStatistics( dataRepository::Group & meshBodies ) +void StatsAggregator::enableRegionStatistics( dataRepository::Group & /*meshBodies*/ ) { GEOS_ERROR_IF_EQ_MSG( m_solver, nullptr, "Flow solver must be set." ); - integer const numPhases = m_solver->numFluidPhases(); - integer const numComps = m_solver->numFluidComponents(); - - m_solver->forDiscretizationOnMeshTargets( meshBodies, [&] ( string const &, - MeshLevel & mesh, - string_array const & regionNames ) - { - ElementRegionManager & elemManager = mesh.getElemManager(); + // integer const numPhases = m_solver->numFluidPhases(); + // integer const numComps = m_solver->numFluidComponents(); + + // m_solver->forDiscretizationOnMeshTargets( meshBodies, [&] ( string const &, + // MeshLevel & mesh, + // string_array const & regionNames ) + // { + // ElementRegionManager & elemManager = mesh.getElemManager(); + + // for( size_t i = 0; i < regionNames.size(); ++i ) + // { + // // ElementRegionBase & region = elemManager.getRegion( regionNames[i] ); + + // // RELOCALISER LES DONNEES region.registerWrapper< RegionStatistics >( VKStruct::regionStatisticsString() ). + // // setRestartFlags( RestartFlags::NO_WRITE ); + // // region.excludeWrappersFromPacking( { VKStruct::regionStatisticsString() } ); + // // RegionStatistics & stats = region.getReference< RegionStatistics >( VKStruct::regionStatisticsString() ); + + // // stats.m_phasePoreVolume.resizeDimension< 0 >( numPhases ); + // // stats.m_phaseMass.resizeDimension< 0 >( numPhases ); + // // stats.m_trappedPhaseMass.resizeDimension< 0 >( numPhases ); + // // stats.m_nonTrappedPhaseMass.resizeDimension< 0 >( numPhases ); + // // stats.m_immobilePhaseMass.resizeDimension< 0 >( numPhases ); + // // stats.m_mobilePhaseMass.resizeDimension< 0 >( numPhases ); + // // stats.m_componentMass.resizeDimension< 0, 1 >( numPhases, numComps ); + // } + // } ); + // m_isRegionStatsEnabled = true; +} - for( size_t i = 0; i < regionNames.size(); ++i ) - { - ElementRegionBase & region = elemManager.getRegion( regionNames[i] ); - - region.registerWrapper< RegionStatistics >( viewKeyStruct::regionStatisticsString() ). - setRestartFlags( RestartFlags::NO_WRITE ); - region.excludeWrappersFromPacking( { viewKeyStruct::regionStatisticsString() } ); - RegionStatistics & stats = region.getReference< RegionStatistics >( viewKeyStruct::regionStatisticsString() ); - - stats.phasePoreVolume.resizeDimension< 0 >( numPhases ); - stats.phaseMass.resizeDimension< 0 >( numPhases ); - stats.trappedPhaseMass.resizeDimension< 0 >( numPhases ); - stats.nonTrappedPhaseMass.resizeDimension< 0 >( numPhases ); - stats.immobilePhaseMass.resizeDimension< 0 >( numPhases ); - stats.mobilePhaseMass.resizeDimension< 0 >( numPhases ); - stats.componentMass.resizeDimension< 0, 1 >( numPhases, numComps ); - } - } ); - m_isRegionStatsEnabled = true; +void StatsAggregator::forRegionStatistics( MeshLevel const & mesh, + StatsAggregator::RegionFunctor functor ) const +{ + GEOS_UNUSED_VAR( mesh ); + GEOS_UNUSED_VAR( functor ); } void StatsAggregator::enableCFLStatistics( dataRepository::Group & meshBodies ) @@ -88,7 +96,7 @@ void StatsAggregator::enableCFLStatistics( dataRepository::Group & meshBodies ) bool StatsAggregator::computeRegionsStatistics( real64 const time, MeshLevel & mesh, - string_array const & regionNames ) const + string_array const & regionNames ) { GEOS_MARK_FUNCTION; @@ -100,29 +108,31 @@ bool StatsAggregator::computeRegionsStatistics( real64 const time, for( size_t i = 0; i < regionNames.size(); ++i ) { ElementRegionBase & region = elemManager.getRegion( regionNames[i] ); - RegionStatistics & stats = region.getReference< RegionStatistics >( viewKeyStruct::regionStatisticsString() ); + RegionStatistics & stats = region.getReference< RegionStatistics >( VKStruct::regionStatisticsString() ); - stats.averagePressure = 0.0; - stats.maxPressure = 0.0; - stats.minPressure = LvArray::NumericLimits< real64 >::max; + stats.m_time = time; - stats.maxDeltaPressure = -LvArray::NumericLimits< real64 >::max; - stats.minDeltaPressure = LvArray::NumericLimits< real64 >::max; + stats.m_averagePressure = 0.0; + stats.m_maxPressure = 0.0; + stats.m_minPressure = LvArray::NumericLimits< real64 >::max; - stats.averageTemperature = 0.0; - stats.maxTemperature = 0.0; - stats.minTemperature = LvArray::NumericLimits< real64 >::max; + stats.m_maxDeltaPressure = -LvArray::NumericLimits< real64 >::max; + stats.m_minDeltaPressure = LvArray::NumericLimits< real64 >::max; - stats.totalPoreVolume = 0.0; - stats.totalUncompactedPoreVolume = 0.0; - stats.phasePoreVolume.setValues< serialPolicy >( 0.0 ); + stats.m_averageTemperature = 0.0; + stats.m_maxTemperature = 0.0; + stats.m_minTemperature = LvArray::NumericLimits< real64 >::max; - stats.phaseMass.setValues< serialPolicy >( 0.0 ); - stats.trappedPhaseMass.setValues< serialPolicy >( 0.0 ); - stats.nonTrappedPhaseMass.setValues< serialPolicy >( 0.0 ); - stats.immobilePhaseMass.setValues< serialPolicy >( 0.0 ); - stats.mobilePhaseMass.setValues< serialPolicy >( 0.0 ); - stats.componentMass.setValues< serialPolicy >( 0.0 ); + stats.m_totalPoreVolume = 0.0; + stats.m_totalUncompactedPoreVolume = 0.0; + stats.m_phasePoreVolume.setValues< serialPolicy >( 0.0 ); + + stats.m_phaseMass.setValues< serialPolicy >( 0.0 ); + stats.m_trappedPhaseMass.setValues< serialPolicy >( 0.0 ); + stats.m_nonTrappedPhaseMass.setValues< serialPolicy >( 0.0 ); + stats.m_immobilePhaseMass.setValues< serialPolicy >( 0.0 ); + stats.m_mobilePhaseMass.setValues< serialPolicy >( 0.0 ); + stats.m_componentMass.setValues< serialPolicy >( 0.0 ); } // Step 2: increment the average/min/max quantities for all the subRegions @@ -207,48 +217,48 @@ bool StatsAggregator::computeRegionsStatistics( real64 const time, subRegionComponentMass.toView() ); ElementRegionBase & region = elemManager.getRegion( ElementRegionBase::getParentRegion( subRegion ).getName() ); - RegionStatistics & stats = region.getReference< RegionStatistics >( viewKeyStruct::regionStatisticsString() ); + RegionStatistics & stats = region.getReference< RegionStatistics >( VKStruct::regionStatisticsString() ); - stats.averagePressure += subRegionAvgPresNumerator; - if( subRegionMinPres < stats.minPressure ) + stats.m_averagePressure += subRegionAvgPresNumerator; + if( subRegionMinPres < stats.m_minPressure ) { - stats.minPressure = subRegionMinPres; + stats.m_minPressure = subRegionMinPres; } - if( subRegionMaxPres > stats.maxPressure ) + if( subRegionMaxPres > stats.m_maxPressure ) { - stats.maxPressure = subRegionMaxPres; + stats.m_maxPressure = subRegionMaxPres; } - if( subRegionMinDeltaPres < stats.minDeltaPressure ) + if( subRegionMinDeltaPres < stats.m_minDeltaPressure ) { - stats.minDeltaPressure = subRegionMinDeltaPres; + stats.m_minDeltaPressure = subRegionMinDeltaPres; } - if( subRegionMaxDeltaPres > stats.maxDeltaPressure ) + if( subRegionMaxDeltaPres > stats.m_maxDeltaPressure ) { - stats.maxDeltaPressure = subRegionMaxDeltaPres; + stats.m_maxDeltaPressure = subRegionMaxDeltaPres; } - stats.averageTemperature += subRegionAvgTempNumerator; - if( subRegionMinTemp < stats.minTemperature ) + stats.m_averageTemperature += subRegionAvgTempNumerator; + if( subRegionMinTemp < stats.m_minTemperature ) { - stats.minTemperature = subRegionMinTemp; + stats.m_minTemperature = subRegionMinTemp; } - if( subRegionMaxTemp > stats.maxTemperature ) + if( subRegionMaxTemp > stats.m_maxTemperature ) { - stats.maxTemperature = subRegionMaxTemp; + stats.m_maxTemperature = subRegionMaxTemp; } - stats.totalUncompactedPoreVolume += subRegionTotalUncompactedPoreVol; + stats.m_totalUncompactedPoreVolume += subRegionTotalUncompactedPoreVol; for( integer ip = 0; ip < numPhases; ++ip ) { - stats.phasePoreVolume[ip] += subRegionPhaseDynamicPoreVol[ip]; - stats.phaseMass[ip] += subRegionPhaseMass[ip]; - stats.trappedPhaseMass[ip] += subRegionTrappedPhaseMass[ip]; - stats.immobilePhaseMass[ip] += subRegionImmobilePhaseMass[ip]; + stats.m_phasePoreVolume[ip] += subRegionPhaseDynamicPoreVol[ip]; + stats.m_phaseMass[ip] += subRegionPhaseMass[ip]; + stats.m_trappedPhaseMass[ip] += subRegionTrappedPhaseMass[ip]; + stats.m_immobilePhaseMass[ip] += subRegionImmobilePhaseMass[ip]; for( integer ic = 0; ic < numComps; ++ic ) { - stats.componentMass[ip][ic] += subRegionComponentMass[ip][ic]; + stats.m_componentMass[ip][ic] += subRegionComponentMass[ip][ic]; } } @@ -258,59 +268,56 @@ bool StatsAggregator::computeRegionsStatistics( real64 const time, for( size_t i = 0; i < regionNames.size(); ++i ) { ElementRegionBase & region = elemManager.getRegion( regionNames[i] ); - RegionStatistics & stats = region.getReference< RegionStatistics >( viewKeyStruct::regionStatisticsString() ); - - stats.minPressure = MpiWrapper::min( stats.minPressure ); - stats.maxPressure = MpiWrapper::max( stats.maxPressure ); - stats.minDeltaPressure = MpiWrapper::min( stats.minDeltaPressure ); - stats.maxDeltaPressure = MpiWrapper::max( stats.maxDeltaPressure ); - stats.minTemperature = MpiWrapper::min( stats.minTemperature ); - stats.maxTemperature = MpiWrapper::max( stats.maxTemperature ); - stats.totalUncompactedPoreVolume = MpiWrapper::sum( stats.totalUncompactedPoreVolume ); - stats.totalPoreVolume = 0.0; + RegionStatistics & stats = region.getReference< RegionStatistics >( VKStruct::regionStatisticsString() ); + + stats.m_minPressure = MpiWrapper::min( stats.m_minPressure ); + stats.m_maxPressure = MpiWrapper::max( stats.m_maxPressure ); + stats.m_minDeltaPressure = MpiWrapper::min( stats.m_minDeltaPressure ); + stats.m_maxDeltaPressure = MpiWrapper::max( stats.m_maxDeltaPressure ); + stats.m_minTemperature = MpiWrapper::min( stats.m_minTemperature ); + stats.m_maxTemperature = MpiWrapper::max( stats.m_maxTemperature ); + stats.m_totalUncompactedPoreVolume = MpiWrapper::sum( stats.m_totalUncompactedPoreVolume ); + stats.m_totalPoreVolume = 0.0; for( integer ip = 0; ip < numPhases; ++ip ) { - stats.phasePoreVolume[ip] = MpiWrapper::sum( stats.phasePoreVolume[ip] ); - stats.phaseMass[ip] = MpiWrapper::sum( stats.phaseMass[ip] ); - stats.trappedPhaseMass[ip] = MpiWrapper::sum( stats.trappedPhaseMass[ip] ); - stats.immobilePhaseMass[ip] = MpiWrapper::sum( stats.immobilePhaseMass[ip] ); - stats.totalPoreVolume += stats.phasePoreVolume[ip]; + stats.m_phasePoreVolume[ip] = MpiWrapper::sum( stats.m_phasePoreVolume[ip] ); + stats.m_phaseMass[ip] = MpiWrapper::sum( stats.m_phaseMass[ip] ); + stats.m_trappedPhaseMass[ip] = MpiWrapper::sum( stats.m_trappedPhaseMass[ip] ); + stats.m_immobilePhaseMass[ip] = MpiWrapper::sum( stats.m_immobilePhaseMass[ip] ); + stats.m_totalPoreVolume += stats.m_phasePoreVolume[ip]; for( integer ic = 0; ic < numComps; ++ic ) { - stats.componentMass[ip][ic] = MpiWrapper::sum( stats.componentMass[ip][ic] ); + stats.m_componentMass[ip][ic] = MpiWrapper::sum( stats.m_componentMass[ip][ic] ); } } - stats.averagePressure = MpiWrapper::sum( stats.averagePressure ); - stats.averageTemperature = MpiWrapper::sum( stats.averageTemperature ); - if( stats.totalUncompactedPoreVolume > 0 ) + stats.m_averagePressure = MpiWrapper::sum( stats.m_averagePressure ); + stats.m_averageTemperature = MpiWrapper::sum( stats.m_averageTemperature ); + if( stats.m_totalUncompactedPoreVolume > 0 ) { - float invTotalUncompactedPoreVolume = 1.0 / stats.totalUncompactedPoreVolume; - stats.averagePressure *= invTotalUncompactedPoreVolume; - stats.averageTemperature *= invTotalUncompactedPoreVolume; + float invTotalUncompactedPoreVolume = 1.0 / stats.m_totalUncompactedPoreVolume; + stats.m_averagePressure *= invTotalUncompactedPoreVolume; + stats.m_averageTemperature *= invTotalUncompactedPoreVolume; } else { - stats.averagePressure = 0.0; - stats.averageTemperature = 0.0; - GEOS_LOG_LEVEL_RANK_0( logInfo::Statistics, - GEOS_FMT( "Cannot compute average pressure because region pore volume is zero in region '{}'.", + stats.m_averagePressure = 0.0; + stats.m_averageTemperature = 0.0; + m_issues.emplace_back( GEOS_FMT( "Cannot compute average pressure because region pore volume is zero in region '{}'.", regionNames[i] ) ); } for( integer ip = 0; ip < numPhases; ++ip ) { - stats.nonTrappedPhaseMass[ip] = stats.phaseMass[ip] - stats.trappedPhaseMass[ip]; - stats.mobilePhaseMass[ip] = stats.phaseMass[ip] - stats.immobilePhaseMass[ip]; + stats.m_nonTrappedPhaseMass[ip] = stats.m_phaseMass[ip] - stats.m_trappedPhaseMass[ip]; + stats.m_mobilePhaseMass[ip] = stats.m_phaseMass[ip] - stats.m_immobilePhaseMass[ip]; } - string_view massUnit = units::getSymbol( m_solver->getMassUnit() ); - stdVector< string > phaseCompName; phaseCompName.reserve( numPhases*numComps ); stdVector< string > massValues; phaseCompName.reserve( numPhases*numComps ); - ConstitutiveManager const & constitutiveManager = this->getGroupByPath< ConstitutiveManager >( "/Problem/domain/Constitutive" ); + ConstitutiveManager const & constitutiveManager = mesh.getGroupByPath< ConstitutiveManager >( "/Problem/domain/Constitutive" ); MultiFluidBase const & fluid = constitutiveManager.getGroup< MultiFluidBase >( m_solver->referenceFluidModelName() ); auto const phaseNames = fluid.phaseNames(); auto const componentNames = fluid.componentNames(); @@ -321,105 +328,39 @@ bool StatsAggregator::computeRegionsStatistics( real64 const time, std::stringstream ss; ss << phaseNames[ip] << "/" << componentNames[ic]; phaseCompName.push_back( ss.str() ); - massValues.push_back( GEOS_FMT( "{}", stats.componentMass[ip][ic] ) ); + massValues.push_back( GEOS_FMT( "{}", stats.m_componentMass[ip][ic] ) ); } } - - if( isLogLevelActive< logInfo::Statistics >( this->getLogLevel() ) && MpiWrapper::commRank() == 0 ) - { - TableData compPhaseStatsData; - compPhaseStatsData.addRow( "Pressure [Pa]", stats.minPressure, stats.averagePressure, stats.maxPressure ); - compPhaseStatsData.addRow( "Delta pressure [Pa]", stats.minDeltaPressure, "/", stats.maxDeltaPressure ); - compPhaseStatsData.addRow( "Temperature [K]", stats.minTemperature, stats.averageTemperature, stats.maxTemperature ); - compPhaseStatsData.addSeparator(); - - compPhaseStatsData.addRow( "Total dynamic pore volume [rm^3]", CellType::MergeNext, CellType::MergeNext, stats.totalPoreVolume ); - compPhaseStatsData.addSeparator(); - compPhaseStatsData.addRow( "Phase dynamic pore volume [rm^3]", - stringutilities::joinLambda( phaseNames, "\n", []( auto data ) { return data[0]; } ), - CellType::MergeNext, - stringutilities::joinLambda( stats.phasePoreVolume, "\n", []( auto data ) { return data[0]; } ) ); - compPhaseStatsData.addSeparator(); - - compPhaseStatsData.addRow( GEOS_FMT( "Phase mass [{}]", massUnit ), - stringutilities::joinLambda( phaseNames, "\n", []( auto data ) { return data[0]; } ), - CellType::MergeNext, - stringutilities::joinLambda( stats.phaseMass, "\n", []( auto data ) { return data[0]; } ) ); - compPhaseStatsData.addSeparator(); - - compPhaseStatsData.addRow( GEOS_FMT( "Trapped phase mass (metric 1) [{}]", massUnit ), - stringutilities::joinLambda( phaseNames, "\n", []( auto value ) { return value[0]; } ), - CellType::MergeNext, - stringutilities::joinLambda( stats.trappedPhaseMass, "\n", []( auto value ) { return value[0]; } ) ); - compPhaseStatsData.addSeparator(); - compPhaseStatsData.addRow( GEOS_FMT( "Non-trapped phase mass (metric 1) [{}]", massUnit ), - stringutilities::joinLambda( phaseNames, "\n", []( auto value ) { return value[0]; } ), - CellType::MergeNext, - stringutilities::joinLambda( nonTrappedPhaseMass, "\n", []( auto value ) { return value[0]; } ) ); - compPhaseStatsData.addSeparator(); - - compPhaseStatsData.addRow( GEOS_FMT( "Immobile phase mass (metric 2) [{}]", massUnit ), - stringutilities::joinLambda( phaseNames, "\n", []( auto value ) { return value[0]; } ), - CellType::MergeNext, - stringutilities::joinLambda( stats.immobilePhaseMass, "\n", []( auto value ) { return value[0]; } ) ); - compPhaseStatsData.addSeparator(); - compPhaseStatsData.addRow( GEOS_FMT( "Mobile phase mass (metric 2) [{}]", massUnit ), - stringutilities::joinLambda( phaseNames, "\n", []( auto value ) { return value[0]; } ), - CellType::MergeNext, - stringutilities::joinLambda( mobilePhaseMass, "\n", []( auto value ) { return value[0]; } ) ); - compPhaseStatsData.addSeparator(); - - compPhaseStatsData.addRow( GEOS_FMT( "Component mass [{}]", massUnit ), - stringutilities::join( phaseCompName, '\n' ), - CellType::MergeNext, - stringutilities::join( massValues, '\n' ) ); - - string const title = GEOS_FMT( "{}, {} (time {} s):", getName(), regionNames[i], time ); - TableLayout const compPhaseStatsLayout( title, { "statistics", "min", "average", "max" } ); - TableTextFormatter tableFormatter( compPhaseStatsLayout ); - GEOS_LOG_RANK_0( tableFormatter.toString( compPhaseStatsData ) ); - } - - if( m_writeCSV > 0 && MpiWrapper::commRank() == 0 ) - { - TableData tableData; - tableData.addRow( time, stats.minPressure, stats.averagePressure, stats.maxPressure, stats.minDeltaPressure, stats.maxDeltaPressure, - stats.minTemperature, stats.averageTemperature, stats.maxTemperature, stats.totalPoreVolume, - stringutilities::joinLambda( stats.phasePoreVolume, "\n", []( auto data ) { return data[0]; } ), - stringutilities::joinLambda( stats.phaseMass, "\n", []( auto data ) { return data[0]; } ), - stringutilities::joinLambda( stats.trappedPhaseMass, "\n", []( auto value ) { return value[0]; } ), - stringutilities::joinLambda( nonTrappedPhaseMass, "\n", []( auto value ) { return value[0]; } ), - stringutilities::joinLambda( stats.immobilePhaseMass, "\n", []( auto value ) { return value[0]; } ), - stringutilities::joinLambda( mobilePhaseMass, "\n", []( auto value ) { return value[0]; } ), - stringutilities::join( massValues, '\n' ) ); - - std::ofstream outputFile( m_outputDir + "/" + regionNames[i] + ".csv", std::ios_base::app ); - TableCSVFormatter const csvOutput; - outputFile << csvOutput.dataToString( tableData ); - outputFile.close(); - } } + return true; } -void CompositionalMultiphaseStatistics::computeCFLNumbers( real64 const time, - real64 const dt, - DomainPartition & domain ) const +bool StatsAggregator::computeCFLNumbers( real64 const time, + real64 const dt, + DomainPartition & domain ) { GEOS_MARK_FUNCTION; real64 maxPhaseCFL, maxCompCFL; + CFLStatistics * stats = getCFLStatistics( domain ); + + m_issues.clear(); + + if( stats!=nullptr ) + { + m_issues.emplace_back( GEOS_FMT( "No statistics structure to compute CFL numbers for domain '{}'.", domain.getName() )); + return false; + } + m_solver->computeCFLNumbers( domain, dt, maxPhaseCFL, maxCompCFL ); - GEOS_LOG_LEVEL_RANK_0( logInfo::CFL, - GEOS_FMT( "{} (time {} s): Max phase CFL number: {}", getName(), time, maxPhaseCFL ) ); - GEOS_LOG_LEVEL_RANK_0( logInfo::CFL, - GEOS_FMT( "{} (time {} s): Max component CFL number: {}", getName(), time, maxCompCFL ) ); -} + stats->m_time = time; + stats->m_maxPhaseCFL = maxPhaseCFL; + stats->m_maxCompCFL = maxCompCFL; + return true; +} -REGISTER_CATALOG_ENTRY( TaskBase, - CompositionalMultiphaseStatistics, - string const &, dataRepository::Group * const ) } /* namespace compositionalMultiphaseStatistics */ diff --git a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsAggregator.hpp b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsAggregator.hpp index 3735f197efe..1e751dd2825 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsAggregator.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsAggregator.hpp @@ -14,7 +14,7 @@ */ /** - * @file CompositionalMultiphaseStatistics.hpp + * @file CompositionalMultiphaseStatisticsAggregator.hpp */ #ifndef SRC_CORECOMPONENTS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONALMULTIPHASESTATISTICSAGGREGATOR_HPP_ @@ -41,75 +41,110 @@ struct AggregatorParameters // TODO: add other params like views and stuff }; -struct RegionStatistics +/** + * @brief Output data group to contain the result of a given stat aggregator on the dataRepository. + * Attributes are public since the class is a POD. Can it be replaced by a wrapped-struct? + */ +class RegionStatistics : public dataRepository::Group { +public: + /// Time of statistics computation - real64 time; + real64 m_time; /// average region pressure - real64 averagePressure; + real64 m_averagePressure; /// minimum region pressure - real64 minPressure; + real64 m_minPressure; /// maximum region pressure - real64 maxPressure; + real64 m_maxPressure; /// minimum region delta pressure - real64 minDeltaPressure; + real64 m_minDeltaPressure; /// maximum region delta pressure - real64 maxDeltaPressure; + real64 m_maxDeltaPressure; /// average region temperature - real64 averageTemperature; + real64 m_averageTemperature; /// minimum region temperature - real64 minTemperature; + real64 m_minTemperature; /// maximum region temperature - real64 maxTemperature; + real64 m_maxTemperature; /// total region pore volume - real64 totalPoreVolume; + real64 m_totalPoreVolume; /// total region uncompacted pore volume - real64 totalUncompactedPoreVolume; + real64 m_totalUncompactedPoreVolume; /// phase region phase pore volume - array1d< real64 > phasePoreVolume; + array1d< real64 > m_phasePoreVolume; /// region phase mass (trapped and non-trapped, immobile and mobile) - array1d< real64 > phaseMass; + array1d< real64 > m_phaseMass; /// trapped region phase mass - array1d< real64 > trappedPhaseMass; + array1d< real64 > m_trappedPhaseMass; /// non-trapped region phase mass - array1d< real64 > nonTrappedPhaseMass; + array1d< real64 > m_nonTrappedPhaseMass; /// immobile region phase mass - array1d< real64 > immobilePhaseMass; + array1d< real64 > m_immobilePhaseMass; /// mobile region phase mass - array1d< real64 > mobilePhaseMass; + array1d< real64 > m_mobilePhaseMass; /// region component mass - array2d< real64 > componentMass; + array2d< real64 > m_componentMass; // TODO: -> split to struct PressureStats...MassStats: // - VKS for struct name ("pressureStats"..."massStats") // - current RegionStatistics struct bits + + /** + * @brief Construct a new Region Statistics object + * @param name instance name in data-repository + * @param parent the instance parent in data-repository + */ + RegionStatistics( const string & name, dataRepository::Group * const parent ); }; -struct CFLStatistics +/** + * @brief Output data group to contain the result of a given stat aggregator on the dataRepository. + * Attributes are public since the class is a POD. Can it be replaced by a wrapped-struct? + */ +class CFLStatistics : public dataRepository::Group { +public: /// Time of statistics computation - real64 time; + real64 m_time; /// Maximum Courant Friedrichs Lewy number in the grid for each phase - real64 maxPhaseCFL; + real64 m_maxPhaseCFL; /// Maximum Courant-Friedrichs-Lewy number in the grid for each component - real64 maxCompCFL; + real64 m_maxCompCFL; + + /** + * @brief Construct a new CFLStatistics object + * @param name instance name in data-repository + * @param parent the instance parent in data-repository + */ + CFLStatistics( const string & name, dataRepository::Group * const parent ); }; +/** + * @brief Reponsible of computing physical statistics over the grid, registering the result in the + * data repository, but not storing / outputing it by itself. It does not have mutable state + * except the encountered issues. + */ class StatsAggregator { public: - struct viewKeyStruct + /** + * @brief the associated view keys + */ + struct VKStruct { - /// String for the region statistics + /// String for the region statistics group constexpr static char const * regionStatisticsString() { return "regionStatistics"; } + /// String for the cfl statistics group + constexpr static char const * cflStatisticsString() { return "cflStatistics"; } }; using RegionFunctor = std::function< void (string_view, RegionStatistics const &) >; @@ -129,8 +164,7 @@ class StatsAggregator // std::function< void(MeshLevel const &, // string_array const & regionNames) > functor ) const; - void forRegionStatistics( DomainPartition const &, - MeshLevel const & mesh, + void forRegionStatistics( MeshLevel const & mesh, RegionFunctor functor ) const; /** @@ -154,29 +188,33 @@ class StatsAggregator * @param[in] time current time * @param[in] mesh the mesh level object * @param[in] regionNames the array of target region names - * return false if + * @return false if there was a problem that prevented the statistics to be computed correctly. */ bool computeRegionsStatistics( real64 const time, MeshLevel & mesh, - string_array const & regionNames ) const; + string_array const & regionNames ); /** * @brief Compute CFL numbers * @param[in] time current time * @param[in] dt the time step size * @param[in] domain the domain partition + * @return false if there was a problem that prevented the statistics to be computed correctly. */ - void computeCFLNumbers( real64 const time, + bool computeCFLNumbers( real64 const time, real64 const dt, - DomainPartition & domain ) const; + DomainPartition & domain ); - CFLStatistics const & getCFLStatistics() const - { return m_cflStats; } + CFLStatistics * getCFLStatistics( DomainPartition & domain ) const + {return domain.getGroupPointer< CFLStatistics >( VKStruct::cflStatisticsString() ); } CompositionalMultiphaseBase const * getSolver() const { return m_solver; } - stdVector< string_view > const & getIssues() const + /** + * @return The encountered issues during the last computing method call. + */ + stdVector< string > const & getIssues() const { return m_issues; } private: @@ -185,9 +223,7 @@ class StatsAggregator AggregatorParameters m_params; - CFLStatistics m_cflStats; - - stdVector< string_view > m_issues; + stdVector< string > m_issues; bool m_isRegionStatsEnabled; diff --git a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsTask.cpp b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsTask.cpp index bf340da9478..0f5aea1d1b9 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsTask.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsTask.cpp @@ -20,9 +20,11 @@ #include "CompositionalMultiphaseStatisticsTask.hpp" #include "common/DataTypes.hpp" +#include "common/MpiWrapper.hpp" #include "common/StdContainerWrappers.hpp" #include "common/format/Format.hpp" #include "mesh/DomainPartition.hpp" +#include "mesh/MeshLevel.hpp" #include "constitutive/fluid/multifluid/MultiFluidBase.hpp" #include "constitutive/relativePermeability/RelativePermeabilityBase.hpp" #include "constitutive/solid/CoupledSolidBase.hpp" @@ -36,6 +38,7 @@ #include "common/format/table/TableFormatter.hpp" #include "common/format/table/TableLayout.hpp" #include +#include namespace geos @@ -106,7 +109,7 @@ void StatsTask::registerDataOnMesh( Group & meshBodies ) m_solver->forDiscretizationOnMeshTargets( meshBodies, [&] ( string const &, MeshLevel & mesh, - string_array const & regionNames ) + string_array const & ) { prepareLogTableLayouts( mesh.getName() ); prepareCsvTableLayouts( mesh.getName() ); @@ -126,7 +129,7 @@ void StatsTask::prepareFluidMetaData() m_fluid.m_phaseCompNames.resize( m_fluid.m_numPhases, - stdVector< string >( m_fluid.m_numComps, {} ) ); + stdVector< string >( m_fluid.m_numComps, string() ) ); for( int ip = 0; ip < m_fluid.m_numPhases; ++ip ) for( int ic = 0; ic < m_fluid.m_numComps; ++ic ) @@ -142,7 +145,7 @@ void StatsTask::prepareLogTableLayouts( string_view meshName ) TableLayout const tableLayout = TableLayout() .setTitle( GEOS_FMT( "{}: mesh {}", getName(), meshName ) ); - m_csvFormatters.emplace( meshName, std::make_unique< TableTextFormatter >( tableLayout ) ); + m_logFormatters.emplace( meshName, std::make_unique< TableTextFormatter >( tableLayout ) ); } void StatsTask::prepareCsvTableLayouts( string_view meshName ) @@ -173,19 +176,19 @@ void StatsTask::prepareCsvTableLayouts( string_view meshName ) string_view massUnit = units::getSymbol( m_solver->getMassUnit() ); TableLayout tableLayout( { - TableLayout::Column().setName( GEOS_FMT( "Time [{}]", units::getSymbol( units::Unit::Time ))), - TableLayout::Column().setName( "Region" ), // TODO : mention this change in PR description - TableLayout::Column().setName( GEOS_FMT( "Min pressure [{}]", units::getSymbol( units::Unit::Pressure ))), - TableLayout::Column().setName( GEOS_FMT( "Average pressure [{}]", units::getSymbol( units::Unit::Pressure )) ), - TableLayout::Column().setName( GEOS_FMT( "Max pressure [{}]", units::getSymbol( units::Unit::Pressure ) ) ), - TableLayout::Column().setName( GEOS_FMT( "Min delta pressure [{}]", units::getSymbol( units::Unit::Pressure ))), - TableLayout::Column().setName( GEOS_FMT( "Max delta pressure [{}]", units::getSymbol( units::Unit::Pressure ))), - TableLayout::Column().setName( GEOS_FMT( "Min temperature [{}]", units::getSymbol( units::Unit::Temperature ) )), - TableLayout::Column().setName( GEOS_FMT( "Average temperature [{}]", units::getSymbol( units::Unit::Temperature ) )), - TableLayout::Column().setName( GEOS_FMT( "Max temperature [{}]", units::getSymbol( units::Unit::Temperature ) )), - TableLayout::Column().setName( GEOS_FMT( "Total dynamic pore volume [{}]", units::getSymbol( units::Unit::ReservoirVolume ) )), - } ); - addPhaseColumns( tableLayout, "Phase dynamic pore volume", units::getSymbol( units::Unit::ReservoirVolume ) ), numPhases ); + TableLayout::Column().setName( GEOS_FMT( "Time [{}]", units::getSymbol( units::Unit::Time ))), + TableLayout::Column().setName( "Region" ), // TODO : mention this change in PR description + TableLayout::Column().setName( GEOS_FMT( "Min pressure [{}]", units::getSymbol( units::Unit::Pressure ))), + TableLayout::Column().setName( GEOS_FMT( "Average pressure [{}]", units::getSymbol( units::Unit::Pressure )) ), + TableLayout::Column().setName( GEOS_FMT( "Max pressure [{}]", units::getSymbol( units::Unit::Pressure ) ) ), + TableLayout::Column().setName( GEOS_FMT( "Min delta pressure [{}]", units::getSymbol( units::Unit::Pressure ))), + TableLayout::Column().setName( GEOS_FMT( "Max delta pressure [{}]", units::getSymbol( units::Unit::Pressure ))), + TableLayout::Column().setName( GEOS_FMT( "Min temperature [{}]", units::getSymbol( units::Unit::Temperature ) )), + TableLayout::Column().setName( GEOS_FMT( "Average temperature [{}]", units::getSymbol( units::Unit::Temperature ) )), + TableLayout::Column().setName( GEOS_FMT( "Max temperature [{}]", units::getSymbol( units::Unit::Temperature ) )), + TableLayout::Column().setName( GEOS_FMT( "Total dynamic pore volume [{}]", units::getSymbol( units::Unit::ReservoirVolume ) )), + } ); + addPhaseColumns( tableLayout, "Phase dynamic pore volume", units::getSymbol( units::Unit::ReservoirVolume ), numPhases ); addPhaseColumns( tableLayout, "Phase mass", massUnit, numPhases ); addPhaseColumns( tableLayout, "Trapped phase mass (metric 1)", massUnit, numPhases ); addPhaseColumns( tableLayout, "Non-trapped phase mass (metric 1)", massUnit, numPhases ); @@ -197,11 +200,14 @@ void StatsTask::prepareCsvTableLayouts( string_view meshName ) m_csvFormatters.emplace( meshName, std::move( csvFormatter ) ); // output CSV header - std::ofstream outputFile( GEOS_FMT( "{}/{}.csv", m_outputDir, meshName )); + std::ofstream outputFile( getCsvFileName( meshName ) ); outputFile << csvFormatter->headerToString(); GEOS_LOG( GEOS_FMT( "table {} : {}", meshName, csvFormatter->headerToString() ) ); // TODO : remove this log } +string StatsTask::getCsvFileName( string_view meshName ) const +{ return GEOS_FMT( "{}/{}.csv", m_outputDir, meshName ); } + bool StatsTask::execute( real64 const time_n, real64 const dt, integer const GEOS_UNUSED_PARAM( cycleNumber ), @@ -232,13 +238,16 @@ bool StatsTask::execute( real64 const time_n, void StatsTask::outputLogStats( real64 const statsTime, MeshLevel & mesh, - string_array const & regionNames ) + string_array const & ) { + if( MpiWrapper::commRank() > 0 || !isLogLevelActive< logInfo::Statistics >( this->getLogLevel() ) ) + return; + auto const formatterIter = m_logFormatters.find( mesh.getName() ); if( formatterIter==m_logFormatters.end()) return; - TableFormatter const & formatter = *formatterIter->second; + TableTextFormatter const & formatter = *formatterIter->second; TableData tableData; static constexpr auto merge = CellType::MergeNext; @@ -248,7 +257,7 @@ void StatsTask::outputLogStats( real64 const statsTime, string_view resVolUnit = units::getSymbol( units::ReservoirVolume ); tableData.addRow( "Statistics time", merge, merge, statsTime ); - m_aggregator.forRegionStatistics( MeshLevel & mesh, + m_aggregator.forRegionStatistics( mesh, [&]( string_view regionName, RegionStatistics const & stats ) { @@ -260,58 +269,107 @@ void StatsTask::outputLogStats( real64 const statsTime, tableData.addSeparator(); tableData.addRow( GEOS_FMT( "Pressure [{}]", pressureUnit ), - stats.minPressure, stats.averagePressure, stats.maxPressure ); + stats.m_minPressure, stats.m_averagePressure, stats.m_maxPressure ); tableData.addRow( GEOS_FMT( "Delta pressure [{}]", pressureUnit ), - stats.minDeltaPressure, "/", stats.maxDeltaPressure ); + stats.m_minDeltaPressure, "/", stats.m_maxDeltaPressure ); tableData.addRow( GEOS_FMT( "Temperature [{}]", tempUnit ), - stats.minTemperature, stats.averageTemperature, stats.maxTemperature ); + stats.m_minTemperature, stats.m_averageTemperature, stats.m_maxTemperature ); tableData.addSeparator(); - tableData.addRow( GEOS_FMT( "Total dynamic pore volume [{}]", resVolUnit ), CellType::MergeNext, CellType::MergeNext, stats.totalPoreVolume ); + tableData.addRow( GEOS_FMT( "Total dynamic pore volume [{}]", resVolUnit ), CellType::MergeNext, CellType::MergeNext, stats.m_totalPoreVolume ); tableData.addRow( GEOS_FMT( "Phase dynamic pore volume [{}]", resVolUnit ), stringutilities::joinLambda( m_fluid.m_phaseNames, "\n", []( auto data ) { return data[0]; } ), CellType::MergeNext, - stringutilities::joinLambda( stats.phasePoreVolume, "\n", []( auto data ) { return data[0]; } ) ); + stringutilities::joinLambda( stats.m_phasePoreVolume, "\n", []( auto data ) { return data[0]; } ) ); tableData.addSeparator(); tableData.addRow( GEOS_FMT( "Phase mass [{}]", massUnit ), stringutilities::joinLambda( m_fluid.m_phaseNames, "\n", []( auto data ) { return data[0]; } ), CellType::MergeNext, - stringutilities::joinLambda( stats.phaseMass, "\n", []( auto data ) { return data[0]; } ) ); + stringutilities::joinLambda( stats.m_phaseMass, "\n", []( auto data ) { return data[0]; } ) ); tableData.addSeparator(); tableData.addRow( GEOS_FMT( "Trapped phase mass (metric 1) [{}]", massUnit ), stringutilities::joinLambda( m_fluid.m_phaseNames, "\n", []( auto value ) { return value[0]; } ), CellType::MergeNext, - stringutilities::joinLambda( stats.trappedPhaseMass, "\n", []( auto value ) { return value[0]; } ) ); + stringutilities::joinLambda( stats.m_trappedPhaseMass, "\n", []( auto value ) { return value[0]; } ) ); tableData.addRow( GEOS_FMT( "Non-trapped phase mass (metric 1) [{}]", massUnit ), stringutilities::joinLambda( m_fluid.m_phaseNames, "\n", []( auto value ) { return value[0]; } ), CellType::MergeNext, - stringutilities::joinLambda( stats.nonTrappedPhaseMass, "\n", []( auto value ) { return value[0]; } ) ); + stringutilities::joinLambda( stats.m_nonTrappedPhaseMass, "\n", []( auto value ) { return value[0]; } ) ); tableData.addSeparator(); tableData.addRow( GEOS_FMT( "Immobile phase mass (metric 2) [{}]", massUnit ), stringutilities::joinLambda( m_fluid.m_phaseNames, "\n", []( auto value ) { return value[0]; } ), CellType::MergeNext, - stringutilities::joinLambda( stats.immobilePhaseMass, "\n", []( auto value ) { return value[0]; } ) ); + stringutilities::joinLambda( stats.m_immobilePhaseMass, "\n", []( auto value ) { return value[0]; } ) ); tableData.addRow( GEOS_FMT( "Mobile phase mass (metric 2) [{}]", massUnit ), stringutilities::joinLambda( m_fluid.m_phaseNames, "\n", []( auto value ) { return value[0]; } ), CellType::MergeNext, - stringutilities::joinLambda( stats.mobilePhaseMass, "\n", []( auto value ) { return value[0]; } ) ); + stringutilities::joinLambda( stats.m_mobilePhaseMass, "\n", []( auto value ) { return value[0]; } ) ); tableData.addSeparator(); tableData.addRow( GEOS_FMT( "Component mass [{}]", massUnit ), - stringutilities::join( m_fluid.m_phaseCompNames, '\n' ), + "TODO" /*stringutilities::join( m_fluid.m_phaseCompNames, '\n' )*/, CellType::MergeNext, - stringutilities::join( stats.componentMass, '\n' ) ); + stringutilities::join( stats.m_componentMass, '\n' ) ); tableData.addSeparator(); } ); + + GEOS_LOG_RANK_0( formatter.toString( tableData ) ); +} + +void StatsTask::outputCsvStats( real64 statsTime, + MeshLevel & mesh, + string_array const & ) +{ + if( MpiWrapper::commRank() > 0 || m_writeCSV == 0 ) + return; + + m_aggregator.forRegionStatistics( mesh, + [&]( string_view meshName, RegionStatistics const & stats ) + { + TableData tableData; + stdVector< string > row; + row.reserve( m_csvFormatters.at( string( meshName ))->getLayout().getTotalLowermostColumnCount() ); + + auto addPhaseValues = []( auto & list, auto const & values ) + { + for( auto value : values ) + list.emplace_back( std::to_string( value ) ); + }; + + row.insert( row.begin(), + { std::to_string( statsTime ), + std::to_string( stats.m_minPressure ), + std::to_string( stats.m_averagePressure ), + std::to_string( stats.m_maxPressure ), + std::to_string( stats.m_minDeltaPressure ), + std::to_string( stats.m_maxDeltaPressure ), + std::to_string( stats.m_minTemperature ), + std::to_string( stats.m_averageTemperature ), + std::to_string( stats.m_maxTemperature ), + std::to_string( stats.m_totalPoreVolume ), + } ); + addPhaseValues( row, stats.m_phasePoreVolume ); + addPhaseValues( row, stats.m_phaseMass ); + addPhaseValues( row, stats.m_trappedPhaseMass ); + addPhaseValues( row, stats.m_nonTrappedPhaseMass ); + addPhaseValues( row, stats.m_immobilePhaseMass ); + addPhaseValues( row, stats.m_mobilePhaseMass ); + addPhaseValues( row, stats.m_componentMass ); // TODO verify phase / comp ordering + + std::ofstream outputFile( getCsvFileName( mesh.getName() ), std::ios_base::app ); + TableCSVFormatter const csvOutput; + outputFile << csvOutput.dataToString( tableData ); + outputFile.close(); + } ); } REGISTER_CATALOG_ENTRY( TaskBase, diff --git a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsTask.hpp b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsTask.hpp index 78fb07eac3e..81be4446537 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsTask.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsTask.hpp @@ -14,7 +14,7 @@ */ /** - * @file CompositionalMultiphaseStatistics.hpp + * @file CompositionalMultiphaseStatisticsTask.hpp */ #ifndef SRC_CORECOMPONENTS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONALMULTIPHASESTATISTICSTASK_HPP_ @@ -97,6 +97,8 @@ class StatsTask : public FieldStatisticsBase< CompositionalMultiphaseBase > void prepareCsvTableLayouts( string_view tableName ); + string getCsvFileName( string_view meshName ) const; + void outputLogStats( real64 statsTime, MeshLevel & mesh, string_array const & regionNames ); @@ -106,10 +108,10 @@ class StatsTask : public FieldStatisticsBase< CompositionalMultiphaseBase > string_array const & regionNames ); /// For each discretization (MeshLevel name), table formatter for log output. - stdMap< string, std::unique_ptr< TableFormatter > > m_logFormatters; + stdMap< string, std::unique_ptr< TableTextFormatter > > m_logFormatters; /// For each discretization (MeshLevel name), table formatter for csv output. - stdMap< string, std::unique_ptr< TableFormatter > > m_csvFormatters; + stdMap< string, std::unique_ptr< TableCSVFormatter > > m_csvFormatters; StatsAggregator m_aggregator; diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp index 28def34e770..befc8a11e1f 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp @@ -48,7 +48,7 @@ #include "physicsSolvers/fluidFlow/kernels/compositional/PhaseVolumeFractionKernel.hpp" #include "physicsSolvers/fluidFlow/kernels/compositional/ThermalPhaseVolumeFractionKernel.hpp" #include "physicsSolvers/fluidFlow/kernels/compositional/FluidUpdateKernel.hpp" -#include "physicsSolvers/fluidFlow/CompositionalMultiphaseStatistics.hpp" +#include "physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsAggregator.hpp" #if defined( __INTEL_COMPILER ) #pragma GCC optimize "O0" @@ -729,21 +729,22 @@ void CompositionalMultiphaseWell::updateVolRatesForConstraint( ElementRegionMana } else { - if( !wellControls.referenceReservoirRegion().empty() ) - { - ElementRegionBase const & region = elemManager.getRegion( wellControls.referenceReservoirRegion()); - GEOS_ERROR_IF ( !region.hasWrapper( CompositionalMultiphaseStatistics::regionStatisticsName() ), - GEOS_FMT( "{}: WellControl {} referenceReservoirRegion field requires CompositionalMultiphaseStatistics to be configured for region {} ", - getDataContext(), wellControls.getName(), wellControls.referenceReservoirRegion() ) ); - - CompositionalMultiphaseStatistics::RegionStatistics const & stats = region.getReference< CompositionalMultiphaseStatistics::RegionStatistics >( - CompositionalMultiphaseStatistics::regionStatisticsName() ); - wellControls.setRegionAveragePressure( stats.averagePressure ); - wellControls.setRegionAverageTemperature( stats.averageTemperature ); - GEOS_ERROR_IF( stats.averagePressure <= 0.0, - GEOS_FMT( "{}: No region average quantities computed. WellControl {} referenceReservoirRegion field requires CompositionalMultiphaseStatistics to be configured for region {} ", - getDataContext(), wellControls.getName(), wellControls.referenceReservoirRegion() )); - } + GEOS_UNUSED_VAR(elemManager); + // if( !wellControls.referenceReservoirRegion().empty() ) + // { + // ElementRegionBase const & region = elemManager.getRegion( wellControls.referenceReservoirRegion()); + // GEOS_ERROR_IF ( !region.hasWrapper( CompositionalMultiphaseStatistics::regionStatisticsName() ), + // GEOS_FMT( "{}: WellControl {} referenceReservoirRegion field requires CompositionalMultiphaseStatistics to be configured for region {} ", + // getDataContext(), wellControls.getName(), wellControls.referenceReservoirRegion() ) ); + + // CompositionalMultiphaseStatistics::RegionStatistics const & stats = region.getReference< CompositionalMultiphaseStatistics::RegionStatistics >( + // CompositionalMultiphaseStatistics::regionStatisticsName() ); + // wellControls.setRegionAveragePressure( stats.averagePressure ); + // wellControls.setRegionAverageTemperature( stats.averageTemperature ); + // GEOS_ERROR_IF( stats.averagePressure <= 0.0, + // GEOS_FMT( "{}: No region average quantities computed. WellControl {} referenceReservoirRegion field requires CompositionalMultiphaseStatistics to be configured for region {} ", + // getDataContext(), wellControls.getName(), wellControls.referenceReservoirRegion() )); + // } // If flashPressure is not set by region the value is defaulted to -1 and indicates to use top segment conditions flashPressure = wellControls.getRegionAveragePressure(); if( flashPressure < 0.0 ) From 15369ed8ebc87287305498996e86eee623cded5a Mon Sep 17 00:00:00 2001 From: MelReyCG Date: Tue, 9 Dec 2025 17:36:00 +0100 Subject: [PATCH 08/28] =?UTF-8?q?=F0=9F=90=9B=20map=20alloc=20bugfix?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../CompositionalMultiphaseStatisticsTask.cpp | 28 ++++++++++--------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsTask.cpp b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsTask.cpp index 0f5aea1d1b9..f49a4ef4c33 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsTask.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsTask.cpp @@ -98,6 +98,8 @@ void StatsTask::registerDataOnMesh( Group & meshBodies ) return; } + getGroupByPath( "/" ).printDataHierarchy(); + prepareFluidMetaData(); if( m_computeRegionStatistics ) @@ -176,17 +178,17 @@ void StatsTask::prepareCsvTableLayouts( string_view meshName ) string_view massUnit = units::getSymbol( m_solver->getMassUnit() ); TableLayout tableLayout( { - TableLayout::Column().setName( GEOS_FMT( "Time [{}]", units::getSymbol( units::Unit::Time ))), - TableLayout::Column().setName( "Region" ), // TODO : mention this change in PR description - TableLayout::Column().setName( GEOS_FMT( "Min pressure [{}]", units::getSymbol( units::Unit::Pressure ))), - TableLayout::Column().setName( GEOS_FMT( "Average pressure [{}]", units::getSymbol( units::Unit::Pressure )) ), - TableLayout::Column().setName( GEOS_FMT( "Max pressure [{}]", units::getSymbol( units::Unit::Pressure ) ) ), - TableLayout::Column().setName( GEOS_FMT( "Min delta pressure [{}]", units::getSymbol( units::Unit::Pressure ))), - TableLayout::Column().setName( GEOS_FMT( "Max delta pressure [{}]", units::getSymbol( units::Unit::Pressure ))), - TableLayout::Column().setName( GEOS_FMT( "Min temperature [{}]", units::getSymbol( units::Unit::Temperature ) )), - TableLayout::Column().setName( GEOS_FMT( "Average temperature [{}]", units::getSymbol( units::Unit::Temperature ) )), - TableLayout::Column().setName( GEOS_FMT( "Max temperature [{}]", units::getSymbol( units::Unit::Temperature ) )), - TableLayout::Column().setName( GEOS_FMT( "Total dynamic pore volume [{}]", units::getSymbol( units::Unit::ReservoirVolume ) )), + TableLayout::Column( GEOS_FMT( "Time [{}]", units::getSymbol( units::Unit::Time ))), + TableLayout::Column( "Region" ), // TODO : mention this change in PR description + TableLayout::Column( GEOS_FMT( "Min pressure [{}]", units::getSymbol( units::Unit::Pressure ))), + TableLayout::Column( GEOS_FMT( "Average pressure [{}]", units::getSymbol( units::Unit::Pressure )) ), + TableLayout::Column( GEOS_FMT( "Max pressure [{}]", units::getSymbol( units::Unit::Pressure ) ) ), + TableLayout::Column( GEOS_FMT( "Min delta pressure [{}]", units::getSymbol( units::Unit::Pressure ))), + TableLayout::Column( GEOS_FMT( "Max delta pressure [{}]", units::getSymbol( units::Unit::Pressure ))), + TableLayout::Column( GEOS_FMT( "Min temperature [{}]", units::getSymbol( units::Unit::Temperature ) )), + TableLayout::Column( GEOS_FMT( "Average temperature [{}]", units::getSymbol( units::Unit::Temperature ) )), + TableLayout::Column( GEOS_FMT( "Max temperature [{}]", units::getSymbol( units::Unit::Temperature ) )), + TableLayout::Column( GEOS_FMT( "Total dynamic pore volume [{}]", units::getSymbol( units::Unit::ReservoirVolume ) )), } ); addPhaseColumns( tableLayout, "Phase dynamic pore volume", units::getSymbol( units::Unit::ReservoirVolume ), numPhases ); addPhaseColumns( tableLayout, "Phase mass", massUnit, numPhases ); @@ -196,8 +198,8 @@ void StatsTask::prepareCsvTableLayouts( string_view meshName ) addPhaseColumns( tableLayout, "Mobile phase mass (metric 2)", massUnit, numPhases ); addPhaseCompColumns( tableLayout, "Component mass", massUnit, numPhases, numComps ); - auto csvFormatter = std::make_unique< TableCSVFormatter >( tableLayout ); - m_csvFormatters.emplace( meshName, std::move( csvFormatter ) ); + auto & csvFormatter = m_csvFormatters.get_inserted( string( meshName ) ); + csvFormatter = std::move( std::make_unique< TableCSVFormatter >( tableLayout ) ); // output CSV header std::ofstream outputFile( getCsvFileName( meshName ) ); From f5affb506a4363f2f6c3b5d4adc03d095ff61e27 Mon Sep 17 00:00:00 2001 From: MelReyCG Date: Mon, 5 Jan 2026 16:01:47 +0100 Subject: [PATCH 09/28] =?UTF-8?q?=F0=9F=9A=A7different=20data=20structures?= =?UTF-8?q?=20plan?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...sitionalMultiphaseStatisticsAggregator.cpp | 156 ++++++++++++++++++ 1 file changed, 156 insertions(+) diff --git a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsAggregator.cpp b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsAggregator.cpp index c2a923a4b0f..0600391cea9 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsAggregator.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsAggregator.cpp @@ -15,6 +15,162 @@ /** * @file CompositionalMultiphaseStatistics.cpp + * @details Region statistics data is stored as follow: + * + * Problem : geos::ProblemManager + * |-> domain : geos::DomainPartition + * |-> MeshBodies : geos::dataRepository::Group + * |-> cartesianMesh : geos::MeshBody + * |-> meshLevels : geos::dataRepository::Group + * |-> Level0 : geos::MeshLevel + * | |-> nodeManager : geos::NodeManager + * | | |-> sets : geos::dataRepository::Group + * | | | * all : geos::dataRepository::Wrapper< index array > + * | | | * xneg : geos::dataRepository::Wrapper< index array > + * | | [...] (other element sets) + * | | + * | |-> ElementRegions : geos::ElementRegionManager + * | | |-> Channel : geos::CellElementRegion + * | | | |-> cb-0_0_0 : geos::CellElementSubRegion + * | | | | | * pressure : geos::dataRepository::Wrapper< real64 array > + * | | | | | * temperature : geos::dataRepository::Wrapper< real64 array > + * | | | | [...] (other fields) + * | | | | + * | | | |-> cb-0_0_1 : geos::CellElementSubRegion + * | | | | | * pressure : geos::dataRepository::Wrapper< real64 array > + * | | | | | * temperature : geos::dataRepository::Wrapper< real64 array > + * | | | | [...] (other fields) + * | | | | + * | | | [...] (other sub-regions) + * | | | + * | | |-> Barrier : geos::CellElementRegion + * | | |-> cb-1_0_0 : geos::CellElementSubRegion + * | | |-> cb-1_0_1 : geos::CellElementSubRegion + * | | [...] (other sub-regions) + * | | + * | [...] (other element managers) + * ____ | | + * | | |-> statistics : geos::dataRepository::Group (storage for all stats) + * | | |-> compFlowStats : geos::dataRepository::Group (storage for this instance stats) + * | | | |-> cflStatistics : geos::compositionalMultiphaseStatistics::CFLStatistics + * | | | |-> regionsStats : geos::compositionalMultiphaseStatistics::RegionStatistics (aggregate) + * | | | |-> Channel : geos::compositionalMultiphaseStatistics::RegionStatistics (aggregate, mpi reduced) + * | | | | |-> cb-0_0_0 : geos::compositionalMultiphaseStatistics::RegionStatistics (compute read-back) + * stats | | | | |-> cb-0_0_1 : geos::compositionalMultiphaseStatistics::RegionStatistics (compute read-back) + * data -> | | | | [...] (other sub-regions stats) + * | | | | + * | | | |-> Barrier : geos::compositionalMultiphaseStatistics::RegionStatistics (aggregate, mpi reduced) + * | | | |-> cb-1_0_0 : geos::compositionalMultiphaseStatistics::RegionStatistics (compute read-back) + * | | | |-> cb-1_0_1 : geos::compositionalMultiphaseStatistics::RegionStatistics (compute read-back) + * | | | [...] (other sub-regions stats) + * | | | + * |___ | [...] (other stats storages) + * | + * [...] (other discretizations) + * + * not feasible because having a StatTask is not mandatory + * Problem : geos::ProblemManager + * |-> domain : geos::DomainPartition + * | |-> MeshBodies : geos::dataRepository::Group + * | |-> cartesianMesh : geos::MeshBody + * | |-> meshLevels : geos::dataRepository::Group + * | |-> Level0 : geos::MeshLevel + * | | |-> nodeManager : geos::NodeManager + * | | | |-> sets : geos::dataRepository::Group + * | | | |-> all : geos::dataRepository::Wrapper< index array > + * | | | |-> xneg : geos::dataRepository::Wrapper< index array > + * | | | [...] (other element sets) + * | | | + * | | |-> ElementRegions : geos::ElementRegionManager + * | | | |-> Channel : geos::CellElementRegion + * | | | | |-> cb-0_0_0 : geos::CellElementSubRegion + * | | | | | |-> pressure : geos::dataRepository::Wrapper< real64 array > + * | | | | | |-> temperature : geos::dataRepository::Wrapper< real64 array > + * | | | | | [...] (other fields) + * | | | | | + * | | | | |-> cb-0_0_1 : geos::CellElementSubRegion + * | | | | | |-> pressure : geos::dataRepository::Wrapper< real64 array > + * | | | | | |-> temperature : geos::dataRepository::Wrapper< real64 array > + * | | | | | [...] (other fields) + * | | | | | + * | | | | [...] (other sub-regions) + * | | | | + * | | | |-> Barrier : geos::CellElementRegion + * | | | |-> cb-1_0_0 : geos::CellElementSubRegion + * | | | |-> cb-1_0_1 : geos::CellElementSubRegion + * | | | [...] (other sub-regions) + * | | | + * | | [...] (other element managers) + * | | + * | [...] (other discretizations) + * | + * |-> Tasks : geos::TaskManager + * |-> compFlowStats : geos::dataRepository::compositionalMultiphaseStatistics::StatTask (storage for this instance stats) + * |-> cartesianMesh : geos::dataRepository::Group + * |-> Level0 : geos::dataRepository::Group + * ____ |-> cartesianMesh_Level0 : geos::dataRepository::Group (storage for all stats) + * | | | |-> cflStatistics : geos::compositionalMultiphaseStatistics::CFLStatistics + * | | | |-> regionsStats : geos::compositionalMultiphaseStatistics::RegionStatistics (aggregate) + * | | | |-> Channel : geos::compositionalMultiphaseStatistics::RegionStatistics (aggregate, mpi reduced) + * | | | | |-> cb-0_0_0 : geos::compositionalMultiphaseStatistics::RegionStatistics (compute read-back) + * stats | | | | |-> cb-0_0_1 : geos::compositionalMultiphaseStatistics::RegionStatistics (compute read-back) + * data -> | | | | ... (other sub-regions stats) + * | | | | + * | | | |-> Barrier : geos::compositionalMultiphaseStatistics::RegionStatistics (aggregate, mpi reduced) + * | | | |-> cb-1_0_0 : geos::compositionalMultiphaseStatistics::RegionStatistics (compute read-back) + * | | | |-> cb-1_0_1 : geos::compositionalMultiphaseStatistics::RegionStatistics (compute read-back) + * | | | ... (other sub-regions stats) + * | | | + * |___ | ... (other stats storages) + * | + * ... (other discretizations) + * + * Stats data structures are much more scattered + the "statistics" Group is still needed + * Problem : geos::ProblemManager + * |-> domain : geos::DomainPartition + * |-> MeshBodies : geos::dataRepository::Group + * |-> cartesianMesh : geos::MeshBody + * |-> meshLevels : geos::dataRepository::Group + * |-> Level0 : geos::MeshLevel + * | |-> nodeManager : geos::NodeManager + * | | |-> sets : geos::dataRepository::Group + * | | | * all : geos::dataRepository::Wrapper< index array > + * | | | * xneg : geos::dataRepository::Wrapper< index array > + * | | ... (other element sets) + * | | + * | |-> other element managers... + * | | + * | |-> ElementRegions : geos::ElementRegionManager + * | |-> Channel : geos::CellElementRegion + * | | |-> cb-0_0_0 : geos::CellElementSubRegion + * | | | | * pressure : geos::dataRepository::Wrapper< real64 array > + * | | | | * temperature : geos::dataRepository::Wrapper< real64 array > + * | | | | [...] (other fields) + * | | | |-> compFlowStats : geos::compositionalMultiphaseStatistics::RegionStatistics (compute read-back) + * | | | + * | | |-> cb-0_0_1 : geos::CellElementSubRegion + * | | | | * pressure : geos::dataRepository::Wrapper< real64 array > + * | | | | * temperature : geos::dataRepository::Wrapper< real64 array > + * | | | | [...] (other fields) + * | | | |-> compFlowStats : geos::compositionalMultiphaseStatistics::RegionStatistics (compute read-back) + * | | | + * | | [...] (other sub-regions) + * | | | + * | | |-> compFlowStats : geos::compositionalMultiphaseStatistics::RegionStatistics (aggregate, mpi reduced) + * | | + * | |-> Barrier : geos::CellElementRegion + * | | |-> cb-1_0_0 : geos::CellElementSubRegion + * | | |-> cb-1_0_1 : geos::CellElementSubRegion + * | | [...] (other sub-regions) + * | | + * | [...] (other regions) + * | | + * | | |-> statistics : geos::dataRepository::Group (storage for all stats) + * | |-> compFlowStats : geos::dataRepository::Group (storage for this instance stats) + * | |-> regionsStats : geos::compositionalMultiphaseStatistics::RegionStatistics (aggregate) + * | |-> cflStatistics : geos::compositionalMultiphaseStatistics::CFLStatistics + * | + * ... (other discretizations) */ #include "CompositionalMultiphaseStatisticsAggregator.hpp" From c2574457a518f42cf3e5687b4ae043bb442db89e Mon Sep 17 00:00:00 2001 From: MelReyCG Date: Mon, 5 Jan 2026 16:02:28 +0100 Subject: [PATCH 10/28] =?UTF-8?q?=F0=9F=9A=A7choosing=20the=20plan=20that?= =?UTF-8?q?=20seem=20like=20the=20best=20one?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...sitionalMultiphaseStatisticsAggregator.cpp | 103 ------------------ 1 file changed, 103 deletions(-) diff --git a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsAggregator.cpp b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsAggregator.cpp index 0600391cea9..002bdb9dd96 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsAggregator.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsAggregator.cpp @@ -68,109 +68,6 @@ * | * [...] (other discretizations) * - * not feasible because having a StatTask is not mandatory - * Problem : geos::ProblemManager - * |-> domain : geos::DomainPartition - * | |-> MeshBodies : geos::dataRepository::Group - * | |-> cartesianMesh : geos::MeshBody - * | |-> meshLevels : geos::dataRepository::Group - * | |-> Level0 : geos::MeshLevel - * | | |-> nodeManager : geos::NodeManager - * | | | |-> sets : geos::dataRepository::Group - * | | | |-> all : geos::dataRepository::Wrapper< index array > - * | | | |-> xneg : geos::dataRepository::Wrapper< index array > - * | | | [...] (other element sets) - * | | | - * | | |-> ElementRegions : geos::ElementRegionManager - * | | | |-> Channel : geos::CellElementRegion - * | | | | |-> cb-0_0_0 : geos::CellElementSubRegion - * | | | | | |-> pressure : geos::dataRepository::Wrapper< real64 array > - * | | | | | |-> temperature : geos::dataRepository::Wrapper< real64 array > - * | | | | | [...] (other fields) - * | | | | | - * | | | | |-> cb-0_0_1 : geos::CellElementSubRegion - * | | | | | |-> pressure : geos::dataRepository::Wrapper< real64 array > - * | | | | | |-> temperature : geos::dataRepository::Wrapper< real64 array > - * | | | | | [...] (other fields) - * | | | | | - * | | | | [...] (other sub-regions) - * | | | | - * | | | |-> Barrier : geos::CellElementRegion - * | | | |-> cb-1_0_0 : geos::CellElementSubRegion - * | | | |-> cb-1_0_1 : geos::CellElementSubRegion - * | | | [...] (other sub-regions) - * | | | - * | | [...] (other element managers) - * | | - * | [...] (other discretizations) - * | - * |-> Tasks : geos::TaskManager - * |-> compFlowStats : geos::dataRepository::compositionalMultiphaseStatistics::StatTask (storage for this instance stats) - * |-> cartesianMesh : geos::dataRepository::Group - * |-> Level0 : geos::dataRepository::Group - * ____ |-> cartesianMesh_Level0 : geos::dataRepository::Group (storage for all stats) - * | | | |-> cflStatistics : geos::compositionalMultiphaseStatistics::CFLStatistics - * | | | |-> regionsStats : geos::compositionalMultiphaseStatistics::RegionStatistics (aggregate) - * | | | |-> Channel : geos::compositionalMultiphaseStatistics::RegionStatistics (aggregate, mpi reduced) - * | | | | |-> cb-0_0_0 : geos::compositionalMultiphaseStatistics::RegionStatistics (compute read-back) - * stats | | | | |-> cb-0_0_1 : geos::compositionalMultiphaseStatistics::RegionStatistics (compute read-back) - * data -> | | | | ... (other sub-regions stats) - * | | | | - * | | | |-> Barrier : geos::compositionalMultiphaseStatistics::RegionStatistics (aggregate, mpi reduced) - * | | | |-> cb-1_0_0 : geos::compositionalMultiphaseStatistics::RegionStatistics (compute read-back) - * | | | |-> cb-1_0_1 : geos::compositionalMultiphaseStatistics::RegionStatistics (compute read-back) - * | | | ... (other sub-regions stats) - * | | | - * |___ | ... (other stats storages) - * | - * ... (other discretizations) - * - * Stats data structures are much more scattered + the "statistics" Group is still needed - * Problem : geos::ProblemManager - * |-> domain : geos::DomainPartition - * |-> MeshBodies : geos::dataRepository::Group - * |-> cartesianMesh : geos::MeshBody - * |-> meshLevels : geos::dataRepository::Group - * |-> Level0 : geos::MeshLevel - * | |-> nodeManager : geos::NodeManager - * | | |-> sets : geos::dataRepository::Group - * | | | * all : geos::dataRepository::Wrapper< index array > - * | | | * xneg : geos::dataRepository::Wrapper< index array > - * | | ... (other element sets) - * | | - * | |-> other element managers... - * | | - * | |-> ElementRegions : geos::ElementRegionManager - * | |-> Channel : geos::CellElementRegion - * | | |-> cb-0_0_0 : geos::CellElementSubRegion - * | | | | * pressure : geos::dataRepository::Wrapper< real64 array > - * | | | | * temperature : geos::dataRepository::Wrapper< real64 array > - * | | | | [...] (other fields) - * | | | |-> compFlowStats : geos::compositionalMultiphaseStatistics::RegionStatistics (compute read-back) - * | | | - * | | |-> cb-0_0_1 : geos::CellElementSubRegion - * | | | | * pressure : geos::dataRepository::Wrapper< real64 array > - * | | | | * temperature : geos::dataRepository::Wrapper< real64 array > - * | | | | [...] (other fields) - * | | | |-> compFlowStats : geos::compositionalMultiphaseStatistics::RegionStatistics (compute read-back) - * | | | - * | | [...] (other sub-regions) - * | | | - * | | |-> compFlowStats : geos::compositionalMultiphaseStatistics::RegionStatistics (aggregate, mpi reduced) - * | | - * | |-> Barrier : geos::CellElementRegion - * | | |-> cb-1_0_0 : geos::CellElementSubRegion - * | | |-> cb-1_0_1 : geos::CellElementSubRegion - * | | [...] (other sub-regions) - * | | - * | [...] (other regions) - * | | - * | | |-> statistics : geos::dataRepository::Group (storage for all stats) - * | |-> compFlowStats : geos::dataRepository::Group (storage for this instance stats) - * | |-> regionsStats : geos::compositionalMultiphaseStatistics::RegionStatistics (aggregate) - * | |-> cflStatistics : geos::compositionalMultiphaseStatistics::CFLStatistics - * | - * ... (other discretizations) */ #include "CompositionalMultiphaseStatisticsAggregator.hpp" From 856a6c71c4be748ee1a758bba56ae35a6b8f6478 Mon Sep 17 00:00:00 2001 From: MelReyCG Date: Wed, 7 Jan 2026 15:48:22 +0100 Subject: [PATCH 11/28] =?UTF-8?q?=E2=99=BB=EF=B8=8Fmoved=20stat=20so=20eac?= =?UTF-8?q?h=20aggregator=20has=20its=20own=20data=20in=20the=20data=20rep?= =?UTF-8?q?ository=20+=20refactored=20aggregating=20functions?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...sitionalMultiphaseStatisticsAggregator.cpp | 628 +++++++++++------- ...sitionalMultiphaseStatisticsAggregator.hpp | 180 +++-- 2 files changed, 518 insertions(+), 290 deletions(-) diff --git a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsAggregator.cpp b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsAggregator.cpp index 002bdb9dd96..f049144ebdb 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsAggregator.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsAggregator.cpp @@ -53,7 +53,7 @@ * | | |-> statistics : geos::dataRepository::Group (storage for all stats) * | | |-> compFlowStats : geos::dataRepository::Group (storage for this instance stats) * | | | |-> cflStatistics : geos::compositionalMultiphaseStatistics::CFLStatistics - * | | | |-> regionsStats : geos::compositionalMultiphaseStatistics::RegionStatistics (aggregate) + * | | | |-> regionsStatistics : geos::compositionalMultiphaseStatistics::RegionStatistics (aggregate) * | | | |-> Channel : geos::compositionalMultiphaseStatistics::RegionStatistics (aggregate, mpi reduced) * | | | | |-> cb-0_0_0 : geos::compositionalMultiphaseStatistics::RegionStatistics (compute read-back) * stats | | | | |-> cb-0_0_1 : geos::compositionalMultiphaseStatistics::RegionStatistics (compute read-back) @@ -72,13 +72,20 @@ #include "CompositionalMultiphaseStatisticsAggregator.hpp" +#include "LvArray/src/math.hpp" #include "common/DataTypes.hpp" #include "common/format/Format.hpp" #include "common/logger/Logger.hpp" +#include "dataRepository/Group.hpp" +#include "mesh/CellElementRegion.hpp" +#include "mesh/CellElementSubRegion.hpp" +#include "mesh/ElementRegionManager.hpp" +#include "mesh/MeshLevel.hpp" #include "physicsSolvers/fluidFlow/CompositionalMultiphaseBase.hpp" #include "physicsSolvers/fluidFlow/kernels/compositional/StatisticsKernel.hpp" #include "physicsSolvers/LogLevelsInfo.hpp" #include "constitutive/relativePermeability/RelativePermeabilityBase.hpp" +#include #include @@ -92,301 +99,407 @@ using namespace constitutive; // using namespace fields; using namespace dataRepository; -StatsAggregator::StatsAggregator(): +StatsAggregator::StatsAggregator( string_view ownerName ): m_params(), - m_isRegionStatsEnabled( false ), - m_isCFLNumberEnabled( false ) + m_ownerName( ownerName ) {} -void StatsAggregator::enableRegionStatistics( dataRepository::Group & /*meshBodies*/ ) +void StatsAggregator::initStatisticsAggregation( dataRepository::Group & meshBodies, + CompositionalMultiphaseBase & solver ) { - GEOS_ERROR_IF_EQ_MSG( m_solver, nullptr, "Flow solver must be set." ); + m_solver = &solver; - // integer const numPhases = m_solver->numFluidPhases(); - // integer const numComps = m_solver->numFluidComponents(); + m_numPhases = m_solver->numFluidPhases(); + m_numComponents = m_solver->numFluidComponents(); - // m_solver->forDiscretizationOnMeshTargets( meshBodies, [&] ( string const &, - // MeshLevel & mesh, - // string_array const & regionNames ) - // { - // ElementRegionManager & elemManager = mesh.getElemManager(); - - // for( size_t i = 0; i < regionNames.size(); ++i ) - // { - // // ElementRegionBase & region = elemManager.getRegion( regionNames[i] ); - - // // RELOCALISER LES DONNEES region.registerWrapper< RegionStatistics >( VKStruct::regionStatisticsString() ). - // // setRestartFlags( RestartFlags::NO_WRITE ); - // // region.excludeWrappersFromPacking( { VKStruct::regionStatisticsString() } ); - // // RegionStatistics & stats = region.getReference< RegionStatistics >( VKStruct::regionStatisticsString() ); - - // // stats.m_phasePoreVolume.resizeDimension< 0 >( numPhases ); - // // stats.m_phaseMass.resizeDimension< 0 >( numPhases ); - // // stats.m_trappedPhaseMass.resizeDimension< 0 >( numPhases ); - // // stats.m_nonTrappedPhaseMass.resizeDimension< 0 >( numPhases ); - // // stats.m_immobilePhaseMass.resizeDimension< 0 >( numPhases ); - // // stats.m_mobilePhaseMass.resizeDimension< 0 >( numPhases ); - // // stats.m_componentMass.resizeDimension< 0, 1 >( numPhases, numComps ); - // } - // } ); - // m_isRegionStatsEnabled = true; + m_solver->forDiscretizationOnMeshTargets( meshBodies, [&] ( string const &, + MeshLevel & mesh, + string_array const & ) + { + // getting the container of all requesters statistics groups (can be already initialized) + Group * allStatisticsGroup = mesh.getGroupPointer( ViewKeys::statisticsString() ); + if( allStatisticsGroup == nullptr ) + allStatisticsGroup = &mesh.registerGroup( ViewKeys::statisticsString() ); + + // registering the container of instance statistics groups (must be unique for this instance) + GEOS_ERROR_IF_NE_MSG( allStatisticsGroup->hasGroup( m_ownerName ), false, + GEOS_FMT( "A statistics aggregator have already been requested for '{}'.", + m_ownerName ) ); + allStatisticsGroup->registerGroup( m_ownerName ); + } ); } -void StatsAggregator::forRegionStatistics( MeshLevel const & mesh, - StatsAggregator::RegionFunctor functor ) const +void StatsAggregator::enableRegionStatisticsAggregation( dataRepository::Group & meshBodies ) { - GEOS_UNUSED_VAR( mesh ); - GEOS_UNUSED_VAR( functor ); + if( m_solver == nullptr ) + return; + + + auto const registerStats = [=] ( Group & parent, + string const & name, + string const & targetName ) -> RegionStatistics & + { + return parent.registerGroup( name, std::make_unique< RegionStatistics >( name, &parent, + targetName, + m_numPhases, + m_numComponents ) ); + }; + + m_solver->forDiscretizationOnMeshTargets( meshBodies, [&] ( string const &, + MeshLevel & mesh, + string_array const & regionNames ) + { + ElementRegionManager & elemManager = mesh.getElemManager(); + Group & statisticsGroup = getInstanceStatisticsGroup( mesh ); + RegionStatistics & allRegionsStats = registerStats( statisticsGroup, + ViewKeys::regionsStatisticsString(), + mesh.getName() ); + + for( size_t i = 0; i < regionNames.size(); ++i ) + { + CellElementRegion & region = elemManager.getRegion< CellElementRegion >( regionNames[i] ); + RegionStatistics & regionStats = registerStats( allRegionsStats, + GEOS_FMT( "{}_region_stats", region.getName() ), + region.getName() ); + + region.forElementSubRegions( [&] ( CellElementSubRegion & subRegion ) + { + registerStats( regionStats, + GEOS_FMT( "{}_subRegion_stats", subRegion.getName() ), + subRegion.getName() ); + } ); + } + } ); + + m_isRegionStatsEnabled = true; } void StatsAggregator::enableCFLStatistics( dataRepository::Group & meshBodies ) { - GEOS_ERROR_IF_EQ_MSG( m_solver, nullptr, "Flow solver must be set." ); + if( m_solver == nullptr ) + return; m_solver->registerDataForCFL( meshBodies ); + m_solver->forDiscretizationOnMeshTargets( meshBodies, [&] ( string const &, + MeshLevel & mesh, + string_array const & regionNames ) + { + Group & statisticsGroup = getInstanceStatisticsGroup( mesh ); + statisticsGroup.registerGroup< CFLStatistics >( ViewKeys::cflStatisticsString() ); + } ); + m_isCFLNumberEnabled = true; } +Group & StatsAggregator::getInstanceStatisticsGroup( MeshLevel & mesh ) const +{ + // considering everything is initialized, or else, crash gracefully + Group & allStatisticsGroup = mesh.getGroup( ViewKeys::statisticsString() ); + Group & instanceStatisticsGroup = allStatisticsGroup.getGroup( m_ownerName ); + return instanceStatisticsGroup; +} + +RegionStatistics & StatsAggregator::getRegionsStatisticsGroup( MeshLevel & mesh ) const +{ + // considering everything is initialized, or else, crash gracefully + Group & instanceStatisticsGroup = getInstanceStatisticsGroup( mesh ); + return instanceStatisticsGroup.getGroup< RegionStatistics >( ViewKeys::regionsStatisticsString() ); +} + +CFLStatistics & StatsAggregator::getCflStatisticsGroup( MeshLevel & mesh ) const +{ + // considering everything is initialized, or else, crash gracefully + Group & instanceStatisticsGroup = getInstanceStatisticsGroup( mesh ); + return instanceStatisticsGroup.getGroup< CFLStatistics >( ViewKeys::cflStatisticsString() ); +} + +void StatsAggregator::forRegionStatistics( dataRepository::Group & meshBodies, + RegionStatisticsFunctor< MeshLevel > const & func ) const +{ + m_solver->forDiscretizationOnMeshTargets( meshBodies, [&] ( string const &, + MeshLevel & mesh, + string_array const & ) + { + Group & instanceStats = getInstanceStatisticsGroup( mesh ); + RegionStatistics & allRegionsStats = getRegionsStatisticsGroup( mesh ); + + func( mesh, allRegionsStats ); + } ); +} + +void StatsAggregator::forRegionStatistics( MeshLevel & mesh, + RegionStatistics & allRegionsStatistics, + RegionStatisticsFunctor< CellElementRegion > const & func ) const +{ + ElementRegionManager & elemManager = mesh.getElemManager(); + allRegionsStatistics.forSubGroups< RegionStatistics >( [&] ( RegionStatistics & regionStatistics ) + { + string_view targetName = regionStatistics.getTargetName(); + CellElementRegion & region = elemManager.getRegion< CellElementRegion >( targetName ); + + func( region, regionStatistics ); + } ); +} + +void StatsAggregator::forRegionStatistics( CellElementRegion & region, + RegionStatistics & regionStatistics, + RegionStatisticsFunctor< CellElementSubRegion > const & func ) const +{ + regionStatistics.forSubGroups< RegionStatistics >( [&] ( RegionStatistics & subRegionStatistics ) + { + string_view targetName = subRegionStatistics.getTargetName(); + CellElementSubRegion & subRegion = region.getSubRegion< CellElementSubRegion >( targetName ); + func( subRegion, subRegionStatistics ); + } ); +} + bool StatsAggregator::computeRegionsStatistics( real64 const time, MeshLevel & mesh, string_array const & regionNames ) { GEOS_MARK_FUNCTION; - integer const numPhases = m_solver->numFluidPhases(); - integer const numComps = m_solver->numFluidComponents(); - - // Step 1: initialize the average/min/max quantities ElementRegionManager & elemManager = mesh.getElemManager(); - for( size_t i = 0; i < regionNames.size(); ++i ) - { - ElementRegionBase & region = elemManager.getRegion( regionNames[i] ); - RegionStatistics & stats = region.getReference< RegionStatistics >( VKStruct::regionStatisticsString() ); + RegionStatistics & allRegionsStats = getRegionsStatisticsGroup( mesh ); - stats.m_time = time; + { // computation of sub region stats + forRegionStatistics( mesh, + allRegionsStats, + [&, time] ( CellElementRegion & region, RegionStatistics & regionStats ) + { + forRegionStatistics( region, + regionStats, + [&, time] ( CellElementSubRegion & subRegion, RegionStatistics & subRegionStats ) + { + initStats( subRegionStats, time ); + computeSubRegionRankStats( subRegion, subRegionStats ); + } ); + } ); + } - stats.m_averagePressure = 0.0; - stats.m_maxPressure = 0.0; - stats.m_minPressure = LvArray::NumericLimits< real64 >::max; + { // aggregation of computations from the sub regions + initStats( allRegionsStats, time ); - stats.m_maxDeltaPressure = -LvArray::NumericLimits< real64 >::max; - stats.m_minDeltaPressure = LvArray::NumericLimits< real64 >::max; + forRegionStatistics( mesh, + allRegionsStats, + [&, time] ( CellElementRegion & region, RegionStatistics & regionStats ) + { + initStats( regionStats, time ); - stats.m_averageTemperature = 0.0; - stats.m_maxTemperature = 0.0; - stats.m_minTemperature = LvArray::NumericLimits< real64 >::max; - - stats.m_totalPoreVolume = 0.0; - stats.m_totalUncompactedPoreVolume = 0.0; - stats.m_phasePoreVolume.setValues< serialPolicy >( 0.0 ); - - stats.m_phaseMass.setValues< serialPolicy >( 0.0 ); - stats.m_trappedPhaseMass.setValues< serialPolicy >( 0.0 ); - stats.m_nonTrappedPhaseMass.setValues< serialPolicy >( 0.0 ); - stats.m_immobilePhaseMass.setValues< serialPolicy >( 0.0 ); - stats.m_mobilePhaseMass.setValues< serialPolicy >( 0.0 ); - stats.m_componentMass.setValues< serialPolicy >( 0.0 ); + forRegionStatistics( region, + regionStats, + [&, time] ( CellElementSubRegion & subRegion, RegionStatistics & subRegionStats ) + { + aggregateStats( regionStats, subRegionStats ); + + mpiAggregateStats( subRegionStats ); + postAggregateStats( subRegionStats ); + } ); + + aggregateStats( allRegionsStats, regionStats ); + + mpiAggregateStats( regionStats ); + postAggregateStats( regionStats ); + } ); + + mpiAggregateStats( allRegionsStats ); + postAggregateStats( allRegionsStats ); } - // Step 2: increment the average/min/max quantities for all the subRegions - elemManager.forElementSubRegions( regionNames, [&]( localIndex const, - ElementSubRegionBase & subRegion ) - { + // stdVector< string > phaseCompName; + // phaseCompName.reserve( numPhases*numComps ); + // stdVector< string > massValues; + // phaseCompName.reserve( numPhases*numComps ); - arrayView1d< integer const > const elemGhostRank = subRegion.ghostRank(); - arrayView1d< real64 const > const volume = subRegion.getElementVolume(); - arrayView1d< real64 const > const pres = subRegion.getField< fields::flow::pressure >(); - arrayView1d< real64 const > const temp = subRegion.getField< fields::flow::temperature >(); - arrayView2d< real64 const, compflow::USD_PHASE > const phaseVolFrac = - subRegion.getField< fields::flow::phaseVolumeFraction >(); - arrayView1d< real64 const > const deltaPres = subRegion.getField< fields::flow::deltaPressure >(); - - Group const & constitutiveModels = subRegion.getGroup( ElementSubRegionBase::groupKeyStruct::constitutiveModelsString() ); - - string const & solidName = subRegion.getReference< string >( CompositionalMultiphaseBase::viewKeyStruct::solidNamesString() ); - CoupledSolidBase const & solid = constitutiveModels.getGroup< CoupledSolidBase >( solidName ); - arrayView1d< real64 const > const refPorosity = solid.getReferencePorosity(); - arrayView2d< real64 const > const porosity = solid.getPorosity(); - - string const & fluidName = subRegion.getReference< string >( CompositionalMultiphaseBase::viewKeyStruct::fluidNamesString() ); - MultiFluidBase const & fluid = constitutiveModels.getGroup< MultiFluidBase >( fluidName ); - arrayView3d< real64 const, multifluid::USD_PHASE > const phaseDensity = fluid.phaseDensity(); - arrayView4d< real64 const, multifluid::USD_PHASE_COMP > const phaseCompFraction = fluid.phaseCompFraction(); - - - //get min vol fraction for each phase to dispactche immobile/mobile mass - string const & relpermName = subRegion.getReference< string >( CompositionalMultiphaseBase::viewKeyStruct::relPermNamesString() ); - RelativePermeabilityBase const & relperm = constitutiveModels.getGroup< RelativePermeabilityBase >( relpermName ); - arrayView3d< real64 const, relperm::USD_RELPERM > const phaseTrappedVolFrac = relperm.phaseTrappedVolFraction(); - arrayView3d< real64 const, relperm::USD_RELPERM > const phaseRelperm = relperm.phaseRelPerm(); - - real64 subRegionAvgPresNumerator = 0.0; - real64 subRegionMinPres = 0.0; - real64 subRegionMaxPres = 0.0; - real64 subRegionMinDeltaPres = 0.0; - real64 subRegionMaxDeltaPres = 0.0; - real64 subRegionAvgTempNumerator = 0.0; - real64 subRegionMinTemp = 0.0; - real64 subRegionMaxTemp = 0.0; - real64 subRegionTotalUncompactedPoreVol = 0.0; - array1d< real64 > subRegionPhaseDynamicPoreVol( numPhases ); - array1d< real64 > subRegionPhaseMass( numPhases ); - array1d< real64 > subRegionTrappedPhaseMass( numPhases ); - array1d< real64 > subRegionImmobilePhaseMass( numPhases ); - array1d< real64 > subRegionRelpermPhaseMass( numPhases ); - array2d< real64 > subRegionComponentMass( numPhases, numComps ); - - isothermalCompositionalMultiphaseBaseKernels:: - StatisticsKernel:: - launch< parallelDevicePolicy<> >( subRegion.size(), - numComps, - numPhases, - m_params.m_relpermThreshold, - elemGhostRank, - volume, - pres, - deltaPres, - temp, - refPorosity, - porosity, - phaseDensity, - phaseCompFraction, - phaseVolFrac, - phaseTrappedVolFrac, - phaseRelperm, - subRegionMinPres, - subRegionAvgPresNumerator, - subRegionMaxPres, - subRegionMinDeltaPres, - subRegionMaxDeltaPres, - subRegionMinTemp, - subRegionAvgTempNumerator, - subRegionMaxTemp, - subRegionTotalUncompactedPoreVol, - subRegionPhaseDynamicPoreVol.toView(), - subRegionPhaseMass.toView(), - subRegionTrappedPhaseMass.toView(), - subRegionImmobilePhaseMass.toView(), - subRegionComponentMass.toView() ); - - ElementRegionBase & region = elemManager.getRegion( ElementRegionBase::getParentRegion( subRegion ).getName() ); - RegionStatistics & stats = region.getReference< RegionStatistics >( VKStruct::regionStatisticsString() ); - - stats.m_averagePressure += subRegionAvgPresNumerator; - if( subRegionMinPres < stats.m_minPressure ) - { - stats.m_minPressure = subRegionMinPres; - } - if( subRegionMaxPres > stats.m_maxPressure ) - { - stats.m_maxPressure = subRegionMaxPres; - } + // ConstitutiveManager const & constitutiveManager = mesh.getGroupByPath< ConstitutiveManager >( "/Problem/domain/Constitutive" ); + // MultiFluidBase const & fluid = constitutiveManager.getGroup< MultiFluidBase >( m_solver->referenceFluidModelName() ); + // auto const phaseNames = fluid.phaseNames(); + // auto const componentNames = fluid.componentNames(); + // for( integer ip = 0; ip < numPhases; ++ip ) + // { + // for( integer ic = 0; ic < numComps; ++ic ) + // { + // std::stringstream ss; + // ss << phaseNames[ip] << "/" << componentNames[ic]; + // phaseCompName.push_back( ss.str() ); + // massValues.push_back( GEOS_FMT( "{}", stats.m_componentMass[ip][ic] ) ); + // } + // } + // } - if( subRegionMinDeltaPres < stats.m_minDeltaPressure ) - { - stats.m_minDeltaPressure = subRegionMinDeltaPres; - } - if( subRegionMaxDeltaPres > stats.m_maxDeltaPressure ) - { - stats.m_maxDeltaPressure = subRegionMaxDeltaPres; - } + return true; +} - stats.m_averageTemperature += subRegionAvgTempNumerator; - if( subRegionMinTemp < stats.m_minTemperature ) - { - stats.m_minTemperature = subRegionMinTemp; - } - if( subRegionMaxTemp > stats.m_maxTemperature ) - { - stats.m_maxTemperature = subRegionMaxTemp; - } +void StatsAggregator::initStats( RegionStatistics & stats, real64 const time ) const +{ + stats.m_time = time; - stats.m_totalUncompactedPoreVolume += subRegionTotalUncompactedPoreVol; - for( integer ip = 0; ip < numPhases; ++ip ) - { - stats.m_phasePoreVolume[ip] += subRegionPhaseDynamicPoreVol[ip]; - stats.m_phaseMass[ip] += subRegionPhaseMass[ip]; - stats.m_trappedPhaseMass[ip] += subRegionTrappedPhaseMass[ip]; - stats.m_immobilePhaseMass[ip] += subRegionImmobilePhaseMass[ip]; + stats.m_averagePressure = 0.0; + stats.m_maxPressure = 0.0; + stats.m_minPressure = LvArray::NumericLimits< real64 >::max; - for( integer ic = 0; ic < numComps; ++ic ) - { - stats.m_componentMass[ip][ic] += subRegionComponentMass[ip][ic]; - } - } + stats.m_maxDeltaPressure = -LvArray::NumericLimits< real64 >::max; + stats.m_minDeltaPressure = LvArray::NumericLimits< real64 >::max; - } ); + stats.m_averageTemperature = 0.0; + stats.m_maxTemperature = 0.0; + stats.m_minTemperature = LvArray::NumericLimits< real64 >::max; + + stats.m_totalPoreVolume = 0.0; + stats.m_totalUncompactedPoreVolume = 0.0; + stats.m_phaseDynamicPoreVolume.setValues< serialPolicy >( 0.0 ); + + stats.m_phaseMass.setValues< serialPolicy >( 0.0 ); + stats.m_trappedPhaseMass.setValues< serialPolicy >( 0.0 ); + stats.m_nonTrappedPhaseMass.setValues< serialPolicy >( 0.0 ); + stats.m_immobilePhaseMass.setValues< serialPolicy >( 0.0 ); + stats.m_mobilePhaseMass.setValues< serialPolicy >( 0.0 ); + stats.m_componentMass.setValues< serialPolicy >( 0.0 ); +} + +void StatsAggregator::computeSubRegionRankStats( CellElementSubRegion & subRegion, RegionStatistics & subRegionStats ) const +{ + arrayView1d< integer const > const elemGhostRank = subRegion.ghostRank(); + arrayView1d< real64 const > const volume = subRegion.getElementVolume(); + arrayView1d< real64 const > const pres = subRegion.getField< fields::flow::pressure >(); + arrayView1d< real64 const > const temp = subRegion.getField< fields::flow::temperature >(); + arrayView2d< real64 const, compflow::USD_PHASE > const phaseVolFrac = + subRegion.getField< fields::flow::phaseVolumeFraction >(); + arrayView1d< real64 const > const deltaPres = subRegion.getField< fields::flow::deltaPressure >(); + + Group const & constitutiveModels = subRegion.getGroup( ElementSubRegionBase::groupKeyStruct::constitutiveModelsString() ); + + string const & solidName = subRegion.getReference< string >( CompositionalMultiphaseBase::viewKeyStruct::solidNamesString() ); + CoupledSolidBase const & solid = constitutiveModels.getGroup< CoupledSolidBase >( solidName ); + arrayView1d< real64 const > const refPorosity = solid.getReferencePorosity(); + arrayView2d< real64 const > const porosity = solid.getPorosity(); + + string const & fluidName = subRegion.getReference< string >( CompositionalMultiphaseBase::viewKeyStruct::fluidNamesString() ); + MultiFluidBase const & fluid = constitutiveModels.getGroup< MultiFluidBase >( fluidName ); + arrayView3d< real64 const, multifluid::USD_PHASE > const phaseDensity = fluid.phaseDensity(); + arrayView4d< real64 const, multifluid::USD_PHASE_COMP > const phaseCompFraction = fluid.phaseCompFraction(); + + //get min vol fraction for each phase to dispactche immobile/mobile mass + string const & relpermName = subRegion.getReference< string >( CompositionalMultiphaseBase::viewKeyStruct::relPermNamesString() ); + RelativePermeabilityBase const & relperm = constitutiveModels.getGroup< RelativePermeabilityBase >( relpermName ); + arrayView3d< real64 const, relperm::USD_RELPERM > const phaseTrappedVolFrac = relperm.phaseTrappedVolFraction(); + arrayView3d< real64 const, relperm::USD_RELPERM > const phaseRelperm = relperm.phaseRelPerm(); + + isothermalCompositionalMultiphaseBaseKernels:: + StatisticsKernel:: + launch< parallelDevicePolicy<> >( subRegion.size(), + m_numComponents, + m_numPhases, + m_params.m_relpermThreshold, + elemGhostRank, + volume, + pres, + deltaPres, + temp, + refPorosity, + porosity, + phaseDensity, + phaseCompFraction, + phaseVolFrac, + phaseTrappedVolFrac, + phaseRelperm, + subRegionStats.m_minPressure, + subRegionStats.m_averagePressure, + subRegionStats.m_maxPressure, + subRegionStats.m_minDeltaPressure, + subRegionStats.m_maxDeltaPressure, + subRegionStats.m_minTemperature, + subRegionStats.m_averageTemperature, + subRegionStats.m_maxTemperature, + subRegionStats.m_totalUncompactedPoreVolume, + subRegionStats.m_phaseDynamicPoreVolume.toView(), + subRegionStats.m_phaseMass.toView(), + subRegionStats.m_trappedPhaseMass.toView(), + subRegionStats.m_immobilePhaseMass.toView(), + subRegionStats.m_componentMass.toView() ); +} + + +void StatsAggregator::aggregateStats( RegionStatistics & stats, RegionStatistics const & other ) const +{ + stats.m_averagePressure += other.m_averagePressure; + stats.m_minPressure = LvArray::math::min( stats.m_minPressure, other.m_minPressure ); + stats.m_maxPressure = LvArray::math::max( stats.m_maxPressure, other.m_maxPressure ); + + stats.m_minDeltaPressure = LvArray::math::min( stats.m_minDeltaPressure, other.m_minDeltaPressure ); + stats.m_maxDeltaPressure = LvArray::math::max( stats.m_maxDeltaPressure, other.m_maxDeltaPressure ); + + stats.m_averageTemperature += other.m_averageTemperature; + stats.m_minTemperature = LvArray::math::min( stats.m_minTemperature, other.m_minTemperature ); + stats.m_maxTemperature = LvArray::math::max( stats.m_maxTemperature, other.m_maxTemperature ); + + stats.m_totalUncompactedPoreVolume += other.m_totalUncompactedPoreVolume; - // Step 3: synchronize the results over the MPI ranks - for( size_t i = 0; i < regionNames.size(); ++i ) + for( integer ip = 0; ip < m_numPhases; ++ip ) { - ElementRegionBase & region = elemManager.getRegion( regionNames[i] ); - RegionStatistics & stats = region.getReference< RegionStatistics >( VKStruct::regionStatisticsString() ); - - stats.m_minPressure = MpiWrapper::min( stats.m_minPressure ); - stats.m_maxPressure = MpiWrapper::max( stats.m_maxPressure ); - stats.m_minDeltaPressure = MpiWrapper::min( stats.m_minDeltaPressure ); - stats.m_maxDeltaPressure = MpiWrapper::max( stats.m_maxDeltaPressure ); - stats.m_minTemperature = MpiWrapper::min( stats.m_minTemperature ); - stats.m_maxTemperature = MpiWrapper::max( stats.m_maxTemperature ); - stats.m_totalUncompactedPoreVolume = MpiWrapper::sum( stats.m_totalUncompactedPoreVolume ); - stats.m_totalPoreVolume = 0.0; - for( integer ip = 0; ip < numPhases; ++ip ) - { - stats.m_phasePoreVolume[ip] = MpiWrapper::sum( stats.m_phasePoreVolume[ip] ); - stats.m_phaseMass[ip] = MpiWrapper::sum( stats.m_phaseMass[ip] ); - stats.m_trappedPhaseMass[ip] = MpiWrapper::sum( stats.m_trappedPhaseMass[ip] ); - stats.m_immobilePhaseMass[ip] = MpiWrapper::sum( stats.m_immobilePhaseMass[ip] ); - stats.m_totalPoreVolume += stats.m_phasePoreVolume[ip]; - for( integer ic = 0; ic < numComps; ++ic ) - { - stats.m_componentMass[ip][ic] = MpiWrapper::sum( stats.m_componentMass[ip][ic] ); - } - } - stats.m_averagePressure = MpiWrapper::sum( stats.m_averagePressure ); - stats.m_averageTemperature = MpiWrapper::sum( stats.m_averageTemperature ); - if( stats.m_totalUncompactedPoreVolume > 0 ) - { - float invTotalUncompactedPoreVolume = 1.0 / stats.m_totalUncompactedPoreVolume; - stats.m_averagePressure *= invTotalUncompactedPoreVolume; - stats.m_averageTemperature *= invTotalUncompactedPoreVolume; - } - else - { - stats.m_averagePressure = 0.0; - stats.m_averageTemperature = 0.0; - m_issues.emplace_back( GEOS_FMT( "Cannot compute average pressure because region pore volume is zero in region '{}'.", - regionNames[i] ) ); - } + stats.m_phaseDynamicPoreVolume[ip] += other.m_phaseDynamicPoreVolume[ip]; + stats.m_phaseMass[ip] += other.m_phaseMass[ip]; + stats.m_trappedPhaseMass[ip] += other.m_trappedPhaseMass[ip]; + stats.m_immobilePhaseMass[ip] += other.m_immobilePhaseMass[ip]; - for( integer ip = 0; ip < numPhases; ++ip ) + for( integer ic = 0; ic < m_numComponents; ++ic ) { - stats.m_nonTrappedPhaseMass[ip] = stats.m_phaseMass[ip] - stats.m_trappedPhaseMass[ip]; - stats.m_mobilePhaseMass[ip] = stats.m_phaseMass[ip] - stats.m_immobilePhaseMass[ip]; + stats.m_componentMass[ip][ic] += other.m_componentMass[ip][ic]; } + } +} + +void StatsAggregator::mpiAggregateStats( RegionStatistics & stats ) const +{ + stats.m_averagePressure = MpiWrapper::sum( stats.m_averagePressure ); + stats.m_minPressure = MpiWrapper::min( stats.m_minPressure ); + stats.m_maxPressure = MpiWrapper::max( stats.m_maxPressure ); + + stats.m_minDeltaPressure = MpiWrapper::min( stats.m_minDeltaPressure ); + stats.m_maxDeltaPressure = MpiWrapper::max( stats.m_maxDeltaPressure ); - stdVector< string > phaseCompName; - phaseCompName.reserve( numPhases*numComps ); - stdVector< string > massValues; - phaseCompName.reserve( numPhases*numComps ); + stats.m_averageTemperature = MpiWrapper::sum( stats.m_averageTemperature ); + stats.m_minTemperature = MpiWrapper::min( stats.m_minTemperature ); + stats.m_maxTemperature = MpiWrapper::max( stats.m_maxTemperature ); + + stats.m_totalUncompactedPoreVolume = MpiWrapper::sum( stats.m_totalUncompactedPoreVolume ); + + for( integer ip = 0; ip < m_numPhases; ++ip ) + { + stats.m_phaseDynamicPoreVolume[ip] = MpiWrapper::sum( stats.m_phaseDynamicPoreVolume[ip] ); + stats.m_phaseMass[ip] = MpiWrapper::sum( stats.m_phaseMass[ip] ); + stats.m_trappedPhaseMass[ip] = MpiWrapper::sum( stats.m_trappedPhaseMass[ip] ); + stats.m_immobilePhaseMass[ip] = MpiWrapper::sum( stats.m_immobilePhaseMass[ip] ); - ConstitutiveManager const & constitutiveManager = mesh.getGroupByPath< ConstitutiveManager >( "/Problem/domain/Constitutive" ); - MultiFluidBase const & fluid = constitutiveManager.getGroup< MultiFluidBase >( m_solver->referenceFluidModelName() ); - auto const phaseNames = fluid.phaseNames(); - auto const componentNames = fluid.componentNames(); - for( integer ip = 0; ip < numPhases; ++ip ) + for( integer ic = 0; ic < m_numComponents; ++ic ) { - for( integer ic = 0; ic < numComps; ++ic ) - { - std::stringstream ss; - ss << phaseNames[ip] << "/" << componentNames[ic]; - phaseCompName.push_back( ss.str() ); - massValues.push_back( GEOS_FMT( "{}", stats.m_componentMass[ip][ic] ) ); - } + stats.m_componentMass[ip][ic] = MpiWrapper::sum( stats.m_componentMass[ip][ic] ); } } +} - return true; +void StatsAggregator::postAggregateStats( RegionStatistics & stats ) +{ + if( stats.m_totalUncompactedPoreVolume > 0 ) + { + float invTotalUncompactedPoreVolume = 1.0 / stats.m_totalUncompactedPoreVolume; + stats.m_averagePressure *= invTotalUncompactedPoreVolume; + stats.m_averageTemperature *= invTotalUncompactedPoreVolume; + } + else + { + stats.m_averagePressure = 0.0; + stats.m_averageTemperature = 0.0; + m_warnings.emplace_back( GEOS_FMT( "Cannot compute average pressure for '{}' because pore volume is zero in '{}'.", + m_ownerName, stats.getTargetName() ) ); + } + + for( integer ip = 0; ip < m_numPhases; ++ip ) + { + stats.m_totalPoreVolume += stats.m_phaseDynamicPoreVolume[ip]; + stats.m_nonTrappedPhaseMass[ip] = stats.m_phaseMass[ip] - stats.m_trappedPhaseMass[ip]; + stats.m_mobilePhaseMass[ip] = stats.m_phaseMass[ip] - stats.m_immobilePhaseMass[ip]; + } } bool StatsAggregator::computeCFLNumbers( real64 const time, @@ -397,11 +510,11 @@ bool StatsAggregator::computeCFLNumbers( real64 const time, real64 maxPhaseCFL, maxCompCFL; CFLStatistics * stats = getCFLStatistics( domain ); - m_issues.clear(); + m_warnings.clear(); if( stats!=nullptr ) { - m_issues.emplace_back( GEOS_FMT( "No statistics structure to compute CFL numbers for domain '{}'.", domain.getName() )); + m_warnings.emplace_back( GEOS_FMT( "No statistics structure to compute CFL numbers for domain '{}'.", domain.getName() )); return false; } @@ -414,6 +527,21 @@ bool StatsAggregator::computeCFLNumbers( real64 const time, return true; } +RegionStatistics::RegionStatistics( string const & name, dataRepository::Group * const parent, + string_view targetName, + integer const numPhases, integer const numComponents ): + dataRepository::Group( name, parent ), + m_targetName( targetName ), + m_phaseDynamicPoreVolume( numPhases ), + m_phaseMass( numPhases ), + m_trappedPhaseMass( numPhases ), + m_nonTrappedPhaseMass( numPhases ), + m_immobilePhaseMass( numPhases ), + m_mobilePhaseMass( numPhases ), + m_componentMass( numPhases, numComponents ) +{ + // TODO : registerWrappers (need repairing of 1D HDF5 output PR #3145) +} } /* namespace compositionalMultiphaseStatistics */ diff --git a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsAggregator.hpp b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsAggregator.hpp index 1e751dd2825..b5189fafcc3 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsAggregator.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsAggregator.hpp @@ -20,8 +20,10 @@ #ifndef SRC_CORECOMPONENTS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONALMULTIPHASESTATISTICSAGGREGATOR_HPP_ #define SRC_CORECOMPONENTS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONALMULTIPHASESTATISTICSAGGREGATOR_HPP_ +#include "common/DataTypes.hpp" #include "common/StdContainerWrappers.hpp" #include "dataRepository/Group.hpp" +#include "mesh/CellElementRegion.hpp" #include "mesh/DomainPartition.hpp" #include "mesh/MeshLevel.hpp" @@ -52,7 +54,7 @@ class RegionStatistics : public dataRepository::Group /// Time of statistics computation real64 m_time; - /// average region pressure + /// average region pressure (numerator value before postAggregateCompute()) real64 m_averagePressure; /// minimum region pressure real64 m_minPressure; @@ -64,7 +66,7 @@ class RegionStatistics : public dataRepository::Group /// maximum region delta pressure real64 m_maxDeltaPressure; - /// average region temperature + /// average region temperature (numerator value before postAggregateCompute()) real64 m_averageTemperature; /// minimum region temperature real64 m_minTemperature; @@ -75,32 +77,51 @@ class RegionStatistics : public dataRepository::Group real64 m_totalPoreVolume; /// total region uncompacted pore volume real64 m_totalUncompactedPoreVolume; - /// phase region phase pore volume - array1d< real64 > m_phasePoreVolume; + /// phase region dynamic pore volume + array1d< real64 > const m_phaseDynamicPoreVolume; /// region phase mass (trapped and non-trapped, immobile and mobile) - array1d< real64 > m_phaseMass; + array1d< real64 > const m_phaseMass; /// trapped region phase mass - array1d< real64 > m_trappedPhaseMass; - /// non-trapped region phase mass - array1d< real64 > m_nonTrappedPhaseMass; + array1d< real64 > const m_trappedPhaseMass; + /// non-trapped region phase mass (available after postAggregateCompute()) + array1d< real64 > const m_nonTrappedPhaseMass; /// immobile region phase mass - array1d< real64 > m_immobilePhaseMass; - /// mobile region phase mass - array1d< real64 > m_mobilePhaseMass; + array1d< real64 > const m_immobilePhaseMass; + /// mobile region phase mass (available after postAggregateCompute()) + array1d< real64 > const m_mobilePhaseMass; /// region component mass - array2d< real64 > m_componentMass; + array2d< real64 > const m_componentMass; - // TODO: -> split to struct PressureStats...MassStats: + // TODO? -> split to struct PressureStats...MassStats: // - VKS for struct name ("pressureStats"..."massStats") // - current RegionStatistics struct bits /** * @brief Construct a new Region Statistics object - * @param name instance name in data-repository + * @param name instance name in data-repository. + * @param targetName name of the data-repository object that is targeted by the statistics + * (mesh level / region / sub-region). * @param parent the instance parent in data-repository + * @param numPhases Fluid phase count + * @param numComponents Fluid component count + */ + RegionStatistics( string const & name, dataRepository::Group * const parent, + string_view targetName, + integer numPhases, integer numComponents ); + + RegionStatistics( RegionStatistics && ) = default; + + /** + * @return the name of the data-repository object that is targeted by the statistics + * (mesh level / region / sub-region). */ - RegionStatistics( const string & name, dataRepository::Group * const parent ); + string_view getTargetName() const + { return m_targetName; } + +private: + /// see getTargetName(); + string const m_targetName; }; /** @@ -139,49 +160,76 @@ class StatsAggregator /** * @brief the associated view keys */ - struct VKStruct + struct ViewKeys { + /// String for the discretization statistics group + constexpr static char const * statisticsString() { return "statistics"; } /// String for the region statistics group - constexpr static char const * regionStatisticsString() { return "regionStatistics"; } + constexpr static char const * regionsStatisticsString() { return "regionsStatistics"; } /// String for the cfl statistics group constexpr static char const * cflStatisticsString() { return "cflStatistics"; } }; - using RegionFunctor = std::function< void (string_view, RegionStatistics const &) >; - - StatsAggregator(); + /** + * @brief Standard function signature for any functor that applies on RegionStatistics instances + * param 0: TODO document + * param 1: TODO document + * @tparam OWNER_T + */ + template< typename OWNER_T > + using RegionStatisticsFunctor = std::function< void ( OWNER_T &, RegionStatistics & ) >; /** - * @brief Set the reference flow solver object to retrieve: - - the simulated regions, - - fields for statistics computation. - * @param solver The reference flow solver + * @brief Construct a new Stats Aggregator object + * @param ownerName the unique name of the entity requesting the statistics. + * An error is thrown if not unique in this context. */ - void setFlowSolver( CompositionalMultiphaseBase & solver ) - { m_solver = &solver; } + StatsAggregator( string_view ownerName ); - // void forDiscretizations( DomainPartition const &, - // std::function< void(MeshLevel const &, - // string_array const & regionNames) > functor ) const; + /** + * @brief Enable the computation of any statistics, initialize data structure to collect them. + * Register the resulting data wrappers so they will be targeted by TimeHistory output + * @param solver flow solver object to retrieve: + - the simulated regions, + - fields for statistics computation. + * @param meshBodies The Group containing the MeshBody objects + */ + void initStatisticsAggregation( dataRepository::Group & meshBodies, + CompositionalMultiphaseBase & solver ); - void forRegionStatistics( MeshLevel const & mesh, - RegionFunctor functor ) const; + /** + * @brief Enable the computation of any statistics, initialize data structure to collect them. + * Register the resulting data wrappers so they will be targeted by TimeHistory output + * @note Must be called in or after the "registerDataOnMesh" initialization phase + */ + void initStatisticsAggregation(); /** * @brief Enable the computation of region statistics, initialize data structure to collect them. * Register the resulting data wrappers so they will be targeted by TimeHistory output - * @note Must be called in "registerDataOnMesh" initialization phase + * @note Must be called in or after the "registerDataOnMesh" initialization phase * @param meshBodies The Group containing the MeshBody objects */ - void enableRegionStatistics( dataRepository::Group & meshBodies ); + void enableRegionStatisticsAggregation( dataRepository::Group & meshBodies ); /** * @brief Register the results structs & wrappers so they will be targeted by TimeHistory output - * @note Must be called in "registerDataOnMesh" initialization phase + * @note Must be called in or after the "registerDataOnMesh" initialization phase * @param meshBodies The Group containing the MeshBody objects */ void enableCFLStatistics( dataRepository::Group & meshBodies ); + void forRegionStatistics( dataRepository::Group & meshBodies, + RegionStatisticsFunctor< MeshLevel > const & functor ) const; + + void forRegionStatistics( MeshLevel & mesh, + RegionStatistics & allRegionsStatistics, + RegionStatisticsFunctor< CellElementRegion > const & functor ) const; + + void forRegionStatistics( CellElementRegion & region, + RegionStatistics & regionStatistics, + RegionStatisticsFunctor< CellElementSubRegion > const & functor ) const; + /** * @brief Compute some statistics on a given mesh discretization (average field pressure, etc) * Results are reduced on rank 0, and broadcasted over all ranks. @@ -206,7 +254,7 @@ class StatsAggregator DomainPartition & domain ); CFLStatistics * getCFLStatistics( DomainPartition & domain ) const - {return domain.getGroupPointer< CFLStatistics >( VKStruct::cflStatisticsString() ); } + {return domain.getGroupPointer< CFLStatistics >( ViewKeys::cflStatisticsString() ); } CompositionalMultiphaseBase const * getSolver() const { return m_solver; } @@ -214,8 +262,20 @@ class StatsAggregator /** * @return The encountered issues during the last computing method call. */ - stdVector< string > const & getIssues() const - { return m_issues; } + stdVector< string > const & getWarnings() const + { return m_warnings; } + + /** + * @return the name of the entity requesting the statistics. + */ + string_view getOwnerName() const + { return m_ownerName; } + + integer getNumPhases() const + { return m_numPhases; } + + integer getNumComponents() const + { return m_numComponents; } private: @@ -223,11 +283,51 @@ class StatsAggregator AggregatorParameters m_params; - stdVector< string > m_issues; + stdVector< string > m_warnings; + + /// @see getOwnerName() + string m_ownerName; + + bool m_isRegionStatsEnabled = false; - bool m_isRegionStatsEnabled; + bool m_isCFLNumberEnabled = false; - bool m_isCFLNumberEnabled; + integer m_numPhases; + + integer m_numComponents; + + dataRepository::Group & getInstanceStatisticsGroup( MeshLevel & mesh ) const; + RegionStatistics & getRegionsStatisticsGroup( MeshLevel & mesh ) const; + CFLStatistics & getCflStatisticsGroup( MeshLevel & mesh ) const; + + /** + * @brief Initialize all statistics values to aggregable default values, + * before any computation / reduction for the current timestep. + * @param stats the statistics instance + * @param time start time of the current timestep (s) + */ + void initStats( RegionStatistics & stats, real64 time ) const; + + void computeSubRegionRankStats( CellElementSubRegion & subRegion, RegionStatistics & subRegionStats ) const; + + /** + * @brief Aggregate all instance statistics with those of another instance on the current rank. + * @param stats the statistics instance + * @param other the other instance to aggregate with. + */ + void aggregateStats( RegionStatistics & stats, RegionStatistics const & other ) const; + + /** + * @brief Aggregate all instance statistics with those of other ranks. + * @param stats the statistics instance + */ + void mpiAggregateStats( RegionStatistics & stats ) const; + + /** + * @brief Do the final computations for the statistics. Must be called after computations & aggregations. + * @param stats the statistics instance + */ + void postAggregateStats( RegionStatistics & stats ); }; From 1c4b603d2fd64ca8e7f8e41c07606b2290c81d4f Mon Sep 17 00:00:00 2001 From: MelReyCG Date: Wed, 7 Jan 2026 16:53:59 +0100 Subject: [PATCH 12/28] =?UTF-8?q?=E2=99=BB=EF=B8=8Fimpact=20new=20aggregat?= =?UTF-8?q?or=20on=20stats=20task=20+=20bugfixes=20on=20formatting=20&=20o?= =?UTF-8?q?utput?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../physicsSolvers/FieldStatisticsBase.hpp | 32 ++--- ...sitionalMultiphaseStatisticsAggregator.cpp | 32 ++--- ...sitionalMultiphaseStatisticsAggregator.hpp | 17 +-- .../CompositionalMultiphaseStatisticsTask.cpp | 119 +++++++++++++----- .../CompositionalMultiphaseStatisticsTask.hpp | 9 +- 5 files changed, 128 insertions(+), 81 deletions(-) diff --git a/src/coreComponents/physicsSolvers/FieldStatisticsBase.hpp b/src/coreComponents/physicsSolvers/FieldStatisticsBase.hpp index af9efb7fefa..40a9f27f682 100644 --- a/src/coreComponents/physicsSolvers/FieldStatisticsBase.hpp +++ b/src/coreComponents/physicsSolvers/FieldStatisticsBase.hpp @@ -50,8 +50,7 @@ class FieldStatisticsBase : public TaskBase m_outputDir( joinPath( OutputBase::getOutputDirectory(), name ) ) { - string const key = SOLVER::coupledSolverAttributePrefix() + "SolverName"; - registerWrapper( key, &m_solverName ). + registerWrapper( getSolverWrapperKey(), &m_solverName ). setRTTypeName( rtTypes::CustomTypes::groupNameRef ). setInputFlag( dataRepository::InputFlags::REQUIRED ). setDescription( "Name of the " + SOLVER::coupledSolverAttributePrefix() + " solver" ); @@ -80,6 +79,20 @@ class FieldStatisticsBase : public TaskBase protected: + struct viewKeyStruct + { + static constexpr char const * writeCSVFlagString() { return "writeCSV"; } + }; + + /// Pointer to the physics solver + SOLVER * m_solver; + + // Output directory + string const m_outputDir; + + // Flag to enable writing CSV output + integer m_writeCSV; + void postInputInitialization() override { Group & problemManager = this->getGroupByPath( "/Problem" ); @@ -104,19 +117,8 @@ class FieldStatisticsBase : public TaskBase } } - struct viewKeyStruct - { - static constexpr char const * writeCSVFlagString() { return "writeCSV"; } - }; - - /// Pointer to the physics solver - SOLVER * m_solver; - - // Output directory - string const m_outputDir; - - // Flag to enable writing CSV output - integer m_writeCSV; + string getSolverWrapperKey() const + { return SOLVER::coupledSolverAttributePrefix() + "SolverName"; } private: diff --git a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsAggregator.cpp b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsAggregator.cpp index f049144ebdb..142adffc13e 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsAggregator.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsAggregator.cpp @@ -134,7 +134,6 @@ void StatsAggregator::enableRegionStatisticsAggregation( dataRepository::Group & if( m_solver == nullptr ) return; - auto const registerStats = [=] ( Group & parent, string const & name, string const & targetName ) -> RegionStatistics & @@ -228,11 +227,11 @@ void StatsAggregator::forRegionStatistics( dataRepository::Group & meshBodies, } void StatsAggregator::forRegionStatistics( MeshLevel & mesh, - RegionStatistics & allRegionsStatistics, + RegionStatistics & meshRegionsStatistics, RegionStatisticsFunctor< CellElementRegion > const & func ) const { ElementRegionManager & elemManager = mesh.getElemManager(); - allRegionsStatistics.forSubGroups< RegionStatistics >( [&] ( RegionStatistics & regionStatistics ) + meshRegionsStatistics.forSubGroups< RegionStatistics >( [&] ( RegionStatistics & regionStatistics ) { string_view targetName = regionStatistics.getTargetName(); CellElementRegion & region = elemManager.getRegion< CellElementRegion >( targetName ); @@ -253,16 +252,15 @@ void StatsAggregator::forRegionStatistics( CellElementRegion & region, } ); } -bool StatsAggregator::computeRegionsStatistics( real64 const time, - MeshLevel & mesh, - string_array const & regionNames ) +bool StatsAggregator::computeRegionsStatistics( real64 const time, Group & meshBodies ) { GEOS_MARK_FUNCTION; - ElementRegionManager & elemManager = mesh.getElemManager(); - RegionStatistics & allRegionsStats = getRegionsStatisticsGroup( mesh ); - - { // computation of sub region stats + // computation of sub region stats + forRegionStatistics( meshBodies, + [&, time] ( MeshLevel & mesh, RegionStatistics & regionStats ) + { + RegionStatistics & allRegionsStats = getRegionsStatisticsGroup( mesh ); forRegionStatistics( mesh, allRegionsStats, [&, time] ( CellElementRegion & region, RegionStatistics & regionStats ) @@ -275,9 +273,13 @@ bool StatsAggregator::computeRegionsStatistics( real64 const time, computeSubRegionRankStats( subRegion, subRegionStats ); } ); } ); - } + } ); - { // aggregation of computations from the sub regions + // aggregation of computations from the sub regions + forRegionStatistics( meshBodies, + [&, time] ( MeshLevel & mesh, RegionStatistics & regionStats ) + { + RegionStatistics & allRegionsStats = getRegionsStatisticsGroup( mesh ); initStats( allRegionsStats, time ); forRegionStatistics( mesh, @@ -304,7 +306,7 @@ bool StatsAggregator::computeRegionsStatistics( real64 const time, mpiAggregateStats( allRegionsStats ); postAggregateStats( allRegionsStats ); - } + } ); // stdVector< string > phaseCompName; // phaseCompName.reserve( numPhases*numComps ); @@ -491,7 +493,7 @@ void StatsAggregator::postAggregateStats( RegionStatistics & stats ) stats.m_averagePressure = 0.0; stats.m_averageTemperature = 0.0; m_warnings.emplace_back( GEOS_FMT( "Cannot compute average pressure for '{}' because pore volume is zero in '{}'.", - m_ownerName, stats.getTargetName() ) ); + m_ownerName, stats.getTargetName() ) ); } for( integer ip = 0; ip < m_numPhases; ++ip ) @@ -540,7 +542,7 @@ RegionStatistics::RegionStatistics( string const & name, dataRepository::Group * m_mobilePhaseMass( numPhases ), m_componentMass( numPhases, numComponents ) { - // TODO : registerWrappers (need repairing of 1D HDF5 output PR #3145) + // TODO : registerWrappers (need repairing of 1D HDF5 output) } } /* namespace compositionalMultiphaseStatistics */ diff --git a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsAggregator.hpp b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsAggregator.hpp index b5189fafcc3..a9f26f7a932 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsAggregator.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsAggregator.hpp @@ -152,6 +152,7 @@ class CFLStatistics : public dataRepository::Group * @brief Reponsible of computing physical statistics over the grid, registering the result in the * data repository, but not storing / outputing it by itself. It does not have mutable state * except the encountered issues. + * @todo repair 1D HDF5 outputs to enable stats HDF5 outputs */ class StatsAggregator { @@ -197,13 +198,6 @@ class StatsAggregator void initStatisticsAggregation( dataRepository::Group & meshBodies, CompositionalMultiphaseBase & solver ); - /** - * @brief Enable the computation of any statistics, initialize data structure to collect them. - * Register the resulting data wrappers so they will be targeted by TimeHistory output - * @note Must be called in or after the "registerDataOnMesh" initialization phase - */ - void initStatisticsAggregation(); - /** * @brief Enable the computation of region statistics, initialize data structure to collect them. * Register the resulting data wrappers so they will be targeted by TimeHistory output @@ -223,7 +217,7 @@ class StatsAggregator RegionStatisticsFunctor< MeshLevel > const & functor ) const; void forRegionStatistics( MeshLevel & mesh, - RegionStatistics & allRegionsStatistics, + RegionStatistics & meshRegionsStatistics, RegionStatisticsFunctor< CellElementRegion > const & functor ) const; void forRegionStatistics( CellElementRegion & region, @@ -234,13 +228,10 @@ class StatsAggregator * @brief Compute some statistics on a given mesh discretization (average field pressure, etc) * Results are reduced on rank 0, and broadcasted over all ranks. * @param[in] time current time - * @param[in] mesh the mesh level object - * @param[in] regionNames the array of target region names + * @param[in] meshBodies the Group containg all MeshBody objects * @return false if there was a problem that prevented the statistics to be computed correctly. */ - bool computeRegionsStatistics( real64 const time, - MeshLevel & mesh, - string_array const & regionNames ); + bool computeRegionsStatistics( real64 const time, dataRepository::Group & meshBodies ); /** * @brief Compute CFL numbers diff --git a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsTask.cpp b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsTask.cpp index f49a4ef4c33..69d99771e5d 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsTask.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsTask.cpp @@ -23,12 +23,16 @@ #include "common/MpiWrapper.hpp" #include "common/StdContainerWrappers.hpp" #include "common/format/Format.hpp" +#include "common/logger/Logger.hpp" +#include "dataRepository/Group.hpp" +#include "mesh/CellElementRegion.hpp" #include "mesh/DomainPartition.hpp" #include "mesh/MeshLevel.hpp" #include "constitutive/fluid/multifluid/MultiFluidBase.hpp" #include "constitutive/relativePermeability/RelativePermeabilityBase.hpp" #include "constitutive/solid/CoupledSolidBase.hpp" #include "physicsSolvers/LogLevelsInfo.hpp" +#include "physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsAggregator.hpp" #include "physicsSolvers/fluidFlow/LogLevelsInfo.hpp" #include "physicsSolvers/fluidFlow/CompositionalMultiphaseBase.hpp" #include "physicsSolvers/fluidFlow/CompositionalMultiphaseBaseFields.hpp" @@ -51,7 +55,7 @@ using namespace dataRepository; namespace compositionalMultiphaseStatistics { -StatsTask::StatsTask( const string & name, Group * const parent ): +StatsTask::StatsTask( string const & name, Group * const parent ): Base( name, parent ), m_aggregator(), m_computeCFLNumbers( 0 ), @@ -80,38 +84,59 @@ void StatsTask::postInputInitialization() { Base::postInputInitialization(); - m_aggregator.setFlowSolver( *m_solver ); + GEOS_THROW_IF_EQ_MSG( m_solver, nullptr, + "To identify simulated regions, a solver must be provided." /*, getWrapperDataContext( getSolverWrapperName() )*/ ); - if( dynamicCast< CompositionalMultiphaseHybridFVM * >( m_solver ) && m_computeCFLNumbers != 0 ) + if( dynamicCast< CompositionalMultiphaseBase * >( m_solver )) + { + GEOS_THROW( GEOS_FMT( "{} {}: incompatible solver selected, a compositional multiphase solver is expected", + catalogName(), getDataContext() ), + InputError ); + + } + else if( dynamicCast< CompositionalMultiphaseHybridFVM * >( m_solver ) && m_computeCFLNumbers != 0 ) { GEOS_THROW( GEOS_FMT( "{} {}: the option to compute CFL numbers is incompatible with CompositionalMultiphaseHybridFVM", catalogName(), getDataContext() ), InputError ); } + + m_aggregator = std::make_unique< StatsAggregator >( getName() ); } void StatsTask::registerDataOnMesh( Group & meshBodies ) { // for now, this guard is needed to avoid breaking the xml schema generation if( m_solver == nullptr ) - { return; - } getGroupByPath( "/" ).printDataHierarchy(); prepareFluidMetaData(); + if( m_computeRegionStatistics || m_computeCFLNumbers ) + { + // expected to work as check is done in postInputInitialization() + CompositionalMultiphaseBase * castedSolver = dynamicCast< CompositionalMultiphaseBase * >( m_solver ); + GEOS_ERROR_IF_EQ_MSG( castedSolver, nullptr, + GEOS_FMT( "{} {}: Unexpected error (solver pointer changed?)", catalogName(), getDataContext() ) ); + m_aggregator->initStatisticsAggregation( meshBodies, *castedSolver ); + } + else + { + GEOS_WARNING( GEOS_FMT( "{} {}: No computing option enabled, no output is scheduled.", + catalogName(), getDataContext() ) ); + } + if( m_computeRegionStatistics ) - m_aggregator.enableRegionStatistics( meshBodies ); + m_aggregator->enableRegionStatisticsAggregation( meshBodies ); // if we have to compute CFL numbers later, we need to register additional variables if( m_computeCFLNumbers ) - m_solver->registerDataForCFL( meshBodies ); + m_aggregator->enableCFLStatistics( meshBodies ); - m_solver->forDiscretizationOnMeshTargets( meshBodies, [&] ( string const &, - MeshLevel & mesh, - string_array const & ) + m_aggregator->forRegionStatistics( meshBodies, + [&] ( MeshLevel & mesh, RegionStatistics & ) { prepareLogTableLayouts( mesh.getName() ); prepareCsvTableLayouts( mesh.getName() ); @@ -220,27 +245,27 @@ bool StatsTask::execute( real64 const time_n, // current time is time_n + dt. TODO: verify implication of events ordering in 'time_n+dt' validity real64 statsTime = time_n + dt; - m_solver->forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, - MeshLevel & mesh, - string_array const & regionNames ) + m_aggregator->computeRegionsStatistics( statsTime, domain.getMeshBodies() ); + + m_aggregator->forRegionStatistics( domain.getMeshBodies(), + [&] ( MeshLevel & mesh, RegionStatistics & meshRegionsStatistics ) { if( m_computeRegionStatistics ) { - m_aggregator.computeRegionsStatistics( statsTime, mesh, regionNames ); - outputLogStats( statsTime, mesh, regionNames ); - outputCsvStats( statsTime, mesh, regionNames ); + outputLogStats( statsTime, mesh, meshRegionsStatistics ); + outputCsvStats( statsTime, mesh, meshRegionsStatistics ); } } ); if( m_computeCFLNumbers ) - m_aggregator.computeCFLNumbers( statsTime, dt, domain ); + m_aggregator->computeCFLNumbers( statsTime, dt, domain ); return false; } void StatsTask::outputLogStats( real64 const statsTime, MeshLevel & mesh, - string_array const & ) + RegionStatistics & meshRegionsStatistics ) { if( MpiWrapper::commRank() > 0 || !isLogLevelActive< logInfo::Statistics >( this->getLogLevel() ) ) return; @@ -253,20 +278,20 @@ void StatsTask::outputLogStats( real64 const statsTime, TableData tableData; static constexpr auto merge = CellType::MergeNext; - string_view massUnit = units::getSymbol( m_aggregator.getSolver()->getMassUnit() ); + string_view massUnit = units::getSymbol( m_aggregator->getSolver()->getMassUnit() ); string_view pressureUnit = units::getSymbol( units::Pressure ); string_view tempUnit = units::getSymbol( units::Temperature ); string_view resVolUnit = units::getSymbol( units::ReservoirVolume ); tableData.addRow( "Statistics time", merge, merge, statsTime ); - m_aggregator.forRegionStatistics( mesh, - [&]( string_view regionName, RegionStatistics const & stats ) - { + // lamda to apply for each region statistics + auto const outputRegionStats = [&] ( string_view targetName, RegionStatistics & stats ) + { tableData.addRow( merge, merge, merge, "" ); tableData.addSeparator(); - tableData.addRow( merge, merge, merge, GEOS_FMT( "Region '{}'", regionName ) ); + tableData.addRow( merge, merge, merge, GEOS_FMT( "Region '{}'", targetName ) ); tableData.addRow( "statistics", "min", "average", "max" ); tableData.addSeparator(); @@ -283,7 +308,7 @@ void StatsTask::outputLogStats( real64 const statsTime, tableData.addRow( GEOS_FMT( "Phase dynamic pore volume [{}]", resVolUnit ), stringutilities::joinLambda( m_fluid.m_phaseNames, "\n", []( auto data ) { return data[0]; } ), CellType::MergeNext, - stringutilities::joinLambda( stats.m_phasePoreVolume, "\n", []( auto data ) { return data[0]; } ) ); + stringutilities::joinLambda( stats.m_phaseDynamicPoreVolume, "\n", []( auto data ) { return data[0]; } ) ); tableData.addSeparator(); @@ -322,24 +347,39 @@ void StatsTask::outputLogStats( real64 const statsTime, stringutilities::join( stats.m_componentMass, '\n' ) ); tableData.addSeparator(); + }; + + // apply the lambda for each region and, finally, the mesh summary + m_aggregator->forRegionStatistics( mesh, meshRegionsStatistics, + [&] ( CellElementRegion & region, RegionStatistics & stats ) + { + outputRegionStats( region.getName(), meshRegionsStatistics ); } ); + outputRegionStats( mesh.getName(), meshRegionsStatistics ); + // output to log GEOS_LOG_RANK_0( formatter.toString( tableData ) ); } void StatsTask::outputCsvStats( real64 statsTime, MeshLevel & mesh, - string_array const & ) + RegionStatistics & meshRegionsStatistics ) { if( MpiWrapper::commRank() > 0 || m_writeCSV == 0 ) return; - m_aggregator.forRegionStatistics( mesh, - [&]( string_view meshName, RegionStatistics const & stats ) + auto const formatterIter = m_csvFormatters.find( mesh.getName() ); + if( formatterIter==m_csvFormatters.end()) + return; + + TableCSVFormatter const & formatter = *formatterIter->second; + TableData tableData; + + // lamda to apply for each region statistics + auto const outputRegionStats = [&] ( string_view targetName, RegionStatistics & stats ) { - TableData tableData; stdVector< string > row; - row.reserve( m_csvFormatters.at( string( meshName ))->getLayout().getTotalLowermostColumnCount() ); + row.reserve( formatter.getLayout().getTotalLowermostColumnCount() ); auto addPhaseValues = []( auto & list, auto const & values ) { @@ -349,6 +389,7 @@ void StatsTask::outputCsvStats( real64 statsTime, row.insert( row.begin(), { std::to_string( statsTime ), + targetName, std::to_string( stats.m_minPressure ), std::to_string( stats.m_averagePressure ), std::to_string( stats.m_maxPressure ), @@ -359,7 +400,7 @@ void StatsTask::outputCsvStats( real64 statsTime, std::to_string( stats.m_maxTemperature ), std::to_string( stats.m_totalPoreVolume ), } ); - addPhaseValues( row, stats.m_phasePoreVolume ); + addPhaseValues( row, stats.m_phaseDynamicPoreVolume ); addPhaseValues( row, stats.m_phaseMass ); addPhaseValues( row, stats.m_trappedPhaseMass ); addPhaseValues( row, stats.m_nonTrappedPhaseMass ); @@ -367,11 +408,21 @@ void StatsTask::outputCsvStats( real64 statsTime, addPhaseValues( row, stats.m_mobilePhaseMass ); addPhaseValues( row, stats.m_componentMass ); // TODO verify phase / comp ordering - std::ofstream outputFile( getCsvFileName( mesh.getName() ), std::ios_base::app ); - TableCSVFormatter const csvOutput; - outputFile << csvOutput.dataToString( tableData ); - outputFile.close(); + tableData.addRow( row ); + }; + + // apply the lambda for each region and, finally, the mesh summary + m_aggregator->forRegionStatistics( mesh, meshRegionsStatistics, + [&] ( CellElementRegion & region, RegionStatistics & stats ) + { + outputRegionStats( region.getName(), meshRegionsStatistics ); } ); + outputRegionStats( mesh.getName(), meshRegionsStatistics ); + + // append to csv file + std::ofstream outputFile( getCsvFileName( mesh.getName() ), std::ios_base::app ); + outputFile << formatter.dataToString( tableData ); + outputFile.close(); } REGISTER_CATALOG_ENTRY( TaskBase, diff --git a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsTask.hpp b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsTask.hpp index 81be4446537..527822b67f1 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsTask.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsTask.hpp @@ -25,6 +25,7 @@ #include "common/format/table/TableLayout.hpp" #include "physicsSolvers/FieldStatisticsBase.hpp" #include "physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsAggregator.hpp" +#include namespace geos { @@ -86,7 +87,6 @@ class StatsTask : public FieldStatisticsBase< CompositionalMultiphaseBase > constexpr static char const * relpermThresholdString() { return "relpermThreshold"; } }; - void postInputInitialization() override; void registerDataOnMesh( Group & meshBodies ) override; @@ -101,11 +101,11 @@ class StatsTask : public FieldStatisticsBase< CompositionalMultiphaseBase > void outputLogStats( real64 statsTime, MeshLevel & mesh, - string_array const & regionNames ); + RegionStatistics & meshRegionsStatistics ); void outputCsvStats( real64 statsTime, MeshLevel & mesh, - string_array const & regionNames ); + RegionStatistics & meshRegionsStatistics ); /// For each discretization (MeshLevel name), table formatter for log output. stdMap< string, std::unique_ptr< TableTextFormatter > > m_logFormatters; @@ -113,7 +113,8 @@ class StatsTask : public FieldStatisticsBase< CompositionalMultiphaseBase > /// For each discretization (MeshLevel name), table formatter for csv output. stdMap< string, std::unique_ptr< TableCSVFormatter > > m_csvFormatters; - StatsAggregator m_aggregator; + // mesh statistics aggregator + std::unique_ptr< StatsAggregator > m_aggregator; /// Flag to decide whether CFL numbers are computed or not integer m_computeCFLNumbers; From 69dfad7f0ddceab3c178b01be98639150c788457 Mon Sep 17 00:00:00 2001 From: MelReyCG Date: Mon, 12 Jan 2026 14:46:18 +0100 Subject: [PATCH 13/28] =?UTF-8?q?=F0=9F=94=8A=20better=20messages=20&=20na?= =?UTF-8?q?ming?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dataRepository/DataContext.hpp | 6 +- ...sitionalMultiphaseStatisticsAggregator.cpp | 149 ++++++++---------- ...sitionalMultiphaseStatisticsAggregator.hpp | 10 +- .../CompositionalMultiphaseStatisticsTask.cpp | 4 +- 4 files changed, 80 insertions(+), 89 deletions(-) diff --git a/src/coreComponents/dataRepository/DataContext.hpp b/src/coreComponents/dataRepository/DataContext.hpp index 63b855e24f2..b4f70ac510b 100644 --- a/src/coreComponents/dataRepository/DataContext.hpp +++ b/src/coreComponents/dataRepository/DataContext.hpp @@ -78,7 +78,7 @@ class DataContext /** * @return Get the target object name */ - string getTargetName() const + string const & getTargetName() const { return m_targetName; } /** * @brief Insert contextual information in the provided stream. @@ -179,13 +179,13 @@ class DataFileContext final : public DataContext /** * @return the type name in the source file (XML node tag name / attribute name). */ - string getTypeName() const + string const & getTypeName() const { return m_typeName; } /** * @return the source file path where the target object has been declared. */ - string getFilePath() const + string const & getFilePath() const { return m_filePath; } /** diff --git a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsAggregator.cpp b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsAggregator.cpp index 142adffc13e..4ec27df6502 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsAggregator.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsAggregator.cpp @@ -16,58 +16,57 @@ /** * @file CompositionalMultiphaseStatistics.cpp * @details Region statistics data is stored as follow: - * - * Problem : geos::ProblemManager - * |-> domain : geos::DomainPartition - * |-> MeshBodies : geos::dataRepository::Group - * |-> cartesianMesh : geos::MeshBody - * |-> meshLevels : geos::dataRepository::Group - * |-> Level0 : geos::MeshLevel - * | |-> nodeManager : geos::NodeManager - * | | |-> sets : geos::dataRepository::Group - * | | | * all : geos::dataRepository::Wrapper< index array > - * | | | * xneg : geos::dataRepository::Wrapper< index array > + + * Problem : ProblemManager + * |-> domain : DomainPartition + * |-> MeshBodies : Group + * |-> cartesianMesh : MeshBody + * |-> meshLevels : Group + * |-> Level0 : MeshLevel + * | |-> nodeManager : NodeManager + * | | |-> sets : Group + * | | | * all : Wrapper< index array > + * | | | * xneg : Wrapper< index array > * | | [...] (other element sets) * | | - * | |-> ElementRegions : geos::ElementRegionManager - * | | |-> Channel : geos::CellElementRegion - * | | | |-> cb-0_0_0 : geos::CellElementSubRegion - * | | | | | * pressure : geos::dataRepository::Wrapper< real64 array > - * | | | | | * temperature : geos::dataRepository::Wrapper< real64 array > + * | |-> ElementRegions : ElementRegionManager + * | | |-> Channel : CellElementRegion + * | | | |-> cb-0_0_0 : CellElementSubRegion + * | | | | | * pressure : Wrapper< real64 array > + * | | | | | * temperature : Wrapper< real64 array > * | | | | [...] (other fields) * | | | | - * | | | |-> cb-0_0_1 : geos::CellElementSubRegion - * | | | | | * pressure : geos::dataRepository::Wrapper< real64 array > - * | | | | | * temperature : geos::dataRepository::Wrapper< real64 array > + * | | | |-> cb-0_0_1 : CellElementSubRegion + * | | | | | * pressure : Wrapper< real64 array > + * | | | | | * temperature : Wrapper< real64 array > * | | | | [...] (other fields) * | | | | * | | | [...] (other sub-regions) * | | | - * | | |-> Barrier : geos::CellElementRegion - * | | |-> cb-1_0_0 : geos::CellElementSubRegion - * | | |-> cb-1_0_1 : geos::CellElementSubRegion + * | | |-> Barrier : CellElementRegion + * | | |-> cb-1_0_0 : CellElementSubRegion + * | | |-> cb-1_0_1 : CellElementSubRegion * | | [...] (other sub-regions) * | | * | [...] (other element managers) * ____ | | - * | | |-> statistics : geos::dataRepository::Group (storage for all stats) - * | | |-> compFlowStats : geos::dataRepository::Group (storage for this instance stats) - * | | | |-> cflStatistics : geos::compositionalMultiphaseStatistics::CFLStatistics - * | | | |-> regionsStatistics : geos::compositionalMultiphaseStatistics::RegionStatistics (aggregate) - * | | | |-> Channel : geos::compositionalMultiphaseStatistics::RegionStatistics (aggregate, mpi reduced) - * | | | | |-> cb-0_0_0 : geos::compositionalMultiphaseStatistics::RegionStatistics (compute read-back) - * stats | | | | |-> cb-0_0_1 : geos::compositionalMultiphaseStatistics::RegionStatistics (compute read-back) + * | | |-> statistics : Group (storage for all stats) + * | | |-> compFlowStats : Group (storage for this instance stats) + * | | | |-> cflStatistics : CFLStatistics + * | | | |-> regionsStatistics : RegionStatistics (aggregate) + * | | | |-> Channel : RegionStatistics (aggregate, mpi reduced) + * | | | | |-> cb-0_0_0 : RegionStatistics (compute read-back) + * stats | | | | |-> cb-0_0_1 : RegionStatistics (compute read-back) * data -> | | | | [...] (other sub-regions stats) * | | | | - * | | | |-> Barrier : geos::compositionalMultiphaseStatistics::RegionStatistics (aggregate, mpi reduced) - * | | | |-> cb-1_0_0 : geos::compositionalMultiphaseStatistics::RegionStatistics (compute read-back) - * | | | |-> cb-1_0_1 : geos::compositionalMultiphaseStatistics::RegionStatistics (compute read-back) + * | | | |-> Barrier : RegionStatistics (aggregate, mpi reduced) + * | | | |-> cb-1_0_0 : RegionStatistics (compute read-back) + * | | | |-> cb-1_0_1 : RegionStatistics (compute read-back) * | | | [...] (other sub-regions stats) * | | | * |___ | [...] (other stats storages) * | * [...] (other discretizations) - * */ #include "CompositionalMultiphaseStatisticsAggregator.hpp" @@ -76,6 +75,7 @@ #include "common/DataTypes.hpp" #include "common/format/Format.hpp" #include "common/logger/Logger.hpp" +#include "dataRepository/DataContext.hpp" #include "dataRepository/Group.hpp" #include "mesh/CellElementRegion.hpp" #include "mesh/CellElementSubRegion.hpp" @@ -83,10 +83,8 @@ #include "mesh/MeshLevel.hpp" #include "physicsSolvers/fluidFlow/CompositionalMultiphaseBase.hpp" #include "physicsSolvers/fluidFlow/kernels/compositional/StatisticsKernel.hpp" -#include "physicsSolvers/LogLevelsInfo.hpp" #include "constitutive/relativePermeability/RelativePermeabilityBase.hpp" #include -#include namespace geos @@ -99,9 +97,9 @@ using namespace constitutive; // using namespace fields; using namespace dataRepository; -StatsAggregator::StatsAggregator( string_view ownerName ): +StatsAggregator::StatsAggregator( DataContext const & ownerDataContext ): m_params(), - m_ownerName( ownerName ) + m_ownerDataContext( ownerDataContext ) {} void StatsAggregator::initStatisticsAggregation( dataRepository::Group & meshBodies, @@ -117,15 +115,16 @@ void StatsAggregator::initStatisticsAggregation( dataRepository::Group & meshBod string_array const & ) { // getting the container of all requesters statistics groups (can be already initialized) - Group * allStatisticsGroup = mesh.getGroupPointer( ViewKeys::statisticsString() ); - if( allStatisticsGroup == nullptr ) - allStatisticsGroup = &mesh.registerGroup( ViewKeys::statisticsString() ); + Group * meshStatsGroup = mesh.getGroupPointer( ViewKeys::statisticsString() ); + if( meshStatsGroup == nullptr ) + meshStatsGroup = &mesh.registerGroup( ViewKeys::statisticsString() ); // registering the container of instance statistics groups (must be unique for this instance) - GEOS_ERROR_IF_NE_MSG( allStatisticsGroup->hasGroup( m_ownerName ), false, - GEOS_FMT( "A statistics aggregator have already been requested for '{}'.", - m_ownerName ) ); - allStatisticsGroup->registerGroup( m_ownerName ); + string const & ownerName = getOwnerName(); + GEOS_ERROR_IF_NE_MSG( meshStatsGroup->hasGroup( ownerName ), false, + "A statistics aggregator have already been requested.", + m_ownerDataContext ); + meshStatsGroup->registerGroup( ownerName ); } ); } @@ -134,6 +133,9 @@ void StatsAggregator::enableRegionStatisticsAggregation( dataRepository::Group & if( m_solver == nullptr ) return; + integer regionCount = 0; + integer subRegionCount = 0; + auto const registerStats = [=] ( Group & parent, string const & name, string const & targetName ) -> RegionStatistics & @@ -150,14 +152,15 @@ void StatsAggregator::enableRegionStatisticsAggregation( dataRepository::Group & { ElementRegionManager & elemManager = mesh.getElemManager(); Group & statisticsGroup = getInstanceStatisticsGroup( mesh ); - RegionStatistics & allRegionsStats = registerStats( statisticsGroup, + RegionStatistics & meshRegionsStats = registerStats( statisticsGroup, ViewKeys::regionsStatisticsString(), mesh.getName() ); for( size_t i = 0; i < regionNames.size(); ++i ) + { CellElementRegion & region = elemManager.getRegion< CellElementRegion >( regionNames[i] ); - RegionStatistics & regionStats = registerStats( allRegionsStats, + RegionStatistics & regionStats = registerStats( meshRegionsStats, GEOS_FMT( "{}_region_stats", region.getName() ), region.getName() ); @@ -166,10 +169,17 @@ void StatsAggregator::enableRegionStatisticsAggregation( dataRepository::Group & registerStats( regionStats, GEOS_FMT( "{}_subRegion_stats", subRegion.getName() ), subRegion.getName() ); + ++subRegionCount; } ); + ++regionCount; } } ); + GEOS_ERROR_IF( regionCount == 0 || subRegionCount == 0, + GEOS_FMT( "Missing region for computing statistics:\n- {} regions,\n- {} sub-regions.", + getOwnerName(), regionCount, subRegionCount ), + m_ownerDataContext ); + m_isRegionStatsEnabled = true; } @@ -193,8 +203,8 @@ void StatsAggregator::enableCFLStatistics( dataRepository::Group & meshBodies ) Group & StatsAggregator::getInstanceStatisticsGroup( MeshLevel & mesh ) const { // considering everything is initialized, or else, crash gracefully - Group & allStatisticsGroup = mesh.getGroup( ViewKeys::statisticsString() ); - Group & instanceStatisticsGroup = allStatisticsGroup.getGroup( m_ownerName ); + Group & meshStatsGroup = mesh.getGroup( ViewKeys::statisticsString() ); + Group & instanceStatisticsGroup = meshStatsGroup.getGroup( getOwnerName() ); return instanceStatisticsGroup; } @@ -220,9 +230,9 @@ void StatsAggregator::forRegionStatistics( dataRepository::Group & meshBodies, string_array const & ) { Group & instanceStats = getInstanceStatisticsGroup( mesh ); - RegionStatistics & allRegionsStats = getRegionsStatisticsGroup( mesh ); + RegionStatistics & meshRegionsStats = getRegionsStatisticsGroup( mesh ); - func( mesh, allRegionsStats ); + func( mesh, meshRegionsStats ); } ); } @@ -260,9 +270,9 @@ bool StatsAggregator::computeRegionsStatistics( real64 const time, Group & meshB forRegionStatistics( meshBodies, [&, time] ( MeshLevel & mesh, RegionStatistics & regionStats ) { - RegionStatistics & allRegionsStats = getRegionsStatisticsGroup( mesh ); + RegionStatistics & meshRegionsStats = getRegionsStatisticsGroup( mesh ); forRegionStatistics( mesh, - allRegionsStats, + meshRegionsStats, [&, time] ( CellElementRegion & region, RegionStatistics & regionStats ) { forRegionStatistics( region, @@ -279,11 +289,11 @@ bool StatsAggregator::computeRegionsStatistics( real64 const time, Group & meshB forRegionStatistics( meshBodies, [&, time] ( MeshLevel & mesh, RegionStatistics & regionStats ) { - RegionStatistics & allRegionsStats = getRegionsStatisticsGroup( mesh ); - initStats( allRegionsStats, time ); + RegionStatistics & meshRegionsStats = getRegionsStatisticsGroup( mesh ); + initStats( meshRegionsStats, time ); forRegionStatistics( mesh, - allRegionsStats, + meshRegionsStats, [&, time] ( CellElementRegion & region, RegionStatistics & regionStats ) { initStats( regionStats, time ); @@ -298,37 +308,16 @@ bool StatsAggregator::computeRegionsStatistics( real64 const time, Group & meshB postAggregateStats( subRegionStats ); } ); - aggregateStats( allRegionsStats, regionStats ); + aggregateStats( meshRegionsStats, regionStats ); mpiAggregateStats( regionStats ); postAggregateStats( regionStats ); } ); - mpiAggregateStats( allRegionsStats ); - postAggregateStats( allRegionsStats ); + mpiAggregateStats( meshRegionsStats ); + postAggregateStats( meshRegionsStats ); } ); - // stdVector< string > phaseCompName; - // phaseCompName.reserve( numPhases*numComps ); - // stdVector< string > massValues; - // phaseCompName.reserve( numPhases*numComps ); - - // ConstitutiveManager const & constitutiveManager = mesh.getGroupByPath< ConstitutiveManager >( "/Problem/domain/Constitutive" ); - // MultiFluidBase const & fluid = constitutiveManager.getGroup< MultiFluidBase >( m_solver->referenceFluidModelName() ); - // auto const phaseNames = fluid.phaseNames(); - // auto const componentNames = fluid.componentNames(); - // for( integer ip = 0; ip < numPhases; ++ip ) - // { - // for( integer ic = 0; ic < numComps; ++ic ) - // { - // std::stringstream ss; - // ss << phaseNames[ip] << "/" << componentNames[ic]; - // phaseCompName.push_back( ss.str() ); - // massValues.push_back( GEOS_FMT( "{}", stats.m_componentMass[ip][ic] ) ); - // } - // } - // } - return true; } @@ -493,7 +482,7 @@ void StatsAggregator::postAggregateStats( RegionStatistics & stats ) stats.m_averagePressure = 0.0; stats.m_averageTemperature = 0.0; m_warnings.emplace_back( GEOS_FMT( "Cannot compute average pressure for '{}' because pore volume is zero in '{}'.", - m_ownerName, stats.getTargetName() ) ); + getOwnerName(), stats.getTargetName() ) ); } for( integer ip = 0; ip < m_numPhases; ++ip ) diff --git a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsAggregator.hpp b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsAggregator.hpp index a9f26f7a932..db921eaf889 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsAggregator.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsAggregator.hpp @@ -22,10 +22,12 @@ #include "common/DataTypes.hpp" #include "common/StdContainerWrappers.hpp" +#include "dataRepository/DataContext.hpp" #include "dataRepository/Group.hpp" #include "mesh/CellElementRegion.hpp" #include "mesh/DomainPartition.hpp" #include "mesh/MeshLevel.hpp" +#include namespace geos { @@ -185,7 +187,7 @@ class StatsAggregator * @param ownerName the unique name of the entity requesting the statistics. * An error is thrown if not unique in this context. */ - StatsAggregator( string_view ownerName ); + StatsAggregator( dataRepository::DataContext const & ownerDataContext ); /** * @brief Enable the computation of any statistics, initialize data structure to collect them. @@ -259,8 +261,8 @@ class StatsAggregator /** * @return the name of the entity requesting the statistics. */ - string_view getOwnerName() const - { return m_ownerName; } + string const & getOwnerName() const + { return m_ownerDataContext.getTargetName(); } integer getNumPhases() const { return m_numPhases; } @@ -277,7 +279,7 @@ class StatsAggregator stdVector< string > m_warnings; /// @see getOwnerName() - string m_ownerName; + dataRepository::DataContext const & m_ownerDataContext; bool m_isRegionStatsEnabled = false; diff --git a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsTask.cpp b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsTask.cpp index 69d99771e5d..33bfaf7259d 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsTask.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsTask.cpp @@ -101,7 +101,7 @@ void StatsTask::postInputInitialization() InputError ); } - m_aggregator = std::make_unique< StatsAggregator >( getName() ); + m_aggregator = std::make_unique< StatsAggregator >( getDataContext() ); } void StatsTask::registerDataOnMesh( Group & meshBodies ) @@ -389,7 +389,7 @@ void StatsTask::outputCsvStats( real64 statsTime, row.insert( row.begin(), { std::to_string( statsTime ), - targetName, + string( targetName ), std::to_string( stats.m_minPressure ), std::to_string( stats.m_averagePressure ), std::to_string( stats.m_maxPressure ), From 55c0eeb7979a3f17b15f48702cfbd5fb867749bc Mon Sep 17 00:00:00 2001 From: MelReyCG Date: Mon, 12 Jan 2026 15:16:15 +0100 Subject: [PATCH 14/28] =?UTF-8?q?=E2=99=BB=EF=B8=8Fcontinue=20refactorings?= =?UTF-8?q?=20before=20solvers=20usages?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...sitionalMultiphaseStatisticsAggregator.cpp | 28 +++++++++++++------ ...sitionalMultiphaseStatisticsAggregator.hpp | 14 ++++++---- 2 files changed, 28 insertions(+), 14 deletions(-) diff --git a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsAggregator.cpp b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsAggregator.cpp index 4ec27df6502..b0c2f620584 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsAggregator.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsAggregator.cpp @@ -153,11 +153,10 @@ void StatsAggregator::enableRegionStatisticsAggregation( dataRepository::Group & ElementRegionManager & elemManager = mesh.getElemManager(); Group & statisticsGroup = getInstanceStatisticsGroup( mesh ); RegionStatistics & meshRegionsStats = registerStats( statisticsGroup, - ViewKeys::regionsStatisticsString(), - mesh.getName() ); + ViewKeys::regionsStatisticsString(), + mesh.getName() ); for( size_t i = 0; i < regionNames.size(); ++i ) - { CellElementRegion & region = elemManager.getRegion< CellElementRegion >( regionNames[i] ); RegionStatistics & regionStats = registerStats( meshRegionsStats, @@ -208,18 +207,29 @@ Group & StatsAggregator::getInstanceStatisticsGroup( MeshLevel & mesh ) const return instanceStatisticsGroup; } -RegionStatistics & StatsAggregator::getRegionsStatisticsGroup( MeshLevel & mesh ) const +RegionStatistics & StatsAggregator::getMeshRegionsStatistics( MeshLevel & mesh ) const { // considering everything is initialized, or else, crash gracefully Group & instanceStatisticsGroup = getInstanceStatisticsGroup( mesh ); return instanceStatisticsGroup.getGroup< RegionStatistics >( ViewKeys::regionsStatisticsString() ); } +RegionStatistics & StatsAggregator::getRegionStatistics( MeshLevel & mesh, string_view regionName ) const +{ + RegionStatistics & meshRegionsStats = getMeshRegionsStatistics( mesh ); + RegionStatistics * regionStats = meshRegionsStats.getGroupPointer< RegionStatistics >( regionName ); + GEOS_THROW_IF( regionStats == nullptr, + GEOS_FMT( "Region '{}' not found to get region statistics, is it a target of the reservoir solver?", + regionName ), + InputError, m_ownerDataContext ); + return *regionStats; +} + CFLStatistics & StatsAggregator::getCflStatisticsGroup( MeshLevel & mesh ) const { // considering everything is initialized, or else, crash gracefully - Group & instanceStatisticsGroup = getInstanceStatisticsGroup( mesh ); - return instanceStatisticsGroup.getGroup< CFLStatistics >( ViewKeys::cflStatisticsString() ); + Group & statisticsGroup = getInstanceStatisticsGroup( mesh ); + return statisticsGroup.getGroup< CFLStatistics >( ViewKeys::cflStatisticsString() ); } void StatsAggregator::forRegionStatistics( dataRepository::Group & meshBodies, @@ -230,7 +240,7 @@ void StatsAggregator::forRegionStatistics( dataRepository::Group & meshBodies, string_array const & ) { Group & instanceStats = getInstanceStatisticsGroup( mesh ); - RegionStatistics & meshRegionsStats = getRegionsStatisticsGroup( mesh ); + RegionStatistics & meshRegionsStats = getMeshRegionsStatistics( mesh ); func( mesh, meshRegionsStats ); } ); @@ -270,7 +280,7 @@ bool StatsAggregator::computeRegionsStatistics( real64 const time, Group & meshB forRegionStatistics( meshBodies, [&, time] ( MeshLevel & mesh, RegionStatistics & regionStats ) { - RegionStatistics & meshRegionsStats = getRegionsStatisticsGroup( mesh ); + RegionStatistics & meshRegionsStats = getMeshRegionsStatistics( mesh ); forRegionStatistics( mesh, meshRegionsStats, [&, time] ( CellElementRegion & region, RegionStatistics & regionStats ) @@ -289,7 +299,7 @@ bool StatsAggregator::computeRegionsStatistics( real64 const time, Group & meshB forRegionStatistics( meshBodies, [&, time] ( MeshLevel & mesh, RegionStatistics & regionStats ) { - RegionStatistics & meshRegionsStats = getRegionsStatisticsGroup( mesh ); + RegionStatistics & meshRegionsStats = getMeshRegionsStatistics( mesh ); initStats( meshRegionsStats, time ); forRegionStatistics( mesh, diff --git a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsAggregator.hpp b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsAggregator.hpp index db921eaf889..73fd8a8e880 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsAggregator.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsAggregator.hpp @@ -259,7 +259,7 @@ class StatsAggregator { return m_warnings; } /** - * @return the name of the entity requesting the statistics. + * @return the name of the entity that needs the statistics. */ string const & getOwnerName() const { return m_ownerDataContext.getTargetName(); } @@ -270,6 +270,14 @@ class StatsAggregator integer getNumComponents() const { return m_numComponents; } + dataRepository::Group & getInstanceStatisticsGroup( MeshLevel & mesh ) const; + + RegionStatistics & getMeshRegionsStatistics( MeshLevel & mesh ) const; + + RegionStatistics & getRegionStatistics( MeshLevel & mesh, string_view regionNname ) const; + + CFLStatistics & getCflStatisticsGroup( MeshLevel & mesh ) const; + private: CompositionalMultiphaseBase * m_solver; @@ -289,10 +297,6 @@ class StatsAggregator integer m_numComponents; - dataRepository::Group & getInstanceStatisticsGroup( MeshLevel & mesh ) const; - RegionStatistics & getRegionsStatisticsGroup( MeshLevel & mesh ) const; - CFLStatistics & getCflStatisticsGroup( MeshLevel & mesh ) const; - /** * @brief Initialize all statistics values to aggregable default values, * before any computation / reduction for the current timestep. From ccfede64f34aec9755d409dd6b4b089af1375639 Mon Sep 17 00:00:00 2001 From: MelReyCG Date: Mon, 12 Jan 2026 15:43:09 +0100 Subject: [PATCH 15/28] =?UTF-8?q?=F0=9F=93=9D=20a=20bit=20of=20docs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../CompositionalMultiphaseStatisticsAggregator.hpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsAggregator.hpp b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsAggregator.hpp index 73fd8a8e880..77275c1f6e1 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsAggregator.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsAggregator.hpp @@ -273,8 +273,15 @@ class StatsAggregator dataRepository::Group & getInstanceStatisticsGroup( MeshLevel & mesh ) const; RegionStatistics & getMeshRegionsStatistics( MeshLevel & mesh ) const; - - RegionStatistics & getRegionStatistics( MeshLevel & mesh, string_view regionNname ) const; + + /** + * @brief TODO + * @throw InputError if no statistics data is found for the given region name. + * @param mesh TODO + * @param regionNname TODO + * @return TODO + */ + RegionStatistics & getRegionStatistics( MeshLevel & mesh, string_view regionName ) const; CFLStatistics & getCflStatisticsGroup( MeshLevel & mesh ) const; From f92b9f78cb8dabdcd5a68cabe5e8504e7eb12beb Mon Sep 17 00:00:00 2001 From: MelReyCG Date: Mon, 12 Jan 2026 15:53:31 +0100 Subject: [PATCH 16/28] =?UTF-8?q?=F0=9F=9A=A7=20draft=20of=20application?= =?UTF-8?q?=20on=20well=20solvers?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .clangd | 23 ++++ .../wells/CompositionalMultiphaseWell.cpp | 102 ++++++++++-------- .../wells/CompositionalMultiphaseWell.hpp | 7 ++ 3 files changed, 85 insertions(+), 47 deletions(-) create mode 100644 .clangd diff --git a/.clangd b/.clangd new file mode 100644 index 00000000000..6e903480907 --- /dev/null +++ b/.clangd @@ -0,0 +1,23 @@ +CompileFlags: + Add: + - -I/data/pau901/SIM_CS/04_WORKSPACE/USERS/MelvinRey/WorkEnv/GEOSX_repos/GEOS/src/coreComponents + - -I/data/pau901/SIM_CS/04_WORKSPACE/USERS/MelvinRey/WorkEnv/GEOSX_repos/GEOS/src/coreComponents/linearAlgebra + - -I/data/pau901/SIM_CS/04_WORKSPACE/USERS/MelvinRey/WorkEnv/GEOSX_repos/GEOS/src/cmake/blt/thirdparty_builtin/googletest/googletest/include + - -I/data/pau901/SIM_CS/04_WORKSPACE/USERS/MelvinRey/WorkEnv/GEOSX_repos/GEOS/build-develop/include + - -I/data/pau901/SIM_CS/04_WORKSPACE/USERS/MelvinRey/WorkEnv/GEOSX_repos/thirdPartyLibs/install-master/build_stage/l1092082/spack-stage-raja-git.1d70abf171474d331f1409908bdf1b1c3fe19222_develop-dfj5hwwhvr4v32yxbduwrv2x4izvriez/spack-src/include + - -I/data/pau901/SIM_CS/04_WORKSPACE/USERS/MelvinRey/WorkEnv/GEOSX_repos/thirdPartyLibs/install-master/gcc-12.2.1/raja-git.1d70abf171474d331f1409908bdf1b1c3fe19222_develop-dfj5hwwhvr4v32yxbduwrv2x4izvriez/.spack/spack-build-dfj5hww/include + - -I/data/pau901/SIM_CS/04_WORKSPACE/USERS/MelvinRey/WorkEnv/GEOSX_repos/thirdPartyLibs/install-master/build_stage/l1092082/spack-stage-camp-git.ee0a3069a7ae72da8bcea63c06260fad34901d43_main-7wyhilu22frfttymb3dgrvaubocr3igk/spack-src/include + - -I/data/pau901/SIM_CS/04_WORKSPACE/USERS/MelvinRey/WorkEnv/GEOSX_repos/thirdPartyLibs/install-master/build_stage/l1092082/spack-stage-camp-git.ee0a3069a7ae72da8bcea63c06260fad34901d43_main-7wyhilu22frfttymb3dgrvaubocr3igk/spack-build-7wyhilu/include + - -I/data/pau901/SIM_CS/04_WORKSPACE/USERS/MelvinRey/WorkEnv/GEOSX_repos/thirdPartyLibs/install-master/build_stage/l1092082/spack-stage-fmt-10.0.0-2ckd7w7qbgdr2ysc2uybihnao6ngqtox/spack-src/include + - -I/data/pau901/SIM_CS/04_WORKSPACE/USERS/MelvinRey/WorkEnv/GEOSX_repos/thirdPartyLibs/install-master/build_stage/l1092082/spack-stage-umpire-git.1ed0669c57f041baa1f1070693991c3a7a43e7ee_develop-orylmsm4ynx3tffjsyablcrrb7xeqr75/spack-src/src + - -I/data/pau901/SIM_CS/04_WORKSPACE/USERS/MelvinRey/WorkEnv/GEOSX_repos/thirdPartyLibs/install-master/build_stage/l1092082/spack-stage-umpire-git.1ed0669c57f041baa1f1070693991c3a7a43e7ee_develop-orylmsm4ynx3tffjsyablcrrb7xeqr75/spack-build-orylmsm/include + - -I/data/pau901/SIM_CS/04_WORKSPACE/USERS/MelvinRey/WorkEnv/GEOSX_repos/thirdPartyLibs/install-master/gcc-12.2.1/umpire-git.1ed0669c57f041baa1f1070693991c3a7a43e7ee_develop-orylmsm4ynx3tffjsyablcrrb7xeqr75/include + - -I/data/pau901/SIM_CS/04_WORKSPACE/USERS/MelvinRey/WorkEnv/GEOSX_repos/thirdPartyLibs/install-master/gcc-12.2.1/chai-git.4b9060b18b9bec1167026cfb3132bd540c4bd56b_develop-kebrblc66x6zw5hvdcbh46kgnpua77n3/include + - -I/data/pau901/SIM_CS/04_WORKSPACE/USERS/MelvinRey/WorkEnv/GEOSX_repos/thirdPartyLibs/install-master/gcc-12.2.1/vtk-9.4.2-cyy6bpea5gfinatsqlbral2d6f5voaob/include/vtk-9.4 + - -I/data/pau901/SIM_CS/04_WORKSPACE/USERS/MelvinRey/WorkEnv/GEOSX_repos/thirdPartyLibs/install-master/build_stage/l1092082/spack-stage-vtk-9.4.2-cyy6bpea5gfinatsqlbral2d6f5voaob/spack-src/ThirdParty/pugixml/vtkpugixml/src + - -I/data/pau901/SIM_CS/04_WORKSPACE/USERS/MelvinRey/WorkEnv/GEOSX_repos/thirdPartyLibs/install-master/build_stage/l1092082/spack-stage-vtk-9.4.2-cyy6bpea5gfinatsqlbral2d6f5voaob/spack-build-cyy6bpe/ThirdParty/pugixml/vtkpugixml/src + - -I/data/pau901/SIM_CS/04_WORKSPACE/USERS/MelvinRey/WorkEnv/GEOSX_repos/thirdPartyLibs/install-master/build_stage/l1092082/spack-stage-caliper-git.287b7f3ad2d12f520aad04268d44f353cd05403c_2.12.0-f3wivxbfbxrtiz2siwdgvm2l27cqec4j/spack-src/include + - -I/data/pau901/SIM_CS/04_WORKSPACE/USERS/MelvinRey/WorkEnv/GEOSX_repos/thirdPartyLibs/install-master/build_stage/l1092082/spack-stage-conduit-git.ad86e316ad56a75c099d30ca5ce75cff275b5924_develop-zu4a2kq24d4vq6sx2iv2wxzjvw6gu6sv/spack-src/src/libs/conduit + - -I/data/pau901/SIM_CS/04_WORKSPACE/USERS/MelvinRey/WorkEnv/GEOSX_repos/thirdPartyLibs/install-master/build_stage/l1092082/spack-stage-conduit-git.ad86e316ad56a75c099d30ca5ce75cff275b5924_develop-zu4a2kq24d4vq6sx2iv2wxzjvw6gu6sv/spack-build-zu4a2kq/libs/conduit + - -I/data/pau901/SIM_CS/04_WORKSPACE/USERS/MelvinRey/WorkEnv/GEOSX_repos/thirdPartyLibs/install-master/build_stage/l1092082/spack-stage-parmetis-4.0.3-7mo5p53bnnfmnfiuivjt4guunnu35teh/spack-src/include + - -I/data/pau901/SIM_CS/04_WORKSPACE/USERS/MelvinRey/WorkEnv/GEOSX_repos/thirdPartyLibs/install-master/build_stage/l1092082/spack-stage-scotch-*/spack-build-*/src/include diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp index befc8a11e1f..fb4542efdad 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp @@ -22,6 +22,7 @@ #include "codingUtilities/Utilities.hpp" #include "common/DataTypes.hpp" #include "common/TimingMacros.hpp" +#include "common/logger/Logger.hpp" #include "constitutive/ConstitutiveManager.hpp" #include "constitutive/fluid/multifluid/MultiFluidBase.hpp" #include "constitutive/fluid/multifluid/MultiFluidFields.hpp" @@ -60,6 +61,7 @@ namespace geos using namespace dataRepository; using namespace constitutive; using namespace fields; +using namespace compositionalMultiphaseStatistics; CompositionalMultiphaseWell::CompositionalMultiphaseWell( const string & name, Group * const parent ) @@ -433,31 +435,17 @@ void CompositionalMultiphaseWell::validateWellConstraints( real64 const & time_n WellElementSubRegion const & subRegion ) { WellControls & wellControls = getWellControls( subRegion ); + if( !wellControls.useSurfaceConditions() ) { - bool const useSeg =wellControls.referenceReservoirRegion().empty(); - GEOS_WARNING_IF( useSeg, + bool const useSegmentValues = wellControls.referenceReservoirRegion().empty(); + GEOS_WARNING_IF( useSegmentValues, "WellControls " <( getFlowSolverName() ); - string_array const & targetRegionsNames = flowSolver.getTargetRegionNames(); - auto const pos = std::find( targetRegionsNames.begin(), targetRegionsNames.end(), regionName ); - GEOS_ERROR_IF( pos == targetRegionsNames.end(), - GEOS_FMT( "{}: Region {} is not a target of the reservoir solver and cannot be used for referenceReservoirRegion in WellControl {}.", - getDataContext(), regionName, wellControls.getName() ) ); - - - } + GEOS_ERROR_IF( !useSegmentValues && !m_reservoirStatsAggregator, + "A stats aggregator should have been initialized in this scenario", getDataContext()); } + string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString()); MultiFluidBase const & fluid = subRegion.getConstitutiveModel< MultiFluidBase >( fluidName ); @@ -729,34 +717,54 @@ void CompositionalMultiphaseWell::updateVolRatesForConstraint( ElementRegionMana } else { - GEOS_UNUSED_VAR(elemManager); - // if( !wellControls.referenceReservoirRegion().empty() ) - // { - // ElementRegionBase const & region = elemManager.getRegion( wellControls.referenceReservoirRegion()); - // GEOS_ERROR_IF ( !region.hasWrapper( CompositionalMultiphaseStatistics::regionStatisticsName() ), - // GEOS_FMT( "{}: WellControl {} referenceReservoirRegion field requires CompositionalMultiphaseStatistics to be configured for region {} ", - // getDataContext(), wellControls.getName(), wellControls.referenceReservoirRegion() ) ); - - // CompositionalMultiphaseStatistics::RegionStatistics const & stats = region.getReference< CompositionalMultiphaseStatistics::RegionStatistics >( - // CompositionalMultiphaseStatistics::regionStatisticsName() ); - // wellControls.setRegionAveragePressure( stats.averagePressure ); - // wellControls.setRegionAverageTemperature( stats.averageTemperature ); - // GEOS_ERROR_IF( stats.averagePressure <= 0.0, - // GEOS_FMT( "{}: No region average quantities computed. WellControl {} referenceReservoirRegion field requires CompositionalMultiphaseStatistics to be configured for region {} ", - // getDataContext(), wellControls.getName(), wellControls.referenceReservoirRegion() )); - // } - // If flashPressure is not set by region the value is defaulted to -1 and indicates to use top segment conditions - flashPressure = wellControls.getRegionAveragePressure(); - if( flashPressure < 0.0 ) + GEOS_UNUSED_VAR( elemManager ); + bool const useSegmentValues = wellControls.referenceReservoirRegion().empty(); + + if( useSegmentValues ) { - // region name not set, use segment conditions - flashPressure = pres[iwelemRef]; - flashTemperature = temp[iwelemRef]; + wellControls.setRegionAveragePressure( -1 ); + wellControls.setRegionAverageTemperature( -1 ); } else { - // use reservoir region averages - flashTemperature = wellControls.getRegionAverageTemperature(); + + // TODO use m_reservoirStatsAggregator + + // if( !wellControls.referenceReservoirRegion().empty() ) + // { + // ElementRegionBase const & region = elemManager.getRegion( wellControls.referenceReservoirRegion()); + // GEOS_ERROR_IF ( !region.hasWrapper( CompositionalMultiphaseStatistics::regionStatisticsName() ), + // GEOS_FMT( "{}: WellControl {} referenceReservoirRegion field requires CompositionalMultiphaseStatistics to be + // configured for region {} ", + // getDataContext(), wellControls.getName(), wellControls.referenceReservoirRegion() ) ); + + // will throw an exception if non-existing + // m_reservoirStatsAggregator->getRegionStatistics( subRegion., wellControls.referenceReservoirRegion() ) + + // CompositionalMultiphaseStatistics::RegionStatistics const & stats = region.getReference< + // CompositionalMultiphaseStatistics::RegionStatistics >( + // CompositionalMultiphaseStatistics::regionStatisticsName() ); + // wellControls.setRegionAveragePressure( stats.averagePressure ); + // wellControls.setRegionAverageTemperature( stats.averageTemperature ); + // GEOS_ERROR_IF( stats.averagePressure <= 0.0, + // GEOS_FMT( "{}: No region average quantities computed. WellControl {} referenceReservoirRegion field requires + // CompositionalMultiphaseStatistics to be configured for region {} ", + // getDataContext(), wellControls.getName(), wellControls.referenceReservoirRegion() )); + // } + + // If flashPressure is not set by region the value is defaulted to -1 and indicates to use top segment conditions + flashPressure = wellControls.getRegionAveragePressure(); + if( flashPressure < 0.0 ) + { + // region name not set, use segment conditions + flashPressure = pres[iwelemRef]; + flashTemperature = temp[iwelemRef]; + } + else + { + // use reservoir region averages + flashTemperature = wellControls.getRegionAverageTemperature(); + } } } arrayView1d< real64 > const & currentPhaseVolRate = @@ -1113,7 +1121,7 @@ void CompositionalMultiphaseWell::initializeWells( DomainPartition & domain, rea numComp, numPhase, wellControls, - 0.0, // initialization done at t = 0 + 0.0, // initialization done at t = 0 resCompFlowAccessors.get( flow::pressure{} ), resCompFlowAccessors.get( flow::temperature{} ), resCompFlowAccessors.get( flow::globalCompDensity{} ), @@ -1363,8 +1371,8 @@ void CompositionalMultiphaseWell::assembleAccumulationTerms( real64 const & time } } ); } - } ); // forElementSubRegions - } ); // forDiscretizationOnMeshTargets + } ); // forElementSubRegions + } ); // forDiscretizationOnMeshTargets } diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.hpp index cb8ed9f1a6f..9102c892769 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.hpp @@ -34,6 +34,11 @@ class ConstitutiveManager; class MultiFluidBase; } +namespace compositionalMultiphaseStatistics +{ +class StatsAggregator; +} + /** * @class CompositionalMultiphaseWell * @@ -398,6 +403,8 @@ class CompositionalMultiphaseWell : public WellSolverBase /// index of the target phase, used to impose the phase rate constraint localIndex m_targetPhaseIndex; + /// optional statistics aggregator to get the average pressure of simulated region + std::unique_ptr< compositionalMultiphaseStatistics::StatsAggregator > m_reservoirStatsAggregator; }; From c295ff7733b149f7a6df3ea9d30d12e14dba0b1e Mon Sep 17 00:00:00 2001 From: MelReyCG Date: Mon, 12 Jan 2026 16:12:37 +0100 Subject: [PATCH 17/28] =?UTF-8?q?=E2=99=BB=EF=B8=8Felement=20manager=20->?= =?UTF-8?q?=20meshlevel=20in=20parameters?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../wells/CompositionalMultiphaseWell.cpp | 22 +++++++++---------- .../wells/CompositionalMultiphaseWell.hpp | 5 +++-- .../fluidFlow/wells/SinglePhaseWell.cpp | 15 ++++++++----- .../fluidFlow/wells/SinglePhaseWell.hpp | 4 ++-- .../fluidFlow/wells/WellSolverBase.cpp | 2 +- .../fluidFlow/wells/WellSolverBase.hpp | 2 +- 6 files changed, 27 insertions(+), 23 deletions(-) diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp index fb4542efdad..76271f1f308 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp @@ -662,7 +662,8 @@ void CompositionalMultiphaseWell::updateBHPForConstraint( WellElementSubRegion & } -void CompositionalMultiphaseWell::updateVolRatesForConstraint( ElementRegionManager const & elemManager, WellElementSubRegion const & subRegion ) +void CompositionalMultiphaseWell::updateVolRatesForConstraint( MeshLevel & meshLevel, + WellElementSubRegion const & subRegion ) { GEOS_MARK_FUNCTION; @@ -717,7 +718,6 @@ void CompositionalMultiphaseWell::updateVolRatesForConstraint( ElementRegionMana } else { - GEOS_UNUSED_VAR( elemManager ); bool const useSegmentValues = wellControls.referenceReservoirRegion().empty(); if( useSegmentValues ) @@ -728,10 +728,9 @@ void CompositionalMultiphaseWell::updateVolRatesForConstraint( ElementRegionMana else { + // TODO use m_reservoirStatsAggregator - // if( !wellControls.referenceReservoirRegion().empty() ) - // { // ElementRegionBase const & region = elemManager.getRegion( wellControls.referenceReservoirRegion()); // GEOS_ERROR_IF ( !region.hasWrapper( CompositionalMultiphaseStatistics::regionStatisticsName() ), // GEOS_FMT( "{}: WellControl {} referenceReservoirRegion field requires CompositionalMultiphaseStatistics to be @@ -750,7 +749,7 @@ void CompositionalMultiphaseWell::updateVolRatesForConstraint( ElementRegionMana // GEOS_FMT( "{}: No region average quantities computed. WellControl {} referenceReservoirRegion field requires // CompositionalMultiphaseStatistics to be configured for region {} ", // getDataContext(), wellControls.getName(), wellControls.referenceReservoirRegion() )); - // } + // // If flashPressure is not set by region the value is defaulted to -1 and indicates to use top segment conditions flashPressure = wellControls.getRegionAveragePressure(); @@ -1027,7 +1026,7 @@ void CompositionalMultiphaseWell::updateState( DomainPartition & domain ) WellControls & wellControls = getWellControls( subRegion ); if( wellControls.getWellStatus() == WellControls::Status::OPEN ) { - real64 const maxRegionPhaseVolFrac = updateSubRegionState( elemManager, subRegion ); + real64 const maxRegionPhaseVolFrac = updateSubRegionState( mesh, subRegion ); maxPhaseVolFrac = LvArray::math::max( maxRegionPhaseVolFrac, maxPhaseVolFrac ); } } ); @@ -1040,14 +1039,15 @@ void CompositionalMultiphaseWell::updateState( DomainPartition & domain ) } -real64 CompositionalMultiphaseWell::updateSubRegionState( ElementRegionManager const & elemManager, WellElementSubRegion & subRegion ) +real64 CompositionalMultiphaseWell::updateSubRegionState( MeshLevel & mesh, + WellElementSubRegion & subRegion ) { // update properties updateGlobalComponentFraction( subRegion ); // update volumetric rates for the well constraints // note: this must be called before updateFluidModel - updateVolRatesForConstraint( elemManager, subRegion ); + updateVolRatesForConstraint( mesh, subRegion ); // update densities, phase fractions, phase volume fractions @@ -1165,7 +1165,7 @@ void CompositionalMultiphaseWell::initializeWells( DomainPartition & domain, rea wellElemCompDens ); // 5) Recompute the pressure-dependent properties - updateSubRegionState( elemManager, subRegion ); + updateSubRegionState( mesh, subRegion ); // 6) Estimate the well rates // TODO: initialize rates using perforation rates @@ -1971,7 +1971,7 @@ void CompositionalMultiphaseWell::resetStateToBeginningOfStep( DomainPartition & if( wellControls.isWellOpen( ) ) { - updateSubRegionState( elemManager, subRegion ); + updateSubRegionState( mesh, subRegion ); } } ); } ); @@ -2165,7 +2165,7 @@ void CompositionalMultiphaseWell::implicitStepSetup( real64 const & time_n, validateWellConstraints( time_n, dt, subRegion ); - updateSubRegionState( elemManager, subRegion ); + updateSubRegionState( mesh, subRegion ); } } ) ; diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.hpp index 9102c892769..0ee69bf2169 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.hpp @@ -22,6 +22,7 @@ #include "constitutive/fluid/multifluid/Layouts.hpp" #include "constitutive/relativePermeability/Layouts.hpp" +#include "mesh/MeshLevel.hpp" #include "physicsSolvers/fluidFlow/wells/WellSolverBase.hpp" #include "physicsSolvers/fluidFlow/CompositionalMultiphaseBase.hpp" @@ -148,7 +149,7 @@ class CompositionalMultiphaseWell : public WellSolverBase * @param elemManager the well region manager containing the well * @param subRegion the well subregion containing all the primary and dependent fields */ - void updateVolRatesForConstraint( ElementRegionManager const & elemManager, WellElementSubRegion const & subRegion ); + void updateVolRatesForConstraint( MeshLevel & mesh, WellElementSubRegion const & subRegion ); /** * @brief Recompute the current BHP pressure @@ -190,7 +191,7 @@ class CompositionalMultiphaseWell : public WellSolverBase */ virtual void updateState( DomainPartition & domain ) override; - virtual real64 updateSubRegionState( ElementRegionManager const & elemManager, WellElementSubRegion & subRegion ) override; + virtual real64 updateSubRegionState( MeshLevel & meshLevel, WellElementSubRegion & subRegion ) override; virtual string wellElementDofName() const override { return viewKeyStruct::dofFieldString(); } diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.cpp index 54716e387d4..266613d3c23 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.cpp @@ -27,6 +27,7 @@ #include "constitutive/fluid/singlefluid/SingleFluidSelector.hpp" #include "dataRepository/Group.hpp" #include "mesh/DomainPartition.hpp" +#include "mesh/ElementRegionManager.hpp" #include "mesh/WellElementSubRegion.hpp" #include "mesh/PerforationFields.hpp" #include "mesh/mpiCommunications/CommunicationTools.hpp" @@ -251,7 +252,7 @@ void SinglePhaseWell::updateBHPForConstraint( WellElementSubRegion & subRegion ) } -void SinglePhaseWell::updateVolRateForConstraint( ElementRegionManager const & elemManager, WellElementSubRegion & subRegion ) +void SinglePhaseWell::updateVolRateForConstraint( MeshLevel & mesh, WellElementSubRegion & subRegion ) { GEOS_MARK_FUNCTION; @@ -294,6 +295,7 @@ void SinglePhaseWell::updateVolRateForConstraint( ElementRegionManager const & e { if( !wellControls.referenceReservoirRegion().empty() ) { + ElementRegionManager const & elemManager = mesh.getElemManager(); ElementRegionBase const & region = elemManager.getRegion( wellControls.referenceReservoirRegion() ); GEOS_ERROR_IF ( !region.hasWrapper( SinglePhaseStatistics::regionStatisticsName()), GEOS_FMT( "{}: WellControl {} referenceReservoirRegion field requires SinglePhaseStatistics to be configured for region {} ", @@ -405,11 +407,12 @@ void SinglePhaseWell::updateFluidModel( WellElementSubRegion & subRegion ) const } ); } -real64 SinglePhaseWell::updateSubRegionState( ElementRegionManager const & elemManager, WellElementSubRegion & subRegion ) +real64 SinglePhaseWell::updateSubRegionState( MeshLevel & mesh, + WellElementSubRegion & subRegion ) { // update volumetric rates for the well constraints // Warning! This must be called before updating the fluid model - updateVolRateForConstraint( elemManager, subRegion ); + updateVolRateForConstraint( mesh, subRegion ); // update density in the well elements updateFluidModel( subRegion ); @@ -495,7 +498,7 @@ void SinglePhaseWell::initializeWells( DomainPartition & domain, real64 const & // 4) Recompute the pressure-dependent properties // Note: I am leaving that here because I would like to use the perforationRates (computed in UpdateState) // to better initialize the rates - updateSubRegionState( elemManager, subRegion ); + updateSubRegionState( meshLevel, subRegion ); string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() ); SingleFluidBase & fluid = subRegion.getConstitutiveModel< SingleFluidBase >( fluidName ); @@ -1156,7 +1159,7 @@ void SinglePhaseWell::resetStateToBeginningOfStep( DomainPartition & domain ) subRegion.getField< well::connectionRate_n >(); connRate.setValues< parallelDevicePolicy<> >( connRate_n ); - updateSubRegionState( elemManager, subRegion ); + updateSubRegionState( mesh, subRegion ); } ); } ); } @@ -1198,7 +1201,7 @@ void SinglePhaseWell::implicitStepSetup( real64 const & time, validateWellConstraints( time, dt, subRegion ); - updateSubRegionState( elemManager, subRegion ); + updateSubRegionState( mesh, subRegion ); } ); } ); } diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.hpp index 8c07e223fb7..aa1ed2c616a 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.hpp @@ -143,7 +143,7 @@ class SinglePhaseWell : public WellSolverBase * @param elemManager the well region manager * @param subRegion the well subregion containing all the primary and dependent fields */ - virtual void updateVolRateForConstraint( ElementRegionManager const & elemManager, WellElementSubRegion & subRegion ); + virtual void updateVolRateForConstraint( MeshLevel & meshLevel, WellElementSubRegion & subRegion ); /** * @brief Recompute the BHP pressure that is used in the well constraints @@ -169,7 +169,7 @@ class SinglePhaseWell : public WellSolverBase * @param elemManager the elemManager containing the well * @param subRegion the well subRegion containing the well elements and their associated fields */ - virtual real64 updateSubRegionState( ElementRegionManager const & elemManager, WellElementSubRegion & subRegion ) override; + virtual real64 updateSubRegionState( MeshLevel & meshLevel, WellElementSubRegion & subRegion ) override; /** * @brief function to assemble the linear system matrix and rhs diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.cpp index a76a66c2c72..7436b636e75 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.cpp @@ -309,7 +309,7 @@ void WellSolverBase::updateState( DomainPartition & domain ) ElementRegionManager & elemManager = mesh.getElemManager(); elemManager.forElementSubRegions< WellElementSubRegion >( regionNames, [&]( localIndex const, WellElementSubRegion & subRegion ) - { updateSubRegionState( elemManager, subRegion ); } ); + { updateSubRegionState( mesh, subRegion ); } ); } ); } diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.hpp index 04fe58112b4..722bd1092d3 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.hpp @@ -253,7 +253,7 @@ class WellSolverBase : public PhysicsSolverBase * @param elemManager the elemManager containing the well * @param subRegion the well subRegion containing the well elements and their associated fields */ - virtual real64 updateSubRegionState( ElementRegionManager const & elemManager, WellElementSubRegion & subRegion ) = 0; + virtual real64 updateSubRegionState( MeshLevel & meshLevel, WellElementSubRegion & subRegion ) = 0; /** * @brief Recompute the perforation rates for all the wells From 8fdf42c1cdacef69a33e1cd15271932a2f66b39b Mon Sep 17 00:00:00 2001 From: MelReyCG Date: Tue, 13 Jan 2026 14:23:12 +0100 Subject: [PATCH 18/28] =?UTF-8?q?=E2=9C=A8=20implement=20statistics=20aggr?= =?UTF-8?q?egator=20call=20from=20wellcontrols?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...sitionalMultiphaseStatisticsAggregator.cpp | 6 +- ...sitionalMultiphaseStatisticsAggregator.hpp | 7 +- .../wells/CompositionalMultiphaseWell.cpp | 79 +++++++++---------- .../wells/CompositionalMultiphaseWell.hpp | 2 + .../fluidFlow/wells/SinglePhaseWell.cpp | 11 ++- .../fluidFlow/wells/SinglePhaseWell.hpp | 2 + .../fluidFlow/wells/WellControls.hpp | 2 +- .../fluidFlow/wells/WellSolverBase.hpp | 2 + 8 files changed, 58 insertions(+), 53 deletions(-) diff --git a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsAggregator.cpp b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsAggregator.cpp index b0c2f620584..bd54eb1c5be 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsAggregator.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsAggregator.cpp @@ -278,9 +278,8 @@ bool StatsAggregator::computeRegionsStatistics( real64 const time, Group & meshB // computation of sub region stats forRegionStatistics( meshBodies, - [&, time] ( MeshLevel & mesh, RegionStatistics & regionStats ) + [&, time] ( MeshLevel & mesh, RegionStatistics & meshRegionsStats ) { - RegionStatistics & meshRegionsStats = getMeshRegionsStatistics( mesh ); forRegionStatistics( mesh, meshRegionsStats, [&, time] ( CellElementRegion & region, RegionStatistics & regionStats ) @@ -297,9 +296,8 @@ bool StatsAggregator::computeRegionsStatistics( real64 const time, Group & meshB // aggregation of computations from the sub regions forRegionStatistics( meshBodies, - [&, time] ( MeshLevel & mesh, RegionStatistics & regionStats ) + [&, time] ( MeshLevel & mesh, RegionStatistics & meshRegionsStats ) { - RegionStatistics & meshRegionsStats = getMeshRegionsStatistics( mesh ); initStats( meshRegionsStats, time ); forRegionStatistics( mesh, diff --git a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsAggregator.hpp b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsAggregator.hpp index 77275c1f6e1..7e1447c1c48 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsAggregator.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsAggregator.hpp @@ -227,13 +227,14 @@ class StatsAggregator RegionStatisticsFunctor< CellElementSubRegion > const & functor ) const; /** - * @brief Compute some statistics on a given mesh discretization (average field pressure, etc) + * @brief Compute statistics on the mesh discretizations (average field pressure, etc) * Results are reduced on rank 0, and broadcasted over all ranks. * @param[in] time current time * @param[in] meshBodies the Group containg all MeshBody objects * @return false if there was a problem that prevented the statistics to be computed correctly. */ - bool computeRegionsStatistics( real64 const time, dataRepository::Group & meshBodies ); + bool computeRegionsStatistics( real64 const time, + dataRepository::Group & meshBodies ); /** * @brief Compute CFL numbers @@ -273,7 +274,7 @@ class StatsAggregator dataRepository::Group & getInstanceStatisticsGroup( MeshLevel & mesh ) const; RegionStatistics & getMeshRegionsStatistics( MeshLevel & mesh ) const; - + /** * @brief TODO * @throw InputError if no statistics data is found for the given region name. diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp index 76271f1f308..8b43adc1535 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp @@ -50,6 +50,7 @@ #include "physicsSolvers/fluidFlow/kernels/compositional/ThermalPhaseVolumeFractionKernel.hpp" #include "physicsSolvers/fluidFlow/kernels/compositional/FluidUpdateKernel.hpp" #include "physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsAggregator.hpp" +#include #if defined( __INTEL_COMPILER ) #pragma GCC optimize "O0" @@ -432,18 +433,42 @@ void CompositionalMultiphaseWell::validateInjectionStreams( WellElementSubRegion void CompositionalMultiphaseWell::validateWellConstraints( real64 const & time_n, real64 const & GEOS_UNUSED_PARAM( dt ), + Group & meshBodies, + MeshLevel & meshLevel, WellElementSubRegion const & subRegion ) { WellControls & wellControls = getWellControls( subRegion ); - if( !wellControls.useSurfaceConditions() ) + string_view refRegionName = wellControls.referenceReservoirRegion(); + bool const useSegmentValues = refRegionName.empty(); + if( useSegmentValues ) { - bool const useSegmentValues = wellControls.referenceReservoirRegion().empty(); - GEOS_WARNING_IF( useSegmentValues, - "WellControls " <( getFlowSolverName() ); + m_reservoirStatsAggregator = std::make_unique< StatsAggregator >( wellControls.getDataContext() ); + m_reservoirStatsAggregator->initStatisticsAggregation( meshBodies, flowSolver ); + m_reservoirStatsAggregator->enableRegionStatisticsAggregation( meshBodies ); + } + + m_reservoirStatsAggregator->computeRegionsStatistics( time_n, meshBodies ); + RegionStatistics & stats = m_reservoirStatsAggregator->getRegionStatistics( meshLevel, refRegionName ); + + GEOS_WARNING_IF( stats.m_averagePressure <= 0.0, + GEOS_FMT( "No region average quantities computed in reference region '{}'.", + wellControls.referenceReservoirRegion() ), + wellControls.getWrapperDataContext( WellControls::viewKeyStruct::referenceReservoirRegionString() ), + getDataContext() ); + + wellControls.setRegionAveragePressure( stats.m_averagePressure ); + wellControls.setRegionAverageTemperature( stats.m_averageTemperature ); } string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString()); @@ -720,37 +745,8 @@ void CompositionalMultiphaseWell::updateVolRatesForConstraint( MeshLevel & meshL { bool const useSegmentValues = wellControls.referenceReservoirRegion().empty(); - if( useSegmentValues ) + if( !useSegmentValues ) { - wellControls.setRegionAveragePressure( -1 ); - wellControls.setRegionAverageTemperature( -1 ); - } - else - { - - - // TODO use m_reservoirStatsAggregator - - // ElementRegionBase const & region = elemManager.getRegion( wellControls.referenceReservoirRegion()); - // GEOS_ERROR_IF ( !region.hasWrapper( CompositionalMultiphaseStatistics::regionStatisticsName() ), - // GEOS_FMT( "{}: WellControl {} referenceReservoirRegion field requires CompositionalMultiphaseStatistics to be - // configured for region {} ", - // getDataContext(), wellControls.getName(), wellControls.referenceReservoirRegion() ) ); - - // will throw an exception if non-existing - // m_reservoirStatsAggregator->getRegionStatistics( subRegion., wellControls.referenceReservoirRegion() ) - - // CompositionalMultiphaseStatistics::RegionStatistics const & stats = region.getReference< - // CompositionalMultiphaseStatistics::RegionStatistics >( - // CompositionalMultiphaseStatistics::regionStatisticsName() ); - // wellControls.setRegionAveragePressure( stats.averagePressure ); - // wellControls.setRegionAverageTemperature( stats.averageTemperature ); - // GEOS_ERROR_IF( stats.averagePressure <= 0.0, - // GEOS_FMT( "{}: No region average quantities computed. WellControl {} referenceReservoirRegion field requires - // CompositionalMultiphaseStatistics to be configured for region {} ", - // getDataContext(), wellControls.getName(), wellControls.referenceReservoirRegion() )); - // - // If flashPressure is not set by region the value is defaulted to -1 and indicates to use top segment conditions flashPressure = wellControls.getRegionAveragePressure(); if( flashPressure < 0.0 ) @@ -2109,9 +2105,10 @@ void CompositionalMultiphaseWell::implicitStepSetup( real64 const & time_n, { WellSolverBase::implicitStepSetup( time_n, dt, domain ); - forDiscretizationOnMeshTargets ( domain.getMeshBodies(), [&] ( string const &, - MeshLevel & mesh, - string_array const & regionNames ) + Group & meshBodies = domain.getMeshBodies(); + forDiscretizationOnMeshTargets ( meshBodies, [&] ( string const &, + MeshLevel & mesh, + string_array const & regionNames ) { ElementRegionManager & elemManager = mesh.getElemManager(); @@ -2163,7 +2160,7 @@ void CompositionalMultiphaseWell::implicitStepSetup( real64 const & time_n, MultiFluidBase const & fluid = getConstitutiveModel< MultiFluidBase >( subRegion, fluidName ); fluid.saveConvergedState(); - validateWellConstraints( time_n, dt, subRegion ); + validateWellConstraints( time_n, dt, meshBodies, mesh, subRegion ); updateSubRegionState( mesh, subRegion ); } diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.hpp index 0ee69bf2169..ce04c2631ae 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.hpp @@ -351,6 +351,8 @@ class CompositionalMultiphaseWell : public WellSolverBase */ virtual void validateWellConstraints( real64 const & time_n, real64 const & dt, + Group & meshBodies, + MeshLevel & meshLevel, WellElementSubRegion const & subRegion ) override; /** diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.cpp index 266613d3c23..7ff7a26acab 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.cpp @@ -141,6 +141,8 @@ string SinglePhaseWell::resElementDofName() const void SinglePhaseWell::validateWellConstraints( real64 const & time_n, real64 const & GEOS_UNUSED_PARAM( dt ), + Group & GEOS_UNUSED_PARAM( meshBodies ), + MeshLevel & GEOS_UNUSED_PARAM( meshLevel ), WellElementSubRegion const & subRegion ) { WellControls & wellControls = getWellControls( subRegion ); @@ -1171,9 +1173,10 @@ void SinglePhaseWell::implicitStepSetup( real64 const & time, { WellSolverBase::implicitStepSetup( time, dt, domain ); - forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, - MeshLevel & mesh, - string_array const & regionNames ) + Group & meshBodies = domain.getMeshBodies(); + forDiscretizationOnMeshTargets( meshBodies, [&] ( string const &, + MeshLevel & mesh, + string_array const & regionNames ) { ElementRegionManager & elemManager = mesh.getElemManager(); @@ -1199,7 +1202,7 @@ void SinglePhaseWell::implicitStepSetup( real64 const & time, getConstitutiveModel< SingleFluidBase >( subRegion, subRegion.getReference< string >( viewKeyStruct::fluidNamesString() ) ); fluid.saveConvergedState(); - validateWellConstraints( time, dt, subRegion ); + validateWellConstraints( time, dt, meshBodies, mesh, subRegion ); updateSubRegionState( mesh, subRegion ); } ); diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.hpp index aa1ed2c616a..40565059939 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.hpp @@ -295,6 +295,8 @@ class SinglePhaseWell : public WellSolverBase */ virtual void validateWellConstraints( real64 const & time_n, real64 const & dt, + Group & meshBodies, + MeshLevel & meshLevel, WellElementSubRegion const & subRegion ) override; }; diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellControls.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellControls.hpp index 301c3c42f7c..cad56c2ebbe 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellControls.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellControls.hpp @@ -252,7 +252,7 @@ class WellControls : public dataRepository::Group * @brief Getter for the reservoir region associated with reservoir volume constraint * @return name of reservoir region */ - string referenceReservoirRegion() const { return m_referenceReservoirRegion; } + string const & referenceReservoirRegion() const { return m_referenceReservoirRegion; } /** * @brief Getter for the surface pressure when m_useSurfaceConditions == 1 diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.hpp index 722bd1092d3..b0726de1b21 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.hpp @@ -321,6 +321,8 @@ class WellSolverBase : public PhysicsSolverBase */ virtual void validateWellConstraints( real64 const & time_n, real64 const & dt, + Group & meshBodies, + MeshLevel & meshLevel, WellElementSubRegion const & subRegion ) = 0; virtual void printRates( real64 const & time_n, From ae978a2aa21bbd876b5d5e662acb3008d600e953 Mon Sep 17 00:00:00 2001 From: MelReyCG Date: Wed, 14 Jan 2026 14:34:36 +0100 Subject: [PATCH 19/28] =?UTF-8?q?=F0=9F=90=9Bcompil=20fixes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...sitionalMultiphaseStatisticsAggregator.cpp | 55 ++++++++++--------- .../CompositionalMultiphaseStatisticsTask.cpp | 7 ++- .../wells/CompositionalMultiphaseWell.cpp | 2 +- .../fluidFlow/wells/WellSolverBase.cpp | 10 ++-- 4 files changed, 41 insertions(+), 33 deletions(-) diff --git a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsAggregator.cpp b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsAggregator.cpp index bd54eb1c5be..b47e6f9b2e3 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsAggregator.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsAggregator.cpp @@ -97,6 +97,28 @@ using namespace constitutive; // using namespace fields; using namespace dataRepository; +RegionStatistics::RegionStatistics( string const & name, dataRepository::Group * const parent, + string_view targetName, + integer const numPhases, integer const numComponents ): + dataRepository::Group( name, parent ), + m_phaseDynamicPoreVolume( numPhases ), + m_phaseMass( numPhases ), + m_trappedPhaseMass( numPhases ), + m_nonTrappedPhaseMass( numPhases ), + m_immobilePhaseMass( numPhases ), + m_mobilePhaseMass( numPhases ), + m_componentMass( numPhases, numComponents ), + m_targetName( targetName ) +{ + // TODO : registerWrappers to store results in HDF5 (but need repairing of 1D HDF5 outputs) +} + +CFLStatistics::CFLStatistics( string const & name, dataRepository::Group * const parent ): + dataRepository::Group( name, parent ) +{ + // TODO : registerWrappers to store results in HDF5 (but need repairing of 1D HDF5 outputs) +} + StatsAggregator::StatsAggregator( DataContext const & ownerDataContext ): m_params(), m_ownerDataContext( ownerDataContext ) @@ -163,7 +185,7 @@ void StatsAggregator::enableRegionStatisticsAggregation( dataRepository::Group & GEOS_FMT( "{}_region_stats", region.getName() ), region.getName() ); - region.forElementSubRegions( [&] ( CellElementSubRegion & subRegion ) + region.forElementSubRegions< CellElementSubRegion >( [&] ( CellElementSubRegion & subRegion ) { registerStats( regionStats, GEOS_FMT( "{}_subRegion_stats", subRegion.getName() ), @@ -190,7 +212,7 @@ void StatsAggregator::enableCFLStatistics( dataRepository::Group & meshBodies ) m_solver->registerDataForCFL( meshBodies ); m_solver->forDiscretizationOnMeshTargets( meshBodies, [&] ( string const &, MeshLevel & mesh, - string_array const & regionNames ) + string_array const & ) { Group & statisticsGroup = getInstanceStatisticsGroup( mesh ); statisticsGroup.registerGroup< CFLStatistics >( ViewKeys::cflStatisticsString() ); @@ -217,12 +239,12 @@ RegionStatistics & StatsAggregator::getMeshRegionsStatistics( MeshLevel & mesh ) RegionStatistics & StatsAggregator::getRegionStatistics( MeshLevel & mesh, string_view regionName ) const { RegionStatistics & meshRegionsStats = getMeshRegionsStatistics( mesh ); - RegionStatistics * regionStats = meshRegionsStats.getGroupPointer< RegionStatistics >( regionName ); - GEOS_THROW_IF( regionStats == nullptr, + RegionStatistics * const stats = meshRegionsStats.getGroupPointer< RegionStatistics >( string( regionName ) ); + GEOS_THROW_IF( stats == nullptr, GEOS_FMT( "Region '{}' not found to get region statistics, is it a target of the reservoir solver?", regionName ), InputError, m_ownerDataContext ); - return *regionStats; + return *stats; } CFLStatistics & StatsAggregator::getCflStatisticsGroup( MeshLevel & mesh ) const @@ -239,7 +261,6 @@ void StatsAggregator::forRegionStatistics( dataRepository::Group & meshBodies, MeshLevel & mesh, string_array const & ) { - Group & instanceStats = getInstanceStatisticsGroup( mesh ); RegionStatistics & meshRegionsStats = getMeshRegionsStatistics( mesh ); func( mesh, meshRegionsStats ); @@ -254,7 +275,7 @@ void StatsAggregator::forRegionStatistics( MeshLevel & mesh, meshRegionsStatistics.forSubGroups< RegionStatistics >( [&] ( RegionStatistics & regionStatistics ) { string_view targetName = regionStatistics.getTargetName(); - CellElementRegion & region = elemManager.getRegion< CellElementRegion >( targetName ); + CellElementRegion & region = elemManager.getRegion< CellElementRegion >( string( targetName ) ); func( region, regionStatistics ); } ); @@ -267,7 +288,7 @@ void StatsAggregator::forRegionStatistics( CellElementRegion & region, regionStatistics.forSubGroups< RegionStatistics >( [&] ( RegionStatistics & subRegionStatistics ) { string_view targetName = subRegionStatistics.getTargetName(); - CellElementSubRegion & subRegion = region.getSubRegion< CellElementSubRegion >( targetName ); + CellElementSubRegion & subRegion = region.getSubRegion< CellElementSubRegion >( string( targetName ) ); func( subRegion, subRegionStatistics ); } ); } @@ -308,7 +329,7 @@ bool StatsAggregator::computeRegionsStatistics( real64 const time, Group & meshB forRegionStatistics( region, regionStats, - [&, time] ( CellElementSubRegion & subRegion, RegionStatistics & subRegionStats ) + [&, time] ( CellElementSubRegion &, RegionStatistics & subRegionStats ) { aggregateStats( regionStats, subRegionStats ); @@ -526,22 +547,6 @@ bool StatsAggregator::computeCFLNumbers( real64 const time, return true; } -RegionStatistics::RegionStatistics( string const & name, dataRepository::Group * const parent, - string_view targetName, - integer const numPhases, integer const numComponents ): - dataRepository::Group( name, parent ), - m_targetName( targetName ), - m_phaseDynamicPoreVolume( numPhases ), - m_phaseMass( numPhases ), - m_trappedPhaseMass( numPhases ), - m_nonTrappedPhaseMass( numPhases ), - m_immobilePhaseMass( numPhases ), - m_mobilePhaseMass( numPhases ), - m_componentMass( numPhases, numComponents ) -{ - // TODO : registerWrappers (need repairing of 1D HDF5 output) -} - } /* namespace compositionalMultiphaseStatistics */ } /* namespace geos */ diff --git a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsTask.cpp b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsTask.cpp index 33bfaf7259d..4288cb0e973 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsTask.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsTask.cpp @@ -85,7 +85,8 @@ void StatsTask::postInputInitialization() Base::postInputInitialization(); GEOS_THROW_IF_EQ_MSG( m_solver, nullptr, - "To identify simulated regions, a solver must be provided." /*, getWrapperDataContext( getSolverWrapperName() )*/ ); + "To identify simulated regions, a solver must be provided.", + InputError /*, getWrapperDataContext( getSolverWrapperName() )*/ ); if( dynamicCast< CompositionalMultiphaseBase * >( m_solver )) { @@ -353,7 +354,7 @@ void StatsTask::outputLogStats( real64 const statsTime, m_aggregator->forRegionStatistics( mesh, meshRegionsStatistics, [&] ( CellElementRegion & region, RegionStatistics & stats ) { - outputRegionStats( region.getName(), meshRegionsStatistics ); + outputRegionStats( region.getName(), stats ); } ); outputRegionStats( mesh.getName(), meshRegionsStatistics ); @@ -415,7 +416,7 @@ void StatsTask::outputCsvStats( real64 statsTime, m_aggregator->forRegionStatistics( mesh, meshRegionsStatistics, [&] ( CellElementRegion & region, RegionStatistics & stats ) { - outputRegionStats( region.getName(), meshRegionsStatistics ); + outputRegionStats( region.getName(), stats ); } ); outputRegionStats( mesh.getName(), meshRegionsStatistics ); diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp index 8b43adc1535..e05a199b397 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp @@ -687,7 +687,7 @@ void CompositionalMultiphaseWell::updateBHPForConstraint( WellElementSubRegion & } -void CompositionalMultiphaseWell::updateVolRatesForConstraint( MeshLevel & meshLevel, +void CompositionalMultiphaseWell::updateVolRatesForConstraint( MeshLevel & GEOS_UNUSED_PARAM( meshLevel ), WellElementSubRegion const & subRegion ) { GEOS_MARK_FUNCTION; diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.cpp index 7436b636e75..aad123dd9ba 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.cpp @@ -19,6 +19,7 @@ #include "WellSolverBase.hpp" +#include "dataRepository/Group.hpp" #include "mesh/DomainPartition.hpp" #include "mesh/PerforationFields.hpp" #include "mesh/WellElementRegion.hpp" @@ -151,16 +152,17 @@ void WellSolverBase::initializePostSubGroups() { DomainPartition & domain = this->getGroupByPath< DomainPartition >( "/Problem/domain" ); FunctionManager & functionManager = FunctionManager::getInstance(); - forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, - MeshLevel & mesh, - string_array const & regionNames ) + Group & meshBodies = domain.getMeshBodies(); + forDiscretizationOnMeshTargets( meshBodies, [&] ( string const &, + MeshLevel & mesh, + string_array const & regionNames ) { ElementRegionManager & elemManager = mesh.getElemManager(); elemManager.forElementSubRegions< WellElementSubRegion >( regionNames, [&]( localIndex const, WellElementSubRegion & subRegion ) { - validateWellConstraints( 0, 0, subRegion ); + validateWellConstraints( 0, 0, meshBodies, mesh, subRegion ); // validate perforation status table PerforationData & perforationData = *subRegion.getPerforationData(); From 4ce27d2144222323009561b6a190faa7ebdfa6af Mon Sep 17 00:00:00 2001 From: MelReyCG Date: Thu, 15 Jan 2026 10:49:47 +0100 Subject: [PATCH 20/28] =?UTF-8?q?=E2=9A=B0=EF=B8=8F=20pruning=20headers?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../fluidFlow/CompositionalMultiphaseStatisticsAggregator.hpp | 1 - .../fluidFlow/CompositionalMultiphaseStatisticsTask.hpp | 1 - 2 files changed, 2 deletions(-) diff --git a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsAggregator.hpp b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsAggregator.hpp index 7e1447c1c48..c0324b8de93 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsAggregator.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsAggregator.hpp @@ -27,7 +27,6 @@ #include "mesh/CellElementRegion.hpp" #include "mesh/DomainPartition.hpp" #include "mesh/MeshLevel.hpp" -#include namespace geos { diff --git a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsTask.hpp b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsTask.hpp index 527822b67f1..9ebc7951224 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsTask.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsTask.hpp @@ -22,7 +22,6 @@ #include "common/DataTypes.hpp" #include "common/format/table/TableFormatter.hpp" -#include "common/format/table/TableLayout.hpp" #include "physicsSolvers/FieldStatisticsBase.hpp" #include "physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsAggregator.hpp" #include From 3288270fcdbef9b34b7dba1a601c85594d7673e8 Mon Sep 17 00:00:00 2001 From: MelReyCG Date: Thu, 15 Jan 2026 10:50:13 +0100 Subject: [PATCH 21/28] =?UTF-8?q?=F0=9F=90=9Bbugfix=20bad=20type=20detecti?= =?UTF-8?q?on?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../fluidFlow/CompositionalMultiphaseStatisticsTask.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsTask.cpp b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsTask.cpp index 4288cb0e973..5ca01a2c914 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsTask.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsTask.cpp @@ -88,12 +88,11 @@ void StatsTask::postInputInitialization() "To identify simulated regions, a solver must be provided.", InputError /*, getWrapperDataContext( getSolverWrapperName() )*/ ); - if( dynamicCast< CompositionalMultiphaseBase * >( m_solver )) + if( !dynamicCast< CompositionalMultiphaseBase * >( m_solver ) ) { GEOS_THROW( GEOS_FMT( "{} {}: incompatible solver selected, a compositional multiphase solver is expected", catalogName(), getDataContext() ), InputError ); - } else if( dynamicCast< CompositionalMultiphaseHybridFVM * >( m_solver ) && m_computeCFLNumbers != 0 ) { From 753d32b713717fef2985e0473fcf662a9884d732 Mon Sep 17 00:00:00 2001 From: MelReyCG Date: Thu, 15 Jan 2026 14:21:08 +0100 Subject: [PATCH 22/28] =?UTF-8?q?=F0=9F=90=9B=20flash=20pressure=20computi?= =?UTF-8?q?ng=20bugfix?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../wells/CompositionalMultiphaseWell.cpp | 35 ++++++++----------- 1 file changed, 15 insertions(+), 20 deletions(-) diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp index e05a199b397..bdf10c1ef51 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp @@ -50,7 +50,6 @@ #include "physicsSolvers/fluidFlow/kernels/compositional/ThermalPhaseVolumeFractionKernel.hpp" #include "physicsSolvers/fluidFlow/kernels/compositional/FluidUpdateKernel.hpp" #include "physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsAggregator.hpp" -#include #if defined( __INTEL_COMPILER ) #pragma GCC optimize "O0" @@ -743,25 +742,21 @@ void CompositionalMultiphaseWell::updateVolRatesForConstraint( MeshLevel & GEOS_ } else { - bool const useSegmentValues = wellControls.referenceReservoirRegion().empty(); - - if( !useSegmentValues ) + // If flashPressure is not set by region the value is defaulted to -1 and indicates to use top segment conditions + flashPressure = wellControls.getRegionAveragePressure(); + if( flashPressure < 0.0 ) { - // If flashPressure is not set by region the value is defaulted to -1 and indicates to use top segment conditions - flashPressure = wellControls.getRegionAveragePressure(); - if( flashPressure < 0.0 ) - { - // region name not set, use segment conditions - flashPressure = pres[iwelemRef]; - flashTemperature = temp[iwelemRef]; - } - else - { - // use reservoir region averages - flashTemperature = wellControls.getRegionAverageTemperature(); - } + // region name not set, use segment conditions + flashPressure = pres[iwelemRef]; + flashTemperature = temp[iwelemRef]; + } + else + { + // use reservoir region averages + flashTemperature = wellControls.getRegionAverageTemperature(); } } + arrayView1d< real64 > const & currentPhaseVolRate = wellControls.getReference< array1d< real64 > >( CompositionalMultiphaseWell::viewKeyStruct::currentPhaseVolRateString() ); arrayView2d< real64 > const & dCurrentPhaseVolRate = @@ -1117,7 +1112,7 @@ void CompositionalMultiphaseWell::initializeWells( DomainPartition & domain, rea numComp, numPhase, wellControls, - 0.0, // initialization done at t = 0 + 0.0, // initialization done at t = 0 resCompFlowAccessors.get( flow::pressure{} ), resCompFlowAccessors.get( flow::temperature{} ), resCompFlowAccessors.get( flow::globalCompDensity{} ), @@ -1367,8 +1362,8 @@ void CompositionalMultiphaseWell::assembleAccumulationTerms( real64 const & time } } ); } - } ); // forElementSubRegions - } ); // forDiscretizationOnMeshTargets + } ); // forElementSubRegions + } ); // forDiscretizationOnMeshTargets } From c2bc1aa7095d249b53c4121661f05c0f418ed9d0 Mon Sep 17 00:00:00 2001 From: MelReyCG Date: Thu, 15 Jan 2026 15:10:36 +0100 Subject: [PATCH 23/28] =?UTF-8?q?=F0=9F=93=A6schemamehcs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/coreComponents/schema/schema.xsd.other | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/coreComponents/schema/schema.xsd.other b/src/coreComponents/schema/schema.xsd.other index 4a2f9c949c6..6ed1f71381f 100644 --- a/src/coreComponents/schema/schema.xsd.other +++ b/src/coreComponents/schema/schema.xsd.other @@ -526,7 +526,7 @@ A field can represent a physical variable. (pressure, temperature, global compos - + @@ -1562,7 +1562,7 @@ A field can represent a physical variable. (pressure, temperature, global compos - + From 1b7fab5ec92717d3b3639e6e4031fae0856c3fbb Mon Sep 17 00:00:00 2001 From: MelReyCG Date: Mon, 19 Jan 2026 10:58:18 +0100 Subject: [PATCH 24/28] =?UTF-8?q?=E2=99=BB=EF=B8=8Fcentralize=20flowSolver?= =?UTF-8?q?=20access?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../wells/CompositionalMultiphaseWell.cpp | 19 +++++++++++++++---- .../fluidFlow/wells/SinglePhaseWell.cpp | 18 +++++++++++++++--- 2 files changed, 30 insertions(+), 7 deletions(-) diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp index bdf10c1ef51..791a2921a1a 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp @@ -63,6 +63,18 @@ using namespace constitutive; using namespace fields; using namespace compositionalMultiphaseStatistics; +CompositionalMultiphaseBase & getFlowSolver( CompositionalMultiphaseWell & wellSolver ) +{ + // TODO: change the way we access the flowSolver here + return wellSolver.getParent().getGroup< CompositionalMultiphaseBase >( wellSolver.getFlowSolverName() ); +} + +CompositionalMultiphaseBase const & getFlowSolver( CompositionalMultiphaseWell const & wellSolver ) +{ + // TODO: change the way we access the flowSolver here + return wellSolver.getParent().getGroup< CompositionalMultiphaseBase >( wellSolver.getFlowSolverName() ); +} + CompositionalMultiphaseWell::CompositionalMultiphaseWell( const string & name, Group * const parent ) : @@ -368,7 +380,7 @@ void CompositionalMultiphaseWell::validateConstitutiveModels( DomainPartition co GEOS_MARK_FUNCTION; ConstitutiveManager const & cm = domain.getConstitutiveManager(); - CompositionalMultiphaseBase const & flowSolver = getParent().getGroup< CompositionalMultiphaseBase >( getFlowSolverName() ); + CompositionalMultiphaseBase const & flowSolver = getFlowSolver( *this ); string const referenceFluidName = flowSolver.referenceFluidModelName(); MultiFluidBase const & referenceFluid = cm.getConstitutiveRelation< MultiFluidBase >( m_referenceFluidModelName ); @@ -1057,8 +1069,7 @@ void CompositionalMultiphaseWell::initializeWells( DomainPartition & domain, rea integer const numComp = m_numComponents; integer const numPhase = m_numPhases; - // TODO: change the way we access the flowSolver here - CompositionalMultiphaseBase const & flowSolver = getParent().getGroup< CompositionalMultiphaseBase >( getFlowSolverName() ); + CompositionalMultiphaseBase const & flowSolver = getFlowSolver( *this ); // loop over the wells forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, @@ -1736,7 +1747,7 @@ void CompositionalMultiphaseWell::computePerforationRates( real64 const & time_n { // TODO: change the way we access the flowSolver here - CompositionalMultiphaseBase const & flowSolver = getParent().getGroup< CompositionalMultiphaseBase >( getFlowSolverName() ); + CompositionalMultiphaseBase const & flowSolver = getFlowSolver( *this ); ElementRegionManager & elemManager = mesh.getElemManager(); elemManager.forElementSubRegions< WellElementSubRegion >( regionNames, [&]( localIndex const, diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.cpp index 7ff7a26acab..41120d9d008 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.cpp @@ -54,6 +54,18 @@ using namespace constitutive; using namespace fields; using namespace singlePhaseWellKernels; +SinglePhaseBase & getFlowSolver( SinglePhaseWell & wellSolver ) +{ + // TODO: change the way we access the flowSolver here + return wellSolver.getParent().getGroup< SinglePhaseBase >( wellSolver.getFlowSolverName() ); +} + +SinglePhaseBase const & getFlowSolver( SinglePhaseWell const & wellSolver ) +{ + // TODO: change the way we access the flowSolver here + return wellSolver.getParent().getGroup< SinglePhaseBase >( wellSolver.getFlowSolverName() ); +} + SinglePhaseWell::SinglePhaseWell( const string & name, Group * const parent ): WellSolverBase( name, parent ) @@ -159,7 +171,7 @@ void SinglePhaseWell::validateWellConstraints( real64 const & time_n, { // Check if region name exists in list of Reservoir's target regions string const regionName = wellControls.referenceReservoirRegion(); - SinglePhaseBase const & flowSolver = getParent().getGroup< SinglePhaseBase >( getFlowSolverName() ); + SinglePhaseBase const & flowSolver = getFlowSolver( *this ); string_array const & targetRegionsNames = flowSolver.getTargetRegionNames(); auto const pos = std::find( targetRegionsNames.begin(), targetRegionsNames.end(), regionName ); GEOS_ERROR_IF( pos == targetRegionsNames.end(), @@ -472,7 +484,7 @@ void SinglePhaseWell::initializeWells( DomainPartition & domain, real64 const & if( wellControls.isWellOpen() && !hasNonZeroRate ) { // TODO: change the way we access the flowSolver here - SinglePhaseBase const & flowSolver = getParent().getGroup< SinglePhaseBase >( getFlowSolverName() ); + SinglePhaseBase const & flowSolver = getFlowSolver( *this ); PresTempInitializationKernel::SinglePhaseFlowAccessors resSinglePhaseFlowAccessors( meshLevel.getElemManager(), flowSolver.getName() ); PresTempInitializationKernel::SingleFluidAccessors resSingleFluidAccessors( meshLevel.getElemManager(), flowSolver.getName() ); @@ -844,7 +856,7 @@ void SinglePhaseWell::computePerforationRates( real64 const & time_n, { // TODO: change the way we access the flowSolver here - SinglePhaseBase const & flowSolver = getParent().getGroup< SinglePhaseBase >( getFlowSolverName() ); + SinglePhaseBase const & flowSolver = getFlowSolver( *this ); PerforationKernel::SinglePhaseFlowAccessors resSinglePhaseFlowAccessors( mesh.getElemManager(), flowSolver.getName() ); PerforationKernel::SingleFluidAccessors resSingleFluidAccessors( mesh.getElemManager(), flowSolver.getName() ); ElementRegionManager & elemManager = mesh.getElemManager(); From ffbfe252f978426fe39f0843b2144ad93b97a183 Mon Sep 17 00:00:00 2001 From: MelReyCG Date: Wed, 21 Jan 2026 08:49:14 +0100 Subject: [PATCH 25/28] =?UTF-8?q?=F0=9F=90=9B=20better=20last-time=20valid?= =?UTF-8?q?ation=20(div/0=20avoided=3F)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../fluidFlow/wells/CompositionalMultiphaseWell.cpp | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp index 791a2921a1a..d306714708d 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp @@ -756,17 +756,12 @@ void CompositionalMultiphaseWell::updateVolRatesForConstraint( MeshLevel & GEOS_ { // If flashPressure is not set by region the value is defaulted to -1 and indicates to use top segment conditions flashPressure = wellControls.getRegionAveragePressure(); - if( flashPressure < 0.0 ) - { - // region name not set, use segment conditions + flashTemperature = wellControls.getRegionAverageTemperature(); + if( flashPressure <= 0.0 || flashTemperature <= 0.0 ) + { // region average stats not initialized, fallback to top segment values flashPressure = pres[iwelemRef]; flashTemperature = temp[iwelemRef]; } - else - { - // use reservoir region averages - flashTemperature = wellControls.getRegionAverageTemperature(); - } } arrayView1d< real64 > const & currentPhaseVolRate = From 0394da8591245b49e0b651a87aad81a1f08c449f Mon Sep 17 00:00:00 2001 From: MelReyCG Date: Wed, 21 Jan 2026 08:55:19 +0100 Subject: [PATCH 26/28] =?UTF-8?q?=F0=9F=90=9B=20accessing=20the=20right=20?= =?UTF-8?q?region=20data=20structure=20+=20added=20validations=20+=20bette?= =?UTF-8?q?r=20parameters=20managment?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...sitionalMultiphaseStatisticsAggregator.cpp | 79 ++++++++++--------- ...sitionalMultiphaseStatisticsAggregator.hpp | 31 +++----- .../CompositionalMultiphaseStatisticsTask.cpp | 21 ++--- .../wells/CompositionalMultiphaseWell.cpp | 15 ++-- .../wells/CompositionalMultiphaseWell.hpp | 2 +- .../fluidFlow/wells/SinglePhaseWell.cpp | 8 +- .../fluidFlow/wells/SinglePhaseWell.hpp | 2 +- .../fluidFlow/wells/WellSolverBase.cpp | 6 +- .../fluidFlow/wells/WellSolverBase.hpp | 2 +- 9 files changed, 84 insertions(+), 82 deletions(-) diff --git a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsAggregator.cpp b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsAggregator.cpp index b47e6f9b2e3..dc619929b81 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsAggregator.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsAggregator.cpp @@ -74,6 +74,7 @@ #include "LvArray/src/math.hpp" #include "common/DataTypes.hpp" #include "common/format/Format.hpp" +#include "common/format/StringUtilities.hpp" #include "common/logger/Logger.hpp" #include "dataRepository/DataContext.hpp" #include "dataRepository/Group.hpp" @@ -98,7 +99,6 @@ using namespace constitutive; using namespace dataRepository; RegionStatistics::RegionStatistics( string const & name, dataRepository::Group * const parent, - string_view targetName, integer const numPhases, integer const numComponents ): dataRepository::Group( name, parent ), m_phaseDynamicPoreVolume( numPhases ), @@ -107,8 +107,7 @@ RegionStatistics::RegionStatistics( string const & name, dataRepository::Group * m_nonTrappedPhaseMass( numPhases ), m_immobilePhaseMass( numPhases ), m_mobilePhaseMass( numPhases ), - m_componentMass( numPhases, numComponents ), - m_targetName( targetName ) + m_componentMass( numPhases, numComponents ) { // TODO : registerWrappers to store results in HDF5 (but need repairing of 1D HDF5 outputs) } @@ -120,14 +119,15 @@ CFLStatistics::CFLStatistics( string const & name, dataRepository::Group * const } StatsAggregator::StatsAggregator( DataContext const & ownerDataContext ): - m_params(), - m_ownerDataContext( ownerDataContext ) + m_ownerDataContext( ownerDataContext ), + m_params() {} void StatsAggregator::initStatisticsAggregation( dataRepository::Group & meshBodies, CompositionalMultiphaseBase & solver ) { m_solver = &solver; + m_meshBodies = &meshBodies; m_numPhases = m_solver->numFluidPhases(); m_numComponents = m_solver->numFluidComponents(); @@ -144,51 +144,48 @@ void StatsAggregator::initStatisticsAggregation( dataRepository::Group & meshBod // registering the container of instance statistics groups (must be unique for this instance) string const & ownerName = getOwnerName(); GEOS_ERROR_IF_NE_MSG( meshStatsGroup->hasGroup( ownerName ), false, - "A statistics aggregator have already been requested.", + GEOS_FMT( "A statistics aggregator have already been requested for '{}'.", + ownerName ), m_ownerDataContext ); meshStatsGroup->registerGroup( ownerName ); } ); } -void StatsAggregator::enableRegionStatisticsAggregation( dataRepository::Group & meshBodies ) +void StatsAggregator::enableRegionStatisticsAggregation() { - if( m_solver == nullptr ) + if( m_solver == nullptr || m_meshBodies == nullptr ) return; integer regionCount = 0; integer subRegionCount = 0; auto const registerStats = [=] ( Group & parent, - string const & name, string const & targetName ) -> RegionStatistics & { - return parent.registerGroup( name, std::make_unique< RegionStatistics >( name, &parent, - targetName, - m_numPhases, - m_numComponents ) ); + return parent.registerGroup( targetName, + std::make_unique< RegionStatistics >( targetName, &parent, + m_numPhases, + m_numComponents ) ); }; - m_solver->forDiscretizationOnMeshTargets( meshBodies, [&] ( string const &, - MeshLevel & mesh, - string_array const & regionNames ) + m_solver->forDiscretizationOnMeshTargets( *m_meshBodies, [&] ( string const &, + MeshLevel & mesh, + string_array const & regionNames ) { ElementRegionManager & elemManager = mesh.getElemManager(); Group & statisticsGroup = getInstanceStatisticsGroup( mesh ); RegionStatistics & meshRegionsStats = registerStats( statisticsGroup, - ViewKeys::regionsStatisticsString(), - mesh.getName() ); + ViewKeys::regionsStatisticsString() ); for( size_t i = 0; i < regionNames.size(); ++i ) { CellElementRegion & region = elemManager.getRegion< CellElementRegion >( regionNames[i] ); RegionStatistics & regionStats = registerStats( meshRegionsStats, - GEOS_FMT( "{}_region_stats", region.getName() ), region.getName() ); region.forElementSubRegions< CellElementSubRegion >( [&] ( CellElementSubRegion & subRegion ) { registerStats( regionStats, - GEOS_FMT( "{}_subRegion_stats", subRegion.getName() ), subRegion.getName() ); ++subRegionCount; } ); @@ -204,15 +201,15 @@ void StatsAggregator::enableRegionStatisticsAggregation( dataRepository::Group & m_isRegionStatsEnabled = true; } -void StatsAggregator::enableCFLStatistics( dataRepository::Group & meshBodies ) +void StatsAggregator::enableCFLStatistics() { if( m_solver == nullptr ) return; - m_solver->registerDataForCFL( meshBodies ); - m_solver->forDiscretizationOnMeshTargets( meshBodies, [&] ( string const &, - MeshLevel & mesh, - string_array const & ) + m_solver->registerDataForCFL( *m_meshBodies ); + m_solver->forDiscretizationOnMeshTargets( *m_meshBodies, [&] ( string const &, + MeshLevel & mesh, + string_array const & ) { Group & statisticsGroup = getInstanceStatisticsGroup( mesh ); statisticsGroup.registerGroup< CFLStatistics >( ViewKeys::cflStatisticsString() ); @@ -236,13 +233,15 @@ RegionStatistics & StatsAggregator::getMeshRegionsStatistics( MeshLevel & mesh ) return instanceStatisticsGroup.getGroup< RegionStatistics >( ViewKeys::regionsStatisticsString() ); } -RegionStatistics & StatsAggregator::getRegionStatistics( MeshLevel & mesh, string_view regionName ) const +RegionStatistics & StatsAggregator::getRegionStatistics( MeshLevel & mesh, + string_view regionName ) const { RegionStatistics & meshRegionsStats = getMeshRegionsStatistics( mesh ); RegionStatistics * const stats = meshRegionsStats.getGroupPointer< RegionStatistics >( string( regionName ) ); GEOS_THROW_IF( stats == nullptr, - GEOS_FMT( "Region '{}' not found to get region statistics, is it a target of the reservoir solver?", - regionName ), + GEOS_FMT( "Region '{}' not found to get region statistics, is it a target of the reservoir solver?\n" + "Available target regions:\n- {}", + regionName, stringutilities::join( meshRegionsStats.getSubGroupsNames(), "\n- " ) ), InputError, m_ownerDataContext ); return *stats; } @@ -254,12 +253,11 @@ CFLStatistics & StatsAggregator::getCflStatisticsGroup( MeshLevel & mesh ) const return statisticsGroup.getGroup< CFLStatistics >( ViewKeys::cflStatisticsString() ); } -void StatsAggregator::forRegionStatistics( dataRepository::Group & meshBodies, - RegionStatisticsFunctor< MeshLevel > const & func ) const +void StatsAggregator::forRegionStatistics( RegionStatisticsFunctor< MeshLevel > const & func ) const { - m_solver->forDiscretizationOnMeshTargets( meshBodies, [&] ( string const &, - MeshLevel & mesh, - string_array const & ) + m_solver->forDiscretizationOnMeshTargets( *m_meshBodies, [&] ( string const &, + MeshLevel & mesh, + string_array const & ) { RegionStatistics & meshRegionsStats = getMeshRegionsStatistics( mesh ); @@ -293,13 +291,12 @@ void StatsAggregator::forRegionStatistics( CellElementRegion & region, } ); } -bool StatsAggregator::computeRegionsStatistics( real64 const time, Group & meshBodies ) +bool StatsAggregator::computeRegionsStatistics( real64 const time ) { GEOS_MARK_FUNCTION; // computation of sub region stats - forRegionStatistics( meshBodies, - [&, time] ( MeshLevel & mesh, RegionStatistics & meshRegionsStats ) + forRegionStatistics( [&, time] ( MeshLevel & mesh, RegionStatistics & meshRegionsStats ) { forRegionStatistics( mesh, meshRegionsStats, @@ -316,8 +313,7 @@ bool StatsAggregator::computeRegionsStatistics( real64 const time, Group & meshB } ); // aggregation of computations from the sub regions - forRegionStatistics( meshBodies, - [&, time] ( MeshLevel & mesh, RegionStatistics & meshRegionsStats ) + forRegionStatistics( [&, time] ( MeshLevel & mesh, RegionStatistics & meshRegionsStats ) { initStats( meshRegionsStats, time ); @@ -532,7 +528,12 @@ bool StatsAggregator::computeCFLNumbers( real64 const time, m_warnings.clear(); - if( stats!=nullptr ) + if( !m_isCFLNumberEnabled ) + { + m_warnings.emplace_back( "CFL numbers computation is not enabled." ); + return false; + } + if( stats == nullptr ) { m_warnings.emplace_back( GEOS_FMT( "No statistics structure to compute CFL numbers for domain '{}'.", domain.getName() )); return false; diff --git a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsAggregator.hpp b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsAggregator.hpp index c0324b8de93..450c8f5f13d 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsAggregator.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsAggregator.hpp @@ -26,6 +26,7 @@ #include "dataRepository/Group.hpp" #include "mesh/CellElementRegion.hpp" #include "mesh/DomainPartition.hpp" +#include "mesh/MeshBody.hpp" #include "mesh/MeshLevel.hpp" namespace geos @@ -100,15 +101,13 @@ class RegionStatistics : public dataRepository::Group /** * @brief Construct a new Region Statistics object - * @param name instance name in data-repository. * @param targetName name of the data-repository object that is targeted by the statistics * (mesh level / region / sub-region). * @param parent the instance parent in data-repository * @param numPhases Fluid phase count * @param numComponents Fluid component count */ - RegionStatistics( string const & name, dataRepository::Group * const parent, - string_view targetName, + RegionStatistics( string const & targetName, dataRepository::Group * const parent, integer numPhases, integer numComponents ); RegionStatistics( RegionStatistics && ) = default; @@ -118,11 +117,8 @@ class RegionStatistics : public dataRepository::Group * (mesh level / region / sub-region). */ string_view getTargetName() const - { return m_targetName; } + { return getName(); } -private: - /// see getTargetName(); - string const m_targetName; }; /** @@ -205,17 +201,16 @@ class StatsAggregator * @note Must be called in or after the "registerDataOnMesh" initialization phase * @param meshBodies The Group containing the MeshBody objects */ - void enableRegionStatisticsAggregation( dataRepository::Group & meshBodies ); + void enableRegionStatisticsAggregation(); /** * @brief Register the results structs & wrappers so they will be targeted by TimeHistory output * @note Must be called in or after the "registerDataOnMesh" initialization phase * @param meshBodies The Group containing the MeshBody objects */ - void enableCFLStatistics( dataRepository::Group & meshBodies ); + void enableCFLStatistics(); - void forRegionStatistics( dataRepository::Group & meshBodies, - RegionStatisticsFunctor< MeshLevel > const & functor ) const; + void forRegionStatistics( RegionStatisticsFunctor< MeshLevel > const & functor ) const; void forRegionStatistics( MeshLevel & mesh, RegionStatistics & meshRegionsStatistics, @@ -229,11 +224,9 @@ class StatsAggregator * @brief Compute statistics on the mesh discretizations (average field pressure, etc) * Results are reduced on rank 0, and broadcasted over all ranks. * @param[in] time current time - * @param[in] meshBodies the Group containg all MeshBody objects * @return false if there was a problem that prevented the statistics to be computed correctly. */ - bool computeRegionsStatistics( real64 const time, - dataRepository::Group & meshBodies ); + bool computeRegionsStatistics( real64 const time ); /** * @brief Compute CFL numbers @@ -287,15 +280,17 @@ class StatsAggregator private: - CompositionalMultiphaseBase * m_solver; + /// @see getOwnerName() + dataRepository::DataContext const & m_ownerDataContext; + + CompositionalMultiphaseBase * m_solver = nullptr; + + dataRepository::Group * m_meshBodies = nullptr; AggregatorParameters m_params; stdVector< string > m_warnings; - /// @see getOwnerName() - dataRepository::DataContext const & m_ownerDataContext; - bool m_isRegionStatsEnabled = false; bool m_isCFLNumberEnabled = false; diff --git a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsTask.cpp b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsTask.cpp index 5ca01a2c914..975be720307 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsTask.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsTask.cpp @@ -107,11 +107,9 @@ void StatsTask::postInputInitialization() void StatsTask::registerDataOnMesh( Group & meshBodies ) { // for now, this guard is needed to avoid breaking the xml schema generation - if( m_solver == nullptr ) + if( m_solver == nullptr || m_aggregator == nullptr ) return; - getGroupByPath( "/" ).printDataHierarchy(); - prepareFluidMetaData(); if( m_computeRegionStatistics || m_computeCFLNumbers ) @@ -129,14 +127,13 @@ void StatsTask::registerDataOnMesh( Group & meshBodies ) } if( m_computeRegionStatistics ) - m_aggregator->enableRegionStatisticsAggregation( meshBodies ); + m_aggregator->enableRegionStatisticsAggregation(); // if we have to compute CFL numbers later, we need to register additional variables if( m_computeCFLNumbers ) - m_aggregator->enableCFLStatistics( meshBodies ); + m_aggregator->enableCFLStatistics(); - m_aggregator->forRegionStatistics( meshBodies, - [&] ( MeshLevel & mesh, RegionStatistics & ) + m_aggregator->forRegionStatistics( [&] ( MeshLevel & mesh, RegionStatistics & ) { prepareLogTableLayouts( mesh.getName() ); prepareCsvTableLayouts( mesh.getName() ); @@ -245,10 +242,12 @@ bool StatsTask::execute( real64 const time_n, // current time is time_n + dt. TODO: verify implication of events ordering in 'time_n+dt' validity real64 statsTime = time_n + dt; - m_aggregator->computeRegionsStatistics( statsTime, domain.getMeshBodies() ); + GEOS_ERROR_IF( !m_aggregator, + "No statistics aggregator initialized!", getDataContext() ); + + m_aggregator->computeRegionsStatistics( statsTime ); - m_aggregator->forRegionStatistics( domain.getMeshBodies(), - [&] ( MeshLevel & mesh, RegionStatistics & meshRegionsStatistics ) + m_aggregator->forRegionStatistics( [&] ( MeshLevel & mesh, RegionStatistics & meshRegionsStatistics ) { if( m_computeRegionStatistics ) { @@ -283,6 +282,8 @@ void StatsTask::outputLogStats( real64 const statsTime, string_view tempUnit = units::getSymbol( units::Temperature ); string_view resVolUnit = units::getSymbol( units::ReservoirVolume ); + tableData.getErrorsList().appendErrors( m_aggregator->getWarnings() ); + tableData.addRow( "Statistics time", merge, merge, statsTime ); // lamda to apply for each region statistics diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp index d306714708d..9c108271307 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp @@ -33,6 +33,7 @@ #include "mesh/WellElementSubRegion.hpp" #include "mesh/mpiCommunications/CommunicationTools.hpp" #include "physicsSolvers/LogLevelsInfo.hpp" +#include "physicsSolvers/fluidFlow/CompositionalMultiphaseBase.hpp" #include "physicsSolvers/fluidFlow/wells/LogLevelsInfo.hpp" #include "physicsSolvers/fluidFlow/wells/WellSolverBaseFields.hpp" #include "physicsSolvers/fluidFlow/wells/WellFields.hpp" @@ -445,7 +446,7 @@ void CompositionalMultiphaseWell::validateInjectionStreams( WellElementSubRegion void CompositionalMultiphaseWell::validateWellConstraints( real64 const & time_n, real64 const & GEOS_UNUSED_PARAM( dt ), Group & meshBodies, - MeshLevel & meshLevel, + MeshBody & meshBody, WellElementSubRegion const & subRegion ) { WellControls & wellControls = getWellControls( subRegion ); @@ -454,23 +455,25 @@ void CompositionalMultiphaseWell::validateWellConstraints( real64 const & time_n bool const useSegmentValues = refRegionName.empty(); if( useSegmentValues ) { - GEOS_WARNING( "WellControls " <( getFlowSolverName() ); + MeshLevel & flowMeshLevel = meshBody.getMeshLevel( flowSolver.getDiscretizationName() ); + if( !m_reservoirStatsAggregator ) { // lazily initialize the region statistics aggregator - auto & flowSolver = getParent().getGroup< CompositionalMultiphaseBase >( getFlowSolverName() ); m_reservoirStatsAggregator = std::make_unique< StatsAggregator >( wellControls.getDataContext() ); m_reservoirStatsAggregator->initStatisticsAggregation( meshBodies, flowSolver ); - m_reservoirStatsAggregator->enableRegionStatisticsAggregation( meshBodies ); + m_reservoirStatsAggregator->enableRegionStatisticsAggregation(); } - m_reservoirStatsAggregator->computeRegionsStatistics( time_n, meshBodies ); - RegionStatistics & stats = m_reservoirStatsAggregator->getRegionStatistics( meshLevel, refRegionName ); + m_reservoirStatsAggregator->computeRegionsStatistics( time_n ); + RegionStatistics & stats = m_reservoirStatsAggregator->getRegionStatistics( flowMeshLevel, refRegionName ); GEOS_WARNING_IF( stats.m_averagePressure <= 0.0, GEOS_FMT( "No region average quantities computed in reference region '{}'.", diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.hpp index ce04c2631ae..a16e49b6095 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.hpp @@ -352,7 +352,7 @@ class CompositionalMultiphaseWell : public WellSolverBase virtual void validateWellConstraints( real64 const & time_n, real64 const & dt, Group & meshBodies, - MeshLevel & meshLevel, + MeshBody & meshBody, WellElementSubRegion const & subRegion ) override; /** diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.cpp index 41120d9d008..4a55ad8edce 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.cpp @@ -154,7 +154,7 @@ string SinglePhaseWell::resElementDofName() const void SinglePhaseWell::validateWellConstraints( real64 const & time_n, real64 const & GEOS_UNUSED_PARAM( dt ), Group & GEOS_UNUSED_PARAM( meshBodies ), - MeshLevel & GEOS_UNUSED_PARAM( meshLevel ), + MeshBody & GEOS_UNUSED_PARAM( meshBody ), WellElementSubRegion const & subRegion ) { WellControls & wellControls = getWellControls( subRegion ); @@ -1186,11 +1186,11 @@ void SinglePhaseWell::implicitStepSetup( real64 const & time, WellSolverBase::implicitStepSetup( time, dt, domain ); Group & meshBodies = domain.getMeshBodies(); - forDiscretizationOnMeshTargets( meshBodies, [&] ( string const &, + forDiscretizationOnMeshTargets( meshBodies, [&] ( string const & meshBodyName, MeshLevel & mesh, string_array const & regionNames ) { - + MeshBody & meshBody = domain.getMeshBody( meshBodyName ); ElementRegionManager & elemManager = mesh.getElemManager(); elemManager.forElementSubRegions< WellElementSubRegion >( regionNames, [&]( localIndex const, @@ -1214,7 +1214,7 @@ void SinglePhaseWell::implicitStepSetup( real64 const & time, getConstitutiveModel< SingleFluidBase >( subRegion, subRegion.getReference< string >( viewKeyStruct::fluidNamesString() ) ); fluid.saveConvergedState(); - validateWellConstraints( time, dt, meshBodies, mesh, subRegion ); + validateWellConstraints( time, dt, meshBodies, meshBody, subRegion ); updateSubRegionState( mesh, subRegion ); } ); diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.hpp index 40565059939..b2e2fd94d33 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.hpp @@ -296,7 +296,7 @@ class SinglePhaseWell : public WellSolverBase virtual void validateWellConstraints( real64 const & time_n, real64 const & dt, Group & meshBodies, - MeshLevel & meshLevel, + MeshBody & meshBody, WellElementSubRegion const & subRegion ) override; }; diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.cpp index aad123dd9ba..6dff86d7c0d 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.cpp @@ -21,6 +21,7 @@ #include "dataRepository/Group.hpp" #include "mesh/DomainPartition.hpp" +#include "mesh/MeshBody.hpp" #include "mesh/PerforationFields.hpp" #include "mesh/WellElementRegion.hpp" #include "mesh/WellElementSubRegion.hpp" @@ -153,16 +154,17 @@ void WellSolverBase::initializePostSubGroups() DomainPartition & domain = this->getGroupByPath< DomainPartition >( "/Problem/domain" ); FunctionManager & functionManager = FunctionManager::getInstance(); Group & meshBodies = domain.getMeshBodies(); - forDiscretizationOnMeshTargets( meshBodies, [&] ( string const &, + forDiscretizationOnMeshTargets( meshBodies, [&] ( string const & meshBodyName, MeshLevel & mesh, string_array const & regionNames ) { + MeshBody & meshBody = domain.getMeshBody( meshBodyName ); ElementRegionManager & elemManager = mesh.getElemManager(); elemManager.forElementSubRegions< WellElementSubRegion >( regionNames, [&]( localIndex const, WellElementSubRegion & subRegion ) { - validateWellConstraints( 0, 0, meshBodies, mesh, subRegion ); + validateWellConstraints( 0, 0, meshBodies, meshBody, subRegion ); // validate perforation status table PerforationData & perforationData = *subRegion.getPerforationData(); diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.hpp index b0726de1b21..6cc0e0b91fa 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.hpp @@ -322,7 +322,7 @@ class WellSolverBase : public PhysicsSolverBase virtual void validateWellConstraints( real64 const & time_n, real64 const & dt, Group & meshBodies, - MeshLevel & meshLevel, + MeshBody & meshBody, WellElementSubRegion const & subRegion ) = 0; virtual void printRates( real64 const & time_n, From d7c3ab0cbb285d33e4a7eb9eb91c1d6242a4f4dc Mon Sep 17 00:00:00 2001 From: MelReyCG Date: Wed, 21 Jan 2026 08:56:53 +0100 Subject: [PATCH 27/28] =?UTF-8?q?=F0=9F=92=84better=20stats=20table=20(TOD?= =?UTF-8?q?O=20justify=20titles=20left)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/coreComponents/common/format/table/TableTypes.hpp | 2 +- .../CompositionalMultiphaseStatisticsTask.cpp | 11 ++++++++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/coreComponents/common/format/table/TableTypes.hpp b/src/coreComponents/common/format/table/TableTypes.hpp index 4565ad92ff8..f81a368353e 100644 --- a/src/coreComponents/common/format/table/TableTypes.hpp +++ b/src/coreComponents/common/format/table/TableTypes.hpp @@ -80,7 +80,7 @@ class TableErrorListing * @brief Append a vector of string to the errors vector. * @param errors A vector of string to append */ - void appendErrors( std::vector< string > & errors ) + void appendErrors( std::vector< string > const & errors ) { m_errorList.insert( m_errorList.end(), errors.begin(), errors.end() );} /** diff --git a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsTask.cpp b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsTask.cpp index 975be720307..b33c97b5e97 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsTask.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsTask.cpp @@ -138,6 +138,8 @@ void StatsTask::registerDataOnMesh( Group & meshBodies ) prepareLogTableLayouts( mesh.getName() ); prepareCsvTableLayouts( mesh.getName() ); } ); + if( MpiWrapper::commRank() == 0 ) + getGroupByPath( "/" ).printDataHierarchy(); } void StatsTask::prepareFluidMetaData() @@ -289,10 +291,12 @@ void StatsTask::outputLogStats( real64 const statsTime, // lamda to apply for each region statistics auto const outputRegionStats = [&] ( string_view targetName, RegionStatistics & stats ) { + tableData.addSeparator(); tableData.addRow( merge, merge, merge, "" ); tableData.addSeparator(); tableData.addRow( merge, merge, merge, GEOS_FMT( "Region '{}'", targetName ) ); + tableData.addSeparator(); tableData.addRow( "statistics", "min", "average", "max" ); tableData.addSeparator(); @@ -305,7 +309,10 @@ void StatsTask::outputLogStats( real64 const statsTime, tableData.addSeparator(); - tableData.addRow( GEOS_FMT( "Total dynamic pore volume [{}]", resVolUnit ), CellType::MergeNext, CellType::MergeNext, stats.m_totalPoreVolume ); + tableData.addRow( GEOS_FMT( "Total dynamic pore volume [{}]", resVolUnit ), + "all", + CellType::MergeNext, + stats.m_totalPoreVolume ); tableData.addRow( GEOS_FMT( "Phase dynamic pore volume [{}]", resVolUnit ), stringutilities::joinLambda( m_fluid.m_phaseNames, "\n", []( auto data ) { return data[0]; } ), CellType::MergeNext, @@ -346,8 +353,6 @@ void StatsTask::outputLogStats( real64 const statsTime, "TODO" /*stringutilities::join( m_fluid.m_phaseCompNames, '\n' )*/, CellType::MergeNext, stringutilities::join( stats.m_componentMass, '\n' ) ); - - tableData.addSeparator(); }; // apply the lambda for each region and, finally, the mesh summary From 44e3c3e67571b69a955689364bf648d774b045bf Mon Sep 17 00:00:00 2001 From: MelReyCG Date: Fri, 23 Jan 2026 12:07:10 +0100 Subject: [PATCH 28/28] =?UTF-8?q?=F0=9F=90=9B=20initialized=20reference=20?= =?UTF-8?q?reservoir=20pressure=20stats=20at=20implicitStepSetup(),=20ensu?= =?UTF-8?q?re=20it=20is=20done=20only=20once?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...sitionalMultiphaseStatisticsAggregator.cpp | 50 +++-- ...sitionalMultiphaseStatisticsAggregator.hpp | 20 +- .../CompositionalMultiphaseStatisticsTask.cpp | 4 +- .../wells/CompositionalMultiphaseWell.cpp | 194 +++++++++++------- .../wells/CompositionalMultiphaseWell.hpp | 16 +- .../fluidFlow/wells/SinglePhaseWell.cpp | 39 ++-- .../fluidFlow/wells/SinglePhaseWell.hpp | 4 +- .../fluidFlow/wells/WellControls.hpp | 2 + .../fluidFlow/wells/WellSolverBase.cpp | 2 +- .../fluidFlow/wells/WellSolverBase.hpp | 2 +- 10 files changed, 217 insertions(+), 116 deletions(-) diff --git a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsAggregator.cpp b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsAggregator.cpp index dc619929b81..19f1c8aad03 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsAggregator.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsAggregator.cpp @@ -72,6 +72,7 @@ #include "CompositionalMultiphaseStatisticsAggregator.hpp" #include "LvArray/src/math.hpp" +#include "LvArray/src/system.hpp" #include "common/DataTypes.hpp" #include "common/format/Format.hpp" #include "common/format/StringUtilities.hpp" @@ -198,7 +199,8 @@ void StatsAggregator::enableRegionStatisticsAggregation() getOwnerName(), regionCount, subRegionCount ), m_ownerDataContext ); - m_isRegionStatsEnabled = true; + m_regionStatsState.m_isEnabled = true; + m_regionStatsState.m_isDirty = true; } void StatsAggregator::enableCFLStatistics() @@ -215,7 +217,8 @@ void StatsAggregator::enableCFLStatistics() statisticsGroup.registerGroup< CFLStatistics >( ViewKeys::cflStatisticsString() ); } ); - m_isCFLNumberEnabled = true; + m_cflStatsState.m_isEnabled = true; + m_cflStatsState.m_isDirty = true; } Group & StatsAggregator::getInstanceStatisticsGroup( MeshLevel & mesh ) const @@ -291,58 +294,77 @@ void StatsAggregator::forRegionStatistics( CellElementRegion & region, } ); } -bool StatsAggregator::computeRegionsStatistics( real64 const time ) +bool StatsAggregator::isComputed( real64 const timeRequest, RegionStatistics const & stats ) +{ + real64 const timePrecisionScale = LvArray::math::max( LvArray::math::abs( timeRequest ), + LvArray::math::abs( stats.m_time ) ); + static constexpr real64 timeRelTol = 1.0e-12; + + return + !m_regionStatsState.m_isDirty && + LvArray::math::abs( timeRequest - stats.m_time ) < timeRelTol * timePrecisionScale; +} + +bool StatsAggregator::computeRegionsStatistics( real64 const timeRequest ) { GEOS_MARK_FUNCTION; + GEOS_LOG_RANK_0( GEOS_FMT( "Computing for {} at stack:{}", m_ownerDataContext.toString(), LvArray::system::stackTrace( true ) )); // computation of sub region stats - forRegionStatistics( [&, time] ( MeshLevel & mesh, RegionStatistics & meshRegionsStats ) + forRegionStatistics( [&, timeRequest] ( MeshLevel & mesh, RegionStatistics & meshRegionsStats ) { forRegionStatistics( mesh, meshRegionsStats, - [&, time] ( CellElementRegion & region, RegionStatistics & regionStats ) + [&, timeRequest] ( CellElementRegion & region, RegionStatistics & regionStats ) { forRegionStatistics( region, regionStats, - [&, time] ( CellElementSubRegion & subRegion, RegionStatistics & subRegionStats ) + [&, timeRequest] ( CellElementSubRegion & subRegion, RegionStatistics & subRegionStats ) { - initStats( subRegionStats, time ); + initStats( subRegionStats, timeRequest ); computeSubRegionRankStats( subRegion, subRegionStats ); + GEOS_LOG_RANK_0( GEOS_FMT( "Computed {}: {} Pa / {} Pa / {} Pa", subRegionStats.getPath(), subRegionStats.m_minPressure, subRegionStats.m_averagePressure, subRegionStats.m_maxPressure )); } ); } ); } ); // aggregation of computations from the sub regions - forRegionStatistics( [&, time] ( MeshLevel & mesh, RegionStatistics & meshRegionsStats ) + forRegionStatistics( [&, timeRequest] ( MeshLevel & mesh, RegionStatistics & meshRegionsStats ) { - initStats( meshRegionsStats, time ); + initStats( meshRegionsStats, timeRequest ); forRegionStatistics( mesh, meshRegionsStats, - [&, time] ( CellElementRegion & region, RegionStatistics & regionStats ) + [&, timeRequest] ( CellElementRegion & region, RegionStatistics & regionStats ) { - initStats( regionStats, time ); + initStats( regionStats, timeRequest ); forRegionStatistics( region, regionStats, - [&, time] ( CellElementSubRegion &, RegionStatistics & subRegionStats ) + [&, timeRequest] ( CellElementSubRegion &, RegionStatistics & subRegionStats ) { aggregateStats( regionStats, subRegionStats ); mpiAggregateStats( subRegionStats ); postAggregateStats( subRegionStats ); + GEOS_LOG_RANK_0( GEOS_FMT( "Aggregated {}: {} Pa / {} Pa / {} Pa", subRegionStats.getPath(), subRegionStats.m_minPressure, subRegionStats.m_averagePressure, subRegionStats.m_maxPressure )); } ); aggregateStats( meshRegionsStats, regionStats ); mpiAggregateStats( regionStats ); postAggregateStats( regionStats ); + GEOS_LOG_RANK_0( GEOS_FMT( "Aggregated {}: {} Pa / {} Pa / {} Pa", regionStats.getPath(), regionStats.m_minPressure, regionStats.m_averagePressure, regionStats.m_maxPressure )); } ); mpiAggregateStats( meshRegionsStats ); postAggregateStats( meshRegionsStats ); + GEOS_LOG_RANK_0( GEOS_FMT( "Aggregated {}: {} Pa / {} Pa / {} Pa", + meshRegionsStats.getPath(), meshRegionsStats.m_minPressure, meshRegionsStats.m_averagePressure, meshRegionsStats.m_maxPressure )); } ); + m_regionStatsState.m_isDirty = false; + return true; } @@ -528,7 +550,7 @@ bool StatsAggregator::computeCFLNumbers( real64 const time, m_warnings.clear(); - if( !m_isCFLNumberEnabled ) + if( !m_cflStatsState.m_isEnabled ) { m_warnings.emplace_back( "CFL numbers computation is not enabled." ); return false; @@ -545,6 +567,8 @@ bool StatsAggregator::computeCFLNumbers( real64 const time, stats->m_maxPhaseCFL = maxPhaseCFL; stats->m_maxCompCFL = maxCompCFL; + m_cflStatsState.m_isDirty = false; + return true; } diff --git a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsAggregator.hpp b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsAggregator.hpp index 450c8f5f13d..9eba40f250d 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsAggregator.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsAggregator.hpp @@ -220,13 +220,20 @@ class StatsAggregator RegionStatistics & regionStatistics, RegionStatisticsFunctor< CellElementSubRegion > const & functor ) const; + /** + * @param[in] timeRequest The time for which we want to know if the statistics are computed. + * @param[in] stats the statistics data structure we want to know if it has been computed + * @return true if the statistics have been computed. + */ + bool isComputed( real64 const timeRequest, RegionStatistics const & stats ); + /** * @brief Compute statistics on the mesh discretizations (average field pressure, etc) * Results are reduced on rank 0, and broadcasted over all ranks. - * @param[in] time current time + * @param[in] timeRequest The time for which we want to compute the statistics. * @return false if there was a problem that prevented the statistics to be computed correctly. */ - bool computeRegionsStatistics( real64 const time ); + bool computeRegionsStatistics( real64 const timeRequest ); /** * @brief Compute CFL numbers @@ -280,6 +287,11 @@ class StatsAggregator private: + struct StatsState { + bool m_isEnabled = false; + bool m_isDirty = false; + }; + /// @see getOwnerName() dataRepository::DataContext const & m_ownerDataContext; @@ -291,9 +303,9 @@ class StatsAggregator stdVector< string > m_warnings; - bool m_isRegionStatsEnabled = false; + StatsState m_regionStatsState; - bool m_isCFLNumberEnabled = false; + StatsState m_cflStatsState; integer m_numPhases; diff --git a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsTask.cpp b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsTask.cpp index b33c97b5e97..7bf2d2de9f0 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsTask.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/CompositionalMultiphaseStatisticsTask.cpp @@ -138,8 +138,8 @@ void StatsTask::registerDataOnMesh( Group & meshBodies ) prepareLogTableLayouts( mesh.getName() ); prepareCsvTableLayouts( mesh.getName() ); } ); - if( MpiWrapper::commRank() == 0 ) - getGroupByPath( "/" ).printDataHierarchy(); + // if( MpiWrapper::commRank() == 0 ) + // getGroupByPath( "/" ).printDataHierarchy(); } void StatsTask::prepareFluidMetaData() diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp index 9c108271307..3bc8543e5bb 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp @@ -19,6 +19,7 @@ #include "CompositionalMultiphaseWell.hpp" +#include "LvArray/src/system.hpp" #include "codingUtilities/Utilities.hpp" #include "common/DataTypes.hpp" #include "common/TimingMacros.hpp" @@ -29,6 +30,7 @@ #include "constitutive/fluid/multifluid/MultiFluidSelector.hpp" #include "dataRepository/Group.hpp" #include "mesh/DomainPartition.hpp" +#include "mesh/MeshBody.hpp" #include "mesh/PerforationFields.hpp" #include "mesh/WellElementSubRegion.hpp" #include "mesh/mpiCommunications/CommunicationTools.hpp" @@ -155,6 +157,7 @@ void CompositionalMultiphaseWell::postInputInitialization() void CompositionalMultiphaseWell::registerDataOnMesh( Group & meshBodies ) { WellSolverBase::registerDataOnMesh( meshBodies ); + GEOS_LOG_RANK_0( " --------> CompositionalMultiphaseWell::registerDataOnMesh" ); DomainPartition const & domain = this->getGroupByPath< DomainPartition >( "/Problem/domain" ); ConstitutiveManager const & cm = domain.getConstitutiveManager(); @@ -358,6 +361,7 @@ void compareMulticomponentModels( MODEL1_TYPE const & lhs, MODEL2_TYPE const & r void CompositionalMultiphaseWell::validateWellControlsForFluid( WellControls const & wellControls, MultiFluidBase const & fluid ) const { + GEOS_LOG_RANK_0( " --------> CompositionalMultiphaseWell::validateWellControlsForFluid" ); if( wellControls.useSurfaceConditions() ) { try @@ -379,6 +383,7 @@ void CompositionalMultiphaseWell::validateWellControlsForFluid( WellControls con void CompositionalMultiphaseWell::validateConstitutiveModels( DomainPartition const & domain ) const { GEOS_MARK_FUNCTION; + GEOS_LOG_RANK_0( " --------> CompositionalMultiphaseWell::validateConstitutiveModels" ); ConstitutiveManager const & cm = domain.getConstitutiveManager(); CompositionalMultiphaseBase const & flowSolver = getFlowSolver( *this ); @@ -408,6 +413,7 @@ void CompositionalMultiphaseWell::validateConstitutiveModels( DomainPartition co void CompositionalMultiphaseWell::validateInjectionStreams( WellElementSubRegion const & subRegion ) const { WellControls const & wellControls = getWellControls( subRegion ); + GEOS_LOG_RANK_0( " --------> CompositionalMultiphaseWell::validateInjectionStreams" ); // check well injection stream for injectors if( wellControls.isInjector()) @@ -445,10 +451,11 @@ void CompositionalMultiphaseWell::validateInjectionStreams( WellElementSubRegion void CompositionalMultiphaseWell::validateWellConstraints( real64 const & time_n, real64 const & GEOS_UNUSED_PARAM( dt ), - Group & meshBodies, - MeshBody & meshBody, + Group &, // TODO: remove ? + MeshBody &, // TODO: remove ? WellElementSubRegion const & subRegion ) { + GEOS_LOG_RANK_0( GEOS_FMT( " ---------------------> CompositionalMultiphaseWell::validateWellConstraints\n{}", LvArray::system::stackTrace( true ) ) ); WellControls & wellControls = getWellControls( subRegion ); string_view refRegionName = wellControls.referenceReservoirRegion(); @@ -457,32 +464,6 @@ void CompositionalMultiphaseWell::validateWellConstraints( real64 const & time_n { GEOS_WARNING( "WellControls " << WellControls::viewKeyStruct::referenceReservoirRegionString() << " not set and well constraint fluid property calculations will use top segement pressure and temp " ); - wellControls.setRegionAveragePressure( -1 ); - wellControls.setRegionAverageTemperature( -1 ); - } - else - { - auto & flowSolver = getParent().getGroup< CompositionalMultiphaseBase >( getFlowSolverName() ); - MeshLevel & flowMeshLevel = meshBody.getMeshLevel( flowSolver.getDiscretizationName() ); - - if( !m_reservoirStatsAggregator ) - { // lazily initialize the region statistics aggregator - m_reservoirStatsAggregator = std::make_unique< StatsAggregator >( wellControls.getDataContext() ); - m_reservoirStatsAggregator->initStatisticsAggregation( meshBodies, flowSolver ); - m_reservoirStatsAggregator->enableRegionStatisticsAggregation(); - } - - m_reservoirStatsAggregator->computeRegionsStatistics( time_n ); - RegionStatistics & stats = m_reservoirStatsAggregator->getRegionStatistics( flowMeshLevel, refRegionName ); - - GEOS_WARNING_IF( stats.m_averagePressure <= 0.0, - GEOS_FMT( "No region average quantities computed in reference region '{}'.", - wellControls.referenceReservoirRegion() ), - wellControls.getWrapperDataContext( WellControls::viewKeyStruct::referenceReservoirRegionString() ), - getDataContext() ); - - wellControls.setRegionAveragePressure( stats.m_averagePressure ); - wellControls.setRegionAverageTemperature( stats.m_averageTemperature ); } string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString()); @@ -551,6 +532,7 @@ void CompositionalMultiphaseWell::initializePostSubGroups() { WellSolverBase::initializePostSubGroups(); + GEOS_LOG_RANK_0( " --------> CompositionalMultiphaseWell::initializePostSubGroups" ); DomainPartition & domain = this->getGroupByPath< DomainPartition >( "/Problem/domain" ); validateConstitutiveModels( domain ); @@ -569,12 +551,14 @@ void CompositionalMultiphaseWell::initializePostSubGroups() void CompositionalMultiphaseWell::initializePostInitialConditionsPreSubGroups() { + GEOS_LOG_RANK_0( " --------> CompositionalMultiphaseWell::mmSIMULAParavie" ); WellSolverBase::initializePostInitialConditionsPreSubGroups(); createSeparator(); } void CompositionalMultiphaseWell::postRestartInitialization() { + GEOS_LOG_RANK_0( " --------> CompositionalMultiphaseWell::postRestartInitialization" ); DomainPartition & domain = this->getGroupByPath< DomainPartition >( "/Problem/domain" ); forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, MeshLevel & mesh, @@ -701,11 +685,11 @@ void CompositionalMultiphaseWell::updateBHPForConstraint( WellElementSubRegion & } -void CompositionalMultiphaseWell::updateVolRatesForConstraint( MeshLevel & GEOS_UNUSED_PARAM( meshLevel ), - WellElementSubRegion const & subRegion ) +void CompositionalMultiphaseWell::updateVolRatesForConstraint( WellElementSubRegion const & subRegion ) { GEOS_MARK_FUNCTION; + GEOS_LOG_RANK_0( GEOS_FMT( " ---------------------> CompositionalMultiphaseWell::updateVolRatesForConstraint\n{}", LvArray::system::stackTrace( true ) ) ); // the rank that owns the reference well element is responsible for the calculations below. if( !subRegion.isLocallyOwned() ) { @@ -720,9 +704,6 @@ void CompositionalMultiphaseWell::updateVolRatesForConstraint( MeshLevel & GEOS_ WellControls & wellControls = getWellControls( subRegion ); // subRegion data - - arrayView1d< real64 const > const & pres = subRegion.getField< well::pressure >(); - arrayView1d< real64 const > const & temp = subRegion.getField< well::temperature >(); arrayView1d< real64 const > const & connRate = subRegion.getField< well::mixtureConnectionRate >(); arrayView2d< real64 const, compflow::USD_COMP > const & compFrac = subRegion.getField< well::globalCompFraction >(); @@ -747,25 +728,7 @@ void CompositionalMultiphaseWell::updateVolRatesForConstraint( MeshLevel & GEOS_ string const massUnit = m_useMass ? "kg" : "mol"; integer const useSurfaceConditions = wellControls.useSurfaceConditions(); - real64 flashPressure; - real64 flashTemperature; - if( useSurfaceConditions ) - { - // use surface conditions - flashPressure = wellControls.getSurfacePressure(); - flashTemperature = wellControls.getSurfaceTemperature(); - } - else - { - // If flashPressure is not set by region the value is defaulted to -1 and indicates to use top segment conditions - flashPressure = wellControls.getRegionAveragePressure(); - flashTemperature = wellControls.getRegionAverageTemperature(); - if( flashPressure <= 0.0 || flashTemperature <= 0.0 ) - { // region average stats not initialized, fallback to top segment values - flashPressure = pres[iwelemRef]; - flashTemperature = temp[iwelemRef]; - } - } + FlashConditions const flashConditions = getFlashConditions( subRegion ); arrayView1d< real64 > const & currentPhaseVolRate = wellControls.getReference< array1d< real64 > >( CompositionalMultiphaseWell::viewKeyStruct::currentPhaseVolRateString() ); @@ -796,8 +759,6 @@ void CompositionalMultiphaseWell::updateVolRatesForConstraint( MeshLevel & GEOS_ forAll< serialPolicy >( 1, [&numComp, &numPhase, fluidSeparatorWrapper, - pres, - temp, compFrac, dCompFrac_dCompDens, connRate, @@ -809,8 +770,7 @@ void CompositionalMultiphaseWell::updateVolRatesForConstraint( MeshLevel & GEOS_ dPhaseFrac, logSurfaceCondition, &useSurfaceConditions, - &flashPressure, - &flashTemperature, + &flashConditions, ¤tTotalVolRate, dCurrentTotalVolRate, currentPhaseVolRate, @@ -833,11 +793,13 @@ void CompositionalMultiphaseWell::updateVolRatesForConstraint( MeshLevel & GEOS_ if( useSurfaceConditions ) { // we need to compute the surface density - fluidSeparatorWrapper.update( iwelemRef, 0, flashPressure, flashTemperature, compFrac[iwelemRef] ); + fluidSeparatorWrapper.update( iwelemRef, 0, + flashConditions.pressure, flashConditions.temperature, + compFrac[iwelemRef] ); if( logSurfaceCondition ) { GEOS_LOG_RANK( GEOS_FMT( "{}: surface density computed with P_surface = {} Pa and T_surface = {} K", - wellControlsName, flashPressure, flashTemperature ) ); + wellControlsName, flashConditions.pressure, flashConditions.temperature ) ); } #ifdef GEOS_USE_HIP GEOS_UNUSED_VAR( wellControlsName ); @@ -846,7 +808,9 @@ void CompositionalMultiphaseWell::updateVolRatesForConstraint( MeshLevel & GEOS_ } else { - fluidSeparatorWrapper.update( iwelemRef, 0, flashPressure, flashTemperature, compFrac[iwelemRef] ); + fluidSeparatorWrapper.update( iwelemRef, 0, + flashConditions.pressure, flashConditions.temperature, + compFrac[iwelemRef] ); } // Step 2: update the total volume rate @@ -935,7 +899,91 @@ void CompositionalMultiphaseWell::updateVolRatesForConstraint( MeshLevel & GEOS_ } ); } +void CompositionalMultiphaseWell::precomputeFlashConditions( real64 const time_n, + Group & meshBodies, + MeshBody & meshBody, + WellElementSubRegion const & subRegion ) +{ + WellControls & wellControls = getWellControls( subRegion ); + integer const useSurfaceConditions = wellControls.useSurfaceConditions(); + if( !useSurfaceConditions ) + { + string_view refRegionName = wellControls.referenceReservoirRegion(); + bool const useSegmentValues = refRegionName.empty(); + if( useSegmentValues ) + { + wellControls.setRegionAveragePressure( -1 ); + wellControls.setRegionAverageTemperature( -1 ); + } + else + { + auto & flowSolver = getParent().getGroup< CompositionalMultiphaseBase >( getFlowSolverName() ); + MeshLevel & flowMeshLevel = meshBody.getMeshLevel( flowSolver.getDiscretizationName() ); + + if( !m_reservoirStatsAggregator ) + { // lazily initialize the region statistics aggregator + m_reservoirStatsAggregator = std::make_unique< StatsAggregator >( wellControls.getDataContext() ); + m_reservoirStatsAggregator->initStatisticsAggregation( meshBodies, flowSolver ); + m_reservoirStatsAggregator->enableRegionStatisticsAggregation(); + } + + RegionStatistics & stats = m_reservoirStatsAggregator->getRegionStatistics( flowMeshLevel, refRegionName ); + + // compute region stats only if needed (could have already been done for another subRegion) + if( !m_reservoirStatsAggregator->isComputed( time_n, stats ) ) + m_reservoirStatsAggregator->computeRegionsStatistics( time_n ); + + GEOS_LOG( GEOS_FMT( "Accessing {}: {} Pa / {} Pa / {} Pa", stats.getPath(), stats.m_minPressure, stats.m_averagePressure, stats.m_maxPressure )); + + GEOS_WARNING_IF( stats.m_averagePressure <= 0.0, + GEOS_FMT( "No region average quantities computed in reference region '{}'.", + wellControls.referenceReservoirRegion() ), + wellControls.getWrapperDataContext( WellControls::viewKeyStruct::referenceReservoirRegionString() ), + getDataContext() ); + + wellControls.setRegionAveragePressure( stats.m_averagePressure ); + wellControls.setRegionAverageTemperature( stats.m_averageTemperature ); + } + } +} + +CompositionalMultiphaseWell::FlashConditions +CompositionalMultiphaseWell::getFlashConditions( WellElementSubRegion const & subRegion ) +{ + WellControls & wellControls = getWellControls( subRegion ); + integer const useSurfaceConditions = wellControls.useSurfaceConditions(); + if( useSurfaceConditions ) + { + // use surface conditions + return { + /* .pressure = */ wellControls.getSurfacePressure(), + /* .temperature = */ wellControls.getSurfaceTemperature(), + }; + } + else + { + if( wellControls.getRegionAveragePressure() > 0.0 && wellControls.getRegionAverageTemperature() > 0.0 ) + { // reference region condition properly computed, we can return them + return { + /* .pressure = */ wellControls.getRegionAveragePressure(), + /* .temperature = */ wellControls.getRegionAverageTemperature(), + }; + } + else + { // region average stats not initialized or initialized, fallback to top segment values + GEOS_WARNING( "CompositionalMultiphaseWell: region average stats not initialized," + " fallback to top segment values" ); // TODO: re-redact + arrayView1d< real64 const > const & pres = subRegion.getField< well::pressure >(); + arrayView1d< real64 const > const & temp = subRegion.getField< well::temperature >(); + localIndex const iwelemRef = subRegion.getTopWellElementIndex(); + return { + /* .pressure = */ pres[iwelemRef], + /* .temperature = */ temp[iwelemRef], + }; + } + } +} void CompositionalMultiphaseWell::updateFluidModel( WellElementSubRegion & subRegion ) { @@ -1027,7 +1075,7 @@ void CompositionalMultiphaseWell::updateState( DomainPartition & domain ) WellControls & wellControls = getWellControls( subRegion ); if( wellControls.getWellStatus() == WellControls::Status::OPEN ) { - real64 const maxRegionPhaseVolFrac = updateSubRegionState( mesh, subRegion ); + real64 const maxRegionPhaseVolFrac = updateSubRegionState( subRegion ); maxPhaseVolFrac = LvArray::math::max( maxRegionPhaseVolFrac, maxPhaseVolFrac ); } } ); @@ -1040,15 +1088,14 @@ void CompositionalMultiphaseWell::updateState( DomainPartition & domain ) } -real64 CompositionalMultiphaseWell::updateSubRegionState( MeshLevel & mesh, - WellElementSubRegion & subRegion ) +real64 CompositionalMultiphaseWell::updateSubRegionState( WellElementSubRegion & subRegion ) { // update properties updateGlobalComponentFraction( subRegion ); // update volumetric rates for the well constraints // note: this must be called before updateFluidModel - updateVolRatesForConstraint( mesh, subRegion ); + updateVolRatesForConstraint( subRegion ); // update densities, phase fractions, phase volume fractions @@ -1063,19 +1110,22 @@ real64 CompositionalMultiphaseWell::updateSubRegionState( MeshLevel & mesh, void CompositionalMultiphaseWell::initializeWells( DomainPartition & domain, real64 const & time_n ) { GEOS_MARK_FUNCTION; + GEOS_LOG_RANK_0( " --------> CompositionalMultiphaseWell::initializeWells" ); integer const numComp = m_numComponents; integer const numPhase = m_numPhases; + Group & meshBodies = domain.getMeshBodies(); CompositionalMultiphaseBase const & flowSolver = getFlowSolver( *this ); // loop over the wells - forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &, + forDiscretizationOnMeshTargets( meshBodies, [&] ( string const & meshBodyName, MeshLevel & mesh, string_array const & regionNames ) { - + MeshBody & meshBody = domain.getMeshBody(meshBodyName); ElementRegionManager & elemManager = mesh.getElemManager(); + compositionalMultiphaseWellKernels::PresTempCompFracInitializationKernel::CompFlowAccessors resCompFlowAccessors( mesh.getElemManager(), flowSolver.getName() ); compositionalMultiphaseWellKernels::PresTempCompFracInitializationKernel::MultiFluidAccessors @@ -1165,7 +1215,8 @@ void CompositionalMultiphaseWell::initializeWells( DomainPartition & domain, rea wellElemCompDens ); // 5) Recompute the pressure-dependent properties - updateSubRegionState( mesh, subRegion ); + precomputeFlashConditions(time_n, meshBodies, meshBody, subRegion); + updateSubRegionState( subRegion ); // 6) Estimate the well rates // TODO: initialize rates using perforation rates @@ -1971,7 +2022,7 @@ void CompositionalMultiphaseWell::resetStateToBeginningOfStep( DomainPartition & if( wellControls.isWellOpen( ) ) { - updateSubRegionState( mesh, subRegion ); + updateSubRegionState( subRegion ); } } ); } ); @@ -2107,14 +2158,15 @@ void CompositionalMultiphaseWell::implicitStepSetup( real64 const & time_n, real64 const & dt, DomainPartition & domain ) { + GEOS_LOG_RANK_0( " --------> CompositionalMultiphaseWell::implicitStepSetup" ); WellSolverBase::implicitStepSetup( time_n, dt, domain ); Group & meshBodies = domain.getMeshBodies(); - forDiscretizationOnMeshTargets ( meshBodies, [&] ( string const &, + forDiscretizationOnMeshTargets ( meshBodies, [&] ( string const & meshBodyName, MeshLevel & mesh, string_array const & regionNames ) { - + MeshBody & meshBody = domain.getMeshBody( meshBodyName ); ElementRegionManager & elemManager = mesh.getElemManager(); elemManager.forElementSubRegions< WellElementSubRegion >( regionNames, @@ -2164,9 +2216,9 @@ void CompositionalMultiphaseWell::implicitStepSetup( real64 const & time_n, MultiFluidBase const & fluid = getConstitutiveModel< MultiFluidBase >( subRegion, fluidName ); fluid.saveConvergedState(); - validateWellConstraints( time_n, dt, meshBodies, mesh, subRegion ); + validateWellConstraints( time_n, dt, meshBodies, meshBody, subRegion ); - updateSubRegionState( mesh, subRegion ); + updateSubRegionState( subRegion ); } } ) ; diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.hpp index a16e49b6095..6e8d6d10cff 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.hpp @@ -20,6 +20,7 @@ #ifndef GEOS_PHYSICSSOLVERS_FLUIDFLOW_WELLS_COMPOSITIONALMULTIPHASEWELL_HPP_ #define GEOS_PHYSICSSOLVERS_FLUIDFLOW_WELLS_COMPOSITIONALMULTIPHASEWELL_HPP_ +#include "common/DataTypes.hpp" #include "constitutive/fluid/multifluid/Layouts.hpp" #include "constitutive/relativePermeability/Layouts.hpp" #include "mesh/MeshLevel.hpp" @@ -149,7 +150,7 @@ class CompositionalMultiphaseWell : public WellSolverBase * @param elemManager the well region manager containing the well * @param subRegion the well subregion containing all the primary and dependent fields */ - void updateVolRatesForConstraint( MeshLevel & mesh, WellElementSubRegion const & subRegion ); + void updateVolRatesForConstraint( WellElementSubRegion const & subRegion ); /** * @brief Recompute the current BHP pressure @@ -191,7 +192,7 @@ class CompositionalMultiphaseWell : public WellSolverBase */ virtual void updateState( DomainPartition & domain ) override; - virtual real64 updateSubRegionState( MeshLevel & meshLevel, WellElementSubRegion & subRegion ) override; + virtual real64 updateSubRegionState( WellElementSubRegion & subRegion ) override; virtual string wellElementDofName() const override { return viewKeyStruct::dofFieldString(); } @@ -366,6 +367,12 @@ class CompositionalMultiphaseWell : public WellSolverBase private: + struct FlashConditions + { + real64 pressure; + real64 temperature; + }; + /** * @brief Initialize all the primary and secondary variables in all the wells * @param domain the domain containing the well manager to access individual wells @@ -374,7 +381,12 @@ class CompositionalMultiphaseWell : public WellSolverBase virtual void setConstitutiveNames( ElementSubRegionBase & subRegion ) const override; + void precomputeFlashConditions( real64 time_n, + Group & meshBodies, + MeshBody & meshBody, + WellElementSubRegion const & subRegion ); + FlashConditions getFlashConditions( WellElementSubRegion const & subRegion ); /// flag indicating whether mass or molar formulation should be used integer m_useMass; diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.cpp index 4a55ad8edce..4e99fbf9145 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.cpp @@ -266,7 +266,7 @@ void SinglePhaseWell::updateBHPForConstraint( WellElementSubRegion & subRegion ) } -void SinglePhaseWell::updateVolRateForConstraint( MeshLevel & mesh, WellElementSubRegion & subRegion ) +void SinglePhaseWell::updateVolRateForConstraint( WellElementSubRegion & subRegion ) { GEOS_MARK_FUNCTION; @@ -309,19 +309,19 @@ void SinglePhaseWell::updateVolRateForConstraint( MeshLevel & mesh, WellElementS { if( !wellControls.referenceReservoirRegion().empty() ) { - ElementRegionManager const & elemManager = mesh.getElemManager(); - ElementRegionBase const & region = elemManager.getRegion( wellControls.referenceReservoirRegion() ); - GEOS_ERROR_IF ( !region.hasWrapper( SinglePhaseStatistics::regionStatisticsName()), - GEOS_FMT( "{}: WellControl {} referenceReservoirRegion field requires SinglePhaseStatistics to be configured for region {} ", - getDataContext(), wellControls.getName(), wellControls.referenceReservoirRegion() ) ); - - SinglePhaseStatistics::RegionStatistics const & stats = region.getReference< SinglePhaseStatistics::RegionStatistics >( SinglePhaseStatistics::regionStatisticsName() ); - GEOS_ERROR_IF( stats.averagePressure <= 0.0, - GEOS_FMT( - "{}: No region average quantities computed. WellControl {} referenceReservoirRegion field requires SinglePhaseStatistics to be configured for region {} ", - getDataContext(), wellControls.getName(), wellControls.referenceReservoirRegion() )); - wellControls.setRegionAveragePressure( stats.averagePressure ); - wellControls.setRegionAverageTemperature( stats.averageTemperature ); + // ElementRegionManager const & elemManager = mesh.getElemManager(); + // ElementRegionBase const & region = elemManager.getRegion( wellControls.referenceReservoirRegion() ); + // GEOS_ERROR_IF ( !region.hasWrapper( SinglePhaseStatistics::regionStatisticsName()), + // GEOS_FMT( "{}: WellControl {} referenceReservoirRegion field requires SinglePhaseStatistics to be configured for region {} ", + // getDataContext(), wellControls.getName(), wellControls.referenceReservoirRegion() ) ); + + // SinglePhaseStatistics::RegionStatistics const & stats = region.getReference< SinglePhaseStatistics::RegionStatistics >( SinglePhaseStatistics::regionStatisticsName() ); + // GEOS_ERROR_IF( stats.averagePressure <= 0.0, + // GEOS_FMT( + // "{}: No region average quantities computed. WellControl {} referenceReservoirRegion field requires SinglePhaseStatistics to be configured for region {} ", + // getDataContext(), wellControls.getName(), wellControls.referenceReservoirRegion() )); + // wellControls.setRegionAveragePressure( stats.averagePressure ); + // wellControls.setRegionAverageTemperature( stats.averageTemperature ); } // use region conditions flashPressure = wellControls.getRegionAveragePressure(); @@ -421,12 +421,11 @@ void SinglePhaseWell::updateFluidModel( WellElementSubRegion & subRegion ) const } ); } -real64 SinglePhaseWell::updateSubRegionState( MeshLevel & mesh, - WellElementSubRegion & subRegion ) +real64 SinglePhaseWell::updateSubRegionState( WellElementSubRegion & subRegion ) { // update volumetric rates for the well constraints // Warning! This must be called before updating the fluid model - updateVolRateForConstraint( mesh, subRegion ); + updateVolRateForConstraint( subRegion ); // update density in the well elements updateFluidModel( subRegion ); @@ -512,7 +511,7 @@ void SinglePhaseWell::initializeWells( DomainPartition & domain, real64 const & // 4) Recompute the pressure-dependent properties // Note: I am leaving that here because I would like to use the perforationRates (computed in UpdateState) // to better initialize the rates - updateSubRegionState( meshLevel, subRegion ); + updateSubRegionState( subRegion ); string const & fluidName = subRegion.getReference< string >( viewKeyStruct::fluidNamesString() ); SingleFluidBase & fluid = subRegion.getConstitutiveModel< SingleFluidBase >( fluidName ); @@ -1173,7 +1172,7 @@ void SinglePhaseWell::resetStateToBeginningOfStep( DomainPartition & domain ) subRegion.getField< well::connectionRate_n >(); connRate.setValues< parallelDevicePolicy<> >( connRate_n ); - updateSubRegionState( mesh, subRegion ); + updateSubRegionState( subRegion ); } ); } ); } @@ -1216,7 +1215,7 @@ void SinglePhaseWell::implicitStepSetup( real64 const & time, validateWellConstraints( time, dt, meshBodies, meshBody, subRegion ); - updateSubRegionState( mesh, subRegion ); + updateSubRegionState( subRegion ); } ); } ); } diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.hpp index b2e2fd94d33..5c4fffe466b 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.hpp @@ -143,7 +143,7 @@ class SinglePhaseWell : public WellSolverBase * @param elemManager the well region manager * @param subRegion the well subregion containing all the primary and dependent fields */ - virtual void updateVolRateForConstraint( MeshLevel & meshLevel, WellElementSubRegion & subRegion ); + virtual void updateVolRateForConstraint( WellElementSubRegion & subRegion ); /** * @brief Recompute the BHP pressure that is used in the well constraints @@ -169,7 +169,7 @@ class SinglePhaseWell : public WellSolverBase * @param elemManager the elemManager containing the well * @param subRegion the well subRegion containing the well elements and their associated fields */ - virtual real64 updateSubRegionState( MeshLevel & meshLevel, WellElementSubRegion & subRegion ) override; + virtual real64 updateSubRegionState( WellElementSubRegion & subRegion ) override; /** * @brief function to assemble the linear system matrix and rhs diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellControls.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellControls.hpp index cad56c2ebbe..a85e2868941 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellControls.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellControls.hpp @@ -316,12 +316,14 @@ class WellControls : public dataRepository::Group /** * @brief Getter for the reservoir average pressure when m_useSurfaceConditions == 0 + * @note When not available, value is less or equal to 0.0. * @return the pressure */ real64 getRegionAveragePressure() const { return m_regionAveragePressure; } /** * @brief Set the reservoir average pressure when m_useSurfaceConditions == 0 + * @note When not available, value is less or equal to 0.0. * @param[in] regionAveragePressure value for pressure */ void setRegionAveragePressure( real64 regionAveragePressure ) { m_regionAveragePressure = regionAveragePressure; } diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.cpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.cpp index 6dff86d7c0d..dacc4420bd4 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.cpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.cpp @@ -313,7 +313,7 @@ void WellSolverBase::updateState( DomainPartition & domain ) ElementRegionManager & elemManager = mesh.getElemManager(); elemManager.forElementSubRegions< WellElementSubRegion >( regionNames, [&]( localIndex const, WellElementSubRegion & subRegion ) - { updateSubRegionState( mesh, subRegion ); } ); + { updateSubRegionState( subRegion ); } ); } ); } diff --git a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.hpp b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.hpp index 6cc0e0b91fa..d92e00eded7 100644 --- a/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.hpp +++ b/src/coreComponents/physicsSolvers/fluidFlow/wells/WellSolverBase.hpp @@ -253,7 +253,7 @@ class WellSolverBase : public PhysicsSolverBase * @param elemManager the elemManager containing the well * @param subRegion the well subRegion containing the well elements and their associated fields */ - virtual real64 updateSubRegionState( MeshLevel & meshLevel, WellElementSubRegion & subRegion ) = 0; + virtual real64 updateSubRegionState( WellElementSubRegion & subRegion ) = 0; /** * @brief Recompute the perforation rates for all the wells