Files
ResInsight/ApplicationLibCode/ReservoirDataModel/RigCaseCellResultsData.h
T
Kristian Bendiksen e85137db6e #14345 Recompute calculated results when data for a time step has been released
The grid calculator releases result data per time step to reduce memory
usage when calculating for many cases. If only some time steps are
released, findOrLoadKnownScalarResult() returned early because data was
present for other time steps, leaving the released time steps empty.
Results computed by ResInsight, like riOILVOLUME, then appeared as
undefined in the 3d view after running a calculation for a selected
time step.

Recompute results computed by ResInsight when data is missing for any
time step. Skip the delegation from the single time step variant when
the requested time step already has data, to avoid repeated
recomputation while the calculator releases other time steps.
2026-09-07 11:18:09 +02:00

277 lines
15 KiB
C++

/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2011- Statoil ASA
// Copyright (C) 2013- Ceetron Solutions AS
// Copyright (C) 2011-2012 Ceetron AS
//
// 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 "RiaDefines.h"
#include "RiaPorosityModel.h"
#include "RigFormationNames.h"
#include "RigStatisticsDataCache.h"
#include <QDateTime>
#include <cmath>
#include <map>
#include <optional>
#include <vector>
class RifReaderInterface;
class RigActiveCellInfo;
class RigMainGrid;
class RigEclipseResultInfo;
class RigEclipseTimeStepInfo;
class RigEclipseCaseData;
class RigAllanDiagramData;
class RigEclipseResultAddress;
class RimEclipseCase;
//==================================================================================================
/// Class containing the results for the complete number of active cells. Both main grid and LGR's
//==================================================================================================
class RigCaseCellResultsData : public cvf::Object
{
public:
explicit RigCaseCellResultsData( RigEclipseCaseData* ownerCaseData, RiaDefines::PorosityModelType porosityModel );
// Initialization
void setReaderInterface( RifReaderInterface* readerInterface );
const RifReaderInterface* readerInterface() const;
void setHdf5Filename( const QString& hdf5SourSimFilename );
void setActiveFormationNames( const RigFormationNames* activeFormationNames );
const RigFormationNames* activeFormationNames() const;
RigAllanDiagramData* allanDiagramData();
void setMainGrid( RigMainGrid* ownerGrid );
RigMainGrid* mainGrid();
void setActiveCellInfo( RigActiveCellInfo* activeCellInfo );
RigActiveCellInfo* activeCellInfo();
const RigActiveCellInfo* activeCellInfo() const;
// Access the results data
const std::vector<std::vector<double>>& cellScalarResults( const RigEclipseResultAddress& resVarAddr ) const;
const std::vector<double>& cellScalarResults( const RigEclipseResultAddress& resVarAddr, size_t timeStepIndex ) const;
std::vector<std::vector<double>>* modifiableCellScalarResultTimesteps( const RigEclipseResultAddress& resVarAddr );
std::vector<double>* modifiableCellScalarResult( const RigEclipseResultAddress& resVarAddr, size_t timeStepIndex );
bool isUsingGlobalActiveIndex( const RigEclipseResultAddress& resVarAddr ) const;
static const std::vector<double>* getResultIndexableStaticResult( RigActiveCellInfo* actCellInfo,
RigCaseCellResultsData* gridCellResults,
QString porvResultName,
std::vector<double>& activeCellsResultsTempContainer );
// Statistic values of the results
void recalculateStatistics( const RigEclipseResultAddress& resVarAddr, const std::set<int>& uniqueValuesOverride = {} );
void minMaxCellScalarValues( const RigEclipseResultAddress& resVarAddr, double& min, double& max );
void minMaxCellScalarValues( const RigEclipseResultAddress& resVarAddr, size_t timeStepIndex, double& min, double& max );
void posNegClosestToZero( const RigEclipseResultAddress& resVarAddr, double& pos, double& neg );
void posNegClosestToZero( const RigEclipseResultAddress& resVarAddr, size_t timeStepIndex, double& pos, double& neg );
const std::vector<size_t>& cellScalarValuesHistogram( const RigEclipseResultAddress& resVarAddr );
const std::vector<size_t>& cellScalarValuesHistogram( const RigEclipseResultAddress& resVarAddr, size_t timeStepIndex );
void p10p90CellScalarValues( const RigEclipseResultAddress& resVarAddr, double& p10, double& p90 );
void p10p90CellScalarValues( const RigEclipseResultAddress& resVarAddr, size_t timeStepIndex, double& p10, double& p90 );
void meanCellScalarValues( const RigEclipseResultAddress& resVarAddr, double& meanValue );
void meanCellScalarValues( const RigEclipseResultAddress& resVarAddr, size_t timeStepIndex, double& meanValue );
const std::vector<int>& uniqueCellScalarValues( const RigEclipseResultAddress& resVarAddr );
void sumCellScalarValues( const RigEclipseResultAddress& resVarAddr, double& sumValue );
void sumCellScalarValues( const RigEclipseResultAddress& resVarAddr, size_t timeStepIndex, double& sumValue );
void mobileVolumeWeightedMean( const RigEclipseResultAddress& resVarAddr, double& meanValue );
void mobileVolumeWeightedMean( const RigEclipseResultAddress& resVarAddr, size_t timeStepIndex, double& meanValue );
// Return the number of double values allocated for each result
std::map<std::string, size_t> resultValueCount() const;
// Access meta-information about the results
size_t timeStepCount( const RigEclipseResultAddress& resVarAddr ) const;
size_t maxTimeStepCount( RigEclipseResultAddress* resultAddressWithMostTimeSteps = nullptr ) const;
std::vector<QDateTime> allTimeStepDatesFromEclipseReader() const;
std::vector<QDateTime> timeStepDates() const;
std::vector<QDateTime> timeStepDates( const RigEclipseResultAddress& resVarAddr ) const;
std::vector<double> daysSinceSimulationStart() const;
std::vector<double> daysSinceSimulationStart( const RigEclipseResultAddress& resVarAddr ) const;
int reportStepNumber( const RigEclipseResultAddress& resVarAddr, size_t timeStepIndex ) const;
std::vector<RigEclipseTimeStepInfo> timeStepInfos( const RigEclipseResultAddress& resVarAddr ) const;
void setTimeStepInfos( const RigEclipseResultAddress& resVarAddr, const std::vector<RigEclipseTimeStepInfo>& timeStepInfos );
void clearScalarResult( RiaDefines::ResultCatType type, const QString& resultName );
void clearScalarResult( const RigEclipseResultAddress& resultAddress );
void clearAllResults();
void freeAllocatedResultsData( const std::vector<RiaDefines::ResultCatType>& categoriesToExclude,
std::optional<size_t> timeStepIndexToRelease );
void eraseAllSourSimData();
void setRemovedTagOnGeneratedResult( const RigEclipseResultAddress& resultAddress );
QStringList resultNames( RiaDefines::ResultCatType type, bool includeAliases = true ) const;
std::vector<RigEclipseResultAddress> existingResults() const;
const RigEclipseResultInfo* resultInfo( const RigEclipseResultAddress& resVarAddr ) const;
bool updateResultName( RiaDefines::ResultCatType resultType, const QString& oldName, const QString& newName );
QString makeResultNameUnique( const QString& resultNameProposal ) const;
bool ensureKnownResultLoaded( const RigEclipseResultAddress& resultAddress );
bool findAndLoadResultByName( const QString& resultName, const std::vector<RiaDefines::ResultCatType>& resultCategorySearchOrder );
// Load result for a single time step. This can be used to process data for a single time step
// Other data access functions assume all time steps are loaded at the same time
size_t findOrLoadKnownScalarResultForTimeStep( const RigEclipseResultAddress& resVarAddr, size_t timeStepIndex );
bool hasResultEntry( const RigEclipseResultAddress& resultAddress ) const;
bool isResultLoaded( const RigEclipseResultAddress& resultAddress ) const;
void createResultEntry( const RigEclipseResultAddress& resultAddress, bool needsToBeStored );
bool updateResultDataType( const RigEclipseResultAddress& resultAddress, RiaDefines::ResultDataType dataType );
void createPlaceholderResultEntries();
// Compute depth-related geometry results (DEPTH/DX/DY/DZ/TOPS/BOTTOM) for both porosity models
// in a single traversal of the shared grid. The values are derived purely from the grid
// geometry, so a cell active in both models is computed only once and written to both.
static void computeDepthRelatedResults( RigCaseCellResultsData* matrixResults, RigCaseCellResultsData* fractureResults );
void computeCellVolumes();
bool hasFlowDiagUsableFluxes() const;
static void copyResultsMetaDataFromMainCase( RigEclipseCaseData* mainCaseResultsData,
RiaDefines::PorosityModelType poroModel,
std::vector<RimEclipseCase*> destinationCases );
void setStatisticsDataCacheNumBins( const RigEclipseResultAddress& resultAddress, size_t numBins );
RigStatisticsDataCache* statistics( const RigEclipseResultAddress& resVarAddr );
size_t addStaticScalarResult( RiaDefines::ResultCatType type, const QString& resultName, bool needsToBeStored, size_t resultValueCount );
RigEclipseResultAddress defaultResult() const;
void addResultAlias( QString originalResultName, QString aliasResultName );
void clearAllResultAliases();
private:
// Per-model buffers used by computeDepthRelatedResults(). Holds pointers to the result rows
// and per-property flags telling whether the row still needs to be computed. A buffer with
// actCellCount == 0 is disabled (the porosity model has no active cells).
struct DepthResultBuffers
{
RigActiveCellInfo* activeCellInfo = nullptr;
size_t actCellCount = 0;
std::vector<double>* depth = nullptr;
std::vector<double>* dx = nullptr;
std::vector<double>* dy = nullptr;
std::vector<double>* dz = nullptr;
std::vector<double>* tops = nullptr;
std::vector<double>* bottom = nullptr;
bool computeDepth = false;
bool computeDx = false;
bool computeDy = false;
bool computeDz = false;
bool computeTops = false;
bool computeBottom = false;
};
DepthResultBuffers prepareDepthRelatedResultArrays();
size_t findOrLoadKnownScalarResult( const RigEclipseResultAddress& resVarAddr );
size_t findOrLoadKnownScalarResultByResultTypeOrder( const RigEclipseResultAddress& resVarAddr,
const std::vector<RiaDefines::ResultCatType>& resultCategorySearchOrder );
// 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;
friend class RigSwatResultCalculator;
friend class RigSgasResultCalculator;
friend class RigFaultDistanceResultCalculator;
friend class RigMobilePoreVolumeResultCalculator;
friend class RigIndexIjkResultCalculator;
friend class RigOilVolumeResultCalculator;
friend class RigCellVolumeResultCalculator;
friend class RigCellsWithNncsCalculator;
friend class RigPorvSoilSgasResultCalculator;
size_t findOrCreateScalarResultIndex( const RigEclipseResultAddress& resVarAddr, bool needsToBeStored );
size_t findScalarResultIndexFromAddress( const RigEclipseResultAddress& resVarAddr ) const;
const std::vector<RigEclipseResultInfo>& infoForEachResultIndex() const;
size_t resultCount() const;
bool mustBeCalculated( size_t scalarResultIndex ) const;
void setMustBeCalculated( size_t scalarResultIndex );
bool isResultComputedByResInsight( const QString& resultName, size_t scalarResultIndex ) const;
bool hasEmptyDataForAnyTimeStep( size_t scalarResultIndex ) const;
void computeSOILForTimeStep( size_t timeStepIndex );
void computeSgasForTimeStep( size_t timeStepIndex );
bool hasCompleteTransmissibilityResults() const;
void computeRiTransComponent( const QString& riTransComponentResultName );
void computeNncCombRiTrans();
void computeRiMULTComponent( const QString& riMultCompName );
void computeNncCombRiMULT();
void computeRiTRANSbyAreaComponent( const QString& riTransByAreaCompResultName );
void computeNncCombRiTRANSbyArea();
void computeCompletionTypeForTimeStep( size_t timeStep );
void computeStaticCompletionType();
void computeCompletionTypeForFrame( std::vector<double>& frameValues, size_t calcTimeStep );
void triggerGeneratedPermeabilityCalculations( RimEclipseCase* eclipseCase );
double darchysValue();
void computeOilVolumes();
void computeMobilePV();
void computePorvSoilSgas();
void computeIndexResults();
void computeFaultDistance();
void computeNncsCells();
bool isDataPresent( size_t scalarResultIndex ) const;
size_t allocatedValueCount( size_t scalarResultIndex ) const;
void assignValuesToTemporaryLgrs( const QString& resultName, std::vector<double>& values );
bool isRadialModel() const;
private:
cvf::ref<RifReaderInterface> m_readerInterface;
cvf::ref<RigAllanDiagramData> m_allanDiagramData;
std::vector<std::vector<std::vector<double>>> m_cellScalarResults; ///< Scalar results on the complete reservoir for
///< each Result index (ResultVariable) and timestep
cvf::Collection<RigStatisticsDataCache> m_statisticsDataCache;
std::vector<RigEclipseResultInfo> m_resultInfos;
std::map<RigEclipseResultAddress, size_t> m_addressToResultIndexMap;
std::map<QString, QString> m_resultAliasMap;
RigMainGrid* m_ownerMainGrid;
RigEclipseCaseData* m_ownerCaseData;
RigActiveCellInfo* m_activeCellInfo;
RiaDefines::PorosityModelType m_porosityModel;
// Stored by value, as the owning RimFormationNames can be reloaded or deleted while this data is in use
RigFormationNames m_activeFormationNamesData;
};