///////////////////////////////////////////////////////////////////////////////// // // Copyright (C) 2017 - Statoil 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 "RimStimPlanFractureTemplate.h" #include "RiaApplication.h" #include "RiaCompletionTypeCalculationScheduler.h" #include "RiaFractureDefines.h" #include "RiaLogging.h" #include "RiaWeightedGeometricMeanCalculator.h" #include "RiaWeightedMeanCalculator.h" #include "RifStimPlanXmlReader.h" #include "RigFractureGrid.h" #include "RigStimPlanFractureDefinition.h" #include "RigTransmissibilityEquations.h" #include "RigWellPathStimplanIntersector.h" #include "RigFractureCell.h" #include "RimEclipseView.h" #include "RimFracture.h" #include "RimFractureContainment.h" #include "RimProject.h" #include "RimStimPlanColors.h" #include "RimStimPlanLegendConfig.h" #include "RimTools.h" #include "RivWellFracturePartMgr.h" #include "cafPdmObject.h" #include "cafPdmUiDoubleSliderEditor.h" #include "cafPdmUiFilePathEditor.h" #include "cvfMath.h" #include "cvfVector3.h" #include #include #include #include static std::vector EMPTY_DOUBLE_VECTOR; CAF_PDM_SOURCE_INIT( RimStimPlanFractureTemplate, "RimStimPlanFractureTemplate" ); //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RimStimPlanFractureTemplate::RimStimPlanFractureTemplate() { // clang-format off CAF_PDM_InitObject("Fracture Template", ":/FractureTemplate16x16.png", "", ""); CAF_PDM_InitFieldNoDefault(&m_stimPlanFileName, "StimPlanFileName", "File Name", "", "", ""); m_stimPlanFileName.uiCapability()->setUiEditorTypeName(caf::PdmUiFilePathEditor::uiEditorTypeName()); CAF_PDM_InitField(&m_wellPathDepthAtFracture, "WellPathDepthAtFracture", 0.0, "Well/Fracture Intersection Depth", "", "", ""); m_wellPathDepthAtFracture.uiCapability()->setUiEditorTypeName(caf::PdmUiDoubleSliderEditor::uiEditorTypeName()); CAF_PDM_InitField(&m_borderPolygonResultName, "BorderPolygonResultName", QString(""), "Parameter", "", "", ""); m_borderPolygonResultName.uiCapability()->setUiHidden(true); CAF_PDM_InitField(&m_activeTimeStepIndex, "ActiveTimeStepIndex", 0, "Active TimeStep Index", "", "", ""); CAF_PDM_InitField(&m_conductivityResultNameOnFile, "ConductivityResultName", QString(""), "Active Conductivity Result Name", "", "", ""); CAF_PDM_InitField(&m_showStimPlanMesh_OBSOLETE, "ShowStimPlanMesh", true, "", "", "", ""); m_showStimPlanMesh_OBSOLETE.uiCapability()->setUiHidden(true); m_fractureGrid = new RigFractureGrid(); m_readError = false; // clang-format on setDeletable( true ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RimStimPlanFractureTemplate::~RimStimPlanFractureTemplate() { } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- int RimStimPlanFractureTemplate::activeTimeStepIndex() { return m_activeTimeStepIndex; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimStimPlanFractureTemplate::fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue ) { RimFractureTemplate::fieldChangedByUi( changedField, oldValue, newValue ); if ( &m_stimPlanFileName == changedField ) { m_readError = false; loadDataAndUpdate(); setDefaultsBasedOnXMLfile(); } if ( &m_activeTimeStepIndex == changedField ) { // Changes to this parameters should change all fractures with this fracture template attached. RimProject* proj; this->firstAncestorOrThisOfType( proj ); if ( proj ) { std::vector fractures; proj->descendantsIncludingThisOfType( fractures ); for ( RimFracture* fracture : fractures ) { if ( fracture->fractureTemplate() == this ) { fracture->setStimPlanTimeIndexToPlot( m_activeTimeStepIndex ); } } proj->scheduleCreateDisplayModelAndRedrawAllViews(); } } if ( &m_wellPathDepthAtFracture == changedField || &m_borderPolygonResultName == changedField || &m_activeTimeStepIndex == changedField || &m_stimPlanFileName == changedField || &m_conductivityResultNameOnFile == changedField ) { updateFractureGrid(); RimProject* proj; this->firstAncestorOrThisOfType( proj ); if ( proj ) { proj->scheduleCreateDisplayModelAndRedrawAllViews(); } } if ( changedField == &m_scaleApplyButton ) { m_scaleApplyButton = false; onLoadDataAndUpdateGeometryHasChanged(); } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimStimPlanFractureTemplate::setFileName( const QString& fileName ) { m_stimPlanFileName = fileName; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- QString RimStimPlanFractureTemplate::fileName() { return m_stimPlanFileName().path(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimStimPlanFractureTemplate::updateFilePathsFromProjectPath( const QString& newProjectPath, const QString& oldProjectPath ) { // m_stimPlanFileName = RimTools::relocateFile( m_stimPlanFileName(), newProjectPath, oldProjectPath, nullptr, // nullptr ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimStimPlanFractureTemplate::setDefaultsBasedOnXMLfile() { if ( m_stimPlanFractureDefinitionData.isNull() ) return; computeDepthOfWellPathAtFracture(); computePerforationLength(); RiaLogging::info( QString( "Setting well/fracture intersection depth at %1" ).arg( m_wellPathDepthAtFracture ) ); m_activeTimeStepIndex = static_cast( m_stimPlanFractureDefinitionData->totalNumberTimeSteps() - 1 ); bool polygonPropertySet = setBorderPolygonResultNameToDefault(); if ( polygonPropertySet ) RiaLogging::info( QString( "Calculating polygon outline based on %1 at timestep %2" ) .arg( m_borderPolygonResultName ) .arg( m_stimPlanFractureDefinitionData->timeSteps()[m_activeTimeStepIndex] ) ); else RiaLogging::info( QString( "Property for polygon calculation not set." ) ); if ( !m_stimPlanFractureDefinitionData->conductivityResultNames().isEmpty() ) { m_conductivityResultNameOnFile = m_stimPlanFractureDefinitionData->conductivityResultNames().front(); } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- bool RimStimPlanFractureTemplate::setBorderPolygonResultNameToDefault() { // first option: Width for ( std::pair property : uiResultNamesWithUnit() ) { if ( property.first == "WIDTH" ) { m_borderPolygonResultName = property.first; return true; } } // if width not found, use conductivity if ( hasConductivity() ) { m_borderPolygonResultName = m_stimPlanFractureDefinitionData->conductivityResultNames().first(); return true; } // else: Set to first property if ( !uiResultNamesWithUnit().empty() ) { m_borderPolygonResultName = uiResultNamesWithUnit()[0].first; return true; } return false; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimStimPlanFractureTemplate::loadDataAndUpdate() { QString errorMessage; if ( m_readError ) return; m_stimPlanFractureDefinitionData = RifStimPlanXmlReader::readStimPlanXMLFile( m_stimPlanFileName().path(), m_conductivityScaleFactor(), m_halfLengthScaleFactor(), m_heightScaleFactor(), -m_wellPathDepthAtFracture(), RifStimPlanXmlReader::MIRROR_AUTO, fractureTemplateUnit(), &errorMessage ); if ( errorMessage.size() > 0 ) RiaLogging::error( errorMessage ); if ( m_stimPlanFractureDefinitionData.notNull() ) { setDefaultConductivityResultIfEmpty(); if ( fractureTemplateUnit() == RiaEclipseUnitTools::UnitSystem::UNITS_UNKNOWN ) { setUnitSystem( m_stimPlanFractureDefinitionData->unitSet() ); } m_readError = false; } else { setUnitSystem( RiaEclipseUnitTools::UnitSystem::UNITS_UNKNOWN ); m_readError = true; } updateFractureGrid(); for ( RimFracture* fracture : fracturesUsingThisTemplate() ) { fracture->clearCachedNonDarcyProperties(); } if ( widthResultValues().empty() ) { m_fractureWidthType = USER_DEFINED_WIDTH; } // Todo: Must update all views using this fracture template RimEclipseView* activeView = dynamic_cast( RiaApplication::instance()->activeReservoirView() ); if ( activeView ) activeView->fractureColors()->loadDataAndUpdate(); updateConnectedEditors(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- QList RimStimPlanFractureTemplate::calculateValueOptions( const caf::PdmFieldHandle* fieldNeedingOptions, bool* useOptionsOnly ) { QList options; if ( fieldNeedingOptions == &m_fractureWidthType ) { options.push_back( caf::PdmOptionItemInfo( caf::AppEnum::uiText( USER_DEFINED_WIDTH ), USER_DEFINED_WIDTH ) ); if ( !widthResultValues().empty() ) { options.push_back( caf::PdmOptionItemInfo( caf::AppEnum::uiText( WIDTH_FROM_FRACTURE ), WIDTH_FROM_FRACTURE ) ); } } if ( fieldNeedingOptions == &m_betaFactorType ) { options.push_back( caf::PdmOptionItemInfo( caf::AppEnum::uiText( USER_DEFINED_BETA_FACTOR ), USER_DEFINED_BETA_FACTOR ) ); if ( isBetaFactorAvailableOnFile() ) { options.push_back( caf::PdmOptionItemInfo( caf::AppEnum::uiText( BETA_FACTOR_FROM_FRACTURE ), BETA_FACTOR_FROM_FRACTURE ) ); } } if ( fieldNeedingOptions == &m_borderPolygonResultName ) { for ( std::pair nameUnit : uiResultNamesWithUnit() ) { options.push_back( caf::PdmOptionItemInfo( nameUnit.first, nameUnit.first ) ); } } else if ( fieldNeedingOptions == &m_activeTimeStepIndex ) { std::vector timeValues = timeSteps(); int index = 0; for ( double value : timeValues ) { options.push_back( caf::PdmOptionItemInfo( QString::number( value ), index ) ); index++; } } else if ( fieldNeedingOptions == &m_conductivityResultNameOnFile ) { if ( m_stimPlanFractureDefinitionData.notNull() ) { QStringList conductivityResultNames = m_stimPlanFractureDefinitionData->conductivityResultNames(); for ( const auto& resultName : conductivityResultNames ) { options.push_back( caf::PdmOptionItemInfo( resultName, resultName ) ); } } } return options; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimStimPlanFractureTemplate::computeDepthOfWellPathAtFracture() { if ( !m_stimPlanFractureDefinitionData.isNull() ) { double firstTvd = m_stimPlanFractureDefinitionData->topPerfTvd(); double lastTvd = m_stimPlanFractureDefinitionData->bottomPerfTvd(); if ( firstTvd != HUGE_VAL && lastTvd != HUGE_VAL ) { m_wellPathDepthAtFracture = ( firstTvd + lastTvd ) / 2; } else { firstTvd = m_stimPlanFractureDefinitionData->minDepth(); lastTvd = m_stimPlanFractureDefinitionData->maxDepth(); m_wellPathDepthAtFracture = ( firstTvd + lastTvd ) / 2; } } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimStimPlanFractureTemplate::computePerforationLength() { if ( !m_stimPlanFractureDefinitionData.isNull() ) { double firstTvd = m_stimPlanFractureDefinitionData->topPerfTvd(); double lastTvd = m_stimPlanFractureDefinitionData->bottomPerfTvd(); if ( firstTvd != HUGE_VAL && lastTvd != HUGE_VAL ) { m_perforationLength = cvf::Math::abs( firstTvd - lastTvd ); } } if ( fractureTemplateUnit() == RiaEclipseUnitTools::UnitSystem::UNITS_METRIC && m_perforationLength < 10 ) { m_perforationLength = 10; } else if ( fractureTemplateUnit() == RiaEclipseUnitTools::UnitSystem::UNITS_FIELD && m_perforationLength < RiaEclipseUnitTools::meterToFeet( 10 ) ) { m_perforationLength = std::round( RiaEclipseUnitTools::meterToFeet( 10 ) ); } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- std::vector RimStimPlanFractureTemplate::fractureGridResultsForUnitSystem( const QString& resultName, const QString& unitName, size_t timeStepIndex, RiaEclipseUnitTools::UnitSystem requiredUnitSystem ) const { auto resultValues = m_stimPlanFractureDefinitionData->fractureGridResults( resultName, unitName, m_activeTimeStepIndex ); if ( fractureTemplateUnit() == RiaEclipseUnitTools::UnitSystem::UNITS_METRIC ) { for ( auto& v : resultValues ) { v = RiaEclipseUnitTools::convertToMeter( v, unitName ); } } else if ( fractureTemplateUnit() == RiaEclipseUnitTools::UnitSystem::UNITS_FIELD ) { for ( auto& v : resultValues ) { v = RiaEclipseUnitTools::convertToFeet( v, unitName ); } } return resultValues; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- WellFractureIntersectionData RimStimPlanFractureTemplate::wellFractureIntersectionData( const RimFracture* fractureInstance ) const { WellFractureIntersectionData values; if ( m_fractureGrid.notNull() ) { if ( orientationType() == ALONG_WELL_PATH ) { CVF_ASSERT( fractureInstance ); RimWellPath* rimWellPath = nullptr; fractureInstance->firstAncestorOrThisOfType( rimWellPath ); if ( rimWellPath && rimWellPath->wellPathGeometry() ) { double totalLength = 0.0; double weightedConductivity = 0.0; double weightedWidth = 0.0; double weightedBetaFactorOnFile = 0.0; { std::vector widthResultValues; { auto nameUnit = widthParameterNameAndUnit(); widthResultValues = fractureGridResultsForUnitSystem( nameUnit.first, nameUnit.second, m_activeTimeStepIndex, fractureTemplateUnit() ); } std::vector conductivityResultValues; { auto nameUnit = conductivityParameterNameAndUnit(); conductivityResultValues = fractureGridResultsForUnitSystem( nameUnit.first, nameUnit.second, m_activeTimeStepIndex, fractureTemplateUnit() ); } std::vector betaFactorResultValues; { auto nameUnit = betaFactorParameterNameAndUnit(); betaFactorResultValues = m_stimPlanFractureDefinitionData->fractureGridResults( nameUnit.first, nameUnit.second, m_activeTimeStepIndex ); } RiaWeightedMeanCalculator widthCalc; RiaWeightedMeanCalculator conductivityCalc; RiaWeightedGeometricMeanCalculator betaFactorCalc; RigWellPathStimplanIntersector intersector( rimWellPath->wellPathGeometry(), fractureInstance ); for ( const auto& v : intersector.intersections() ) { size_t fractureGlobalCellIndex = v.first; double intersectionLength = v.second.computeLength(); if ( fractureGlobalCellIndex < widthResultValues.size() ) { widthCalc.addValueAndWeight( widthResultValues[fractureGlobalCellIndex], intersectionLength ); } if ( fractureGlobalCellIndex < conductivityResultValues.size() ) { conductivityCalc.addValueAndWeight( conductivityResultValues[fractureGlobalCellIndex], intersectionLength ); } if ( fractureGlobalCellIndex < betaFactorResultValues.size() ) { double nativeBetaFactor = betaFactorResultValues[fractureGlobalCellIndex]; // Guard against zero beta values, as these values will set the geometric mean to zero // Consider using the conductivity threshold instead of a local beta threshold const double threshold = 1e-6; if ( fabs( nativeBetaFactor ) > threshold ) { betaFactorCalc.addValueAndWeight( nativeBetaFactor, intersectionLength ); } } } if ( conductivityCalc.validAggregatedWeight() ) { weightedConductivity = conductivityCalc.weightedMean(); } if ( widthCalc.validAggregatedWeight() ) { weightedWidth = widthCalc.weightedMean(); totalLength = widthCalc.aggregatedWeight(); } if ( betaFactorCalc.validAggregatedWeight() ) { weightedBetaFactorOnFile = betaFactorCalc.weightedMean(); } } if ( totalLength > 1e-7 ) { values.m_width = weightedWidth; values.m_conductivity = weightedConductivity; double conversionFactorForBeta = conversionFactorForBetaValues(); double betaFactorForcheimer = weightedBetaFactorOnFile / conversionFactorForBeta; values.m_betaFactorInForcheimerUnits = betaFactorForcheimer; } values.m_permeability = RigTransmissibilityEquations::permeability( weightedConductivity, weightedWidth ); } } else { std::pair wellCellIJ = m_fractureGrid->fractureCellAtWellCenter(); size_t wellCellIndex = m_fractureGrid->getGlobalIndexFromIJ( wellCellIJ.first, wellCellIJ.second ); const RigFractureCell& wellCell = m_fractureGrid->cellFromIndex( wellCellIndex ); double conductivity = wellCell.getConductivityValue(); values.m_conductivity = conductivity; { auto nameUnit = widthParameterNameAndUnit(); if ( !nameUnit.first.isEmpty() ) { double widthInRequiredUnit = HUGE_VAL; { auto resultValues = fractureGridResultsForUnitSystem( nameUnit.first, nameUnit.second, m_activeTimeStepIndex, fractureTemplateUnit() ); if ( wellCellIndex < resultValues.size() ) { widthInRequiredUnit = resultValues[wellCellIndex]; } } if ( widthInRequiredUnit != HUGE_VAL && fabs( widthInRequiredUnit ) > 1e-20 ) { values.m_width = widthInRequiredUnit; values.m_permeability = RigTransmissibilityEquations::permeability( conductivity, widthInRequiredUnit ); } } } { auto nameUnit = betaFactorParameterNameAndUnit(); std::vector betaFactorResultValues = m_stimPlanFractureDefinitionData->fractureGridResults( nameUnit.first, nameUnit.second, m_activeTimeStepIndex ); if ( wellCellIndex < betaFactorResultValues.size() ) { double nativeBetaValue = betaFactorResultValues[wellCellIndex]; double conversionFactorForBeta = conversionFactorForBetaValues(); double betaFactorForcheimer = nativeBetaValue / conversionFactorForBeta; values.m_betaFactorInForcheimerUnits = betaFactorForcheimer; } } } } return values; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- std::pair RimStimPlanFractureTemplate::widthParameterNameAndUnit() const { if ( m_stimPlanFractureDefinitionData.notNull() ) { std::vector> propertyNamesUnitsOnFile = m_stimPlanFractureDefinitionData->getStimPlanPropertyNamesUnits(); for ( const auto& nameUnit : propertyNamesUnitsOnFile ) { if ( nameUnit.first.contains( "effective width", Qt::CaseInsensitive ) ) { return nameUnit; } if ( nameUnit.first.contains( "width", Qt::CaseInsensitive ) ) { return nameUnit; } } } return std::pair(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- std::pair RimStimPlanFractureTemplate::conductivityParameterNameAndUnit() const { if ( m_stimPlanFractureDefinitionData.notNull() ) { std::vector> propertyNamesUnitsOnFile = m_stimPlanFractureDefinitionData->getStimPlanPropertyNamesUnits(); for ( const auto& nameUnit : propertyNamesUnitsOnFile ) { if ( nameUnit.first.contains( m_conductivityResultNameOnFile, Qt::CaseInsensitive ) ) { return nameUnit; } } } return std::pair(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- std::pair RimStimPlanFractureTemplate::betaFactorParameterNameAndUnit() const { if ( m_stimPlanFractureDefinitionData.notNull() ) { std::vector> propertyNamesUnitsOnFile = m_stimPlanFractureDefinitionData->getStimPlanPropertyNamesUnits(); for ( const auto& nameUnit : propertyNamesUnitsOnFile ) { if ( nameUnit.first.contains( "beta", Qt::CaseInsensitive ) ) { return nameUnit; } } } return std::pair(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- bool RimStimPlanFractureTemplate::isBetaFactorAvailableOnFile() const { auto nameAndUnit = betaFactorParameterNameAndUnit(); return !nameAndUnit.first.isEmpty(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- double RimStimPlanFractureTemplate::conversionFactorForBetaValues() const { auto nameUnit = betaFactorParameterNameAndUnit(); double conversionFactorForBeta = 1.0; QString trimmedUnit = nameUnit.second.trimmed().toLower(); if ( trimmedUnit == "/m" ) { conversionFactorForBeta = 1.01325E+08; } else if ( trimmedUnit == "/cm" ) { conversionFactorForBeta = 1.01325E+06; } else if ( trimmedUnit == "/ft" ) { conversionFactorForBeta = 3.088386E+07; } return conversionFactorForBeta; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimStimPlanFractureTemplate::setDefaultConductivityResultIfEmpty() { if ( m_conductivityResultNameOnFile().isEmpty() ) { if ( !m_stimPlanFractureDefinitionData->conductivityResultNames().isEmpty() ) { m_conductivityResultNameOnFile = m_stimPlanFractureDefinitionData->conductivityResultNames().front(); } } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- QString RimStimPlanFractureTemplate::mapUiResultNameToFileResultName( const QString& uiResultName ) const { QString fileResultName; if ( uiResultName == RiaDefines::conductivityResultName() ) { fileResultName = m_conductivityResultNameOnFile(); } else { fileResultName = uiResultName; } return fileResultName; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- bool RimStimPlanFractureTemplate::showStimPlanMesh() const { return m_showStimPlanMesh_OBSOLETE(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimStimPlanFractureTemplate::convertToUnitSystem( RiaEclipseUnitTools::UnitSystem neededUnit ) { if ( m_fractureTemplateUnit() == neededUnit ) return; setUnitSystem( neededUnit ); RimFractureTemplate::convertToUnitSystem( neededUnit ); m_readError = false; loadDataAndUpdate(); if ( m_stimPlanFractureDefinitionData.isNull() ) return; if ( neededUnit == RiaEclipseUnitTools::UnitSystem::UNITS_FIELD ) { m_wellPathDepthAtFracture = RiaEclipseUnitTools::meterToFeet( m_wellPathDepthAtFracture ); } else if ( neededUnit == RiaEclipseUnitTools::UnitSystem::UNITS_METRIC ) { m_wellPathDepthAtFracture = RiaEclipseUnitTools::feetToMeter( m_wellPathDepthAtFracture ); } m_activeTimeStepIndex = static_cast( m_stimPlanFractureDefinitionData->totalNumberTimeSteps() - 1 ); bool polygonPropertySet = setBorderPolygonResultNameToDefault(); if ( polygonPropertySet ) RiaLogging::info( QString( "Calculating polygon outline based on %1 at timestep %2" ) .arg( m_borderPolygonResultName ) .arg( m_stimPlanFractureDefinitionData->timeSteps()[m_activeTimeStepIndex] ) ); else RiaLogging::info( QString( "Property for polygon calculation not set." ) ); if ( !m_stimPlanFractureDefinitionData->conductivityResultNames().isEmpty() ) { m_conductivityResultNameOnFile = m_stimPlanFractureDefinitionData->conductivityResultNames().front(); } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimStimPlanFractureTemplate::onLoadDataAndUpdateGeometryHasChanged() { loadDataAndUpdate(); RimProject* proj; this->firstAncestorOrThisOfType( proj ); if ( proj ) { proj->scheduleCreateDisplayModelAndRedrawAllViews(); RiaCompletionTypeCalculationScheduler::instance()->scheduleRecalculateCompletionTypeAndRedrawAllViews(); } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- std::vector RimStimPlanFractureTemplate::timeSteps() { if ( m_stimPlanFractureDefinitionData.notNull() ) { return m_stimPlanFractureDefinitionData->timeSteps(); } return std::vector(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- std::vector> RimStimPlanFractureTemplate::uiResultNamesWithUnit() const { std::vector> propertyNamesAndUnits; if ( m_stimPlanFractureDefinitionData.notNull() ) { QString conductivityUnit = "mD/s"; std::vector> tmp; std::vector> propertyNamesUnitsOnFile = m_stimPlanFractureDefinitionData->getStimPlanPropertyNamesUnits(); for ( const auto& nameUnitPair : propertyNamesUnitsOnFile ) { if ( nameUnitPair.first.contains( RiaDefines::conductivityResultName(), Qt::CaseInsensitive ) ) { conductivityUnit = nameUnitPair.second; } else { tmp.push_back( nameUnitPair ); } } propertyNamesAndUnits.push_back( std::make_pair( RiaDefines::conductivityResultName(), conductivityUnit ) ); for ( const auto& nameUnitPair : tmp ) { propertyNamesAndUnits.push_back( nameUnitPair ); } } return propertyNamesAndUnits; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- std::vector> RimStimPlanFractureTemplate::resultValues( const QString& uiResultName, const QString& unitName, size_t timeStepIndex ) const { if ( m_stimPlanFractureDefinitionData.notNull() ) { QString fileResultName = mapUiResultNameToFileResultName( uiResultName ); return m_stimPlanFractureDefinitionData->getDataAtTimeIndex( fileResultName, unitName, timeStepIndex ); } return std::vector>(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- std::vector RimStimPlanFractureTemplate::fractureGridResults( const QString& uiResultName, const QString& unitName, size_t timeStepIndex ) const { if ( m_stimPlanFractureDefinitionData.notNull() ) { QString fileResultName = mapUiResultNameToFileResultName( uiResultName ); return m_stimPlanFractureDefinitionData->fractureGridResults( fileResultName, unitName, timeStepIndex ); } return std::vector(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- bool RimStimPlanFractureTemplate::hasConductivity() const { if ( m_stimPlanFractureDefinitionData.notNull() && !m_stimPlanFractureDefinitionData->conductivityResultNames().isEmpty() ) { return true; } return false; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- double RimStimPlanFractureTemplate::resultValueAtIJ( const QString& uiResultName, const QString& unitName, size_t timeStepIndex, size_t i, size_t j ) { auto values = resultValues( uiResultName, unitName, timeStepIndex ); if ( values.empty() ) return HUGE_VAL; size_t adjustedI = i + 1; size_t adjustedJ = j + 1; if ( adjustedI >= fractureGrid()->iCellCount() || adjustedJ >= fractureGrid()->jCellCount() ) { return HUGE_VAL; } return values[adjustedJ][adjustedI]; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- std::vector RimStimPlanFractureTemplate::widthResultValues() const { std::vector resultValues; auto nameUnit = widthParameterNameAndUnit(); if ( !nameUnit.first.isEmpty() ) { resultValues = fractureGridResultsForUnitSystem( nameUnit.first, nameUnit.second, m_activeTimeStepIndex, fractureTemplateUnit() ); } return resultValues; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimStimPlanFractureTemplate::appendDataToResultStatistics( const QString& uiResultName, const QString& unit, MinMaxAccumulator& minMaxAccumulator, PosNegAccumulator& posNegAccumulator ) const { if ( m_stimPlanFractureDefinitionData.notNull() ) { QString fileResultName = mapUiResultNameToFileResultName( uiResultName ); m_stimPlanFractureDefinitionData->appendDataToResultStatistics( fileResultName, unit, minMaxAccumulator, posNegAccumulator ); } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- const RigFractureGrid* RimStimPlanFractureTemplate::fractureGrid() const { return m_fractureGrid.p(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimStimPlanFractureTemplate::updateFractureGrid() { m_fractureGrid = nullptr; if ( m_stimPlanFractureDefinitionData.notNull() ) { m_fractureGrid = m_stimPlanFractureDefinitionData->createFractureGrid( m_conductivityResultNameOnFile, m_activeTimeStepIndex, m_wellPathDepthAtFracture, m_fractureTemplateUnit() ); } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimStimPlanFractureTemplate::fractureTriangleGeometry( std::vector* nodeCoords, std::vector* triangleIndices ) const { if ( m_stimPlanFractureDefinitionData.notNull() ) { m_stimPlanFractureDefinitionData->createFractureTriangleGeometry( m_wellPathDepthAtFracture, name(), nodeCoords, triangleIndices ); } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimStimPlanFractureTemplate::defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) { uiOrdering.add( &m_name ); uiOrdering.add( &m_id ); { caf::PdmUiGroup* group = uiOrdering.addNewGroup( "Input" ); group->add( &m_stimPlanFileName ); group->add( &m_activeTimeStepIndex ); group->add( &m_wellPathDepthAtFracture ); } { caf::PdmUiGroup* group = uiOrdering.addNewGroup( "Geometry" ); group->add( &m_orientationType ); group->add( &m_azimuthAngle ); } { caf::PdmUiGroup* group = uiOrdering.addNewGroup( "Fracture Truncation" ); group->setCollapsedByDefault( true ); m_fractureContainment()->uiOrdering( uiConfigName, *group ); } { caf::PdmUiGroup* group = uiOrdering.addNewGroup( "Properties" ); group->add( &m_conductivityResultNameOnFile ); group->add( &m_conductivityType ); group->add( &m_skinFactor ); group->add( &m_perforationLength ); group->add( &m_perforationEfficiency ); group->add( &m_wellDiameter ); } if ( widthResultValues().empty() ) { m_fractureWidthType = USER_DEFINED_WIDTH; } RimFractureTemplate::defineUiOrdering( uiConfigName, uiOrdering ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimStimPlanFractureTemplate::defineEditorAttribute( const caf::PdmFieldHandle* field, QString uiConfigName, caf::PdmUiEditorAttribute* attribute ) { RimFractureTemplate::defineEditorAttribute( field, uiConfigName, attribute ); if ( field == &m_stimPlanFileName ) { caf::PdmUiFilePathEditorAttribute* myAttr = dynamic_cast( attribute ); if ( myAttr ) { myAttr->m_fileSelectionFilter = "StimPlan Xml Files(*.xml);;All Files (*.*)"; } } if ( field == &m_wellPathDepthAtFracture ) { if ( !m_stimPlanFractureDefinitionData.isNull() && ( m_stimPlanFractureDefinitionData->yCount() > 0 ) ) { caf::PdmUiDoubleSliderEditorAttribute* myAttr = dynamic_cast( attribute ); if ( myAttr ) { myAttr->m_minimum = m_stimPlanFractureDefinitionData->minDepth(); myAttr->m_maximum = m_stimPlanFractureDefinitionData->maxDepth(); } } } }