Refactor: extract Soil computation.

This commit is contained in:
Kristian Bendiksen 2023-04-17 15:12:26 +02:00
parent cc0691f48c
commit 5a64e90103
10 changed files with 319 additions and 118 deletions

View File

@ -121,6 +121,7 @@ include_directories(
${CMAKE_CURRENT_SOURCE_DIR}/ReservoirDataModel
${CMAKE_CURRENT_SOURCE_DIR}/ReservoirDataModel/Completions
${CMAKE_CURRENT_SOURCE_DIR}/ReservoirDataModel/ResultAccessors
${CMAKE_CURRENT_SOURCE_DIR}/ReservoirDataModel/ResultCalculators
${CMAKE_CURRENT_SOURCE_DIR}/GeoMech/OdbReader
${CMAKE_CURRENT_SOURCE_DIR}/GeoMech/GeoMechDataModel
${CMAKE_CURRENT_SOURCE_DIR}/GeoMech/GeoMechVisualization
@ -168,6 +169,7 @@ list(
ReservoirDataModel/CMakeLists_filesNotToUnitTest.cmake
ReservoirDataModel/Completions/CMakeLists_files.cmake
ReservoirDataModel/ResultAccessors/CMakeLists_files.cmake
ReservoirDataModel/ResultCalculators/CMakeLists_files.cmake
FileInterface/CMakeLists_files.cmake
ProjectDataModel/CMakeLists_files.cmake
ProjectDataModel/AnalysisPlots/CMakeLists_files.cmake
@ -435,6 +437,7 @@ target_include_directories(
${CMAKE_SOURCE_DIR}/ApplicationLibCode/ProjectDataModel/Intersections
${CMAKE_SOURCE_DIR}/ApplicationLibCode/ReservoirDataModel
${CMAKE_SOURCE_DIR}/ApplicationLibCode/ReservoirDataModel/ResultAccessors
${CMAKE_SOURCE_DIR}/ApplicationLibCode/ReservoirDataModel/ResultCalculators
${CMAKE_SOURCE_DIR}/ApplicationLibCode/SocketInterface
${CMAKE_SOURCE_DIR}/ApplicationLibCode/UserInterface
)

View File

@ -0,0 +1,19 @@
set(SOURCE_GROUP_HEADER_FILES
${CMAKE_CURRENT_LIST_DIR}/RigEclipseResultCalculator.h
${CMAKE_CURRENT_LIST_DIR}/RigSoilResultCalculator.h
)
set(SOURCE_GROUP_SOURCE_FILES
${CMAKE_CURRENT_LIST_DIR}/RigEclipseResultCalculator.cpp
${CMAKE_CURRENT_LIST_DIR}/RigSoilResultCalculator.cpp
)
list(APPEND CODE_HEADER_FILES ${SOURCE_GROUP_HEADER_FILES})
list(APPEND CODE_SOURCE_FILES ${SOURCE_GROUP_SOURCE_FILES})
source_group(
"ReservoirDataModel\\ResultCalculators"
FILES ${SOURCE_GROUP_HEADER_FILES} ${SOURCE_GROUP_SOURCE_FILES}
${CMAKE_CURRENT_LIST_DIR}/CMakeLists_files.cmake
)

View File

@ -0,0 +1,34 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2023- Equinor ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RigEclipseResultCalculator.h"
//==================================================================================================
///
//==================================================================================================
RigEclipseResultCalculator::RigEclipseResultCalculator( RigCaseCellResultsData& resultsData )
: m_resultsData( &resultsData )
{
}
//==================================================================================================
///
//==================================================================================================
RigEclipseResultCalculator::~RigEclipseResultCalculator()
{
}

View File

@ -0,0 +1,39 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2023- Equinor ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include <cstddef>
class RigCaseCellResultsData;
class RigEclipseResultAddress;
//==================================================================================================
///
//==================================================================================================
class RigEclipseResultCalculator
{
public:
RigEclipseResultCalculator( RigCaseCellResultsData& resultsData );
virtual ~RigEclipseResultCalculator();
virtual bool isMatching( const RigEclipseResultAddress& resVarAddr ) const = 0;
virtual void calculate( const RigEclipseResultAddress& resVarAddr, size_t timeStepIndex ) = 0;
protected:
RigCaseCellResultsData* m_resultsData;
};

View File

@ -0,0 +1,169 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2023- Equinor ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RigSoilResultCalculator.h"
#include "RigCaseCellResultsData.h"
#include "RigEclipseResultInfo.h"
#include "RiaResultNames.h"
//==================================================================================================
///
//==================================================================================================
RigSoilResultCalculator::RigSoilResultCalculator( RigCaseCellResultsData& resultsData )
: RigEclipseResultCalculator( resultsData )
{
}
//==================================================================================================
///
//==================================================================================================
RigSoilResultCalculator::~RigSoilResultCalculator()
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RigSoilResultCalculator::isMatching( const RigEclipseResultAddress& resVarAddr ) const
{
return resVarAddr.resultName() == RiaResultNames::soil() && resVarAddr.resultCatType() == RiaDefines::ResultCatType::DYNAMIC_NATIVE;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RigSoilResultCalculator::calculate( const RigEclipseResultAddress& resVarAddr, size_t timeStepIndex )
{
// Compute SGAS based on SWAT if the simulation contains no oil
m_resultsData->testAndComputeSgasForTimeStep( timeStepIndex );
RigEclipseResultAddress SWATAddr( RiaDefines::ResultCatType::DYNAMIC_NATIVE, RiaResultNames::swat() );
RigEclipseResultAddress SGASAddr( RiaDefines::ResultCatType::DYNAMIC_NATIVE, RiaResultNames::sgas() );
RigEclipseResultAddress SSOLAddr( RiaDefines::ResultCatType::DYNAMIC_NATIVE, "SSOL" );
size_t scalarIndexSWAT =
m_resultsData->findOrLoadKnownScalarResultForTimeStep( RigEclipseResultAddress( RiaDefines::ResultCatType::DYNAMIC_NATIVE,
RiaResultNames::swat() ),
timeStepIndex );
size_t scalarIndexSGAS =
m_resultsData->findOrLoadKnownScalarResultForTimeStep( RigEclipseResultAddress( RiaDefines::ResultCatType::DYNAMIC_NATIVE,
RiaResultNames::sgas() ),
timeStepIndex );
size_t scalarIndexSSOL =
m_resultsData->findOrLoadKnownScalarResultForTimeStep( RigEclipseResultAddress( RiaDefines::ResultCatType::DYNAMIC_NATIVE, "SSOL" ),
timeStepIndex );
// Early exit if none of SWAT or SGAS is present
if ( scalarIndexSWAT == cvf::UNDEFINED_SIZE_T && scalarIndexSGAS == cvf::UNDEFINED_SIZE_T )
{
return;
}
size_t soilResultValueCount = 0;
size_t soilTimeStepCount = 0;
if ( scalarIndexSWAT != cvf::UNDEFINED_SIZE_T )
{
const std::vector<double>& swatForTimeStep = m_resultsData->cellScalarResults( SWATAddr, timeStepIndex );
if ( swatForTimeStep.size() > 0 )
{
soilResultValueCount = swatForTimeStep.size();
soilTimeStepCount = m_resultsData->infoForEachResultIndex()[scalarIndexSWAT].timeStepInfos().size();
}
}
if ( scalarIndexSGAS != cvf::UNDEFINED_SIZE_T )
{
const std::vector<double>& sgasForTimeStep = m_resultsData->cellScalarResults( SGASAddr, timeStepIndex );
if ( sgasForTimeStep.size() > 0 )
{
soilResultValueCount = qMax( soilResultValueCount, sgasForTimeStep.size() );
size_t sgasTimeStepCount = m_resultsData->infoForEachResultIndex()[scalarIndexSGAS].timeStepInfos().size();
soilTimeStepCount = qMax( soilTimeStepCount, sgasTimeStepCount );
}
}
// Make sure memory is allocated for the new SOIL results
size_t soilResultScalarIndex = m_resultsData->findScalarResultIndexFromAddress( resVarAddr );
m_resultsData->m_cellScalarResults[soilResultScalarIndex].resize( soilTimeStepCount );
if ( m_resultsData->cellScalarResults( resVarAddr, timeStepIndex ).size() > 0 )
{
// Data is computed and allocated, nothing more to do
return;
}
m_resultsData->m_cellScalarResults[soilResultScalarIndex][timeStepIndex].resize( soilResultValueCount );
const std::vector<double>* swatForTimeStep = nullptr;
const std::vector<double>* sgasForTimeStep = nullptr;
const std::vector<double>* ssolForTimeStep = nullptr;
if ( scalarIndexSWAT != cvf::UNDEFINED_SIZE_T )
{
swatForTimeStep = &( m_resultsData->cellScalarResults( SWATAddr, timeStepIndex ) );
if ( swatForTimeStep->size() == 0 )
{
swatForTimeStep = nullptr;
}
}
if ( scalarIndexSGAS != cvf::UNDEFINED_SIZE_T )
{
sgasForTimeStep = &( m_resultsData->cellScalarResults( SGASAddr, timeStepIndex ) );
if ( sgasForTimeStep->size() == 0 )
{
sgasForTimeStep = nullptr;
}
}
if ( scalarIndexSSOL != cvf::UNDEFINED_SIZE_T )
{
ssolForTimeStep = &( m_resultsData->cellScalarResults( SSOLAddr, timeStepIndex ) );
if ( ssolForTimeStep->size() == 0 )
{
ssolForTimeStep = nullptr;
}
}
std::vector<double>* soilForTimeStep = m_resultsData->modifiableCellScalarResult( resVarAddr, timeStepIndex );
#pragma omp parallel for
for ( int idx = 0; idx < static_cast<int>( soilResultValueCount ); idx++ )
{
double soilValue = 1.0;
if ( sgasForTimeStep )
{
soilValue -= sgasForTimeStep->at( idx );
}
if ( swatForTimeStep )
{
soilValue -= swatForTimeStep->at( idx );
}
if ( ssolForTimeStep )
{
soilValue -= ssolForTimeStep->at( idx );
}
soilForTimeStep->at( idx ) = soilValue;
}
}

View File

@ -0,0 +1,38 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2023- Equinor ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include <cstddef>
#include "RigEclipseResultCalculator.h"
class RigCaseCellResultsData;
class RigEclipseResultAddress;
//==================================================================================================
///
//==================================================================================================
class RigSoilResultCalculator : public RigEclipseResultCalculator
{
public:
RigSoilResultCalculator( RigCaseCellResultsData& resultsData );
~RigSoilResultCalculator() override;
bool isMatching( const RigEclipseResultAddress& resVarAddr ) const override;
void calculate( const RigEclipseResultAddress& resVarAddr, size_t timeStepIndex ) override;
};

View File

@ -35,6 +35,7 @@
#include "RigEclipseResultInfo.h"
#include "RigFormationNames.h"
#include "RigMainGrid.h"
#include "RigSoilResultCalculator.h"
#include "RigStatisticsDataCache.h"
#include "RigStatisticsMath.h"
@ -801,7 +802,7 @@ const std::vector<double>* RigCaseCellResultsData::getResultIndexableStaticResul
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
const std::vector<RigEclipseResultInfo>& RigCaseCellResultsData::infoForEachResultIndex()
const std::vector<RigEclipseResultInfo>& RigCaseCellResultsData::infoForEachResultIndex() const
{
return m_resultInfos;
}
@ -1585,120 +1586,9 @@ size_t RigCaseCellResultsData::findOrLoadKnownScalarResultForTimeStep( const Rig
//--------------------------------------------------------------------------------------------------
void RigCaseCellResultsData::computeSOILForTimeStep( size_t timeStepIndex )
{
// Compute SGAS based on SWAT if the simulation contains no oil
testAndComputeSgasForTimeStep( timeStepIndex );
RigEclipseResultAddress SWATAddr( RiaDefines::ResultCatType::DYNAMIC_NATIVE, RiaResultNames::swat() );
RigEclipseResultAddress SGASAddr( RiaDefines::ResultCatType::DYNAMIC_NATIVE, RiaResultNames::sgas() );
RigEclipseResultAddress SSOLAddr( RiaDefines::ResultCatType::DYNAMIC_NATIVE, "SSOL" );
size_t scalarIndexSWAT =
findOrLoadKnownScalarResultForTimeStep( RigEclipseResultAddress( RiaDefines::ResultCatType::DYNAMIC_NATIVE, RiaResultNames::swat() ),
timeStepIndex );
size_t scalarIndexSGAS =
findOrLoadKnownScalarResultForTimeStep( RigEclipseResultAddress( RiaDefines::ResultCatType::DYNAMIC_NATIVE, RiaResultNames::sgas() ),
timeStepIndex );
size_t scalarIndexSSOL =
findOrLoadKnownScalarResultForTimeStep( RigEclipseResultAddress( RiaDefines::ResultCatType::DYNAMIC_NATIVE, "SSOL" ), timeStepIndex );
// Early exit if none of SWAT or SGAS is present
if ( scalarIndexSWAT == cvf::UNDEFINED_SIZE_T && scalarIndexSGAS == cvf::UNDEFINED_SIZE_T )
{
return;
}
size_t soilResultValueCount = 0;
size_t soilTimeStepCount = 0;
if ( scalarIndexSWAT != cvf::UNDEFINED_SIZE_T )
{
const std::vector<double>& swatForTimeStep = this->cellScalarResults( SWATAddr, timeStepIndex );
if ( swatForTimeStep.size() > 0 )
{
soilResultValueCount = swatForTimeStep.size();
soilTimeStepCount = this->infoForEachResultIndex()[scalarIndexSWAT].timeStepInfos().size();
}
}
if ( scalarIndexSGAS != cvf::UNDEFINED_SIZE_T )
{
const std::vector<double>& sgasForTimeStep = this->cellScalarResults( SGASAddr, timeStepIndex );
if ( sgasForTimeStep.size() > 0 )
{
soilResultValueCount = qMax( soilResultValueCount, sgasForTimeStep.size() );
size_t sgasTimeStepCount = this->infoForEachResultIndex()[scalarIndexSGAS].timeStepInfos().size();
soilTimeStepCount = qMax( soilTimeStepCount, sgasTimeStepCount );
}
}
// Make sure memory is allocated for the new SOIL results
RigEclipseResultAddress SOILAddr( RiaDefines::ResultCatType::DYNAMIC_NATIVE, RiaResultNames::soil() );
size_t soilResultScalarIndex = this->findScalarResultIndexFromAddress( SOILAddr );
m_cellScalarResults[soilResultScalarIndex].resize( soilTimeStepCount );
if ( this->cellScalarResults( SOILAddr, timeStepIndex ).size() > 0 )
{
// Data is computed and allocated, nothing more to do
return;
}
m_cellScalarResults[soilResultScalarIndex][timeStepIndex].resize( soilResultValueCount );
const std::vector<double>* swatForTimeStep = nullptr;
const std::vector<double>* sgasForTimeStep = nullptr;
const std::vector<double>* ssolForTimeStep = nullptr;
if ( scalarIndexSWAT != cvf::UNDEFINED_SIZE_T )
{
swatForTimeStep = &( this->cellScalarResults( SWATAddr, timeStepIndex ) );
if ( swatForTimeStep->size() == 0 )
{
swatForTimeStep = nullptr;
}
}
if ( scalarIndexSGAS != cvf::UNDEFINED_SIZE_T )
{
sgasForTimeStep = &( this->cellScalarResults( SGASAddr, timeStepIndex ) );
if ( sgasForTimeStep->size() == 0 )
{
sgasForTimeStep = nullptr;
}
}
if ( scalarIndexSSOL != cvf::UNDEFINED_SIZE_T )
{
ssolForTimeStep = &( this->cellScalarResults( SSOLAddr, timeStepIndex ) );
if ( ssolForTimeStep->size() == 0 )
{
ssolForTimeStep = nullptr;
}
}
std::vector<double>* soilForTimeStep = this->modifiableCellScalarResult( SOILAddr, timeStepIndex );
#pragma omp parallel for
for ( int idx = 0; idx < static_cast<int>( soilResultValueCount ); idx++ )
{
double soilValue = 1.0;
if ( sgasForTimeStep )
{
soilValue -= sgasForTimeStep->at( idx );
}
if ( swatForTimeStep )
{
soilValue -= swatForTimeStep->at( idx );
}
if ( ssolForTimeStep )
{
soilValue -= ssolForTimeStep->at( idx );
}
soilForTimeStep->at( idx ) = soilValue;
}
RigSoilResultCalculator calculator( *this );
calculator.calculate( SOILAddr, timeStepIndex );
}
//--------------------------------------------------------------------------------------------------

View File

@ -153,6 +153,7 @@ private:
// Add a friend class, as this way of loading data requires careful management of state
// All other data access assumes all time steps are loaded at the same time
friend class RimEclipseStatisticsCaseEvaluator;
friend class RigSoilResultCalculator;
size_t findOrLoadKnownScalarResultForTimeStep( const RigEclipseResultAddress& resVarAddr, size_t timeStepIndex );
size_t findOrCreateScalarResultIndex( const RigEclipseResultAddress& resVarAddr, bool needsToBeStored );
@ -161,7 +162,7 @@ private:
size_t addStaticScalarResult( RiaDefines::ResultCatType type, const QString& resultName, bool needsToBeStored, size_t resultValueCount );
const std::vector<RigEclipseResultInfo>& infoForEachResultIndex();
const std::vector<RigEclipseResultInfo>& infoForEachResultIndex() const;
size_t resultCount() const;
bool mustBeCalculated( size_t scalarResultIndex ) const;

View File

@ -128,6 +128,14 @@ size_t RigEclipseResultInfo::gridScalarResultIndex() const
return m_gridScalarResultIndex;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
const RigEclipseResultAddress& RigEclipseResultInfo::eclipseResultAddress() const
{
return m_resultAddress;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------

View File

@ -65,7 +65,8 @@ public:
bool operator<( const RigEclipseResultInfo& rhs ) const;
const RigEclipseResultAddress& eclipseResultAddress() const { return m_resultAddress; }
const RigEclipseResultAddress& eclipseResultAddress() const;
const std::vector<RigEclipseTimeStepInfo>& timeStepInfos() const;
private:
friend class RigCaseCellResultsData;
@ -75,8 +76,7 @@ private:
void setMustBeCalculated( bool mustCalculate );
size_t gridScalarResultIndex() const;
const std::vector<RigEclipseTimeStepInfo>& timeStepInfos() const;
void setTimeStepInfos( const std::vector<RigEclipseTimeStepInfo>& timeSteps );
void setTimeStepInfos( const std::vector<RigEclipseTimeStepInfo>& timeSteps );
RigEclipseResultAddress m_resultAddress;
size_t m_gridScalarResultIndex;