///////////////////////////////////////////////////////////////////////////////// // // Copyright (C) 2026- 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 "RimcEclipseView.h" #include "ExportCommands/RicEclipseCellResultToFileImpl.h" #include "ExportCommands/RicSaveEclipseInputVisibleCellsFeature.h" #include "RiaViewRedrawScheduler.h" #include "RigResultAccessor.h" #include "RigResultAccessorFactory.h" #include "RimEclipseCase.h" #include "RimEclipseCellColors.h" #include "RimEclipseView.h" #include "RimFaultDistance.h" #include "RimFaultDistanceCollection.h" #include "RimFaultInView.h" #include "RimFaultInViewCollection.h" #include "cafPdmAbstractFieldScriptingCapability.h" #include "cafPdmFieldScriptingCapability.h" #include "cafUtils.h" CAF_PDM_OBJECT_METHOD_SOURCE_INIT( RimEclipseView, RimcEclipseView_addFaultDistance, "add_fault_distance" ); //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RimcEclipseView_addFaultDistance::RimcEclipseView_addFaultDistance( caf::PdmObjectHandle* self ) : caf::PdmObjectCreationMethod( self ) { CAF_PDM_InitObject( "Add Fault Distance", "", "", "Create a FAULTDIST cell result for a chosen subset of faults" ); CAF_PDM_InitScriptableFieldNoDefault( &m_resultName, "Name", "Name (default FAULTDIST if empty)" ); CAF_PDM_InitScriptableFieldNoDefault( &m_faults, "Faults", "Faults to include (empty = all)" ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- std::expected RimcEclipseView_addFaultDistance::execute() { auto* eclipseView = self(); if ( !eclipseView ) return std::unexpected( QString( "No view" ) ); auto* distanceCollection = eclipseView->faultDistanceCollection(); if ( !distanceCollection ) return std::unexpected( QString( "No fault distance results collection" ) ); auto* newResult = distanceCollection->addResult(); if ( !newResult ) return std::unexpected( QString( "Failed to create fault distance result" ) ); if ( !m_resultName().isEmpty() ) newResult->setResultName( m_resultName() ); std::vector selected = m_faults.ptrReferencedObjectsByType(); if ( selected.empty() && eclipseView->faultCollection() ) { // Default to all faults, but leave the ResInsight-generated faults unticked. selected = eclipseView->faultCollection()->faults(); std::erase_if( selected, []( RimFaultInView* fault ) { return fault && fault->isGeneratedFault(); } ); } newResult->setSelectedFaults( selected ); // When created from Python, always trigger the calculation (the UI uses an explicit Generate button instead). newResult->compute(); eclipseView->updateConnectedEditors(); return newResult; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- QString RimcEclipseView_addFaultDistance::classKeywordReturnedType() const { return RimFaultDistance::classKeywordStatic(); } CAF_PDM_OBJECT_METHOD_SOURCE_INIT( RimEclipseView, RimEclipseView_exportCurrentProperty, "exportCurrentProperty" ); //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RimEclipseView_exportCurrentProperty::RimEclipseView_exportCurrentProperty( caf::PdmObjectHandle* self ) : caf::PdmVoidObjectMethod( self ) { CAF_PDM_InitObject( "Export Current Property", "", "", "Export the cell result currently shown in the view to a GRDECL style text file" ); CAF_PDM_InitScriptableField( &m_exportFile, "ExportFile", QString(), "Export File", "", "", "Full path of the file to write" ); CAF_PDM_InitScriptableField( &m_undefinedValue, "UndefinedValue", 0.0, "Undefined Value", "", "", "Value written for undefined cells" ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimEclipseView_exportCurrentProperty::setExportFile( const QString& exportFile ) { m_exportFile = exportFile; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimEclipseView_exportCurrentProperty::setUndefinedValue( double undefinedValue ) { m_undefinedValue = undefinedValue; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- std::expected RimEclipseView_exportCurrentProperty::execute() { auto* view = self(); if ( !view ) return std::unexpected( "No view is available." ); if ( m_exportFile().isEmpty() ) return std::unexpected( "No export file specified." ); RimEclipseCase* eclipseCase = view->eclipseCase(); if ( !eclipseCase || !eclipseCase->eclipseCaseData() ) return std::unexpected( "The view has no case data." ); cvf::ref resultAccessor = currentPropertyAccessor( view ); const QString propertyName = view->cellResult()->resultVariableUiShortName(); if ( resultAccessor.isNull() ) { return std::unexpected( QString( "Could not find property '%1' at time step %2 in view '%3'" ) .arg( propertyName ) .arg( view->currentTimeStep() ) .arg( view->name() ) ); } const bool writeEchoKeywords = false; QString errorMessage; if ( !RicEclipseCellResultToFileImpl::writeResultToTextFile( m_exportFile(), eclipseCase->eclipseCaseData(), resultAccessor.p(), propertyName, m_undefinedValue(), "exportProperty", writeEchoKeywords, &errorMessage ) ) { return std::unexpected( errorMessage ); } return nullptr; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- cvf::ref RimEclipseView_exportCurrentProperty::currentPropertyAccessor( const RimEclipseView* view ) { if ( !view || !view->eclipseCase() || !view->eclipseCase()->eclipseCaseData() ) return nullptr; const int mainGridIndex = 0; return RigResultAccessorFactory::createFromResultDefinition( view->eclipseCase()->eclipseCaseData(), mainGridIndex, view->currentTimeStep(), view->cellResult() ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- bool RimEclipseView_exportCurrentProperty::hasCurrentProperty( const RimEclipseView* view ) { return currentPropertyAccessor( view ).notNull(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- QString RimEclipseView_exportCurrentProperty::defaultFileBaseName( const RimEclipseView* view ) { if ( !view || !view->eclipseCase() ) return {}; const QString propertyName = view->cellResult()->resultVariableUiShortName(); const QString fileName = QString( "%1-%2-T%3-%4" ).arg( view->eclipseCase()->caseUserDescription() ).arg( view->name() ).arg( view->currentTimeStep() ).arg( propertyName ); return caf::Utils::makeValidFileBasename( fileName ); } CAF_PDM_OBJECT_METHOD_SOURCE_INIT( RimEclipseView, RimEclipseView_exportVisibleCells, "exportVisibleCells" ); //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RimEclipseView_exportVisibleCells::RimEclipseView_exportVisibleCells( caf::PdmObjectHandle* self ) : caf::PdmVoidObjectMethod( self ) { CAF_PDM_InitObject( "Export Visible Cells", "", "", "Export a GRDECL keyword with one value per cell based on cell visibility in the view" ); CAF_PDM_InitScriptableField( &m_exportFile, "ExportFile", QString(), "Export File", "", "", "Full path of the file to write" ); CAF_PDM_InitScriptableField( &m_exportKeyword, "ExportKeyword", RicSaveEclipseInputVisibleCellsUi::FLUXNUM, "Export Keyword", "", "", "GRDECL keyword to write" ); CAF_PDM_InitScriptableField( &m_visibleActiveCellsValue, "VisibleActiveCellsValue", 1, "Visible Active Cells Value", "", "", "Value for visible active cells" ); CAF_PDM_InitScriptableField( &m_hiddenActiveCellsValue, "HiddenActiveCellsValue", 0, "Hidden Active Cells Value", "", "", "Value for hidden active cells" ); CAF_PDM_InitScriptableField( &m_inactiveCellsValue, "InactiveCellsValue", 0, "Inactive Cells Value", "", "", "Value for inactive cells" ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimEclipseView_exportVisibleCells::setExportFile( const QString& exportFile ) { m_exportFile = exportFile; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimEclipseView_exportVisibleCells::setExportKeyword( RicSaveEclipseInputVisibleCellsUi::ExportKeyword exportKeyword ) { m_exportKeyword = exportKeyword; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimEclipseView_exportVisibleCells::setVisibleActiveCellsValue( int value ) { m_visibleActiveCellsValue = value; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimEclipseView_exportVisibleCells::setHiddenActiveCellsValue( int value ) { m_hiddenActiveCellsValue = value; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimEclipseView_exportVisibleCells::setInactiveCellsValue( int value ) { m_inactiveCellsValue = value; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- std::expected RimEclipseView_exportVisibleCells::execute() { auto* view = self(); if ( !view ) return std::unexpected( "No view is available." ); if ( m_exportFile().isEmpty() ) return std::unexpected( "No export file specified." ); RiaViewRedrawScheduler::instance()->clearViewsScheduledForUpdate(); RicSaveEclipseInputVisibleCellsUi exportSettings; exportSettings.exportFilename = m_exportFile(); exportSettings.exportKeyword = m_exportKeyword(); exportSettings.visibleActiveCellsValue = m_visibleActiveCellsValue(); exportSettings.hiddenActiveCellsValue = m_hiddenActiveCellsValue(); exportSettings.inactiveCellsValue = m_inactiveCellsValue(); if ( auto result = RicSaveEclipseInputVisibleCellsFeature::exportVisibleCells( view, exportSettings ); !result ) { return std::unexpected( result.error() ); } return nullptr; }