///////////////////////////////////////////////////////////////////////////////// // // Copyright (C) 2016- 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 "RimFlowDiagSolution.h" #include "RiaApplication.h" #include "RiaColorTables.h" #include "RigActiveCellInfo.h" #include "RigCaseCellResultsData.h" #include "RigEclipseCaseData.h" #include "RigFlowDiagResults.h" #include "RigMainGrid.h" #include "RigSingleWellResultsData.h" #include "RimEclipseResultCase.h" #include "RimEclipseView.h" #include "RimEclipseWell.h" #include "RimEclipseWellCollection.h" CAF_PDM_SOURCE_INIT(RimFlowDiagSolution, "FlowDiagSolution"); #define CROSS_FLOW_ENDING "-XF" //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- bool RimFlowDiagSolution::hasCrossFlowEnding(const QString& tracerName) { return tracerName.endsWith(CROSS_FLOW_ENDING); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- QString RimFlowDiagSolution::removeCrossFlowEnding(const QString& tracerName) { if (tracerName.endsWith(CROSS_FLOW_ENDING)) { return tracerName.left(tracerName.size() - 3); } else { return tracerName; } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- QString RimFlowDiagSolution::addCrossFlowEnding(const QString& wellName) { return wellName + CROSS_FLOW_ENDING; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RimFlowDiagSolution::RimFlowDiagSolution(void) { CAF_PDM_InitObject("Flow Diagnostics Solution", "", "", ""); CAF_PDM_InitField(&m_userDescription, "UserDescription", QString("All Wells") ,"Description", "", "",""); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RimFlowDiagSolution::~RimFlowDiagSolution(void) { } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- QString RimFlowDiagSolution::userDescription() const { return m_userDescription(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RigFlowDiagResults* RimFlowDiagSolution::flowDiagResults() { if ( m_flowDiagResults.isNull() ) { size_t timeStepCount; { RimEclipseResultCase* eclCase; this->firstAncestorOrThisOfType(eclCase); CVF_ASSERT(eclCase && eclCase->eclipseCaseData() ); timeStepCount = eclCase->eclipseCaseData()->results(RiaDefines::MATRIX_MODEL)->maxTimeStepCount(); } m_flowDiagResults = new RigFlowDiagResults(this, timeStepCount); } return m_flowDiagResults.p(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- std::vector RimFlowDiagSolution::tracerNames() const { RimEclipseResultCase* eclCase; this->firstAncestorOrThisOfType(eclCase); std::vector tracerNameSet; if (eclCase) { const cvf::Collection& wellResults = eclCase->eclipseCaseData()->wellResults(); for (size_t wIdx = 0; wIdx < wellResults.size(); ++wIdx) { tracerNameSet.push_back(wellResults[wIdx]->m_wellName); tracerNameSet.push_back(addCrossFlowEnding(wellResults[wIdx]->m_wellName)); } } return tracerNameSet; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- std::map > RimFlowDiagSolution::allInjectorTracerActiveCellIndices(size_t timeStepIndex) const { return allTracerActiveCellIndices(timeStepIndex, true); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- std::map > RimFlowDiagSolution::allProducerTracerActiveCellIndices(size_t timeStepIndex) const { return allTracerActiveCellIndices(timeStepIndex, false); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- std::map > RimFlowDiagSolution::allTracerActiveCellIndices(size_t timeStepIndex, bool useInjectors) const { RimEclipseResultCase* eclCase; this->firstAncestorOrThisOfType(eclCase); std::map > tracersWithCells; if ( eclCase ) { const cvf::Collection& wellResults = eclCase->eclipseCaseData()->wellResults(); RigMainGrid* mainGrid = eclCase->eclipseCaseData()->mainGrid(); RigActiveCellInfo* activeCellInfo = eclCase->eclipseCaseData()->activeCellInfo(RiaDefines::MATRIX_MODEL); //Todo: Must come from the results definition for ( size_t wIdx = 0; wIdx < wellResults.size(); ++wIdx ) { if (!wellResults[wIdx]->hasWellResult(timeStepIndex) ) continue; const RigWellResultFrame& wellResFrame = wellResults[wIdx]->wellResultFrame(timeStepIndex); bool isInjectorWell = ( wellResFrame.m_productionType != RigWellResultFrame::PRODUCER && wellResFrame.m_productionType != RigWellResultFrame::UNDEFINED_PRODUCTION_TYPE); std::string wellName = wellResults[wIdx]->m_wellName.toStdString(); std::string wellNameXf = addCrossFlowEnding(wellResults[wIdx]->m_wellName).toStdString(); std::vector& tracerCells = tracersWithCells[wellName]; std::vector& tracerCellsCrossFlow = tracersWithCells[wellNameXf]; for (const RigWellResultBranch& wBr: wellResFrame.m_wellResultBranches) { for (const RigWellResultPoint& wrp: wBr.m_branchResultPoints) { if (wrp.isValid() && wrp.m_isOpen && ( (useInjectors && wrp.flowRate() < 0.0) || (!useInjectors && wrp.flowRate() > 0.0) ) ) { RigGridBase * grid = mainGrid->gridByIndex(wrp.m_gridIndex); size_t reservoirCellIndex = grid->reservoirCellIndex(wrp.m_gridCellIndex); int cellActiveIndex = static_cast(activeCellInfo->cellResultIndex(reservoirCellIndex)); if ( useInjectors == isInjectorWell ) { tracerCells.push_back(cellActiveIndex); } else { tracerCellsCrossFlow.push_back(cellActiveIndex); } } } } if (tracerCells.empty()) tracersWithCells.erase(wellName); if (tracerCellsCrossFlow.empty()) tracersWithCells.erase(wellNameXf); } } return tracersWithCells; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RimFlowDiagSolution::TracerStatusType RimFlowDiagSolution::tracerStatusOverall(const QString& tracerName) const { RimEclipseResultCase* eclCase; this->firstAncestorOrThisOfTypeAsserted(eclCase); TracerStatusType tracerStatus = UNDEFINED; const cvf::Collection& wellResults = eclCase->eclipseCaseData()->wellResults(); for ( size_t wIdx = 0; wIdx < wellResults.size(); ++wIdx ) { QString wellName = removeCrossFlowEnding(tracerName); if ( wellResults[wIdx]->m_wellName != wellName ) continue; tracerStatus = CLOSED; for ( const RigWellResultFrame& wellResFrame : wellResults[wIdx]->m_wellCellsTimeSteps ) { if ( wellResFrame.m_productionType == RigWellResultFrame::GAS_INJECTOR || wellResFrame.m_productionType == RigWellResultFrame::OIL_INJECTOR || wellResFrame.m_productionType == RigWellResultFrame::WATER_INJECTOR ) { if ( tracerStatus == PRODUCER ) tracerStatus = VARYING; else tracerStatus = INJECTOR; } else if ( wellResFrame.m_productionType == RigWellResultFrame::PRODUCER ) { if ( tracerStatus == INJECTOR ) tracerStatus = VARYING; else tracerStatus = PRODUCER; } if ( tracerStatus == VARYING ) break; } break; } if (hasCrossFlowEnding(tracerName)) { if (tracerStatus == PRODUCER) tracerStatus = INJECTOR; else if (tracerStatus == INJECTOR) tracerStatus = PRODUCER; } return tracerStatus; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RimFlowDiagSolution::TracerStatusType RimFlowDiagSolution::tracerStatusInTimeStep(const QString& tracerName, size_t timeStepIndex) const { RimEclipseResultCase* eclCase; this->firstAncestorOrThisOfTypeAsserted(eclCase); const cvf::Collection& wellResults = eclCase->eclipseCaseData()->wellResults(); for ( size_t wIdx = 0; wIdx < wellResults.size(); ++wIdx ) { QString wellName = removeCrossFlowEnding(tracerName); if ( wellResults[wIdx]->m_wellName != wellName ) continue; if (!wellResults[wIdx]->hasWellResult(timeStepIndex)) return CLOSED; const RigWellResultFrame& wellResFrame = wellResults[wIdx]->wellResultFrame(timeStepIndex); if ( wellResFrame.m_productionType == RigWellResultFrame::GAS_INJECTOR || wellResFrame.m_productionType == RigWellResultFrame::OIL_INJECTOR || wellResFrame.m_productionType == RigWellResultFrame::WATER_INJECTOR ) { if ( hasCrossFlowEnding(tracerName) ) return PRODUCER; return INJECTOR; } else if ( wellResFrame.m_productionType == RigWellResultFrame::PRODUCER || wellResFrame.m_productionType == RigWellResultFrame::UNDEFINED_PRODUCTION_TYPE ) { if ( hasCrossFlowEnding(tracerName) ) return INJECTOR; return PRODUCER; } else { CVF_ASSERT(false); } } CVF_ASSERT(false); return UNDEFINED; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- cvf::Color3f RimFlowDiagSolution::tracerColor(const QString& tracerName) const { QString wellName = removeCrossFlowEnding(tracerName); if (wellName == RIG_FLOW_TOTAL_NAME) return cvf::Color3f::LIGHT_GRAY; if (wellName == RIG_RESERVOIR_TRACER_NAME) return cvf::Color3f::LIGHT_GRAY; if (wellName == RIG_TINY_TRACER_GROUP_NAME) return cvf::Color3f::DARK_GRAY; RimEclipseResultCase* eclCase; this->firstAncestorOrThisOfType(eclCase); if ( eclCase ) { return eclCase->defaultWellColor(wellName); } return cvf::Color3f::LIGHT_GRAY; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- caf::PdmFieldHandle* RimFlowDiagSolution::userDescriptionField() { return &m_userDescription; }