diff --git a/ApplicationCode/ProjectDataModel/RimEclipseResultCase.cpp b/ApplicationCode/ProjectDataModel/RimEclipseResultCase.cpp index 2ab655b4ec..c32875a5f5 100644 --- a/ApplicationCode/ProjectDataModel/RimEclipseResultCase.cpp +++ b/ApplicationCode/ProjectDataModel/RimEclipseResultCase.cpp @@ -35,6 +35,7 @@ #include "RimReservoirCellResultsStorage.h" #include "RimTools.h" #include "RimFlowDiagSolution.h" +#include "RigFlowDiagSolverInterface.h" #include "cafPdmSettings.h" #include "cafPdmUiPropertyViewDialog.h" @@ -71,6 +72,8 @@ RimEclipseResultCase::RimEclipseResultCase() flipYAxis.xmlCapability()->setIOWritable(true); //flipYAxis.uiCapability()->setUiHidden(true); + m_flowDagSolverInterface = new RigFlowDiagSolverInterface(this); + m_activeCellInfoIsReadFromFile = false; m_gridAndWellDataIsReadFromFile = false; } @@ -357,6 +360,14 @@ std::vector RimEclipseResultCase::flowDiagSolutions() return flowSols; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RigFlowDiagSolverInterface* RimEclipseResultCase::flowDiagSolverInterface() +{ + return m_flowDagSolverInterface.p(); +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ProjectDataModel/RimEclipseResultCase.h b/ApplicationCode/ProjectDataModel/RimEclipseResultCase.h index bb67fa856a..4543cec58e 100644 --- a/ApplicationCode/ProjectDataModel/RimEclipseResultCase.h +++ b/ApplicationCode/ProjectDataModel/RimEclipseResultCase.h @@ -25,6 +25,7 @@ class RifReaderInterface; class RigMainGrid; class RimFlowDiagSolution; +class RigFlowDiagSolverInterface; //================================================================================================== // @@ -52,6 +53,8 @@ public: virtual void updateFilePathsFromProjectPath(const QString& newProjectPath, const QString& oldProjectPath); std::vector flowDiagSolutions(); + RigFlowDiagSolverInterface* flowDiagSolverInterface(); + private: cvf::ref createMockModel(QString modelName); @@ -59,6 +62,8 @@ private: virtual void defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ); + cvf::ref m_flowDagSolverInterface; + // Fields: caf::PdmField caseFileName; caf::PdmChildArrayField m_flowDiagSolutions; diff --git a/ApplicationCode/ProjectDataModel/RimEclipseView.cpp b/ApplicationCode/ProjectDataModel/RimEclipseView.cpp index 700d4d8958..c210251aa1 100644 --- a/ApplicationCode/ProjectDataModel/RimEclipseView.cpp +++ b/ApplicationCode/ProjectDataModel/RimEclipseView.cpp @@ -76,6 +76,9 @@ #include #include +#include "RimEclipseResultDefinition.h" +#include "RimFlowDiagSolution.h" +#include "RigFlowDiagResults.h" @@ -947,6 +950,7 @@ void RimEclipseView::updateLegends() CVF_ASSERT(results); updateMinMaxValuesAndAddLegendToView(QString("Cell Results: \n"), this->cellResult(), results); + if (this->faultResultSettings()->showCustomFaultResult() && this->faultResultSettings()->hasValidCustomResult()) { updateMinMaxValuesAndAddLegendToView(QString("Fault Results: \n"), this->currentFaultResultColors(), results); @@ -994,7 +998,43 @@ void RimEclipseView::updateMinMaxValuesAndAddLegendToView(QString legendLabel, R { if (resultColors->resultType() == RimDefines::FLOW_DIAGNOSTICS) { - // Todo + double globalMin, globalMax; + double globalPosClosestToZero, globalNegClosestToZero; + RigFlowDiagResults* cellResultsData = resultColors->flowDiagSolution()->flowDiagResults(); + RigFlowDiagResultAddress resAddr = resultColors->flowDiagResAddress(); + + cellResultsData->minMaxScalarValues(resAddr, m_currentTimeStep, &globalMin, &globalMax); + cellResultsData->posNegClosestToZero(resAddr, m_currentTimeStep, &globalPosClosestToZero, &globalNegClosestToZero); + + double localMin, localMax; + double localPosClosestToZero, localNegClosestToZero; + if ( resultColors->hasDynamicResult() ) + { + cellResultsData->minMaxScalarValues(resAddr, m_currentTimeStep, &localMin, &localMax); + cellResultsData->posNegClosestToZero(resAddr, m_currentTimeStep, &localPosClosestToZero, &localNegClosestToZero); + } + else + { + localMin = globalMin; + localMax = globalMax; + + localPosClosestToZero = globalPosClosestToZero; + localNegClosestToZero = globalNegClosestToZero; + } + + CVF_ASSERT(resultColors->legendConfig()); + + resultColors->legendConfig()->setClosestToZeroValues(globalPosClosestToZero, globalNegClosestToZero, localPosClosestToZero, localNegClosestToZero); + resultColors->legendConfig()->setAutomaticRanges(globalMin, globalMax, localMin, localMax); + + if ( resultColors->hasCategoryResult() ) + { + resultColors->legendConfig()->setIntegerCategories(cellResultsData->uniqueCellScalarValues(resAddr, m_currentTimeStep)); + } + + m_viewer->addColorLegendToBottomLeftCorner(resultColors->legendConfig()->legend()); + resultColors->legendConfig()->setTitle(cvfqt::Utils::toString(legendLabel + resultColors->resultVariable())); + } else { diff --git a/ApplicationCode/ProjectDataModel/RimFlowDiagSolution.cpp b/ApplicationCode/ProjectDataModel/RimFlowDiagSolution.cpp index 442e2c9606..f32298c065 100644 --- a/ApplicationCode/ProjectDataModel/RimFlowDiagSolution.cpp +++ b/ApplicationCode/ProjectDataModel/RimFlowDiagSolution.cpp @@ -21,6 +21,7 @@ #include "RigCaseData.h" #include "RigFlowDiagResults.h" +#include "RigCaseCellResultsData.h" CAF_PDM_SOURCE_INIT(RimFlowDiagSolution, "FlowDiagSolution"); @@ -94,6 +95,82 @@ std::set RimFlowDiagSolution::tracerNames() return tracerNameSet; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::map > RimFlowDiagSolution::allInjectorTracerActiveCellIndices(size_t timeStepIndex) +{ + return allTracerActiveCellIndices(timeStepIndex, true); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::map > RimFlowDiagSolution::allProducerTracerActiveCellIndices(size_t timeStepIndex) +{ + return allTracerActiveCellIndices(timeStepIndex, false); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::map > RimFlowDiagSolution::allTracerActiveCellIndices(size_t timeStepIndex, bool useInjectors) +{ + RimEclipseResultCase* eclCase; + this->firstAncestorOrThisOfType(eclCase); + TracerStatusType tracerStatus = UNDEFINED; + + std::map > tracersWithCells; + + if ( eclCase ) + { + const cvf::Collection& wellResults = eclCase->reservoirData()->wellResults(); + RigMainGrid* mainGrid = eclCase->reservoirData()->mainGrid(); + RigActiveCellInfo* activeCellInfo = eclCase->reservoirData()->activeCellInfo(RifReaderInterface::MATRIX_RESULTS); //Todo: Must come from the results definition + + for ( size_t wIdx = 0; wIdx < wellResults.size(); ++wIdx ) + { + if (!wellResults[wIdx]->hasWellResult(timeStepIndex) ) continue; + + size_t wellTimeStep = wellResults[wIdx]->m_resultTimeStepIndexToWellTimeStepIndex[timeStepIndex]; + const RigWellResultFrame& wellResFrame = wellResults[wIdx]->m_wellCellsTimeSteps[wellTimeStep]; + + if ( !wellResFrame.m_isOpen ) continue; + + bool useWell = ( useInjectors && ( wellResFrame.m_productionType == RigWellResultFrame::GAS_INJECTOR + || wellResFrame.m_productionType == RigWellResultFrame::OIL_INJECTOR + || wellResFrame.m_productionType == RigWellResultFrame::WATER_INJECTOR) ) + || (!useInjectors && wellResFrame.m_productionType == RigWellResultFrame::PRODUCER); + + + if (useWell) + { + std::string wellname = wellResults[wIdx]->m_wellName.toStdString(); + std::vector& tracerCells = tracersWithCells[wellname]; + + for (const RigWellResultBranch& wBr: wellResFrame.m_wellResultBranches) + { + for (const RigWellResultPoint& wrp: wBr.m_branchResultPoints) + { + if (wrp.isValid() && wrp.m_isOpen) + { + RigGridBase * grid = mainGrid->gridByIndex(wrp.m_gridIndex); + size_t reservoirCellIndex = grid->reservoirCellIndex(wrp.m_gridCellIndex); + + int cellActiveIndex = static_cast(activeCellInfo->cellResultIndex(reservoirCellIndex)); + tracerCells.push_back(cellActiveIndex); + } + } + } + } + } + } + + return tracersWithCells; +} + + + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ProjectDataModel/RimFlowDiagSolution.h b/ApplicationCode/ProjectDataModel/RimFlowDiagSolution.h index 50fd86baf3..f156396f0e 100644 --- a/ApplicationCode/ProjectDataModel/RimFlowDiagSolution.h +++ b/ApplicationCode/ProjectDataModel/RimFlowDiagSolution.h @@ -40,6 +40,9 @@ public: RigFlowDiagResults* flowDiagResults(); std::set tracerNames(); + std::map > allInjectorTracerActiveCellIndices(size_t timeStepIndex); + std::map > allProducerTracerActiveCellIndices(size_t timeStepIndex); + enum TracerStatusType { PRODUCER, @@ -50,10 +53,13 @@ public: TracerStatusType tracerStatus(QString tracerName); + protected: //virtual QList calculateValueOptions(const caf::PdmFieldHandle* fieldNeedingOptions, bool * useOptionsOnly) override; private: + std::map > allTracerActiveCellIndices(size_t timeStepIndex, bool useInjectors); + virtual caf::PdmFieldHandle* userDescriptionField() override; caf::PdmField m_userDescription; diff --git a/ApplicationCode/ReservoirDataModel/CMakeLists_files.cmake b/ApplicationCode/ReservoirDataModel/CMakeLists_files.cmake index 34b0c768e4..37b2250550 100644 --- a/ApplicationCode/ReservoirDataModel/CMakeLists_files.cmake +++ b/ApplicationCode/ReservoirDataModel/CMakeLists_files.cmake @@ -24,6 +24,9 @@ ${CEE_CURRENT_LIST_DIR}RigFlowDiagResultAddress.h ${CEE_CURRENT_LIST_DIR}RigFlowDiagResults.h ${CEE_CURRENT_LIST_DIR}RigFlowDiagResultFrames.h ${CEE_CURRENT_LIST_DIR}RigFlowDiagSolverInterface.h +${CEE_CURRENT_LIST_DIR}RigFlowDiagInterfaceTools.h +${CEE_CURRENT_LIST_DIR}RigFlowDiagStatCalc.h +${CEE_CURRENT_LIST_DIR}RigFlowDiagVisibleCellsStatCalc.h ${CEE_CURRENT_LIST_DIR}RigWellLogExtractor.h ${CEE_CURRENT_LIST_DIR}RigEclipseWellLogExtractor.h ${CEE_CURRENT_LIST_DIR}RigLocalGrid.h @@ -66,6 +69,8 @@ ${CEE_CURRENT_LIST_DIR}RigFormationNames.cpp ${CEE_CURRENT_LIST_DIR}RigFlowDiagResults.cpp ${CEE_CURRENT_LIST_DIR}RigFlowDiagResultFrames.cpp ${CEE_CURRENT_LIST_DIR}RigFlowDiagSolverInterface.cpp +${CEE_CURRENT_LIST_DIR}RigFlowDiagStatCalc.cpp +${CEE_CURRENT_LIST_DIR}RigFlowDiagVisibleCellsStatCalc.cpp ${CEE_CURRENT_LIST_DIR}RigWellLogExtractor.cpp ${CEE_CURRENT_LIST_DIR}RigEclipseWellLogExtractor.cpp ${CEE_CURRENT_LIST_DIR}RigLocalGrid.cpp diff --git a/ApplicationCode/ReservoirDataModel/RigFlowDiagInterfaceTools.h b/ApplicationCode/ReservoirDataModel/RigFlowDiagInterfaceTools.h new file mode 100644 index 0000000000..7861663ef4 --- /dev/null +++ b/ApplicationCode/ReservoirDataModel/RigFlowDiagInterfaceTools.h @@ -0,0 +1,131 @@ + +#pragma once + + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +namespace RigFlowDiagInterfaceTools { + + + inline Opm::FlowDiagnostics::ConnectionValues + extractFluxField(const Opm::ECLGraph& G) + { + using ConnVals = Opm::FlowDiagnostics::ConnectionValues; + + using NConn = ConnVals::NumConnections; + using NPhas = ConnVals::NumPhases; + + const auto nconn = NConn{G.numConnections()}; + const auto nphas = NPhas{3}; + + auto flux = ConnVals(nconn, nphas); + + auto phas = ConnVals::PhaseID{0}; + + for (const auto& p : { Opm::ECLGraph::PhaseIndex::Aqua , + Opm::ECLGraph::PhaseIndex::Liquid , + Opm::ECLGraph::PhaseIndex::Vapour }) + { + const std::vector pflux = G.flux(p); + + if (! pflux.empty()) { + assert (pflux.size() == nconn.total); + + auto conn = ConnVals::ConnID{0}; + + for (const auto& v : pflux) { + flux(conn, phas) = v; + + conn.id += 1; + } + } + + phas.id += 1; + } + + return flux; + } + + template + Opm::FlowDiagnostics::CellSetValues + extractWellFlows(const Opm::ECLGraph& G, + const WellFluxes& well_fluxes) + { + Opm::FlowDiagnostics::CellSetValues inflow; + for (const auto& well : well_fluxes) { + for (const auto& completion : well.completions) { + const int grid_index = completion.grid_index; + const auto& ijk = completion.ijk; + const int cell_index = G.activeCell(ijk, grid_index); + if (cell_index >= 0) { + inflow.emplace(cell_index, completion.reservoir_inflow_rate); + } + } + } + + return inflow; + } + + namespace Hack { + inline Opm::FlowDiagnostics::ConnectionValues + convert_flux_to_SI(Opm::FlowDiagnostics::ConnectionValues&& fl) + { + using Co = Opm::FlowDiagnostics::ConnectionValues::ConnID; + using Ph = Opm::FlowDiagnostics::ConnectionValues::PhaseID; + + const auto nconn = fl.numConnections(); + const auto nphas = fl.numPhases(); + + for (auto phas = Ph{0}; phas.id < nphas; ++phas.id) { + for (auto conn = Co{0}; conn.id < nconn; ++conn.id) { + fl(conn, phas) /= 86400; + } + } + + return fl; + } + } + + inline Opm::FlowDiagnostics::Toolbox + initialiseFlowDiagnostics(const Opm::ECLGraph& G) + { + const Opm::FlowDiagnostics::ConnectivityGraph connGraph = + Opm::FlowDiagnostics::ConnectivityGraph{ static_cast(G.numCells()), + G.neighbours() }; + + // Create the Toolbox. + + Opm::FlowDiagnostics::Toolbox tool = Opm::FlowDiagnostics::Toolbox{ connGraph }; + + tool.assignPoreVolume(G.poreVolume()); + + Opm::FlowDiagnostics::ConnectionValues connectionsVals = Hack::convert_flux_to_SI(extractFluxField(G)); + tool.assignConnectionFlux(connectionsVals); + + Opm::ECLWellSolution wsol = Opm::ECLWellSolution{}; + + const std::vector well_fluxes = + wsol.solution(G.rawResultData(), G.numGrids()); + + tool.assignInflowFlux(extractWellFlows(G, well_fluxes)); + + return tool; + } + + + +} + + + diff --git a/ApplicationCode/ReservoirDataModel/RigFlowDiagResults.cpp b/ApplicationCode/ReservoirDataModel/RigFlowDiagResults.cpp index a2c24e7d1a..7513f78d0f 100644 --- a/ApplicationCode/ReservoirDataModel/RigFlowDiagResults.cpp +++ b/ApplicationCode/ReservoirDataModel/RigFlowDiagResults.cpp @@ -19,16 +19,18 @@ #include "RigFlowDiagResults.h" #include "RigFlowDiagSolverInterface.h" #include "RimFlowDiagSolution.h" +#include "RimEclipseResultCase.h" +#include "RimEclipseCase.h" +#include "RigCaseData.h" +#include "RigFlowDiagStatCalc.h" //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RigFlowDiagResults::RigFlowDiagResults(RimFlowDiagSolution* flowSolution, size_t timeStepCount) - : m_flowDiagSolution() + : m_flowDiagSolution(flowSolution) { - m_flowDagSolverInterface = new RigFlowDiagSolverInterface(flowSolution); - m_timeStepCount = timeStepCount; m_hasAtemptedNativeResults.resize(timeStepCount, false); } @@ -52,6 +54,17 @@ const std::vector* RigFlowDiagResults::resultValues(const RigFlowDiagRes return findOrCalculateResult(resVarAddr, frameIndex); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +const RigActiveCellInfo * RigFlowDiagResults::activeCellInfo(const RigFlowDiagResultAddress& resVarAddr) +{ + RimEclipseResultCase* eclCase; + m_flowDiagSolution->firstAncestorOrThisOfType(eclCase); + + return eclCase->reservoirData()->activeCellInfo(RifReaderInterface::MATRIX_RESULTS); // Todo: base on resVarAddr member +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -70,7 +83,10 @@ const std::vector* RigFlowDiagResults::findOrCalculateResult(const RigFl if (!m_hasAtemptedNativeResults[frameIndex]) { - RigFlowDiagTimeStepResult nativeTimestepResults = m_flowDagSolverInterface->calculate(frameIndex); + + RigFlowDiagTimeStepResult nativeTimestepResults = solverInterface()->calculate(frameIndex, + m_flowDiagSolution->allInjectorTracerActiveCellIndices(frameIndex), + m_flowDiagSolution->allProducerTracerActiveCellIndices(frameIndex)); std::map >& nativeResults = nativeTimestepResults.nativeResults(); @@ -103,6 +119,17 @@ std::vector* RigFlowDiagResults::findScalarResultFrame(const RigFlowDiag return nullptr; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RigFlowDiagSolverInterface* RigFlowDiagResults::solverInterface() +{ + RimEclipseResultCase* eclCase; + m_flowDiagSolution->firstAncestorOrThisOfType(eclCase); + + return eclCase->flowDiagSolverInterface(); +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -134,3 +161,138 @@ std::vector* RigFlowDiagResults::calculateDerivedResult(const RigFlowDia return nullptr; // Todo } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RigStatisticsDataCache* RigFlowDiagResults::statistics(const RigFlowDiagResultAddress& resVarAddr) +{ + RigStatisticsDataCache* statCache = m_resultStatistics[resVarAddr].p(); + if ( !statCache ) + { + RigFlowDiagStatCalc* calculator = new RigFlowDiagStatCalc(this, resVarAddr); + statCache = new RigStatisticsDataCache(calculator); + m_resultStatistics[resVarAddr] = statCache; + } + + return statCache; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RigFlowDiagResults::minMaxScalarValues(const RigFlowDiagResultAddress& resVarAddr, int frameIndex, + double* localMin, double* localMax) +{ + this->statistics(resVarAddr)->minMaxCellScalarValues(frameIndex, *localMin, *localMax); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RigFlowDiagResults::minMaxScalarValues(const RigFlowDiagResultAddress& resVarAddr, + double* globalMin, double* globalMax) +{ + this->statistics(resVarAddr)->minMaxCellScalarValues(*globalMin, *globalMax); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RigFlowDiagResults::posNegClosestToZero(const RigFlowDiagResultAddress& resVarAddr, int frameIndex, double* localPosClosestToZero, double* localNegClosestToZero) +{ + this->statistics(resVarAddr)->posNegClosestToZero(frameIndex, *localPosClosestToZero, *localNegClosestToZero); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RigFlowDiagResults::posNegClosestToZero(const RigFlowDiagResultAddress& resVarAddr, double* globalPosClosestToZero, double* globalNegClosestToZero) +{ + this->statistics(resVarAddr)->posNegClosestToZero(*globalPosClosestToZero, *globalNegClosestToZero); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RigFlowDiagResults::meanScalarValue(const RigFlowDiagResultAddress& resVarAddr, double* meanValue) +{ + CVF_ASSERT(meanValue); + + this->statistics(resVarAddr)->meanCellScalarValues(*meanValue); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RigFlowDiagResults::meanScalarValue(const RigFlowDiagResultAddress& resVarAddr, int frameIndex, double* meanValue) +{ + this->statistics(resVarAddr)->meanCellScalarValues(frameIndex, *meanValue); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RigFlowDiagResults::p10p90ScalarValues(const RigFlowDiagResultAddress& resVarAddr, double* p10, double* p90) +{ + this->statistics(resVarAddr)->p10p90CellScalarValues(*p10, *p90); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RigFlowDiagResults::p10p90ScalarValues(const RigFlowDiagResultAddress& resVarAddr, int frameIndex, double* p10, double* p90) +{ + this->statistics(resVarAddr)->p10p90CellScalarValues(frameIndex, *p10, *p90); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RigFlowDiagResults::sumScalarValue(const RigFlowDiagResultAddress& resVarAddr, double* sum) +{ + CVF_ASSERT(sum); + + this->statistics(resVarAddr)->sumCellScalarValues(*sum); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RigFlowDiagResults::sumScalarValue(const RigFlowDiagResultAddress& resVarAddr, int frameIndex, double* sum) +{ + CVF_ASSERT(sum); + + this->statistics(resVarAddr)->sumCellScalarValues(frameIndex, *sum); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +const std::vector& RigFlowDiagResults::scalarValuesHistogram(const RigFlowDiagResultAddress& resVarAddr) +{ + return this->statistics(resVarAddr)->cellScalarValuesHistogram(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +const std::vector& RigFlowDiagResults::scalarValuesHistogram(const RigFlowDiagResultAddress& resVarAddr, int frameIndex) +{ + return this->statistics(resVarAddr)->cellScalarValuesHistogram(frameIndex); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +const std::vector& RigFlowDiagResults::uniqueCellScalarValues(const RigFlowDiagResultAddress& resVarAddr) +{ + return this->statistics(resVarAddr)->uniqueCellScalarValues(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +const std::vector& RigFlowDiagResults::uniqueCellScalarValues(const RigFlowDiagResultAddress& resVarAddr, int frameIndex) +{ + return this->statistics(resVarAddr)->uniqueCellScalarValues(frameIndex); +} diff --git a/ApplicationCode/ReservoirDataModel/RigFlowDiagResults.h b/ApplicationCode/ReservoirDataModel/RigFlowDiagResults.h index dfc4ce5e0f..0f4d9ecfe1 100644 --- a/ApplicationCode/ReservoirDataModel/RigFlowDiagResults.h +++ b/ApplicationCode/ReservoirDataModel/RigFlowDiagResults.h @@ -40,11 +40,31 @@ public: virtual ~RigFlowDiagResults(); const std::vector* resultValues(const RigFlowDiagResultAddress& resVarAddr, size_t frameIndex); + size_t timeStepCount() { return m_timeStepCount; } + const RigActiveCellInfo * activeCellInfo(const RigFlowDiagResultAddress& resVarAddr); + + + void minMaxScalarValues (const RigFlowDiagResultAddress& resVarAddr, int frameIndex, double* localMin, double* localMax); + void minMaxScalarValues (const RigFlowDiagResultAddress& resVarAddr, double* globalMin, double* globalMax); + void posNegClosestToZero(const RigFlowDiagResultAddress& resVarAddr, int frameIndex, double* localPosClosestToZero, double* localNegClosestToZero); + void posNegClosestToZero(const RigFlowDiagResultAddress& resVarAddr, double* globalPosClosestToZero, double* globalNegClosestToZero); + void meanScalarValue(const RigFlowDiagResultAddress& resVarAddr, double* meanValue); + void meanScalarValue(const RigFlowDiagResultAddress& resVarAddr, int frameIndex, double* meanValue); + void p10p90ScalarValues(const RigFlowDiagResultAddress& resVarAddr, double* p10, double* p90); + void p10p90ScalarValues(const RigFlowDiagResultAddress& resVarAddr, int frameIndex, double* p10, double* p90); + void sumScalarValue(const RigFlowDiagResultAddress& resVarAddr, double* sum); + void sumScalarValue(const RigFlowDiagResultAddress& resVarAddr, int frameIndex, double* sum); + const std::vector& scalarValuesHistogram(const RigFlowDiagResultAddress& resVarAddr); + const std::vector& scalarValuesHistogram(const RigFlowDiagResultAddress& resVarAddr, int frameIndex); + const std::vector& uniqueCellScalarValues(const RigFlowDiagResultAddress& resVarAddr); + const std::vector& uniqueCellScalarValues(const RigFlowDiagResultAddress& resVarAddr, int frameIndex); private: const std::vector* findOrCalculateResult (const RigFlowDiagResultAddress& resVarAddr, size_t frameIndex); std::vector* calculateDerivedResult(const RigFlowDiagResultAddress& resVarAddr, size_t frameIndex); - void calculateFractionWeightedTOF ( size_t timeStepIdx, std::set selectedTracerNames); + RigStatisticsDataCache* statistics(const RigFlowDiagResultAddress& resVarAddr); + + void calculateFractionWeightedTOF (size_t timeStepIdx, std::set selectedTracerNames); void calculateSumOfFractions ( size_t timeStepIdx, std::set selectedTracerNames); void calculateTracerWithMaxFraction( size_t timeStepIdx, std::set selectedTracerNames); // Needs a tracer index void calculateCommunication ( size_t timeStepIdx, std::set selectedTracerNames); @@ -60,7 +80,7 @@ private: std::map< RigFlowDiagResultAddress, cvf::ref > m_resultSets; std::map< RigFlowDiagResultAddress, cvf::ref > m_resultStatistics; - cvf::ref m_flowDagSolverInterface; + RigFlowDiagSolverInterface* solverInterface(); caf::PdmPointer m_flowDiagSolution; diff --git a/ApplicationCode/ReservoirDataModel/RigFlowDiagSolverInterface.cpp b/ApplicationCode/ReservoirDataModel/RigFlowDiagSolverInterface.cpp index 04f2c44f7b..2e3fe4098f 100644 --- a/ApplicationCode/ReservoirDataModel/RigFlowDiagSolverInterface.cpp +++ b/ApplicationCode/ReservoirDataModel/RigFlowDiagSolverInterface.cpp @@ -18,11 +18,21 @@ #include "RigFlowDiagSolverInterface.h" #include "RimFlowDiagSolution.h" +#include "RimEclipseResultCase.h" +#include "RigCaseCellResultsData.h" + +#include "RigFlowDiagInterfaceTools.h" +#include "RifEclipseOutputFileTools.h" +#include "RigCaseData.h" +#include "RimEclipseCase.h" +#include "RifReaderInterface.h" +#include //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RigFlowDiagTimeStepResult::RigFlowDiagTimeStepResult(size_t activeCellCount) + : m_activeCellCount(activeCellCount) { } @@ -31,10 +41,70 @@ RigFlowDiagTimeStepResult::RigFlowDiagTimeStepResult(size_t activeCellCount) //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -RigFlowDiagSolverInterface::RigFlowDiagSolverInterface(RimFlowDiagSolution* flowSol) -: m_flowDiagSolution(flowSol) +void RigFlowDiagTimeStepResult::setInjectorTracerTOF(const std::string& tracerName, const std::map& cellValues) { + std::set tracers; + tracers.insert(tracerName); + this->addResult(RigFlowDiagResultAddress(RIG_FLD_TOF_RESNAME, tracers), cellValues); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RigFlowDiagTimeStepResult::setInjectorTracerFraction(const std::string& tracerName, const std::map& cellValues) +{ + std::set tracers; + tracers.insert(tracerName); + + this->addResult(RigFlowDiagResultAddress(RIG_FLD_CELL_FRACTION_RESNAME, tracers), cellValues); + +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RigFlowDiagTimeStepResult::setProducerTracerTOF(const std::string& tracerName, const std::map& cellValues) +{ + std::set tracers; + tracers.insert(tracerName); + + this->addResult(RigFlowDiagResultAddress(RIG_FLD_TOF_RESNAME, tracers), cellValues); + +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RigFlowDiagTimeStepResult::setProducerTracerFraction(const std::string& tracerName, const std::map& cellValues) +{ + std::set tracers; + tracers.insert(tracerName); + + this->addResult(RigFlowDiagResultAddress(RIG_FLD_CELL_FRACTION_RESNAME, tracers), cellValues); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RigFlowDiagTimeStepResult::addResult(const RigFlowDiagResultAddress& resAddr, const std::map& cellValues) +{ + std::vector& activeCellValues = m_nativeResults[resAddr]; + activeCellValues.resize(m_activeCellCount, HUGE_VAL); + + for (const auto& pairIt : cellValues) + { + activeCellValues[pairIt.first] = pairIt.second; + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RigFlowDiagSolverInterface::RigFlowDiagSolverInterface(RimEclipseResultCase * eclipseCase) +: m_eclipseCase(eclipseCase) +{ + } //-------------------------------------------------------------------------------------------------- @@ -48,10 +118,92 @@ RigFlowDiagSolverInterface::~RigFlowDiagSolverInterface() //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -RigFlowDiagTimeStepResult RigFlowDiagSolverInterface::calculate(size_t timestep) +RigFlowDiagTimeStepResult RigFlowDiagSolverInterface::calculate(size_t timeStepIndex, + std::map > injectorTracers, + std::map > producerTracers) { - std::vector allTracerData; + using namespace Opm::FlowDiagnostics; - return RigFlowDiagTimeStepResult(0); // Relying on implicit move constructor + RigFlowDiagTimeStepResult result(m_eclipseCase->reservoirData()->activeCellInfo(RifReaderInterface::MATRIX_RESULTS)->reservoirActiveCellCount()); + + // Get set of files + QString gridFileName = m_eclipseCase->gridFileName(); + + QStringList m_filesWithSameBaseName; + + if ( !RifEclipseOutputFileTools::findSiblingFilesWithSameBaseName(gridFileName, &m_filesWithSameBaseName) ) return result; + + QString initFileName = RifEclipseOutputFileTools::firstFileNameOfType(m_filesWithSameBaseName, ECL_INIT_FILE); + + Opm::ECLGraph graph = Opm::ECLGraph::load(gridFileName.toStdString(), + initFileName.toStdString()); + + // Look for unified restart file + QString restartFileName = RifEclipseOutputFileTools::firstFileNameOfType(m_filesWithSameBaseName, ECL_UNIFIED_RESTART_FILE); + + if ( restartFileName.isEmpty() ) + { + // Look for set of restart files (one file per time step) + + QStringList restartFileNames; + restartFileNames = RifEclipseOutputFileTools::filterFileNamesOfType(m_filesWithSameBaseName, ECL_RESTART_FILE); + if (restartFileNames.size() <= timeStepIndex && restartFileNames.size() != m_eclipseCase->reservoirData()->results(RifReaderInterface::MATRIX_RESULTS)->maxTimeStepCount() ) + { + QMessageBox::critical(nullptr, "ResInsight", "Flow Diagnostics: Could not find all the restart files. Results will not be loaded."); + return result; + } + + restartFileNames.sort(); // To make sure they are sorted in increasing *.X000N order. Hack. Should probably be actual time stored on file. + restartFileName = restartFileNames[static_cast(timeStepIndex)]; + } + + std::string casePath; + graph.assignFluxDataSource(restartFileName.toStdString()); + + if ( ! graph.selectReportStep(static_cast(timeStepIndex)) ) + { + QMessageBox::critical(nullptr, "ResInsight", "Flow Diagnostics: Could not find the requested timestep in the result file. Results will not be loaded."); + return result; + } + + { + Toolbox fdTool = RigFlowDiagInterfaceTools::initialiseFlowDiagnostics(graph); + { + std::vector injectorCellSet; + for ( const auto& tIt: injectorTracers ) + { + injectorCellSet.push_back(CellSet(CellSetID(tIt.first), tIt.second)); + } + + Solution injSol = fdTool.computeInjectionDiagnostics(injectorCellSet).fd; + + for ( const CellSetID& tracerId: injSol.startPoints() ) + { + CellSetValues tofVals = injSol.timeOfFlight(tracerId); + result.setInjectorTracerTOF(tracerId.to_string(), tofVals); + CellSetValues fracVals = injSol.concentration(tracerId); + result.setInjectorTracerFraction(tracerId.to_string(), fracVals); + } + } + + { + std::vector prodjCellSet; + for ( const auto& tIt: producerTracers ) + { + prodjCellSet.push_back(CellSet(CellSetID(tIt.first), tIt.second)); + } + Solution prodSol = fdTool.computeProductionDiagnostics(prodjCellSet).fd; + for ( const CellSetID& tracerId: prodSol.startPoints() ) + { + CellSetValues tofVals = prodSol.timeOfFlight(tracerId); + result.setProducerTracerTOF(tracerId.to_string(), tofVals); + CellSetValues fracVals = prodSol.concentration(tracerId); + result.setInjectorTracerFraction(tracerId.to_string(), fracVals); + } + } + } + + + return result; // Relying on implicit move constructor } diff --git a/ApplicationCode/ReservoirDataModel/RigFlowDiagSolverInterface.h b/ApplicationCode/ReservoirDataModel/RigFlowDiagSolverInterface.h index b525e00e68..7149a969fc 100644 --- a/ApplicationCode/ReservoirDataModel/RigFlowDiagSolverInterface.h +++ b/ApplicationCode/ReservoirDataModel/RigFlowDiagSolverInterface.h @@ -29,13 +29,6 @@ class RimEclipseResultCase; class RimFlowDiagSolution; -struct RigTracerCells -{ - std::string tracerName; - std::vector tracerCellActiveIndices; -}; - - class RigFlowDiagTimeStepResult { @@ -54,21 +47,25 @@ private: void addResult(const RigFlowDiagResultAddress& resAddr, const std::map& cellValues); std::map > m_nativeResults; + size_t m_activeCellCount; }; - +class RigCaseData; class RigFlowDiagSolverInterface : public cvf::Object { public: - RigFlowDiagSolverInterface(RimFlowDiagSolution* flowSol); + RigFlowDiagSolverInterface(RimEclipseResultCase * eclipseCase); virtual ~RigFlowDiagSolverInterface(); - RigFlowDiagTimeStepResult calculate(size_t timestep); + RigFlowDiagTimeStepResult calculate(size_t timestep, + std::map > injectorTracers, + std::map > producerTracers); private: - caf::PdmPointer m_flowDiagSolution; + RimEclipseResultCase * m_eclipseCase; + }; diff --git a/ApplicationCode/ReservoirDataModel/RigFlowDiagStatCalc.cpp b/ApplicationCode/ReservoirDataModel/RigFlowDiagStatCalc.cpp new file mode 100644 index 0000000000..724d026ebd --- /dev/null +++ b/ApplicationCode/ReservoirDataModel/RigFlowDiagStatCalc.cpp @@ -0,0 +1,107 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) Statoil ASA +// Copyright (C) Ceetron Solutions 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 +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RigFlowDiagStatCalc.h" +#include "RigFlowDiagResults.h" + +#include +#include "RigStatisticsMath.h" + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RigFlowDiagStatCalc::RigFlowDiagStatCalc(RigFlowDiagResults* flowDiagResults, const RigFlowDiagResultAddress& resVarAddr) +: m_resVarAddr(resVarAddr) +{ + m_resultsData = flowDiagResults; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RigFlowDiagStatCalc::minMaxCellScalarValues(size_t timeStepIndex, double& min, double& max) +{ + MinMaxAccumulator minMaxCalc(min, max); + const std::vector* vals = m_resultsData->resultValues(m_resVarAddr, timeStepIndex); + + if (vals) minMaxCalc.addData(*vals); + + min = minMaxCalc.min; + max = minMaxCalc.max; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RigFlowDiagStatCalc::posNegClosestToZero(size_t timeStepIndex, double& pos, double& neg) +{ + PosNegAccumulator posNegCalc(pos, neg); + const std::vector* vals = m_resultsData->resultValues(m_resVarAddr, timeStepIndex); + + if ( vals ) posNegCalc.addData(*vals); + + pos = posNegCalc.pos; + neg = posNegCalc.neg; +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RigFlowDiagStatCalc::valueSumAndSampleCount(size_t timeStepIndex, double& valueSum, size_t& sampleCount) +{ + SumCountAccumulator sumCountCalc(valueSum, sampleCount); + const std::vector* vals = m_resultsData->resultValues(m_resVarAddr, timeStepIndex); + + if ( vals ) sumCountCalc.addData(*vals); + + valueSum = sumCountCalc.valueSum; + sampleCount = sumCountCalc.sampleCount; +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RigFlowDiagStatCalc::addDataToHistogramCalculator(size_t timeStepIndex, RigHistogramCalculator& histogramCalculator) +{ + const std::vector* vals = m_resultsData->resultValues(m_resVarAddr, timeStepIndex); + + if ( vals ) histogramCalculator.addData(*vals); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RigFlowDiagStatCalc::uniqueValues(size_t timeStepIndex, std::set& uniqueValues) +{ + const std::vector* vals = m_resultsData->resultValues(m_resVarAddr, timeStepIndex); + + if ( vals ) for ( double val : (*vals) ) uniqueValues.insert(static_cast(val)); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +size_t RigFlowDiagStatCalc::timeStepCount() +{ + return m_resultsData->timeStepCount(); +} + + diff --git a/ApplicationCode/ReservoirDataModel/RigFlowDiagStatCalc.h b/ApplicationCode/ReservoirDataModel/RigFlowDiagStatCalc.h new file mode 100644 index 0000000000..bd145c43d2 --- /dev/null +++ b/ApplicationCode/ReservoirDataModel/RigFlowDiagStatCalc.h @@ -0,0 +1,50 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) Statoil ASA +// Copyright (C) Ceetron Solutions 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 +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "RigStatisticsCalculator.h" +#include "RigFlowDiagResultAddress.h" + +class RigHistogramCalculator; +class RigFlowDiagResults; + +//================================================================================================== +/// +//================================================================================================== + +class RigFlowDiagStatCalc : public RigStatisticsCalculator +{ +public: + RigFlowDiagStatCalc(RigFlowDiagResults* femResultCollection, const RigFlowDiagResultAddress& resVarAddr); + + virtual void minMaxCellScalarValues(size_t timeStepIndex, double& min, double& max); + virtual void posNegClosestToZero(size_t timeStepIndex, double& pos, double& neg); + virtual void valueSumAndSampleCount(size_t timeStepIndex, double& valueSum, size_t& sampleCount); + virtual void addDataToHistogramCalculator(size_t timeStepIndex, RigHistogramCalculator& histogramCalculator); + virtual void uniqueValues(size_t timeStepIndex, std::set& values); + virtual size_t timeStepCount(); + +private: + RigFlowDiagResults* m_resultsData; + RigFlowDiagResultAddress m_resVarAddr; +}; + + + diff --git a/ApplicationCode/ReservoirDataModel/RigFlowDiagVisibleCellsStatCalc.cpp b/ApplicationCode/ReservoirDataModel/RigFlowDiagVisibleCellsStatCalc.cpp new file mode 100644 index 0000000000..e0d8357354 --- /dev/null +++ b/ApplicationCode/ReservoirDataModel/RigFlowDiagVisibleCellsStatCalc.cpp @@ -0,0 +1,98 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2015- Statoil ASA +// Copyright (C) 2015- Ceetron Solutions 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 +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + + +#include "RigFlowDiagVisibleCellsStatCalc.h" + +#include +#include "RigStatisticsMath.h" +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RigFlowDiagVisibleCellsStatCalc::RigFlowDiagVisibleCellsStatCalc(RigFlowDiagResults* resultsData, + const RigFlowDiagResultAddress& resVarAddr, + const cvf::UByteArray* cellVisibilities) +: m_resultsData(resultsData), m_resVarAddr(resVarAddr), m_cellVisibilities(cellVisibilities) +{ +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RigFlowDiagVisibleCellsStatCalc::minMaxCellScalarValues(size_t timeStepIndex, double& min, double& max) +{ + MinMaxAccumulator acc(min, max); + traverseElementNodes(acc, timeStepIndex); + min = acc.min; + max = acc.max; +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RigFlowDiagVisibleCellsStatCalc::posNegClosestToZero(size_t timeStepIndex, double& pos, double& neg) +{ + PosNegAccumulator acc(pos, neg); + traverseElementNodes(acc, timeStepIndex); + pos = acc.pos; + neg = acc.neg; + +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RigFlowDiagVisibleCellsStatCalc::valueSumAndSampleCount(size_t timeStepIndex, double& valueSum, size_t& sampleCount) +{ + SumCountAccumulator acc(valueSum, sampleCount); + traverseElementNodes(acc, timeStepIndex); + valueSum = acc.valueSum; + sampleCount = acc.sampleCount; +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RigFlowDiagVisibleCellsStatCalc::addDataToHistogramCalculator(size_t timeStepIndex, RigHistogramCalculator& histogramCalculator) +{ + traverseElementNodes(histogramCalculator, timeStepIndex); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RigFlowDiagVisibleCellsStatCalc::uniqueValues(size_t timeStepIndex, std::set& values) +{ + UniqueValueAccumulator acc; + traverseElementNodes(acc, timeStepIndex); + values = acc.uniqueValues; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +size_t RigFlowDiagVisibleCellsStatCalc::timeStepCount() +{ + return m_resultsData->timeStepCount(); +} + + diff --git a/ApplicationCode/ReservoirDataModel/RigFlowDiagVisibleCellsStatCalc.h b/ApplicationCode/ReservoirDataModel/RigFlowDiagVisibleCellsStatCalc.h new file mode 100644 index 0000000000..4a862a2ea1 --- /dev/null +++ b/ApplicationCode/ReservoirDataModel/RigFlowDiagVisibleCellsStatCalc.h @@ -0,0 +1,78 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2015- Statoil ASA +// Copyright (C) 2015- Ceetron Solutions 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 +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +//================================================================================================== +/// +//================================================================================================== +#include "RigStatisticsCalculator.h" +#include "RigFlowDiagResultAddress.h" +#include "RigFlowDiagResults.h" + +#include "cvfArray.h" + +class RigFlowDiagResults; + + +class RigFlowDiagVisibleCellsStatCalc : public RigStatisticsCalculator +{ +public: + RigFlowDiagVisibleCellsStatCalc(RigFlowDiagResults* resultsData, + const RigFlowDiagResultAddress& resVarAddr, + const cvf::UByteArray* cellVisibilities); + + virtual void minMaxCellScalarValues(size_t timeStepIndex, double& min, double& max); + virtual void posNegClosestToZero(size_t timeStepIndex, double& pos, double& neg); + virtual void valueSumAndSampleCount(size_t timeStepIndex, double& valueSum, size_t& sampleCount); + virtual void addDataToHistogramCalculator(size_t timeStepIndex, RigHistogramCalculator& histogramCalculator); + virtual void uniqueValues(size_t timeStepIndex, std::set& values); + virtual size_t timeStepCount(); + +private: + RigFlowDiagResults* m_resultsData; + RigFlowDiagResultAddress m_resVarAddr; + cvf::cref m_cellVisibilities; + + template + void traverseElementNodes(StatisticsAccumulator& accumulator, size_t timeStepIndex) + { + const std::vector* values = m_resultsData->resultValues(m_resVarAddr, timeStepIndex); + if (!values) return; + + const RigActiveCellInfo* actCellInfo = m_resultsData->activeCellInfo(m_resVarAddr); + + size_t cellCount = actCellInfo->reservoirCellCount(); + + CVF_TIGHT_ASSERT(cellCount == m_cellVisibilities->size()); + + for ( size_t cIdx = 0; cIdx < cellCount; ++cIdx ) + { + if ( !(*m_cellVisibilities)[cIdx] ) continue; + + size_t cellResultIndex = actCellInfo->cellResultIndex(cIdx); + + if ( cellResultIndex != cvf::UNDEFINED_SIZE_T ) accumulator.addValue((*values)[cellResultIndex]); + } + } + +}; + + +