#13281 Improve unit system handling for Eclipse files

- Add shared utility functions in RifEclipseOutputFileTools:
  - unitValueToEnum(): Convert int unit value to optional enum
  - determineUnitSystem(): Apply unit preference hierarchy and log warnings
- Implement correct unit preference hierarchy: egrid > init > unrst
  (previously was unrst > init > egrid)
- Add validation and warning when different unit systems are detected
  across files
- Enhance grid unit parsing with debug logging to explicitly document
  support for "m" as abbreviation for "METRES"
This commit is contained in:
Kristian Bendiksen committed 2025-12-05 14:18:45 +01:00
1 parent 1ed297e124
commit 37ee50cc9e
5 files changed
+165 -49

No files matched your search

@@ -20,6 +20,7 @@
#include "RifEclipseOutputFileTools.h"
#include "RiaLogging.h"
#include "RiaOpmParserTools.h"
#include "RiaQDateTimeTools.h"
#include "RiaStringEncodingTools.h"
@@ -951,3 +952,90 @@ void RifEclipseOutputFileTools::extractResultValuesBasedOnPorosityModel( RigEcli
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::optional<RiaDefines::EclipseUnitSystem> RifEclipseOutputFileTools::unitValueToEnum( int unitValue )
{
if ( unitValue == 1 )
return RiaDefines::EclipseUnitSystem::UNITS_METRIC;
else if ( unitValue == 2 )
return RiaDefines::EclipseUnitSystem::UNITS_FIELD;
else if ( unitValue == 3 )
return RiaDefines::EclipseUnitSystem::UNITS_LAB;
return std::nullopt;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RiaDefines::EclipseUnitSystem RifEclipseOutputFileTools::determineUnitSystem( const std::optional<RiaDefines::EclipseUnitSystem>& egridUnit,
const std::optional<RiaDefines::EclipseUnitSystem>& initUnit,
const std::optional<RiaDefines::EclipseUnitSystem>& unrstUnit )
{
// Helper lambda to get unit name string
auto getUnitName = []( RiaDefines::EclipseUnitSystem unit ) -> QString
{
if ( unit == RiaDefines::EclipseUnitSystem::UNITS_METRIC ) return "METRIC";
if ( unit == RiaDefines::EclipseUnitSystem::UNITS_FIELD ) return "FIELD";
if ( unit == RiaDefines::EclipseUnitSystem::UNITS_LAB ) return "LAB";
return "UNKNOWN";
};
// Determine which unit to use based on priority: egrid > init > unrst
std::optional<RiaDefines::EclipseUnitSystem> selectedUnit;
QString selectedSource;
if ( egridUnit.has_value() )
{
selectedUnit = egridUnit;
selectedSource = "EGRID";
}
else if ( initUnit.has_value() )
{
selectedUnit = initUnit;
selectedSource = "INIT";
}
else if ( unrstUnit.has_value() )
{
selectedUnit = unrstUnit;
selectedSource = "UNRST";
}
// Check for mismatches and warn
if ( selectedUnit.has_value() )
{
// Build list of sources that differ from selected
QStringList conflicts;
if ( egridUnit.has_value() && initUnit.has_value() && egridUnit.value() != initUnit.value() )
{
conflicts.append( QString( "INIT file has %1" ).arg( getUnitName( initUnit.value() ) ) );
}
if ( egridUnit.has_value() && unrstUnit.has_value() && egridUnit.value() != unrstUnit.value() )
{
conflicts.append( QString( "UNRST file has %1" ).arg( getUnitName( unrstUnit.value() ) ) );
}
if ( !egridUnit.has_value() && initUnit.has_value() && unrstUnit.has_value() && initUnit.value() != unrstUnit.value() )
{
conflicts.append( QString( "UNRST file has %1" ).arg( getUnitName( unrstUnit.value() ) ) );
}
if ( !conflicts.isEmpty() )
{
QString warning = QString( "Unit system mismatch detected: Using %1 from %2 file, but %3. "
"Please verify your simulation files have consistent unit systems." )
.arg( getUnitName( selectedUnit.value() ) )
.arg( selectedSource )
.arg( conflicts.join( " and " ) );
RiaLogging::warning( warning );
}
return selectedUnit.value();
}
// Default to METRIC if no unit found
return RiaDefines::EclipseUnitSystem::UNITS_METRIC;
}
@@ -35,6 +35,7 @@
#include <QString>
#include <QStringList>
#include <optional>
#include <vector>
using ecl_file_type = struct ecl_file_struct;
@@ -114,6 +115,12 @@ public:
std::vector<double>* values,
const std::vector<double>& fileValues );
// Unit system handling utilities
static std::optional<RiaDefines::EclipseUnitSystem> unitValueToEnum( int unitValue );
static RiaDefines::EclipseUnitSystem determineUnitSystem( const std::optional<RiaDefines::EclipseUnitSystem>& egridUnit,
const std::optional<RiaDefines::EclipseUnitSystem>& initUnit,
const std::optional<RiaDefines::EclipseUnitSystem>& unrstUnit );
private:
static void getDayMonthYear( const ecl_kw_type* intehead_kw, int* day, int* month, int* year );
static RifEclipseReportKeywords createReportStepsMetaData( const std::vector<ecl_file_type*>& ecl_files );
@@ -895,34 +895,30 @@ void RifReaderEclipseOutput::buildMetaData( ecl_grid_type* grid )
// Unit system
{
// Default units type is METRIC
RiaDefines::EclipseUnitSystem unitsType = RiaDefines::EclipseUnitSystem::UNITS_METRIC;
int unitsTypeValue;
std::optional<RiaDefines::EclipseUnitSystem> egridUnit;
std::optional<RiaDefines::EclipseUnitSystem> initUnit;
std::optional<RiaDefines::EclipseUnitSystem> unrstUnit;
// Read from grid file
if ( grid )
{
egridUnit = RifEclipseOutputFileTools::unitValueToEnum( ecl_grid_get_unit_system( grid ) );
}
// Read from init file
if ( m_ecl_init_file )
{
initUnit = RifEclipseOutputFileTools::unitValueToEnum( RifEclipseOutputFileTools::readUnitsType( m_ecl_init_file ) );
}
// Read from restart file
if ( m_dynamicResultsAccess.notNull() )
{
unitsTypeValue = m_dynamicResultsAccess->readUnitsType();
}
else
{
if ( m_ecl_init_file )
{
unitsTypeValue = RifEclipseOutputFileTools::readUnitsType( m_ecl_init_file );
}
else
{
unitsTypeValue = ecl_grid_get_unit_system( grid );
}
unrstUnit = RifEclipseOutputFileTools::unitValueToEnum( m_dynamicResultsAccess->readUnitsType() );
}
if ( unitsTypeValue == 2 )
{
unitsType = RiaDefines::EclipseUnitSystem::UNITS_FIELD;
}
else if ( unitsTypeValue == 3 )
{
unitsType = RiaDefines::EclipseUnitSystem::UNITS_LAB;
}
// Determine final unit system using hierarchy (egrid > init > unrst) with warnings
RiaDefines::EclipseUnitSystem unitsType = RifEclipseOutputFileTools::determineUnitSystem( egridUnit, initUnit, unrstUnit );
m_eclipseCaseData->setUnitsType( unitsType );
}
@@ -189,13 +189,30 @@ bool RifReaderOpmCommon::importGrid( RigMainGrid* mainGrid, RigEclipseCaseData*
mainGrid->setDualPorosity( opmGrid.porosity_mode() > 0 );
// assign grid unit, if found (1 = Metric, 2 = Field, 3 = Lab)
// Note: Accepts "m" or "M" as abbreviation for "METRES" (METRIC units)
auto gridUnitStr = RiaStdStringTools::toUpper( opmGrid.grid_unit() );
if ( gridUnitStr.starts_with( 'M' ) )
{
m_gridUnit = 1;
RiaLogging::debug(
QString( "Grid unit from EGRID file: '%1' (interpreted as METRIC)" ).arg( QString::fromStdString( opmGrid.grid_unit() ) ) );
}
else if ( gridUnitStr.starts_with( 'F' ) )
{
m_gridUnit = 2;
RiaLogging::debug(
QString( "Grid unit from EGRID file: '%1' (interpreted as FIELD)" ).arg( QString::fromStdString( opmGrid.grid_unit() ) ) );
}
else if ( gridUnitStr.starts_with( 'C' ) )
{
m_gridUnit = 3;
RiaLogging::debug(
QString( "Grid unit from EGRID file: '%1' (interpreted as LAB)" ).arg( QString::fromStdString( opmGrid.grid_unit() ) ) );
}
else if ( !gridUnitStr.empty() )
{
RiaLogging::warning( QString( "Unknown grid unit from EGRID file: '%1'" ).arg( QString::fromStdString( opmGrid.grid_unit() ) ) );
}
auto totalCellCount = opmGrid.totalNumberOfCells();
auto globalMatrixActiveSize = opmGrid.activeCells();
@@ -925,12 +942,23 @@ void RifReaderOpmCommon::buildMetaData( RigEclipseCaseData* eclipseCaseData, caf
// Unit system
{
// Default units type is METRIC, look in restart file, then init file and then grid file until we find something
RiaDefines::EclipseUnitSystem unitsType = RiaDefines::EclipseUnitSystem::UNITS_METRIC;
int unitsTypeValue = -1;
std::optional<RiaDefines::EclipseUnitSystem> egridUnit = RifEclipseOutputFileTools::unitValueToEnum( m_gridUnit );
std::optional<RiaDefines::EclipseUnitSystem> initUnit;
std::optional<RiaDefines::EclipseUnitSystem> unrstUnit;
namespace VI = Opm::RestartIO::Helpers::VectorItems;
// Read from init file
if ( m_initFile != nullptr )
{
const auto& intHeader = m_initFile->getInitData<int>( "INTEHEAD" );
if ( intHeader.size() > 2 )
{
initUnit = RifEclipseOutputFileTools::unitValueToEnum( intHeader[2] );
}
}
// Read from restart file
if ( m_restartFile != nullptr )
{
for ( auto reportStep : m_restartFile->listOfReportStepNumbers() )
@@ -940,35 +968,15 @@ void RifReaderOpmCommon::buildMetaData( RigEclipseCaseData* eclipseCaseData, caf
const auto& intHeader = m_restartFile->getRestartData<int>( "INTEHEAD", reportStep );
if ( intHeader.size() > VI::intehead::UNIT )
{
unitsTypeValue = intHeader[VI::intehead::UNIT];
unrstUnit = RifEclipseOutputFileTools::unitValueToEnum( intHeader[VI::intehead::UNIT] );
break;
}
}
}
}
if ( unitsTypeValue < 0 )
{
if ( m_initFile != nullptr )
{
const auto& intHeader = m_initFile->getInitData<int>( "INTEHEAD" );
if ( intHeader.size() > 2 ) unitsTypeValue = intHeader[2];
}
}
if ( unitsTypeValue < 0 )
{
unitsTypeValue = m_gridUnit;
}
if ( unitsTypeValue == 2 )
{
unitsType = RiaDefines::EclipseUnitSystem::UNITS_FIELD;
}
else if ( unitsTypeValue == 3 )
{
unitsType = RiaDefines::EclipseUnitSystem::UNITS_LAB;
}
// Determine final unit system using hierarchy (egrid > init > unrst) with warnings
RiaDefines::EclipseUnitSystem unitsType = RifEclipseOutputFileTools::determineUnitSystem( egridUnit, initUnit, unrstUnit );
m_eclipseCaseData->setUnitsType( unitsType );
}
@@ -77,13 +77,30 @@ bool RifReaderOpmCommonActive::importGrid( RigMainGrid* /* mainGrid*/, RigEclips
activeGrid->setDualPorosity( opmGrid.porosity_mode() > 0 );
// assign grid unit, if found (1 = Metric, 2 = Field, 3 = Lab)
// Note: Accepts "m" or "M" as abbreviation for "METRES" (METRIC units)
auto gridUnitStr = RiaStdStringTools::toUpper( opmGrid.grid_unit() );
if ( gridUnitStr.starts_with( 'M' ) )
{
m_gridUnit = 1;
RiaLogging::debug(
QString( "Grid unit from EGRID file: '%1' (interpreted as METRIC)" ).arg( QString::fromStdString( opmGrid.grid_unit() ) ) );
}
else if ( gridUnitStr.starts_with( 'F' ) )
{
m_gridUnit = 2;
RiaLogging::debug(
QString( "Grid unit from EGRID file: '%1' (interpreted as FIELD)" ).arg( QString::fromStdString( opmGrid.grid_unit() ) ) );
}
else if ( gridUnitStr.starts_with( 'C' ) )
{
m_gridUnit = 3;
RiaLogging::debug(
QString( "Grid unit from EGRID file: '%1' (interpreted as LAB)" ).arg( QString::fromStdString( opmGrid.grid_unit() ) ) );
}
else if ( !gridUnitStr.empty() )
{
RiaLogging::warning( QString( "Unknown grid unit from EGRID file: '%1'" ).arg( QString::fromStdString( opmGrid.grid_unit() ) ) );
}
auto totalCellCount = opmGrid.totalNumberOfCells();
auto totalActiveCellCount = opmGrid.totalActiveCells();