Skip to content

Implement arbitrary region statistics#3037

Closed
dkachuma wants to merge 9 commits into
developfrom
feature/dkachuma/region-statistics
Closed

Implement arbitrary region statistics#3037
dkachuma wants to merge 9 commits into
developfrom
feature/dkachuma/region-statistics

Conversation

@dkachuma
Copy link
Copy Markdown
Contributor

@dkachuma dkachuma commented Mar 11, 2024

The purpose of this PR is to allow the user to report region statistics for arbitrary cell regions (cell collections) that are not linked to the simulation (solvers or constitutive models).

The idea is that the user will create a task similar to CompositionalMultiphaseStatistics. With that they can specify the properties to report and then target this with an event.

    <Tasks>
        <RegionMultiphaseStatistics
            name="REGION.STATISTICS"
            flowSolverName="FLOW.SOLVER"
            regionNames="{ PLATFORM_A, PLATFORM_B1, PLATFORM_B2 }"
            regionIdentifiers="{ 13, 28, 3 }"
            propertyNames="{ pressure, poreVolume, volumeFraction }"
            writeCSV="1"
            logLevel="1" />
    </Tasks>
    <Events>
        <PeriodicEvent
            name="REGION.STATISTICS"
            target="/Tasks/REGION.STATISTICS"
            timeFrequency="7200" />
    </Events>

In this example, there are 3 non-overlapping regions named PLATFORM_A, PLATFORM_B1 and PLATFORM_B2 not linked to the simulation and the user wants statistics for pressure, pore volume and volume fraction in these regions. The 3 regions are identified by an attribute and these are assigned values 13, 28 and 3 respectively. The creation of the task will create a fieldName REGION.STATISTICS_region for each grid cell. The user can use this field to load a property and mark the cells belonging to each region. For example

    <Mesh>
        <VTKMesh
            name="MESH"
            file="mesh.vtu"
            regionAttribute="attribute"
            fieldsToImport="{ report }"
            fieldNamesInGEOSX="{ REGION.STATISTICS_region }"
            logLevel="5" />
    </Mesh>

@dkachuma dkachuma self-assigned this Mar 12, 2024
@dkachuma dkachuma added the spe11 spe11-required-feature label Mar 12, 2024
@jafranc
Copy link
Copy Markdown
Contributor

jafranc commented Mar 13, 2024

Great idea. Can we make it work with '' define boxes too ?

@dkachuma dkachuma requested a review from MelReyCG March 25, 2024 20:05
Copy link
Copy Markdown
Contributor

@MelReyCG MelReyCG left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here is a batch of (non-blocking) comments. we could meet to discuss about them.

Comment on lines +138 to +142
GEOS_HOST_DEVICE
static constexpr real64 safeInverse( real64 const val )
{
return (val < LvArray::NumericLimits< real64 >::epsilon) ? 0.0 : 1.0 / val;
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could this be exposed in a header that is commonly used for calculations? I think safe-dividing could be useful to everyone. :)

Comment on lines +583 to +598
regData[Statistics::CELL_COUNT] = MpiWrapper::sum( regData[Statistics::CELL_COUNT] );
regData[Statistics::STATIC_PORE_VOLUME] = MpiWrapper::sum( regData[Statistics::STATIC_PORE_VOLUME] );
regData[Statistics::PORE_VOLUME] = MpiWrapper::sum( regData[Statistics::PORE_VOLUME] );

regData[Statistics::MINIMUM_PRESSURE] = MpiWrapper::min( regData[Statistics::MINIMUM_PRESSURE] );
regData[Statistics::MAXIMUM_PRESSURE] = MpiWrapper::max( regData[Statistics::MAXIMUM_PRESSURE] );
regData[Statistics::MINIMUM_TEMPERATURE] = MpiWrapper::min( regData[Statistics::MINIMUM_TEMPERATURE] );
regData[Statistics::MAXIMUM_TEMPERATURE] = MpiWrapper::max( regData[Statistics::MAXIMUM_TEMPERATURE] );

regData[Statistics::AVERAGE_PRESSURE] = MpiWrapper::sum( regData[Statistics::AVERAGE_PRESSURE] );
regData[Statistics::AVERAGE_TEMPERATURE] = MpiWrapper::sum( regData[Statistics::AVERAGE_TEMPERATURE] );

for( integer propIndex = Statistics::PHASE_PORE_VOLUME; propIndex < Statistics::END; ++propIndex )
{
regData[propIndex] = MpiWrapper::sum( regData[propIndex] );
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know the impact, but I'm wondering if this kind of repeated reductions should & could be grouped to be optimized.


registerWrapper( viewKeyStruct::propertyNamesString(), &m_propertyNames ).
setInputFlag( InputFlags::OPTIONAL ).
setDescription( "The list of names of properties to report" );
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
setDescription( "The list of names of properties to report" );
setDescription( "The list of names of properties to report. If leaved empty, all available properties are selected." );

Comment on lines +302 to +312
m_propertyNameTypes.emplace_back( PropertyNameType::Pressure );
m_propertyNameTypes.emplace_back( PropertyNameType::Temperature );
m_propertyNameTypes.emplace_back( PropertyNameType::StaticPoreVolume );
m_propertyNameTypes.emplace_back( PropertyNameType::PoreVolume );
m_propertyNameTypes.emplace_back( PropertyNameType::PhaseVolumeFraction );
m_propertyNameTypes.emplace_back( PropertyNameType::PhasePoreVolume );
m_propertyNameTypes.emplace_back( PropertyNameType::PhaseMass );
m_propertyNameTypes.emplace_back( PropertyNameType::PhaseDensity );
m_propertyNameTypes.emplace_back( PropertyNameType::PhaseViscosity );
m_propertyNameTypes.emplace_back( PropertyNameType::PhaseComponentMass );
m_propertyNameTypes.emplace_back( PropertyNameType::ComponentMass );
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In order to automatically iterate over enum labels :

Suggested change
m_propertyNameTypes.emplace_back( PropertyNameType::Pressure );
m_propertyNameTypes.emplace_back( PropertyNameType::Temperature );
m_propertyNameTypes.emplace_back( PropertyNameType::StaticPoreVolume );
m_propertyNameTypes.emplace_back( PropertyNameType::PoreVolume );
m_propertyNameTypes.emplace_back( PropertyNameType::PhaseVolumeFraction );
m_propertyNameTypes.emplace_back( PropertyNameType::PhasePoreVolume );
m_propertyNameTypes.emplace_back( PropertyNameType::PhaseMass );
m_propertyNameTypes.emplace_back( PropertyNameType::PhaseDensity );
m_propertyNameTypes.emplace_back( PropertyNameType::PhaseViscosity );
m_propertyNameTypes.emplace_back( PropertyNameType::PhaseComponentMass );
m_propertyNameTypes.emplace_back( PropertyNameType::ComponentMass );
constexpr auto labelCount = EnumStrings< PropertyNameType >::count;
for( integer i = 0; i < labelCount; ++i )
{
m_propertyNameTypes.emplace_back( i );
}

... we could add a getEnumStringsCount( ENUM const ) in the ENUM_STRINGS() macro :

  inline constexpr size_t getEnumStringsCount( ENUM const )           \
  {                                                                   \
    constexpr char const * arr[] { __VA_ARGS__ };                     \
    constexpr auto s = std::end( arr ) - std::begin( arr );           \
    return s;                                                         \
  }                                                                   \

... and a constexpr count in EnumStrings :

  inline static constexpr size_t count = getEnumStringsCount( enum_type{} );

Comment on lines +781 to +789
std::ofstream outputFile( m_outputDir + "/" + viewKeyStruct::fileNameString() + ".csv" );

writeArray( outputFile, propNames );
writeArray( outputFile, propUnits );
writeArray( outputFile, regNames );
writeArray( outputFile, phaseNames );
writeArray( outputFile, compNames );

outputFile.close();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Me or @arng40 will certainly make a future PR to add table output in the log (using the component from this PR) and to the csv export with centralized components.

Comment on lines +680 to +681
string const massUnit = useMass ? "kg" : "mol";
string const densityUnit = useMass ? "kg/m^3" : "mol/m^3";
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
string const massUnit = useMass ? "kg" : "mol";
string const densityUnit = useMass ? "kg/m^3" : "mol/m^3";
string const massUnit = getSymbol( useMass ? units::Unit::Mass : units::Unit::Mole );
string const densityUnit = getSymbol( useMass ? units::Unit::MassRate : units::Unit::MoleRate );

Comment on lines +32 to +39
struct RegionMultiphaseStatistics::Statistics
{
static constexpr integer MAX_NUM_PHASE = 3;
static constexpr integer MAX_NUM_COMPS = 5;
/// Indices for properties
static constexpr integer CELL_COUNT = 0;
static constexpr integer STATIC_PORE_VOLUME = 1;
static constexpr integer PORE_VOLUME = 2;
Copy link
Copy Markdown
Contributor

@MelReyCG MelReyCG Mar 27, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here, what do you think of grouping the indices in a C Enum?

Suggested change
struct RegionMultiphaseStatistics::Statistics
{
static constexpr integer MAX_NUM_PHASE = 3;
static constexpr integer MAX_NUM_COMPS = 5;
/// Indices for properties
static constexpr integer CELL_COUNT = 0;
static constexpr integer STATIC_PORE_VOLUME = 1;
static constexpr integer PORE_VOLUME = 2;
struct RegionMultiphaseStatistics::Statistics
{
static constexpr integer MAX_NUM_PHASE = 3;
static constexpr integer MAX_NUM_COMPS = 5;
enum PropIds : integer {
CELL_COUNT,
STATIC_PORE_VOLUME,
PORE_VOLUME,
// [...]
END
};

Comment on lines +64 to +84
GEOS_HOST_DEVICE Statistics( Statistics const & rhs )
{
for( integer i = 0; i < END; i++ )
{
m_data[i] = rhs.m_data[i];
}
}

GEOS_HOST_DEVICE Statistics const & operator=( Statistics const & rhs )
{
for( integer i = 0; i < END; i++ )
{
m_data[i] = rhs.m_data[i];
}
return *this;
}

Statistics( Statistics && rhs )
{
std::swap( m_data, rhs.m_data );
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aren't they the default?

Comment on lines +180 to +181
RAJA::ReduceSum< ReducePolicy< POLICY >, Statistics > sumStats( RAJA::operators::plus< Statistics >::identity() );
RAJA::ReduceMin< ReducePolicy< POLICY >, Statistics > minStats( RAJA::operators::minimum< Statistics >::identity() );
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible to declare a RAJA::ReduceSum< ReducePolicy< POLICY >, real64[] >?

} );

// Create the csv file if requires
if( 0 < getLogLevel() && 0 < m_writeCSV && MpiWrapper::commRank() == 0 )
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why this condition is different to the one below? (in RegionMultiphaseStatistics::computeRegionStatistics()).

@dkachuma
Copy link
Copy Markdown
Contributor Author

Superceded by #4005

@dkachuma dkachuma closed this May 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

spe11 spe11-required-feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants