///////////////////////////////////////////////////////////////////////////////// // // Copyright (C) 2018- 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 "RimGeoMechContourMapProjection.h" #include "RigContourMapCalculator.h" #include "RigContourMapGrid.h" #include "RigContourMapProjection.h" #include "RigFemAddressDefines.h" #include "RigFemPart.h" #include "RigFemPartCollection.h" #include "RigFemPartGrid.h" #include "RigFemPartResultsCollection.h" #include "RigGeoMechCaseData.h" #include "RigGeoMechContourMapProjection.h" #include "RimCellFilterCollection.h" #include "RimGeoMechCase.h" #include "RimGeoMechCellColors.h" #include "RimGeoMechContourMapView.h" #include "RimPropertyFilterCollection.h" #include "RimRegularLegendConfig.h" #include "RivFemElmVisibilityCalculator.h" #include "cafPdmUiDoubleSliderEditor.h" #include "cvfArray.h" #include "cvfStructGridGeometryGenerator.h" #include "cvfVector3.h" CAF_PDM_SOURCE_INIT( RimGeoMechContourMapProjection, "RimGeoMechContourMapProjection" ); //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RimGeoMechContourMapProjection::RimGeoMechContourMapProjection() { CAF_PDM_InitObject( "RimContourMapProjection", ":/2DMapProjection16x16.png" ); CAF_PDM_InitField( &m_limitToPorePressureRegions, "LimitToPorRegion", true, "Limit to Pore Pressure regions" ); CAF_PDM_InitField( &m_applyPPRegionLimitVertically, "VerticalLimit", false, "Apply Limit Vertically" ); CAF_PDM_InitField( &m_paddingAroundPorePressureRegion, "PaddingAroundPorRegion", 0.0, "Horizontal Padding around PP regions" ); m_paddingAroundPorePressureRegion.uiCapability()->setUiEditorTypeName( caf::PdmUiDoubleSliderEditor::uiEditorTypeName() ); setName( "Map Projection" ); nameField()->uiCapability()->setUiReadOnly( true ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RimGeoMechContourMapProjection::~RimGeoMechContourMapProjection() { } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- QString RimGeoMechContourMapProjection::resultDescriptionText() const { QString resultText = QString( "%1, %2" ).arg( resultAggregationText() ).arg( view()->cellResult()->resultFieldUiName() ); return resultText; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RimRegularLegendConfig* RimGeoMechContourMapProjection::legendConfig() const { return view()->cellResult()->legendConfig(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimGeoMechContourMapProjection::updateLegend() { RimGeoMechCellColors* cellColors = view()->cellResult(); double minVal = m_contourMapProjection->minValue(); double maxVal = m_contourMapProjection->maxValue(); std::pair minmaxValAllTimeSteps = minmaxValuesAllTimeSteps(); legendConfig()->setAutomaticRanges( minmaxValAllTimeSteps.first, minmaxValAllTimeSteps.second, minVal, maxVal ); QString projectionLegendText = QString( "Map Projection\n%1" ).arg( m_resultAggregation().uiText() ); if ( cellColors->resultAddress().isValid() ) { projectionLegendText += QString( "\nResult: %1" ).arg( cellColors->resultFieldUiName() ); if ( !cellColors->resultComponentUiName().isEmpty() ) { projectionLegendText += QString( ", %1" ).arg( cellColors->resultComponentUiName() ); } } else { projectionLegendText += QString( "\nNo Result Selected" ); } legendConfig()->setTitle( projectionLegendText ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- double RimGeoMechContourMapProjection::sampleSpacing() const { RimGeoMechCase* geoMechCase = this->geoMechCase(); if ( geoMechCase ) { return m_relativeSampleSpacing * geoMechCase->characteristicCellSize(); } return 0.0; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- cvf::ref RimGeoMechContourMapProjection::getCellVisibility() const { cvf::ref cellGridIdxVisibility = new cvf::UByteArray( m_femPart->elementCount() ); RivFemElmVisibilityCalculator::computeAllVisible( cellGridIdxVisibility.p(), m_femPart.p() ); if ( view()->cellFilterCollection()->isActive() ) { cvf::CellRangeFilter cellRangeFilter; view()->cellFilterCollection()->compoundCellRangeFilter( &cellRangeFilter, 0 ); cvf::UByteArray indexIncludeVis = ( *cellGridIdxVisibility.p() ); cvf::UByteArray indexExcludeVis = ( *cellGridIdxVisibility.p() ); view()->cellFilterCollection()->updateCellVisibilityByIndex( &indexIncludeVis, &indexExcludeVis, 0 ); RivFemElmVisibilityCalculator::computeRangeVisibility( cellGridIdxVisibility.p(), m_femPart.p(), cellRangeFilter, &indexIncludeVis, &indexExcludeVis, view()->cellFilterCollection()->hasActiveIncludeIndexFilters(), view()->cellFilterCollection()->useAndOperation() ); } if ( view()->propertyFilterCollection()->isActive() ) { auto [stepIdx, frameIdx] = view()->currentStepAndDataFrame(); RivFemElmVisibilityCalculator::computePropertyVisibility( cellGridIdxVisibility.p(), m_femPart.p(), stepIdx, frameIdx, cellGridIdxVisibility.p(), view()->geoMechPropertyFilterCollection() ); } return cellGridIdxVisibility; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimGeoMechContourMapProjection::updateGridInformation() { RimGeoMechCase* geoMechCase = this->geoMechCase(); if ( !geoMechCase ) return; m_femPart = geoMechCase->geoMechData()->femParts()->part( 0 ); m_femPartGrid = m_femPart->getOrCreateStructGrid(); m_femPart->ensureIntersectionSearchTreeIsBuilt(); cvf::BoundingBox gridBoundingBox = geoMechCase->activeCellsBoundingBox(); cvf::BoundingBox expandedBoundingBox; if ( m_limitToPorePressureRegions ) { auto [stepIdx, frameIdx] = view()->currentStepAndDataFrame(); expandedBoundingBox = RigGeoMechContourMapProjection::calculateExpandedPorBarBBox( *geoMechCase->geoMechData(), view()->cellResult()->resultComponentName().toStdString(), stepIdx, frameIdx, m_paddingAroundPorePressureRegion() ); if ( !expandedBoundingBox.isValid() ) { m_limitToPorePressureRegions = false; } } if ( !m_limitToPorePressureRegions ) { expandedBoundingBox = gridBoundingBox; } cvf::Vec3d minExpandedPoint = expandedBoundingBox.min() - cvf::Vec3d( gridEdgeOffset(), gridEdgeOffset(), 0.0 ); cvf::Vec3d maxExpandedPoint = expandedBoundingBox.max() + cvf::Vec3d( gridEdgeOffset(), gridEdgeOffset(), 0.0 ); if ( m_limitToPorePressureRegions && !m_applyPPRegionLimitVertically ) { minExpandedPoint.z() = gridBoundingBox.min().z(); maxExpandedPoint.z() = gridBoundingBox.max().z(); } expandedBoundingBox = cvf::BoundingBox( minExpandedPoint, maxExpandedPoint ); m_contourMapGrid = std::make_unique( gridBoundingBox, expandedBoundingBox, sampleSpacing() ); m_contourMapProjection = std::make_unique( *geoMechCase->geoMechData(), *m_contourMapGrid, m_limitToPorePressureRegions, m_paddingAroundPorePressureRegion ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- std::vector RimGeoMechContourMapProjection::retrieveParameterWeights() { return std::vector(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- std::vector RimGeoMechContourMapProjection::generateResults( int viewerStepIndex ) const { if ( m_contourMapProjection ) { RimGeoMechCellColors* cellColors = view()->cellResult(); RigFemResultAddress resultAddress = cellColors->resultAddress(); return generateResultsFromAddress( resultAddress, m_mapCellVisibility, viewerStepIndex ); } return {}; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimGeoMechContourMapProjection::generateAndSaveResults( int timeStep ) { if ( m_contourMapProjection ) { RimGeoMechCellColors* cellColors = view()->cellResult(); RigFemResultAddress resultAddress = cellColors->resultAddress(); dynamic_cast( m_contourMapProjection.get() ) ->generateAndSaveResults( resultAddress, m_resultAggregation(), timeStep ); } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- std::vector RimGeoMechContourMapProjection::generateResultsFromAddress( RigFemResultAddress resultAddress, const std::vector& mapCellVisibility, int viewerStepIndex ) const { return dynamic_cast( m_contourMapProjection.get() ) ->generateResultsFromAddress( resultAddress, mapCellVisibility, m_resultAggregation(), viewerStepIndex ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- bool RimGeoMechContourMapProjection::resultVariableChanged() const { RimGeoMechCellColors* cellColors = view()->cellResult(); RigFemResultAddress resAddr = cellColors->resultAddress(); return !m_currentResultAddr.isValid() || !( m_currentResultAddr == resAddr ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimGeoMechContourMapProjection::clearResultVariable() { m_currentResultAddr = RigFemResultAddress(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RimGridView* RimGeoMechContourMapProjection::baseView() const { return view(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RimGeoMechCase* RimGeoMechContourMapProjection::geoMechCase() const { return firstAncestorOrThisOfType(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RimGeoMechContourMapView* RimGeoMechContourMapProjection::view() const { return firstAncestorOrThisOfTypeAsserted(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimGeoMechContourMapProjection::updateAfterResultGeneration( int timeStep ) { m_currentResultTimestep = timeStep; RimGeoMechCellColors* cellColors = view()->cellResult(); RigFemResultAddress resAddr = cellColors->resultAddress(); m_currentResultAddr = resAddr; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimGeoMechContourMapProjection::fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue ) { RimContourMapProjection::fieldChangedByUi( changedField, oldValue, newValue ); if ( changedField == &m_limitToPorePressureRegions || changedField == &m_applyPPRegionLimitVertically || changedField == &m_paddingAroundPorePressureRegion ) { clearGridMapping(); } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- QList RimGeoMechContourMapProjection::calculateValueOptions( const caf::PdmFieldHandle* fieldNeedingOptions ) { QList options; if ( fieldNeedingOptions == &m_resultAggregation ) { std::vector validOptions = { RigContourMapCalculator::TOP_VALUE, RigContourMapCalculator::MEAN, RigContourMapCalculator::GEOMETRIC_MEAN, RigContourMapCalculator::HARMONIC_MEAN, RigContourMapCalculator::MIN_VALUE, RigContourMapCalculator::MAX_VALUE, RigContourMapCalculator::SUM }; for ( RigContourMapCalculator::ResultAggregationType option : validOptions ) { options.push_back( caf::PdmOptionItemInfo( ResultAggregation::uiText( option ), option ) ); } } return options; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimGeoMechContourMapProjection::defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) { RimContourMapProjection::defineUiOrdering( uiConfigName, uiOrdering ); caf::PdmUiGroup* group = uiOrdering.addNewGroup( "Map Boundaries" ); group->add( &m_limitToPorePressureRegions ); group->add( &m_applyPPRegionLimitVertically ); group->add( &m_paddingAroundPorePressureRegion ); m_applyPPRegionLimitVertically.uiCapability()->setUiReadOnly( !m_limitToPorePressureRegions() ); m_paddingAroundPorePressureRegion.uiCapability()->setUiReadOnly( !m_limitToPorePressureRegions() ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimGeoMechContourMapProjection::defineEditorAttribute( const caf::PdmFieldHandle* field, QString uiConfigName, caf::PdmUiEditorAttribute* attribute ) { RimContourMapProjection::defineEditorAttribute( field, uiConfigName, attribute ); if ( field == &m_paddingAroundPorePressureRegion ) { caf::PdmUiDoubleSliderEditorAttribute* myAttr = dynamic_cast( attribute ); if ( myAttr ) { myAttr->m_minimum = 0.0; myAttr->m_maximum = 2.0; myAttr->m_sliderTickCount = 4; myAttr->m_delaySliderUpdateUntilRelease = true; } } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- std::pair RimGeoMechContourMapProjection::minmaxValuesAllTimeSteps() { if ( !resultRangeIsValid() ) { clearTimeStepRange(); if ( geoMechCase()->geoMechData()->femPartResults() ) { int steps = geoMechCase()->geoMechData()->femPartResults()->totalSteps(); for ( int stepIdx = 0; stepIdx < steps; stepIdx++ ) { std::vector aggregatedResults = generateResults( stepIdx ); m_minResultAllTimeSteps = std::min( m_minResultAllTimeSteps, RigContourMapProjection::minValue( aggregatedResults ) ); m_maxResultAllTimeSteps = std::max( m_maxResultAllTimeSteps, RigContourMapProjection::maxValue( aggregatedResults ) ); } } } return std::make_pair( m_minResultAllTimeSteps, m_maxResultAllTimeSteps ); }