///////////////////////////////////////////////////////////////////////////////// // // 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 "RimWellPltPlot.h" #include "RiaApplication.h" #include "RiaColorTables.h" #include "RiaDateStringParser.h" #include "RiaWellNameComparer.h" #include "RifReaderEclipseRft.h" #include "RigAccWellFlowCalculator.h" #include "RigCaseCellResultsData.h" #include "RigEclipseCaseData.h" #include "RigEclipseWellLogExtractor.h" #include "RigMainGrid.h" #include "RigSimWellData.h" #include "RigWellLogExtractor.h" #include "RigWellPath.h" #include "RimEclipseCase.h" #include "RimEclipseCaseCollection.h" #include "RimEclipseResultCase.h" #include "RimEclipseResultDefinition.h" #include "RimMainPlotCollection.h" #include "RimOilField.h" #include "RimProject.h" #include "RimSummaryCurveAppearanceCalculator.h" #include "RimTools.h" #include "RimWellFlowRateCurve.h" #include "RimWellLogExtractionCurve.h" #include "RimWellLogFile.h" #include "RimWellLogFileChannel.h" #include "RimWellLogFileCurve.h" #include "RimWellLogPlot.h" #include "RimWellLogPlotCollection.h" #include "RimWellLogRftCurve.h" #include "RimWellLogTrack.h" #include "RimWellPath.h" #include "RimWellPathCollection.h" #include "RimWellPlotTools.h" #include "RiuWellPltPlot.h" #include "cafPdmUiTreeOrdering.h" #include "cafPdmUiTreeSelectionEditor.h" #include "cafVecIjk.h" #include #include #include #include "QMessageBox" CAF_PDM_SOURCE_INIT(RimWellPltPlot, "WellPltPlot"); namespace caf { template<> void caf::AppEnum< FlowType>::setUp() { addItem(FLOW_TYPE_TOTAL, "TOTAL", "Total Flow"); addItem(FLOW_TYPE_PHASE_SPLIT, "PHASE_SPLIT", "Phase Split"); } template<> void caf::AppEnum< FlowPhase>::setUp() { addItem(FLOW_PHASE_OIL, "PHASE_OIL", "Oil"); addItem(FLOW_PHASE_GAS, "PHASE_GAS", "Gas"); addItem(FLOW_PHASE_WATER, "PHASE_WATER", "Water"); } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- const char RimWellPltPlot::PLOT_NAME_QFORMAT_STRING[] = "PLT: %1"; //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RimWellPltPlot::RimWellPltPlot() { CAF_PDM_InitObject("Well Allocation Plot", ":/WellAllocPlot16x16.png", "", ""); CAF_PDM_InitField(&m_userName, "PlotDescription", QString("PLT Plot"), "Name", "", "", ""); m_userName.uiCapability()->setUiReadOnly(true); CAF_PDM_InitField(&m_showPlotTitle, "ShowPlotTitle", true, "Show Plot Title", "", "", ""); CAF_PDM_InitFieldNoDefault(&m_wellLogPlot, "WellLog", "WellLog", "", "", ""); m_wellLogPlot.uiCapability()->setUiHidden(true); m_wellLogPlot = new RimWellLogPlot(); m_wellLogPlot->setDepthType(RimWellLogPlot::MEASURED_DEPTH); CAF_PDM_InitFieldNoDefault(&m_wellPathName, "WellName", "WellName", "", "", ""); CAF_PDM_InitFieldNoDefault(&m_selectedSources, "SourcesInternal", "SourcesInternal", "", "", ""); m_selectedSources.uiCapability()->setUiEditorTypeName(caf::PdmUiTreeSelectionEditor::uiEditorTypeName()); m_selectedSources.uiCapability()->setUiLabelPosition(caf::PdmUiItemInfo::HIDDEN); m_selectedSources.uiCapability()->setAutoAddingOptionFromValue(false); m_selectedSources.xmlCapability()->disableIO(); CAF_PDM_InitFieldNoDefault(&m_selectedSourcesForIo, "Sources", "Sources", "", "", ""); m_selectedSourcesForIo.uiCapability()->setUiHidden(true); CAF_PDM_InitFieldNoDefault(&m_selectedTimeSteps, "TimeSteps", "TimeSteps", "", "", ""); m_selectedTimeSteps.uiCapability()->setUiEditorTypeName(caf::PdmUiTreeSelectionEditor::uiEditorTypeName()); m_selectedTimeSteps.uiCapability()->setUiLabelPosition(caf::PdmUiItemInfo::HIDDEN); m_selectedTimeSteps.uiCapability()->setAutoAddingOptionFromValue(false); CAF_PDM_InitFieldNoDefault(&m_phaseSelectionMode, "PhaseSelectionMode", "Mode", "", "", ""); CAF_PDM_InitFieldNoDefault(&m_phases, "Phases", "Phases", "", "", ""); m_phases.uiCapability()->setUiEditorTypeName(caf::PdmUiTreeSelectionEditor::uiEditorTypeName()); m_phases = std::vector>({ FLOW_PHASE_OIL, FLOW_PHASE_GAS, FLOW_PHASE_WATER }); this->setAsPlotMdiWindow(); m_doInitAfterLoad = false; m_isOnLoad = true; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RimWellPltPlot::~RimWellPltPlot() { removeMdiWindowFromMdiArea(); deleteViewWidget(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimWellPltPlot::deleteViewWidget() { if (m_wellLogPlotWidget) { m_wellLogPlotWidget->deleteLater(); m_wellLogPlotWidget = nullptr; } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimWellPltPlot::setPlotXAxisTitles(RimWellLogTrack* plotTrack) { std::set< RiaEclipseUnitTools::UnitSystem> presentUnitSystems; for (const RifDataSourceForRftPlt& source : m_selectedSources.v()) { if (source.eclCase()) presentUnitSystems.insert(source.eclCase()->eclipseCaseData()->unitsType()); if (source.wellLogFile()) { if (source.wellLogFile()->wellLogFileData()) { // Todo: Handle different units in the relevant las channels switch (source.wellLogFile()->wellLogFileData()->depthUnit()) { case RiaDefines::UNIT_METER: presentUnitSystems.insert(RiaEclipseUnitTools::UNITS_METRIC); case RiaDefines::UNIT_FEET: presentUnitSystems.insert(RiaEclipseUnitTools::UNITS_FIELD); case RiaDefines::UNIT_NONE: presentUnitSystems.insert(RiaEclipseUnitTools::UNITS_UNKNOWN); } } } } if (presentUnitSystems.size() > 1) { QMessageBox::warning(nullptr, "ResInsight PLT Plot", "Inconsistent units in PLT plot");} QString unitText; for ( auto unitSet: presentUnitSystems ) { switch ( unitSet ) { case RiaEclipseUnitTools::UNITS_METRIC: unitText += "[Liquid Sm3/day], [Gas kSm3/day]"; break; case RiaEclipseUnitTools::UNITS_FIELD: unitText += "[Liquid BBL/day], [Gas BOE/day]"; break; case RiaEclipseUnitTools::UNITS_LAB: unitText += "[cm3/hr]"; break; default: unitText += "(unknown unit)"; break; } } plotTrack->setXAxisTitle("Surface Flow Rate " + unitText); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimWellPltPlot::updateFormationsOnPlot() const { if (m_wellLogPlot->trackCount() > 0) { RimProject* proj = RiaApplication::instance()->project(); RimWellPath* wellPath = proj->wellPathByName(m_wellPathName); RimCase* formationNamesCase = m_wellLogPlot->trackByIndex(0)->formationNamesCase(); if ( !formationNamesCase ) { /// Set default case. Todo : Use the first of the selected cases in the plot std::vector cases; proj->allCases(cases); if ( !cases.empty() ) { formationNamesCase = cases[0]; } } m_wellLogPlot->trackByIndex(0)->setAndUpdateWellPathFormationNamesData(formationNamesCase, wellPath); } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimWellPltPlot::updateWidgetTitleWindowTitle() { updateMdiWindowTitle(); if (m_wellLogPlotWidget) { if (m_showPlotTitle) { m_wellLogPlotWidget->showTitle(m_userName); } else { m_wellLogPlotWidget->hideTitle(); } } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- std::set < std::pair> RimWellPltPlot::selectedCurveDefs() const { std::set> curveDefs; const QString simWellName = RimWellPlotTools::simWellName(m_wellPathName); std::set selectedTimeSteps(m_selectedTimeSteps.v().begin(), m_selectedTimeSteps.v().end()); for ( const RifDataSourceForRftPlt& addr : selectedSourcesExpanded() ) { if ( addr.rftReader() ) { std::set rftTimes = addr.rftReader()->availableTimeSteps(simWellName, { RifEclipseRftAddress::ORAT, RifEclipseRftAddress::WRAT, RifEclipseRftAddress::GRAT }); for ( const QDateTime& time : rftTimes ) { if ( selectedTimeSteps.count(time) ) { curveDefs.insert(std::make_pair(addr, time)); } } } else if ( addr.sourceType() == RifDataSourceForRftPlt::GRID && addr.eclCase() ) { std::set timeSteps = RimWellPlotTools::availableSimWellTimesteps(addr.eclCase(), simWellName); for ( const QDateTime& time : timeSteps ) { if ( selectedTimeSteps.count(time) ) { curveDefs.insert(std::make_pair(addr, time)); } } } else if ( addr.sourceType() == RifDataSourceForRftPlt::OBSERVED ) { if ( addr.wellLogFile() ) { if ( selectedTimeSteps.count(addr.wellLogFile()->date()) ) { curveDefs.insert(std::make_pair(addr, addr.wellLogFile()->date())); } } } } return curveDefs; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- class RigResultPointCalculator { public: RigResultPointCalculator() {} virtual ~RigResultPointCalculator() {} const std::vector & pipeBranchCLCoords() { return m_pipeBranchCLCoords; } const std::vector & pipeBranchWellResultPoints() { return m_pipeBranchWellResultPoints; } const std::vector & pipeBranchMeasuredDepths() { return m_pipeBranchMeasuredDepths; } protected: RigEclipseWellLogExtractor* findWellLogExtractor(const QString& wellPathName, RimEclipseResultCase* eclCase) { RimProject* proj = RiaApplication::instance()->project(); RimWellPath* wellPath = proj->wellPathByName(wellPathName); RimWellLogPlotCollection* wellLogCollection = proj->mainPlotCollection()->wellLogPlotCollection(); RigEclipseWellLogExtractor* eclExtractor = wellLogCollection->findOrCreateExtractor(wellPath, eclCase); return eclExtractor; } std::vector m_pipeBranchCLCoords; std::vector m_pipeBranchWellResultPoints; std::vector m_pipeBranchMeasuredDepths; }; //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- class RigRftResultPointCalculator : public RigResultPointCalculator { public: RigRftResultPointCalculator(const QString& wellPathName, RimEclipseResultCase* eclCase, QDateTime m_timeStep) { RifEclipseRftAddress gasRateAddress(RimWellPlotTools::simWellName(wellPathName), m_timeStep, RifEclipseRftAddress::GRAT); RifEclipseRftAddress oilRateAddress(RimWellPlotTools::simWellName(wellPathName), m_timeStep, RifEclipseRftAddress::ORAT); RifEclipseRftAddress watRateAddress(RimWellPlotTools::simWellName(wellPathName), m_timeStep, RifEclipseRftAddress::WRAT); std::vector rftIndices; eclCase->rftReader()->cellIndices(gasRateAddress, &rftIndices); if (rftIndices.empty()) eclCase->rftReader()->cellIndices(oilRateAddress, &rftIndices); if (rftIndices.empty()) eclCase->rftReader()->cellIndices(watRateAddress, &rftIndices); if (rftIndices.empty()) return; std::vector gasRates; std::vector oilRates; std::vector watRates; eclCase->rftReader()->values(gasRateAddress, &gasRates); eclCase->rftReader()->values(oilRateAddress, &oilRates); eclCase->rftReader()->values(watRateAddress, &watRates); std::map globCellIdxToIdxInRftFile; const RigMainGrid* mainGrid = eclCase->eclipseCaseData()->mainGrid(); for (size_t rftCellIdx = 0; rftCellIdx < rftIndices.size(); rftCellIdx++) { caf::VecIjk ijkIndex = rftIndices[rftCellIdx]; size_t globalCellIndex = mainGrid->cellIndexFromIJK(ijkIndex.i(), ijkIndex.j(), ijkIndex.k()); globCellIdxToIdxInRftFile[globalCellIndex] = rftCellIdx; } RigEclipseWellLogExtractor* eclExtractor = findWellLogExtractor(wellPathName, eclCase); if (!eclExtractor) return; std::vector intersections = eclExtractor->intersectionInfo(); for (size_t wpExIdx = 0; wpExIdx < intersections.size(); wpExIdx++) { size_t globCellIdx = intersections[wpExIdx].globCellIndex; auto it = globCellIdxToIdxInRftFile.find(globCellIdx); if (it == globCellIdxToIdxInRftFile.end()) { if (wpExIdx == (intersections.size() - 1)) { m_pipeBranchWellResultPoints.pop_back(); } continue; } m_pipeBranchCLCoords.push_back(intersections[wpExIdx].startPoint); m_pipeBranchMeasuredDepths.push_back(intersections[wpExIdx].startMD); m_pipeBranchCLCoords.push_back(intersections[wpExIdx].endPoint); m_pipeBranchMeasuredDepths.push_back(intersections[wpExIdx].endMD); RigWellResultPoint resPoint; resPoint.m_isOpen = true; resPoint.m_gridIndex = 0; // Always main grid resPoint.m_gridCellIndex = globCellIdx; // Shortcut, since we only have main grid results from RFT resPoint.m_gasRate = RiaEclipseUnitTools::convertSurfaceGasFlowRateToOilEquivalents(eclCase->eclipseCaseData()->unitsType(), gasRates[it->second]); resPoint.m_oilRate = oilRates[it->second]; resPoint.m_waterRate = watRates[it->second]; m_pipeBranchWellResultPoints.push_back(resPoint); if ( wpExIdx < intersections.size() - 1 ) { m_pipeBranchWellResultPoints.push_back(RigWellResultPoint()); // Invalid res point describing the "line" between the cells } } } }; //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- class RigSimWellResultPointCalculator: public RigResultPointCalculator { public: RigSimWellResultPointCalculator(const QString& wellPathName, RimEclipseResultCase* eclCase, QDateTime m_timeStep) { // Find timestep index from qdatetime const std::vector timeSteps = eclCase->eclipseCaseData()->results(RiaDefines::MATRIX_MODEL)->timeStepDates(); size_t tsIdx = timeSteps.size(); for ( tsIdx = 0; tsIdx < timeSteps.size(); ++tsIdx) { if (timeSteps[tsIdx] == m_timeStep) break; } if (tsIdx >= timeSteps.size()) return; // Build search map into simulation well data std::map > globCellIdxToIdxInSimWellBranch; const RimWellPath* wellPath = RimWellPlotTools::wellPathByWellPathNameOrSimWellName(wellPathName); const RigSimWellData* simWell = wellPath != nullptr ? eclCase->eclipseCaseData()->findSimWellData(wellPath->associatedSimulationWell()) : nullptr; if (!simWell) return; if (!simWell->hasWellResult(tsIdx)) return; const RigWellResultFrame & resFrame = simWell->wellResultFrame(tsIdx); const RigMainGrid* mainGrid = eclCase->eclipseCaseData()->mainGrid(); for (size_t brIdx = 0; brIdx < resFrame.m_wellResultBranches.size(); ++brIdx) { const std::vector& branchResPoints = resFrame.m_wellResultBranches[brIdx].m_branchResultPoints; for ( size_t wrpIdx = 0; wrpIdx < branchResPoints.size(); wrpIdx++ ) { const RigGridBase* grid = mainGrid->gridByIndex(branchResPoints[wrpIdx].m_gridIndex); size_t globalCellIndex = grid->reservoirCellIndex(branchResPoints[wrpIdx].m_gridCellIndex); globCellIdxToIdxInSimWellBranch[globalCellIndex] = std::make_pair(brIdx, wrpIdx); } } RigEclipseWellLogExtractor* eclExtractor = findWellLogExtractor(wellPathName, eclCase); if (!eclExtractor) return; std::vector intersections = eclExtractor->intersectionInfo(); for (size_t wpExIdx = 0; wpExIdx < intersections.size(); wpExIdx++) { size_t globCellIdx = intersections[wpExIdx].globCellIndex; auto it = globCellIdxToIdxInSimWellBranch.find(globCellIdx); if (it == globCellIdxToIdxInSimWellBranch.end()) { if (wpExIdx == (intersections.size() - 1)) { m_pipeBranchWellResultPoints.pop_back(); } continue; } m_pipeBranchCLCoords.push_back(intersections[wpExIdx].startPoint); m_pipeBranchMeasuredDepths.push_back(intersections[wpExIdx].startMD); m_pipeBranchCLCoords.push_back(intersections[wpExIdx].endPoint); m_pipeBranchMeasuredDepths.push_back(intersections[wpExIdx].endMD); const RigWellResultPoint& resPoint = resFrame.m_wellResultBranches[it->second.first].m_branchResultPoints[it->second.second]; m_pipeBranchWellResultPoints.push_back(resPoint); if ( wpExIdx < intersections.size() - 1 ) { m_pipeBranchWellResultPoints.push_back(RigWellResultPoint()); // Invalid res point describing the "line" between the cells } } } }; //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimWellPltPlot::syncCurvesFromUiSelection() { RimWellLogTrack* plotTrack = m_wellLogPlot->trackByIndex(0); const std::set>& curveDefs = selectedCurveDefs(); setPlotXAxisTitles(plotTrack); // Delete existing curves plotTrack->deleteAllCurves(); int curveGroupId = 0; RimProject* proj = RiaApplication::instance()->project(); RimWellPath* wellPath = RimWellPlotTools::wellPathByWellPathNameOrSimWellName(m_wellPathName); // Add curves for (const std::pair& curveDefToAdd : curveDefs) { std::set selectedPhases = m_phaseSelectionMode == FLOW_TYPE_PHASE_SPLIT ? std::set(m_phases().begin(), m_phases().end()) : std::set({ FLOW_PHASE_TOTAL }); RifDataSourceForRftPlt sourceDef = curveDefToAdd.first; QDateTime timeStep = curveDefToAdd.second; std::unique_ptr resultPointCalc; QString curveName; { curveName += sourceDef.eclCase() ? sourceDef.eclCase()->caseUserDescription() : ""; curveName += sourceDef.wellLogFile() ? sourceDef.wellLogFile()->name() : ""; if ( sourceDef.sourceType() == RifDataSourceForRftPlt::RFT ) curveName += ", RFT"; curveName += ", " + timeStep.toString(); } if ( sourceDef.sourceType() == RifDataSourceForRftPlt::RFT ) { resultPointCalc.reset(new RigRftResultPointCalculator(m_wellPathName, dynamic_cast(sourceDef.eclCase()), timeStep)); } else if (sourceDef.sourceType() == RifDataSourceForRftPlt::GRID) { resultPointCalc.reset(new RigSimWellResultPointCalculator(m_wellPathName, dynamic_cast(sourceDef.eclCase()), timeStep)); } if (resultPointCalc != nullptr) { if ( resultPointCalc->pipeBranchCLCoords().size() ) { RigAccWellFlowCalculator wfAccumulator(resultPointCalc->pipeBranchCLCoords(), resultPointCalc->pipeBranchWellResultPoints(), resultPointCalc->pipeBranchMeasuredDepths(), false); // m_phaseSelectionMode() != FLOW_TYPE_PHASE_SPLIT); The total flow is reservoir conditions must be careful const std::vector& depthValues = wfAccumulator.pseudoLengthFromTop(0); std::vector tracerNames = wfAccumulator.tracerNames(); for ( const QString& tracerName: tracerNames ) { auto color = tracerName == RIG_FLOW_OIL_NAME ? cvf::Color3f::DARK_GREEN : tracerName == RIG_FLOW_GAS_NAME ? cvf::Color3f::DARK_RED : tracerName == RIG_FLOW_WATER_NAME ? cvf::Color3f::BLUE : cvf::Color3f::DARK_GRAY; if ( tracerName == RIG_FLOW_OIL_NAME && selectedPhases.count(FLOW_PHASE_OIL) || tracerName == RIG_FLOW_GAS_NAME && selectedPhases.count(FLOW_PHASE_GAS) || tracerName == RIG_FLOW_WATER_NAME && selectedPhases.count(FLOW_PHASE_WATER) || tracerName == RIG_FLOW_TOTAL_NAME && selectedPhases.count(FLOW_PHASE_TOTAL) ) { const std::vector accFlow = wfAccumulator.accumulatedTracerFlowPrPseudoLength(tracerName, 0); addStackedCurve(curveName + ", " + tracerName, depthValues, accFlow, plotTrack, color, curveGroupId, false); } } } } else if ( sourceDef.sourceType() == RifDataSourceForRftPlt::OBSERVED ) { RimWellLogFile* const wellLogFile = sourceDef.wellLogFile(); if ( wellLogFile ) { RigWellLogFile* rigWellLogFile = wellLogFile->wellLogFileData(); if ( rigWellLogFile ) { for (RimWellLogFileChannel* channel : RimWellPlotTools::getFlowChannelsFromWellFile(wellLogFile)) { const auto& channelName = channel->name(); if (selectedPhases.count(RimWellPlotTools::flowPhaseFromChannelName(channelName)) > 0) { auto color = RimWellPlotTools::isOilFlowChannel(channelName) ? cvf::Color3f::DARK_GREEN : RimWellPlotTools::isGasFlowChannel(channelName) ? cvf::Color3f::DARK_RED : RimWellPlotTools::isWaterFlowChannel(channelName) ? cvf::Color3f::BLUE : cvf::Color3f::DARK_GRAY; addStackedCurve(curveName + ", " + channelName, rigWellLogFile->depthValues(), rigWellLogFile->values(channelName), plotTrack, color, curveGroupId, true); } } } } } curveGroupId++; } m_wellLogPlot->loadDataAndUpdate(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimWellPltPlot::addStackedCurve(const QString& curveName, const std::vector& depthValues, const std::vector& accFlow, RimWellLogTrack* plotTrack, cvf::Color3f color, int curveGroupId, bool doFillCurve) { RimWellFlowRateCurve* curve = new RimWellFlowRateCurve; curve->setFlowValuesPrDepthValue(curveName, depthValues, accFlow); curve->setColor(color); curve->setGroupId(curveGroupId); curve->setDoFillCurve(doFillCurve); curve->setSymbol(RimSummaryCurveAppearanceCalculator::cycledSymbol(curveGroupId)); plotTrack->addCurve(curve); curve->loadDataAndUpdate(true); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- std::vector RimWellPltPlot::selectedSourcesExpanded() const { std::vector sources; for (const RifDataSourceForRftPlt& addr : m_selectedSources()) { if (addr.sourceType() == RifDataSourceForRftPlt::OBSERVED) { for (RimWellLogFile* const wellLogFile : RimWellPlotTools::wellLogFilesContainingFlow(m_wellPathName)) { sources.push_back(RifDataSourceForRftPlt(RifDataSourceForRftPlt::OBSERVED, wellLogFile)); } } else sources.push_back(addr); } return sources; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- QWidget* RimWellPltPlot::viewWidget() { return m_wellLogPlotWidget; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimWellPltPlot::zoomAll() { m_wellLogPlot()->zoomAll(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RimWellLogPlot* RimWellPltPlot::wellLogPlot() const { return m_wellLogPlot(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimWellPltPlot::setCurrentWellName(const QString& currWellName) { m_wellPathName = currWellName; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- QString RimWellPltPlot::currentWellName() const { return m_wellPathName; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- const char* RimWellPltPlot::plotNameFormatString() { return PLOT_NAME_QFORMAT_STRING; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- QList RimWellPltPlot::calculateValueOptions(const caf::PdmFieldHandle* fieldNeedingOptions, bool * useOptionsOnly) { QList options; const QString simWellName = RimWellPlotTools::simWellName(m_wellPathName); if (fieldNeedingOptions == &m_wellPathName) { calculateValueOptionsForWells(options); } else if (fieldNeedingOptions == &m_selectedSources) { std::set optionAddresses; const std::vector rftCases = RimWellPlotTools::rftCasesForWell(simWellName); std::set availableRftSources; for (const auto& rftCase : rftCases) { std::set rftTimes = rftCase->rftReader()->availableTimeSteps(simWellName, { RifEclipseRftAddress::ORAT, RifEclipseRftAddress::WRAT, RifEclipseRftAddress::GRAT }); if (rftTimes.size()) { availableRftSources.insert(RifDataSourceForRftPlt(RifDataSourceForRftPlt::RFT, rftCase)); } } if ( availableRftSources.size() ) { options.push_back(caf::PdmOptionItemInfo::createHeader(RifDataSourceForRftPlt::sourceTypeUiText(RifDataSourceForRftPlt::RFT), true)); for ( const auto& addr : availableRftSources ) { auto item = caf::PdmOptionItemInfo(addr.eclCase()->caseUserDescription(), QVariant::fromValue(addr)); item.setLevel(1); options.push_back(item); } } const std::vector gridCases = RimWellPlotTools::gridCasesForWell(simWellName); if (gridCases.size() > 0) { options.push_back(caf::PdmOptionItemInfo::createHeader(RifDataSourceForRftPlt::sourceTypeUiText(RifDataSourceForRftPlt::GRID), true)); } for (const auto& gridCase : gridCases) { auto addr = RifDataSourceForRftPlt(RifDataSourceForRftPlt::GRID, gridCase); auto item = caf::PdmOptionItemInfo(gridCase->caseUserDescription(), QVariant::fromValue(addr)); item.setLevel(1); options.push_back(item); } if (RimWellPlotTools::wellLogFilesContainingFlow(m_wellPathName).size() > 0) { options.push_back(caf::PdmOptionItemInfo::createHeader(RifDataSourceForRftPlt::sourceTypeUiText(RifDataSourceForRftPlt::OBSERVED), true)); auto addr = RifDataSourceForRftPlt(RifDataSourceForRftPlt::OBSERVED); auto item = caf::PdmOptionItemInfo("Observed Data", QVariant::fromValue(addr)); item.setLevel(1); options.push_back(item); optionAddresses.insert(addr); } } else if (fieldNeedingOptions == &m_selectedTimeSteps) { calculateValueOptionsForTimeSteps(m_wellPathName, options); } if (fieldNeedingOptions == &m_phaseSelectionMode) { } else if (fieldNeedingOptions == &m_phases) { options.push_back(caf::PdmOptionItemInfo("Oil", FLOW_PHASE_OIL)); options.push_back(caf::PdmOptionItemInfo("Gas", FLOW_PHASE_GAS)); options.push_back(caf::PdmOptionItemInfo("Water", FLOW_PHASE_WATER)); } return options; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimWellPltPlot::fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) { RimViewWindow::fieldChangedByUi(changedField, oldValue, newValue); if (changedField == &m_wellPathName) { setDescription(QString(plotNameFormatString()).arg(m_wellPathName)); } if (changedField == &m_wellPathName) { RimWellLogTrack* const plotTrack = m_wellLogPlot->trackByIndex(0); plotTrack->deleteAllCurves(); m_selectedSources.v().clear(); m_selectedTimeSteps.v().clear(); updateFormationsOnPlot(); } else if (changedField == &m_selectedSources) { } if (changedField == &m_selectedSources || changedField == &m_selectedTimeSteps) { updateFormationsOnPlot(); syncSourcesIoFieldFromGuiField(); syncCurvesFromUiSelection(); } else if (changedField == &m_showPlotTitle) { //m_wellLogPlot->setShowDescription(m_showPlotTitle); } if (changedField == &m_phaseSelectionMode || changedField == &m_phases) { syncCurvesFromUiSelection(); } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimWellPltPlot::defineUiTreeOrdering(caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName) { uiTreeOrdering.skipRemainingChildren(true); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- QImage RimWellPltPlot::snapshotWindowContent() { QImage image; if (m_wellLogPlotWidget) { QPixmap pix = QPixmap::grabWidget(m_wellLogPlotWidget); image = pix.toImage(); } return image; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimWellPltPlot::defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) { const QString simWellName = RimWellPlotTools::simWellName(m_wellPathName); uiOrdering.add(&m_userName); uiOrdering.add(&m_wellPathName); caf::PdmUiGroup* sourcesGroup = uiOrdering.addNewGroupWithKeyword("Sources", "Sources"); sourcesGroup->add(&m_selectedSources); caf::PdmUiGroup* timeStepsGroup = uiOrdering.addNewGroupWithKeyword("Time Steps", "TimeSteps"); timeStepsGroup->add(&m_selectedTimeSteps); caf::PdmUiGroup* flowGroup = uiOrdering.addNewGroupWithKeyword("Phase Selection", "PhaseSelection"); flowGroup->add(&m_phaseSelectionMode); if (m_phaseSelectionMode == FLOW_TYPE_PHASE_SPLIT) { flowGroup->add(&m_phases); } //uiOrdering.add(&m_showPlotTitle); if (m_wellLogPlot && m_wellLogPlot->trackCount() > 0) { RimWellLogTrack* track = m_wellLogPlot->trackByIndex(0); track->uiOrderingForShowFormationNamesAndCase(uiOrdering); caf::PdmUiGroup* legendAndAxisGroup = uiOrdering.addNewGroup("Legend and Axis"); legendAndAxisGroup->setCollapsedByDefault(true); m_wellLogPlot->uiOrderingForPlot(*legendAndAxisGroup); track->uiOrderingForVisibleXRange(*legendAndAxisGroup); m_wellLogPlot->uiOrderingForVisibleDepthRange(*legendAndAxisGroup); } uiOrdering.skipRemainingFields(true); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimWellPltPlot::defineEditorAttribute(const caf::PdmFieldHandle* field, QString uiConfigName, caf::PdmUiEditorAttribute* attribute) { if (field == &m_phases) { caf::PdmUiTreeSelectionEditorAttribute* attrib = dynamic_cast (attribute); attrib->showTextFilter = false; attrib->showToggleAllCheckbox = false; } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimWellPltPlot::initAfterRead() { RimViewWindow::initAfterRead(); // Postpone init until data has been loaded m_doInitAfterLoad = true; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimWellPltPlot::setupBeforeSave() { syncSourcesIoFieldFromGuiField(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimWellPltPlot::initAfterLoad() { std::vector selectedSources; for (RimDataSourceForRftPlt* addr : m_selectedSourcesForIo) { selectedSources.push_back(addr->address()); } m_selectedSources = selectedSources; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimWellPltPlot::syncSourcesIoFieldFromGuiField() { m_selectedSourcesForIo.clear(); for (const RifDataSourceForRftPlt& addr : m_selectedSources()) { m_selectedSourcesForIo.push_back(new RimDataSourceForRftPlt(addr)); } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimWellPltPlot::calculateValueOptionsForWells(QList& options) { RimProject * proj = RiaApplication::instance()->project(); if (proj != nullptr) { std::set wellNames; // Observed wells for (const RimWellPath* const wellPath : proj->allWellPaths()) { wellNames.insert(wellPath->name()); } for (const auto& wellName : wellNames) { options.push_back(caf::PdmOptionItemInfo(wellName, wellName)); } } options.push_back(caf::PdmOptionItemInfo("None", "")); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimWellPltPlot::calculateValueOptionsForTimeSteps(const QString& wellPathNameOrSimWellName, QList& options) { std::vector selSources = selectedSourcesExpanded(); bool hasObservedData = false; bool hasRftData = false; bool hasGridData = false; for (const auto& source : selSources ) { switch (source.sourceType()) { case RifDataSourceForRftPlt::RFT: hasRftData = true; break; case RifDataSourceForRftPlt::GRID: hasGridData = true; break; case RifDataSourceForRftPlt::OBSERVED: hasObservedData = true; break; } } std::map > observedTimeStepsWithSources; std::map > rftTimeStepsWithSources; std::map > gridTimestepsWithSources; QString simWellName = RimWellPlotTools::simWellName(wellPathNameOrSimWellName); if (hasObservedData) { for (const auto& source : selSources ) { if (source.sourceType() == RifDataSourceForRftPlt::OBSERVED && source.wellLogFile()) { observedTimeStepsWithSources[source.wellLogFile()->date()].insert(source); } } } if (hasRftData) { for (const auto& source : selSources ) { if (source.sourceType() == RifDataSourceForRftPlt::RFT && source.rftReader()) { std::set rftTimes = source.rftReader()->availableTimeSteps(simWellName, { RifEclipseRftAddress::ORAT, RifEclipseRftAddress::WRAT, RifEclipseRftAddress::GRAT } ); for ( const QDateTime& date: rftTimes) { rftTimeStepsWithSources[date].insert(source); } } } } if ( hasGridData ) { for ( const auto& source : selSources ) { if ( source.sourceType() == RifDataSourceForRftPlt::GRID && source.eclCase() ) { std::set wellTimeSteps = RimWellPlotTools::availableSimWellTimesteps(source.eclCase(), simWellName); for ( const QDateTime& date: wellTimeSteps) { gridTimestepsWithSources[date].insert(source); } } } } // If we have a time baseline add the equal or adjacent grid timesteps std::map > timestepsToShowWithSources; std::map >* timeBaseline = nullptr; if (hasObservedData) { timeBaseline = &observedTimeStepsWithSources; } else if (hasRftData) { timeBaseline = &rftTimeStepsWithSources; } if (timeBaseline) { std::set baseTimeSteps; for (const auto& dateSourceSetPair: *timeBaseline) baseTimeSteps.insert(dateSourceSetPair.first); std::set rftTimeSteps; for (const auto& dateSourceSetPair: rftTimeStepsWithSources) rftTimeSteps.insert(dateSourceSetPair.first); std::set gridTimeSteps; for (const auto& dateSourceSetPair: gridTimestepsWithSources) gridTimeSteps.insert(dateSourceSetPair.first); std::set filteredRftTimeSteps = RimWellPlotTools::findMatchingOrAdjacentTimeSteps(baseTimeSteps, rftTimeSteps); std::set filteredGridTimeSteps = RimWellPlotTools::findMatchingOrAdjacentTimeSteps(baseTimeSteps, gridTimeSteps); // Fill final map timestepsToShowWithSources = observedTimeStepsWithSources; for (const QDateTime& time: filteredRftTimeSteps) { std::set& sourceSet = rftTimeStepsWithSources.find(time)->second; timestepsToShowWithSources[time].insert(sourceSet.begin(), sourceSet.end()); } for (const QDateTime& time: filteredGridTimeSteps) { std::set& sourceSet = gridTimestepsWithSources.find(time)->second; timestepsToShowWithSources[time].insert(sourceSet.begin(), sourceSet.end()); } } else { timestepsToShowWithSources = gridTimestepsWithSources; } // Create formatted options of all the timesteps std::vector allTimeSteps; for (const std::pair>& timeStepPair : timestepsToShowWithSources) { allTimeSteps.push_back(timeStepPair.first); } const QString dateFormatString = RimTools::createTimeFormatStringFromDates(allTimeSteps); for (const std::pair>& timeStepPair : timestepsToShowWithSources) { QString optionText = timeStepPair.first.toString(dateFormatString); bool hasObs = false; bool hasRft = false; bool hasGrid = false; for (const auto& source : timeStepPair.second) { switch (source.sourceType()){ case RifDataSourceForRftPlt::OBSERVED: hasObs = true; break; case RifDataSourceForRftPlt::RFT : hasRft = true; break; case RifDataSourceForRftPlt::GRID : hasGrid = true; break; } } optionText += " \t[ "; if (hasObs) optionText += "O "; if (hasRft) optionText += "R "; if (hasGrid) optionText += "G"; optionText += " ]"; options.push_back(caf::PdmOptionItemInfo(optionText, timeStepPair.first)); } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimWellPltPlot::setDescription(const QString& description) { m_userName = description; updateWidgetTitleWindowTitle(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- QString RimWellPltPlot::description() const { return m_userName(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimWellPltPlot::onLoadDataAndUpdate() { if (m_doInitAfterLoad) { initAfterLoad(); m_doInitAfterLoad = false; } if (m_isOnLoad) { if (m_wellLogPlot->trackCount() > 0) { m_wellLogPlot->trackByIndex(0)->setShowFormations(true); } m_isOnLoad = false; } updateMdiWindowVisibility(); updateFormationsOnPlot(); syncCurvesFromUiSelection(); m_wellLogPlot->loadDataAndUpdate(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- QWidget* RimWellPltPlot::createViewWidget(QWidget* mainWindowParent) { m_wellLogPlotWidget = new RiuWellPltPlot(this, mainWindowParent); return m_wellLogPlotWidget; }