From 24c2eeb0226b0a924b5d8f5687f1425a9e4d6281 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Mon, 14 Jun 2021 08:01:28 +0200 Subject: [PATCH 01/14] Guard nullpointer access and catch exceptions --- .../RimEclipseResultDefinition.cpp | 5594 ++++++++--------- .../ProjectDataModel/RimVfpTableExtractor.cpp | 181 +- 2 files changed, 2885 insertions(+), 2890 deletions(-) diff --git a/ApplicationLibCode/ProjectDataModel/RimEclipseResultDefinition.cpp b/ApplicationLibCode/ProjectDataModel/RimEclipseResultDefinition.cpp index 904360b48c..c10d9df067 100644 --- a/ApplicationLibCode/ProjectDataModel/RimEclipseResultDefinition.cpp +++ b/ApplicationLibCode/ProjectDataModel/RimEclipseResultDefinition.cpp @@ -1,2797 +1,2797 @@ -///////////////////////////////////////////////////////////////////////////////// -// -// Copyright (C) 2011- Statoil ASA -// Copyright (C) 2013- Ceetron Solutions AS -// Copyright (C) 2011-2012 Ceetron AS -// -// ResInsight is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or -// FITNESS FOR A PARTICULAR PURPOSE. -// -// See the GNU General Public License at -// for more details. -// -///////////////////////////////////////////////////////////////////////////////// - -#include "RimEclipseResultDefinition.h" - -#include "RiaColorTables.h" -#include "RiaColorTools.h" -#include "RiaLogging.h" -#include "RiaNncDefines.h" -#include "RiaQDateTimeTools.h" - -#include "RicfCommandObject.h" - -#include "RigActiveCellInfo.h" -#include "RigAllanDiagramData.h" -#include "RigCaseCellResultsData.h" -#include "RigEclipseCaseData.h" -#include "RigEclipseResultInfo.h" -#include "RigFlowDiagResultAddress.h" -#include "RigFlowDiagResults.h" -#include "RigFormationNames.h" -#include "RigVisibleCategoriesCalculator.h" - -#include "Rim3dView.h" -#include "Rim3dWellLogCurve.h" -#include "RimCellEdgeColors.h" -#include "RimColorLegend.h" -#include "RimContourMapProjection.h" -#include "RimEclipseCase.h" -#include "RimEclipseCellColors.h" -#include "RimEclipseContourMapProjection.h" -#include "RimEclipseContourMapView.h" -#include "RimEclipseFaultColors.h" -#include "RimEclipseInputProperty.h" -#include "RimEclipseInputPropertyCollection.h" -#include "RimEclipsePropertyFilter.h" -#include "RimEclipseResultCase.h" -#include "RimEclipseView.h" -#include "RimFlowDiagSolution.h" -#include "RimGridCrossPlot.h" -#include "RimGridCrossPlotDataSet.h" -#include "RimGridTimeHistoryCurve.h" -#include "RimIntersectionCollection.h" -#include "RimIntersectionResultDefinition.h" -#include "RimPlotCurve.h" -#include "RimProject.h" -#include "RimReservoirCellResultsStorage.h" -#include "RimSimWellInView.h" -#include "RimSimWellInViewCollection.h" -#include "RimTernaryLegendConfig.h" -#include "RimViewLinker.h" -#include "RimWellLogExtractionCurve.h" -#include "RimWellLogTrack.h" - -#ifdef USE_QTCHARTS -#include "RimGridStatisticsPlot.h" -#endif - -#include "cafCategoryMapper.h" -#include "cafPdmFieldScriptingCapability.h" -#include "cafPdmUiListEditor.h" -#include "cafPdmUiToolButtonEditor.h" -#include "cafPdmUiTreeSelectionEditor.h" -#include "cafUtils.h" - -#include - -namespace caf -{ -template <> -void RimEclipseResultDefinition::FlowTracerSelectionEnum::setUp() -{ - addItem( RimEclipseResultDefinition::FLOW_TR_INJ_AND_PROD, "FLOW_TR_INJ_AND_PROD", "All Injectors and Producers" ); - addItem( RimEclipseResultDefinition::FLOW_TR_PRODUCERS, "FLOW_TR_PRODUCERS", "All Producers" ); - addItem( RimEclipseResultDefinition::FLOW_TR_INJECTORS, "FLOW_TR_INJECTORS", "All Injectors" ); - addItem( RimEclipseResultDefinition::FLOW_TR_BY_SELECTION, "FLOW_TR_BY_SELECTION", "By Selection" ); - - setDefault( RimEclipseResultDefinition::FLOW_TR_INJ_AND_PROD ); -} -} // namespace caf - -CAF_PDM_SOURCE_INIT( RimEclipseResultDefinition, "ResultDefinition" ); - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -RimEclipseResultDefinition::RimEclipseResultDefinition( caf::PdmUiItemInfo::LabelPosType labelPosition ) - : m_isDeltaResultEnabled( false ) - , m_labelPosition( labelPosition ) - , m_ternaryEnabled( true ) -{ - CAF_PDM_InitScriptableObjectWithNameAndComment( "Result Definition", "", "", "", "EclipseResult", "An eclipse result definition" ); - - CAF_PDM_InitScriptableFieldNoDefault( &m_resultType, "ResultType", "Type", "", "", "" ); - m_resultType.uiCapability()->setUiHidden( true ); - - CAF_PDM_InitScriptableFieldNoDefault( &m_porosityModel, "PorosityModelType", "Porosity", "", "", "" ); - m_porosityModel.uiCapability()->setUiHidden( true ); - - CAF_PDM_InitScriptableField( &m_resultVariable, - "ResultVariable", - RiaResultNames::undefinedResultName(), - "Variable", - "", - "", - "" ); - m_resultVariable.uiCapability()->setUiHidden( true ); - - CAF_PDM_InitFieldNoDefault( &m_flowSolution, "FlowDiagSolution", "Solution", "", "", "" ); - m_flowSolution.uiCapability()->setUiHidden( true ); - - CAF_PDM_InitField( &m_timeLapseBaseTimestep, - "TimeLapseBaseTimeStep", - RigEclipseResultAddress::noTimeLapseValue(), - "Base Time Step", - "", - "", - "" ); - - CAF_PDM_InitFieldNoDefault( &m_differenceCase, "DifferenceCase", "Difference Case", "", "", "" ); - - CAF_PDM_InitField( &m_divideByCellFaceArea, "DivideByCellFaceArea", false, "Divide By Area", "", "", "" ); - - CAF_PDM_InitScriptableFieldNoDefault( &m_selectedInjectorTracers, "SelectedInjectorTracers", "Injector Tracers", "", "", "" ); - m_selectedInjectorTracers.uiCapability()->setUiHidden( true ); - - CAF_PDM_InitScriptableFieldNoDefault( &m_selectedProducerTracers, "SelectedProducerTracers", "Producer Tracers", "", "", "" ); - m_selectedProducerTracers.uiCapability()->setUiHidden( true ); - - CAF_PDM_InitScriptableFieldNoDefault( &m_selectedSouringTracers, "SelectedSouringTracers", "Tracers", "", "", "" ); - m_selectedSouringTracers.uiCapability()->setUiHidden( true ); - - CAF_PDM_InitScriptableFieldNoDefault( &m_flowTracerSelectionMode, "FlowTracerSelectionMode", "Tracers", "", "", "" ); - CAF_PDM_InitScriptableFieldNoDefault( &m_phaseSelection, "PhaseSelection", "Phases", "", "", "" ); - m_phaseSelection.uiCapability()->setUiLabelPosition( m_labelPosition ); - - CAF_PDM_InitScriptableField( &m_showOnlyVisibleCategoriesInLegend, - "ShowOnlyVisibleCategoriesInLegend", - true, - "Show Only Visible Categories In Legend", - "", - "", - "" ); - - // Ui only fields - - CAF_PDM_InitFieldNoDefault( &m_resultTypeUiField, "MResultType", "Type", "", "", "" ); - m_resultTypeUiField.xmlCapability()->disableIO(); - m_resultTypeUiField.uiCapability()->setUiLabelPosition( m_labelPosition ); - - CAF_PDM_InitFieldNoDefault( &m_porosityModelUiField, "MPorosityModelType", "Porosity", "", "", "" ); - m_porosityModelUiField.xmlCapability()->disableIO(); - m_porosityModelUiField.uiCapability()->setUiLabelPosition( m_labelPosition ); - - CAF_PDM_InitField( &m_resultVariableUiField, - "MResultVariable", - RiaResultNames::undefinedResultName(), - "Result Property", - "", - "", - "" ); - m_resultVariableUiField.xmlCapability()->disableIO(); - m_resultVariableUiField.uiCapability()->setUiEditorTypeName( caf::PdmUiListEditor::uiEditorTypeName() ); - m_resultVariableUiField.uiCapability()->setUiLabelPosition( m_labelPosition ); - - CAF_PDM_InitFieldNoDefault( &m_inputPropertyFileName, "InputPropertyFileName", "File Name", "", "", "" ); - m_inputPropertyFileName.xmlCapability()->disableIO(); - m_inputPropertyFileName.uiCapability()->setUiReadOnly( true ); - - CAF_PDM_InitFieldNoDefault( &m_flowSolutionUiField, "MFlowDiagSolution", "Solution", "", "", "" ); - m_flowSolutionUiField.xmlCapability()->disableIO(); - m_flowSolutionUiField.uiCapability()->setUiHidden( true ); // For now since there are only one to choose from - - CAF_PDM_InitField( &m_syncInjectorToProducerSelection, "MSyncSelectedInjProd", false, "Add Communicators ->", "", "", "" ); - m_syncInjectorToProducerSelection.uiCapability()->setUiEditorTypeName( caf::PdmUiToolButtonEditor::uiEditorTypeName() ); - - CAF_PDM_InitField( &m_syncProducerToInjectorSelection, "MSyncSelectedProdInj", false, "<- Add Communicators", "", "", "" ); - m_syncProducerToInjectorSelection.uiCapability()->setUiEditorTypeName( caf::PdmUiToolButtonEditor::uiEditorTypeName() ); - - CAF_PDM_InitFieldNoDefault( &m_selectedInjectorTracersUiField, "MSelectedInjectorTracers", "Injector Tracers", "", "", "" ); - m_selectedInjectorTracersUiField.xmlCapability()->disableIO(); - m_selectedInjectorTracersUiField.uiCapability()->setUiEditorTypeName( - caf::PdmUiTreeSelectionEditor::uiEditorTypeName() ); - m_selectedInjectorTracersUiField.uiCapability()->setUiLabelPosition( caf::PdmUiItemInfo::HIDDEN ); - - CAF_PDM_InitFieldNoDefault( &m_selectedProducerTracersUiField, "MSelectedProducerTracers", "Producer Tracers", "", "", "" ); - m_selectedProducerTracersUiField.xmlCapability()->disableIO(); - m_selectedProducerTracersUiField.uiCapability()->setUiEditorTypeName( - caf::PdmUiTreeSelectionEditor::uiEditorTypeName() ); - m_selectedProducerTracersUiField.uiCapability()->setUiLabelPosition( caf::PdmUiItemInfo::HIDDEN ); - - CAF_PDM_InitFieldNoDefault( &m_selectedSouringTracersUiField, "MSelectedSouringTracers", "Tracers", "", "", "" ); - m_selectedSouringTracersUiField.xmlCapability()->disableIO(); - m_selectedSouringTracersUiField.uiCapability()->setUiEditorTypeName( caf::PdmUiListEditor::uiEditorTypeName() ); - m_selectedSouringTracersUiField.uiCapability()->setUiLabelPosition( m_labelPosition ); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -RimEclipseResultDefinition::~RimEclipseResultDefinition() -{ -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimEclipseResultDefinition::simpleCopy( const RimEclipseResultDefinition* other ) -{ - this->setResultVariable( other->resultVariable() ); - this->setPorosityModel( other->porosityModel() ); - this->setResultType( other->resultType() ); - this->setFlowSolution( other->m_flowSolution() ); - this->setSelectedInjectorTracers( other->m_selectedInjectorTracers() ); - this->setSelectedProducerTracers( other->m_selectedProducerTracers() ); - this->setSelectedSouringTracers( other->m_selectedSouringTracers() ); - m_flowTracerSelectionMode = other->m_flowTracerSelectionMode(); - m_phaseSelection = other->m_phaseSelection; - - m_differenceCase = other->m_differenceCase(); - m_timeLapseBaseTimestep = other->m_timeLapseBaseTimestep(); - m_divideByCellFaceArea = other->m_divideByCellFaceArea(); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimEclipseResultDefinition::setEclipseCase( RimEclipseCase* eclipseCase ) -{ - m_eclipseCase = eclipseCase; - - assignFlowSolutionFromCase(); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -RimEclipseCase* RimEclipseResultDefinition::eclipseCase() const -{ - return m_eclipseCase; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -RigCaseCellResultsData* RimEclipseResultDefinition::currentGridCellResults() const -{ - if ( !m_eclipseCase ) return nullptr; - - return m_eclipseCase->results( m_porosityModel() ); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimEclipseResultDefinition::fieldChangedByUi( const caf::PdmFieldHandle* changedField, - const QVariant& oldValue, - const QVariant& newValue ) -{ - if ( &m_flowSolutionUiField == changedField || &m_resultTypeUiField == changedField || - &m_porosityModelUiField == changedField ) - { - // If the user are seeing the list with the actually selected result, - // select that result in the list. Otherwise select nothing. - - QStringList varList = getResultNamesForResultType( m_resultTypeUiField(), this->currentGridCellResults() ); - - bool isFlowDiagFieldsRelevant = ( m_resultType() == RiaDefines::ResultCatType::FLOW_DIAGNOSTICS ); - - if ( ( m_flowSolutionUiField() == m_flowSolution() || !isFlowDiagFieldsRelevant ) && - m_resultTypeUiField() == m_resultType() && m_porosityModelUiField() == m_porosityModel() ) - { - if ( varList.contains( resultVariable() ) ) - { - m_resultVariableUiField = resultVariable(); - } - - if ( isFlowDiagFieldsRelevant ) - { - m_selectedInjectorTracersUiField = m_selectedInjectorTracers(); - m_selectedProducerTracersUiField = m_selectedProducerTracers(); - } - else - { - m_selectedInjectorTracersUiField = std::vector(); - m_selectedProducerTracersUiField = std::vector(); - } - } - else - { - m_resultVariableUiField = ""; - m_selectedInjectorTracersUiField = std::vector(); - m_selectedProducerTracersUiField = std::vector(); - } - } - - if ( &m_resultVariableUiField == changedField ) - { - m_porosityModel = m_porosityModelUiField; - m_resultType = m_resultTypeUiField; - m_resultVariable = m_resultVariableUiField; - - if ( m_resultTypeUiField() == RiaDefines::ResultCatType::FLOW_DIAGNOSTICS ) - { - m_flowSolution = m_flowSolutionUiField(); - m_selectedInjectorTracers = m_selectedInjectorTracersUiField(); - m_selectedProducerTracers = m_selectedProducerTracersUiField(); - } - else if ( m_resultTypeUiField() == RiaDefines::ResultCatType::INJECTION_FLOODING ) - { - m_selectedSouringTracers = m_selectedSouringTracersUiField(); - } - else if ( m_resultTypeUiField() == RiaDefines::ResultCatType::INPUT_PROPERTY ) - { - m_inputPropertyFileName = getInputPropertyFileName( newValue.toString() ); - } - loadDataAndUpdate(); - } - - if ( &m_porosityModelUiField == changedField ) - { - m_porosityModel = m_porosityModelUiField; - m_resultVariableUiField = resultVariable(); - - RimEclipseView* eclipseView = nullptr; - this->firstAncestorOrThisOfType( eclipseView ); - if ( eclipseView ) - { - // Active cells can be different between matrix and fracture, make sure all geometry is recreated - eclipseView->scheduleReservoirGridGeometryRegen(); - } - - loadDataAndUpdate(); - } - - RimEclipseContourMapView* contourMapView = nullptr; - this->firstAncestorOrThisOfType( contourMapView ); - - if ( &m_differenceCase == changedField ) - { - m_timeLapseBaseTimestep = RigEclipseResultAddress::noTimeLapseValue(); - - if ( contourMapView ) - { - contourMapView->contourMapProjection()->updatedWeightingResult(); - } - - loadDataAndUpdate(); - } - - if ( &m_timeLapseBaseTimestep == changedField ) - { - if ( contourMapView ) - { - contourMapView->contourMapProjection()->updatedWeightingResult(); - } - - loadDataAndUpdate(); - } - - if ( &m_divideByCellFaceArea == changedField ) - { - loadDataAndUpdate(); - } - - if ( &m_flowTracerSelectionMode == changedField ) - { - loadDataAndUpdate(); - } - - if ( &m_selectedInjectorTracersUiField == changedField ) - { - changedTracerSelectionField( true ); - } - - if ( &m_selectedProducerTracersUiField == changedField ) - { - changedTracerSelectionField( false ); - } - - if ( &m_syncInjectorToProducerSelection == changedField ) - { - syncInjectorToProducerSelection(); - m_syncInjectorToProducerSelection = false; - } - - if ( &m_syncProducerToInjectorSelection == changedField ) - { - syncProducerToInjectorSelection(); - m_syncProducerToInjectorSelection = false; - } - - if ( &m_selectedSouringTracersUiField == changedField ) - { - if ( !m_resultVariable().isEmpty() ) - { - m_selectedSouringTracers = m_selectedSouringTracersUiField(); - loadDataAndUpdate(); - } - } - - if ( &m_phaseSelection == changedField ) - { - if ( m_phaseSelection() != RigFlowDiagResultAddress::PHASE_ALL ) - { - m_resultType = m_resultTypeUiField; - m_resultVariable = RIG_FLD_TOF_RESNAME; - m_resultVariableUiField = RIG_FLD_TOF_RESNAME; - } - loadDataAndUpdate(); - } - - if ( &m_showOnlyVisibleCategoriesInLegend == changedField ) - { - loadDataAndUpdate(); - } - - updateAnyFieldHasChanged(); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimEclipseResultDefinition::changedTracerSelectionField( bool injector ) -{ - m_flowSolution = m_flowSolutionUiField(); - - std::vector& selectedTracers = injector ? m_selectedInjectorTracers.v() : m_selectedProducerTracers.v(); - const std::vector& selectedTracersUi = injector ? m_selectedInjectorTracersUiField.v() - : m_selectedProducerTracersUiField.v(); - - selectedTracers = selectedTracersUi; - - loadDataAndUpdate(); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimEclipseResultDefinition::updateAnyFieldHasChanged() -{ - RimEclipsePropertyFilter* propFilter = nullptr; - this->firstAncestorOrThisOfType( propFilter ); - if ( propFilter ) - { - propFilter->updateConnectedEditors(); - } - - RimEclipseFaultColors* faultColors = nullptr; - this->firstAncestorOrThisOfType( faultColors ); - if ( faultColors ) - { - faultColors->updateConnectedEditors(); - } - - RimCellEdgeColors* cellEdgeColors = nullptr; - this->firstAncestorOrThisOfType( cellEdgeColors ); - if ( cellEdgeColors ) - { - cellEdgeColors->updateConnectedEditors(); - } - - RimEclipseCellColors* cellColors = nullptr; - this->firstAncestorOrThisOfType( cellColors ); - if ( cellColors ) - { - cellColors->updateConnectedEditors(); - } - - RimIntersectionResultDefinition* intersectResDef = nullptr; - this->firstAncestorOrThisOfType( intersectResDef ); - if ( intersectResDef ) - { - intersectResDef->updateConnectedEditors(); - } - - RimGridCrossPlotDataSet* crossPlotCurveSet = nullptr; - this->firstAncestorOrThisOfType( crossPlotCurveSet ); - if ( crossPlotCurveSet ) - { - crossPlotCurveSet->updateConnectedEditors(); - } - - RimPlotCurve* curve = nullptr; - this->firstAncestorOrThisOfType( curve ); - if ( curve ) - { - curve->updateConnectedEditors(); - } - - Rim3dWellLogCurve* rim3dWellLogCurve = nullptr; - this->firstAncestorOrThisOfType( rim3dWellLogCurve ); - if ( rim3dWellLogCurve ) - { - rim3dWellLogCurve->resetMinMaxValues(); - } - - RimEclipseContourMapProjection* contourMap = nullptr; - this->firstAncestorOrThisOfType( contourMap ); - if ( contourMap ) - { - contourMap->updatedWeightingResult(); - } - - RimWellLogTrack* wellLogTrack = nullptr; - this->firstAncestorOrThisOfType( wellLogTrack ); - if ( wellLogTrack ) - { - wellLogTrack->loadDataAndUpdate(); - wellLogTrack->updateEditors(); - } -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimEclipseResultDefinition::setTofAndSelectTracer( const QString& tracerName ) -{ - setResultType( RiaDefines::ResultCatType::FLOW_DIAGNOSTICS ); - setResultVariable( "TOF" ); - setFlowDiagTracerSelectionType( FLOW_TR_BY_SELECTION ); - - if ( m_flowSolution() == nullptr ) - { - assignFlowSolutionFromCase(); - } - - if ( m_flowSolution() ) - { - RimFlowDiagSolution::TracerStatusType tracerStatus = m_flowSolution()->tracerStatusOverall( tracerName ); - - std::vector tracers; - tracers.push_back( tracerName ); - if ( ( tracerStatus == RimFlowDiagSolution::TracerStatusType::INJECTOR ) || - ( tracerStatus == RimFlowDiagSolution::TracerStatusType::VARYING ) ) - { - setSelectedInjectorTracers( tracers ); - } - - if ( ( tracerStatus == RimFlowDiagSolution::TracerStatusType::PRODUCER ) || - ( tracerStatus == RimFlowDiagSolution::TracerStatusType::VARYING ) ) - { - setSelectedProducerTracers( tracers ); - } - } -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimEclipseResultDefinition::loadDataAndUpdate() -{ - Rim3dView* view = nullptr; - this->firstAncestorOrThisOfType( view ); - - loadResult(); - - RimEclipsePropertyFilter* propFilter = nullptr; - this->firstAncestorOrThisOfType( propFilter ); - if ( propFilter ) - { - propFilter->setToDefaultValues(); - propFilter->updateFilterName(); - - if ( view ) - { - view->scheduleGeometryRegen( PROPERTY_FILTERED ); - view->scheduleCreateDisplayModelAndRedraw(); - } - } - - RimEclipseCellColors* cellColors = nullptr; - this->firstAncestorOrThisOfType( cellColors ); - if ( cellColors ) - { - this->updateLegendCategorySettings(); - - if ( view ) - { - RimViewLinker* viewLinker = view->assosiatedViewLinker(); - if ( viewLinker ) - { - viewLinker->updateCellResult(); - } - RimGridView* eclView = dynamic_cast( view ); - if ( eclView ) eclView->intersectionCollection()->scheduleCreateDisplayModelAndRedraw2dIntersectionViews(); - } - } - - RimIntersectionResultDefinition* sepIntersectionResDef = nullptr; - this->firstAncestorOrThisOfType( sepIntersectionResDef ); - if ( sepIntersectionResDef && sepIntersectionResDef->isInAction() ) - { - if ( view ) view->scheduleCreateDisplayModelAndRedraw(); - RimGridView* gridView = dynamic_cast( view ); - if ( gridView ) gridView->intersectionCollection()->scheduleCreateDisplayModelAndRedraw2dIntersectionViews(); - } - - RimCellEdgeColors* cellEdgeColors = nullptr; - this->firstAncestorOrThisOfType( cellEdgeColors ); - if ( cellEdgeColors ) - { - cellEdgeColors->singleVarEdgeResultColors()->updateLegendCategorySettings(); - cellEdgeColors->loadResult(); - - if ( view ) - { - view->scheduleCreateDisplayModelAndRedraw(); - } - } - - RimGridCrossPlotDataSet* crossPlotCurveSet = nullptr; - this->firstAncestorOrThisOfType( crossPlotCurveSet ); - if ( crossPlotCurveSet ) - { - crossPlotCurveSet->destroyCurves(); - crossPlotCurveSet->loadDataAndUpdate( true ); - } - - RimPlotCurve* curve = nullptr; - this->firstAncestorOrThisOfType( curve ); - if ( curve ) - { - curve->loadDataAndUpdate( true ); - } - - Rim3dWellLogCurve* rim3dWellLogCurve = nullptr; - this->firstAncestorOrThisOfType( rim3dWellLogCurve ); - if ( rim3dWellLogCurve ) - { - rim3dWellLogCurve->updateCurveIn3dView(); - } - -#ifdef USE_QTCHARTS - RimGridStatisticsPlot* gridStatisticsPlot = nullptr; - this->firstAncestorOrThisOfType( gridStatisticsPlot ); - if ( gridStatisticsPlot ) - { - gridStatisticsPlot->loadDataAndUpdate(); - } -#endif -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -QList - RimEclipseResultDefinition::calculateValueOptions( const caf::PdmFieldHandle* fieldNeedingOptions, bool* useOptionsOnly ) -{ - QList options; - - if ( fieldNeedingOptions == &m_resultTypeUiField ) - { - bool hasSourSimRLFile = false; - RimEclipseResultCase* eclResCase = dynamic_cast( m_eclipseCase.p() ); - if ( eclResCase && eclResCase->eclipseCaseData() ) - { - hasSourSimRLFile = eclResCase->hasSourSimFile(); - } - -#ifndef USE_HDF5 - // If using ResInsight without HDF5 support, ignore SourSim files and - // do not show it as a result category. - hasSourSimRLFile = false; -#endif - - bool enableSouring = false; - -#ifdef USE_HDF5 - if ( m_eclipseCase.notNull() ) - { - RigCaseCellResultsData* cellResultsData = m_eclipseCase->results( this->porosityModel() ); - - if ( cellResultsData && cellResultsData->hasFlowDiagUsableFluxes() ) - { - enableSouring = true; - } - } -#endif /* USE_HDF5 */ - - RimGridTimeHistoryCurve* timeHistoryCurve; - this->firstAncestorOrThisOfType( timeHistoryCurve ); - - bool isSeparateFaultResult = false; - { - RimEclipseFaultColors* sepFaultResult; - this->firstAncestorOrThisOfType( sepFaultResult ); - if ( sepFaultResult ) isSeparateFaultResult = true; - } - - using ResCatEnum = caf::AppEnum; - for ( size_t i = 0; i < ResCatEnum::size(); ++i ) - { - RiaDefines::ResultCatType resType = ResCatEnum::fromIndex( i ); - - // Do not include flow diagnostics results if it is a time history curve - - if ( resType == RiaDefines::ResultCatType::FLOW_DIAGNOSTICS && ( timeHistoryCurve ) ) - { - continue; - } - - if ( resType == RiaDefines::ResultCatType::FLOW_DIAGNOSTICS && m_eclipseCase && - m_eclipseCase->eclipseCaseData()->hasFractureResults() ) - { - // Flow diagnostics is not supported for dual porosity models - continue; - } - - // Do not include SourSimRL if no SourSim file is loaded - - if ( resType == RiaDefines::ResultCatType::SOURSIMRL && ( !hasSourSimRLFile ) ) - { - continue; - } - - if ( resType == RiaDefines::ResultCatType::INJECTION_FLOODING && !enableSouring ) - { - continue; - } - - if ( resType == RiaDefines::ResultCatType::ALLAN_DIAGRAMS && !isSeparateFaultResult ) - { - continue; - } - - QString uiString = ResCatEnum::uiTextFromIndex( i ); - options.push_back( caf::PdmOptionItemInfo( uiString, resType ) ); - } - } - - if ( m_resultTypeUiField() == RiaDefines::ResultCatType::FLOW_DIAGNOSTICS ) - { - if ( fieldNeedingOptions == &m_resultVariableUiField ) - { - options.push_back( caf::PdmOptionItemInfo( timeOfFlightString( false ), RIG_FLD_TOF_RESNAME ) ); - if ( m_phaseSelection() == RigFlowDiagResultAddress::PHASE_ALL ) - { - options.push_back( caf::PdmOptionItemInfo( "Tracer Cell Fraction (Sum)", RIG_FLD_CELL_FRACTION_RESNAME ) ); - options.push_back( - caf::PdmOptionItemInfo( maxFractionTracerString( false ), RIG_FLD_MAX_FRACTION_TRACER_RESNAME ) ); - options.push_back( - caf::PdmOptionItemInfo( "Injector Producer Communication", RIG_FLD_COMMUNICATION_RESNAME ) ); - } - } - else if ( fieldNeedingOptions == &m_flowSolutionUiField ) - { - RimEclipseResultCase* eclCase = dynamic_cast( m_eclipseCase.p() ); - if ( eclCase ) - { - std::vector flowSols = eclCase->flowDiagSolutions(); - for ( RimFlowDiagSolution* flowSol : flowSols ) - { - options.push_back( caf::PdmOptionItemInfo( flowSol->userDescription(), flowSol ) ); - } - } - } - else if ( fieldNeedingOptions == &m_selectedInjectorTracersUiField ) - { - options = calcOptionsForSelectedTracerField( true ); - } - else if ( fieldNeedingOptions == &m_selectedProducerTracersUiField ) - { - options = calcOptionsForSelectedTracerField( false ); - } - } - else if ( m_resultTypeUiField() == RiaDefines::ResultCatType::INJECTION_FLOODING ) - { - if ( fieldNeedingOptions == &m_selectedSouringTracersUiField ) - { - RigCaseCellResultsData* cellResultsStorage = currentGridCellResults(); - if ( cellResultsStorage ) - { - QStringList dynamicResultNames = - cellResultsStorage->resultNames( RiaDefines::ResultCatType::DYNAMIC_NATIVE ); - - for ( const QString& resultName : dynamicResultNames ) - { - if ( !resultName.endsWith( "F" ) || resultName == RiaResultNames::completionTypeResultName() ) - { - continue; - } - options.push_back( caf::PdmOptionItemInfo( resultName, resultName ) ); - } - } - } - else if ( fieldNeedingOptions == &m_resultVariableUiField ) - { - options.push_back( caf::PdmOptionItemInfo( RIG_NUM_FLOODED_PV, RIG_NUM_FLOODED_PV ) ); - } - } - else - { - if ( fieldNeedingOptions == &m_resultVariableUiField ) - { - options = calcOptionsForVariableUiFieldStandard( m_resultTypeUiField(), - this->currentGridCellResults(), - showDerivedResultsFirstInVariableUiField(), - addPerCellFaceOptionsForVariableUiField(), - m_ternaryEnabled ); - } - else if ( fieldNeedingOptions == &m_differenceCase ) - { - options.push_back( caf::PdmOptionItemInfo( "None", nullptr ) ); - - RimEclipseCase* eclipseCase = nullptr; - this->firstAncestorOrThisOfTypeAsserted( eclipseCase ); - if ( eclipseCase && eclipseCase->eclipseCaseData() && eclipseCase->eclipseCaseData()->mainGrid() ) - { - RimProject* proj = nullptr; - eclipseCase->firstAncestorOrThisOfTypeAsserted( proj ); - - std::vector allCases = proj->eclipseCases(); - for ( RimEclipseCase* otherCase : allCases ) - { - if ( otherCase == eclipseCase ) continue; - - if ( otherCase->eclipseCaseData() && otherCase->eclipseCaseData()->mainGrid() ) - { - options.push_back( caf::PdmOptionItemInfo( QString( "%1 (#%2)" ) - .arg( otherCase->caseUserDescription() ) - .arg( otherCase->caseId() ), - otherCase, - false, - otherCase->uiIconProvider() ) ); - } - } - } - } - else if ( fieldNeedingOptions == &m_timeLapseBaseTimestep ) - { - RimEclipseCase* currentCase = nullptr; - this->firstAncestorOrThisOfTypeAsserted( currentCase ); - - RimEclipseCase* baseCase = currentCase; - if ( m_differenceCase ) - { - baseCase = m_differenceCase; - } - - options.push_back( caf::PdmOptionItemInfo( "Disabled", RigEclipseResultAddress::noTimeLapseValue() ) ); - - std::vector stepDates = baseCase->timeStepDates(); - for ( size_t stepIdx = 0; stepIdx < stepDates.size(); ++stepIdx ) - { - QString displayString = stepDates[stepIdx].toString( RiaQDateTimeTools::dateFormatString() ); - displayString += QString( " (#%1)" ).arg( stepIdx ); - - options.push_back( caf::PdmOptionItemInfo( displayString, static_cast( stepIdx ) ) ); - } - } - } - - ( *useOptionsOnly ) = true; - - return options; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -RigEclipseResultAddress RimEclipseResultDefinition::eclipseResultAddress() const -{ - if ( isFlowDiagOrInjectionFlooding() ) return RigEclipseResultAddress(); - - const RigCaseCellResultsData* gridCellResults = this->currentGridCellResults(); - if ( gridCellResults ) - { - int timelapseTimeStep = RigEclipseResultAddress::noTimeLapseValue(); - int diffCaseId = RigEclipseResultAddress::noCaseDiffValue(); - - if ( isDeltaTimeStepActive() ) - { - timelapseTimeStep = m_timeLapseBaseTimestep(); - } - - if ( isDeltaCaseActive() ) - { - diffCaseId = m_differenceCase->caseId(); - } - - return RigEclipseResultAddress( m_resultType(), - m_resultVariable(), - timelapseTimeStep, - diffCaseId, - isDivideByCellFaceAreaActive() ); - } - else - { - return RigEclipseResultAddress(); - } -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimEclipseResultDefinition::setFromEclipseResultAddress( const RigEclipseResultAddress& address ) -{ - RigEclipseResultAddress canonizedAddress = address; - - const RigCaseCellResultsData* gridCellResults = this->currentGridCellResults(); - if ( gridCellResults ) - { - auto rinfo = gridCellResults->resultInfo( address ); - if ( rinfo ) canonizedAddress = rinfo->eclipseResultAddress(); - } - - m_resultType = canonizedAddress.resultCatType(); - m_resultVariable = canonizedAddress.resultName(); - m_timeLapseBaseTimestep = canonizedAddress.deltaTimeStepIndex(); - m_divideByCellFaceArea = canonizedAddress.isDivideByCellFaceAreaActive(); - - if ( canonizedAddress.isDeltaCaseActive() ) - { - auto eclipseCases = RimProject::current()->eclipseCases(); - for ( RimEclipseCase* c : eclipseCases ) - { - if ( c && c->caseId() == canonizedAddress.deltaCaseId() ) - { - m_differenceCase = c; - } - } - } - - this->updateUiFieldsFromActiveResult(); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -RigFlowDiagResultAddress RimEclipseResultDefinition::flowDiagResAddress() const -{ - CVF_ASSERT( isFlowDiagOrInjectionFlooding() ); - - if ( m_resultType() == RiaDefines::ResultCatType::FLOW_DIAGNOSTICS ) - { - size_t timeStep = 0; - - Rim3dView* rimView = nullptr; - this->firstAncestorOrThisOfType( rimView ); - if ( rimView ) - { - timeStep = rimView->currentTimeStep(); - } - RimWellLogExtractionCurve* wellLogExtractionCurve = nullptr; - this->firstAncestorOrThisOfType( wellLogExtractionCurve ); - if ( wellLogExtractionCurve ) - { - timeStep = static_cast( wellLogExtractionCurve->currentTimeStep() ); - } - - // Time history curves are not supported, since it requires the time - // step to access to be supplied. - RimGridTimeHistoryCurve* timeHistoryCurve = nullptr; - this->firstAncestorOrThisOfType( timeHistoryCurve ); - CVF_ASSERT( timeHistoryCurve == nullptr ); - - std::set selTracerNames; - if ( m_flowTracerSelectionMode == FLOW_TR_BY_SELECTION ) - { - for ( const QString& tName : m_selectedInjectorTracers() ) - { - selTracerNames.insert( tName.toStdString() ); - } - for ( const QString& tName : m_selectedProducerTracers() ) - { - selTracerNames.insert( tName.toStdString() ); - } - } - else - { - RimFlowDiagSolution* flowSol = m_flowSolution(); - if ( flowSol ) - { - std::vector tracerNames = flowSol->tracerNames(); - - if ( m_flowTracerSelectionMode == FLOW_TR_INJECTORS || m_flowTracerSelectionMode == FLOW_TR_INJ_AND_PROD ) - { - for ( const QString& tracerName : tracerNames ) - { - RimFlowDiagSolution::TracerStatusType status = - flowSol->tracerStatusInTimeStep( tracerName, timeStep ); - if ( status == RimFlowDiagSolution::TracerStatusType::INJECTOR ) - { - selTracerNames.insert( tracerName.toStdString() ); - } - } - } - - if ( m_flowTracerSelectionMode == FLOW_TR_PRODUCERS || m_flowTracerSelectionMode == FLOW_TR_INJ_AND_PROD ) - { - for ( const QString& tracerName : tracerNames ) - { - RimFlowDiagSolution::TracerStatusType status = - flowSol->tracerStatusInTimeStep( tracerName, timeStep ); - if ( status == RimFlowDiagSolution::TracerStatusType::PRODUCER ) - { - selTracerNames.insert( tracerName.toStdString() ); - } - } - } - } - } - - return RigFlowDiagResultAddress( m_resultVariable().toStdString(), m_phaseSelection(), selTracerNames ); - } - else - { - std::set selTracerNames; - for ( const QString& selectedTracerName : m_selectedSouringTracers() ) - { - selTracerNames.insert( selectedTracerName.toUtf8().constData() ); - } - return RigFlowDiagResultAddress( m_resultVariable().toStdString(), - RigFlowDiagResultAddress::PHASE_ALL, - selTracerNames ); - } -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimEclipseResultDefinition::setFlowDiagTracerSelectionType( FlowTracerSelectionType selectionType ) -{ - m_flowTracerSelectionMode = selectionType; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -QString RimEclipseResultDefinition::resultVariableUiName() const -{ - if ( resultType() == RiaDefines::ResultCatType::FLOW_DIAGNOSTICS ) - { - return flowDiagResUiText( false, 32 ); - } - - if ( isDivideByCellFaceAreaActive() ) - { - return m_resultVariable() + " /A"; - } - - return m_resultVariable(); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -QString RimEclipseResultDefinition::resultVariableUiShortName() const -{ - if ( resultType() == RiaDefines::ResultCatType::FLOW_DIAGNOSTICS ) - { - return flowDiagResUiText( true, 24 ); - } - - if ( isDivideByCellFaceAreaActive() ) - { - return m_resultVariable() + " /A"; - } - - return m_resultVariable(); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -QString RimEclipseResultDefinition::additionalResultText() const -{ - QStringList resultText; - - if ( isDeltaTimeStepActive() ) - { - std::vector stepDates; - const RigCaseCellResultsData* gridCellResults = this->currentGridCellResults(); - if ( gridCellResults ) - { - stepDates = gridCellResults->timeStepDates(); - resultText += - QString( "Base Time Step: %1" ) - .arg( stepDates[m_timeLapseBaseTimestep()].toString( RiaQDateTimeTools::dateFormatString() ) ); - } - } - if ( isDeltaCaseActive() ) - { - resultText += QString( "Base Case: %1" ).arg( m_differenceCase()->caseUserDescription() ); - } - return resultText.join( "
" ); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -QString RimEclipseResultDefinition::additionalResultTextShort() const -{ - QString resultTextShort; - if ( isDeltaTimeStepActive() || isDeltaCaseActive() ) - { - QStringList resultTextLines; - resultTextLines += QString( "\nDiff. Options:" ); - if ( isDeltaCaseActive() ) - { - resultTextLines += QString( "Base Case: #%1" ).arg( m_differenceCase()->caseId() ); - } - if ( isDeltaTimeStepActive() ) - { - resultTextLines += QString( "Base Time: #%1" ).arg( m_timeLapseBaseTimestep() ); - } - resultTextShort = resultTextLines.join( "\n" ); - } - - return resultTextShort; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -int RimEclipseResultDefinition::timeLapseBaseTimeStep() const -{ - return m_timeLapseBaseTimestep; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -int RimEclipseResultDefinition::caseDiffIndex() const -{ - if ( m_differenceCase ) - { - return m_differenceCase->caseId(); - } - return -1; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimEclipseResultDefinition::loadResult() -{ - if ( isFlowDiagOrInjectionFlooding() ) return; // Will load automatically on access - - if ( m_eclipseCase ) - { - if ( !m_eclipseCase->ensureReservoirCaseIsOpen() ) - { - RiaLogging::error( "Could not open the Eclipse Grid file: " + m_eclipseCase->gridFileName() ); - return; - } - } - - if ( m_differenceCase ) - { - if ( !m_differenceCase->ensureReservoirCaseIsOpen() ) - { - RiaLogging::error( "Could not open the Eclipse Grid file: " + m_eclipseCase->gridFileName() ); - return; - } - } - - RigCaseCellResultsData* gridCellResults = this->currentGridCellResults(); - if ( gridCellResults ) - { - if ( isDeltaTimeStepActive() || isDeltaCaseActive() || isDivideByCellFaceAreaActive() ) - { - gridCellResults->createResultEntry( this->eclipseResultAddress(), false ); - } - - QString resultName = m_resultVariable(); - std::set eclipseResultNamesWithNncData = RiaResultNames::nncResultNames(); - if ( eclipseResultNamesWithNncData.find( resultName ) != eclipseResultNamesWithNncData.end() ) - { - eclipseCase()->ensureFaultDataIsComputed(); - - bool dataWasComputed = eclipseCase()->ensureNncDataIsComputed(); - if ( dataWasComputed ) - { - eclipseCase()->createDisplayModelAndUpdateAllViews(); - } - } - - gridCellResults->ensureKnownResultLoaded( this->eclipseResultAddress() ); - } -} - -//-------------------------------------------------------------------------------------------------- -/// Returns whether the result requested by the definition is a single frame result -/// The result needs to be loaded before asking -//-------------------------------------------------------------------------------------------------- -bool RimEclipseResultDefinition::hasStaticResult() const -{ - if ( isFlowDiagOrInjectionFlooding() ) return false; - - const RigCaseCellResultsData* gridCellResults = this->currentGridCellResults(); - RigEclipseResultAddress gridScalarResultIndex = this->eclipseResultAddress(); - - if ( hasResult() && gridCellResults->timeStepCount( gridScalarResultIndex ) == 1 ) - { - return true; - } - else - { - return false; - } -} - -//-------------------------------------------------------------------------------------------------- -/// Returns whether the result requested by the definition is loaded or possible to load from the result file -//-------------------------------------------------------------------------------------------------- -bool RimEclipseResultDefinition::hasResult() const -{ - if ( isFlowDiagOrInjectionFlooding() ) - { - if ( m_flowSolution() && !m_resultVariable().isEmpty() ) return true; - } - else if ( this->currentGridCellResults() ) - { - const RigCaseCellResultsData* gridCellResults = this->currentGridCellResults(); - - return gridCellResults->hasResultEntry( this->eclipseResultAddress() ); - } - - return false; -} - -//-------------------------------------------------------------------------------------------------- -/// Returns whether the result requested by the definition is a multi frame result -/// The result needs to be loaded before asking -//-------------------------------------------------------------------------------------------------- -bool RimEclipseResultDefinition::hasDynamicResult() const -{ - if ( hasResult() ) - { - if ( m_resultType() == RiaDefines::ResultCatType::DYNAMIC_NATIVE ) - { - return true; - } - else if ( m_resultType() == RiaDefines::ResultCatType::SOURSIMRL ) - { - return true; - } - else if ( m_resultType() == RiaDefines::ResultCatType::FLOW_DIAGNOSTICS ) - { - return true; - } - else if ( m_resultType() == RiaDefines::ResultCatType::INJECTION_FLOODING ) - { - return true; - } - - if ( this->currentGridCellResults() ) - { - const RigCaseCellResultsData* gridCellResults = this->currentGridCellResults(); - RigEclipseResultAddress gridScalarResultIndex = this->eclipseResultAddress(); - if ( gridCellResults->timeStepCount( gridScalarResultIndex ) > 1 ) - { - return true; - } - } - } - - return false; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimEclipseResultDefinition::initAfterRead() -{ - if ( m_flowSolution() == nullptr ) - { - assignFlowSolutionFromCase(); - } - - if ( m_resultVariable == "Formation Allen" ) - { - m_resultVariable = RiaResultNames::formationAllanResultName(); - m_resultType = RiaDefines::ResultCatType::ALLAN_DIAGRAMS; - } - else if ( m_resultVariable == "Binary Formation Allen" ) - { - m_resultVariable = RiaResultNames::formationBinaryAllanResultName(); - m_resultType = RiaDefines::ResultCatType::ALLAN_DIAGRAMS; - } - - m_porosityModelUiField = m_porosityModel; - m_resultTypeUiField = m_resultType; - m_resultVariableUiField = m_resultVariable; - - m_flowSolutionUiField = m_flowSolution(); - m_selectedInjectorTracersUiField = m_selectedInjectorTracers; - - this->updateUiIconFromToggleField(); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimEclipseResultDefinition::setResultType( RiaDefines::ResultCatType val ) -{ - m_resultType = val; - m_resultTypeUiField = val; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimEclipseResultDefinition::setPorosityModel( RiaDefines::PorosityModelType val ) -{ - m_porosityModel = val; - m_porosityModelUiField = val; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimEclipseResultDefinition::setResultVariable( const QString& val ) -{ - m_resultVariable = val; - m_resultVariableUiField = val; -} - -//-------------------------------------------------------------------------------------------------- -/// Return phase type if the current result is known to be of a particular -/// fluid phase type. Otherwise the method will return PHASE_NOT_APPLICABLE. -//-------------------------------------------------------------------------------------------------- -RiaDefines::PhaseType RimEclipseResultDefinition::resultPhaseType() const -{ - if ( QRegularExpression( "OIL" ).match( m_resultVariable() ).hasMatch() ) - { - return RiaDefines::PhaseType::OIL_PHASE; - } - else if ( QRegularExpression( "GAS" ).match( m_resultVariable() ).hasMatch() ) - { - return RiaDefines::PhaseType::GAS_PHASE; - } - else if ( QRegularExpression( "WAT" ).match( m_resultVariable() ).hasMatch() ) - { - return RiaDefines::PhaseType::WATER_PHASE; - } - return RiaDefines::PhaseType::PHASE_NOT_APPLICABLE; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -RimFlowDiagSolution* RimEclipseResultDefinition::flowDiagSolution() const -{ - return m_flowSolution(); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimEclipseResultDefinition::setFlowSolution( RimFlowDiagSolution* flowSol ) -{ - this->m_flowSolution = flowSol; - this->m_flowSolutionUiField = flowSol; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimEclipseResultDefinition::setSelectedTracers( const std::vector& selectedTracers ) -{ - if ( m_flowSolution() == nullptr ) - { - assignFlowSolutionFromCase(); - } - if ( m_flowSolution() ) - { - std::vector injectorTracers; - std::vector producerTracers; - for ( const QString& tracerName : selectedTracers ) - { - RimFlowDiagSolution::TracerStatusType tracerStatus = m_flowSolution()->tracerStatusOverall( tracerName ); - if ( tracerStatus == RimFlowDiagSolution::TracerStatusType::INJECTOR ) - { - injectorTracers.push_back( tracerName ); - } - else if ( tracerStatus == RimFlowDiagSolution::TracerStatusType::PRODUCER ) - { - producerTracers.push_back( tracerName ); - } - else if ( tracerStatus == RimFlowDiagSolution::TracerStatusType::VARYING || - tracerStatus == RimFlowDiagSolution::TracerStatusType::UNDEFINED ) - { - injectorTracers.push_back( tracerName ); - producerTracers.push_back( tracerName ); - } - } - setSelectedInjectorTracers( injectorTracers ); - setSelectedProducerTracers( producerTracers ); - } -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimEclipseResultDefinition::setSelectedInjectorTracers( const std::vector& selectedTracers ) -{ - this->m_selectedInjectorTracers = selectedTracers; - this->m_selectedInjectorTracersUiField = selectedTracers; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimEclipseResultDefinition::setSelectedProducerTracers( const std::vector& selectedTracers ) -{ - this->m_selectedProducerTracers = selectedTracers; - this->m_selectedProducerTracersUiField = selectedTracers; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimEclipseResultDefinition::setSelectedSouringTracers( const std::vector& selectedTracers ) -{ - this->m_selectedSouringTracers = selectedTracers; - this->m_selectedSouringTracersUiField = selectedTracers; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimEclipseResultDefinition::updateUiFieldsFromActiveResult() -{ - m_resultTypeUiField = m_resultType; - m_resultVariableUiField = resultVariable(); - m_selectedInjectorTracersUiField = m_selectedInjectorTracers; - m_selectedProducerTracersUiField = m_selectedProducerTracers; - m_selectedSouringTracersUiField = m_selectedSouringTracers; - m_porosityModelUiField = m_porosityModel; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimEclipseResultDefinition::enableDeltaResults( bool enable ) -{ - m_isDeltaResultEnabled = enable; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -bool RimEclipseResultDefinition::isTernarySaturationSelected() const -{ - bool isTernary = - ( m_resultType() == RiaDefines::ResultCatType::DYNAMIC_NATIVE ) && - ( m_resultVariable().compare( RiaResultNames::ternarySaturationResultName(), Qt::CaseInsensitive ) == 0 ); - - return isTernary; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -bool RimEclipseResultDefinition::isCompletionTypeSelected() const -{ - return ( m_resultType() == RiaDefines::ResultCatType::DYNAMIC_NATIVE && - m_resultVariable() == RiaResultNames::completionTypeResultName() ); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -bool RimEclipseResultDefinition::hasCategoryResult() const -{ - if ( this->m_resultType() == RiaDefines::ResultCatType::FORMATION_NAMES && m_eclipseCase && - m_eclipseCase->eclipseCaseData() && !m_eclipseCase->eclipseCaseData()->formationNames().empty() ) - return true; - - if ( this->m_resultType() == RiaDefines::ResultCatType::DYNAMIC_NATIVE && - this->resultVariable() == RiaResultNames::completionTypeResultName() ) - return true; - - if ( this->m_resultType() == RiaDefines::ResultCatType::FLOW_DIAGNOSTICS && - m_resultVariable() == RIG_FLD_MAX_FRACTION_TRACER_RESNAME ) - return true; - - if ( this->resultVariable() == RiaResultNames::formationAllanResultName() || - this->resultVariable() == RiaResultNames::formationBinaryAllanResultName() ) - { - return true; - } - - if ( !this->hasStaticResult() ) return false; - - return RiaDefines::isNativeCategoryResult( this->resultVariable() ); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -bool RimEclipseResultDefinition::isFlowDiagOrInjectionFlooding() const -{ - if ( this->m_resultType() == RiaDefines::ResultCatType::FLOW_DIAGNOSTICS || - this->m_resultType() == RiaDefines::ResultCatType::INJECTION_FLOODING ) - { - return true; - } - - return false; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimEclipseResultDefinition::defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) -{ - uiOrdering.add( &m_resultTypeUiField ); - - if ( hasDualPorFractureResult() ) - { - uiOrdering.add( &m_porosityModelUiField ); - } - - if ( m_resultTypeUiField() == RiaDefines::ResultCatType::FLOW_DIAGNOSTICS ) - { - uiOrdering.add( &m_flowSolutionUiField ); - - uiOrdering.add( &m_flowTracerSelectionMode ); - - if ( m_flowTracerSelectionMode == FLOW_TR_BY_SELECTION ) - { - caf::PdmUiGroup* selectionGroup = uiOrdering.addNewGroup( "Tracer Selection" ); - selectionGroup->setEnableFrame( false ); - - caf::PdmUiGroup* injectorGroup = selectionGroup->addNewGroup( "Injectors" ); - injectorGroup->add( &m_selectedInjectorTracersUiField ); - injectorGroup->add( &m_syncInjectorToProducerSelection ); - - caf::PdmUiGroup* producerGroup = selectionGroup->addNewGroup( "Producers", false ); - producerGroup->add( &m_selectedProducerTracersUiField ); - producerGroup->add( &m_syncProducerToInjectorSelection ); - } - - uiOrdering.add( &m_phaseSelection ); - - if ( m_flowSolution() == nullptr ) - { - assignFlowSolutionFromCase(); - } - } - - if ( m_resultTypeUiField() == RiaDefines::ResultCatType::INJECTION_FLOODING ) - { - uiOrdering.add( &m_selectedSouringTracersUiField ); - } - - uiOrdering.add( &m_resultVariableUiField ); - if ( m_resultTypeUiField() == RiaDefines::ResultCatType::INPUT_PROPERTY ) - { - uiOrdering.add( &m_inputPropertyFileName ); - } - - if ( isDivideByCellFaceAreaPossible() ) - { - uiOrdering.add( &m_divideByCellFaceArea ); - - QString resultPropertyLabel = "Result Property"; - if ( isDivideByCellFaceAreaActive() ) - { - resultPropertyLabel += QString( "\nDivided by Area" ); - } - m_resultVariableUiField.uiCapability()->setUiName( resultPropertyLabel ); - } - - { - caf::PdmUiGroup* legendGroup = uiOrdering.addNewGroup( "Legend" ); - legendGroup->add( &m_showOnlyVisibleCategoriesInLegend ); - - bool showOnlyVisibleCategoriesOption = false; - - RimEclipseView* eclView = nullptr; - this->firstAncestorOrThisOfType( eclView ); - - if ( eclView ) - { - if ( eclView->cellResult() == this && this->hasCategoryResult() ) showOnlyVisibleCategoriesOption = true; - } - - if ( m_resultTypeUiField() == RiaDefines::ResultCatType::FLOW_DIAGNOSTICS && - m_resultVariableUiField() == RIG_FLD_MAX_FRACTION_TRACER_RESNAME ) - { - showOnlyVisibleCategoriesOption = true; - } - - legendGroup->setUiHidden( !showOnlyVisibleCategoriesOption ); - } - - if ( isDeltaCasePossible() || isDeltaTimeStepPossible() ) - { - caf::PdmUiGroup* differenceGroup = uiOrdering.addNewGroup( "Difference Options" ); - differenceGroup->setUiReadOnly( !( isDeltaTimeStepPossible() || isDeltaCasePossible() ) ); - - m_differenceCase.uiCapability()->setUiReadOnly( !isDeltaCasePossible() ); - m_timeLapseBaseTimestep.uiCapability()->setUiReadOnly( !isDeltaTimeStepPossible() ); - - if ( isDeltaCasePossible() ) differenceGroup->add( &m_differenceCase ); - if ( isDeltaTimeStepPossible() ) differenceGroup->add( &m_timeLapseBaseTimestep ); - - QString resultPropertyLabel = "Result Property"; - if ( isDeltaTimeStepActive() || isDeltaCaseActive() ) - { - resultPropertyLabel += QString( "\n%1" ).arg( additionalResultTextShort() ); - } - m_resultVariableUiField.uiCapability()->setUiName( resultPropertyLabel ); - } - - uiOrdering.skipRemainingFields( true ); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimEclipseResultDefinition::defineEditorAttribute( const caf::PdmFieldHandle* field, - QString uiConfigName, - caf::PdmUiEditorAttribute* attribute ) -{ - if ( m_resultTypeUiField() == RiaDefines::ResultCatType::FLOW_DIAGNOSTICS ) - { - if ( field == &m_resultVariableUiField ) - { - caf::PdmUiListEditorAttribute* listEditAttr = dynamic_cast( attribute ); - if ( listEditAttr ) - { - listEditAttr->m_heightHint = 50; - } - } - else if ( field == &m_syncInjectorToProducerSelection || field == &m_syncProducerToInjectorSelection ) - { - caf::PdmUiToolButtonEditorAttribute* toolButtonAttr = - dynamic_cast( attribute ); - if ( toolButtonAttr ) - { - toolButtonAttr->m_sizePolicy.setHorizontalPolicy( QSizePolicy::MinimumExpanding ); - } - } - } - if ( field == &m_resultVariableUiField ) - { - caf::PdmUiListEditorAttribute* listEditAttr = dynamic_cast( attribute ); - if ( listEditAttr ) - { - listEditAttr->m_allowHorizontalScrollBar = false; - } - } -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -bool RimEclipseResultDefinition::TracerComp::operator()( const QString& lhs, const QString& rhs ) const -{ - if ( !lhs.endsWith( "-XF" ) && rhs.endsWith( "-XF" ) ) - { - return true; - } - else if ( lhs.endsWith( "-XF" ) && !rhs.endsWith( "-XF" ) ) - { - return false; - } - else - { - return lhs < rhs; - } -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimEclipseResultDefinition::assignFlowSolutionFromCase() -{ - RimFlowDiagSolution* defaultFlowDiagSolution = nullptr; - - RimEclipseResultCase* eclCase = dynamic_cast( m_eclipseCase.p() ); - - if ( eclCase ) - { - defaultFlowDiagSolution = eclCase->defaultFlowDiagSolution(); - } - this->setFlowSolution( defaultFlowDiagSolution ); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -bool RimEclipseResultDefinition::hasDualPorFractureResult() -{ - if ( m_eclipseCase && m_eclipseCase->eclipseCaseData() ) - { - return m_eclipseCase->eclipseCaseData()->hasFractureResults(); - } - - return false; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -QString RimEclipseResultDefinition::flowDiagResUiText( bool shortLabel, int maxTracerStringLength ) const -{ - QString uiText = QString::fromStdString( flowDiagResAddress().variableName ); - if ( flowDiagResAddress().variableName == RIG_FLD_TOF_RESNAME ) - { - uiText = timeOfFlightString( shortLabel ); - } - else if ( flowDiagResAddress().variableName == RIG_FLD_MAX_FRACTION_TRACER_RESNAME ) - { - uiText = maxFractionTracerString( shortLabel ); - } - - QString tracersString = selectedTracersString(); - - if ( !tracersString.isEmpty() ) - { - const QString postfix = "..."; - - if ( tracersString.size() > maxTracerStringLength + postfix.size() ) - { - tracersString = tracersString.left( maxTracerStringLength ); - tracersString += postfix; - } - uiText += QString( "\n%1" ).arg( tracersString ); - } - return uiText; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -QList - RimEclipseResultDefinition::calcOptionsForVariableUiFieldStandard( RiaDefines::ResultCatType resultCatType, - const RigCaseCellResultsData* results, - bool showDerivedResultsFirst, - bool addPerCellFaceOptionItems, - bool ternaryEnabled ) -{ - CVF_ASSERT( resultCatType != RiaDefines::ResultCatType::FLOW_DIAGNOSTICS && - resultCatType != RiaDefines::ResultCatType::INJECTION_FLOODING ); - - if ( results ) - { - QList optionList; - - QStringList cellCenterResultNames; - QStringList cellFaceResultNames; - - for ( const QString& s : getResultNamesForResultType( resultCatType, results ) ) - { - if ( s == RiaResultNames::completionTypeResultName() ) - { - if ( results->timeStepDates().empty() ) continue; - } - - if ( RiaResultNames::isPerCellFaceResult( s ) ) - { - cellFaceResultNames.push_back( s ); - } - else - { - cellCenterResultNames.push_back( s ); - } - } - - cellCenterResultNames.sort(); - cellFaceResultNames.sort(); - - // Cell Center result names - for ( const QString& s : cellCenterResultNames ) - { - optionList.push_back( caf::PdmOptionItemInfo( s, s ) ); - } - - if ( addPerCellFaceOptionItems ) - { - for ( const QString& s : cellFaceResultNames ) - { - if ( showDerivedResultsFirst ) - { - optionList.push_front( caf::PdmOptionItemInfo( s, s ) ); - } - else - { - optionList.push_back( caf::PdmOptionItemInfo( s, s ) ); - } - } - - // Ternary Result - if ( ternaryEnabled ) - { - bool hasAtLeastOneTernaryComponent = false; - if ( cellCenterResultNames.contains( "SOIL" ) ) - hasAtLeastOneTernaryComponent = true; - else if ( cellCenterResultNames.contains( "SGAS" ) ) - hasAtLeastOneTernaryComponent = true; - else if ( cellCenterResultNames.contains( "SWAT" ) ) - hasAtLeastOneTernaryComponent = true; - - if ( resultCatType == RiaDefines::ResultCatType::DYNAMIC_NATIVE && hasAtLeastOneTernaryComponent ) - { - optionList.push_front( caf::PdmOptionItemInfo( RiaResultNames::ternarySaturationResultName(), - RiaResultNames::ternarySaturationResultName() ) ); - } - } - } - - optionList.push_front( - caf::PdmOptionItemInfo( RiaResultNames::undefinedResultName(), RiaResultNames::undefinedResultName() ) ); - - return optionList; - } - - return QList(); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimEclipseResultDefinition::setTernaryEnabled( bool enabled ) -{ - m_ternaryEnabled = enabled; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -bool operator<( const cvf::Color3ub first, const cvf::Color3ub second ) -{ - if ( first.r() != second.r() ) return first.r() < second.r(); - if ( first.g() != second.g() ) return first.g() < second.g(); - if ( first.b() != second.b() ) return first.b() < second.b(); - - return false; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -class TupleCompare -{ -public: - bool operator()( const std::tuple& t1, - const std::tuple& t2 ) const - { - using namespace std; - if ( get<0>( t1 ) != get<0>( t2 ) ) return get<0>( t1 ) < get<0>( t2 ); - if ( get<1>( t1 ) != get<1>( t2 ) ) return get<1>( t1 ) < get<1>( t2 ); - if ( get<2>( t1 ) != get<2>( t2 ) ) return get<2>( t1 ) < get<2>( t2 ); - - return false; - } -}; - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimEclipseResultDefinition::updateRangesForExplicitLegends( RimRegularLegendConfig* legendConfigToUpdate, - RimTernaryLegendConfig* ternaryLegendConfigToUpdate, - int currentTimeStep ) - -{ - RimEclipseCase* rimEclipseCase = this->eclipseCase(); - - if ( this->hasResult() ) - { - if ( this->isFlowDiagOrInjectionFlooding() ) - { - CVF_ASSERT( currentTimeStep >= 0 ); - - double globalMin, globalMax; - double globalPosClosestToZero, globalNegClosestToZero; - RigFlowDiagResults* flowResultsData = this->flowDiagSolution()->flowDiagResults(); - RigFlowDiagResultAddress resAddr = this->flowDiagResAddress(); - - flowResultsData->minMaxScalarValues( resAddr, currentTimeStep, &globalMin, &globalMax ); - flowResultsData->posNegClosestToZero( resAddr, currentTimeStep, &globalPosClosestToZero, &globalNegClosestToZero ); - - double localMin, localMax; - double localPosClosestToZero, localNegClosestToZero; - if ( this->hasDynamicResult() ) - { - flowResultsData->minMaxScalarValues( resAddr, currentTimeStep, &localMin, &localMax ); - flowResultsData->posNegClosestToZero( resAddr, currentTimeStep, &localPosClosestToZero, &localNegClosestToZero ); - } - else - { - localMin = globalMin; - localMax = globalMax; - - localPosClosestToZero = globalPosClosestToZero; - localNegClosestToZero = globalNegClosestToZero; - } - - CVF_ASSERT( legendConfigToUpdate ); - - legendConfigToUpdate->disableAllTimeStepsRange( true ); - legendConfigToUpdate->setClosestToZeroValues( globalPosClosestToZero, - globalNegClosestToZero, - localPosClosestToZero, - localNegClosestToZero ); - legendConfigToUpdate->setAutomaticRanges( globalMin, globalMax, localMin, localMax ); - - if ( this->hasCategoryResult() ) - { - RimEclipseView* eclView = nullptr; - this->firstAncestorOrThisOfType( eclView ); - - if ( eclView ) - { - std::set, TupleCompare> categories; - - std::vector tracerNames = this->flowDiagSolution()->tracerNames(); - int tracerIndex = 0; - - for ( const auto& tracerName : tracerNames ) - { - cvf::Color3ub color( cvf::Color3::GRAY ); - - RimSimWellInView* well = eclView->wellCollection()->findWell( - RimFlowDiagSolution::removeCrossFlowEnding( tracerName ) ); - - if ( well ) color = cvf::Color3ub( well->wellPipeColor() ); - - categories.insert( std::make_tuple( tracerName, tracerIndex, color ) ); - ++tracerIndex; - } - - std::vector> categoryVector; - - if ( m_showOnlyVisibleCategoriesInLegend ) - { - std::set visibleTracers = - RigVisibleCategoriesCalculator::visibleFlowDiagCategories( *eclView, - *flowResultsData, - resAddr, - currentTimeStep ); - for ( auto tupIt : categories ) - { - int tracerIndex = std::get<1>( tupIt ); - if ( visibleTracers.count( tracerIndex ) ) categoryVector.push_back( tupIt ); - } - } - else - { - for ( auto tupIt : categories ) - { - categoryVector.push_back( tupIt ); - } - } - - legendConfigToUpdate->setCategoryItems( categoryVector ); - } - } - } - else - { - if ( !rimEclipseCase ) return; - - RigEclipseCaseData* eclipseCaseData = rimEclipseCase->eclipseCaseData(); - if ( !eclipseCaseData ) return; - - RigCaseCellResultsData* cellResultsData = eclipseCaseData->results( this->porosityModel() ); - cellResultsData->ensureKnownResultLoaded( this->eclipseResultAddress() ); - - double globalMin, globalMax; - double globalPosClosestToZero, globalNegClosestToZero; - - cellResultsData->minMaxCellScalarValues( this->eclipseResultAddress(), globalMin, globalMax ); - cellResultsData->posNegClosestToZero( this->eclipseResultAddress(), - globalPosClosestToZero, - globalNegClosestToZero ); - - double localMin, localMax; - double localPosClosestToZero, localNegClosestToZero; - if ( this->hasDynamicResult() && currentTimeStep >= 0 ) - { - cellResultsData->minMaxCellScalarValues( this->eclipseResultAddress(), currentTimeStep, localMin, localMax ); - cellResultsData->posNegClosestToZero( this->eclipseResultAddress(), - currentTimeStep, - localPosClosestToZero, - localNegClosestToZero ); - } - else - { - localMin = globalMin; - localMax = globalMax; - - localPosClosestToZero = globalPosClosestToZero; - localNegClosestToZero = globalNegClosestToZero; - } - - CVF_ASSERT( legendConfigToUpdate ); - - legendConfigToUpdate->disableAllTimeStepsRange( false ); - legendConfigToUpdate->setClosestToZeroValues( globalPosClosestToZero, - globalNegClosestToZero, - localPosClosestToZero, - localNegClosestToZero ); - legendConfigToUpdate->setAutomaticRanges( globalMin, globalMax, localMin, localMax ); - - if ( this->hasCategoryResult() ) - { - if ( this->resultType() == RiaDefines::ResultCatType::ALLAN_DIAGRAMS ) - { - if ( this->resultVariable() == RiaResultNames::formationAllanResultName() ) - { - const std::vector fnVector = eclipseCaseData->formationNames(); - std::vector fnameIdxes; - for ( int i = 0; i < static_cast( fnVector.size() ); i++ ) - { - fnameIdxes.push_back( i ); - } - - cvf::Color3ubArray legendBaseColors = legendConfigToUpdate->colorLegend()->colorArray(); - - cvf::ref formationColorMapper = new caf::CategoryMapper; - formationColorMapper->setCategories( fnameIdxes ); - formationColorMapper->setInterpolateColors( legendBaseColors ); - - const std::map, int>& formationCombToCategory = - eclipseCaseData->allanDiagramData()->formationCombinationToCategory(); - - std::vector> categories; - for ( int frmNameIdx : fnameIdxes ) - { - cvf::Color3ub formationColor = formationColorMapper->mapToColor( frmNameIdx ); - categories.emplace_back( std::make_tuple( fnVector[frmNameIdx], frmNameIdx, formationColor ) ); - } - - std::set visibleAllanCategories; - { - RimEclipseView* eclView = nullptr; - this->firstAncestorOrThisOfType( eclView ); - - visibleAllanCategories = RigVisibleCategoriesCalculator::visibleAllanCategories( eclView ); - } - - for ( auto [formationPair, categoryIndex] : formationCombToCategory ) - { - int frmIdx1 = formationPair.first; - int frmIdx2 = formationPair.second; - - if ( visibleAllanCategories.count( categoryIndex ) == 0 ) continue; - - int fnVectorSize = static_cast( fnVector.size() ); - if ( frmIdx1 >= fnVectorSize || frmIdx2 >= fnVectorSize ) continue; - - QString frmName1 = fnVector[frmIdx1]; - QString frmName2 = fnVector[frmIdx2]; - - cvf::Color3f formationColor1 = cvf::Color3f( formationColorMapper->mapToColor( frmIdx1 ) ); - cvf::Color3f formationColor2 = cvf::Color3f( formationColorMapper->mapToColor( frmIdx2 ) ); - - cvf::Color3ub blendColor = - cvf::Color3ub( RiaColorTools::blendCvfColors( formationColor1, formationColor2 ) ); - - categories.emplace_back( - std::make_tuple( frmName1 + "-" + frmName2, categoryIndex, blendColor ) ); - } - - legendConfigToUpdate->setCategoryItems( categories ); - } - else if ( this->resultVariable() == RiaResultNames::formationBinaryAllanResultName() ) - { - std::vector> categories; - categories.emplace_back( std::make_tuple( "Same formation", 0, cvf::Color3ub::BROWN ) ); - categories.emplace_back( std::make_tuple( "Different formation", 1, cvf::Color3ub::ORANGE ) ); - - legendConfigToUpdate->setCategoryItems( categories ); - } - } - else if ( this->resultType() == RiaDefines::ResultCatType::DYNAMIC_NATIVE && - this->resultVariable() == RiaResultNames::completionTypeResultName() ) - { - const std::vector& visibleCategories = - cellResultsData->uniqueCellScalarValues( this->eclipseResultAddress() ); - - std::vector supportedCompletionTypes = - { RiaDefines::WellPathComponentType::WELL_PATH, - RiaDefines::WellPathComponentType::FISHBONES, - RiaDefines::WellPathComponentType::PERFORATION_INTERVAL, - RiaDefines::WellPathComponentType::FRACTURE }; - - RiaColorTables::WellPathComponentColors colors = RiaColorTables::wellPathComponentColors(); - - std::vector> categories; - for ( auto completionType : supportedCompletionTypes ) - { - if ( std::find( visibleCategories.begin(), - visibleCategories.end(), - static_cast( completionType ) ) != visibleCategories.end() ) - { - QString categoryText = - caf::AppEnum::uiText( completionType ); - categories.push_back( std::make_tuple( categoryText, - static_cast( completionType ), - colors[completionType] ) ); - } - } - - legendConfigToUpdate->setCategoryItems( categories ); - } - else - { - auto uniqueValues = cellResultsData->uniqueCellScalarValues( this->eclipseResultAddress() ); - if ( this->eclipseResultAddress().resultCatType() == RiaDefines::ResultCatType::FORMATION_NAMES ) - { - std::vector fnVector = eclipseCaseData->formationNames(); - uniqueValues.resize( fnVector.size() ); - std::iota( uniqueValues.begin(), uniqueValues.end(), 0 ); - } - - cvf::Color3ubArray legendBaseColors = legendConfigToUpdate->colorLegend()->colorArray(); - - cvf::ref categoryMapper = new caf::CategoryMapper; - categoryMapper->setCategories( uniqueValues ); - categoryMapper->setInterpolateColors( legendBaseColors ); - - std::vector visibleCategoryValues = uniqueValues; - - if ( m_showOnlyVisibleCategoriesInLegend ) - { - RimEclipseView* eclView = nullptr; - this->firstAncestorOrThisOfType( eclView ); - if ( eclView && eclView->showWindow() ) - { - // Check if current result is cell result, and update the visible set of values - // TODO: Can be extended to the separate geometry results (separate fault result, separate - // intersection results), but this requires some refactoring - if ( eclView->cellResult() == this ) - { - std::set visibleCategorySet = - RigVisibleCategoriesCalculator::visibleCategories( eclView ); - - visibleCategoryValues.clear(); - visibleCategoryValues.insert( visibleCategoryValues.begin(), - visibleCategorySet.begin(), - visibleCategorySet.end() ); - } - } - } - std::vector> categoryVector; - - for ( auto value : visibleCategoryValues ) - { - cvf::Color3ub categoryColor = categoryMapper->mapToColor( value ); - - QString valueTxt; - if ( this->resultType() == RiaDefines::ResultCatType::FORMATION_NAMES ) - { - std::vector fnVector = eclipseCaseData->formationNames(); - - if ( value < static_cast( fnVector.size() ) ) - { - valueTxt = fnVector[value]; - } - } - else - valueTxt = QString( "%1" ).arg( value ); - - categoryVector.push_back( std::make_tuple( valueTxt, value, categoryColor ) ); - } - legendConfigToUpdate->setCategoryItems( categoryVector ); - } - } - } - } - - // Ternary legend update - { - if ( !rimEclipseCase ) return; - - RigEclipseCaseData* eclipseCase = rimEclipseCase->eclipseCaseData(); - if ( !eclipseCase ) return; - - RigCaseCellResultsData* cellResultsData = eclipseCase->results( this->porosityModel() ); - - size_t maxTimeStepCount = cellResultsData->maxTimeStepCount(); - if ( this->isTernarySaturationSelected() && maxTimeStepCount > 1 ) - { - RigCaseCellResultsData* gridCellResults = this->currentGridCellResults(); - { - RigEclipseResultAddress resAddr( RiaDefines::ResultCatType::DYNAMIC_NATIVE, "SOIL" ); - - if ( gridCellResults->ensureKnownResultLoaded( resAddr ) ) - { - double globalMin = 0.0; - double globalMax = 1.0; - double localMin = 0.0; - double localMax = 1.0; - - cellResultsData->minMaxCellScalarValues( resAddr, globalMin, globalMax ); - cellResultsData->minMaxCellScalarValues( resAddr, currentTimeStep, localMin, localMax ); - - ternaryLegendConfigToUpdate->setAutomaticRanges( RimTernaryLegendConfig::TERNARY_SOIL_IDX, - globalMin, - globalMax, - localMin, - localMax ); - } - } - - { - RigEclipseResultAddress resAddr( RiaDefines::ResultCatType::DYNAMIC_NATIVE, "SGAS" ); - - if ( gridCellResults->ensureKnownResultLoaded( resAddr ) ) - { - double globalMin = 0.0; - double globalMax = 1.0; - double localMin = 0.0; - double localMax = 1.0; - - cellResultsData->minMaxCellScalarValues( resAddr, globalMin, globalMax ); - cellResultsData->minMaxCellScalarValues( resAddr, currentTimeStep, localMin, localMax ); - - ternaryLegendConfigToUpdate->setAutomaticRanges( RimTernaryLegendConfig::TERNARY_SGAS_IDX, - globalMin, - globalMax, - localMin, - localMax ); - } - } - - { - RigEclipseResultAddress resAddr( RiaDefines::ResultCatType::DYNAMIC_NATIVE, "SWAT" ); - - if ( gridCellResults->ensureKnownResultLoaded( resAddr ) ) - { - double globalMin = 0.0; - double globalMax = 1.0; - double localMin = 0.0; - double localMax = 1.0; - - cellResultsData->minMaxCellScalarValues( resAddr, globalMin, globalMax ); - cellResultsData->minMaxCellScalarValues( resAddr, currentTimeStep, localMin, localMax ); - - ternaryLegendConfigToUpdate->setAutomaticRanges( RimTernaryLegendConfig::TERNARY_SWAT_IDX, - globalMin, - globalMax, - localMin, - localMax ); - } - } - } - } -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimEclipseResultDefinition::updateLegendTitle( RimRegularLegendConfig* legendConfig, const QString& legendHeading ) -{ - QString title = legendHeading + this->resultVariableUiName(); - if ( !this->additionalResultTextShort().isEmpty() ) - { - title += additionalResultTextShort(); - } - - if ( this->hasDualPorFractureResult() ) - { - QString porosityModelText = caf::AppEnum::uiText( this->porosityModel() ); - - title += QString( "\nDual Por : %1" ).arg( porosityModelText ); - } - - legendConfig->setTitle( title ); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -QList RimEclipseResultDefinition::calcOptionsForSelectedTracerField( bool injector ) -{ - QList options; - - RimFlowDiagSolution* flowSol = m_flowSolutionUiField(); - if ( flowSol ) - { - std::set sortedTracers = setOfTracersOfType( injector ); - - for ( const QString& tracerName : sortedTracers ) - { - QString postfix; - RimFlowDiagSolution::TracerStatusType status = flowSol->tracerStatusOverall( tracerName ); - if ( status == RimFlowDiagSolution::TracerStatusType::VARYING ) - { - postfix = " [I/P]"; - } - else if ( status == RimFlowDiagSolution::TracerStatusType::UNDEFINED ) - { - postfix = " [U]"; - } - options.push_back( caf::PdmOptionItemInfo( tracerName + postfix, tracerName ) ); - } - } - return options; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -QString RimEclipseResultDefinition::timeOfFlightString( bool shorter ) const -{ - QString tofString; - bool multipleSelected = false; - if ( injectorSelectionState() != NONE_SELECTED && producerSelectionState() != NONE_SELECTED ) - { - tofString = shorter ? "Res.Time" : "Residence Time"; - multipleSelected = true; - } - else if ( injectorSelectionState() != NONE_SELECTED ) - { - tofString = shorter ? "Fwd.TOF" : "Forward Time of Flight"; - } - else if ( producerSelectionState() != NONE_SELECTED ) - { - tofString = shorter ? "Rev.TOF" : "Reverse Time of Flight"; - } - else - { - tofString = shorter ? "TOF" : "Time of Flight"; - } - - multipleSelected = multipleSelected || injectorSelectionState() >= MULTIPLE_SELECTED || - producerSelectionState() >= MULTIPLE_SELECTED; - - if ( multipleSelected && !shorter ) - { - tofString += " (Average)"; - } - - tofString += " [days]"; - // Conversion from seconds in flow module to days is done in RigFlowDiagTimeStepResult::setTracerTOF() - - return tofString; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -QString RimEclipseResultDefinition::maxFractionTracerString( bool shorter ) const -{ - QString mfString; - if ( injectorSelectionState() >= ONE_SELECTED && producerSelectionState() == NONE_SELECTED ) - { - mfString = shorter ? "FloodReg" : "Flooding Region"; - if ( injectorSelectionState() >= MULTIPLE_SELECTED ) mfString += "s"; - } - else if ( injectorSelectionState() == NONE_SELECTED && producerSelectionState() >= ONE_SELECTED ) - { - mfString = shorter ? "DrainReg" : "Drainage Region"; - if ( producerSelectionState() >= MULTIPLE_SELECTED ) mfString += "s"; - } - else - { - mfString = shorter ? "Drain&FloodReg" : "Drainage/Flooding Regions"; - } - return mfString; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -QString RimEclipseResultDefinition::selectedTracersString() const -{ - QStringList fullTracersList; - - FlowTracerSelectionState injectorState = injectorSelectionState(); - FlowTracerSelectionState producerState = producerSelectionState(); - - if ( injectorState == ALL_SELECTED && producerState == ALL_SELECTED ) - { - fullTracersList += caf::AppEnum::uiText( FLOW_TR_INJ_AND_PROD ); - } - else - { - if ( injectorState == ALL_SELECTED ) - { - fullTracersList += caf::AppEnum::uiText( FLOW_TR_INJECTORS ); - } - - if ( producerState == ALL_SELECTED ) - { - fullTracersList += caf::AppEnum::uiText( FLOW_TR_PRODUCERS ); - } - - if ( injectorSelectionState() == ONE_SELECTED || injectorSelectionState() == MULTIPLE_SELECTED ) - { - QStringList listOfSelectedInjectors; - for ( const QString& injector : m_selectedInjectorTracers() ) - { - listOfSelectedInjectors.push_back( injector ); - } - if ( !listOfSelectedInjectors.empty() ) - { - fullTracersList += listOfSelectedInjectors.join( ", " ); - } - } - - if ( producerSelectionState() == ONE_SELECTED || producerSelectionState() == MULTIPLE_SELECTED ) - { - QStringList listOfSelectedProducers; - for ( const QString& producer : m_selectedProducerTracers() ) - { - listOfSelectedProducers.push_back( producer ); - } - if ( !listOfSelectedProducers.empty() ) - { - fullTracersList.push_back( listOfSelectedProducers.join( ", " ) ); - } - } - } - - QString tracersText; - if ( !fullTracersList.empty() ) - { - tracersText = fullTracersList.join( ", " ); - } - return tracersText; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -QStringList RimEclipseResultDefinition::getResultNamesForResultType( RiaDefines::ResultCatType resultCatType, - const RigCaseCellResultsData* results ) -{ - if ( resultCatType != RiaDefines::ResultCatType::FLOW_DIAGNOSTICS ) - { - if ( !results ) return QStringList(); - - return results->resultNames( resultCatType ); - } - else - { - QStringList flowVars; - flowVars.push_back( RIG_FLD_TOF_RESNAME ); - flowVars.push_back( RIG_FLD_CELL_FRACTION_RESNAME ); - flowVars.push_back( RIG_FLD_MAX_FRACTION_TRACER_RESNAME ); - flowVars.push_back( RIG_FLD_COMMUNICATION_RESNAME ); - return flowVars; - } -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -std::vector RimEclipseResultDefinition::allTracerNames() const -{ - std::vector tracerNames; - - RimFlowDiagSolution* flowSol = m_flowSolutionUiField(); - if ( flowSol ) - { - tracerNames = flowSol->tracerNames(); - } - - return tracerNames; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -std::set RimEclipseResultDefinition::setOfTracersOfType( bool injector ) const -{ - std::set sortedTracers; - - RimFlowDiagSolution* flowSol = m_flowSolutionUiField(); - if ( flowSol ) - { - std::vector tracerNames = allTracerNames(); - for ( const QString& tracerName : tracerNames ) - { - RimFlowDiagSolution::TracerStatusType status = flowSol->tracerStatusOverall( tracerName ); - bool includeTracer = status == RimFlowDiagSolution::TracerStatusType::VARYING || - status == RimFlowDiagSolution::TracerStatusType::UNDEFINED; - includeTracer |= injector && status == RimFlowDiagSolution::TracerStatusType::INJECTOR; - includeTracer |= !injector && status == RimFlowDiagSolution::TracerStatusType::PRODUCER; - - if ( includeTracer ) - { - sortedTracers.insert( tracerName ); - } - } - } - return sortedTracers; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -RimEclipseResultDefinition::FlowTracerSelectionState RimEclipseResultDefinition::injectorSelectionState() const -{ - if ( m_flowTracerSelectionMode == FLOW_TR_INJECTORS || m_flowTracerSelectionMode == FLOW_TR_INJ_AND_PROD ) - { - return ALL_SELECTED; - } - else if ( m_flowTracerSelectionMode == FLOW_TR_BY_SELECTION ) - { - if ( m_selectedInjectorTracers().size() == setOfTracersOfType( true ).size() ) - { - return ALL_SELECTED; - } - else if ( m_selectedInjectorTracers().size() == (size_t)1 ) - { - return ONE_SELECTED; - } - else if ( m_selectedInjectorTracers().size() > (size_t)1 ) - { - return MULTIPLE_SELECTED; - } - } - return NONE_SELECTED; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -RimEclipseResultDefinition::FlowTracerSelectionState RimEclipseResultDefinition::producerSelectionState() const -{ - if ( m_flowTracerSelectionMode == FLOW_TR_PRODUCERS || m_flowTracerSelectionMode == FLOW_TR_INJ_AND_PROD ) - { - return ALL_SELECTED; - } - else if ( m_flowTracerSelectionMode == FLOW_TR_BY_SELECTION ) - { - if ( m_selectedProducerTracers().size() == setOfTracersOfType( false ).size() ) - { - return ALL_SELECTED; - } - else if ( m_selectedProducerTracers().size() == (size_t)1 ) - { - return ONE_SELECTED; - } - else if ( m_selectedProducerTracers().size() > (size_t)1 ) - { - return MULTIPLE_SELECTED; - } - } - return NONE_SELECTED; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimEclipseResultDefinition::syncInjectorToProducerSelection() -{ - const double epsilon = 1.0e-8; - - int timeStep = 0; - - Rim3dView* rimView = nullptr; - this->firstAncestorOrThisOfType( rimView ); - if ( rimView ) - { - timeStep = rimView->currentTimeStep(); - } - - RimFlowDiagSolution* flowSol = m_flowSolution(); - if ( flowSol && m_flowTracerSelectionMode == FLOW_TR_BY_SELECTION ) - { - std::set producers = setOfTracersOfType( false ); - - std::set newProducerSelection; - for ( const QString& selectedInjector : m_selectedInjectorTracers() ) - { - for ( const QString& producer : producers ) - { - std::pair commFluxes = - flowSol->flowDiagResults()->injectorProducerPairFluxes( selectedInjector.toStdString(), - producer.toStdString(), - timeStep ); - if ( std::abs( commFluxes.first ) > epsilon || std::abs( commFluxes.second ) > epsilon ) - { - newProducerSelection.insert( producer ); - } - } - } - // Add all currently selected producers to set - for ( const QString& selectedProducer : m_selectedProducerTracers() ) - { - newProducerSelection.insert( selectedProducer ); - } - std::vector newProducerVector( newProducerSelection.begin(), newProducerSelection.end() ); - setSelectedProducerTracers( newProducerVector ); - } -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimEclipseResultDefinition::syncProducerToInjectorSelection() -{ - const double epsilon = 1.0e-8; - - int timeStep = 0; - - Rim3dView* rimView = nullptr; - this->firstAncestorOrThisOfType( rimView ); - if ( rimView ) - { - timeStep = rimView->currentTimeStep(); - } - - RimFlowDiagSolution* flowSol = m_flowSolution(); - if ( flowSol && m_flowTracerSelectionMode == FLOW_TR_BY_SELECTION ) - { - std::set injectors = setOfTracersOfType( true ); - - std::set newInjectorSelection; - for ( const QString& selectedProducer : m_selectedProducerTracers() ) - { - for ( const QString& injector : injectors ) - { - std::pair commFluxes = - flowSol->flowDiagResults()->injectorProducerPairFluxes( injector.toStdString(), - selectedProducer.toStdString(), - timeStep ); - if ( std::abs( commFluxes.first ) > epsilon || std::abs( commFluxes.second ) > epsilon ) - { - newInjectorSelection.insert( injector ); - } - } - } - // Add all currently selected injectors to set - for ( const QString& selectedInjector : m_selectedInjectorTracers() ) - { - newInjectorSelection.insert( selectedInjector ); - } - std::vector newInjectorVector( newInjectorSelection.begin(), newInjectorSelection.end() ); - setSelectedInjectorTracers( newInjectorVector ); - } -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -bool RimEclipseResultDefinition::isDeltaResultEnabled() const -{ - return m_isDeltaResultEnabled; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -bool RimEclipseResultDefinition::isDeltaTimeStepPossible() const -{ - return isDeltaResultEnabled() && m_resultTypeUiField() == RiaDefines::ResultCatType::DYNAMIC_NATIVE && - !isTernarySaturationSelected(); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -bool RimEclipseResultDefinition::isDeltaTimeStepActive() const -{ - return isDeltaTimeStepPossible() && m_timeLapseBaseTimestep() >= 0; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -bool RimEclipseResultDefinition::isDeltaCasePossible() const -{ - return isDeltaResultEnabled() && !isTernarySaturationSelected() && - ( m_resultTypeUiField() == RiaDefines::ResultCatType::DYNAMIC_NATIVE || - m_resultTypeUiField() == RiaDefines::ResultCatType::STATIC_NATIVE || - m_resultTypeUiField() == RiaDefines::ResultCatType::GENERATED ); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -bool RimEclipseResultDefinition::isDeltaCaseActive() const -{ - return isDeltaCasePossible() && m_differenceCase() != nullptr; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -bool RimEclipseResultDefinition::isDivideByCellFaceAreaPossible() const -{ - QString str = m_resultVariable; - - // TODO : Move to RiaDefines or a separate file for cell face results - - if ( str == "FLRWATI+" ) return true; - if ( str == "FLRWATJ+" ) return true; - if ( str == "FLRWATK+" ) return true; - - if ( str == "FLROILI+" ) return true; - if ( str == "FLROILJ+" ) return true; - if ( str == "FLROILK+" ) return true; - - if ( str == "FLRGASI+" ) return true; - if ( str == "FLRGASJ+" ) return true; - if ( str == "FLRGASK+" ) return true; - - if ( str == "TRANX" ) return true; - if ( str == "TRANY" ) return true; - if ( str == "TRANZ" ) return true; - - if ( str == "riTRANX" ) return true; - if ( str == "riTRANY" ) return true; - if ( str == "riTRANZ" ) return true; - - return false; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -bool RimEclipseResultDefinition::isDivideByCellFaceAreaActive() const -{ - return isDivideByCellFaceAreaPossible() && m_divideByCellFaceArea; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -bool RimEclipseResultDefinition::showDerivedResultsFirstInVariableUiField() const -{ - // Cell Face result names - bool showDerivedResultsFirstInList = false; - RimEclipseFaultColors* rimEclipseFaultColors = nullptr; - this->firstAncestorOrThisOfType( rimEclipseFaultColors ); - - if ( rimEclipseFaultColors ) showDerivedResultsFirstInList = true; - - return showDerivedResultsFirstInList; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -bool RimEclipseResultDefinition::addPerCellFaceOptionsForVariableUiField() const -{ - RimPlotCurve* curve = nullptr; - this->firstAncestorOrThisOfType( curve ); - - RimEclipsePropertyFilter* propFilter = nullptr; - this->firstAncestorOrThisOfType( propFilter ); - - RimCellEdgeColors* cellEdge = nullptr; - this->firstAncestorOrThisOfType( cellEdge ); - - if ( propFilter || curve || cellEdge ) - { - return false; - } - - return true; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -QString RimEclipseResultDefinition::getInputPropertyFileName( const QString& resultName ) const -{ - RimEclipseCase* eclipseCase; - this->firstAncestorOrThisOfType( eclipseCase ); - - if ( eclipseCase ) - { - RimEclipseInputPropertyCollection* inputPropertyCollection = eclipseCase->inputPropertyCollection(); - if ( inputPropertyCollection ) - { - RimEclipseInputProperty* inputProperty = inputPropertyCollection->findInputProperty( resultName ); - if ( inputProperty ) - { - return inputProperty->fileName.v().path(); - } - } - } - - return ""; -} +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2011- Statoil ASA +// Copyright (C) 2013- Ceetron Solutions AS +// Copyright (C) 2011-2012 Ceetron AS +// +// ResInsight is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. +// +// See the GNU General Public License at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RimEclipseResultDefinition.h" + +#include "RiaColorTables.h" +#include "RiaColorTools.h" +#include "RiaLogging.h" +#include "RiaNncDefines.h" +#include "RiaQDateTimeTools.h" + +#include "RicfCommandObject.h" + +#include "RigActiveCellInfo.h" +#include "RigAllanDiagramData.h" +#include "RigCaseCellResultsData.h" +#include "RigEclipseCaseData.h" +#include "RigEclipseResultInfo.h" +#include "RigFlowDiagResultAddress.h" +#include "RigFlowDiagResults.h" +#include "RigFormationNames.h" +#include "RigVisibleCategoriesCalculator.h" + +#include "Rim3dView.h" +#include "Rim3dWellLogCurve.h" +#include "RimCellEdgeColors.h" +#include "RimColorLegend.h" +#include "RimContourMapProjection.h" +#include "RimEclipseCase.h" +#include "RimEclipseCellColors.h" +#include "RimEclipseContourMapProjection.h" +#include "RimEclipseContourMapView.h" +#include "RimEclipseFaultColors.h" +#include "RimEclipseInputProperty.h" +#include "RimEclipseInputPropertyCollection.h" +#include "RimEclipsePropertyFilter.h" +#include "RimEclipseResultCase.h" +#include "RimEclipseView.h" +#include "RimFlowDiagSolution.h" +#include "RimGridCrossPlot.h" +#include "RimGridCrossPlotDataSet.h" +#include "RimGridTimeHistoryCurve.h" +#include "RimIntersectionCollection.h" +#include "RimIntersectionResultDefinition.h" +#include "RimPlotCurve.h" +#include "RimProject.h" +#include "RimReservoirCellResultsStorage.h" +#include "RimSimWellInView.h" +#include "RimSimWellInViewCollection.h" +#include "RimTernaryLegendConfig.h" +#include "RimViewLinker.h" +#include "RimWellLogExtractionCurve.h" +#include "RimWellLogTrack.h" + +#ifdef USE_QTCHARTS +#include "RimGridStatisticsPlot.h" +#endif + +#include "cafCategoryMapper.h" +#include "cafPdmFieldScriptingCapability.h" +#include "cafPdmUiListEditor.h" +#include "cafPdmUiToolButtonEditor.h" +#include "cafPdmUiTreeSelectionEditor.h" +#include "cafUtils.h" + +#include + +namespace caf +{ +template <> +void RimEclipseResultDefinition::FlowTracerSelectionEnum::setUp() +{ + addItem( RimEclipseResultDefinition::FLOW_TR_INJ_AND_PROD, "FLOW_TR_INJ_AND_PROD", "All Injectors and Producers" ); + addItem( RimEclipseResultDefinition::FLOW_TR_PRODUCERS, "FLOW_TR_PRODUCERS", "All Producers" ); + addItem( RimEclipseResultDefinition::FLOW_TR_INJECTORS, "FLOW_TR_INJECTORS", "All Injectors" ); + addItem( RimEclipseResultDefinition::FLOW_TR_BY_SELECTION, "FLOW_TR_BY_SELECTION", "By Selection" ); + + setDefault( RimEclipseResultDefinition::FLOW_TR_INJ_AND_PROD ); +} +} // namespace caf + +CAF_PDM_SOURCE_INIT( RimEclipseResultDefinition, "ResultDefinition" ); + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimEclipseResultDefinition::RimEclipseResultDefinition( caf::PdmUiItemInfo::LabelPosType labelPosition ) + : m_isDeltaResultEnabled( false ) + , m_labelPosition( labelPosition ) + , m_ternaryEnabled( true ) +{ + CAF_PDM_InitScriptableObjectWithNameAndComment( "Result Definition", "", "", "", "EclipseResult", "An eclipse result definition" ); + + CAF_PDM_InitScriptableFieldNoDefault( &m_resultType, "ResultType", "Type", "", "", "" ); + m_resultType.uiCapability()->setUiHidden( true ); + + CAF_PDM_InitScriptableFieldNoDefault( &m_porosityModel, "PorosityModelType", "Porosity", "", "", "" ); + m_porosityModel.uiCapability()->setUiHidden( true ); + + CAF_PDM_InitScriptableField( &m_resultVariable, + "ResultVariable", + RiaResultNames::undefinedResultName(), + "Variable", + "", + "", + "" ); + m_resultVariable.uiCapability()->setUiHidden( true ); + + CAF_PDM_InitFieldNoDefault( &m_flowSolution, "FlowDiagSolution", "Solution", "", "", "" ); + m_flowSolution.uiCapability()->setUiHidden( true ); + + CAF_PDM_InitField( &m_timeLapseBaseTimestep, + "TimeLapseBaseTimeStep", + RigEclipseResultAddress::noTimeLapseValue(), + "Base Time Step", + "", + "", + "" ); + + CAF_PDM_InitFieldNoDefault( &m_differenceCase, "DifferenceCase", "Difference Case", "", "", "" ); + + CAF_PDM_InitField( &m_divideByCellFaceArea, "DivideByCellFaceArea", false, "Divide By Area", "", "", "" ); + + CAF_PDM_InitScriptableFieldNoDefault( &m_selectedInjectorTracers, "SelectedInjectorTracers", "Injector Tracers", "", "", "" ); + m_selectedInjectorTracers.uiCapability()->setUiHidden( true ); + + CAF_PDM_InitScriptableFieldNoDefault( &m_selectedProducerTracers, "SelectedProducerTracers", "Producer Tracers", "", "", "" ); + m_selectedProducerTracers.uiCapability()->setUiHidden( true ); + + CAF_PDM_InitScriptableFieldNoDefault( &m_selectedSouringTracers, "SelectedSouringTracers", "Tracers", "", "", "" ); + m_selectedSouringTracers.uiCapability()->setUiHidden( true ); + + CAF_PDM_InitScriptableFieldNoDefault( &m_flowTracerSelectionMode, "FlowTracerSelectionMode", "Tracers", "", "", "" ); + CAF_PDM_InitScriptableFieldNoDefault( &m_phaseSelection, "PhaseSelection", "Phases", "", "", "" ); + m_phaseSelection.uiCapability()->setUiLabelPosition( m_labelPosition ); + + CAF_PDM_InitScriptableField( &m_showOnlyVisibleCategoriesInLegend, + "ShowOnlyVisibleCategoriesInLegend", + true, + "Show Only Visible Categories In Legend", + "", + "", + "" ); + + // Ui only fields + + CAF_PDM_InitFieldNoDefault( &m_resultTypeUiField, "MResultType", "Type", "", "", "" ); + m_resultTypeUiField.xmlCapability()->disableIO(); + m_resultTypeUiField.uiCapability()->setUiLabelPosition( m_labelPosition ); + + CAF_PDM_InitFieldNoDefault( &m_porosityModelUiField, "MPorosityModelType", "Porosity", "", "", "" ); + m_porosityModelUiField.xmlCapability()->disableIO(); + m_porosityModelUiField.uiCapability()->setUiLabelPosition( m_labelPosition ); + + CAF_PDM_InitField( &m_resultVariableUiField, + "MResultVariable", + RiaResultNames::undefinedResultName(), + "Result Property", + "", + "", + "" ); + m_resultVariableUiField.xmlCapability()->disableIO(); + m_resultVariableUiField.uiCapability()->setUiEditorTypeName( caf::PdmUiListEditor::uiEditorTypeName() ); + m_resultVariableUiField.uiCapability()->setUiLabelPosition( m_labelPosition ); + + CAF_PDM_InitFieldNoDefault( &m_inputPropertyFileName, "InputPropertyFileName", "File Name", "", "", "" ); + m_inputPropertyFileName.xmlCapability()->disableIO(); + m_inputPropertyFileName.uiCapability()->setUiReadOnly( true ); + + CAF_PDM_InitFieldNoDefault( &m_flowSolutionUiField, "MFlowDiagSolution", "Solution", "", "", "" ); + m_flowSolutionUiField.xmlCapability()->disableIO(); + m_flowSolutionUiField.uiCapability()->setUiHidden( true ); // For now since there are only one to choose from + + CAF_PDM_InitField( &m_syncInjectorToProducerSelection, "MSyncSelectedInjProd", false, "Add Communicators ->", "", "", "" ); + m_syncInjectorToProducerSelection.uiCapability()->setUiEditorTypeName( caf::PdmUiToolButtonEditor::uiEditorTypeName() ); + + CAF_PDM_InitField( &m_syncProducerToInjectorSelection, "MSyncSelectedProdInj", false, "<- Add Communicators", "", "", "" ); + m_syncProducerToInjectorSelection.uiCapability()->setUiEditorTypeName( caf::PdmUiToolButtonEditor::uiEditorTypeName() ); + + CAF_PDM_InitFieldNoDefault( &m_selectedInjectorTracersUiField, "MSelectedInjectorTracers", "Injector Tracers", "", "", "" ); + m_selectedInjectorTracersUiField.xmlCapability()->disableIO(); + m_selectedInjectorTracersUiField.uiCapability()->setUiEditorTypeName( + caf::PdmUiTreeSelectionEditor::uiEditorTypeName() ); + m_selectedInjectorTracersUiField.uiCapability()->setUiLabelPosition( caf::PdmUiItemInfo::HIDDEN ); + + CAF_PDM_InitFieldNoDefault( &m_selectedProducerTracersUiField, "MSelectedProducerTracers", "Producer Tracers", "", "", "" ); + m_selectedProducerTracersUiField.xmlCapability()->disableIO(); + m_selectedProducerTracersUiField.uiCapability()->setUiEditorTypeName( + caf::PdmUiTreeSelectionEditor::uiEditorTypeName() ); + m_selectedProducerTracersUiField.uiCapability()->setUiLabelPosition( caf::PdmUiItemInfo::HIDDEN ); + + CAF_PDM_InitFieldNoDefault( &m_selectedSouringTracersUiField, "MSelectedSouringTracers", "Tracers", "", "", "" ); + m_selectedSouringTracersUiField.xmlCapability()->disableIO(); + m_selectedSouringTracersUiField.uiCapability()->setUiEditorTypeName( caf::PdmUiListEditor::uiEditorTypeName() ); + m_selectedSouringTracersUiField.uiCapability()->setUiLabelPosition( m_labelPosition ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimEclipseResultDefinition::~RimEclipseResultDefinition() +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimEclipseResultDefinition::simpleCopy( const RimEclipseResultDefinition* other ) +{ + this->setResultVariable( other->resultVariable() ); + this->setPorosityModel( other->porosityModel() ); + this->setResultType( other->resultType() ); + this->setFlowSolution( other->m_flowSolution() ); + this->setSelectedInjectorTracers( other->m_selectedInjectorTracers() ); + this->setSelectedProducerTracers( other->m_selectedProducerTracers() ); + this->setSelectedSouringTracers( other->m_selectedSouringTracers() ); + m_flowTracerSelectionMode = other->m_flowTracerSelectionMode(); + m_phaseSelection = other->m_phaseSelection; + + m_differenceCase = other->m_differenceCase(); + m_timeLapseBaseTimestep = other->m_timeLapseBaseTimestep(); + m_divideByCellFaceArea = other->m_divideByCellFaceArea(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimEclipseResultDefinition::setEclipseCase( RimEclipseCase* eclipseCase ) +{ + m_eclipseCase = eclipseCase; + + assignFlowSolutionFromCase(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimEclipseCase* RimEclipseResultDefinition::eclipseCase() const +{ + return m_eclipseCase; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RigCaseCellResultsData* RimEclipseResultDefinition::currentGridCellResults() const +{ + if ( !m_eclipseCase ) return nullptr; + + return m_eclipseCase->results( m_porosityModel() ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimEclipseResultDefinition::fieldChangedByUi( const caf::PdmFieldHandle* changedField, + const QVariant& oldValue, + const QVariant& newValue ) +{ + if ( &m_flowSolutionUiField == changedField || &m_resultTypeUiField == changedField || + &m_porosityModelUiField == changedField ) + { + // If the user are seeing the list with the actually selected result, + // select that result in the list. Otherwise select nothing. + + QStringList varList = getResultNamesForResultType( m_resultTypeUiField(), this->currentGridCellResults() ); + + bool isFlowDiagFieldsRelevant = ( m_resultType() == RiaDefines::ResultCatType::FLOW_DIAGNOSTICS ); + + if ( ( m_flowSolutionUiField() == m_flowSolution() || !isFlowDiagFieldsRelevant ) && + m_resultTypeUiField() == m_resultType() && m_porosityModelUiField() == m_porosityModel() ) + { + if ( varList.contains( resultVariable() ) ) + { + m_resultVariableUiField = resultVariable(); + } + + if ( isFlowDiagFieldsRelevant ) + { + m_selectedInjectorTracersUiField = m_selectedInjectorTracers(); + m_selectedProducerTracersUiField = m_selectedProducerTracers(); + } + else + { + m_selectedInjectorTracersUiField = std::vector(); + m_selectedProducerTracersUiField = std::vector(); + } + } + else + { + m_resultVariableUiField = ""; + m_selectedInjectorTracersUiField = std::vector(); + m_selectedProducerTracersUiField = std::vector(); + } + } + + if ( &m_resultVariableUiField == changedField ) + { + m_porosityModel = m_porosityModelUiField; + m_resultType = m_resultTypeUiField; + m_resultVariable = m_resultVariableUiField; + + if ( m_resultTypeUiField() == RiaDefines::ResultCatType::FLOW_DIAGNOSTICS ) + { + m_flowSolution = m_flowSolutionUiField(); + m_selectedInjectorTracers = m_selectedInjectorTracersUiField(); + m_selectedProducerTracers = m_selectedProducerTracersUiField(); + } + else if ( m_resultTypeUiField() == RiaDefines::ResultCatType::INJECTION_FLOODING ) + { + m_selectedSouringTracers = m_selectedSouringTracersUiField(); + } + else if ( m_resultTypeUiField() == RiaDefines::ResultCatType::INPUT_PROPERTY ) + { + m_inputPropertyFileName = getInputPropertyFileName( newValue.toString() ); + } + loadDataAndUpdate(); + } + + if ( &m_porosityModelUiField == changedField ) + { + m_porosityModel = m_porosityModelUiField; + m_resultVariableUiField = resultVariable(); + + RimEclipseView* eclipseView = nullptr; + this->firstAncestorOrThisOfType( eclipseView ); + if ( eclipseView ) + { + // Active cells can be different between matrix and fracture, make sure all geometry is recreated + eclipseView->scheduleReservoirGridGeometryRegen(); + } + + loadDataAndUpdate(); + } + + RimEclipseContourMapView* contourMapView = nullptr; + this->firstAncestorOrThisOfType( contourMapView ); + + if ( &m_differenceCase == changedField ) + { + m_timeLapseBaseTimestep = RigEclipseResultAddress::noTimeLapseValue(); + + if ( contourMapView ) + { + contourMapView->contourMapProjection()->updatedWeightingResult(); + } + + loadDataAndUpdate(); + } + + if ( &m_timeLapseBaseTimestep == changedField ) + { + if ( contourMapView ) + { + contourMapView->contourMapProjection()->updatedWeightingResult(); + } + + loadDataAndUpdate(); + } + + if ( &m_divideByCellFaceArea == changedField ) + { + loadDataAndUpdate(); + } + + if ( &m_flowTracerSelectionMode == changedField ) + { + loadDataAndUpdate(); + } + + if ( &m_selectedInjectorTracersUiField == changedField ) + { + changedTracerSelectionField( true ); + } + + if ( &m_selectedProducerTracersUiField == changedField ) + { + changedTracerSelectionField( false ); + } + + if ( &m_syncInjectorToProducerSelection == changedField ) + { + syncInjectorToProducerSelection(); + m_syncInjectorToProducerSelection = false; + } + + if ( &m_syncProducerToInjectorSelection == changedField ) + { + syncProducerToInjectorSelection(); + m_syncProducerToInjectorSelection = false; + } + + if ( &m_selectedSouringTracersUiField == changedField ) + { + if ( !m_resultVariable().isEmpty() ) + { + m_selectedSouringTracers = m_selectedSouringTracersUiField(); + loadDataAndUpdate(); + } + } + + if ( &m_phaseSelection == changedField ) + { + if ( m_phaseSelection() != RigFlowDiagResultAddress::PHASE_ALL ) + { + m_resultType = m_resultTypeUiField; + m_resultVariable = RIG_FLD_TOF_RESNAME; + m_resultVariableUiField = RIG_FLD_TOF_RESNAME; + } + loadDataAndUpdate(); + } + + if ( &m_showOnlyVisibleCategoriesInLegend == changedField ) + { + loadDataAndUpdate(); + } + + updateAnyFieldHasChanged(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimEclipseResultDefinition::changedTracerSelectionField( bool injector ) +{ + m_flowSolution = m_flowSolutionUiField(); + + std::vector& selectedTracers = injector ? m_selectedInjectorTracers.v() : m_selectedProducerTracers.v(); + const std::vector& selectedTracersUi = injector ? m_selectedInjectorTracersUiField.v() + : m_selectedProducerTracersUiField.v(); + + selectedTracers = selectedTracersUi; + + loadDataAndUpdate(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimEclipseResultDefinition::updateAnyFieldHasChanged() +{ + RimEclipsePropertyFilter* propFilter = nullptr; + this->firstAncestorOrThisOfType( propFilter ); + if ( propFilter ) + { + propFilter->updateConnectedEditors(); + } + + RimEclipseFaultColors* faultColors = nullptr; + this->firstAncestorOrThisOfType( faultColors ); + if ( faultColors ) + { + faultColors->updateConnectedEditors(); + } + + RimCellEdgeColors* cellEdgeColors = nullptr; + this->firstAncestorOrThisOfType( cellEdgeColors ); + if ( cellEdgeColors ) + { + cellEdgeColors->updateConnectedEditors(); + } + + RimEclipseCellColors* cellColors = nullptr; + this->firstAncestorOrThisOfType( cellColors ); + if ( cellColors ) + { + cellColors->updateConnectedEditors(); + } + + RimIntersectionResultDefinition* intersectResDef = nullptr; + this->firstAncestorOrThisOfType( intersectResDef ); + if ( intersectResDef ) + { + intersectResDef->updateConnectedEditors(); + } + + RimGridCrossPlotDataSet* crossPlotCurveSet = nullptr; + this->firstAncestorOrThisOfType( crossPlotCurveSet ); + if ( crossPlotCurveSet ) + { + crossPlotCurveSet->updateConnectedEditors(); + } + + RimPlotCurve* curve = nullptr; + this->firstAncestorOrThisOfType( curve ); + if ( curve ) + { + curve->updateConnectedEditors(); + } + + Rim3dWellLogCurve* rim3dWellLogCurve = nullptr; + this->firstAncestorOrThisOfType( rim3dWellLogCurve ); + if ( rim3dWellLogCurve ) + { + rim3dWellLogCurve->resetMinMaxValues(); + } + + RimEclipseContourMapProjection* contourMap = nullptr; + this->firstAncestorOrThisOfType( contourMap ); + if ( contourMap ) + { + contourMap->updatedWeightingResult(); + } + + RimWellLogTrack* wellLogTrack = nullptr; + this->firstAncestorOrThisOfType( wellLogTrack ); + if ( wellLogTrack ) + { + wellLogTrack->loadDataAndUpdate(); + wellLogTrack->updateEditors(); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimEclipseResultDefinition::setTofAndSelectTracer( const QString& tracerName ) +{ + setResultType( RiaDefines::ResultCatType::FLOW_DIAGNOSTICS ); + setResultVariable( "TOF" ); + setFlowDiagTracerSelectionType( FLOW_TR_BY_SELECTION ); + + if ( m_flowSolution() == nullptr ) + { + assignFlowSolutionFromCase(); + } + + if ( m_flowSolution() ) + { + RimFlowDiagSolution::TracerStatusType tracerStatus = m_flowSolution()->tracerStatusOverall( tracerName ); + + std::vector tracers; + tracers.push_back( tracerName ); + if ( ( tracerStatus == RimFlowDiagSolution::TracerStatusType::INJECTOR ) || + ( tracerStatus == RimFlowDiagSolution::TracerStatusType::VARYING ) ) + { + setSelectedInjectorTracers( tracers ); + } + + if ( ( tracerStatus == RimFlowDiagSolution::TracerStatusType::PRODUCER ) || + ( tracerStatus == RimFlowDiagSolution::TracerStatusType::VARYING ) ) + { + setSelectedProducerTracers( tracers ); + } + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimEclipseResultDefinition::loadDataAndUpdate() +{ + Rim3dView* view = nullptr; + this->firstAncestorOrThisOfType( view ); + + loadResult(); + + RimEclipsePropertyFilter* propFilter = nullptr; + this->firstAncestorOrThisOfType( propFilter ); + if ( propFilter ) + { + propFilter->setToDefaultValues(); + propFilter->updateFilterName(); + + if ( view ) + { + view->scheduleGeometryRegen( PROPERTY_FILTERED ); + view->scheduleCreateDisplayModelAndRedraw(); + } + } + + RimEclipseCellColors* cellColors = nullptr; + this->firstAncestorOrThisOfType( cellColors ); + if ( cellColors ) + { + this->updateLegendCategorySettings(); + + if ( view ) + { + RimViewLinker* viewLinker = view->assosiatedViewLinker(); + if ( viewLinker ) + { + viewLinker->updateCellResult(); + } + RimGridView* eclView = dynamic_cast( view ); + if ( eclView ) eclView->intersectionCollection()->scheduleCreateDisplayModelAndRedraw2dIntersectionViews(); + } + } + + RimIntersectionResultDefinition* sepIntersectionResDef = nullptr; + this->firstAncestorOrThisOfType( sepIntersectionResDef ); + if ( sepIntersectionResDef && sepIntersectionResDef->isInAction() ) + { + if ( view ) view->scheduleCreateDisplayModelAndRedraw(); + RimGridView* gridView = dynamic_cast( view ); + if ( gridView ) gridView->intersectionCollection()->scheduleCreateDisplayModelAndRedraw2dIntersectionViews(); + } + + RimCellEdgeColors* cellEdgeColors = nullptr; + this->firstAncestorOrThisOfType( cellEdgeColors ); + if ( cellEdgeColors ) + { + cellEdgeColors->singleVarEdgeResultColors()->updateLegendCategorySettings(); + cellEdgeColors->loadResult(); + + if ( view ) + { + view->scheduleCreateDisplayModelAndRedraw(); + } + } + + RimGridCrossPlotDataSet* crossPlotCurveSet = nullptr; + this->firstAncestorOrThisOfType( crossPlotCurveSet ); + if ( crossPlotCurveSet ) + { + crossPlotCurveSet->destroyCurves(); + crossPlotCurveSet->loadDataAndUpdate( true ); + } + + RimPlotCurve* curve = nullptr; + this->firstAncestorOrThisOfType( curve ); + if ( curve ) + { + curve->loadDataAndUpdate( true ); + } + + Rim3dWellLogCurve* rim3dWellLogCurve = nullptr; + this->firstAncestorOrThisOfType( rim3dWellLogCurve ); + if ( rim3dWellLogCurve ) + { + rim3dWellLogCurve->updateCurveIn3dView(); + } + +#ifdef USE_QTCHARTS + RimGridStatisticsPlot* gridStatisticsPlot = nullptr; + this->firstAncestorOrThisOfType( gridStatisticsPlot ); + if ( gridStatisticsPlot ) + { + gridStatisticsPlot->loadDataAndUpdate(); + } +#endif +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QList + RimEclipseResultDefinition::calculateValueOptions( const caf::PdmFieldHandle* fieldNeedingOptions, bool* useOptionsOnly ) +{ + QList options; + + if ( fieldNeedingOptions == &m_resultTypeUiField ) + { + bool hasSourSimRLFile = false; + RimEclipseResultCase* eclResCase = dynamic_cast( m_eclipseCase.p() ); + if ( eclResCase && eclResCase->eclipseCaseData() ) + { + hasSourSimRLFile = eclResCase->hasSourSimFile(); + } + +#ifndef USE_HDF5 + // If using ResInsight without HDF5 support, ignore SourSim files and + // do not show it as a result category. + hasSourSimRLFile = false; +#endif + + bool enableSouring = false; + +#ifdef USE_HDF5 + if ( m_eclipseCase.notNull() ) + { + RigCaseCellResultsData* cellResultsData = m_eclipseCase->results( this->porosityModel() ); + + if ( cellResultsData && cellResultsData->hasFlowDiagUsableFluxes() ) + { + enableSouring = true; + } + } +#endif /* USE_HDF5 */ + + RimGridTimeHistoryCurve* timeHistoryCurve; + this->firstAncestorOrThisOfType( timeHistoryCurve ); + + bool isSeparateFaultResult = false; + { + RimEclipseFaultColors* sepFaultResult; + this->firstAncestorOrThisOfType( sepFaultResult ); + if ( sepFaultResult ) isSeparateFaultResult = true; + } + + using ResCatEnum = caf::AppEnum; + for ( size_t i = 0; i < ResCatEnum::size(); ++i ) + { + RiaDefines::ResultCatType resType = ResCatEnum::fromIndex( i ); + + // Do not include flow diagnostics results if it is a time history curve + + if ( resType == RiaDefines::ResultCatType::FLOW_DIAGNOSTICS && ( timeHistoryCurve ) ) + { + continue; + } + + if ( resType == RiaDefines::ResultCatType::FLOW_DIAGNOSTICS && m_eclipseCase && + m_eclipseCase->eclipseCaseData() && m_eclipseCase->eclipseCaseData()->hasFractureResults() ) + { + // Flow diagnostics is not supported for dual porosity models + continue; + } + + // Do not include SourSimRL if no SourSim file is loaded + + if ( resType == RiaDefines::ResultCatType::SOURSIMRL && ( !hasSourSimRLFile ) ) + { + continue; + } + + if ( resType == RiaDefines::ResultCatType::INJECTION_FLOODING && !enableSouring ) + { + continue; + } + + if ( resType == RiaDefines::ResultCatType::ALLAN_DIAGRAMS && !isSeparateFaultResult ) + { + continue; + } + + QString uiString = ResCatEnum::uiTextFromIndex( i ); + options.push_back( caf::PdmOptionItemInfo( uiString, resType ) ); + } + } + + if ( m_resultTypeUiField() == RiaDefines::ResultCatType::FLOW_DIAGNOSTICS ) + { + if ( fieldNeedingOptions == &m_resultVariableUiField ) + { + options.push_back( caf::PdmOptionItemInfo( timeOfFlightString( false ), RIG_FLD_TOF_RESNAME ) ); + if ( m_phaseSelection() == RigFlowDiagResultAddress::PHASE_ALL ) + { + options.push_back( caf::PdmOptionItemInfo( "Tracer Cell Fraction (Sum)", RIG_FLD_CELL_FRACTION_RESNAME ) ); + options.push_back( + caf::PdmOptionItemInfo( maxFractionTracerString( false ), RIG_FLD_MAX_FRACTION_TRACER_RESNAME ) ); + options.push_back( + caf::PdmOptionItemInfo( "Injector Producer Communication", RIG_FLD_COMMUNICATION_RESNAME ) ); + } + } + else if ( fieldNeedingOptions == &m_flowSolutionUiField ) + { + RimEclipseResultCase* eclCase = dynamic_cast( m_eclipseCase.p() ); + if ( eclCase ) + { + std::vector flowSols = eclCase->flowDiagSolutions(); + for ( RimFlowDiagSolution* flowSol : flowSols ) + { + options.push_back( caf::PdmOptionItemInfo( flowSol->userDescription(), flowSol ) ); + } + } + } + else if ( fieldNeedingOptions == &m_selectedInjectorTracersUiField ) + { + options = calcOptionsForSelectedTracerField( true ); + } + else if ( fieldNeedingOptions == &m_selectedProducerTracersUiField ) + { + options = calcOptionsForSelectedTracerField( false ); + } + } + else if ( m_resultTypeUiField() == RiaDefines::ResultCatType::INJECTION_FLOODING ) + { + if ( fieldNeedingOptions == &m_selectedSouringTracersUiField ) + { + RigCaseCellResultsData* cellResultsStorage = currentGridCellResults(); + if ( cellResultsStorage ) + { + QStringList dynamicResultNames = + cellResultsStorage->resultNames( RiaDefines::ResultCatType::DYNAMIC_NATIVE ); + + for ( const QString& resultName : dynamicResultNames ) + { + if ( !resultName.endsWith( "F" ) || resultName == RiaResultNames::completionTypeResultName() ) + { + continue; + } + options.push_back( caf::PdmOptionItemInfo( resultName, resultName ) ); + } + } + } + else if ( fieldNeedingOptions == &m_resultVariableUiField ) + { + options.push_back( caf::PdmOptionItemInfo( RIG_NUM_FLOODED_PV, RIG_NUM_FLOODED_PV ) ); + } + } + else + { + if ( fieldNeedingOptions == &m_resultVariableUiField ) + { + options = calcOptionsForVariableUiFieldStandard( m_resultTypeUiField(), + this->currentGridCellResults(), + showDerivedResultsFirstInVariableUiField(), + addPerCellFaceOptionsForVariableUiField(), + m_ternaryEnabled ); + } + else if ( fieldNeedingOptions == &m_differenceCase ) + { + options.push_back( caf::PdmOptionItemInfo( "None", nullptr ) ); + + RimEclipseCase* eclipseCase = nullptr; + this->firstAncestorOrThisOfTypeAsserted( eclipseCase ); + if ( eclipseCase && eclipseCase->eclipseCaseData() && eclipseCase->eclipseCaseData()->mainGrid() ) + { + RimProject* proj = nullptr; + eclipseCase->firstAncestorOrThisOfTypeAsserted( proj ); + + std::vector allCases = proj->eclipseCases(); + for ( RimEclipseCase* otherCase : allCases ) + { + if ( otherCase == eclipseCase ) continue; + + if ( otherCase->eclipseCaseData() && otherCase->eclipseCaseData()->mainGrid() ) + { + options.push_back( caf::PdmOptionItemInfo( QString( "%1 (#%2)" ) + .arg( otherCase->caseUserDescription() ) + .arg( otherCase->caseId() ), + otherCase, + false, + otherCase->uiIconProvider() ) ); + } + } + } + } + else if ( fieldNeedingOptions == &m_timeLapseBaseTimestep ) + { + RimEclipseCase* currentCase = nullptr; + this->firstAncestorOrThisOfTypeAsserted( currentCase ); + + RimEclipseCase* baseCase = currentCase; + if ( m_differenceCase ) + { + baseCase = m_differenceCase; + } + + options.push_back( caf::PdmOptionItemInfo( "Disabled", RigEclipseResultAddress::noTimeLapseValue() ) ); + + std::vector stepDates = baseCase->timeStepDates(); + for ( size_t stepIdx = 0; stepIdx < stepDates.size(); ++stepIdx ) + { + QString displayString = stepDates[stepIdx].toString( RiaQDateTimeTools::dateFormatString() ); + displayString += QString( " (#%1)" ).arg( stepIdx ); + + options.push_back( caf::PdmOptionItemInfo( displayString, static_cast( stepIdx ) ) ); + } + } + } + + ( *useOptionsOnly ) = true; + + return options; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RigEclipseResultAddress RimEclipseResultDefinition::eclipseResultAddress() const +{ + if ( isFlowDiagOrInjectionFlooding() ) return RigEclipseResultAddress(); + + const RigCaseCellResultsData* gridCellResults = this->currentGridCellResults(); + if ( gridCellResults ) + { + int timelapseTimeStep = RigEclipseResultAddress::noTimeLapseValue(); + int diffCaseId = RigEclipseResultAddress::noCaseDiffValue(); + + if ( isDeltaTimeStepActive() ) + { + timelapseTimeStep = m_timeLapseBaseTimestep(); + } + + if ( isDeltaCaseActive() ) + { + diffCaseId = m_differenceCase->caseId(); + } + + return RigEclipseResultAddress( m_resultType(), + m_resultVariable(), + timelapseTimeStep, + diffCaseId, + isDivideByCellFaceAreaActive() ); + } + else + { + return RigEclipseResultAddress(); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimEclipseResultDefinition::setFromEclipseResultAddress( const RigEclipseResultAddress& address ) +{ + RigEclipseResultAddress canonizedAddress = address; + + const RigCaseCellResultsData* gridCellResults = this->currentGridCellResults(); + if ( gridCellResults ) + { + auto rinfo = gridCellResults->resultInfo( address ); + if ( rinfo ) canonizedAddress = rinfo->eclipseResultAddress(); + } + + m_resultType = canonizedAddress.resultCatType(); + m_resultVariable = canonizedAddress.resultName(); + m_timeLapseBaseTimestep = canonizedAddress.deltaTimeStepIndex(); + m_divideByCellFaceArea = canonizedAddress.isDivideByCellFaceAreaActive(); + + if ( canonizedAddress.isDeltaCaseActive() ) + { + auto eclipseCases = RimProject::current()->eclipseCases(); + for ( RimEclipseCase* c : eclipseCases ) + { + if ( c && c->caseId() == canonizedAddress.deltaCaseId() ) + { + m_differenceCase = c; + } + } + } + + this->updateUiFieldsFromActiveResult(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RigFlowDiagResultAddress RimEclipseResultDefinition::flowDiagResAddress() const +{ + CVF_ASSERT( isFlowDiagOrInjectionFlooding() ); + + if ( m_resultType() == RiaDefines::ResultCatType::FLOW_DIAGNOSTICS ) + { + size_t timeStep = 0; + + Rim3dView* rimView = nullptr; + this->firstAncestorOrThisOfType( rimView ); + if ( rimView ) + { + timeStep = rimView->currentTimeStep(); + } + RimWellLogExtractionCurve* wellLogExtractionCurve = nullptr; + this->firstAncestorOrThisOfType( wellLogExtractionCurve ); + if ( wellLogExtractionCurve ) + { + timeStep = static_cast( wellLogExtractionCurve->currentTimeStep() ); + } + + // Time history curves are not supported, since it requires the time + // step to access to be supplied. + RimGridTimeHistoryCurve* timeHistoryCurve = nullptr; + this->firstAncestorOrThisOfType( timeHistoryCurve ); + CVF_ASSERT( timeHistoryCurve == nullptr ); + + std::set selTracerNames; + if ( m_flowTracerSelectionMode == FLOW_TR_BY_SELECTION ) + { + for ( const QString& tName : m_selectedInjectorTracers() ) + { + selTracerNames.insert( tName.toStdString() ); + } + for ( const QString& tName : m_selectedProducerTracers() ) + { + selTracerNames.insert( tName.toStdString() ); + } + } + else + { + RimFlowDiagSolution* flowSol = m_flowSolution(); + if ( flowSol ) + { + std::vector tracerNames = flowSol->tracerNames(); + + if ( m_flowTracerSelectionMode == FLOW_TR_INJECTORS || m_flowTracerSelectionMode == FLOW_TR_INJ_AND_PROD ) + { + for ( const QString& tracerName : tracerNames ) + { + RimFlowDiagSolution::TracerStatusType status = + flowSol->tracerStatusInTimeStep( tracerName, timeStep ); + if ( status == RimFlowDiagSolution::TracerStatusType::INJECTOR ) + { + selTracerNames.insert( tracerName.toStdString() ); + } + } + } + + if ( m_flowTracerSelectionMode == FLOW_TR_PRODUCERS || m_flowTracerSelectionMode == FLOW_TR_INJ_AND_PROD ) + { + for ( const QString& tracerName : tracerNames ) + { + RimFlowDiagSolution::TracerStatusType status = + flowSol->tracerStatusInTimeStep( tracerName, timeStep ); + if ( status == RimFlowDiagSolution::TracerStatusType::PRODUCER ) + { + selTracerNames.insert( tracerName.toStdString() ); + } + } + } + } + } + + return RigFlowDiagResultAddress( m_resultVariable().toStdString(), m_phaseSelection(), selTracerNames ); + } + else + { + std::set selTracerNames; + for ( const QString& selectedTracerName : m_selectedSouringTracers() ) + { + selTracerNames.insert( selectedTracerName.toUtf8().constData() ); + } + return RigFlowDiagResultAddress( m_resultVariable().toStdString(), + RigFlowDiagResultAddress::PHASE_ALL, + selTracerNames ); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimEclipseResultDefinition::setFlowDiagTracerSelectionType( FlowTracerSelectionType selectionType ) +{ + m_flowTracerSelectionMode = selectionType; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RimEclipseResultDefinition::resultVariableUiName() const +{ + if ( resultType() == RiaDefines::ResultCatType::FLOW_DIAGNOSTICS ) + { + return flowDiagResUiText( false, 32 ); + } + + if ( isDivideByCellFaceAreaActive() ) + { + return m_resultVariable() + " /A"; + } + + return m_resultVariable(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RimEclipseResultDefinition::resultVariableUiShortName() const +{ + if ( resultType() == RiaDefines::ResultCatType::FLOW_DIAGNOSTICS ) + { + return flowDiagResUiText( true, 24 ); + } + + if ( isDivideByCellFaceAreaActive() ) + { + return m_resultVariable() + " /A"; + } + + return m_resultVariable(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RimEclipseResultDefinition::additionalResultText() const +{ + QStringList resultText; + + if ( isDeltaTimeStepActive() ) + { + std::vector stepDates; + const RigCaseCellResultsData* gridCellResults = this->currentGridCellResults(); + if ( gridCellResults ) + { + stepDates = gridCellResults->timeStepDates(); + resultText += + QString( "Base Time Step: %1" ) + .arg( stepDates[m_timeLapseBaseTimestep()].toString( RiaQDateTimeTools::dateFormatString() ) ); + } + } + if ( isDeltaCaseActive() ) + { + resultText += QString( "Base Case: %1" ).arg( m_differenceCase()->caseUserDescription() ); + } + return resultText.join( "
" ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RimEclipseResultDefinition::additionalResultTextShort() const +{ + QString resultTextShort; + if ( isDeltaTimeStepActive() || isDeltaCaseActive() ) + { + QStringList resultTextLines; + resultTextLines += QString( "\nDiff. Options:" ); + if ( isDeltaCaseActive() ) + { + resultTextLines += QString( "Base Case: #%1" ).arg( m_differenceCase()->caseId() ); + } + if ( isDeltaTimeStepActive() ) + { + resultTextLines += QString( "Base Time: #%1" ).arg( m_timeLapseBaseTimestep() ); + } + resultTextShort = resultTextLines.join( "\n" ); + } + + return resultTextShort; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +int RimEclipseResultDefinition::timeLapseBaseTimeStep() const +{ + return m_timeLapseBaseTimestep; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +int RimEclipseResultDefinition::caseDiffIndex() const +{ + if ( m_differenceCase ) + { + return m_differenceCase->caseId(); + } + return -1; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimEclipseResultDefinition::loadResult() +{ + if ( isFlowDiagOrInjectionFlooding() ) return; // Will load automatically on access + + if ( m_eclipseCase ) + { + if ( !m_eclipseCase->ensureReservoirCaseIsOpen() ) + { + RiaLogging::error( "Could not open the Eclipse Grid file: " + m_eclipseCase->gridFileName() ); + return; + } + } + + if ( m_differenceCase ) + { + if ( !m_differenceCase->ensureReservoirCaseIsOpen() ) + { + RiaLogging::error( "Could not open the Eclipse Grid file: " + m_eclipseCase->gridFileName() ); + return; + } + } + + RigCaseCellResultsData* gridCellResults = this->currentGridCellResults(); + if ( gridCellResults ) + { + if ( isDeltaTimeStepActive() || isDeltaCaseActive() || isDivideByCellFaceAreaActive() ) + { + gridCellResults->createResultEntry( this->eclipseResultAddress(), false ); + } + + QString resultName = m_resultVariable(); + std::set eclipseResultNamesWithNncData = RiaResultNames::nncResultNames(); + if ( eclipseResultNamesWithNncData.find( resultName ) != eclipseResultNamesWithNncData.end() ) + { + eclipseCase()->ensureFaultDataIsComputed(); + + bool dataWasComputed = eclipseCase()->ensureNncDataIsComputed(); + if ( dataWasComputed ) + { + eclipseCase()->createDisplayModelAndUpdateAllViews(); + } + } + + gridCellResults->ensureKnownResultLoaded( this->eclipseResultAddress() ); + } +} + +//-------------------------------------------------------------------------------------------------- +/// Returns whether the result requested by the definition is a single frame result +/// The result needs to be loaded before asking +//-------------------------------------------------------------------------------------------------- +bool RimEclipseResultDefinition::hasStaticResult() const +{ + if ( isFlowDiagOrInjectionFlooding() ) return false; + + const RigCaseCellResultsData* gridCellResults = this->currentGridCellResults(); + RigEclipseResultAddress gridScalarResultIndex = this->eclipseResultAddress(); + + if ( hasResult() && gridCellResults->timeStepCount( gridScalarResultIndex ) == 1 ) + { + return true; + } + else + { + return false; + } +} + +//-------------------------------------------------------------------------------------------------- +/// Returns whether the result requested by the definition is loaded or possible to load from the result file +//-------------------------------------------------------------------------------------------------- +bool RimEclipseResultDefinition::hasResult() const +{ + if ( isFlowDiagOrInjectionFlooding() ) + { + if ( m_flowSolution() && !m_resultVariable().isEmpty() ) return true; + } + else if ( this->currentGridCellResults() ) + { + const RigCaseCellResultsData* gridCellResults = this->currentGridCellResults(); + + return gridCellResults->hasResultEntry( this->eclipseResultAddress() ); + } + + return false; +} + +//-------------------------------------------------------------------------------------------------- +/// Returns whether the result requested by the definition is a multi frame result +/// The result needs to be loaded before asking +//-------------------------------------------------------------------------------------------------- +bool RimEclipseResultDefinition::hasDynamicResult() const +{ + if ( hasResult() ) + { + if ( m_resultType() == RiaDefines::ResultCatType::DYNAMIC_NATIVE ) + { + return true; + } + else if ( m_resultType() == RiaDefines::ResultCatType::SOURSIMRL ) + { + return true; + } + else if ( m_resultType() == RiaDefines::ResultCatType::FLOW_DIAGNOSTICS ) + { + return true; + } + else if ( m_resultType() == RiaDefines::ResultCatType::INJECTION_FLOODING ) + { + return true; + } + + if ( this->currentGridCellResults() ) + { + const RigCaseCellResultsData* gridCellResults = this->currentGridCellResults(); + RigEclipseResultAddress gridScalarResultIndex = this->eclipseResultAddress(); + if ( gridCellResults->timeStepCount( gridScalarResultIndex ) > 1 ) + { + return true; + } + } + } + + return false; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimEclipseResultDefinition::initAfterRead() +{ + if ( m_flowSolution() == nullptr ) + { + assignFlowSolutionFromCase(); + } + + if ( m_resultVariable == "Formation Allen" ) + { + m_resultVariable = RiaResultNames::formationAllanResultName(); + m_resultType = RiaDefines::ResultCatType::ALLAN_DIAGRAMS; + } + else if ( m_resultVariable == "Binary Formation Allen" ) + { + m_resultVariable = RiaResultNames::formationBinaryAllanResultName(); + m_resultType = RiaDefines::ResultCatType::ALLAN_DIAGRAMS; + } + + m_porosityModelUiField = m_porosityModel; + m_resultTypeUiField = m_resultType; + m_resultVariableUiField = m_resultVariable; + + m_flowSolutionUiField = m_flowSolution(); + m_selectedInjectorTracersUiField = m_selectedInjectorTracers; + + this->updateUiIconFromToggleField(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimEclipseResultDefinition::setResultType( RiaDefines::ResultCatType val ) +{ + m_resultType = val; + m_resultTypeUiField = val; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimEclipseResultDefinition::setPorosityModel( RiaDefines::PorosityModelType val ) +{ + m_porosityModel = val; + m_porosityModelUiField = val; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimEclipseResultDefinition::setResultVariable( const QString& val ) +{ + m_resultVariable = val; + m_resultVariableUiField = val; +} + +//-------------------------------------------------------------------------------------------------- +/// Return phase type if the current result is known to be of a particular +/// fluid phase type. Otherwise the method will return PHASE_NOT_APPLICABLE. +//-------------------------------------------------------------------------------------------------- +RiaDefines::PhaseType RimEclipseResultDefinition::resultPhaseType() const +{ + if ( QRegularExpression( "OIL" ).match( m_resultVariable() ).hasMatch() ) + { + return RiaDefines::PhaseType::OIL_PHASE; + } + else if ( QRegularExpression( "GAS" ).match( m_resultVariable() ).hasMatch() ) + { + return RiaDefines::PhaseType::GAS_PHASE; + } + else if ( QRegularExpression( "WAT" ).match( m_resultVariable() ).hasMatch() ) + { + return RiaDefines::PhaseType::WATER_PHASE; + } + return RiaDefines::PhaseType::PHASE_NOT_APPLICABLE; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimFlowDiagSolution* RimEclipseResultDefinition::flowDiagSolution() const +{ + return m_flowSolution(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimEclipseResultDefinition::setFlowSolution( RimFlowDiagSolution* flowSol ) +{ + this->m_flowSolution = flowSol; + this->m_flowSolutionUiField = flowSol; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimEclipseResultDefinition::setSelectedTracers( const std::vector& selectedTracers ) +{ + if ( m_flowSolution() == nullptr ) + { + assignFlowSolutionFromCase(); + } + if ( m_flowSolution() ) + { + std::vector injectorTracers; + std::vector producerTracers; + for ( const QString& tracerName : selectedTracers ) + { + RimFlowDiagSolution::TracerStatusType tracerStatus = m_flowSolution()->tracerStatusOverall( tracerName ); + if ( tracerStatus == RimFlowDiagSolution::TracerStatusType::INJECTOR ) + { + injectorTracers.push_back( tracerName ); + } + else if ( tracerStatus == RimFlowDiagSolution::TracerStatusType::PRODUCER ) + { + producerTracers.push_back( tracerName ); + } + else if ( tracerStatus == RimFlowDiagSolution::TracerStatusType::VARYING || + tracerStatus == RimFlowDiagSolution::TracerStatusType::UNDEFINED ) + { + injectorTracers.push_back( tracerName ); + producerTracers.push_back( tracerName ); + } + } + setSelectedInjectorTracers( injectorTracers ); + setSelectedProducerTracers( producerTracers ); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimEclipseResultDefinition::setSelectedInjectorTracers( const std::vector& selectedTracers ) +{ + this->m_selectedInjectorTracers = selectedTracers; + this->m_selectedInjectorTracersUiField = selectedTracers; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimEclipseResultDefinition::setSelectedProducerTracers( const std::vector& selectedTracers ) +{ + this->m_selectedProducerTracers = selectedTracers; + this->m_selectedProducerTracersUiField = selectedTracers; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimEclipseResultDefinition::setSelectedSouringTracers( const std::vector& selectedTracers ) +{ + this->m_selectedSouringTracers = selectedTracers; + this->m_selectedSouringTracersUiField = selectedTracers; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimEclipseResultDefinition::updateUiFieldsFromActiveResult() +{ + m_resultTypeUiField = m_resultType; + m_resultVariableUiField = resultVariable(); + m_selectedInjectorTracersUiField = m_selectedInjectorTracers; + m_selectedProducerTracersUiField = m_selectedProducerTracers; + m_selectedSouringTracersUiField = m_selectedSouringTracers; + m_porosityModelUiField = m_porosityModel; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimEclipseResultDefinition::enableDeltaResults( bool enable ) +{ + m_isDeltaResultEnabled = enable; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimEclipseResultDefinition::isTernarySaturationSelected() const +{ + bool isTernary = + ( m_resultType() == RiaDefines::ResultCatType::DYNAMIC_NATIVE ) && + ( m_resultVariable().compare( RiaResultNames::ternarySaturationResultName(), Qt::CaseInsensitive ) == 0 ); + + return isTernary; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimEclipseResultDefinition::isCompletionTypeSelected() const +{ + return ( m_resultType() == RiaDefines::ResultCatType::DYNAMIC_NATIVE && + m_resultVariable() == RiaResultNames::completionTypeResultName() ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimEclipseResultDefinition::hasCategoryResult() const +{ + if ( this->m_resultType() == RiaDefines::ResultCatType::FORMATION_NAMES && m_eclipseCase && + m_eclipseCase->eclipseCaseData() && !m_eclipseCase->eclipseCaseData()->formationNames().empty() ) + return true; + + if ( this->m_resultType() == RiaDefines::ResultCatType::DYNAMIC_NATIVE && + this->resultVariable() == RiaResultNames::completionTypeResultName() ) + return true; + + if ( this->m_resultType() == RiaDefines::ResultCatType::FLOW_DIAGNOSTICS && + m_resultVariable() == RIG_FLD_MAX_FRACTION_TRACER_RESNAME ) + return true; + + if ( this->resultVariable() == RiaResultNames::formationAllanResultName() || + this->resultVariable() == RiaResultNames::formationBinaryAllanResultName() ) + { + return true; + } + + if ( !this->hasStaticResult() ) return false; + + return RiaDefines::isNativeCategoryResult( this->resultVariable() ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimEclipseResultDefinition::isFlowDiagOrInjectionFlooding() const +{ + if ( this->m_resultType() == RiaDefines::ResultCatType::FLOW_DIAGNOSTICS || + this->m_resultType() == RiaDefines::ResultCatType::INJECTION_FLOODING ) + { + return true; + } + + return false; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimEclipseResultDefinition::defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) +{ + uiOrdering.add( &m_resultTypeUiField ); + + if ( hasDualPorFractureResult() ) + { + uiOrdering.add( &m_porosityModelUiField ); + } + + if ( m_resultTypeUiField() == RiaDefines::ResultCatType::FLOW_DIAGNOSTICS ) + { + uiOrdering.add( &m_flowSolutionUiField ); + + uiOrdering.add( &m_flowTracerSelectionMode ); + + if ( m_flowTracerSelectionMode == FLOW_TR_BY_SELECTION ) + { + caf::PdmUiGroup* selectionGroup = uiOrdering.addNewGroup( "Tracer Selection" ); + selectionGroup->setEnableFrame( false ); + + caf::PdmUiGroup* injectorGroup = selectionGroup->addNewGroup( "Injectors" ); + injectorGroup->add( &m_selectedInjectorTracersUiField ); + injectorGroup->add( &m_syncInjectorToProducerSelection ); + + caf::PdmUiGroup* producerGroup = selectionGroup->addNewGroup( "Producers", false ); + producerGroup->add( &m_selectedProducerTracersUiField ); + producerGroup->add( &m_syncProducerToInjectorSelection ); + } + + uiOrdering.add( &m_phaseSelection ); + + if ( m_flowSolution() == nullptr ) + { + assignFlowSolutionFromCase(); + } + } + + if ( m_resultTypeUiField() == RiaDefines::ResultCatType::INJECTION_FLOODING ) + { + uiOrdering.add( &m_selectedSouringTracersUiField ); + } + + uiOrdering.add( &m_resultVariableUiField ); + if ( m_resultTypeUiField() == RiaDefines::ResultCatType::INPUT_PROPERTY ) + { + uiOrdering.add( &m_inputPropertyFileName ); + } + + if ( isDivideByCellFaceAreaPossible() ) + { + uiOrdering.add( &m_divideByCellFaceArea ); + + QString resultPropertyLabel = "Result Property"; + if ( isDivideByCellFaceAreaActive() ) + { + resultPropertyLabel += QString( "\nDivided by Area" ); + } + m_resultVariableUiField.uiCapability()->setUiName( resultPropertyLabel ); + } + + { + caf::PdmUiGroup* legendGroup = uiOrdering.addNewGroup( "Legend" ); + legendGroup->add( &m_showOnlyVisibleCategoriesInLegend ); + + bool showOnlyVisibleCategoriesOption = false; + + RimEclipseView* eclView = nullptr; + this->firstAncestorOrThisOfType( eclView ); + + if ( eclView ) + { + if ( eclView->cellResult() == this && this->hasCategoryResult() ) showOnlyVisibleCategoriesOption = true; + } + + if ( m_resultTypeUiField() == RiaDefines::ResultCatType::FLOW_DIAGNOSTICS && + m_resultVariableUiField() == RIG_FLD_MAX_FRACTION_TRACER_RESNAME ) + { + showOnlyVisibleCategoriesOption = true; + } + + legendGroup->setUiHidden( !showOnlyVisibleCategoriesOption ); + } + + if ( isDeltaCasePossible() || isDeltaTimeStepPossible() ) + { + caf::PdmUiGroup* differenceGroup = uiOrdering.addNewGroup( "Difference Options" ); + differenceGroup->setUiReadOnly( !( isDeltaTimeStepPossible() || isDeltaCasePossible() ) ); + + m_differenceCase.uiCapability()->setUiReadOnly( !isDeltaCasePossible() ); + m_timeLapseBaseTimestep.uiCapability()->setUiReadOnly( !isDeltaTimeStepPossible() ); + + if ( isDeltaCasePossible() ) differenceGroup->add( &m_differenceCase ); + if ( isDeltaTimeStepPossible() ) differenceGroup->add( &m_timeLapseBaseTimestep ); + + QString resultPropertyLabel = "Result Property"; + if ( isDeltaTimeStepActive() || isDeltaCaseActive() ) + { + resultPropertyLabel += QString( "\n%1" ).arg( additionalResultTextShort() ); + } + m_resultVariableUiField.uiCapability()->setUiName( resultPropertyLabel ); + } + + uiOrdering.skipRemainingFields( true ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimEclipseResultDefinition::defineEditorAttribute( const caf::PdmFieldHandle* field, + QString uiConfigName, + caf::PdmUiEditorAttribute* attribute ) +{ + if ( m_resultTypeUiField() == RiaDefines::ResultCatType::FLOW_DIAGNOSTICS ) + { + if ( field == &m_resultVariableUiField ) + { + caf::PdmUiListEditorAttribute* listEditAttr = dynamic_cast( attribute ); + if ( listEditAttr ) + { + listEditAttr->m_heightHint = 50; + } + } + else if ( field == &m_syncInjectorToProducerSelection || field == &m_syncProducerToInjectorSelection ) + { + caf::PdmUiToolButtonEditorAttribute* toolButtonAttr = + dynamic_cast( attribute ); + if ( toolButtonAttr ) + { + toolButtonAttr->m_sizePolicy.setHorizontalPolicy( QSizePolicy::MinimumExpanding ); + } + } + } + if ( field == &m_resultVariableUiField ) + { + caf::PdmUiListEditorAttribute* listEditAttr = dynamic_cast( attribute ); + if ( listEditAttr ) + { + listEditAttr->m_allowHorizontalScrollBar = false; + } + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimEclipseResultDefinition::TracerComp::operator()( const QString& lhs, const QString& rhs ) const +{ + if ( !lhs.endsWith( "-XF" ) && rhs.endsWith( "-XF" ) ) + { + return true; + } + else if ( lhs.endsWith( "-XF" ) && !rhs.endsWith( "-XF" ) ) + { + return false; + } + else + { + return lhs < rhs; + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimEclipseResultDefinition::assignFlowSolutionFromCase() +{ + RimFlowDiagSolution* defaultFlowDiagSolution = nullptr; + + RimEclipseResultCase* eclCase = dynamic_cast( m_eclipseCase.p() ); + + if ( eclCase ) + { + defaultFlowDiagSolution = eclCase->defaultFlowDiagSolution(); + } + this->setFlowSolution( defaultFlowDiagSolution ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimEclipseResultDefinition::hasDualPorFractureResult() +{ + if ( m_eclipseCase && m_eclipseCase->eclipseCaseData() ) + { + return m_eclipseCase->eclipseCaseData()->hasFractureResults(); + } + + return false; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RimEclipseResultDefinition::flowDiagResUiText( bool shortLabel, int maxTracerStringLength ) const +{ + QString uiText = QString::fromStdString( flowDiagResAddress().variableName ); + if ( flowDiagResAddress().variableName == RIG_FLD_TOF_RESNAME ) + { + uiText = timeOfFlightString( shortLabel ); + } + else if ( flowDiagResAddress().variableName == RIG_FLD_MAX_FRACTION_TRACER_RESNAME ) + { + uiText = maxFractionTracerString( shortLabel ); + } + + QString tracersString = selectedTracersString(); + + if ( !tracersString.isEmpty() ) + { + const QString postfix = "..."; + + if ( tracersString.size() > maxTracerStringLength + postfix.size() ) + { + tracersString = tracersString.left( maxTracerStringLength ); + tracersString += postfix; + } + uiText += QString( "\n%1" ).arg( tracersString ); + } + return uiText; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QList + RimEclipseResultDefinition::calcOptionsForVariableUiFieldStandard( RiaDefines::ResultCatType resultCatType, + const RigCaseCellResultsData* results, + bool showDerivedResultsFirst, + bool addPerCellFaceOptionItems, + bool ternaryEnabled ) +{ + CVF_ASSERT( resultCatType != RiaDefines::ResultCatType::FLOW_DIAGNOSTICS && + resultCatType != RiaDefines::ResultCatType::INJECTION_FLOODING ); + + if ( results ) + { + QList optionList; + + QStringList cellCenterResultNames; + QStringList cellFaceResultNames; + + for ( const QString& s : getResultNamesForResultType( resultCatType, results ) ) + { + if ( s == RiaResultNames::completionTypeResultName() ) + { + if ( results->timeStepDates().empty() ) continue; + } + + if ( RiaResultNames::isPerCellFaceResult( s ) ) + { + cellFaceResultNames.push_back( s ); + } + else + { + cellCenterResultNames.push_back( s ); + } + } + + cellCenterResultNames.sort(); + cellFaceResultNames.sort(); + + // Cell Center result names + for ( const QString& s : cellCenterResultNames ) + { + optionList.push_back( caf::PdmOptionItemInfo( s, s ) ); + } + + if ( addPerCellFaceOptionItems ) + { + for ( const QString& s : cellFaceResultNames ) + { + if ( showDerivedResultsFirst ) + { + optionList.push_front( caf::PdmOptionItemInfo( s, s ) ); + } + else + { + optionList.push_back( caf::PdmOptionItemInfo( s, s ) ); + } + } + + // Ternary Result + if ( ternaryEnabled ) + { + bool hasAtLeastOneTernaryComponent = false; + if ( cellCenterResultNames.contains( "SOIL" ) ) + hasAtLeastOneTernaryComponent = true; + else if ( cellCenterResultNames.contains( "SGAS" ) ) + hasAtLeastOneTernaryComponent = true; + else if ( cellCenterResultNames.contains( "SWAT" ) ) + hasAtLeastOneTernaryComponent = true; + + if ( resultCatType == RiaDefines::ResultCatType::DYNAMIC_NATIVE && hasAtLeastOneTernaryComponent ) + { + optionList.push_front( caf::PdmOptionItemInfo( RiaResultNames::ternarySaturationResultName(), + RiaResultNames::ternarySaturationResultName() ) ); + } + } + } + + optionList.push_front( + caf::PdmOptionItemInfo( RiaResultNames::undefinedResultName(), RiaResultNames::undefinedResultName() ) ); + + return optionList; + } + + return QList(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimEclipseResultDefinition::setTernaryEnabled( bool enabled ) +{ + m_ternaryEnabled = enabled; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool operator<( const cvf::Color3ub first, const cvf::Color3ub second ) +{ + if ( first.r() != second.r() ) return first.r() < second.r(); + if ( first.g() != second.g() ) return first.g() < second.g(); + if ( first.b() != second.b() ) return first.b() < second.b(); + + return false; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +class TupleCompare +{ +public: + bool operator()( const std::tuple& t1, + const std::tuple& t2 ) const + { + using namespace std; + if ( get<0>( t1 ) != get<0>( t2 ) ) return get<0>( t1 ) < get<0>( t2 ); + if ( get<1>( t1 ) != get<1>( t2 ) ) return get<1>( t1 ) < get<1>( t2 ); + if ( get<2>( t1 ) != get<2>( t2 ) ) return get<2>( t1 ) < get<2>( t2 ); + + return false; + } +}; + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimEclipseResultDefinition::updateRangesForExplicitLegends( RimRegularLegendConfig* legendConfigToUpdate, + RimTernaryLegendConfig* ternaryLegendConfigToUpdate, + int currentTimeStep ) + +{ + RimEclipseCase* rimEclipseCase = this->eclipseCase(); + + if ( this->hasResult() ) + { + if ( this->isFlowDiagOrInjectionFlooding() ) + { + CVF_ASSERT( currentTimeStep >= 0 ); + + double globalMin, globalMax; + double globalPosClosestToZero, globalNegClosestToZero; + RigFlowDiagResults* flowResultsData = this->flowDiagSolution()->flowDiagResults(); + RigFlowDiagResultAddress resAddr = this->flowDiagResAddress(); + + flowResultsData->minMaxScalarValues( resAddr, currentTimeStep, &globalMin, &globalMax ); + flowResultsData->posNegClosestToZero( resAddr, currentTimeStep, &globalPosClosestToZero, &globalNegClosestToZero ); + + double localMin, localMax; + double localPosClosestToZero, localNegClosestToZero; + if ( this->hasDynamicResult() ) + { + flowResultsData->minMaxScalarValues( resAddr, currentTimeStep, &localMin, &localMax ); + flowResultsData->posNegClosestToZero( resAddr, currentTimeStep, &localPosClosestToZero, &localNegClosestToZero ); + } + else + { + localMin = globalMin; + localMax = globalMax; + + localPosClosestToZero = globalPosClosestToZero; + localNegClosestToZero = globalNegClosestToZero; + } + + CVF_ASSERT( legendConfigToUpdate ); + + legendConfigToUpdate->disableAllTimeStepsRange( true ); + legendConfigToUpdate->setClosestToZeroValues( globalPosClosestToZero, + globalNegClosestToZero, + localPosClosestToZero, + localNegClosestToZero ); + legendConfigToUpdate->setAutomaticRanges( globalMin, globalMax, localMin, localMax ); + + if ( this->hasCategoryResult() ) + { + RimEclipseView* eclView = nullptr; + this->firstAncestorOrThisOfType( eclView ); + + if ( eclView ) + { + std::set, TupleCompare> categories; + + std::vector tracerNames = this->flowDiagSolution()->tracerNames(); + int tracerIndex = 0; + + for ( const auto& tracerName : tracerNames ) + { + cvf::Color3ub color( cvf::Color3::GRAY ); + + RimSimWellInView* well = eclView->wellCollection()->findWell( + RimFlowDiagSolution::removeCrossFlowEnding( tracerName ) ); + + if ( well ) color = cvf::Color3ub( well->wellPipeColor() ); + + categories.insert( std::make_tuple( tracerName, tracerIndex, color ) ); + ++tracerIndex; + } + + std::vector> categoryVector; + + if ( m_showOnlyVisibleCategoriesInLegend ) + { + std::set visibleTracers = + RigVisibleCategoriesCalculator::visibleFlowDiagCategories( *eclView, + *flowResultsData, + resAddr, + currentTimeStep ); + for ( auto tupIt : categories ) + { + int tracerIndex = std::get<1>( tupIt ); + if ( visibleTracers.count( tracerIndex ) ) categoryVector.push_back( tupIt ); + } + } + else + { + for ( auto tupIt : categories ) + { + categoryVector.push_back( tupIt ); + } + } + + legendConfigToUpdate->setCategoryItems( categoryVector ); + } + } + } + else + { + if ( !rimEclipseCase ) return; + + RigEclipseCaseData* eclipseCaseData = rimEclipseCase->eclipseCaseData(); + if ( !eclipseCaseData ) return; + + RigCaseCellResultsData* cellResultsData = eclipseCaseData->results( this->porosityModel() ); + cellResultsData->ensureKnownResultLoaded( this->eclipseResultAddress() ); + + double globalMin, globalMax; + double globalPosClosestToZero, globalNegClosestToZero; + + cellResultsData->minMaxCellScalarValues( this->eclipseResultAddress(), globalMin, globalMax ); + cellResultsData->posNegClosestToZero( this->eclipseResultAddress(), + globalPosClosestToZero, + globalNegClosestToZero ); + + double localMin, localMax; + double localPosClosestToZero, localNegClosestToZero; + if ( this->hasDynamicResult() && currentTimeStep >= 0 ) + { + cellResultsData->minMaxCellScalarValues( this->eclipseResultAddress(), currentTimeStep, localMin, localMax ); + cellResultsData->posNegClosestToZero( this->eclipseResultAddress(), + currentTimeStep, + localPosClosestToZero, + localNegClosestToZero ); + } + else + { + localMin = globalMin; + localMax = globalMax; + + localPosClosestToZero = globalPosClosestToZero; + localNegClosestToZero = globalNegClosestToZero; + } + + CVF_ASSERT( legendConfigToUpdate ); + + legendConfigToUpdate->disableAllTimeStepsRange( false ); + legendConfigToUpdate->setClosestToZeroValues( globalPosClosestToZero, + globalNegClosestToZero, + localPosClosestToZero, + localNegClosestToZero ); + legendConfigToUpdate->setAutomaticRanges( globalMin, globalMax, localMin, localMax ); + + if ( this->hasCategoryResult() ) + { + if ( this->resultType() == RiaDefines::ResultCatType::ALLAN_DIAGRAMS ) + { + if ( this->resultVariable() == RiaResultNames::formationAllanResultName() ) + { + const std::vector fnVector = eclipseCaseData->formationNames(); + std::vector fnameIdxes; + for ( int i = 0; i < static_cast( fnVector.size() ); i++ ) + { + fnameIdxes.push_back( i ); + } + + cvf::Color3ubArray legendBaseColors = legendConfigToUpdate->colorLegend()->colorArray(); + + cvf::ref formationColorMapper = new caf::CategoryMapper; + formationColorMapper->setCategories( fnameIdxes ); + formationColorMapper->setInterpolateColors( legendBaseColors ); + + const std::map, int>& formationCombToCategory = + eclipseCaseData->allanDiagramData()->formationCombinationToCategory(); + + std::vector> categories; + for ( int frmNameIdx : fnameIdxes ) + { + cvf::Color3ub formationColor = formationColorMapper->mapToColor( frmNameIdx ); + categories.emplace_back( std::make_tuple( fnVector[frmNameIdx], frmNameIdx, formationColor ) ); + } + + std::set visibleAllanCategories; + { + RimEclipseView* eclView = nullptr; + this->firstAncestorOrThisOfType( eclView ); + + visibleAllanCategories = RigVisibleCategoriesCalculator::visibleAllanCategories( eclView ); + } + + for ( auto [formationPair, categoryIndex] : formationCombToCategory ) + { + int frmIdx1 = formationPair.first; + int frmIdx2 = formationPair.second; + + if ( visibleAllanCategories.count( categoryIndex ) == 0 ) continue; + + int fnVectorSize = static_cast( fnVector.size() ); + if ( frmIdx1 >= fnVectorSize || frmIdx2 >= fnVectorSize ) continue; + + QString frmName1 = fnVector[frmIdx1]; + QString frmName2 = fnVector[frmIdx2]; + + cvf::Color3f formationColor1 = cvf::Color3f( formationColorMapper->mapToColor( frmIdx1 ) ); + cvf::Color3f formationColor2 = cvf::Color3f( formationColorMapper->mapToColor( frmIdx2 ) ); + + cvf::Color3ub blendColor = + cvf::Color3ub( RiaColorTools::blendCvfColors( formationColor1, formationColor2 ) ); + + categories.emplace_back( + std::make_tuple( frmName1 + "-" + frmName2, categoryIndex, blendColor ) ); + } + + legendConfigToUpdate->setCategoryItems( categories ); + } + else if ( this->resultVariable() == RiaResultNames::formationBinaryAllanResultName() ) + { + std::vector> categories; + categories.emplace_back( std::make_tuple( "Same formation", 0, cvf::Color3ub::BROWN ) ); + categories.emplace_back( std::make_tuple( "Different formation", 1, cvf::Color3ub::ORANGE ) ); + + legendConfigToUpdate->setCategoryItems( categories ); + } + } + else if ( this->resultType() == RiaDefines::ResultCatType::DYNAMIC_NATIVE && + this->resultVariable() == RiaResultNames::completionTypeResultName() ) + { + const std::vector& visibleCategories = + cellResultsData->uniqueCellScalarValues( this->eclipseResultAddress() ); + + std::vector supportedCompletionTypes = + { RiaDefines::WellPathComponentType::WELL_PATH, + RiaDefines::WellPathComponentType::FISHBONES, + RiaDefines::WellPathComponentType::PERFORATION_INTERVAL, + RiaDefines::WellPathComponentType::FRACTURE }; + + RiaColorTables::WellPathComponentColors colors = RiaColorTables::wellPathComponentColors(); + + std::vector> categories; + for ( auto completionType : supportedCompletionTypes ) + { + if ( std::find( visibleCategories.begin(), + visibleCategories.end(), + static_cast( completionType ) ) != visibleCategories.end() ) + { + QString categoryText = + caf::AppEnum::uiText( completionType ); + categories.push_back( std::make_tuple( categoryText, + static_cast( completionType ), + colors[completionType] ) ); + } + } + + legendConfigToUpdate->setCategoryItems( categories ); + } + else + { + auto uniqueValues = cellResultsData->uniqueCellScalarValues( this->eclipseResultAddress() ); + if ( this->eclipseResultAddress().resultCatType() == RiaDefines::ResultCatType::FORMATION_NAMES ) + { + std::vector fnVector = eclipseCaseData->formationNames(); + uniqueValues.resize( fnVector.size() ); + std::iota( uniqueValues.begin(), uniqueValues.end(), 0 ); + } + + cvf::Color3ubArray legendBaseColors = legendConfigToUpdate->colorLegend()->colorArray(); + + cvf::ref categoryMapper = new caf::CategoryMapper; + categoryMapper->setCategories( uniqueValues ); + categoryMapper->setInterpolateColors( legendBaseColors ); + + std::vector visibleCategoryValues = uniqueValues; + + if ( m_showOnlyVisibleCategoriesInLegend ) + { + RimEclipseView* eclView = nullptr; + this->firstAncestorOrThisOfType( eclView ); + if ( eclView && eclView->showWindow() ) + { + // Check if current result is cell result, and update the visible set of values + // TODO: Can be extended to the separate geometry results (separate fault result, separate + // intersection results), but this requires some refactoring + if ( eclView->cellResult() == this ) + { + std::set visibleCategorySet = + RigVisibleCategoriesCalculator::visibleCategories( eclView ); + + visibleCategoryValues.clear(); + visibleCategoryValues.insert( visibleCategoryValues.begin(), + visibleCategorySet.begin(), + visibleCategorySet.end() ); + } + } + } + std::vector> categoryVector; + + for ( auto value : visibleCategoryValues ) + { + cvf::Color3ub categoryColor = categoryMapper->mapToColor( value ); + + QString valueTxt; + if ( this->resultType() == RiaDefines::ResultCatType::FORMATION_NAMES ) + { + std::vector fnVector = eclipseCaseData->formationNames(); + + if ( value < static_cast( fnVector.size() ) ) + { + valueTxt = fnVector[value]; + } + } + else + valueTxt = QString( "%1" ).arg( value ); + + categoryVector.push_back( std::make_tuple( valueTxt, value, categoryColor ) ); + } + legendConfigToUpdate->setCategoryItems( categoryVector ); + } + } + } + } + + // Ternary legend update + { + if ( !rimEclipseCase ) return; + + RigEclipseCaseData* eclipseCase = rimEclipseCase->eclipseCaseData(); + if ( !eclipseCase ) return; + + RigCaseCellResultsData* cellResultsData = eclipseCase->results( this->porosityModel() ); + + size_t maxTimeStepCount = cellResultsData->maxTimeStepCount(); + if ( this->isTernarySaturationSelected() && maxTimeStepCount > 1 ) + { + RigCaseCellResultsData* gridCellResults = this->currentGridCellResults(); + { + RigEclipseResultAddress resAddr( RiaDefines::ResultCatType::DYNAMIC_NATIVE, "SOIL" ); + + if ( gridCellResults->ensureKnownResultLoaded( resAddr ) ) + { + double globalMin = 0.0; + double globalMax = 1.0; + double localMin = 0.0; + double localMax = 1.0; + + cellResultsData->minMaxCellScalarValues( resAddr, globalMin, globalMax ); + cellResultsData->minMaxCellScalarValues( resAddr, currentTimeStep, localMin, localMax ); + + ternaryLegendConfigToUpdate->setAutomaticRanges( RimTernaryLegendConfig::TERNARY_SOIL_IDX, + globalMin, + globalMax, + localMin, + localMax ); + } + } + + { + RigEclipseResultAddress resAddr( RiaDefines::ResultCatType::DYNAMIC_NATIVE, "SGAS" ); + + if ( gridCellResults->ensureKnownResultLoaded( resAddr ) ) + { + double globalMin = 0.0; + double globalMax = 1.0; + double localMin = 0.0; + double localMax = 1.0; + + cellResultsData->minMaxCellScalarValues( resAddr, globalMin, globalMax ); + cellResultsData->minMaxCellScalarValues( resAddr, currentTimeStep, localMin, localMax ); + + ternaryLegendConfigToUpdate->setAutomaticRanges( RimTernaryLegendConfig::TERNARY_SGAS_IDX, + globalMin, + globalMax, + localMin, + localMax ); + } + } + + { + RigEclipseResultAddress resAddr( RiaDefines::ResultCatType::DYNAMIC_NATIVE, "SWAT" ); + + if ( gridCellResults->ensureKnownResultLoaded( resAddr ) ) + { + double globalMin = 0.0; + double globalMax = 1.0; + double localMin = 0.0; + double localMax = 1.0; + + cellResultsData->minMaxCellScalarValues( resAddr, globalMin, globalMax ); + cellResultsData->minMaxCellScalarValues( resAddr, currentTimeStep, localMin, localMax ); + + ternaryLegendConfigToUpdate->setAutomaticRanges( RimTernaryLegendConfig::TERNARY_SWAT_IDX, + globalMin, + globalMax, + localMin, + localMax ); + } + } + } + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimEclipseResultDefinition::updateLegendTitle( RimRegularLegendConfig* legendConfig, const QString& legendHeading ) +{ + QString title = legendHeading + this->resultVariableUiName(); + if ( !this->additionalResultTextShort().isEmpty() ) + { + title += additionalResultTextShort(); + } + + if ( this->hasDualPorFractureResult() ) + { + QString porosityModelText = caf::AppEnum::uiText( this->porosityModel() ); + + title += QString( "\nDual Por : %1" ).arg( porosityModelText ); + } + + legendConfig->setTitle( title ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QList RimEclipseResultDefinition::calcOptionsForSelectedTracerField( bool injector ) +{ + QList options; + + RimFlowDiagSolution* flowSol = m_flowSolutionUiField(); + if ( flowSol ) + { + std::set sortedTracers = setOfTracersOfType( injector ); + + for ( const QString& tracerName : sortedTracers ) + { + QString postfix; + RimFlowDiagSolution::TracerStatusType status = flowSol->tracerStatusOverall( tracerName ); + if ( status == RimFlowDiagSolution::TracerStatusType::VARYING ) + { + postfix = " [I/P]"; + } + else if ( status == RimFlowDiagSolution::TracerStatusType::UNDEFINED ) + { + postfix = " [U]"; + } + options.push_back( caf::PdmOptionItemInfo( tracerName + postfix, tracerName ) ); + } + } + return options; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RimEclipseResultDefinition::timeOfFlightString( bool shorter ) const +{ + QString tofString; + bool multipleSelected = false; + if ( injectorSelectionState() != NONE_SELECTED && producerSelectionState() != NONE_SELECTED ) + { + tofString = shorter ? "Res.Time" : "Residence Time"; + multipleSelected = true; + } + else if ( injectorSelectionState() != NONE_SELECTED ) + { + tofString = shorter ? "Fwd.TOF" : "Forward Time of Flight"; + } + else if ( producerSelectionState() != NONE_SELECTED ) + { + tofString = shorter ? "Rev.TOF" : "Reverse Time of Flight"; + } + else + { + tofString = shorter ? "TOF" : "Time of Flight"; + } + + multipleSelected = multipleSelected || injectorSelectionState() >= MULTIPLE_SELECTED || + producerSelectionState() >= MULTIPLE_SELECTED; + + if ( multipleSelected && !shorter ) + { + tofString += " (Average)"; + } + + tofString += " [days]"; + // Conversion from seconds in flow module to days is done in RigFlowDiagTimeStepResult::setTracerTOF() + + return tofString; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RimEclipseResultDefinition::maxFractionTracerString( bool shorter ) const +{ + QString mfString; + if ( injectorSelectionState() >= ONE_SELECTED && producerSelectionState() == NONE_SELECTED ) + { + mfString = shorter ? "FloodReg" : "Flooding Region"; + if ( injectorSelectionState() >= MULTIPLE_SELECTED ) mfString += "s"; + } + else if ( injectorSelectionState() == NONE_SELECTED && producerSelectionState() >= ONE_SELECTED ) + { + mfString = shorter ? "DrainReg" : "Drainage Region"; + if ( producerSelectionState() >= MULTIPLE_SELECTED ) mfString += "s"; + } + else + { + mfString = shorter ? "Drain&FloodReg" : "Drainage/Flooding Regions"; + } + return mfString; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RimEclipseResultDefinition::selectedTracersString() const +{ + QStringList fullTracersList; + + FlowTracerSelectionState injectorState = injectorSelectionState(); + FlowTracerSelectionState producerState = producerSelectionState(); + + if ( injectorState == ALL_SELECTED && producerState == ALL_SELECTED ) + { + fullTracersList += caf::AppEnum::uiText( FLOW_TR_INJ_AND_PROD ); + } + else + { + if ( injectorState == ALL_SELECTED ) + { + fullTracersList += caf::AppEnum::uiText( FLOW_TR_INJECTORS ); + } + + if ( producerState == ALL_SELECTED ) + { + fullTracersList += caf::AppEnum::uiText( FLOW_TR_PRODUCERS ); + } + + if ( injectorSelectionState() == ONE_SELECTED || injectorSelectionState() == MULTIPLE_SELECTED ) + { + QStringList listOfSelectedInjectors; + for ( const QString& injector : m_selectedInjectorTracers() ) + { + listOfSelectedInjectors.push_back( injector ); + } + if ( !listOfSelectedInjectors.empty() ) + { + fullTracersList += listOfSelectedInjectors.join( ", " ); + } + } + + if ( producerSelectionState() == ONE_SELECTED || producerSelectionState() == MULTIPLE_SELECTED ) + { + QStringList listOfSelectedProducers; + for ( const QString& producer : m_selectedProducerTracers() ) + { + listOfSelectedProducers.push_back( producer ); + } + if ( !listOfSelectedProducers.empty() ) + { + fullTracersList.push_back( listOfSelectedProducers.join( ", " ) ); + } + } + } + + QString tracersText; + if ( !fullTracersList.empty() ) + { + tracersText = fullTracersList.join( ", " ); + } + return tracersText; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QStringList RimEclipseResultDefinition::getResultNamesForResultType( RiaDefines::ResultCatType resultCatType, + const RigCaseCellResultsData* results ) +{ + if ( resultCatType != RiaDefines::ResultCatType::FLOW_DIAGNOSTICS ) + { + if ( !results ) return QStringList(); + + return results->resultNames( resultCatType ); + } + else + { + QStringList flowVars; + flowVars.push_back( RIG_FLD_TOF_RESNAME ); + flowVars.push_back( RIG_FLD_CELL_FRACTION_RESNAME ); + flowVars.push_back( RIG_FLD_MAX_FRACTION_TRACER_RESNAME ); + flowVars.push_back( RIG_FLD_COMMUNICATION_RESNAME ); + return flowVars; + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RimEclipseResultDefinition::allTracerNames() const +{ + std::vector tracerNames; + + RimFlowDiagSolution* flowSol = m_flowSolutionUiField(); + if ( flowSol ) + { + tracerNames = flowSol->tracerNames(); + } + + return tracerNames; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::set RimEclipseResultDefinition::setOfTracersOfType( bool injector ) const +{ + std::set sortedTracers; + + RimFlowDiagSolution* flowSol = m_flowSolutionUiField(); + if ( flowSol ) + { + std::vector tracerNames = allTracerNames(); + for ( const QString& tracerName : tracerNames ) + { + RimFlowDiagSolution::TracerStatusType status = flowSol->tracerStatusOverall( tracerName ); + bool includeTracer = status == RimFlowDiagSolution::TracerStatusType::VARYING || + status == RimFlowDiagSolution::TracerStatusType::UNDEFINED; + includeTracer |= injector && status == RimFlowDiagSolution::TracerStatusType::INJECTOR; + includeTracer |= !injector && status == RimFlowDiagSolution::TracerStatusType::PRODUCER; + + if ( includeTracer ) + { + sortedTracers.insert( tracerName ); + } + } + } + return sortedTracers; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimEclipseResultDefinition::FlowTracerSelectionState RimEclipseResultDefinition::injectorSelectionState() const +{ + if ( m_flowTracerSelectionMode == FLOW_TR_INJECTORS || m_flowTracerSelectionMode == FLOW_TR_INJ_AND_PROD ) + { + return ALL_SELECTED; + } + else if ( m_flowTracerSelectionMode == FLOW_TR_BY_SELECTION ) + { + if ( m_selectedInjectorTracers().size() == setOfTracersOfType( true ).size() ) + { + return ALL_SELECTED; + } + else if ( m_selectedInjectorTracers().size() == (size_t)1 ) + { + return ONE_SELECTED; + } + else if ( m_selectedInjectorTracers().size() > (size_t)1 ) + { + return MULTIPLE_SELECTED; + } + } + return NONE_SELECTED; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimEclipseResultDefinition::FlowTracerSelectionState RimEclipseResultDefinition::producerSelectionState() const +{ + if ( m_flowTracerSelectionMode == FLOW_TR_PRODUCERS || m_flowTracerSelectionMode == FLOW_TR_INJ_AND_PROD ) + { + return ALL_SELECTED; + } + else if ( m_flowTracerSelectionMode == FLOW_TR_BY_SELECTION ) + { + if ( m_selectedProducerTracers().size() == setOfTracersOfType( false ).size() ) + { + return ALL_SELECTED; + } + else if ( m_selectedProducerTracers().size() == (size_t)1 ) + { + return ONE_SELECTED; + } + else if ( m_selectedProducerTracers().size() > (size_t)1 ) + { + return MULTIPLE_SELECTED; + } + } + return NONE_SELECTED; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimEclipseResultDefinition::syncInjectorToProducerSelection() +{ + const double epsilon = 1.0e-8; + + int timeStep = 0; + + Rim3dView* rimView = nullptr; + this->firstAncestorOrThisOfType( rimView ); + if ( rimView ) + { + timeStep = rimView->currentTimeStep(); + } + + RimFlowDiagSolution* flowSol = m_flowSolution(); + if ( flowSol && m_flowTracerSelectionMode == FLOW_TR_BY_SELECTION ) + { + std::set producers = setOfTracersOfType( false ); + + std::set newProducerSelection; + for ( const QString& selectedInjector : m_selectedInjectorTracers() ) + { + for ( const QString& producer : producers ) + { + std::pair commFluxes = + flowSol->flowDiagResults()->injectorProducerPairFluxes( selectedInjector.toStdString(), + producer.toStdString(), + timeStep ); + if ( std::abs( commFluxes.first ) > epsilon || std::abs( commFluxes.second ) > epsilon ) + { + newProducerSelection.insert( producer ); + } + } + } + // Add all currently selected producers to set + for ( const QString& selectedProducer : m_selectedProducerTracers() ) + { + newProducerSelection.insert( selectedProducer ); + } + std::vector newProducerVector( newProducerSelection.begin(), newProducerSelection.end() ); + setSelectedProducerTracers( newProducerVector ); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimEclipseResultDefinition::syncProducerToInjectorSelection() +{ + const double epsilon = 1.0e-8; + + int timeStep = 0; + + Rim3dView* rimView = nullptr; + this->firstAncestorOrThisOfType( rimView ); + if ( rimView ) + { + timeStep = rimView->currentTimeStep(); + } + + RimFlowDiagSolution* flowSol = m_flowSolution(); + if ( flowSol && m_flowTracerSelectionMode == FLOW_TR_BY_SELECTION ) + { + std::set injectors = setOfTracersOfType( true ); + + std::set newInjectorSelection; + for ( const QString& selectedProducer : m_selectedProducerTracers() ) + { + for ( const QString& injector : injectors ) + { + std::pair commFluxes = + flowSol->flowDiagResults()->injectorProducerPairFluxes( injector.toStdString(), + selectedProducer.toStdString(), + timeStep ); + if ( std::abs( commFluxes.first ) > epsilon || std::abs( commFluxes.second ) > epsilon ) + { + newInjectorSelection.insert( injector ); + } + } + } + // Add all currently selected injectors to set + for ( const QString& selectedInjector : m_selectedInjectorTracers() ) + { + newInjectorSelection.insert( selectedInjector ); + } + std::vector newInjectorVector( newInjectorSelection.begin(), newInjectorSelection.end() ); + setSelectedInjectorTracers( newInjectorVector ); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimEclipseResultDefinition::isDeltaResultEnabled() const +{ + return m_isDeltaResultEnabled; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimEclipseResultDefinition::isDeltaTimeStepPossible() const +{ + return isDeltaResultEnabled() && m_resultTypeUiField() == RiaDefines::ResultCatType::DYNAMIC_NATIVE && + !isTernarySaturationSelected(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimEclipseResultDefinition::isDeltaTimeStepActive() const +{ + return isDeltaTimeStepPossible() && m_timeLapseBaseTimestep() >= 0; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimEclipseResultDefinition::isDeltaCasePossible() const +{ + return isDeltaResultEnabled() && !isTernarySaturationSelected() && + ( m_resultTypeUiField() == RiaDefines::ResultCatType::DYNAMIC_NATIVE || + m_resultTypeUiField() == RiaDefines::ResultCatType::STATIC_NATIVE || + m_resultTypeUiField() == RiaDefines::ResultCatType::GENERATED ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimEclipseResultDefinition::isDeltaCaseActive() const +{ + return isDeltaCasePossible() && m_differenceCase() != nullptr; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimEclipseResultDefinition::isDivideByCellFaceAreaPossible() const +{ + QString str = m_resultVariable; + + // TODO : Move to RiaDefines or a separate file for cell face results + + if ( str == "FLRWATI+" ) return true; + if ( str == "FLRWATJ+" ) return true; + if ( str == "FLRWATK+" ) return true; + + if ( str == "FLROILI+" ) return true; + if ( str == "FLROILJ+" ) return true; + if ( str == "FLROILK+" ) return true; + + if ( str == "FLRGASI+" ) return true; + if ( str == "FLRGASJ+" ) return true; + if ( str == "FLRGASK+" ) return true; + + if ( str == "TRANX" ) return true; + if ( str == "TRANY" ) return true; + if ( str == "TRANZ" ) return true; + + if ( str == "riTRANX" ) return true; + if ( str == "riTRANY" ) return true; + if ( str == "riTRANZ" ) return true; + + return false; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimEclipseResultDefinition::isDivideByCellFaceAreaActive() const +{ + return isDivideByCellFaceAreaPossible() && m_divideByCellFaceArea; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimEclipseResultDefinition::showDerivedResultsFirstInVariableUiField() const +{ + // Cell Face result names + bool showDerivedResultsFirstInList = false; + RimEclipseFaultColors* rimEclipseFaultColors = nullptr; + this->firstAncestorOrThisOfType( rimEclipseFaultColors ); + + if ( rimEclipseFaultColors ) showDerivedResultsFirstInList = true; + + return showDerivedResultsFirstInList; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimEclipseResultDefinition::addPerCellFaceOptionsForVariableUiField() const +{ + RimPlotCurve* curve = nullptr; + this->firstAncestorOrThisOfType( curve ); + + RimEclipsePropertyFilter* propFilter = nullptr; + this->firstAncestorOrThisOfType( propFilter ); + + RimCellEdgeColors* cellEdge = nullptr; + this->firstAncestorOrThisOfType( cellEdge ); + + if ( propFilter || curve || cellEdge ) + { + return false; + } + + return true; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RimEclipseResultDefinition::getInputPropertyFileName( const QString& resultName ) const +{ + RimEclipseCase* eclipseCase; + this->firstAncestorOrThisOfType( eclipseCase ); + + if ( eclipseCase ) + { + RimEclipseInputPropertyCollection* inputPropertyCollection = eclipseCase->inputPropertyCollection(); + if ( inputPropertyCollection ) + { + RimEclipseInputProperty* inputProperty = inputPropertyCollection->findInputProperty( resultName ); + if ( inputProperty ) + { + return inputProperty->fileName.v().path(); + } + } + } + + return ""; +} diff --git a/ApplicationLibCode/ProjectDataModel/RimVfpTableExtractor.cpp b/ApplicationLibCode/ProjectDataModel/RimVfpTableExtractor.cpp index 92efe10168..e8825f2d1d 100644 --- a/ApplicationLibCode/ProjectDataModel/RimVfpTableExtractor.cpp +++ b/ApplicationLibCode/ProjectDataModel/RimVfpTableExtractor.cpp @@ -1,93 +1,88 @@ -///////////////////////////////////////////////////////////////////////////////// -// -// Copyright (C) 2020- Equinor 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 "RimVfpTableExtractor.h" - -// #include "RiaApplication.h" - -// #include "RimCase.h" -// #include "RimEclipseCase.h" -// #include "RimGeoMechCase.h" -// #include "RimOilField.h" -// #include "RimProject.h" -// #include "RimWellLogFile.h" -// #include "RimWellPath.h" -// #include "RimWellPathCollection.h" - -#include "cafPdmUiItem.h" -#include "cafUtils.h" - -// #include -// #include -// #include - -// #include "opm/parser/eclipse/EclipseState/Schedule/VFPInjTable.hpp" -// #include "opm/parser/eclipse/EclipseState/Schedule/VFPProdTable.hpp" -#include "opm/parser/eclipse/Parser/Parser.hpp" - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -std::vector RimVfpTableExtractor::extractVfpInjectionTables( const std::string& filename ) -{ - std::vector tables; - - Opm::Parser parser; - auto deck = parser.parseFile( filename ); - - std::string myKeyword = "VFPINJ"; - auto keywordList = deck.getKeywordList( myKeyword ); - - Opm::UnitSystem unitSystem; - - for ( auto kw : keywordList ) - { - auto name = kw->name(); - - Opm::VFPInjTable table( *kw, unitSystem ); - tables.push_back( table ); - } - - return tables; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -std::vector RimVfpTableExtractor::extractVfpProductionTables( const std::string& filename ) -{ - std::vector tables; - - Opm::Parser parser; - auto deck = parser.parseFile( filename ); - - std::string myKeyword = "VFPPROD"; - auto keywordList = deck.getKeywordList( myKeyword ); - - Opm::UnitSystem unitSystem; - - for ( auto kw : keywordList ) - { - auto name = kw->name(); - - Opm::VFPProdTable table( *kw, unitSystem ); - tables.push_back( table ); - } - - return tables; -} +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2020- Equinor 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 "RimVfpTableExtractor.h" + +#include "cafPdmUiItem.h" +#include "cafUtils.h" + +#include "opm/parser/eclipse/Parser/Parser.hpp" + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RimVfpTableExtractor::extractVfpInjectionTables( const std::string& filename ) +{ + std::vector tables; + + try + { + Opm::Parser parser; + auto deck = parser.parseFile( filename ); + + std::string myKeyword = "VFPINJ"; + auto keywordList = deck.getKeywordList( myKeyword ); + + Opm::UnitSystem unitSystem; + + for ( auto kw : keywordList ) + { + auto name = kw->name(); + + Opm::VFPInjTable table( *kw, unitSystem ); + tables.push_back( table ); + } + } + catch ( ... ) + { + } + + return tables; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RimVfpTableExtractor::extractVfpProductionTables( const std::string& filename ) +{ + std::vector tables; + + try + { + Opm::Parser parser; + auto deck = parser.parseFile( filename ); + + std::string myKeyword = "VFPPROD"; + auto keywordList = deck.getKeywordList( myKeyword ); + + Opm::UnitSystem unitSystem; + + for ( auto kw : keywordList ) + { + auto name = kw->name(); + + Opm::VFPProdTable table( *kw, unitSystem ); + tables.push_back( table ); + } + } + catch ( ... ) + { + } + + return tables; +} From a4fd24a15aca2ff5aae195fd8b61217dd11ed5ce Mon Sep 17 00:00:00 2001 From: jonjenssen <69144954+jonjenssen@users.noreply.github.com> Date: Wed, 16 Jun 2021 17:31:25 +0200 Subject: [PATCH 02/14] Improve handling of LGRs in cell filters (#7783) * Improve handling of LGRs in cell filters --- .../RicNewRangeFilterSlice3dviewFeature.cpp | 3 +- .../RicNewRangeFilterSliceFeature.cpp | 3 +- .../RicAdvancedSnapshotExportFeature.cpp | 3 +- .../CellFilters/RimCellFilter.cpp | 1 - .../CellFilters/RimCellFilter.h | 2 +- .../CellFilters/RimCellFilterCollection.cpp | 10 +- .../CellFilters/RimCellFilterCollection.h | 7 +- .../CellFilters/RimCellRangeFilter.cpp | 8 +- .../CellFilters/RimCellRangeFilter.h | 2 +- .../CellFilters/RimPolygonFilter.cpp | 177 ++++++++++++------ .../CellFilters/RimPolygonFilter.h | 14 +- .../CellFilters/RimPropertyFilter.h | 2 +- .../CellFilters/RimUserDefinedFilter.cpp | 6 +- .../CellFilters/RimUserDefinedFilter.h | 2 +- .../ReservoirDataModel/RigCell.cpp | 6 +- 15 files changed, 163 insertions(+), 83 deletions(-) diff --git a/ApplicationLibCode/Commands/CellFilterCommands/RicNewRangeFilterSlice3dviewFeature.cpp b/ApplicationLibCode/Commands/CellFilterCommands/RicNewRangeFilterSlice3dviewFeature.cpp index 65be153cb4..b9f79b1e0c 100644 --- a/ApplicationLibCode/Commands/CellFilterCommands/RicNewRangeFilterSlice3dviewFeature.cpp +++ b/ApplicationLibCode/Commands/CellFilterCommands/RicNewRangeFilterSlice3dviewFeature.cpp @@ -72,10 +72,9 @@ void RicNewRangeFilterSlice3dviewFeature::onActionTriggered( bool isChecked ) int sliceStart = list[1].toInt(); int gridIndex = list[2].toInt(); - RimCellFilter* newFilter = filtColl->addNewCellRangeFilter( sourceCase, direction, sliceStart ); + RimCellFilter* newFilter = filtColl->addNewCellRangeFilter( sourceCase, gridIndex, direction, sliceStart ); if ( newFilter ) { - newFilter->setGridIndex( gridIndex ); Riu3DMainWindowTools::selectAsCurrentItem( newFilter ); activeView->setSurfaceDrawstyle(); } diff --git a/ApplicationLibCode/Commands/CellFilterCommands/RicNewRangeFilterSliceFeature.cpp b/ApplicationLibCode/Commands/CellFilterCommands/RicNewRangeFilterSliceFeature.cpp index 97d5c61769..7995bf3360 100644 --- a/ApplicationLibCode/Commands/CellFilterCommands/RicNewRangeFilterSliceFeature.cpp +++ b/ApplicationLibCode/Commands/CellFilterCommands/RicNewRangeFilterSliceFeature.cpp @@ -56,7 +56,8 @@ void RicNewRangeFilterSliceFeature::onActionTriggered( bool isChecked ) RimCase* sourceCase = nullptr; filtColl->firstAncestorOrThisOfTypeAsserted( sourceCase ); - RimCellFilter* lastCreatedOrUpdated = filtColl->addNewCellRangeFilter( sourceCase, m_sliceDirection ); + int gridIndex = 0; + RimCellFilter* lastCreatedOrUpdated = filtColl->addNewCellRangeFilter( sourceCase, gridIndex, m_sliceDirection ); if ( lastCreatedOrUpdated ) { Riu3DMainWindowTools::selectAsCurrentItem( lastCreatedOrUpdated ); diff --git a/ApplicationLibCode/Commands/ExportCommands/RicAdvancedSnapshotExportFeature.cpp b/ApplicationLibCode/Commands/ExportCommands/RicAdvancedSnapshotExportFeature.cpp index ae5a63373c..2fc2cf3946 100644 --- a/ApplicationLibCode/Commands/ExportCommands/RicAdvancedSnapshotExportFeature.cpp +++ b/ApplicationLibCode/Commands/ExportCommands/RicAdvancedSnapshotExportFeature.cpp @@ -262,7 +262,8 @@ void RicAdvancedSnapshotExportFeature::exportViewVariationsToFolder( RimGridView } else { - RimCellRangeFilter* rangeFilter = rimView->cellFilterCollection()->addNewCellRangeFilter( rimCase ); + int gridIndex = 0; + RimCellRangeFilter* rangeFilter = rimView->cellFilterCollection()->addNewCellRangeFilter( rimCase, gridIndex ); bool rangeFilterInitState = rimView->cellFilterCollection()->isActive(); rimView->cellFilterCollection()->setActive( true ); diff --git a/ApplicationLibCode/ProjectDataModel/CellFilters/RimCellFilter.cpp b/ApplicationLibCode/ProjectDataModel/CellFilters/RimCellFilter.cpp index ea330c5e6b..d213bd93a7 100644 --- a/ApplicationLibCode/ProjectDataModel/CellFilters/RimCellFilter.cpp +++ b/ApplicationLibCode/ProjectDataModel/CellFilters/RimCellFilter.cpp @@ -210,7 +210,6 @@ void RimCellFilter::defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& auto group = uiOrdering.addNewGroup( "General" ); group->add( &m_filterMode ); group->add( &m_gridIndex ); - group->add( &m_propagateToSubGrids ); bool readOnlyState = isFilterControlled(); diff --git a/ApplicationLibCode/ProjectDataModel/CellFilters/RimCellFilter.h b/ApplicationLibCode/ProjectDataModel/CellFilters/RimCellFilter.h index e90026aa61..3760c30ad0 100644 --- a/ApplicationLibCode/ProjectDataModel/CellFilters/RimCellFilter.h +++ b/ApplicationLibCode/ProjectDataModel/CellFilters/RimCellFilter.h @@ -69,7 +69,7 @@ public: void updateIconState(); void updateActiveState( bool isControlled ); - virtual void updateCompundFilter( cvf::CellRangeFilter* cellRangeFilter ) = 0; + virtual void updateCompundFilter( cvf::CellRangeFilter* cellRangeFilter, int gridIndex ) = 0; virtual QString fullName() const; protected: diff --git a/ApplicationLibCode/ProjectDataModel/CellFilters/RimCellFilterCollection.cpp b/ApplicationLibCode/ProjectDataModel/CellFilters/RimCellFilterCollection.cpp index 6dcf3068e9..40759a2580 100644 --- a/ApplicationLibCode/ProjectDataModel/CellFilters/RimCellFilterCollection.cpp +++ b/ApplicationLibCode/ProjectDataModel/CellFilters/RimCellFilterCollection.cpp @@ -263,10 +263,12 @@ RimUserDefinedFilter* RimCellFilterCollection::addNewUserDefinedFilter( RimCase* //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -RimCellRangeFilter* RimCellFilterCollection::addNewCellRangeFilter( RimCase* srcCase, int sliceDirection, int defaultSlice ) +RimCellRangeFilter* + RimCellFilterCollection::addNewCellRangeFilter( RimCase* srcCase, int gridIndex, int sliceDirection, int defaultSlice ) { RimCellRangeFilter* pFilter = new RimCellRangeFilter(); addFilter( pFilter ); + pFilter->setGridIndex( gridIndex ); pFilter->setDefaultValues( sliceDirection, defaultSlice ); onFilterUpdated( pFilter ); return pFilter; @@ -369,11 +371,13 @@ void RimCellFilterCollection::compoundCellRangeFilter( cvf::CellRangeFilter* cel { CVF_ASSERT( cellRangeFilter ); + int gIndx = static_cast( gridIndex ); + for ( RimCellFilter* filter : m_cellFilters ) { - if ( filter->isFilterEnabled() && static_cast( filter->gridIndex() ) == gridIndex ) + if ( filter->isFilterEnabled() ) { - filter->updateCompundFilter( cellRangeFilter ); + filter->updateCompundFilter( cellRangeFilter, gIndx ); } } } diff --git a/ApplicationLibCode/ProjectDataModel/CellFilters/RimCellFilterCollection.h b/ApplicationLibCode/ProjectDataModel/CellFilters/RimCellFilterCollection.h index 76d45ff75e..9cef295640 100644 --- a/ApplicationLibCode/ProjectDataModel/CellFilters/RimCellFilterCollection.h +++ b/ApplicationLibCode/ProjectDataModel/CellFilters/RimCellFilterCollection.h @@ -47,7 +47,8 @@ public: RimPolygonFilter* addNewPolygonFilter( RimCase* srcCase ); RimUserDefinedFilter* addNewUserDefinedFilter( RimCase* srcCase ); - RimCellRangeFilter* addNewCellRangeFilter( RimCase* srcCase, int sliceDirection = -1, int defaultSlice = -1 ); + RimCellRangeFilter* + addNewCellRangeFilter( RimCase* srcCase, int gridIndex, int sliceDirection = -1, int defaultSlice = -1 ); void removeFilter( RimCellFilter* filter ); @@ -71,12 +72,12 @@ public: void setCase( RimCase* theCase ); protected: - // Overridden methods void fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue ) override; void defineUiTreeOrdering( caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName ) override; caf::PdmFieldHandle* objectToggleField() override; void initAfterRead() override; - void onFilterUpdated( const SignalEmitter* emitter ); + + void onFilterUpdated( const SignalEmitter* emitter ); private: void setAutoName( RimCellFilter* pFilter ); diff --git a/ApplicationLibCode/ProjectDataModel/CellFilters/RimCellRangeFilter.cpp b/ApplicationLibCode/ProjectDataModel/CellFilters/RimCellRangeFilter.cpp index 8144edca0a..daa3bbecb5 100644 --- a/ApplicationLibCode/ProjectDataModel/CellFilters/RimCellRangeFilter.cpp +++ b/ApplicationLibCode/ProjectDataModel/CellFilters/RimCellRangeFilter.cpp @@ -58,6 +58,8 @@ RimCellRangeFilter::RimCellRangeFilter() CAF_PDM_InitField( &cellCountK, "CellCountK", 1, "Cell Count K", "", "", "" ); cellCountK.uiCapability()->setUiEditorTypeName( caf::PdmUiSliderEditor::uiEditorTypeName() ); + m_propagateToSubGrids = true; + updateIconState(); setDeletable( true ); } @@ -265,6 +267,8 @@ void RimCellRangeFilter::defineUiOrdering( QString uiConfigName, caf::PdmUiOrder { RimCellFilter::defineUiOrdering( uiConfigName, uiOrdering ); + m_gridIndex.uiCapability()->setUiReadOnly( true ); + const cvf::StructGridInterface* grid = selectedGrid(); RimCase* rimCase = nullptr; @@ -332,10 +336,12 @@ void RimCellRangeFilter::defineUiTreeOrdering( caf::PdmUiTreeOrdering& uiTreeOrd //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RimCellRangeFilter::updateCompundFilter( cvf::CellRangeFilter* cellRangeFilter ) +void RimCellRangeFilter::updateCompundFilter( cvf::CellRangeFilter* cellRangeFilter, int gridIndex ) { CVF_ASSERT( cellRangeFilter ); + if ( gridIndex != m_gridIndex ) return; + if ( filterMode() == RimCellFilter::INCLUDE ) { cellRangeFilter->addCellIncludeRange( static_cast( startIndexI ) - 1, diff --git a/ApplicationLibCode/ProjectDataModel/CellFilters/RimCellRangeFilter.h b/ApplicationLibCode/ProjectDataModel/CellFilters/RimCellRangeFilter.h index 25028c478b..40d556c7d8 100644 --- a/ApplicationLibCode/ProjectDataModel/CellFilters/RimCellRangeFilter.h +++ b/ApplicationLibCode/ProjectDataModel/CellFilters/RimCellRangeFilter.h @@ -57,7 +57,7 @@ public: void setDefaultValues( int sliceDirection = -1, int defaultSlice = -1 ); - void updateCompundFilter( cvf::CellRangeFilter* cellRangeFilter ) override; + void updateCompundFilter( cvf::CellRangeFilter* cellRangeFilter, int gridIndex ) override; protected: void fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue ) override; diff --git a/ApplicationLibCode/ProjectDataModel/CellFilters/RimPolygonFilter.cpp b/ApplicationLibCode/ProjectDataModel/CellFilters/RimPolygonFilter.cpp index efb04e63ca..67d97fe4f4 100644 --- a/ApplicationLibCode/ProjectDataModel/CellFilters/RimPolygonFilter.cpp +++ b/ApplicationLibCode/ProjectDataModel/CellFilters/RimPolygonFilter.cpp @@ -26,6 +26,7 @@ #include "RigGeoMechCaseData.h" #include "RigMainGrid.h" #include "RigPolyLinesData.h" +#include "RigReservoirGridTools.h" #include "Rim3dView.h" #include "RimCase.h" @@ -161,6 +162,8 @@ RimPolygonFilter::RimPolygonFilter() this->setUi3dEditorTypeName( RicPolyline3dEditor::uiEditorTypeName() ); this->uiCapability()->setUiTreeChildrenHidden( true ); + m_propagateToSubGrids = false; + updateIconState(); setDeletable( true ); } @@ -237,7 +240,12 @@ QString RimPolygonFilter::fullName() const { if ( m_enableFiltering ) { - return QString( "%1 [%2 cells]" ).arg( RimCellFilter::fullName(), QString::number( m_cells.size() ) ); + int cells = 0; + for ( const auto& item : m_cells ) + { + cells += (int)item.size(); + } + return QString( "%1 [%2 cells]" ).arg( RimCellFilter::fullName(), QString::number( cells ) ); } return QString( "%1 [off]" ).arg( RimCellFilter::fullName() ); } @@ -399,8 +407,6 @@ void RimPolygonFilter::defineUiOrdering( QString uiConfigName, caf::PdmUiOrderin auto group3 = uiOrdering.addNewGroup( "Advanced Filter Settings" ); group3->add( &m_enableKFilter ); group3->add( &m_kFilterStr ); - group3->add( &m_gridIndex ); - group3->add( &m_propagateToSubGrids ); group3->setCollapsedByDefault( true ); uiOrdering.skipRemainingFields( true ); @@ -468,18 +474,24 @@ caf::PickEventHandler* RimPolygonFilter::pickEventHandler() const //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RimPolygonFilter::updateCompundFilter( cvf::CellRangeFilter* cellRangeFilter ) +void RimPolygonFilter::updateCompundFilter( cvf::CellRangeFilter* cellRangeFilter, int gridIndex ) { CVF_ASSERT( cellRangeFilter ); if ( !m_enableFiltering ) return; - if ( m_cells.size() == 0 ) updateCells(); + const int noofgrids = static_cast( m_cells.size() ); + if ( ( noofgrids == 0 ) || ( gridIndex >= noofgrids ) ) + { + updateCells(); + } - const auto grid = selectedGrid(); + if ( gridIndex >= static_cast( m_cells.size() ) ) return; + + const auto grid = RigReservoirGridTools::gridByIndex( m_srcCase, gridIndex ); size_t i, j, k; - for ( size_t cellidx : m_cells ) + for ( size_t cellidx : m_cells[gridIndex] ) { grid->ijkFromCellIndex( cellidx, &i, &j, &k ); if ( this->filterMode() == RimCellFilter::INCLUDE ) @@ -531,14 +543,15 @@ bool RimPolygonFilter::cellInsidePolygon2D( cvf::Vec3d center, return bInside; } -void RimPolygonFilter::updateCellsDepthEclipse( const std::vector& points, const RigMainGrid* grid ) +void RimPolygonFilter::updateCellsDepthEclipse( const std::vector& points, const RigGridBase* grid ) { // we should look in depth using Z coordinate + const int gIdx = static_cast( grid->gridIndex() ); // loop over all cells for ( size_t n = 0; n < grid->cellCount(); n++ ) { // valid cell? - RigCell cell = grid->cellByGridAndGridLocalCellIdx( gridIndex(), n ); + RigCell cell = grid->cell( n ); if ( cell.isInvalid() ) continue; // get corner coordinates @@ -553,7 +566,7 @@ void RimPolygonFilter::updateCellsDepthEclipse( const std::vector& p // check if the polygon includes the cell if ( cellInsidePolygon2D( cell.center(), hexCorners, points ) ) { - m_cells.push_back( n ); + m_cells[gIdx].push_back( n ); } } } @@ -564,50 +577,19 @@ void RimPolygonFilter::updateCellsDepthEclipse( const std::vector& p // 2. find all cells in this K layer that matches the selection criteria // 3. extend those cells to all K layers //-------------------------------------------------------------------------------------------------- -void RimPolygonFilter::updateCellsKIndexEclipse( const std::vector& points, const RigMainGrid* grid ) +void RimPolygonFilter::updateCellsKIndexEclipse( const std::vector& points, const RigGridBase* grid, int K ) { - // we need to find the K layer we hit with the first point - size_t ni, nj, nk; - // move the point a bit downwards to make sure it is inside something - cvf::Vec3d point = points[0]; - point.z() += 0.2; - - bool cellFound = false; - - // loop over all points to find at least one point with a valid K layer - for ( size_t p = 0; p < points.size() - 1; p++ ) - { - // loop over all cells to find the correct one - for ( size_t i = 0; i < grid->cellCount(); i++ ) - { - // valid cell? - RigCell cell = grid->cellByGridAndGridLocalCellIdx( gridIndex(), i ); - if ( cell.isInvalid() ) continue; - - // is the point inside? - cvf::BoundingBox bb = cell.boundingBox(); - if ( !bb.contains( points[p] ) ) continue; - - // found the cell, get the IJK - grid->ijkFromCellIndexUnguarded( cell.mainGridCellIndex(), &ni, &nj, &nk ); - cellFound = true; - break; - } - if ( cellFound ) break; - } - - // should not really happen, but just to be sure - if ( !cellFound ) return; + const int gIdx = static_cast( grid->gridIndex() ); std::list foundCells; - // find all cells in this K layer that matches the polygon + // find all cells in the K layer that matches the polygon for ( size_t i = 0; i < grid->cellCountI(); i++ ) { for ( size_t j = 0; j < grid->cellCountJ(); j++ ) { - size_t cellIdx = grid->cellIndexFromIJK( i, j, nk ); - RigCell cell = grid->cellByGridAndGridLocalCellIdx( gridIndex(), cellIdx ); + size_t cellIdx = grid->cellIndexFromIJK( i, j, K ); + RigCell cell = grid->cell( cellIdx ); // valid cell? if ( cell.isInvalid() ) continue; @@ -636,10 +618,10 @@ void RimPolygonFilter::updateCellsKIndexEclipse( const std::vector& // get the cell index size_t newIdx = grid->cellIndexFromIJK( ci, cj, k ); // valid cell? - RigCell cell = grid->cellByGridAndGridLocalCellIdx( gridIndex(), newIdx ); + RigCell cell = grid->cell( newIdx ); if ( cell.isInvalid() ) continue; - m_cells.push_back( newIdx ); + m_cells[gIdx].push_back( newIdx ); } } } @@ -652,16 +634,24 @@ void RimPolygonFilter::updateCellsForEclipse( const std::vector& poi RigEclipseCaseData* data = eCase->eclipseCaseData(); if ( !data ) return; - RigMainGrid* grid = data->mainGrid(); - if ( !grid ) return; - if ( m_polyFilterMode == PolygonFilterModeType::DEPTH_Z ) { - updateCellsDepthEclipse( points, grid ); + for ( size_t gridIndex = 0; gridIndex < data->gridCount(); gridIndex++ ) + { + auto grid = data->grid( gridIndex ); + updateCellsDepthEclipse( points, grid ); + } } else if ( m_polyFilterMode == PolygonFilterModeType::INDEX_K ) { - updateCellsKIndexEclipse( points, grid ); + int K = findEclipseKLayer( points, data ); + if ( K < 0 ) return; + + for ( size_t gridIndex = 0; gridIndex < data->gridCount(); gridIndex++ ) + { + auto grid = data->grid( gridIndex ); + updateCellsKIndexEclipse( points, grid, K ); + } } } @@ -693,7 +683,7 @@ void RimPolygonFilter::updateCellsDepthGeoMech( const std::vector& p // check if the polygon includes the cell if ( cellInsidePolygon2D( center, corners, points ) ) { - m_cells.push_back( cellIdx ); + m_cells[0].push_back( cellIdx ); } } } @@ -787,7 +777,7 @@ void RimPolygonFilter::updateCellsKIndexGeoMech( const std::vector& // get the cell index size_t newIdx = grid->cellIndexFromIJK( ci, cj, k ); - m_cells.push_back( newIdx ); + m_cells[0].push_back( newIdx ); } } } @@ -813,12 +803,12 @@ void RimPolygonFilter::updateCellsForGeoMech( const std::vector& poi } //-------------------------------------------------------------------------------------------------- -/// Update the cell index list with the cells that are inside our polygon, if any +/// Update the cell index map with the cells that are inside our polygon, if any //-------------------------------------------------------------------------------------------------- void RimPolygonFilter::updateCells() { - // reset - m_cells.clear(); + // reset cell map for all grids + initializeCellList(); // get optional k-cell filter m_intervalTool.setInterval( m_enableKFilter, m_kFilterStr ); @@ -833,7 +823,7 @@ void RimPolygonFilter::updateCells() // We need at least three points to make a sensible polygon if ( points.size() < 3 ) return; - // make sure first and last point is the same (req. by polygon methods later) + // make sure first and last point is the same (req. by polygon methods used later) points.push_back( points.front() ); RimEclipseCase* eCase = dynamic_cast( m_srcCase() ); @@ -877,3 +867,72 @@ cvf::ref RimPolygonFilter::polyLinesData() const return pld; } + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimPolygonFilter::initializeCellList() +{ + m_cells.clear(); + + int gridCount = RigReservoirGridTools::gridCount( m_srcCase() ); + for ( int i = 0; i < gridCount; i++ ) + { + m_cells.push_back( std::vector() ); + } +} + +//-------------------------------------------------------------------------------------------------- +/// Find which K layer we hit, in any of the grids, for any of the selected points +//-------------------------------------------------------------------------------------------------- +int RimPolygonFilter::findEclipseKLayer( const std::vector& points, RigEclipseCaseData* data ) +{ + size_t ni, nj, nk; + + // look for a hit in the main grid frist + RigMainGrid* mainGrid = data->mainGrid(); + for ( size_t p = 0; p < points.size() - 1; p++ ) + { + size_t cIdx = mainGrid->findReservoirCellIndexFromPoint( points[p] ); + if ( cIdx != cvf::UNDEFINED_SIZE_T ) + { + mainGrid->ijkFromCellIndexUnguarded( cIdx, &ni, &nj, &nk ); + if ( mainGrid->isCellValid( ni, nj, nk ) ) return static_cast( nk ); + } + } + + // loop over all sub-grids to find one with a cell hit in case main grid search failed + for ( size_t gridIndex = 1; gridIndex < data->gridCount(); gridIndex++ ) + { + auto grid = data->grid( gridIndex ); + + // loop over all cells to find the correct one + for ( size_t i = 0; i < grid->cellCount(); i++ ) + { + // valid cell? + RigCell cell = grid->cell( i ); + if ( cell.isInvalid() ) continue; + + // is the point inside cell bb? + cvf::BoundingBox bb; + std::array hexCorners; + grid->cellCornerVertices( i, hexCorners.data() ); + for ( const auto& corner : hexCorners ) + { + bb.add( corner ); + } + + // loop over all points to find at least one point with a valid K layer + for ( size_t p = 0; p < points.size() - 1; p++ ) + { + if ( bb.contains( points[p] ) ) + { + // found the cell, get the IJK + grid->ijkFromCellIndexUnguarded( i, &ni, &nj, &nk ); + return static_cast( nk ); + } + } + } + } + return -1; +} diff --git a/ApplicationLibCode/ProjectDataModel/CellFilters/RimPolygonFilter.h b/ApplicationLibCode/ProjectDataModel/CellFilters/RimPolygonFilter.h index 7c7eb0f207..3fcd0df7b1 100644 --- a/ApplicationLibCode/ProjectDataModel/CellFilters/RimPolygonFilter.h +++ b/ApplicationLibCode/ProjectDataModel/CellFilters/RimPolygonFilter.h @@ -42,9 +42,11 @@ class RimPolylineTarget; class RimCase; class RimEclipseCase; class RimGeoMechCase; +class RigGridBase; class RigMainGrid; class RigFemPartGrid; class RigPolylinesData; +class RigEclipseCaseData; //================================================================================================== /// @@ -87,7 +89,7 @@ public: bool pickingEnabled() const override; caf::PickEventHandler* pickEventHandler() const override; - void updateCompundFilter( cvf::CellRangeFilter* cellRangeFilter ) override; + void updateCompundFilter( cvf::CellRangeFilter* cellRangeFilter, int gridIndex ) override; cvf::ref polyLinesData() const override; @@ -108,13 +110,17 @@ private: void updateCellsForEclipse( const std::vector& points, RimEclipseCase* eCase ); void updateCellsForGeoMech( const std::vector& points, RimGeoMechCase* gCase ); - void updateCellsDepthEclipse( const std::vector& points, const RigMainGrid* grid ); - void updateCellsKIndexEclipse( const std::vector& points, const RigMainGrid* grid ); + void updateCellsDepthEclipse( const std::vector& points, const RigGridBase* grid ); + void updateCellsKIndexEclipse( const std::vector& points, const RigGridBase* grid, int K ); + int findEclipseKLayer( const std::vector& points, RigEclipseCaseData* data ); + void updateCellsDepthGeoMech( const std::vector& points, const RigFemPartGrid* grid ); void updateCellsKIndexGeoMech( const std::vector& points, const RigFemPartGrid* grid ); bool cellInsidePolygon2D( cvf::Vec3d center, std::array& corners, std::vector polygon ); + void initializeCellList(); + caf::PdmField m_enablePicking; caf::PdmChildArrayField m_targets; caf::PdmField> m_polyFilterMode; @@ -134,7 +140,7 @@ private: std::shared_ptr m_pickTargetsEventHandler; - std::list m_cells; + std::vector> m_cells; RimCellFilterIntervalTool m_intervalTool; }; diff --git a/ApplicationLibCode/ProjectDataModel/CellFilters/RimPropertyFilter.h b/ApplicationLibCode/ProjectDataModel/CellFilters/RimPropertyFilter.h index 55a081b9d0..4210a2eba0 100644 --- a/ApplicationLibCode/ProjectDataModel/CellFilters/RimPropertyFilter.h +++ b/ApplicationLibCode/ProjectDataModel/CellFilters/RimPropertyFilter.h @@ -34,7 +34,7 @@ public: std::vector selectedCategoryValues() const; - void updateCompundFilter( cvf::CellRangeFilter* cellRangeFilter ) override{}; + void updateCompundFilter( cvf::CellRangeFilter* cellRangeFilter, int gridIndex ) override{}; protected: void setCategoryValues( const std::vector& categoryValues ); diff --git a/ApplicationLibCode/ProjectDataModel/CellFilters/RimUserDefinedFilter.cpp b/ApplicationLibCode/ProjectDataModel/CellFilters/RimUserDefinedFilter.cpp index 0dfa26e9d2..ee4c303716 100644 --- a/ApplicationLibCode/ProjectDataModel/CellFilters/RimUserDefinedFilter.cpp +++ b/ApplicationLibCode/ProjectDataModel/CellFilters/RimUserDefinedFilter.cpp @@ -35,6 +35,8 @@ RimUserDefinedFilter::RimUserDefinedFilter() "Use Ctrl-C for copy and Ctrl-V for paste", "" ); + m_propagateToSubGrids = true; + updateIconState(); setDeletable( true ); } @@ -85,10 +87,12 @@ void RimUserDefinedFilter::fieldChangedByUi( const caf::PdmFieldHandle* changedF //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RimUserDefinedFilter::updateCompundFilter( cvf::CellRangeFilter* cellRangeFilter ) +void RimUserDefinedFilter::updateCompundFilter( cvf::CellRangeFilter* cellRangeFilter, int gridIndex ) { CVF_ASSERT( cellRangeFilter ); + if ( gridIndex != m_gridIndex ) return; + if ( this->filterMode() == RimCellFilter::INCLUDE ) { for ( const auto& cellIndex : m_individualCellIndices() ) diff --git a/ApplicationLibCode/ProjectDataModel/CellFilters/RimUserDefinedFilter.h b/ApplicationLibCode/ProjectDataModel/CellFilters/RimUserDefinedFilter.h index cf7de5dbea..4747de5009 100644 --- a/ApplicationLibCode/ProjectDataModel/CellFilters/RimUserDefinedFilter.h +++ b/ApplicationLibCode/ProjectDataModel/CellFilters/RimUserDefinedFilter.h @@ -37,7 +37,7 @@ public: RimUserDefinedFilter(); ~RimUserDefinedFilter() override; - void updateCompundFilter( cvf::CellRangeFilter* cellRangeFilter ) override; + void updateCompundFilter( cvf::CellRangeFilter* cellRangeFilter, int gridIndex ) override; protected: void defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) override; diff --git a/ApplicationLibCode/ReservoirDataModel/RigCell.cpp b/ApplicationLibCode/ReservoirDataModel/RigCell.cpp index 6982aa9e46..504d9cd18d 100644 --- a/ApplicationLibCode/ReservoirDataModel/RigCell.cpp +++ b/ApplicationLibCode/ReservoirDataModel/RigCell.cpp @@ -430,9 +430,9 @@ cvf::BoundingBox RigCell::boundingBox() const cvf::BoundingBox bb; std::array hexCorners; - if ( m_hostGrid && m_hostGrid->mainGrid() ) + if ( m_hostGrid ) { - m_hostGrid->mainGrid()->cellCornerVertices( mainGridCellIndex(), hexCorners.data() ); + m_hostGrid->cellCornerVertices( m_gridLocalCellIndex, hexCorners.data() ); for ( const auto& corner : hexCorners ) { bb.add( corner ); @@ -442,7 +442,7 @@ cvf::BoundingBox RigCell::boundingBox() const } //-------------------------------------------------------------------------------------------------- -/// Return the neighbor cell of the given face +/// Return the main grid neighbor cell of the given face //-------------------------------------------------------------------------------------------------- RigCell RigCell::neighborCell( cvf::StructGridInterface::FaceType face ) const { From acdc1d5c15a8075bbf2608b1b454acd5fa9be7cd Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Tue, 15 Jun 2021 12:17:50 +0200 Subject: [PATCH 03/14] #7780 Polyline Cell Filter : Make sure event handler is unregistered --- .../WellPathCommands/RicPolylineTargetsPickEventHandler.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/ApplicationLibCode/Commands/WellPathCommands/RicPolylineTargetsPickEventHandler.cpp b/ApplicationLibCode/Commands/WellPathCommands/RicPolylineTargetsPickEventHandler.cpp index ae08f98569..804620a0b6 100644 --- a/ApplicationLibCode/Commands/WellPathCommands/RicPolylineTargetsPickEventHandler.cpp +++ b/ApplicationLibCode/Commands/WellPathCommands/RicPolylineTargetsPickEventHandler.cpp @@ -52,6 +52,7 @@ RicPolylineTargetsPickEventHandler::RicPolylineTargetsPickEventHandler( RimPolyl //-------------------------------------------------------------------------------------------------- RicPolylineTargetsPickEventHandler::~RicPolylineTargetsPickEventHandler() { + Ric3dViewPickEventHandler::unregisterAsPickEventHandler(); } //-------------------------------------------------------------------------------------------------- From 27b1d6ebfb1a6e17b6af887c0474fd8400347ea9 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Tue, 15 Jun 2021 16:00:47 +0200 Subject: [PATCH 04/14] Octave : Always execute command objects in queue before return --- ApplicationLibCode/Application/RiaGuiApplication.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ApplicationLibCode/Application/RiaGuiApplication.cpp b/ApplicationLibCode/Application/RiaGuiApplication.cpp index 74f13726c0..287f19f2a2 100644 --- a/ApplicationLibCode/Application/RiaGuiApplication.cpp +++ b/ApplicationLibCode/Application/RiaGuiApplication.cpp @@ -1582,6 +1582,9 @@ void RiaGuiApplication::slotWorkerProcessFinished( int exitCode, QProcess::ExitS } m_workerProcess = nullptr; + // Always make sure the command objects are executed before any return statement + executeCommandObjects(); + // Either the work process crashed or was aborted by the user if ( exitStatus == QProcess::CrashExit ) { @@ -1590,8 +1593,6 @@ void RiaGuiApplication::slotWorkerProcessFinished( int exitCode, QProcess::ExitS return; } - executeCommandObjects(); - // Exit code != 0 means we have an error if ( exitCode != 0 ) { From 273e416b409b5164986754ee390291a6c15f9382 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Fri, 25 Jun 2021 14:18:36 +0200 Subject: [PATCH 05/14] Python adjustments (#7809) * #7797 Well Targets: Add scripting capability * #7794 Python : Do not update childField or childFieldArray * #7797: Python - Add scripting to well path collection - Extend the pdmobject.py with method add_object() - allow objects to be created from Python in well path collections - add well targets to modelled well path * #7795 Python : Make sure referenced generated classes are defined * #7810 StimPlanModel: clean-up python generation * Python : Always use empty string as default value for ptrFieldValue It can happen that a ptrField is assigned to a pointer on object construction. (FaciesProperties) Make sure that constructor always assigns an empty string. Co-authored-by: magnesj Co-authored-by: Kristian Bendiksen --- .../Application/RiaApplication.cpp | 21 ++++- .../Application/RiaGuiApplication.cpp | 2 +- .../RicImportFormationNamesFeature.cpp | 4 +- .../CellFilters/RimCellFilterCollection.cpp | 2 +- ...sembleFractureStatisticsPlotCollection.cpp | 4 +- .../RimGridStatisticsPlotCollection.cpp | 4 +- .../RimWellPathCollection.cpp | 22 ++++- .../ProjectDataModel/RimWellPathCollection.h | 2 + .../ProjectDataModel/RimWellPathGroup.cpp | 30 +++---- .../ProjectDataModel/RimWellPathTarget.cpp | 20 +++-- .../RimFaciesInitialPressureConfig.cpp | 10 ++- .../StimPlanModel/RimPressureTable.cpp | 8 +- .../StimPlanModel/RimPressureTableItem.cpp | 10 ++- .../cafPdmScripting/cafPdmCodeGenerator.h | 4 +- .../cafPdmMarkdownGenerator.cpp | 2 +- .../cafPdmScripting/cafPdmMarkdownGenerator.h | 2 +- .../cafPdmScripting/cafPdmPythonGenerator.cpp | 26 +++++- .../cafPdmScripting/cafPdmPythonGenerator.h | 4 +- .../cafPdmScriptingBasicTest.cpp | 3 +- .../cafPdmCore/cafPdmObjectHandle.h | 2 + GrpcInterface/GrpcProtos/PdmObject.proto | 1 + GrpcInterface/Python/rips/pdmobject.py | 35 ++++++++ .../Python/rips/tests/create_well_path.py | 35 ++++++++ GrpcInterface/Python/setup.py.cmake | 2 +- GrpcInterface/RiaGrpcCommandService.cpp | 2 +- GrpcInterface/RiaGrpcPdmObjectService.cpp | 12 ++- GrpcInterface/RiaGrpcServiceInterface.cpp | 89 ++++++++++++++++--- GrpcInterface/RiaGrpcServiceInterface.h | 9 +- 28 files changed, 294 insertions(+), 73 deletions(-) create mode 100644 GrpcInterface/Python/rips/tests/create_well_path.py diff --git a/ApplicationLibCode/Application/RiaApplication.cpp b/ApplicationLibCode/Application/RiaApplication.cpp index 493572af43..53619538b0 100644 --- a/ApplicationLibCode/Application/RiaApplication.cpp +++ b/ApplicationLibCode/Application/RiaApplication.cpp @@ -1555,7 +1555,9 @@ bool RiaApplication::generateCode( const QString& fileName, gsl::not_nullgenerate( caf::PdmDefaultObjectFactory::instance() ); + std::vector logMessages; + + out << generator->generate( caf::PdmDefaultObjectFactory::instance(), logMessages ); } { @@ -1613,7 +1615,22 @@ bool RiaApplication::generateCode( const QString& fileName, gsl::not_nullgenerate( caf::PdmDefaultObjectFactory::instance() ); + std::vector logMessages; + + out << generator->generate( caf::PdmDefaultObjectFactory::instance(), logMessages ); + + QString errorText; + for ( const auto& msg : logMessages ) + { + errorText += msg; + errorText += "\n"; + } + + if ( !errorText.isEmpty() ) + { + *errMsg = errorText; + return false; + } } return true; diff --git a/ApplicationLibCode/Application/RiaGuiApplication.cpp b/ApplicationLibCode/Application/RiaGuiApplication.cpp index 287f19f2a2..2df91a9845 100644 --- a/ApplicationLibCode/Application/RiaGuiApplication.cpp +++ b/ApplicationLibCode/Application/RiaGuiApplication.cpp @@ -453,7 +453,7 @@ RiaApplication::ApplicationStatus RiaGuiApplication::handleArguments( gsl::not_n if ( !RiaApplication::generateCode( outputFile, &errMsg ) ) { RiaLogging::error( QString( "Error: %1" ).arg( errMsg ) ); - return RiaApplication::ApplicationStatus::EXIT_WITH_ERROR; + return RiaApplication::ApplicationStatus::KEEP_GOING; } return RiaApplication::ApplicationStatus::EXIT_COMPLETED; diff --git a/ApplicationLibCode/Commands/RicImportFormationNamesFeature.cpp b/ApplicationLibCode/Commands/RicImportFormationNamesFeature.cpp index 6ee33db26b..c4916cb28a 100644 --- a/ApplicationLibCode/Commands/RicImportFormationNamesFeature.cpp +++ b/ApplicationLibCode/Commands/RicImportFormationNamesFeature.cpp @@ -89,7 +89,9 @@ RimFormationNames* RicImportFormationNamesFeature::importFormationFiles( const Q } } - return formationNames.back(); + if ( !formationNames.empty() ) return formationNames.back(); + + return nullptr; } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationLibCode/ProjectDataModel/CellFilters/RimCellFilterCollection.cpp b/ApplicationLibCode/ProjectDataModel/CellFilters/RimCellFilterCollection.cpp index 40759a2580..f4b1dd7fad 100644 --- a/ApplicationLibCode/ProjectDataModel/CellFilters/RimCellFilterCollection.cpp +++ b/ApplicationLibCode/ProjectDataModel/CellFilters/RimCellFilterCollection.cpp @@ -44,7 +44,7 @@ RimCellFilterCollection::RimCellFilterCollection() CAF_PDM_InitScriptableField( &m_isActive, "Active", true, "Active", "", "", "" ); m_isActive.uiCapability()->setUiHidden( true ); - CAF_PDM_InitScriptableFieldNoDefault( &m_cellFilters, "CellFilters", "Filters", "", "", "" ); + CAF_PDM_InitFieldNoDefault( &m_cellFilters, "CellFilters", "Filters", "", "", "" ); m_cellFilters.uiCapability()->setUiTreeHidden( true ); caf::PdmFieldReorderCapability::addToField( &m_cellFilters ); diff --git a/ApplicationLibCode/ProjectDataModel/RimEnsembleFractureStatisticsPlotCollection.cpp b/ApplicationLibCode/ProjectDataModel/RimEnsembleFractureStatisticsPlotCollection.cpp index df2823f6d3..949ec056f2 100644 --- a/ApplicationLibCode/ProjectDataModel/RimEnsembleFractureStatisticsPlotCollection.cpp +++ b/ApplicationLibCode/ProjectDataModel/RimEnsembleFractureStatisticsPlotCollection.cpp @@ -30,9 +30,9 @@ CAF_PDM_SOURCE_INIT( RimEnsembleFractureStatisticsPlotCollection, "EnsembleFract //-------------------------------------------------------------------------------------------------- RimEnsembleFractureStatisticsPlotCollection::RimEnsembleFractureStatisticsPlotCollection() { - CAF_PDM_InitScriptableObject( "Ensemble Fracture Statistics Plots", ":/WellLogPlots16x16.png", "", "" ); + CAF_PDM_InitObject( "Ensemble Fracture Statistics Plots", ":/WellLogPlots16x16.png", "", "" ); - CAF_PDM_InitScriptableFieldNoDefault( &m_ensembleFractureStatisticsPlots, "EnsembleFractureStatisticsPlots", "", "", "", "" ); + CAF_PDM_InitFieldNoDefault( &m_ensembleFractureStatisticsPlots, "EnsembleFractureStatisticsPlots", "", "", "", "" ); m_ensembleFractureStatisticsPlots.uiCapability()->setUiHidden( true ); } diff --git a/ApplicationLibCode/ProjectDataModel/RimGridStatisticsPlotCollection.cpp b/ApplicationLibCode/ProjectDataModel/RimGridStatisticsPlotCollection.cpp index b33f58261d..31e7422bc3 100644 --- a/ApplicationLibCode/ProjectDataModel/RimGridStatisticsPlotCollection.cpp +++ b/ApplicationLibCode/ProjectDataModel/RimGridStatisticsPlotCollection.cpp @@ -30,9 +30,9 @@ CAF_PDM_SOURCE_INIT( RimGridStatisticsPlotCollection, "GridStatisticsPlotCollect //-------------------------------------------------------------------------------------------------- RimGridStatisticsPlotCollection::RimGridStatisticsPlotCollection() { - CAF_PDM_InitScriptableObject( "Grid Statistics Plots", ":/WellLogPlots16x16.png", "", "" ); + CAF_PDM_InitObject( "Grid Statistics Plots", ":/WellLogPlots16x16.png", "", "" ); - CAF_PDM_InitScriptableFieldNoDefault( &m_gridStatisticsPlots, "GridStatisticsPlots", "", "", "", "" ); + CAF_PDM_InitFieldNoDefault( &m_gridStatisticsPlots, "GridStatisticsPlots", "", "", "", "" ); m_gridStatisticsPlots.uiCapability()->setUiHidden( true ); } diff --git a/ApplicationLibCode/ProjectDataModel/RimWellPathCollection.cpp b/ApplicationLibCode/ProjectDataModel/RimWellPathCollection.cpp index 8879113ba0..f31df93ae2 100644 --- a/ApplicationLibCode/ProjectDataModel/RimWellPathCollection.cpp +++ b/ApplicationLibCode/ProjectDataModel/RimWellPathCollection.cpp @@ -54,6 +54,8 @@ #include "Riu3DMainWindowTools.h" +#include "cafPdmFieldScriptingCapability.h" +#include "cafPdmObjectScriptingCapability.h" #include "cafPdmUiEditorHandle.h" #include "cafPdmUiTreeOrdering.h" #include "cafProgressInfo.h" @@ -83,7 +85,12 @@ CAF_PDM_SOURCE_INIT( RimWellPathCollection, "WellPaths" ); //-------------------------------------------------------------------------------------------------- RimWellPathCollection::RimWellPathCollection() { - CAF_PDM_InitObject( "Wells", ":/WellCollection.png", "", "" ); + CAF_PDM_InitScriptableObjectWithNameAndComment( "Wells", + ":/WellCollection.png", + "", + "", + "WellPathCollection", + "Collection of Well Paths" ); CAF_PDM_InitField( &isActive, "Active", true, "Active", "", "", "" ); isActive.uiCapability()->setUiHidden( true ); @@ -109,7 +116,7 @@ RimWellPathCollection::RimWellPathCollection() CAF_PDM_InitField( &wellPathClip, "WellPathClip", true, "Clip Well Paths", "", "", "" ); CAF_PDM_InitField( &wellPathClipZDistance, "WellPathClipZDistance", 100, "Well Path Clipping Depth Distance", "", "", "" ); - CAF_PDM_InitFieldNoDefault( &m_wellPaths, "WellPaths", "Well Paths", "", "", "" ); + CAF_PDM_InitScriptableFieldNoDefault( &m_wellPaths, "WellPaths", "Well Paths", "", "", "" ); m_wellPaths.uiCapability()->setUiHidden( true ); m_wellPaths.uiCapability()->setUiTreeHidden( true ); m_wellPaths.uiCapability()->setUiTreeChildrenHidden( true ); @@ -977,3 +984,14 @@ void RimWellPathCollection::onChildDeleted( caf::PdmChildArrayFieldHandle* scheduleRedrawAffectedViews(); uiCapability()->updateConnectedEditors(); } + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimWellPathCollection::onChildAdded( caf::PdmFieldHandle* containerForNewObject ) +{ + rebuildWellPathNodes(); + + scheduleRedrawAffectedViews(); + uiCapability()->updateConnectedEditors(); +} diff --git a/ApplicationLibCode/ProjectDataModel/RimWellPathCollection.h b/ApplicationLibCode/ProjectDataModel/RimWellPathCollection.h index 97964b3500..2f22495b2d 100644 --- a/ApplicationLibCode/ProjectDataModel/RimWellPathCollection.h +++ b/ApplicationLibCode/ProjectDataModel/RimWellPathCollection.h @@ -127,6 +127,8 @@ public: void onChildDeleted( caf::PdmChildArrayFieldHandle* childArray, std::vector& referringObjects ) override; + void onChildAdded( caf::PdmFieldHandle* containerForNewObject ) override; + protected: void fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue ) override; diff --git a/ApplicationLibCode/ProjectDataModel/RimWellPathGroup.cpp b/ApplicationLibCode/ProjectDataModel/RimWellPathGroup.cpp index 081c47fb2a..f1afeb8997 100644 --- a/ApplicationLibCode/ProjectDataModel/RimWellPathGroup.cpp +++ b/ApplicationLibCode/ProjectDataModel/RimWellPathGroup.cpp @@ -25,8 +25,7 @@ #include "RimWellPathCompletions.h" #include "RimWellPathValve.h" -#include "cafPdmFieldScriptingCapability.h" -#include "cafPdmObjectScriptingCapability.h" +#include "cafPdmObject.h" #include "cafPdmUiTreeOrdering.h" #include @@ -38,23 +37,18 @@ CAF_PDM_SOURCE_INIT( RimWellPathGroup, "WellPathGroup" ); //-------------------------------------------------------------------------------------------------- RimWellPathGroup::RimWellPathGroup() { - CAF_PDM_InitScriptableObjectWithNameAndComment( "Well Path Group", - ":/WellPathGroup.svg", - "", - "", - "WellPathGroup", - "A Group of Well Paths" ); - CAF_PDM_InitScriptableFieldNoDefault( &m_childWellPaths, "ChildWellPaths", "Child Well Paths", "", "", "" ); - CAF_PDM_InitScriptableFieldNoDefault( &m_groupName, "GroupName", "Group Name", "", "", "" ); + CAF_PDM_InitObject( "Well Path Group", ":/WellPathGroup.svg", "", "" ); + CAF_PDM_InitFieldNoDefault( &m_childWellPaths, "ChildWellPaths", "Child Well Paths", "", "", "" ); + CAF_PDM_InitFieldNoDefault( &m_groupName, "GroupName", "Group Name", "", "", "" ); - CAF_PDM_InitScriptableField( &m_addValveAtConnection, - "AddValveAtConnection", - false, - "Add Outlet Valve for Branches", - "", - "Should an outlet valve be added to branches for MSW export?", - "" ); - CAF_PDM_InitScriptableFieldNoDefault( &m_valve, "Valve", "Branch Outlet Valve", "", "", "" ); + CAF_PDM_InitField( &m_addValveAtConnection, + "AddValveAtConnection", + false, + "Add Outlet Valve for Branches", + "", + "Should an outlet valve be added to branches for MSW export?", + "" ); + CAF_PDM_InitFieldNoDefault( &m_valve, "Valve", "Branch Outlet Valve", "", "", "" ); m_valve = new RimWellPathValve; m_groupName.registerGetMethod( this, &RimWellPathGroup::createGroupName ); diff --git a/ApplicationLibCode/ProjectDataModel/RimWellPathTarget.cpp b/ApplicationLibCode/ProjectDataModel/RimWellPathTarget.cpp index 652a76ff37..97dfb1c189 100644 --- a/ApplicationLibCode/ProjectDataModel/RimWellPathTarget.cpp +++ b/ApplicationLibCode/ProjectDataModel/RimWellPathTarget.cpp @@ -26,6 +26,9 @@ #include "RimWellPath.h" #include "RimWellPathGeometryDef.h" +#include "cafPdmFieldScriptingCapability.h" +#include "cafPdmFieldScriptingCapabilityCvfVec3d.h" +#include "cafPdmObjectScriptingCapability.h" #include "cafPdmUiCheckBoxEditor.h" #include "cafPdmUiLineEditor.h" @@ -54,19 +57,26 @@ RimWellPathTarget::RimWellPathTarget() , m_inclination( 0.0 ) , m_isFullUpdateEnabled( true ) { + CAF_PDM_InitScriptableObjectWithNameAndComment( "Well Target", + "", + "", + "", + "WellPathTarget", + "Class containing the Well Target definition" ); + CAF_PDM_InitField( &m_isEnabled, "IsEnabled", true, "", "", "", "" ); CAF_PDM_InitField( &m_isLocked, "IsLocked", false, "", "", "", "" ); m_isLocked.uiCapability()->setUiHidden( true ); // m_targetType.uiCapability()->setUiHidden(true); - CAF_PDM_InitFieldNoDefault( &m_targetPoint, "TargetPoint", "Point", "", "", "" ); - CAF_PDM_InitField( &m_dogleg1, "Dogleg1", 3.0, "DL in", "", "[deg/30m]", "" ); - CAF_PDM_InitField( &m_dogleg2, "Dogleg2", 3.0, "DL out", "", "[deg/30m]", "" ); + CAF_PDM_InitScriptableFieldNoDefault( &m_targetPoint, "TargetPoint", "Point", "", "", "" ); + CAF_PDM_InitScriptableField( &m_dogleg1, "Dogleg1", 3.0, "DL in", "", "[deg/30m]", "" ); + CAF_PDM_InitScriptableField( &m_dogleg2, "Dogleg2", 3.0, "DL out", "", "[deg/30m]", "" ); CAF_PDM_InitFieldNoDefault( &m_targetType, "TargetType", "Type", "", "", "" ); m_targetType.uiCapability()->setUiHidden( true ); CAF_PDM_InitField( &m_hasTangentConstraintUiField, "HasTangentConstraint", false, "Dir", "", "", "" ); m_hasTangentConstraintUiField.xmlCapability()->disableIO(); - CAF_PDM_InitField( &m_azimuth, "Azimuth", 0.0, "Azi(deg)", "", "", "" ); - CAF_PDM_InitField( &m_inclination, "Inclination", 0.0, "Inc(deg)", "", "", "" ); + CAF_PDM_InitScriptableField( &m_azimuth, "Azimuth", 0.0, "Azi(deg)", "", "", "" ); + CAF_PDM_InitScriptableField( &m_inclination, "Inclination", 0.0, "Inc(deg)", "", "", "" ); CAF_PDM_InitFieldNoDefault( &m_parentWellPath, "ParentWellPath", "Parent Well Path", "", "", "" ); diff --git a/ApplicationLibCode/ProjectDataModel/StimPlanModel/RimFaciesInitialPressureConfig.cpp b/ApplicationLibCode/ProjectDataModel/StimPlanModel/RimFaciesInitialPressureConfig.cpp index 60d48d28e2..b7e01ee320 100644 --- a/ApplicationLibCode/ProjectDataModel/StimPlanModel/RimFaciesInitialPressureConfig.cpp +++ b/ApplicationLibCode/ProjectDataModel/StimPlanModel/RimFaciesInitialPressureConfig.cpp @@ -18,6 +18,8 @@ #include "RimFaciesInitialPressureConfig.h" +#include "cafPdmFieldScriptingCapability.h" +#include "cafPdmObjectScriptingCapability.h" #include "cafPdmUiCheckBoxEditor.h" #include "cafPdmUiLineEditor.h" @@ -29,12 +31,14 @@ CAF_PDM_SOURCE_INIT( RimFaciesInitialPressureConfig, "FaciesInitialPressureConfi RimFaciesInitialPressureConfig::RimFaciesInitialPressureConfig() : changed( this ) { + CAF_PDM_InitScriptableObject( "Facies Initial Pressure Config", "", "", "" ); + m_isChecked.uiCapability()->setUiHidden( false ); - CAF_PDM_InitFieldNoDefault( &m_faciesName, "FaciesName", "Facies", "", "", "" ); + CAF_PDM_InitScriptableFieldNoDefault( &m_faciesName, "FaciesName", "Facies", "", "", "" ); m_faciesName.uiCapability()->setUiReadOnly( true ); - CAF_PDM_InitFieldNoDefault( &m_faciesValue, "FaciesValue", "Value", "", "", "" ); + CAF_PDM_InitScriptableFieldNoDefault( &m_faciesValue, "FaciesValue", "Value", "", "", "" ); m_faciesValue.uiCapability()->setUiHidden( true ); // Use unicode for delta letter @@ -44,7 +48,7 @@ RimFaciesInitialPressureConfig::RimFaciesInitialPressureConfig() QString deltaPressureFractionString = QString::fromUtf8( "\u0394 Pressure Fraction" ); #endif - CAF_PDM_InitField( &m_fraction, "Fraction", 0.0, deltaPressureFractionString, "", "", "" ); + CAF_PDM_InitScriptableField( &m_fraction, "Fraction", 0.0, deltaPressureFractionString, "", "", "" ); } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationLibCode/ProjectDataModel/StimPlanModel/RimPressureTable.cpp b/ApplicationLibCode/ProjectDataModel/StimPlanModel/RimPressureTable.cpp index eebfc6a389..af8a836048 100644 --- a/ApplicationLibCode/ProjectDataModel/StimPlanModel/RimPressureTable.cpp +++ b/ApplicationLibCode/ProjectDataModel/StimPlanModel/RimPressureTable.cpp @@ -21,6 +21,8 @@ #include "RimPressureTableItem.h" #include "cafCmdFeatureMenuBuilder.h" +#include "cafPdmFieldScriptingCapability.h" +#include "cafPdmObjectScriptingCapability.h" #include "cafPdmUiTableViewEditor.h" #include "cafPdmUiTreeOrdering.h" @@ -32,14 +34,14 @@ CAF_PDM_SOURCE_INIT( RimPressureTable, "PressureTable" ); RimPressureTable::RimPressureTable() : changed( this ) { - CAF_PDM_InitObject( "Pressure Table", "", "", "" ); + CAF_PDM_InitScriptableObject( "Pressure Table", "", "", "" ); - CAF_PDM_InitFieldNoDefault( &m_pressureTableItems, "Items", "Pressure Table Items", "", "", "" ); + CAF_PDM_InitScriptableFieldNoDefault( &m_pressureTableItems, "Items", "Pressure Table Items", "", "", "" ); m_pressureTableItems.uiCapability()->setUiEditorTypeName( caf::PdmUiTableViewEditor::uiEditorTypeName() ); m_pressureTableItems.uiCapability()->setUiLabelPosition( caf::PdmUiItemInfo::HIDDEN ); m_pressureTableItems.uiCapability()->setCustomContextMenuEnabled( true ); - CAF_PDM_InitFieldNoDefault( &m_pressureDate, "PressureDate", "Pressure Date", "", "", "" ); + CAF_PDM_InitScriptableFieldNoDefault( &m_pressureDate, "PressureDate", "Pressure Date", "", "", "" ); } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationLibCode/ProjectDataModel/StimPlanModel/RimPressureTableItem.cpp b/ApplicationLibCode/ProjectDataModel/StimPlanModel/RimPressureTableItem.cpp index 81ac53ee7c..7b7b3ca71b 100644 --- a/ApplicationLibCode/ProjectDataModel/StimPlanModel/RimPressureTableItem.cpp +++ b/ApplicationLibCode/ProjectDataModel/StimPlanModel/RimPressureTableItem.cpp @@ -18,6 +18,8 @@ #include "RimPressureTableItem.h" +#include "cafPdmFieldScriptingCapability.h" +#include "cafPdmObjectScriptingCapability.h" #include "cafPdmUiCheckBoxEditor.h" #include "cafPdmUiLineEditor.h" @@ -29,9 +31,11 @@ CAF_PDM_SOURCE_INIT( RimPressureTableItem, "PressureTableItem" ); RimPressureTableItem::RimPressureTableItem() : changed( this ) { - CAF_PDM_InitField( &m_depth, "Depth", 0.0, "Depth TVDMSL [m]", "", "", "" ); - CAF_PDM_InitField( &m_initialPressure, "InitialPressure", 0.0, "Initial Pressure [Bar]", "", "", "" ); - CAF_PDM_InitField( &m_pressure, "Pressure", 0.0, "Pressure [Bar]", "", "", "" ); + CAF_PDM_InitScriptableObject( "Pressure Table Item", "", "", "" ); + + CAF_PDM_InitScriptableField( &m_depth, "Depth", 0.0, "Depth TVDMSL [m]", "", "", "" ); + CAF_PDM_InitScriptableField( &m_initialPressure, "InitialPressure", 0.0, "Initial Pressure [Bar]", "", "", "" ); + CAF_PDM_InitScriptableField( &m_pressure, "Pressure", 0.0, "Pressure [Bar]", "", "", "" ); } //-------------------------------------------------------------------------------------------------- diff --git a/Fwk/AppFwk/cafPdmScripting/cafPdmCodeGenerator.h b/Fwk/AppFwk/cafPdmScripting/cafPdmCodeGenerator.h index b7fb3ccae4..88f01eec37 100644 --- a/Fwk/AppFwk/cafPdmScripting/cafPdmCodeGenerator.h +++ b/Fwk/AppFwk/cafPdmScripting/cafPdmCodeGenerator.h @@ -61,9 +61,9 @@ class PdmObjectFactory; class PdmCodeGenerator { public: - virtual QString generate( PdmObjectFactory* factory ) const = 0; + virtual QString generate( PdmObjectFactory* factory, std::vector& errorMessages ) const = 0; }; typedef Factory PdmCodeGeneratorFactory; -} // namespace caf \ No newline at end of file +} // namespace caf diff --git a/Fwk/AppFwk/cafPdmScripting/cafPdmMarkdownGenerator.cpp b/Fwk/AppFwk/cafPdmScripting/cafPdmMarkdownGenerator.cpp index fec56b0988..73fcbbbfc2 100644 --- a/Fwk/AppFwk/cafPdmScripting/cafPdmMarkdownGenerator.cpp +++ b/Fwk/AppFwk/cafPdmScripting/cafPdmMarkdownGenerator.cpp @@ -46,7 +46,7 @@ CAF_PDM_CODE_GENERATOR_SOURCE_INIT( PdmMarkdownGenerator, "md" ); //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -QString caf::PdmMarkdownGenerator::generate( PdmObjectFactory* factory ) const +QString caf::PdmMarkdownGenerator::generate( PdmObjectFactory* factory, std::vector& errorMessages ) const { QString generatedCode; QTextStream out( &generatedCode ); diff --git a/Fwk/AppFwk/cafPdmScripting/cafPdmMarkdownGenerator.h b/Fwk/AppFwk/cafPdmScripting/cafPdmMarkdownGenerator.h index 5a21651a26..ddffdb8e92 100644 --- a/Fwk/AppFwk/cafPdmScripting/cafPdmMarkdownGenerator.h +++ b/Fwk/AppFwk/cafPdmScripting/cafPdmMarkdownGenerator.h @@ -58,7 +58,7 @@ class PdmMarkdownGenerator : public PdmCodeGenerator }; public: - QString generate( PdmObjectFactory* factory ) const override; + QString generate( PdmObjectFactory* factory, std::vector& errorMessages ) const override; }; } // namespace caf diff --git a/Fwk/AppFwk/cafPdmScripting/cafPdmPythonGenerator.cpp b/Fwk/AppFwk/cafPdmScripting/cafPdmPythonGenerator.cpp index 9a5c848bb9..8c581ff8e9 100644 --- a/Fwk/AppFwk/cafPdmScripting/cafPdmPythonGenerator.cpp +++ b/Fwk/AppFwk/cafPdmScripting/cafPdmPythonGenerator.cpp @@ -59,7 +59,7 @@ CAF_PDM_CODE_GENERATOR_SOURCE_INIT( PdmPythonGenerator, "py" ); //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -QString PdmPythonGenerator::generate( PdmObjectFactory* factory ) const +QString caf::PdmPythonGenerator::generate( PdmObjectFactory* factory, std::vector& errorMessages ) const { QString generatedCode; QTextStream out( &generatedCode ); @@ -92,6 +92,7 @@ QString PdmPythonGenerator::generate( PdmObjectFactory* factory ) const std::map>> classAttributesGenerated; std::map> classMethodsGenerated; std::map classCommentsGenerated; + std::set dataTypesInChildFields; // First generate all attributes and comments to go into each object for ( std::shared_ptr object : dummyObjects ) @@ -181,9 +182,14 @@ QString PdmPythonGenerator::generate( PdmObjectFactory* factory ) const } else { - QString valueString; - QTextStream valueStream( &valueString ); - scriptability->readFromField( valueStream, true, true ); + QString valueString; + + // Always make sure the default value for a ptrField is empty string + if ( !field->hasPtrReferencedObjects() ) + { + QTextStream valueStream( &valueString ); + scriptability->readFromField( valueStream, true, true ); + } if ( valueString.isEmpty() ) valueString = QString( "\"\"" ); valueString = pythonifyDataValue( valueString ); @@ -203,6 +209,8 @@ QString PdmPythonGenerator::generate( PdmObjectFactory* factory ) const QString scriptDataType = PdmObjectScriptingCapabilityRegister::scriptClassNameFromClassKeyword( dataType ); + dataTypesInChildFields.insert( scriptDataType ); + QString commentDataType = field->xmlCapability()->isVectorField() ? QString( "List of %1" ).arg( scriptDataType ) : scriptDataType; @@ -385,6 +393,16 @@ QString PdmPythonGenerator::generate( PdmObjectFactory* factory ) const out << " return all_classes[class_keyword]\n"; out << " return None\n"; + // Check if all referenced data types are exported as classes + for ( const auto& scriptDataType : dataTypesInChildFields ) + { + if ( classesWritten.count( scriptDataType ) == 0 ) + { + QString errorText = "No export for data type " + scriptDataType; + errorMessages.push_back( errorText ); + } + } + return generatedCode; } diff --git a/Fwk/AppFwk/cafPdmScripting/cafPdmPythonGenerator.h b/Fwk/AppFwk/cafPdmScripting/cafPdmPythonGenerator.h index 4587178d66..f4068e84a8 100644 --- a/Fwk/AppFwk/cafPdmScripting/cafPdmPythonGenerator.h +++ b/Fwk/AppFwk/cafPdmScripting/cafPdmPythonGenerator.h @@ -49,11 +49,11 @@ class PdmPythonGenerator : public PdmCodeGenerator CAF_PDM_CODE_GENERATOR_HEADER_INIT; public: - QString generate( PdmObjectFactory* factory ) const override; + QString generate( PdmObjectFactory* factory, std::vector& errorMessages ) const override; static QString camelToSnakeCase( const QString& camelString ); static QString dataTypeString( const PdmFieldHandle* field, bool useStrForUnknownDataTypes ); static QString pythonifyDataValue( const QString& dataValue ); }; -} // namespace caf \ No newline at end of file +} // namespace caf diff --git a/Fwk/AppFwk/cafPdmScripting/cafPdmScripting_UnitTests/cafPdmScriptingBasicTest.cpp b/Fwk/AppFwk/cafPdmScripting/cafPdmScripting_UnitTests/cafPdmScriptingBasicTest.cpp index 042fe399da..372b533003 100644 --- a/Fwk/AppFwk/cafPdmScripting/cafPdmScripting_UnitTests/cafPdmScriptingBasicTest.cpp +++ b/Fwk/AppFwk/cafPdmScripting/cafPdmScripting_UnitTests/cafPdmScriptingBasicTest.cpp @@ -250,7 +250,8 @@ TEST( PdmScriptingTest, BasicUse ) std::string fileExt = "py"; std::unique_ptr generator( caf::PdmCodeGeneratorFactory::instance()->create( fileExt ) ); - auto generatedText = generator->generate( caf::PdmDefaultObjectFactory::instance() ); + std::vector logMessages; + auto generatedText = generator->generate( caf::PdmDefaultObjectFactory::instance(), logMessages ); auto string = generatedText.toStdString(); } diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmObjectHandle.h b/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmObjectHandle.h index f94a78110c..3811191203 100644 --- a/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmObjectHandle.h +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmObjectHandle.h @@ -104,6 +104,8 @@ public: virtual void onChildDeleted( PdmChildArrayFieldHandle* childArray, std::vector& referringObjects ); + virtual void onChildAdded( caf::PdmFieldHandle* containerForNewObject ){}; + protected: void addField( PdmFieldHandle* field, const QString& keyword ); diff --git a/GrpcInterface/GrpcProtos/PdmObject.proto b/GrpcInterface/GrpcProtos/PdmObject.proto index e64712c8c4..cff7e5db9b 100644 --- a/GrpcInterface/GrpcProtos/PdmObject.proto +++ b/GrpcInterface/GrpcProtos/PdmObject.proto @@ -32,6 +32,7 @@ message CreatePdmChildObjectRequest { PdmObject object = 1; string child_field = 2; + string class_keyword = 3; } message PdmParentObjectRequest diff --git a/GrpcInterface/Python/rips/pdmobject.py b/GrpcInterface/Python/rips/pdmobject.py index 400492d8e5..e919cd96c1 100644 --- a/GrpcInterface/Python/rips/pdmobject.py +++ b/GrpcInterface/Python/rips/pdmobject.py @@ -284,6 +284,41 @@ class PdmObjectBase: return [] raise e + def add_new_object(self, class_definition, child_field=""): + """Create and add an object to the specified child field + Arguments: + class_definition[class]: Class definition of the object to create + child_field[str]: The keyword for the field to create a new object in. If empty, the first child array field is used. + Returns: + The created PdmObject inside the child_field + """ + from .generated.generated_classes import class_from_keyword + + assert inspect.isclass(class_definition) + + class_keyword = class_definition.__name__ + + request = PdmObject_pb2.CreatePdmChildObjectRequest( + object=self._pb2_object, + child_field=child_field, + class_keyword=class_keyword, + ) + try: + pb2_object = self._pdm_object_stub.CreateChildPdmObject(request) + child_class_definition = class_from_keyword(pb2_object.class_keyword) + + if child_class_definition is None: + child_class_definition = class_keyword + + pdm_object = child_class_definition( + pb2_object=pb2_object, channel=self.channel() + ) + return pdm_object + except grpc.RpcError as e: + if e.code() == grpc.StatusCode.NOT_FOUND: + return None + raise e + def ancestor(self, class_definition): """Find the first ancestor that matches the provided class_keyword Arguments: diff --git a/GrpcInterface/Python/rips/tests/create_well_path.py b/GrpcInterface/Python/rips/tests/create_well_path.py new file mode 100644 index 0000000000..41206b7174 --- /dev/null +++ b/GrpcInterface/Python/rips/tests/create_well_path.py @@ -0,0 +1,35 @@ +from rips.generated.generated_classes import ( + ModeledWellPath, + StimPlanModel, + WellPathGeometry, + WellPathTarget, +) +import sys +import os + +sys.path.insert(1, os.path.join(sys.path[0], "../../")) +import rips + + +def test_well_path_target(rips_instance, initialize_test): + well_path_coll = rips_instance.project.descendants(rips.WellPathCollection)[0] + + my_well_path = well_path_coll.add_new_object(rips.ModeledWellPath) + my_well_path.name = "test" + my_well_path.update() + + geometry = my_well_path.well_path_geometry() + geometry.add_new_object(rips.WellPathTarget) + geometry.add_new_object(rips.WellPathTarget) + geometry.add_new_object(rips.WellPathTarget) + assert len(geometry.well_path_targets()) == 3 + + assert len(well_path_coll.well_paths()) == 1 + my_well_path_duplicate = well_path_coll.well_paths()[0] + assert my_well_path_duplicate.name == "test" + geometry_duplicate = my_well_path_duplicate.well_path_geometry() + assert len(geometry_duplicate.well_path_targets()) == 3 + + # Not allowed to add object of unrelated type + invalid_object = geometry.add_new_object(rips.WellPath) + assert invalid_object is None diff --git a/GrpcInterface/Python/setup.py.cmake b/GrpcInterface/Python/setup.py.cmake index 498fa2194a..9f14dcab76 100644 --- a/GrpcInterface/Python/setup.py.cmake +++ b/GrpcInterface/Python/setup.py.cmake @@ -19,5 +19,5 @@ setup( license=license, packages=['rips'], package_data={'rips': ['*.py', 'generated/*.py', 'PythonExamples/*.py', 'tests/*.py']}, - install_requires=['grpcio>=1.20.0', protobuf, wheel] + install_requires=['grpcio>=1.20.0', 'protobuf', 'wheel'] ) \ No newline at end of file diff --git a/GrpcInterface/RiaGrpcCommandService.cpp b/GrpcInterface/RiaGrpcCommandService.cpp index 7ebad0af0a..a8073357cf 100644 --- a/GrpcInterface/RiaGrpcCommandService.cpp +++ b/GrpcInterface/RiaGrpcCommandService.cpp @@ -269,7 +269,7 @@ void RiaGrpcCommandService::assignPdmObjectValues( caf::PdmObjectHandle* } else if ( childObjects.empty() ) { - childObject = emplaceChildField( pdmChildFieldHandle ); + childObject = emplaceChildField( pdmChildFieldHandle, "" ); } CAF_ASSERT( childObject ); if ( childObject ) diff --git a/GrpcInterface/RiaGrpcPdmObjectService.cpp b/GrpcInterface/RiaGrpcPdmObjectService.cpp index 1847a6b301..c52af25c3d 100644 --- a/GrpcInterface/RiaGrpcPdmObjectService.cpp +++ b/GrpcInterface/RiaGrpcPdmObjectService.cpp @@ -473,11 +473,15 @@ grpc::Status RiaGrpcPdmObjectService::CreateChildPdmObject( grpc::ServerContext* { CAF_ASSERT( request ); - caf::PdmObjectHandle* pdmObject = - emplaceChildField( matchingObject, QString::fromStdString( request->child_field() ) ); - if ( pdmObject ) + QString keywordClassToCreate = QString::fromStdString( request->class_keyword() ); + QString fieldKeyword = QString::fromStdString( request->child_field() ); + + caf::PdmObjectHandle* pdmObjectHandle = emplaceChildField( matchingObject, fieldKeyword, keywordClassToCreate ); + if ( pdmObjectHandle ) { - copyPdmObjectFromCafToRips( pdmObject, reply ); + copyPdmObjectFromCafToRips( pdmObjectHandle, reply ); + matchingObject->uiCapability()->updateConnectedEditors(); + return grpc::Status::OK; } return grpc::Status( grpc::NOT_FOUND, "Could not create PdmObject" ); diff --git a/GrpcInterface/RiaGrpcServiceInterface.cpp b/GrpcInterface/RiaGrpcServiceInterface.cpp index 12107a9b13..a91366ee57 100644 --- a/GrpcInterface/RiaGrpcServiceInterface.cpp +++ b/GrpcInterface/RiaGrpcServiceInterface.cpp @@ -142,6 +142,12 @@ void RiaGrpcServiceInterface::copyPdmObjectFromRipsToCaf( const rips::PdmObject* auto scriptability = field->template capability(); if ( scriptability ) { + if ( !dynamic_cast( field ) ) + { + // Recursive object update is not supported + // https://github.com/OPM/ResInsight/issues/7794 + continue; + } QString keyword = scriptability->scriptFieldName(); QString value = QString::fromStdString( parametersMap[keyword.toStdString()] ); @@ -181,7 +187,9 @@ bool RiaGrpcServiceInterface::assignFieldValue( const QString& stringValue //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -caf::PdmObjectHandle* RiaGrpcServiceInterface::emplaceChildField( caf::PdmObject* parent, const QString& fieldLabel ) +caf::PdmObjectHandle* RiaGrpcServiceInterface::emplaceChildField( caf::PdmObject* parent, + const QString& fieldKeyword, + const QString& keywordForClassToCreate ) { std::vector fields; parent->fields( fields ); @@ -190,13 +198,32 @@ caf::PdmObjectHandle* RiaGrpcServiceInterface::emplaceChildField( caf::PdmObject { auto pdmChildArrayField = dynamic_cast( field ); auto pdmChildField = dynamic_cast( field ); - if ( pdmChildArrayField && pdmChildArrayField->keyword() == fieldLabel ) + if ( pdmChildArrayField ) { - return emplaceChildArrayField( pdmChildArrayField ); + bool isMatching = false; + if ( fieldKeyword.isEmpty() ) + { + // Use first child array field if no fieldKeyword is specified + isMatching = true; + } + else + { + isMatching = ( pdmChildArrayField->keyword() == fieldKeyword ); + } + + if ( isMatching ) + { + auto objectCreated = emplaceChildArrayField( pdmChildArrayField, keywordForClassToCreate ); + + // Notify parent object that a new object has been created + if ( objectCreated ) parent->onChildAdded( pdmChildArrayField ); + + return objectCreated; + } } - else if ( pdmChildField && pdmChildField->keyword() == fieldLabel ) + else if ( pdmChildField && pdmChildField->keyword() == fieldKeyword ) { - return emplaceChildField( pdmChildField ); + return emplaceChildField( pdmChildField, keywordForClassToCreate ); } } return nullptr; @@ -205,12 +232,33 @@ caf::PdmObjectHandle* RiaGrpcServiceInterface::emplaceChildField( caf::PdmObject //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -caf::PdmObjectHandle* RiaGrpcServiceInterface::emplaceChildField( caf::PdmChildFieldHandle* childField ) +caf::PdmObjectHandle* RiaGrpcServiceInterface::emplaceChildField( caf::PdmChildFieldHandle* childField, + const QString& keywordForClassToCreate ) { - QString childClassKeyword = childField->xmlCapability()->dataTypeName(); + QString childClassKeyword; + if ( keywordForClassToCreate.isEmpty() ) + { + childClassKeyword = childField->xmlCapability()->dataTypeName(); + } + else + { + childClassKeyword = keywordForClassToCreate; + } auto pdmObjectHandle = caf::PdmDefaultObjectFactory::instance()->create( childClassKeyword ); CAF_ASSERT( pdmObjectHandle ); + + { + auto childDataTypeName = childField->xmlCapability()->dataTypeName(); + + auto isInheritanceValid = pdmObjectHandle->xmlCapability()->inheritsClassWithKeyword( childDataTypeName ); + if ( !isInheritanceValid ) + { + delete pdmObjectHandle; + return nullptr; + } + } + childField->setChildObject( pdmObjectHandle ); return pdmObjectHandle; } @@ -218,13 +266,34 @@ caf::PdmObjectHandle* RiaGrpcServiceInterface::emplaceChildField( caf::PdmChildF //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -caf::PdmObjectHandle* RiaGrpcServiceInterface::emplaceChildArrayField( caf::PdmChildArrayFieldHandle* childArrayField ) +caf::PdmObjectHandle* RiaGrpcServiceInterface::emplaceChildArrayField( caf::PdmChildArrayFieldHandle* childArrayField, + const QString& keywordForClassToCreate ) { - QString childClassKeyword = childArrayField->xmlCapability()->dataTypeName(); + QString childClassKeyword; + if ( keywordForClassToCreate.isEmpty() ) + { + childClassKeyword = childArrayField->xmlCapability()->dataTypeName(); + } + else + { + childClassKeyword = keywordForClassToCreate; + } auto pdmObjectHandle = caf::PdmDefaultObjectFactory::instance()->create( childClassKeyword ); - CAF_ASSERT( pdmObjectHandle ); + if ( !pdmObjectHandle ) return nullptr; + + { + auto childDataTypeName = childArrayField->xmlCapability()->dataTypeName(); + + auto isInheritanceValid = pdmObjectHandle->xmlCapability()->inheritsClassWithKeyword( childDataTypeName ); + if ( !isInheritanceValid ) + { + delete pdmObjectHandle; + return nullptr; + } + } childArrayField->insertAt( -1, pdmObjectHandle ); + return pdmObjectHandle; } diff --git a/GrpcInterface/RiaGrpcServiceInterface.h b/GrpcInterface/RiaGrpcServiceInterface.h index 95c5870a87..997cb0f304 100644 --- a/GrpcInterface/RiaGrpcServiceInterface.h +++ b/GrpcInterface/RiaGrpcServiceInterface.h @@ -60,10 +60,13 @@ public: static bool assignFieldValue( const QString& stringValue, caf::PdmFieldHandle* field, QVariant* oldValue, QVariant* newValue ); - static caf::PdmObjectHandle* emplaceChildField( caf::PdmObject* parent, const QString& fieldLabel ); + static caf::PdmObjectHandle* + emplaceChildField( caf::PdmObject* parent, const QString& fieldKeyword, const QString& keywordForClassToCreate ); - static caf::PdmObjectHandle* emplaceChildField( caf::PdmChildFieldHandle* childField ); - static caf::PdmObjectHandle* emplaceChildArrayField( caf::PdmChildArrayFieldHandle* childArrayField ); + static caf::PdmObjectHandle* emplaceChildField( caf::PdmChildFieldHandle* childField, + const QString& keywordForClassToCreate ); + static caf::PdmObjectHandle* emplaceChildArrayField( caf::PdmChildArrayFieldHandle* childArrayField, + const QString& keywordForClassToCreate ); }; #include "cafFactory.h" From 16887129f16649364a2534273284b5bf22895d35 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Tue, 29 Jun 2021 20:41:50 +0200 Subject: [PATCH 06/14] #7829 AppEnum : Make sure text used in XML serialization is trimmed If the AppEnum text used to serialize the AppEnum contains whitespace at start or end, the serialization will fail and the AppEnum value will end up with a default value. This commit will make sure that this field is always trimmed ( text coming from the application, from xml parsing, text from scripting). --- .../cafProjectDataModel/cafPdmCore/cafAppEnum.h | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafAppEnum.h b/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafAppEnum.h index 5fe04028a0..af69fc4402 100644 --- a/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafAppEnum.h +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafAppEnum.h @@ -191,7 +191,10 @@ private: public: void addItem( T enumVal, const QString& text, QString uiText ) { - instance()->m_mapping.push_back( Triplet( enumVal, text, uiText ) ); + // Make sure the text is trimmed, as this text is streamed to XML and will be trimmed when read back from + // XML text + // https://github.com/OPM/ResInsight/issues/7829 + instance()->m_mapping.push_back( Triplet( enumVal, text.trimmed(), uiText ) ); } static EnumMapper* instance() @@ -244,7 +247,9 @@ private: size_t idx; for ( idx = 0; idx < m_mapping.size(); ++idx ) { - if ( text == m_mapping[idx].m_text ) + // Make sure the text parsed from a text stream is trimmed + // https://github.com/OPM/ResInsight/issues/7829 + if ( text.trimmed() == m_mapping[idx].m_text ) { value = m_mapping[idx].m_enumVal; return true; @@ -349,7 +354,10 @@ QTextStream& operator>>( QTextStream& str, caf::AppEnum& appEnum ) { QString text; str >> text; - appEnum.setFromText( text ); + + // Make sure the text parsed from a text stream is trimmed + // https://github.com/OPM/ResInsight/issues/7829 + appEnum.setFromText( text.trimmed() ); return str; } From 4ae3f0af1f6adff8017431fd354a0bdf740dfe55 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Wed, 30 Jun 2021 14:19:15 +0200 Subject: [PATCH 07/14] #7831 Janitor: Do not create QtChart features if compiled without QtChart --- .../ProjectDataModel/RimContextCommandBuilder.cpp | 2 ++ ApplicationLibCode/UserInterface/RiuViewerCommands.cpp | 2 ++ 2 files changed, 4 insertions(+) diff --git a/ApplicationLibCode/ProjectDataModel/RimContextCommandBuilder.cpp b/ApplicationLibCode/ProjectDataModel/RimContextCommandBuilder.cpp index 2f3d6d101a..50ccd4e86e 100644 --- a/ApplicationLibCode/ProjectDataModel/RimContextCommandBuilder.cpp +++ b/ApplicationLibCode/ProjectDataModel/RimContextCommandBuilder.cpp @@ -897,7 +897,9 @@ caf::CmdFeatureMenuBuilder RimContextCommandBuilder::commandsFromSelection() } else if ( dynamic_cast( firstUiItem ) ) { +#ifdef USE_QTCHARTS menuBuilder << "RicCreateGridStatisticsPlotFeature"; +#endif menuBuilder << "RicShowGridStatisticsFeature"; } else if ( dynamic_cast( firstUiItem ) ) diff --git a/ApplicationLibCode/UserInterface/RiuViewerCommands.cpp b/ApplicationLibCode/UserInterface/RiuViewerCommands.cpp index f914875be8..8ae429129a 100644 --- a/ApplicationLibCode/UserInterface/RiuViewerCommands.cpp +++ b/ApplicationLibCode/UserInterface/RiuViewerCommands.cpp @@ -618,7 +618,9 @@ void RiuViewerCommands::displayContextMenu( QMouseEvent* event ) menuBuilder.addSeparator(); menuBuilder << "RicExportEclipseInputGridFeature"; menuBuilder << "RicSaveEclipseInputActiveVisibleCellsFeature"; +#ifdef USE_QTCHARTS menuBuilder << "RicCreateGridStatisticsPlotFeature"; +#endif menuBuilder << "RicShowGridStatisticsFeature"; menuBuilder << "RicSelectColorResult"; } From 41a4e19f9e16070c269cacc0bac3b5b2525d1559 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Fri, 2 Jul 2021 07:54:01 +0200 Subject: [PATCH 08/14] Janitor : Update vector count --- ApplicationLibCode/UnitTests/HDF5FileReader-Test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ApplicationLibCode/UnitTests/HDF5FileReader-Test.cpp b/ApplicationLibCode/UnitTests/HDF5FileReader-Test.cpp index e66e74ebd1..62f54824b3 100644 --- a/ApplicationLibCode/UnitTests/HDF5FileReader-Test.cpp +++ b/ApplicationLibCode/UnitTests/HDF5FileReader-Test.cpp @@ -90,7 +90,7 @@ TEST( HDFTests, ReadOpmSummaryData ) hdf5SummaryReader.open( filePath, false, nullptr ); auto addresses = hdf5SummaryReader.allResultAddresses(); - EXPECT_EQ( size_t( 2770 ), addresses.size() ); + EXPECT_EQ( size_t( 2786 ), addresses.size() ); int itemCount = 0; size_t totalValueCount = 0; From 1fcc24d84d415d3220cc465c89bbbb7af66b7605 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Thu, 1 Jul 2021 16:05:46 +0200 Subject: [PATCH 09/14] #7838 Summary: Include missing Node vector GPR in category Group --- ApplicationLibCode/FileInterface/RifOpmCommonSummary.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ApplicationLibCode/FileInterface/RifOpmCommonSummary.cpp b/ApplicationLibCode/FileInterface/RifOpmCommonSummary.cpp index f02ab4e6a9..7da8170bb3 100644 --- a/ApplicationLibCode/FileInterface/RifOpmCommonSummary.cpp +++ b/ApplicationLibCode/FileInterface/RifOpmCommonSummary.cpp @@ -274,6 +274,10 @@ RifEclipseSummaryAddress RifOpmCommonSummaryTools::createAddressFromSummaryNode( default: break; case Opm::EclIO::SummaryNode::Category::Node: + // The vector "GPR" is defined as Node + // The behavior in libecl is to use the category Group + // https://github.com/OPM/ResInsight/issues/7838 + return RifEclipseSummaryAddress::wellGroupAddress( summaryNode.keyword, summaryNode.wgname ); break; case Opm::EclIO::SummaryNode::Category::Network: return RifEclipseSummaryAddress::networkAddress( summaryNode.keyword ); From f5bf8dd5029c7e7976cd29193b03e380edc18b36 Mon Sep 17 00:00:00 2001 From: Kristian Bendiksen Date: Thu, 8 Jul 2021 09:13:16 +0200 Subject: [PATCH 10/14] #7842 Python: fix undefined variable on version mismatch. The location variable was not defined when creating the error message for version mismatch between rips and application. --- GrpcInterface/Python/rips/instance.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/GrpcInterface/Python/rips/instance.py b/GrpcInterface/Python/rips/instance.py index b541d7e112..cc6fe76e18 100644 --- a/GrpcInterface/Python/rips/instance.py +++ b/GrpcInterface/Python/rips/instance.py @@ -188,7 +188,7 @@ class Instance: # Main version check package self.app = App_pb2_grpc.AppStub(self.channel) - self._check_connection_and_version(self.channel, launched) + self._check_connection_and_version(self.channel, launched, location) # Intercept UNAVAILABLE errors and retry on failures interceptors = ( @@ -211,7 +211,7 @@ class Instance: path = os.getcwd() self.set_start_dir(path=path) - def _check_connection_and_version(self, channel, launched): + def _check_connection_and_version(self, channel, launched, location): connection_ok = False version_ok = False From 40fc7dacd048c8505b7f4117aade57df2e6aa217 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Tue, 3 Aug 2021 13:39:36 +0200 Subject: [PATCH 11/14] #7856 Default settings for H5 summary file handling --- ApplicationLibCode/Application/RiaPreferencesSummary.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ApplicationLibCode/Application/RiaPreferencesSummary.cpp b/ApplicationLibCode/Application/RiaPreferencesSummary.cpp index f5a7dd416d..76dcae78ea 100644 --- a/ApplicationLibCode/Application/RiaPreferencesSummary.cpp +++ b/ApplicationLibCode/Application/RiaPreferencesSummary.cpp @@ -130,7 +130,7 @@ RiaPreferencesSummary::RiaPreferencesSummary() CAF_PDM_InitField( &m_createH5SummaryDataFile, "createH5SummaryDataFile", - false, + true, "Create h5 Summary Files", "", "If not present, create summary file with extension '*.h5'", @@ -139,7 +139,7 @@ RiaPreferencesSummary::RiaPreferencesSummary() CAF_PDM_InitField( &m_checkH5FileTimeStamp, "checkH5FileTimeStamp", - false, + true, "Check File Timestamp", "", "Compare timestamp of h5 and SMSPEC, and recreate h5 when required", From 5cd72f55f3cfd299583b5a4dc1a191b14d84402b Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Tue, 3 Aug 2021 14:34:51 +0200 Subject: [PATCH 12/14] #7852 Crash on dual porosity grid model load and clicking on cell in 3D view --- .../opm-flowdiagnostics-applications/opm/utility/ECLGraph.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ThirdParty/custom-opm-flowdiag-app/opm-flowdiagnostics-applications/opm/utility/ECLGraph.cpp b/ThirdParty/custom-opm-flowdiag-app/opm-flowdiagnostics-applications/opm/utility/ECLGraph.cpp index f83a13eb24..663893a0f6 100644 --- a/ThirdParty/custom-opm-flowdiag-app/opm-flowdiagnostics-applications/opm/utility/ECLGraph.cpp +++ b/ThirdParty/custom-opm-flowdiag-app/opm-flowdiagnostics-applications/opm/utility/ECLGraph.cpp @@ -1233,7 +1233,9 @@ deriveNeighbours(const std::vector& gcells, continue; } - if (T[globID] > 0.0) { + // Guard access to transmissibility vector. Crash seen in some dual porosity models + // https://github.com/OPM/ResInsight/issues/7852 + if (globID < T.size() && T[globID] > 0.0) { const auto other = this->cells_.getNeighbour(globID, d); if ((other >= 0) && ! this->cells_.isSubdivided(other)) { From 5e9ec68f33abd8dbbd72492a145b4a7cdc570f87 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Wed, 4 Aug 2021 13:30:56 +0200 Subject: [PATCH 13/14] Set version to 2021.06.1-RC_01 --- ResInsightVersion.cmake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ResInsightVersion.cmake b/ResInsightVersion.cmake index 54256664b5..88af727845 100644 --- a/ResInsightVersion.cmake +++ b/ResInsightVersion.cmake @@ -1,11 +1,11 @@ set(RESINSIGHT_MAJOR_VERSION 2021) set(RESINSIGHT_MINOR_VERSION 06) -set(RESINSIGHT_PATCH_VERSION 0) +set(RESINSIGHT_PATCH_VERSION 1) # Opional text with no restrictions # set(RESINSIGHT_VERSION_TEXT "-dev") -# set(RESINSIGHT_VERSION_TEXT "-RC_03") +set(RESINSIGHT_VERSION_TEXT "-RC_01") # Optional text # Must be unique and increasing within one combination of major/minor/patch version From 3e4d07cbe91f84f01a543129468baf15d75469be Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Wed, 4 Aug 2021 18:57:45 +0200 Subject: [PATCH 14/14] Allow two different counts for summary vector reader --- GrpcInterface/Python/rips/tests/test_summary_cases.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/GrpcInterface/Python/rips/tests/test_summary_cases.py b/GrpcInterface/Python/rips/tests/test_summary_cases.py index 5cb753ca42..b80bf7d641 100644 --- a/GrpcInterface/Python/rips/tests/test_summary_cases.py +++ b/GrpcInterface/Python/rips/tests/test_summary_cases.py @@ -37,7 +37,9 @@ def test_summary_data(rips_instance, initialize_test): assert summary_case.id == 1 addresses = summary_case.available_addresses() - assert len(addresses.values) == 343 + # Summary reader type is controlled from Preferences. libecl reports 343 vectors, opm_common reports 361. + # As this configuration can be different, allow both variants + assert len(addresses.values) == 343 or len(addresses.values) == 361 summary_data = summary_case.summary_vector_values("FOPT") assert len(summary_data.values) == 60