ResInsight/ApplicationLibCode/ProjectDataModel/GeoMech/RimGeoMechResultDefinition.cpp
Magne Sjaastad 833a0e8584 Performance: Cellcount functions are used in many loops, and must be as fast as possible
cellCountIJK was computed based on the value of griPointDimensions. These converstion turned up during profiling. Change implementation to have cellcount as a member variable instead of being computed every time.
2024-01-22 14:52:49 +01:00

993 lines
40 KiB
C++

/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2018- Equinor ASA
// Copyright (C) 2015-2018 Statoil ASA
// Copyright (C) 2015- Ceetron Solutions 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 <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RimGeoMechResultDefinition.h"
#include "RiaMedianCalculator.h"
#include "RiaResultNames.h"
#include "RifGeoMechReaderInterface.h"
#include "RigFemAddressDefines.h"
#include "RigFemPartCollection.h"
#include "RigFemPartGrid.h"
#include "RigFemPartResultCalculatorStressAnisotropy.h"
#include "RigFemPartResultsCollection.h"
#include "RigFemResultAddress.h"
#include "RigFormationNames.h"
#include "RigGeoMechCaseData.h"
#include "RigWbsParameter.h"
#include "RigWellPath.h"
#include "Rim3dWellLogCurve.h"
#include "RimGeoMechCase.h"
#include "RimGeoMechCellColors.h"
#include "RimGeoMechPropertyFilter.h"
#include "RimGeoMechView.h"
#include "RimIntersectionCollection.h"
#include "RimPlotCurve.h"
#include "RimProject.h"
#include "RimRegularLegendConfig.h"
#include "RimViewLinker.h"
#include "RimWellPath.h"
#include "cafPdmUiDoubleValueEditor.h"
#include "cafPdmUiTreeSelectionEditor.h"
#include <QDoubleValidator>
namespace caf
{
template <>
void caf::AppEnum<RigFemResultPosEnum>::setUp()
{
addItem( RIG_NODAL, "NODAL", "Nodal" );
addItem( RIG_ELEMENT_NODAL, "ELEMENT_NODAL", "Element Nodal" );
addItem( RIG_INTEGRATION_POINT, "INTEGRATION_POINT", "Integration Point" );
addItem( RIG_ELEMENT_NODAL_FACE, "ELEMENT_NODAL_FACE", "Element Nodal On Face" );
addItem( RIG_FORMATION_NAMES, "FORMATION_NAMES", "Formation Names" );
addItem( RIG_ELEMENT, "ELEMENT", "Element" );
addItem( RIG_WELLPATH_DERIVED, "WELLPATH_DERIVED", "Well Path Derived" );
addItem( RIG_DIFFERENTIALS, "DIFFERENTIALS", "Differentials" );
setDefault( RIG_NODAL );
}
} // namespace caf
CAF_PDM_SOURCE_INIT( RimGeoMechResultDefinition, "GeoMechResultDefinition" );
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimGeoMechResultDefinition::RimGeoMechResultDefinition()
{
CAF_PDM_InitObject( "Color Result", ":/CellResult.png" );
CAF_PDM_InitFieldNoDefault( &m_resultPositionType, "ResultPositionType", "Result Position" );
m_resultPositionType.uiCapability()->setUiHidden( true );
CAF_PDM_InitField( &m_resultFieldName, "ResultFieldName", QString( "" ), "Field Name" );
m_resultFieldName.uiCapability()->setUiHidden( true );
CAF_PDM_InitField( &m_resultComponentName, "ResultComponentName", QString( "" ), "Component" );
m_resultComponentName.uiCapability()->setUiHidden( true );
CAF_PDM_InitField( &m_timeLapseBaseTimestep, "TimeLapseBaseTimeStep", RigFemResultAddress::noTimeLapseValue(), "Base Time Step" );
CAF_PDM_InitField( &m_referenceTimeStep, "ReferenceTimeStep", 0, "Reference Time Step" );
CAF_PDM_InitField( &m_compactionRefLayer, "CompactionRefLayer", 0, "Compaction Ref Layer" );
m_compactionRefLayer.uiCapability()->setUiHidden( true );
CAF_PDM_InitFieldNoDefault( &m_resultPositionTypeUiField, "ResultPositionTypeUi", "Result Position" );
m_resultPositionTypeUiField.xmlCapability()->disableIO();
CAF_PDM_InitField( &m_resultVariableUiField, "ResultVariableUI", QString( "" ), "Value" );
m_resultVariableUiField.xmlCapability()->disableIO();
m_resultVariableUiField.uiCapability()->setUiEditorTypeName( caf::PdmUiTreeSelectionEditor::uiEditorTypeName() );
m_resultVariableUiField.uiCapability()->setUiLabelPosition( caf::PdmUiItemInfo::TOP );
CAF_PDM_InitField( &m_normalizeByHydrostaticPressure, "NormalizeByHSP", false, "Normalize by Hydrostatic Pressure" );
CAF_PDM_InitField( &m_normalizationAirGap, "NormalizationAirGap", 0.0, "Air Gap" );
m_normalizationAirGap.uiCapability()->setUiEditorTypeName( caf::PdmUiDoubleValueEditor::uiEditorTypeName() );
CAF_PDM_InitField( &m_compactionRefLayerUiField,
"CompactionRefLayerUi",
RigFemResultAddress::noCompactionValue(),
"Compaction Ref Layer",
"",
"The compaction is calculated with reference to this layer. Default layer is the topmost "
"layer "
"with POR",
"" );
m_compactionRefLayerUiField.xmlCapability()->disableIO();
m_isChangedByField = false;
m_addWellPathDerivedResults = false;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimGeoMechResultDefinition::~RimGeoMechResultDefinition()
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimGeoMechResultDefinition::defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering )
{
uiOrdering.add( &m_resultPositionTypeUiField );
uiOrdering.add( &m_resultVariableUiField );
QString valueLabel = "Value";
if ( m_timeLapseBaseTimestep != RigFemResultAddress::noTimeLapseValue() )
{
valueLabel += QString( " (%1)" ).arg( diffResultUiName() );
}
m_resultVariableUiField.uiCapability()->setUiName( valueLabel );
if ( normalizableResultSelected() )
{
caf::PdmUiGroup* normalizationGroup = uiOrdering.addNewGroup( "Result Normalization" );
normalizationGroup->add( &m_normalizeByHydrostaticPressure );
if ( m_normalizeByHydrostaticPressure )
{
normalizationGroup->add( &m_normalizationAirGap );
}
}
if ( m_resultPositionTypeUiField() != RIG_FORMATION_NAMES )
{
bool isReferenceCaseDependent = referenceCaseDependentResultSelected();
if ( isReferenceCaseDependent )
{
caf::PdmUiGroup* referenceCaseGr = uiOrdering.addNewGroup( "Reference Case" );
referenceCaseGr->add( &m_referenceTimeStep );
}
else
{
caf::PdmUiGroup* timeLapseGr = uiOrdering.addNewGroup( "Difference Options" );
timeLapseGr->add( &m_timeLapseBaseTimestep );
}
}
if ( m_resultPositionTypeUiField() == RIG_NODAL )
{
caf::PdmUiGroup* compactionGroup = uiOrdering.addNewGroup( "Compaction Options" );
compactionGroup->add( &m_compactionRefLayerUiField );
if ( m_compactionRefLayerUiField == RigFemResultAddress::noCompactionValue() )
{
if ( m_geomCase && m_geomCase->geoMechData() )
{
m_compactionRefLayerUiField =
(int)m_geomCase->geoMechData()->femParts()->part( 0 )->getOrCreateStructGrid()->reservoirIJKBoundingBox().first.z();
}
}
}
if ( !m_isChangedByField )
{
m_resultPositionTypeUiField = m_resultPositionType;
m_resultVariableUiField = composeFieldCompString( m_resultFieldName(), m_resultComponentName() );
}
m_isChangedByField = false;
uiOrdering.skipRemainingFields( true );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QList<caf::PdmOptionItemInfo> RimGeoMechResultDefinition::calculateValueOptions( const caf::PdmFieldHandle* fieldNeedingOptions )
{
QList<caf::PdmOptionItemInfo> options;
if ( m_geomCase )
{
if ( &m_resultPositionTypeUiField == fieldNeedingOptions )
{
std::vector<RigFemResultPosEnum> optionItems = { RIG_NODAL,
RIG_ELEMENT_NODAL,
RIG_INTEGRATION_POINT,
RIG_ELEMENT_NODAL_FACE,
RIG_FORMATION_NAMES,
RIG_ELEMENT,
RIG_DIFFERENTIALS };
if ( m_addWellPathDerivedResults )
{
optionItems.push_back( RIG_WELLPATH_DERIVED );
}
for ( RigFemResultPosEnum value : optionItems )
{
options.push_back( caf::PdmOptionItemInfo( caf::AppEnum<RigFemResultPosEnum>::uiText( value ), QVariant( value ) ) );
}
}
else if ( &m_resultVariableUiField == fieldNeedingOptions )
{
std::map<std::string, std::vector<std::string>> fieldCompNames = getResultMetaDataForUIFieldSetting();
QStringList uiVarNames;
QStringList varNames;
getUiAndResultVariableStringList( &uiVarNames, &varNames, fieldCompNames );
for ( int oIdx = 0; oIdx < uiVarNames.size(); ++oIdx )
{
options.push_back( caf::PdmOptionItemInfo( uiVarNames[oIdx], varNames[oIdx] ) );
}
}
else if ( &m_timeLapseBaseTimestep == fieldNeedingOptions )
{
std::vector<std::string> stepNames;
if ( m_geomCase->geoMechData() )
{
stepNames = m_geomCase->geoMechData()->femPartResults()->stepNames();
}
options.push_back( caf::PdmOptionItemInfo( QString( "Disabled" ), RigFemResultAddress::noTimeLapseValue() ) );
for ( size_t stepIdx = 0; stepIdx < stepNames.size(); ++stepIdx )
{
options.push_back(
caf::PdmOptionItemInfo( QString( "%1 (#%2)" ).arg( QString::fromStdString( stepNames[stepIdx] ) ).arg( stepIdx ),
static_cast<int>( stepIdx ) ) );
}
}
else if ( &m_referenceTimeStep == fieldNeedingOptions )
{
std::vector<std::string> stepNames;
if ( m_geomCase->geoMechData() )
{
stepNames = m_geomCase->geoMechData()->femPartResults()->stepNames();
}
for ( size_t stepIdx = 0; stepIdx < stepNames.size(); ++stepIdx )
{
options.push_back(
caf::PdmOptionItemInfo( QString( "%1 (#%2)" ).arg( QString::fromStdString( stepNames[stepIdx] ) ).arg( stepIdx ),
static_cast<int>( stepIdx ) ) );
}
}
else if ( &m_compactionRefLayerUiField == fieldNeedingOptions )
{
if ( m_geomCase->geoMechData() )
{
size_t kCount = m_geomCase->geoMechData()->femParts()->part( 0 )->getOrCreateStructGrid()->cellCountK();
for ( size_t layerIdx = 0; layerIdx < kCount; ++layerIdx )
{
options.push_back( caf::PdmOptionItemInfo( QString::number( layerIdx + 1 ), (int)layerIdx ) );
}
}
}
}
return options;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimGeoMechResultDefinition::setGeoMechCase( RimGeoMechCase* geomCase )
{
m_geomCase = geomCase;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimGeoMechCase* RimGeoMechResultDefinition::geoMechCase() const
{
return m_geomCase;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimGeoMechResultDefinition::fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue )
{
m_isChangedByField = true;
if ( &m_resultPositionTypeUiField == changedField )
{
if ( m_resultPositionTypeUiField() == RIG_WELLPATH_DERIVED || m_resultPositionType() == RIG_FORMATION_NAMES )
{
m_timeLapseBaseTimestep = RigFemResultAddress::noTimeLapseValue();
m_timeLapseBaseTimestep.uiCapability()->setUiReadOnly( true );
}
else
{
m_timeLapseBaseTimestep.uiCapability()->setUiReadOnly( false );
}
}
if ( &m_resultPositionTypeUiField == changedField || &m_timeLapseBaseTimestep == changedField || &m_referenceTimeStep == changedField )
{
std::map<std::string, std::vector<std::string>> fieldCompNames = getResultMetaDataForUIFieldSetting();
QStringList uiVarNames;
QStringList varNames;
getUiAndResultVariableStringList( &uiVarNames, &varNames, fieldCompNames );
if ( m_resultPositionTypeUiField() == m_resultPositionType() &&
varNames.contains( composeFieldCompString( m_resultFieldName(), m_resultComponentName() ) ) )
{
m_resultVariableUiField = composeFieldCompString( m_resultFieldName(), m_resultComponentName() );
}
else
{
m_resultVariableUiField = "";
}
if ( &m_referenceTimeStep == changedField )
{
m_geomCase->geoMechData()->femPartResults()->setReferenceTimeStep( m_referenceTimeStep() );
}
}
if ( &m_normalizeByHydrostaticPressure == changedField && m_normalizationAirGap == 0.0 )
{
calculateNormalizationAirGapDefault();
if ( m_normalizeByHydrostaticPressure )
{
m_geomCase->geoMechData()->femPartResults()->setNormalizationAirGap( m_normalizationAirGap );
}
}
// Get the possible property filter owner
auto propFilter = dynamic_cast<RimGeoMechPropertyFilter*>( parentField()->ownerObject() );
auto view = firstAncestorOrThisOfType<RimGridView>();
auto curve = firstAncestorOrThisOfType<RimPlotCurve>();
auto rim3dWellLogCurve = firstAncestorOrThisOfType<Rim3dWellLogCurve>();
if ( &m_resultVariableUiField == changedField || &m_compactionRefLayerUiField == changedField ||
&m_timeLapseBaseTimestep == changedField || &m_normalizeByHydrostaticPressure == changedField ||
&m_normalizationAirGap == changedField || &m_referenceTimeStep == changedField || &m_isChecked == changedField )
{
QStringList fieldComponentNames = m_resultVariableUiField().split( QRegExp( "\\s+" ) );
if ( !fieldComponentNames.empty() )
{
m_resultPositionType = m_resultPositionTypeUiField;
if ( m_resultPositionType() == RIG_FORMATION_NAMES )
{
// Complete string of selected formation is stored in m_resultFieldName
m_resultFieldName = m_resultVariableUiField();
m_resultComponentName = "";
}
else
{
m_resultFieldName = fieldComponentNames[0];
if ( fieldComponentNames.size() > 1 )
{
m_resultComponentName = fieldComponentNames[1];
}
else
{
m_resultComponentName = "";
}
m_compactionRefLayer = m_compactionRefLayerUiField();
}
if ( propFilter )
{
propFilter->setToDefaultValues();
if ( view ) view->scheduleGeometryRegen( PROPERTY_FILTERED );
}
if ( view )
{
view->scheduleCreateDisplayModelAndRedraw();
view->intersectionCollection()->scheduleCreateDisplayModelAndRedraw2dIntersectionViews();
}
if ( dynamic_cast<RimGeoMechCellColors*>( this ) )
{
updateLegendCategorySettings();
if ( view )
{
RimViewLinker* viewLinker = view->assosiatedViewLinker();
if ( viewLinker )
{
viewLinker->updateCellResult();
}
}
}
if ( curve )
{
curve->loadDataAndUpdate( true );
}
if ( rim3dWellLogCurve )
{
rim3dWellLogCurve->updateCurveIn3dView();
}
}
}
if ( rim3dWellLogCurve )
{
rim3dWellLogCurve->resetMinMaxValues();
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimGeoMechResultDefinition::calculateNormalizationAirGapDefault()
{
RiaMedianCalculator<double> airGapCalc;
for ( auto wellPath : RimProject::current()->allWellPaths() )
{
if ( wellPath->wellPathGeometry() )
{
double airGap = wellPath->wellPathGeometry()->rkbDiff();
if ( airGap > 0.0 )
{
airGapCalc.add( airGap );
}
}
}
if ( airGapCalc.valid() )
{
m_normalizationAirGap = airGapCalc.median();
}
else
{
m_normalizationAirGap = 0.0;
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RimGeoMechResultDefinition::useUndoRedoForFieldChanged()
{
// Do not use undo/redo, because a state variable is initialized in fieldChanged(), and the undo/redo framework
// trigger a call to defineUiOrdering() before fieldChanged causing invalid state in this object.
// Having a state variable in fieldChanged/defineUiOrdering is a fragile pattern and should be avoided
// See CmdFieldChangeExec::redo()
return false;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::map<std::string, std::vector<std::string>> RimGeoMechResultDefinition::getResultMetaDataForUIFieldSetting()
{
RimGeoMechCase* gmCase = m_geomCase;
std::map<std::string, std::vector<std::string>> fieldWithComponentNames;
if ( gmCase && gmCase->geoMechData() )
{
fieldWithComponentNames = gmCase->geoMechData()->femPartResults()->scalarFieldAndComponentNames( m_resultPositionTypeUiField() );
}
return fieldWithComponentNames;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimGeoMechResultDefinition::getUiAndResultVariableStringList( QStringList* uiNames,
QStringList* variableNames,
const std::map<std::string, std::vector<std::string>>& fieldCompNames )
{
CVF_ASSERT( uiNames && variableNames );
std::map<std::string, std::vector<std::string>>::const_iterator fieldIt;
for ( fieldIt = fieldCompNames.begin(); fieldIt != fieldCompNames.end(); ++fieldIt )
{
QString resultFieldName = QString::fromStdString( fieldIt->first );
if ( resultFieldName == "E" || resultFieldName == "S" || resultFieldName == "POR" )
continue; // We will not show the native POR, Stress and Strain
QString resultFieldUiName = convertToUiResultFieldName( resultFieldName );
uiNames->push_back( resultFieldUiName );
variableNames->push_back( resultFieldName );
std::vector<std::string>::const_iterator compIt;
for ( compIt = fieldIt->second.begin(); compIt != fieldIt->second.end(); ++compIt )
{
QString resultCompName = QString::fromStdString( *compIt );
uiNames->push_back( " " + resultCompName );
variableNames->push_back( composeFieldCompString( resultFieldName, resultCompName ) );
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RimGeoMechResultDefinition::composeFieldCompString( const QString& resultFieldName, const QString& resultComponentName )
{
if ( resultComponentName.isEmpty() )
return resultFieldName;
else
return resultFieldName + " " + resultComponentName;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimGeoMechResultDefinition::initAfterRead()
{
if ( m_resultComponentName() == "STM" || m_resultComponentName() == "SEM" ) m_resultComponentName = "SM";
m_resultPositionTypeUiField = m_resultPositionType;
m_resultVariableUiField = composeFieldCompString( m_resultFieldName(), m_resultComponentName() );
m_compactionRefLayerUiField = m_compactionRefLayer;
m_timeLapseBaseTimestep.uiCapability()->setUiReadOnly( resultPositionType() == RIG_WELLPATH_DERIVED );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimGeoMechResultDefinition::defineEditorAttribute( const caf::PdmFieldHandle* field, QString uiConfigName, caf::PdmUiEditorAttribute* attribute )
{
if ( field == &m_normalizationAirGap )
{
auto attr = dynamic_cast<caf::PdmUiDoubleValueEditorAttribute*>( attribute );
if ( attr )
{
attr->m_decimals = 2;
attr->m_validator = new QDoubleValidator( 0.0, std::numeric_limits<double>::max(), 2 );
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimGeoMechResultDefinition::loadResult()
{
if ( m_geomCase && m_geomCase->geoMechData() )
{
if ( resultAddress().fieldName == RiaResultNames::wbsFGResult().toStdString() ||
resultAddress().fieldName == RiaResultNames::wbsSFGResult().toStdString() )
{
RigFemResultAddress stressResAddr( RIG_ELEMENT_NODAL, std::string( "ST" ), "" );
RigFemResultAddress porBarResAddr = RigFemAddressDefines::elementNodalPorBarAddress();
m_geomCase->geoMechData()->femPartResults()->assertResultsLoaded( stressResAddr );
m_geomCase->geoMechData()->femPartResults()->assertResultsLoaded( porBarResAddr );
}
else
{
m_geomCase->geoMechData()->femPartResults()->assertResultsLoaded( resultAddress() );
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimGeoMechResultDefinition::setAddWellPathDerivedResults( bool addWellPathDerivedResults )
{
m_addWellPathDerivedResults = addWellPathDerivedResults;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RigFemResultAddress RimGeoMechResultDefinition::resultAddress() const
{
// Convert differentials to their underlying position type
if ( resultPositionType() == RIG_DIFFERENTIALS )
{
RigFemResultPosEnum resultPositionType = RIG_ELEMENT_NODAL;
if ( resultFieldName().toStdString() == RigFemAddressDefines::porBar() )
{
resultPositionType = RIG_NODAL;
}
return RigFemResultAddress( resultPositionType,
resultFieldName().toStdString(),
resultComponentName().toStdString(),
m_timeLapseBaseTimestep(),
RigFemResultAddress::noCompactionValue() );
}
else
{
RigFemResultAddress address( resultPositionType(),
resultFieldName().toStdString(),
resultComponentName().toStdString(),
m_timeLapseBaseTimestep(),
resultFieldName().toStdString() == RigFemPartResultsCollection::FIELD_NAME_COMPACTION
? m_compactionRefLayer()
: RigFemResultAddress::noCompactionValue(),
m_normalizeByHydrostaticPressure );
if ( !RigFemPartResultsCollection::isNormalizableResult( address ) )
{
address.normalizedByHydrostaticPressure = false;
}
if ( RigFemPartResultsCollection::isReferenceCaseDependentResult( address ) )
{
address.timeLapseBaseStepIdx = RigFemResultAddress::noTimeLapseValue();
}
return address;
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<RigFemResultAddress> RimGeoMechResultDefinition::observedResults() const
{
return std::vector<RigFemResultAddress>( 1, resultAddress() );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RigFemResultPosEnum RimGeoMechResultDefinition::resultPositionType() const
{
return m_resultPositionType();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RimGeoMechResultDefinition::resultFieldName() const
{
if ( !isChecked() ) return "";
return m_resultFieldName();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RimGeoMechResultDefinition::resultComponentName() const
{
return m_resultComponentName();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RimGeoMechResultDefinition::diffResultUiName() const
{
QString diffResultString;
if ( m_geomCase->geoMechData() )
{
if ( referenceCaseDependentResultSelected() )
{
std::vector<std::string> timeStepNames = m_geomCase->geoMechData()->femPartResults()->stepNames();
QString timeStepString = QString::fromStdString( timeStepNames[m_referenceTimeStep()] );
diffResultString += QString( "<b>Reference Time Step</b>: %1" ).arg( timeStepString );
}
else if ( m_timeLapseBaseTimestep != RigFemResultAddress::noTimeLapseValue() )
{
std::vector<std::string> timeStepNames = m_geomCase->geoMechData()->femPartResults()->stepNames();
QString timeStepString = QString::fromStdString( timeStepNames[m_timeLapseBaseTimestep()] );
diffResultString += QString( "<b>Base Time Step</b>: %1" ).arg( timeStepString );
}
}
return diffResultString;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RimGeoMechResultDefinition::diffResultUiShortName() const
{
QString diffResultString;
if ( m_geomCase->geoMechData() )
{
if ( referenceCaseDependentResultSelected() )
{
diffResultString += QString( "Ref. Time: #%1" ).arg( m_referenceTimeStep() );
}
else if ( m_timeLapseBaseTimestep != RigFemResultAddress::noTimeLapseValue() )
{
diffResultString += QString( "Base Time: #%1" ).arg( m_timeLapseBaseTimestep() );
}
}
return diffResultString;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RigGeoMechCaseData* RimGeoMechResultDefinition::ownerCaseData() const
{
return m_geomCase ? m_geomCase->geoMechData() : nullptr;
}
//--------------------------------------------------------------------------------------------------
/// Is the result probably valid and possible to load
//--------------------------------------------------------------------------------------------------
bool RimGeoMechResultDefinition::hasResult()
{
RigGeoMechCaseData* caseData = ownerCaseData();
if ( caseData )
{
RigFemPartResultsCollection* results = caseData->femPartResults();
if ( results )
{
return results->assertResultsLoaded( resultAddress() );
}
}
return false;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RimGeoMechResultDefinition::resultFieldUiName() const
{
return convertToUiResultFieldName( m_resultFieldName() );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RimGeoMechResultDefinition::resultComponentUiName() const
{
return m_resultComponentName();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RimGeoMechResultDefinition::resultVariableUiName() const
{
QString name = resultFieldName();
QString resCompName = resultComponentName();
if ( !resCompName.isEmpty() )
{
name += "." + resCompName;
}
return name;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RimGeoMechResultDefinition::resultVariableName() const
{
if ( m_resultPositionType == RIG_WELLPATH_DERIVED )
{
RigWbsParameter param;
if ( RigWbsParameter::findParameter( resultFieldName(), &param ) )
{
QString lasName = param.addressString( RigWbsParameter::LAS_FILE );
if ( !lasName.isEmpty() ) return lasName;
}
}
return resultVariableUiName();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RimGeoMechResultDefinition::currentResultUnits() const
{
RigFemResultAddress rigFemResultAddress = resultAddress();
if ( RigFemPartResultCalculatorStressAnisotropy::isAnisotropyResult( rigFemResultAddress ) )
{
return RiaWellLogUnitTools<double>::noUnitString();
}
if ( resultFieldName() == "SE" || resultFieldName() == "ST" ||
resultFieldName() == QString::fromStdString( RigFemAddressDefines::porBar() ) || resultFieldName() == "SM" ||
resultFieldName() == "SEM" || resultFieldName() == "Q" )
{
auto componentName = resultComponentName();
if ( componentName.endsWith( "azi" ) || componentName.endsWith( "inc" ) )
{
return "Deg";
}
if ( rigFemResultAddress.normalizeByHydrostaticPressure() )
{
return "sg";
}
return "Bar";
}
else if ( resultFieldName() == "MODULUS" )
{
return "GPa";
}
else if ( resultFieldName() == "COMPRESSIBILITY" && ( resultComponentName() == "PORE" || resultComponentName() == "VERTICAL" ) )
{
return "1/GPa";
}
else if ( resultFieldName() == "PORO-PERM" && resultComponentName() == "PERM" )
{
return "mD";
}
else
{
for ( auto resultName : RiaResultNames::wbsDerivedResultNames() )
{
if ( resultName == resultFieldName() )
{
return RiaWellLogUnitTools<double>::sg_emwUnitString();
}
}
}
return RiaWellLogUnitTools<double>::noUnitString();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RimGeoMechResultDefinition::defaultLasUnits() const
{
if ( m_resultPositionType == RIG_WELLPATH_DERIVED )
{
RigWbsParameter param;
if ( RigWbsParameter::findParameter( resultFieldName(), &param ) )
{
return param.units( RigWbsParameter::LAS_FILE );
}
}
return currentResultUnits();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
double RimGeoMechResultDefinition::normalizationAirGap() const
{
return m_normalizationAirGap;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimGeoMechResultDefinition::setNormalizationAirGap( double airGap )
{
m_normalizationAirGap = airGap;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RimGeoMechResultDefinition::convertToUiResultFieldName( QString resultFieldName )
{
QString newName( resultFieldName );
if ( resultFieldName == "E" ) newName = "NativeAbaqus Strain";
if ( resultFieldName == "S" ) newName = "NativeAbaqus Stress";
if ( resultFieldName == "NE" ) newName = "E"; // Make NE and NS appear as E and SE
if ( resultFieldName == QString::fromStdString( RigFemAddressDefines::porBar() ) ) newName = "POR"; // POR-Bar appear as POR
if ( resultFieldName == "MODULUS" ) newName = "Young's Modulus";
if ( resultFieldName == "RATIO" ) newName = "Poisson's Ratio";
if ( resultFieldName == "UCS" ) newName = "UCS bar/ 100";
return newName;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RimGeoMechResultDefinition::normalizableResultSelected() const
{
return RigFemPartResultsCollection::isNormalizableResult( resultAddress() );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RimGeoMechResultDefinition::referenceCaseDependentResultSelected() const
{
return RigFemPartResultsCollection::isReferenceCaseDependentResult( resultAddress() );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimGeoMechResultDefinition::setResultAddress( const RigFemResultAddress& resultAddress )
{
m_resultPositionType = resultAddress.resultPosType;
m_resultFieldName = QString::fromStdString( resultAddress.fieldName );
m_resultComponentName = QString::fromStdString( resultAddress.componentName );
m_timeLapseBaseTimestep = resultAddress.timeLapseBaseStepIdx;
m_compactionRefLayer = resultAddress.refKLayerIndex;
m_normalizeByHydrostaticPressure = resultAddress.normalizedByHydrostaticPressure;
m_resultPositionTypeUiField = m_resultPositionType;
m_resultVariableUiField = composeFieldCompString( m_resultFieldName(), m_resultComponentName() );
m_compactionRefLayerUiField = m_compactionRefLayer;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimGeoMechResultDefinition::updateLegendTextAndRanges( RimRegularLegendConfig* legendConfigToUpdate,
const QString& legendHeading,
int viewerStepIndex )
{
if ( !ownerCaseData() || !( resultAddress().isValid() ) )
{
return;
}
double localMin, localMax;
double localPosClosestToZero, localNegClosestToZero;
double globalMin, globalMax;
double globalPosClosestToZero, globalNegClosestToZero;
RigGeoMechCaseData* gmCase = ownerCaseData();
CVF_ASSERT( gmCase );
RigFemResultAddress resVarAddress = resultAddress();
auto [stepIdx, frameIdx] = gmCase->femPartResults()->stepListIndexToTimeStepAndDataFrameIndex( viewerStepIndex );
gmCase->femPartResults()->minMaxScalarValues( resVarAddress, stepIdx, frameIdx, &localMin, &localMax );
gmCase->femPartResults()->posNegClosestToZero( resVarAddress, stepIdx, frameIdx, &localPosClosestToZero, &localNegClosestToZero );
gmCase->femPartResults()->minMaxScalarValues( resVarAddress, &globalMin, &globalMax );
gmCase->femPartResults()->posNegClosestToZero( resVarAddress, &globalPosClosestToZero, &globalNegClosestToZero );
legendConfigToUpdate->setClosestToZeroValues( globalPosClosestToZero, globalNegClosestToZero, localPosClosestToZero, localNegClosestToZero );
legendConfigToUpdate->setAutomaticRanges( globalMin, globalMax, localMin, localMax );
if ( hasCategoryResult() )
{
std::vector<QString> fnVector = gmCase->femPartResults()->formationNames();
legendConfigToUpdate->setNamedCategories( fnVector );
}
QString legendTitle = legendHeading + caf::AppEnum<RigFemResultPosEnum>( resultPositionType() ).uiText() + "\n" + resultFieldUiName();
if ( !resultComponentUiName().isEmpty() )
{
legendTitle += ", " + resultComponentUiName();
}
QString unitString = currentResultUnits();
if ( unitString != RiaWellLogUnitTools<double>::noUnitString() )
{
legendTitle += QString( " [%1]" ).arg( unitString );
}
if ( !diffResultUiShortName().isEmpty() )
{
legendTitle += QString( "\nTime Diff:\n%1" ).arg( diffResultUiShortName() );
}
legendConfigToUpdate->setTitle( legendTitle );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RimGeoMechResultDefinition::isBiotCoefficientDependent() const
{
return ( resultFieldName() == "COMPRESSIBILITY" || resultFieldName() == "PORO-PERM" );
}