From 1fefc6124f27e677305cacbd91840c07b4b1520b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacob=20St=C3=B8ren?= Date: Fri, 24 Mar 2017 15:10:39 +0100 Subject: [PATCH] #1321 Wip: First shot on bringing the flow characteristics curves up into the open. --- .../Flow/CMakeLists_files.cmake | 2 + .../Flow/RimFlowCharacteristicsPlot.cpp | 225 ++++++++++++++++++ .../Flow/RimFlowCharacteristicsPlot.h | 82 +++++++ .../Flow/RimFlowPlotCollection.cpp | 5 + .../Flow/RimFlowPlotCollection.h | 2 + .../ReservoirDataModel/RigFlowDiagResults.cpp | 21 ++ .../ReservoirDataModel/RigFlowDiagResults.h | 19 ++ .../RigFlowDiagSolverInterface.cpp | 67 ++++-- .../RigFlowDiagSolverInterface.h | 19 +- .../UserInterface/CMakeLists_files.cmake | 3 + .../RiuFlowCharacteristicsPlot.cpp | 154 ++++++++++++ .../RiuFlowCharacteristicsPlot.h | 70 ++++++ .../UserInterface/RiuSummaryQwtPlot.h | 3 +- 13 files changed, 644 insertions(+), 28 deletions(-) create mode 100644 ApplicationCode/ProjectDataModel/Flow/RimFlowCharacteristicsPlot.cpp create mode 100644 ApplicationCode/ProjectDataModel/Flow/RimFlowCharacteristicsPlot.h create mode 100644 ApplicationCode/UserInterface/RiuFlowCharacteristicsPlot.cpp create mode 100644 ApplicationCode/UserInterface/RiuFlowCharacteristicsPlot.h diff --git a/ApplicationCode/ProjectDataModel/Flow/CMakeLists_files.cmake b/ApplicationCode/ProjectDataModel/Flow/CMakeLists_files.cmake index a65e9daffd..e0d6fb0abe 100644 --- a/ApplicationCode/ProjectDataModel/Flow/CMakeLists_files.cmake +++ b/ApplicationCode/ProjectDataModel/Flow/CMakeLists_files.cmake @@ -11,6 +11,7 @@ ${CEE_CURRENT_LIST_DIR}RimWellAllocationPlot.h ${CEE_CURRENT_LIST_DIR}RimTotalWellAllocationPlot.h ${CEE_CURRENT_LIST_DIR}RimWellFlowRateCurve.h ${CEE_CURRENT_LIST_DIR}RimWellAllocationPlotLegend.h +${CEE_CURRENT_LIST_DIR}RimFlowCharacteristicsPlot.h ) set (SOURCE_GROUP_SOURCE_FILES @@ -20,6 +21,7 @@ ${CEE_CURRENT_LIST_DIR}RimWellAllocationPlot.cpp ${CEE_CURRENT_LIST_DIR}RimTotalWellAllocationPlot.cpp ${CEE_CURRENT_LIST_DIR}RimWellFlowRateCurve.cpp ${CEE_CURRENT_LIST_DIR}RimWellAllocationPlotLegend.cpp +${CEE_CURRENT_LIST_DIR}RimFlowCharacteristicsPlot.cpp ) list(APPEND CODE_HEADER_FILES diff --git a/ApplicationCode/ProjectDataModel/Flow/RimFlowCharacteristicsPlot.cpp b/ApplicationCode/ProjectDataModel/Flow/RimFlowCharacteristicsPlot.cpp new file mode 100644 index 0000000000..d19200dd67 --- /dev/null +++ b/ApplicationCode/ProjectDataModel/Flow/RimFlowCharacteristicsPlot.cpp @@ -0,0 +1,225 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2017 Statoil 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 +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RimFlowCharacteristicsPlot.h" + +#include "RimFlowDiagSolution.h" +#include "RimEclipseResultCase.h" + +#include "RigFlowDiagResults.h" + +#include "RiuFlowCharacteristicsPlot.h" +#include "RimProject.h" + + +CAF_PDM_SOURCE_INIT(RimFlowCharacteristicsPlot, "FlowCharacteristicsPlot"); + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimFlowCharacteristicsPlot::RimFlowCharacteristicsPlot() +{ + CAF_PDM_InitObject("Flow Characteristics", ":/WellAllocPie16x16.png", "", ""); + + CAF_PDM_InitFieldNoDefault(&m_case, "FlowCase", "Case", "", "", ""); + CAF_PDM_InitFieldNoDefault(&m_flowDiagSolution, "FlowDiagSolution", "Flow Diag Solution", "", "", ""); + + this->m_showWindow = false; + setAsPlotMdiWindow(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimFlowCharacteristicsPlot::~RimFlowCharacteristicsPlot() +{ + removeMdiWindowFromMdiArea(); + + deleteViewWidget(); +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimFlowCharacteristicsPlot::setFromFlowSolution(RimFlowDiagSolution* flowSolution) +{ + if ( !flowSolution ) + { + m_case = nullptr; + } + else + { + RimEclipseResultCase* eclCase; + flowSolution->firstAncestorOrThisOfType(eclCase); + m_case = eclCase; + } + + m_flowDiagSolution = flowSolution; + + loadDataAndUpdate(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimFlowCharacteristicsPlot::deleteViewWidget() +{ + if (m_flowCharPlotWidget) + { + m_flowCharPlotWidget->deleteLater(); + m_flowCharPlotWidget= nullptr; + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QList RimFlowCharacteristicsPlot::calculateValueOptions(const caf::PdmFieldHandle* fieldNeedingOptions, bool* useOptionsOnly) +{ + QList options; + + if ( fieldNeedingOptions == &m_case ) + { + RimProject* proj = nullptr; + this->firstAncestorOrThisOfType(proj); + if ( proj ) + { + std::vector cases; + proj->descendantsIncludingThisOfType(cases); + + for ( RimEclipseResultCase* c : cases ) + { + options.push_back(caf::PdmOptionItemInfo(c->caseUserDescription(), c, false, c->uiIcon())); + } + } + } + else if ( fieldNeedingOptions == &m_flowDiagSolution ) + { + if ( m_case ) + { + std::vector flowSols = m_case->flowDiagSolutions(); + + for ( RimFlowDiagSolution* flowSol : flowSols ) + { + options.push_back(caf::PdmOptionItemInfo("None", nullptr)); + options.push_back(caf::PdmOptionItemInfo(flowSol->userDescription(), flowSol, false, flowSol->uiIcon())); + } + } + } + + return options; + +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QWidget* RimFlowCharacteristicsPlot::viewWidget() +{ + return m_flowCharPlotWidget; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimFlowCharacteristicsPlot::zoomAll() +{ +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimFlowCharacteristicsPlot::fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) +{ + RimViewWindow::fieldChangedByUi(changedField, oldValue, newValue); + + if ( &m_case == changedField + || &m_flowDiagSolution == changedField) + { + this->loadDataAndUpdate(); + } + +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QImage RimFlowCharacteristicsPlot::snapshotWindowContent() +{ + QImage image; + + if (m_flowCharPlotWidget) + { + QPixmap pix = QPixmap::grabWidget(m_flowCharPlotWidget); + image = pix.toImage(); + } + + return image; +} + + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimFlowCharacteristicsPlot::loadDataAndUpdate() +{ + updateMdiWindowVisibility(); + + if (m_flowDiagSolution) + { + RigFlowDiagResults* flowResult = m_flowDiagSolution->flowDiagResults(); + std::vector calculatedTimesteps = flowResult->calculatedTimeSteps(); + + std::vector timeStepDates = m_case->timeStepDates(); + std::vector lorenzVals(timeStepDates.size(), HUGE_VAL); + + for (int timeStepIdx: calculatedTimesteps) + { + lorenzVals[timeStepIdx] = flowResult->flowCharacteristicsResults(timeStepIdx).m_lorenzCoefficient; + + if ( m_flowCharPlotWidget) + { + const auto & flowCharResults = flowResult->flowCharacteristicsResults(timeStepIdx); + m_flowCharPlotWidget->addFlowCapStorageCapCurve(timeStepDates[timeStepIdx], + flowCharResults.m_flowCapStorageCapCurve.first, + flowCharResults.m_flowCapStorageCapCurve.second); + m_flowCharPlotWidget->addSweepEfficiencyCurve(timeStepDates[timeStepIdx], + flowCharResults.m_sweepEfficiencyCurve.first, + flowCharResults.m_sweepEfficiencyCurve.second); + } + } + + if ( m_flowCharPlotWidget) m_flowCharPlotWidget->setLorenzCurve(timeStepDates, lorenzVals); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QWidget* RimFlowCharacteristicsPlot::createViewWidget(QWidget* mainWindowParent) +{ + m_flowCharPlotWidget = new RiuFlowCharacteristicsPlot(this, mainWindowParent); + return m_flowCharPlotWidget; +} + + diff --git a/ApplicationCode/ProjectDataModel/Flow/RimFlowCharacteristicsPlot.h b/ApplicationCode/ProjectDataModel/Flow/RimFlowCharacteristicsPlot.h new file mode 100644 index 0000000000..5eb58b0ead --- /dev/null +++ b/ApplicationCode/ProjectDataModel/Flow/RimFlowCharacteristicsPlot.h @@ -0,0 +1,82 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2017 Statoil 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 +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + + +#include "RimViewWindow.h" + +#include "cafPdmField.h" +#include "cafPdmObject.h" +#include "cafPdmPtrField.h" + +#include + +class RimFlowDiagSolution; +class RimEclipseResultCase; + +class RiuFlowCharacteristicsPlot; + +namespace caf { + class PdmOptionItemInfo; +} + +namespace cvf { + class Color3f; +} + + +//================================================================================================== +/// +/// +//================================================================================================== +class RimFlowCharacteristicsPlot : public RimViewWindow +{ + CAF_PDM_HEADER_INIT; + +public: + RimFlowCharacteristicsPlot(); + virtual ~RimFlowCharacteristicsPlot(); + + void setFromFlowSolution(RimFlowDiagSolution* flowSolution); + + // RimViewWindow overrides + + virtual QWidget* viewWidget() override; + virtual void zoomAll() override; + virtual QWidget* createViewWidget(QWidget* mainWindowParent) override; + virtual void deleteViewWidget() override; + + + +protected: + // RimViewWindow overrides + + virtual void loadDataAndUpdate() override; + virtual QImage snapshotWindowContent() override; + + // Overridden PDM methods + virtual void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) override; + virtual QList calculateValueOptions(const caf::PdmFieldHandle* fieldNeedingOptions, bool* useOptionsOnly) override; + +private: + caf::PdmPtrField m_case; + caf::PdmPtrField m_flowDiagSolution; + + QPointer m_flowCharPlotWidget; +}; diff --git a/ApplicationCode/ProjectDataModel/Flow/RimFlowPlotCollection.cpp b/ApplicationCode/ProjectDataModel/Flow/RimFlowPlotCollection.cpp index 1f29ada313..0f0cacda1e 100644 --- a/ApplicationCode/ProjectDataModel/Flow/RimFlowPlotCollection.cpp +++ b/ApplicationCode/ProjectDataModel/Flow/RimFlowPlotCollection.cpp @@ -19,6 +19,7 @@ #include "RimFlowPlotCollection.h" #include "RimWellAllocationPlot.h" +#include "RimFlowCharacteristicsPlot.h" #include "cvfAssert.h" @@ -33,6 +34,10 @@ RimFlowPlotCollection::RimFlowPlotCollection() { CAF_PDM_InitObject("Flow Diagnostics Plots", ":/WellAllocPlots16x16.png", "", ""); + CAF_PDM_InitFieldNoDefault(&m_flowCharacteristicsPlot, "FlowCharacteristicsPlot", "", "", "", ""); + m_flowCharacteristicsPlot.uiCapability()->setUiHidden(true); + m_flowCharacteristicsPlot = new RimFlowCharacteristicsPlot; + CAF_PDM_InitFieldNoDefault(&m_defaultPlot, "DefaultFlowPlot", "", "", "", ""); m_defaultPlot.uiCapability()->setUiHidden(true); diff --git a/ApplicationCode/ProjectDataModel/Flow/RimFlowPlotCollection.h b/ApplicationCode/ProjectDataModel/Flow/RimFlowPlotCollection.h index e48ab29229..0868fcddd0 100644 --- a/ApplicationCode/ProjectDataModel/Flow/RimFlowPlotCollection.h +++ b/ApplicationCode/ProjectDataModel/Flow/RimFlowPlotCollection.h @@ -23,6 +23,7 @@ #include "cafPdmChildField.h" class RimWellAllocationPlot; +class RimFlowCharacteristicsPlot; //================================================================================================== /// @@ -43,6 +44,7 @@ public: RimWellAllocationPlot* defaultPlot(); private: + caf::PdmChildField m_flowCharacteristicsPlot; caf::PdmChildField m_defaultPlot; caf::PdmChildArrayField m_flowPlots; }; diff --git a/ApplicationCode/ReservoirDataModel/RigFlowDiagResults.cpp b/ApplicationCode/ReservoirDataModel/RigFlowDiagResults.cpp index 7481e14b50..5db6725bd1 100644 --- a/ApplicationCode/ReservoirDataModel/RigFlowDiagResults.cpp +++ b/ApplicationCode/ReservoirDataModel/RigFlowDiagResults.cpp @@ -39,6 +39,7 @@ RigFlowDiagResults::RigFlowDiagResults(RimFlowDiagSolution* flowSolution, size_t m_timeStepCount = timeStepCount; m_hasAtemptedNativeResults.resize(timeStepCount, false); m_injProdPairFluxCommunicationTimesteps.resize(timeStepCount); + m_flowCharResultFrames.resize(timeStepCount); } //-------------------------------------------------------------------------------------------------- @@ -118,6 +119,12 @@ void RigFlowDiagResults::calculateNativeResultsIfNotPreviouslyAttempted(size_t f m_injProdPairFluxCommunicationTimesteps[frameIndex].swap(nativeTimestepResults.injProdWellPairFluxes()); + m_flowCharResultFrames[frameIndex].m_lorenzCoefficient = nativeTimestepResults.lorenzCoefficient(); + m_flowCharResultFrames[frameIndex].m_flowCapStorageCapCurve.first.swap(nativeTimestepResults.flowCapStorageCapCurve().first); + m_flowCharResultFrames[frameIndex].m_flowCapStorageCapCurve.second.swap(nativeTimestepResults.flowCapStorageCapCurve().second); + m_flowCharResultFrames[frameIndex].m_sweepEfficiencyCurve.first.swap(nativeTimestepResults.sweepEfficiencyCurve().first); + m_flowCharResultFrames[frameIndex].m_sweepEfficiencyCurve.second.swap(nativeTimestepResults.sweepEfficiencyCurve().second); + m_hasAtemptedNativeResults[frameIndex] = true; } } @@ -652,3 +659,17 @@ double RigFlowDiagResults::maxAbsPairFlux(int frameIndex) return maxFlux; } + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RigFlowDiagResults::calculatedTimeSteps() +{ + std::vector timestepIndices; + for (size_t tsIdx = 0; tsIdx < m_timeStepCount; ++tsIdx) + { + if (m_hasAtemptedNativeResults[tsIdx]) timestepIndices.push_back(static_cast(tsIdx)); + } + + return timestepIndices; +} diff --git a/ApplicationCode/ReservoirDataModel/RigFlowDiagResults.h b/ApplicationCode/ReservoirDataModel/RigFlowDiagResults.h index 25a3662935..236e0616a3 100644 --- a/ApplicationCode/ReservoirDataModel/RigFlowDiagResults.h +++ b/ApplicationCode/ReservoirDataModel/RigFlowDiagResults.h @@ -62,6 +62,21 @@ public: std::pair injectorProducerPairFluxes(const std::string& injTracername, const std::string& prodTracerName, int frameIndex); double maxAbsPairFlux(int frameIndex); + std::vector calculatedTimeSteps(); + + struct FlowCharacteristicsResultFrame + { + FlowCharacteristicsResultFrame() : m_lorenzCoefficient(HUGE_VAL) {} + + using Curve = std::pair< std::vector, std::vector >; + + Curve m_flowCapStorageCapCurve; + Curve m_sweepEfficiencyCurve; + double m_lorenzCoefficient; + }; + + const FlowCharacteristicsResultFrame& flowCharacteristicsResults(int frameIndex) { return m_flowCharResultFrames[frameIndex];} + private: const std::vector* findOrCalculateResult (const RigFlowDiagResultAddress& resVarAddr, size_t frameIndex); void calculateNativeResultsIfNotPreviouslyAttempted(size_t frameIndex); @@ -118,6 +133,10 @@ private: using InjectorProducerCommunicationMap = std::map< std::pair, std::pair >; std::vector m_injProdPairFluxCommunicationTimesteps; + + + std::vector m_flowCharResultFrames; + }; diff --git a/ApplicationCode/ReservoirDataModel/RigFlowDiagSolverInterface.cpp b/ApplicationCode/ReservoirDataModel/RigFlowDiagSolverInterface.cpp index fbe9812cf2..9fd5b6dfa1 100644 --- a/ApplicationCode/ReservoirDataModel/RigFlowDiagSolverInterface.cpp +++ b/ApplicationCode/ReservoirDataModel/RigFlowDiagSolverInterface.cpp @@ -39,7 +39,7 @@ /// //-------------------------------------------------------------------------------------------------- RigFlowDiagTimeStepResult::RigFlowDiagTimeStepResult(size_t activeCellCount) - : m_activeCellCount(activeCellCount) + : m_activeCellCount(activeCellCount), m_lorenzCoefficient(HUGE_VAL) { } @@ -107,12 +107,16 @@ void RigFlowDiagTimeStepResult::addResult(const RigFlowDiagResultAddress& resAdd class RigOpmFldStaticData : public cvf::Object { public: - RigOpmFldStaticData(const std::string& grid, const std::string& init) : eclGraph(Opm::ECLGraph::load(grid, init)), m_hasUnifiedRestartFile(false) {} + RigOpmFldStaticData(const std::string& grid, const std::string& init) : m_eclGraph(Opm::ECLGraph::load(grid, init)), m_hasUnifiedRestartFile(false) + { + m_poreVolume = m_eclGraph.poreVolume(); + } - Opm::ECLGraph eclGraph; - std::unique_ptr fldToolbox; - bool m_hasUnifiedRestartFile; - QStringList restartFileNames; + Opm::ECLGraph m_eclGraph; + std::vector m_poreVolume; + std::unique_ptr m_fldToolbox; + bool m_hasUnifiedRestartFile; + QStringList m_restartFileNames; }; @@ -168,31 +172,31 @@ RigFlowDiagTimeStepResult RigFlowDiagSolverInterface::calculate(size_t timeStepI progressInfo.setProgressDescription("Calculating Connectivities"); const Opm::FlowDiagnostics::ConnectivityGraph connGraph = - Opm::FlowDiagnostics::ConnectivityGraph{ static_cast(m_opmFldData->eclGraph.numCells()), - m_opmFldData->eclGraph.neighbours() }; + Opm::FlowDiagnostics::ConnectivityGraph{ static_cast(m_opmFldData->m_eclGraph.numCells()), + m_opmFldData->m_eclGraph.neighbours() }; progressInfo.incrementProgress(); progressInfo.setProgressDescription("Initialize Solver"); // Create the Toolbox. - m_opmFldData->fldToolbox.reset(new Opm::FlowDiagnostics::Toolbox{ connGraph }); - m_opmFldData->fldToolbox->assignPoreVolume( m_opmFldData->eclGraph.poreVolume()); + m_opmFldData->m_fldToolbox.reset(new Opm::FlowDiagnostics::Toolbox{ connGraph }); + m_opmFldData->m_fldToolbox->assignPoreVolume( m_opmFldData->m_poreVolume); // Look for unified restart file QString restartFileName = RifEclipseOutputFileTools::firstFileNameOfType(m_filesWithSameBaseName, ECL_UNIFIED_RESTART_FILE); if ( !restartFileName.isEmpty() ) { - m_opmFldData->eclGraph.assignFluxDataSource(restartFileName.toStdString()); + m_opmFldData->m_eclGraph.assignFluxDataSource(restartFileName.toStdString()); m_opmFldData->m_hasUnifiedRestartFile = true; } else { - m_opmFldData->restartFileNames = RifEclipseOutputFileTools::filterFileNamesOfType(m_filesWithSameBaseName, ECL_RESTART_FILE); + m_opmFldData->m_restartFileNames = RifEclipseOutputFileTools::filterFileNamesOfType(m_filesWithSameBaseName, ECL_RESTART_FILE); - size_t restartFileCount = static_cast(m_opmFldData->restartFileNames.size()); + size_t restartFileCount = static_cast(m_opmFldData->m_restartFileNames.size()); size_t maxTimeStepCount = m_eclipseCase->eclipseCaseData()->results(RifReaderInterface::MATRIX_RESULTS)->maxTimeStepCount(); if (restartFileCount <= timeStepIndex && restartFileCount != maxTimeStepCount ) @@ -201,7 +205,7 @@ RigFlowDiagTimeStepResult RigFlowDiagSolverInterface::calculate(size_t timeStepI return result; } - m_opmFldData->restartFileNames.sort(); // To make sure they are sorted in increasing *.X000N order. Hack. Should probably be actual time stored on file. + m_opmFldData->m_restartFileNames.sort(); // To make sure they are sorted in increasing *.X000N order. Hack. Should probably be actual time stored on file. m_opmFldData->m_hasUnifiedRestartFile = false; } } @@ -211,8 +215,8 @@ RigFlowDiagTimeStepResult RigFlowDiagSolverInterface::calculate(size_t timeStepI if ( ! m_opmFldData->m_hasUnifiedRestartFile ) { - QString restartFileName = m_opmFldData->restartFileNames[static_cast(timeStepIndex)]; - m_opmFldData->eclGraph.assignFluxDataSource(restartFileName.toStdString()); + QString restartFileName = m_opmFldData->m_restartFileNames[static_cast(timeStepIndex)]; + m_opmFldData->m_eclGraph.assignFluxDataSource(restartFileName.toStdString()); } size_t resultIndexWithMaxTimeSteps = cvf::UNDEFINED_SIZE_T; @@ -220,7 +224,7 @@ RigFlowDiagTimeStepResult RigFlowDiagSolverInterface::calculate(size_t timeStepI int reportStepNumber = m_eclipseCase->eclipseCaseData()->results(RifReaderInterface::MATRIX_RESULTS)->reportStepNumber(resultIndexWithMaxTimeSteps, timeStepIndex); - if ( ! m_opmFldData->eclGraph.selectReportStep(reportStepNumber) ) + if ( ! m_opmFldData->m_eclGraph.selectReportStep(reportStepNumber) ) { QMessageBox::critical(nullptr, "ResInsight", "Flow Diagnostics: Could not find the requested timestep in the result file. Results will not be loaded."); return result; @@ -231,20 +235,20 @@ RigFlowDiagTimeStepResult RigFlowDiagSolverInterface::calculate(size_t timeStepI Opm::FlowDiagnostics::CellSetValues sumWellFluxPrCell; { - Opm::FlowDiagnostics::ConnectionValues connectionsVals = RigFlowDiagInterfaceTools::extractFluxField(m_opmFldData->eclGraph, false); + Opm::FlowDiagnostics::ConnectionValues connectionsVals = RigFlowDiagInterfaceTools::extractFluxField(m_opmFldData->m_eclGraph, false); - m_opmFldData->fldToolbox->assignConnectionFlux(connectionsVals); + m_opmFldData->m_fldToolbox->assignConnectionFlux(connectionsVals); progressInfo.incrementProgress(); Opm::ECLWellSolution wsol = Opm::ECLWellSolution{-1.0 , false}; const std::vector well_fluxes = - wsol.solution(m_opmFldData->eclGraph.rawResultData(), m_opmFldData->eclGraph.numGrids()); + wsol.solution(m_opmFldData->m_eclGraph.rawResultData(), m_opmFldData->m_eclGraph.numGrids()); - sumWellFluxPrCell = RigFlowDiagInterfaceTools::extractWellFlows(m_opmFldData->eclGraph, well_fluxes); + sumWellFluxPrCell = RigFlowDiagInterfaceTools::extractWellFlows(m_opmFldData->m_eclGraph, well_fluxes); - m_opmFldData->fldToolbox->assignInflowFlux(sumWellFluxPrCell); + m_opmFldData->m_fldToolbox->assignInflowFlux(sumWellFluxPrCell); // Filter connection cells with inconsistent well in flow direction (Hack, we should do something better) @@ -295,7 +299,7 @@ RigFlowDiagTimeStepResult RigFlowDiagSolverInterface::calculate(size_t timeStepI std::unique_ptr injectorSolution; try { - injectorSolution.reset(new Toolbox::Forward( m_opmFldData->fldToolbox->computeInjectionDiagnostics(injectorCellSets))); + injectorSolution.reset(new Toolbox::Forward( m_opmFldData->m_fldToolbox->computeInjectionDiagnostics(injectorCellSets))); } catch (const std::exception& e) { @@ -325,7 +329,7 @@ RigFlowDiagTimeStepResult RigFlowDiagSolverInterface::calculate(size_t timeStepI std::unique_ptr producerSolution; try { - producerSolution.reset(new Toolbox::Reverse(m_opmFldData->fldToolbox->computeProductionDiagnostics(prodjCellSets))); + producerSolution.reset(new Toolbox::Reverse(m_opmFldData->m_fldToolbox->computeProductionDiagnostics(prodjCellSets))); } catch ( const std::exception& e ) { @@ -366,6 +370,21 @@ RigFlowDiagTimeStepResult RigFlowDiagSolverInterface::calculate(size_t timeStepI } } } + + try + { + Graph flowCapStorCapCurve = flowCapacityStorageCapacityCurve(*(injectorSolution.get()), + *(producerSolution.get()), + m_opmFldData->m_poreVolume); + + result.setFlowCapStorageCapCurve(flowCapStorCapCurve); + result.setSweepEfficiencyCurve(sweepEfficiency(flowCapStorCapCurve)); + result.setLorenzCoefficient(lorenzCoefficient(flowCapStorCapCurve)); + } + catch ( const std::exception& e ) + { + QMessageBox::critical(nullptr, "ResInsight", "Flow Diagnostics: " + QString(e.what())); + } } return result; // Relying on implicit move constructor diff --git a/ApplicationCode/ReservoirDataModel/RigFlowDiagSolverInterface.h b/ApplicationCode/ReservoirDataModel/RigFlowDiagSolverInterface.h index 8623e3575f..653d9e54d2 100644 --- a/ApplicationCode/ReservoirDataModel/RigFlowDiagSolverInterface.h +++ b/ApplicationCode/ReservoirDataModel/RigFlowDiagSolverInterface.h @@ -41,17 +41,30 @@ public: const std::string& producerTracerName, const std::pair& injProdFluxes) ; - // Use to "steal" the data from this one using swap - std::map >& nativeResults() { return m_nativeResults; } + using Curve = std::pair< std::vector, std::vector >; + void setFlowCapStorageCapCurve(const Curve& flCapStCapCurve) { m_flowCapStorageCapCurve = flCapStCapCurve;} + void setSweepEfficiencyCurve(const Curve& sweepEffCurve) { m_sweepEfficiencyCurve = sweepEffCurve; } + void setLorenzCoefficient(double coeff) { m_lorenzCoefficient = coeff;} + + // Used to "steal" the data from this one using swap + std::map >& nativeResults() { return m_nativeResults; } std::map, std::pair > & injProdWellPairFluxes() { return m_injProdWellPairFluxes; } + Curve& flowCapStorageCapCurve() { return m_flowCapStorageCapCurve; } + Curve& sweepEfficiencyCurve() { return m_sweepEfficiencyCurve; } + double lorenzCoefficient() { return m_lorenzCoefficient;} + private: void addResult(const RigFlowDiagResultAddress& resAddr, const std::map& cellValues); - std::map > m_nativeResults; + std::map > m_nativeResults; std::map, std::pair > m_injProdWellPairFluxes; + Curve m_flowCapStorageCapCurve; + Curve m_sweepEfficiencyCurve; + double m_lorenzCoefficient; + size_t m_activeCellCount; }; diff --git a/ApplicationCode/UserInterface/CMakeLists_files.cmake b/ApplicationCode/UserInterface/CMakeLists_files.cmake index 1579fb480b..501cb99546 100644 --- a/ApplicationCode/UserInterface/CMakeLists_files.cmake +++ b/ApplicationCode/UserInterface/CMakeLists_files.cmake @@ -39,6 +39,7 @@ ${CEE_CURRENT_LIST_DIR}RiuGeoMechXfTensorResultAccessor.h ${CEE_CURRENT_LIST_DIR}RiuFemTimeHistoryResultAccessor.h ${CEE_CURRENT_LIST_DIR}RiuExportMultipleSnapshotsWidget.h ${CEE_CURRENT_LIST_DIR}RiuWellAllocationPlot.h +${CEE_CURRENT_LIST_DIR}RiuFlowCharacteristicsPlot.h ${CEE_CURRENT_LIST_DIR}RiuNightchartsWidget.h ${CEE_CURRENT_LIST_DIR}RiuMessagePanel.h ) @@ -78,6 +79,7 @@ ${CEE_CURRENT_LIST_DIR}RiuGeoMechXfTensorResultAccessor.cpp ${CEE_CURRENT_LIST_DIR}RiuFemTimeHistoryResultAccessor.cpp ${CEE_CURRENT_LIST_DIR}RiuExportMultipleSnapshotsWidget.cpp ${CEE_CURRENT_LIST_DIR}RiuWellAllocationPlot.cpp +${CEE_CURRENT_LIST_DIR}RiuFlowCharacteristicsPlot.cpp ${CEE_CURRENT_LIST_DIR}RiuNightchartsWidget.cpp ${CEE_CURRENT_LIST_DIR}RiuMessagePanel.cpp ) @@ -107,6 +109,7 @@ ${CEE_CURRENT_LIST_DIR}RiuSummaryQwtPlot.h ${CEE_CURRENT_LIST_DIR}RiuQwtScalePicker.h ${CEE_CURRENT_LIST_DIR}RiuExportMultipleSnapshotsWidget.h ${CEE_CURRENT_LIST_DIR}RiuWellAllocationPlot.h +${CEE_CURRENT_LIST_DIR}RiuFlowCharacteristicsPlot.h ${CEE_CURRENT_LIST_DIR}RiuNightchartsWidget.h ${CEE_CURRENT_LIST_DIR}RiuMessagePanel.h ) diff --git a/ApplicationCode/UserInterface/RiuFlowCharacteristicsPlot.cpp b/ApplicationCode/UserInterface/RiuFlowCharacteristicsPlot.cpp new file mode 100644 index 0000000000..ac8a0d2107 --- /dev/null +++ b/ApplicationCode/UserInterface/RiuFlowCharacteristicsPlot.cpp @@ -0,0 +1,154 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2017 Statoil 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 +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RiuFlowCharacteristicsPlot.h" +#include "RimFlowCharacteristicsPlot.h" +#include "RiuResultQwtPlot.h" + +#include "qwt_plot.h" +#include "cvfBase.h" +#include "cvfColor3.h" + +#include +#include +#include +#include +#include "RiuLineSegmentQwtPlotCurve.h" +#include + + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RiuFlowCharacteristicsPlot::RiuFlowCharacteristicsPlot(RimFlowCharacteristicsPlot* plotDefinition, QWidget* parent) + : m_plotDefinition(plotDefinition), + QFrame(parent) +{ + Q_ASSERT(m_plotDefinition); + + QVBoxLayout* mainLayout = new QVBoxLayout(); + this->setLayout(mainLayout); + this->layout()->setMargin(0); + this->layout()->setSpacing(2); + + // White background + QPalette pal = this->palette(); + pal.setColor(QPalette::Background, Qt::white); + this->setAutoFillBackground(true); + this->setPalette(pal); + + m_lorenzPlot = new RiuResultQwtPlot(this); + m_flowCapVsStorageCapPlot = new RiuResultQwtPlot(this); + m_sweepEffPlot = new RiuResultQwtPlot(this); + mainLayout->addWidget(m_lorenzPlot); + mainLayout->addWidget(m_flowCapVsStorageCapPlot); + mainLayout->addWidget(m_sweepEffPlot); + +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RiuFlowCharacteristicsPlot::~RiuFlowCharacteristicsPlot() +{ + if (m_plotDefinition) + { + m_plotDefinition->handleMdiWindowClosed(); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuFlowCharacteristicsPlot::setLorenzCurve(const std::vector& dateTimes, const std::vector& timeHistoryValues) +{ + m_lorenzPlot->deleteAllCurves(); + m_lorenzPlot->addCurve("Lorenz Coefficient", cvf::Color3f::BLUE, dateTimes, timeHistoryValues); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuFlowCharacteristicsPlot::addFlowCapStorageCapCurve(const QDateTime& dateTime, const std::vector& xVals, const std::vector& yVals) +{ + RiuLineSegmentQwtPlotCurve* plotCurve = new RiuLineSegmentQwtPlotCurve(dateTime.toString()); + plotCurve->setSamplesFromTimeAndValues(xVals, yVals, false); + plotCurve->setTitle(dateTime.toString()); + + plotCurve->setPen(QPen(QColor(180, 0, 20))); + + plotCurve->attach(m_flowCapVsStorageCapPlot); + + m_flowCapVsStorageCapPlot->setAxisScale( QwtPlot::xBottom, 0.0, 1.0); + + m_flowCapVsStorageCapPlot->replot(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuFlowCharacteristicsPlot::addSweepEfficiencyCurve(const QDateTime& dateTime, const std::vector& xVals, const std::vector& yVals) +{ + RiuLineSegmentQwtPlotCurve* plotCurve = new RiuLineSegmentQwtPlotCurve(dateTime.toString()); + plotCurve->setSamplesFromTimeAndValues(xVals, yVals, false); + plotCurve->setTitle(dateTime.toString()); + + plotCurve->setPen(QPen(QColor(180, 0, 20))); + + plotCurve->attach(m_sweepEffPlot); + + //m_sweepEffPlot->setAxisScale( QwtPlot::xBottom, 0.0, 1.0); + + m_sweepEffPlot->replot(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimFlowCharacteristicsPlot* RiuFlowCharacteristicsPlot::ownerPlotDefinition() +{ + return m_plotDefinition; +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QSize RiuFlowCharacteristicsPlot::minimumSizeHint() const +{ + return QSize(0, 100); +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QSize RiuFlowCharacteristicsPlot::sizeHint() const +{ + return QSize(0, 0); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuFlowCharacteristicsPlot::setDefaults() +{ + +} + diff --git a/ApplicationCode/UserInterface/RiuFlowCharacteristicsPlot.h b/ApplicationCode/UserInterface/RiuFlowCharacteristicsPlot.h new file mode 100644 index 0000000000..6de6647d1f --- /dev/null +++ b/ApplicationCode/UserInterface/RiuFlowCharacteristicsPlot.h @@ -0,0 +1,70 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2017 Statoil 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 +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "qwt_plot.h" + +#include "cafPdmPointer.h" + +#include +#include + +class RimFlowCharacteristicsPlot; +class RiuNightchartsWidget; +class RiuResultQwtPlot; + +class QLabel; + +namespace cvf { + class Color3f; +} + +//================================================================================================== +// +// +// +//================================================================================================== +class RiuFlowCharacteristicsPlot : public QFrame +{ + Q_OBJECT; +public: + RiuFlowCharacteristicsPlot(RimFlowCharacteristicsPlot* plotDefinition, QWidget* parent = NULL); + virtual ~RiuFlowCharacteristicsPlot(); + + void setLorenzCurve(const std::vector& dateTimes, const std::vector& timeHistoryValues); + void addFlowCapStorageCapCurve(const QDateTime& dateTime, const std::vector& xVals, const std::vector& yVals); + void addSweepEfficiencyCurve(const QDateTime& dateTime, const std::vector& xVals, const std::vector& yVals); + + RimFlowCharacteristicsPlot* ownerPlotDefinition(); + +protected: + virtual QSize sizeHint() const override; + virtual QSize minimumSizeHint() const override; + +private: + void setDefaults(); + +private: + caf::PdmPointer m_plotDefinition; + QPointer m_lorenzPlot; + QPointer m_flowCapVsStorageCapPlot; + QPointer m_sweepEffPlot; + +}; + diff --git a/ApplicationCode/UserInterface/RiuSummaryQwtPlot.h b/ApplicationCode/UserInterface/RiuSummaryQwtPlot.h index d6a9058195..7ccde7dbef 100644 --- a/ApplicationCode/UserInterface/RiuSummaryQwtPlot.h +++ b/ApplicationCode/UserInterface/RiuSummaryQwtPlot.h @@ -63,7 +63,8 @@ protected: virtual QSize sizeHint() const override; virtual QSize minimumSizeHint() const override; - virtual void contextMenuEvent(QContextMenuEvent *) override; + virtual void contextMenuEvent(QContextMenuEvent *) override; + private: friend class RiuQwtPlotPicker; QPointF closestCurvePoint(const QPoint& pos, QString* valueString, QString* timeString, int* yAxis) const;