///////////////////////////////////////////////////////////////////////////////// // // Copyright (C) 2023 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 "RimFaultReactivationModel.h" #include "RiaApplication.h" #include "RiaPreferences.h" #include "RiaPreferencesGeoMech.h" #include "RiaQDateTimeTools.h" #include "RifJsonEncodeDecode.h" #include "RigBasicPlane.h" #include "RigFaultReactivationModel.h" #include "RigPolyLinesData.h" #include "WellPathCommands/PointTangentManipulator/RicPolyline3dEditor.h" #include "WellPathCommands/RicPolylineTargetsPickEventHandler.h" #include "RiuViewer.h" #include "RivFaultReactivationModelPartMgr.h" #include "Rim3dView.h" #include "RimEclipseCase.h" #include "RimEclipseView.h" #include "RimFaultInView.h" #include "RimFaultInViewCollection.h" #include "RimFaultReactivationTools.h" #include "RimPolylineTarget.h" #include "RimTimeStepFilter.h" #include "RimTools.h" #include "cafPdmUiDoubleSliderEditor.h" #include "cafPdmUiTableViewEditor.h" #include "cafPdmUiTreeSelectionEditor.h" #include "cvfPlane.h" #include "cvfTextureImage.h" #include #include #include #include CAF_PDM_SOURCE_INIT( RimFaultReactivationModel, "FaultReactivationModel" ); //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RimFaultReactivationModel::RimFaultReactivationModel() : m_pickTargetsEventHandler( new RicPolylineTargetsPickEventHandler( this ) ) { CAF_PDM_InitObject( "Fault Reactivation Model", ":/fault_react_24x24.png" ); CAF_PDM_InitField( &m_userDescription, "UserDescription", QString( "Model" ), "Name" ); CAF_PDM_InitFieldNoDefault( &m_baseDir, "BaseDirectory", "Working folder" ); CAF_PDM_InitField( &m_modelThickness, "ModelThickness", 100.0, "Model Cell Thickness" ); CAF_PDM_InitField( &m_extentHorizontal, "HorizontalExtent", 1000.0, "Horizontal Extent" ); CAF_PDM_InitField( &m_extentVerticalAbove, "VerticalExtentAbove", 200.0, "Vertical Extent Above Anchor" ); m_extentVerticalAbove.uiCapability()->setUiEditorTypeName( caf::PdmUiDoubleSliderEditor::uiEditorTypeName() ); m_extentVerticalAbove.uiCapability()->setUiLabelPosition( caf::PdmUiItemInfo::LabelPosType::TOP ); CAF_PDM_InitField( &m_extentVerticalBelow, "VerticalExtentBelow", 200.0, "Vertical Extent Below Anchor" ); m_extentVerticalBelow.uiCapability()->setUiEditorTypeName( caf::PdmUiDoubleSliderEditor::uiEditorTypeName() ); m_extentVerticalBelow.uiCapability()->setUiLabelPosition( caf::PdmUiItemInfo::LabelPosType::TOP ); CAF_PDM_InitField( &m_modelExtentFromAnchor, "ModelExtentFromAnchor", 1000.0, "Horz. Extent from Anchor" ); CAF_PDM_InitField( &m_modelMinZ, "ModelMinZ", 0.0, "Start Depth" ); CAF_PDM_InitField( &m_modelBelowSize, "ModelBelowSize", 500.0, "Depth Below Fault" ); CAF_PDM_InitField( &m_showFaultPlane, "ShowFaultPlane", true, "Show Fault Plane" ); CAF_PDM_InitField( &m_showModelPlane, "ShowModelPlane", false, "Show 2D Model" ); CAF_PDM_InitFieldNoDefault( &m_fault, "Fault", "Fault" ); m_fault.uiCapability()->setUiReadOnly( true ); CAF_PDM_InitField( &m_faultPlaneColor, "FaultPlaneColor", cvf::Color3f( cvf::Color3f::GRAY ), "Plane Color" ); CAF_PDM_InitField( &m_modelPart1Color, "ModelPart1Color", cvf::Color3f( cvf::Color3f::GREEN ), "Part 1 Color" ); CAF_PDM_InitField( &m_modelPart2Color, "ModelPart2Color", cvf::Color3f( cvf::Color3f::BLUE ), "Part 2 Color" ); CAF_PDM_InitField( &m_numberOfCellsHorzPart1, "NumberOfCellsHorzPart1", 20, "Horizontal Number of Cells, Part 1" ); CAF_PDM_InitField( &m_numberOfCellsHorzPart2, "NumberOfCellsHorzPart2", 20, "Horizontal Number of Cells, Part 2" ); CAF_PDM_InitField( &m_numberOfCellsVertUp, "NumberOfCellsVertUp", 20, "Vertical Number of Cells, Upper Part" ); CAF_PDM_InitField( &m_numberOfCellsVertMid, "NumberOfCellsVertMid", 20, "Vertical Number of Cells, Middle Part" ); CAF_PDM_InitField( &m_numberOfCellsVertLow, "NumberOfCellsVertLow", 20, "Vertical Number of Cells, Lower Part" ); // Time Step Selection CAF_PDM_InitFieldNoDefault( &m_timeStepFilter, "TimeStepFilter", "Available Time Steps" ); CAF_PDM_InitFieldNoDefault( &m_selectedTimeSteps, "TimeSteps", "Select Time Steps" ); m_selectedTimeSteps.uiCapability()->setUiEditorTypeName( caf::PdmUiTreeSelectionEditor::uiEditorTypeName() ); m_selectedTimeSteps.uiCapability()->setUiLabelPosition( caf::PdmUiItemInfo::TOP ); CAF_PDM_InitFieldNoDefault( &m_targets, "Targets", "Targets" ); m_targets.uiCapability()->setUiEditorTypeName( caf::PdmUiTableViewEditor::uiEditorTypeName() ); m_targets.uiCapability()->setUiTreeChildrenHidden( true ); m_targets.uiCapability()->setUiLabelPosition( caf::PdmUiItemInfo::TOP ); m_targets.uiCapability()->setCustomContextMenuEnabled( false ); this->setUi3dEditorTypeName( RicPolyline3dEditor::uiEditorTypeName() ); this->uiCapability()->setUiTreeChildrenHidden( true ); setDeletable( true ); m_faultPlane = new RigBasicPlane(); m_modelPlane = new RigFaultReactivationModel(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RimFaultReactivationModel::~RimFaultReactivationModel() { } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimFaultReactivationModel::initAfterRead() { updateVisualization(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- QString RimFaultReactivationModel::userDescription() { return m_userDescription; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimFaultReactivationModel::setUserDescription( QString description ) { m_userDescription = description; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- caf::PdmFieldHandle* RimFaultReactivationModel::userDescriptionField() { return &m_userDescription; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimFaultReactivationModel::setFault( RimFaultInView* fault ) { m_fault = fault; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RimFaultInView* RimFaultReactivationModel::fault() const { return m_fault(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimFaultReactivationModel::setTargets( cvf::Vec3d target1, cvf::Vec3d target2 ) { m_targets.deleteChildren(); RimPolylineTarget* planeCenter = new RimPolylineTarget(); planeCenter->setAsPointXYZ( target1 ); m_targets.push_back( planeCenter ); RimPolylineTarget* steeringTarget = new RimPolylineTarget(); steeringTarget->setAsPointXYZ( target2 ); m_targets.push_back( steeringTarget ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- std::vector RimFaultReactivationModel::activeTargets() const { return m_targets.childrenByType(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimFaultReactivationModel::insertTarget( const RimPolylineTarget* targetToInsertBefore, RimPolylineTarget* targetToInsert ) { // do nothing, we should only have 2 predefined targets } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimFaultReactivationModel::deleteTarget( RimPolylineTarget* targetToDelete ) { // do nothing, we should always have 2 predefined targets } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- bool RimFaultReactivationModel::pickingEnabled() const { // never pick, we only have our 2 predefined targets return false; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- caf::PickEventHandler* RimFaultReactivationModel::pickEventHandler() const { return m_pickTargetsEventHandler.get(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimFaultReactivationModel::updateVisualization() { auto view = firstAncestorOrThisOfType(); if ( !view ) return; auto normal = m_targets[1]->targetPointXYZ() - m_targets[0]->targetPointXYZ(); normal.z() = normal.z() * view->scaleZ() * view->scaleZ(); normal.normalize(); m_faultPlane->setPlane( m_targets[0]->targetPointXYZ(), normal ); m_faultPlane->setMaxExtentFromAnchor( m_extentHorizontal, m_extentVerticalAbove, m_extentVerticalBelow ); m_faultPlane->setColor( m_faultPlaneColor ); m_faultPlane->updateRect(); double maxZ = m_faultPlane->maxDepth(); auto [topInt, bottomInt] = m_faultPlane->intersectTopBottomLine(); cvf::Vec3d zdir( 0, 0, 1 ); auto modelNormal = normal ^ zdir; modelNormal.normalize(); m_modelPlane->setPlane( m_targets[0]->targetPointXYZ(), modelNormal ); m_modelPlane->setFaultPlaneIntersect( topInt, bottomInt ); m_modelPlane->setMaxExtentFromAnchor( m_modelExtentFromAnchor, m_modelMinZ, maxZ + m_modelBelowSize ); m_modelPlane->setPartColors( m_modelPart1Color, m_modelPart2Color ); m_modelPlane->setCellCounts( m_numberOfCellsHorzPart1, m_numberOfCellsHorzPart2, m_numberOfCellsVertUp, m_numberOfCellsVertMid, m_numberOfCellsVertLow ); m_modelPlane->setThickness( m_modelThickness ); m_modelPlane->updateRects(); view->scheduleCreateDisplayModelAndRedraw(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimFaultReactivationModel::updateEditorsAndVisualization() { updateConnectedEditors(); updateVisualization(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- cvf::ref RimFaultReactivationModel::polyLinesData() const { cvf::ref pld = new RigPolyLinesData; std::vector line; for ( const RimPolylineTarget* target : m_targets ) { line.push_back( target->targetPointXYZ() ); } pld->setPolyLine( line ); return pld; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- QList RimFaultReactivationModel::calculateValueOptions( const caf::PdmFieldHandle* fieldNeedingOptions ) { QList options; if ( fieldNeedingOptions == &m_fault ) { if ( m_fault() != nullptr ) { auto coll = m_fault->firstAncestorOrThisOfType(); if ( coll != nullptr ) RimTools::faultOptionItems( &options, coll ); } } else if ( fieldNeedingOptions == &m_selectedTimeSteps ) { RimTimeStepFilter::timeStepOptions( options, &m_selectedTimeSteps, m_availableTimeSteps, m_selectedTimeSteps, m_timeStepFilter() ); } return options; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RivFaultReactivationModelPartMgr* RimFaultReactivationModel::partMgr() { if ( m_partMgr.isNull() ) m_partMgr = new RivFaultReactivationModelPartMgr( this ); return m_partMgr.p(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- cvf::ref RimFaultReactivationModel::faultPlane() const { return m_faultPlane; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- cvf::ref RimFaultReactivationModel::model() const { return m_modelPlane; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- bool RimFaultReactivationModel::showFaultPlane() const { return m_showFaultPlane; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- bool RimFaultReactivationModel::showModel() const { return m_showModelPlane; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- std::pair RimFaultReactivationModel::localCoordSysNormalsXY() const { cvf::Vec3d yNormal = m_modelPlane->normal(); cvf::Vec3d xNormal = yNormal ^ cvf::Vec3d::Z_AXIS; return std::make_pair( xNormal, yNormal ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimFaultReactivationModel::defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) { auto genGrp = uiOrdering.addNewGroup( "General" ); genGrp->add( &m_userDescription ); genGrp->add( &m_fault ); genGrp->add( &m_baseDir ); auto faultGrp = uiOrdering.addNewGroup( "Fault Plane" ); faultGrp->add( &m_showFaultPlane ); faultGrp->add( &m_faultPlaneColor ); faultGrp->add( &m_extentHorizontal ); faultGrp->add( &m_extentVerticalAbove ); faultGrp->add( &m_extentVerticalBelow ); auto modelGrp = uiOrdering.addNewGroup( "2D Model" ); modelGrp->add( &m_showModelPlane ); auto sizeModelGrp = modelGrp->addNewGroup( "Size" ); sizeModelGrp->add( &m_modelExtentFromAnchor ); sizeModelGrp->add( &m_modelMinZ ); sizeModelGrp->add( &m_modelBelowSize ); auto gridModelGrp = modelGrp->addNewGroup( "Grid" ); gridModelGrp->add( &m_modelThickness ); gridModelGrp->add( &m_numberOfCellsHorzPart1 ); gridModelGrp->add( &m_numberOfCellsHorzPart2 ); gridModelGrp->add( &m_numberOfCellsVertUp ); gridModelGrp->add( &m_numberOfCellsVertMid ); gridModelGrp->add( &m_numberOfCellsVertLow ); auto timeStepGrp = uiOrdering.addNewGroup( "Time Steps" ); timeStepGrp->add( &m_timeStepFilter ); timeStepGrp->add( &m_selectedTimeSteps ); auto appModelGrp = modelGrp->addNewGroup( "Appearance" ); appModelGrp->add( &m_modelPart1Color ); appModelGrp->add( &m_modelPart2Color ); auto trgGroup = uiOrdering.addNewGroup( "Debug" ); trgGroup->setCollapsedByDefault(); trgGroup->add( &m_targets ); uiOrdering.skipRemainingFields(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimFaultReactivationModel::fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue ) { if ( changedField == &m_userDescription ) { updateConnectedEditors(); } else { updateVisualization(); } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimFaultReactivationModel::defineEditorAttribute( const caf::PdmFieldHandle* field, QString uiConfigName, caf::PdmUiEditorAttribute* attribute ) { if ( field == &m_targets ) { auto tvAttribute = dynamic_cast( attribute ); if ( tvAttribute ) { tvAttribute->resizePolicy = caf::PdmUiTableViewEditorAttribute::RESIZE_TO_FIT_CONTENT; } } else if ( ( field == &m_extentVerticalAbove ) || ( field == &m_extentVerticalBelow ) ) { auto* attr = dynamic_cast( attribute ); if ( attr ) { auto eclCase = eclipseCase(); if ( eclCase ) { auto bb = eclCase->allCellsBoundingBox(); double diff = bb.max().z() - bb.min().z(); attr->m_minimum = 0; attr->m_maximum = diff; } else { attr->m_minimum = 0; attr->m_maximum = 1000; } } } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RimEclipseCase* RimFaultReactivationModel::eclipseCase() { auto eCase = firstAncestorOrThisOfType(); if ( eCase == nullptr ) { eCase = dynamic_cast( RiaApplication::instance()->activeGridView()->ownerCase() ); } return eCase; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimFaultReactivationModel::setBaseDir( QString path ) { m_baseDir = path; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- QString RimFaultReactivationModel::baseDir() const { return m_baseDir().path(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimFaultReactivationModel::updateTimeSteps() { m_availableTimeSteps.clear(); const auto eCase = eclipseCase(); if ( eCase != nullptr ) m_availableTimeSteps = eCase->timeStepDates(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- std::vector RimFaultReactivationModel::selectedTimeSteps() const { return m_selectedTimeSteps(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- QStringList RimFaultReactivationModel::commandParameters() const { QStringList retlist; retlist << baseDir(); retlist << inputFilename(); retlist << outputOdbFilename(); return retlist; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- QString RimFaultReactivationModel::outputOdbFilename() const { QDir directory( baseDir() ); return directory.absoluteFilePath( baseFilename() + ".odb" ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- QString RimFaultReactivationModel::inputFilename() const { QDir directory( baseDir() ); return directory.absoluteFilePath( baseFilename() + ".inp" ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- QString RimFaultReactivationModel::settingsFilename() const { QDir directory( baseDir() ); return directory.absoluteFilePath( baseFilename() + ".settings.json" ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- QString RimFaultReactivationModel::baseFilename() const { QString tmp = m_userDescription(); if ( tmp.isEmpty() ) return "faultReactivation"; tmp.replace( ' ', '_' ); tmp.replace( '/', '_' ); tmp.replace( '\\', '_' ); tmp.replace( ':', '_' ); return tmp; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- bool RimFaultReactivationModel::exportModelSettings() { if ( m_faultPlane.isNull() ) return false; QMap settings; auto [topPosition, bottomPosition] = m_faultPlane->intersectTopBottomLine(); auto faultNormal = m_faultPlane->normal(); // make sure we move horizontally faultNormal.z() = 0.0; faultNormal.normalize(); RimFaultReactivationTools::addSettingsToMap( settings, faultNormal, topPosition, bottomPosition ); QDir directory( baseDir() ); return ResInsightInternalJson::JsonWriter::encodeFile( settingsFilename(), settings ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- bool RimFaultReactivationModel::extractAndExportModelData() { exportModelSettings(); // TODO - get values from eclipse and geomech models here return true; }