From e96cc60ee7ea689815d1b000cfa214f1c71c35ee Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Mon, 24 Sep 2018 15:10:46 +0200 Subject: [PATCH] #3224 Non-Darcy longitudinal : Use geometric mean for B-factor --- .../RimEllipseFractureTemplate.cpp | 6 +- .../Completions/RimEllipseFractureTemplate.h | 2 +- .../Completions/RimFracture.cpp | 1 + .../Completions/RimFracture.h | 2 + .../Completions/RimFractureTemplate.cpp | 89 ++++++++++++++++--- .../Completions/RimFractureTemplate.h | 27 ++++-- .../RimStimPlanFractureTemplate.cpp | 84 +++++++++++++++-- .../Completions/RimStimPlanFractureTemplate.h | 4 +- 8 files changed, 182 insertions(+), 33 deletions(-) diff --git a/ApplicationCode/ProjectDataModel/Completions/RimEllipseFractureTemplate.cpp b/ApplicationCode/ProjectDataModel/Completions/RimEllipseFractureTemplate.cpp index 4adc06552e..00f4568938 100644 --- a/ApplicationCode/ProjectDataModel/Completions/RimEllipseFractureTemplate.cpp +++ b/ApplicationCode/ProjectDataModel/Completions/RimEllipseFractureTemplate.cpp @@ -228,10 +228,10 @@ void RimEllipseFractureTemplate::createFractureGridAndAssignConductivities() //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -FractureWidthAndConductivity - RimEllipseFractureTemplate::widthAndConductivityAtWellPathIntersection(const RimFracture* fractureInstance) const +WellFractureIntersectionData + RimEllipseFractureTemplate::wellFractureIntersectionData(const RimFracture* fractureInstance) const { - FractureWidthAndConductivity values; + WellFractureIntersectionData values; values.m_width = m_width; values.m_permeability = m_permeability; diff --git a/ApplicationCode/ProjectDataModel/Completions/RimEllipseFractureTemplate.h b/ApplicationCode/ProjectDataModel/Completions/RimEllipseFractureTemplate.h index eebeb10d44..ac5b1b1d30 100644 --- a/ApplicationCode/ProjectDataModel/Completions/RimEllipseFractureTemplate.h +++ b/ApplicationCode/ProjectDataModel/Completions/RimEllipseFractureTemplate.h @@ -76,7 +76,7 @@ private: void createFractureGridAndAssignConductivities(); std::vector fractureBorderPolygon() const; - FractureWidthAndConductivity widthAndConductivityAtWellPathIntersection(const RimFracture* fractureInstance) const override; + WellFractureIntersectionData wellFractureIntersectionData(const RimFracture* fractureInstance) const override; private: cvf::ref m_fractureGrid; diff --git a/ApplicationCode/ProjectDataModel/Completions/RimFracture.cpp b/ApplicationCode/ProjectDataModel/Completions/RimFracture.cpp index 01ef3b8da0..034b9eb98e 100644 --- a/ApplicationCode/ProjectDataModel/Completions/RimFracture.cpp +++ b/ApplicationCode/ProjectDataModel/Completions/RimFracture.cpp @@ -269,6 +269,7 @@ void RimFracture::ensureValidNonDarcyProperties() props.dFactor = m_fractureTemplate->computeDFactor(this); props.effectivePermeability = m_fractureTemplate->computeEffectivePermeability(this); props.eqWellRadius = m_fractureTemplate->computeWellRadiusForDFactorCalculation(this); + props.betaFactor = m_fractureTemplate->getOrComputeBetaFactor(this); props.isDataDirty = false; } diff --git a/ApplicationCode/ProjectDataModel/Completions/RimFracture.h b/ApplicationCode/ProjectDataModel/Completions/RimFracture.h index fa98379d45..99562c8eeb 100644 --- a/ApplicationCode/ProjectDataModel/Completions/RimFracture.h +++ b/ApplicationCode/ProjectDataModel/Completions/RimFracture.h @@ -50,6 +50,7 @@ public: , effectivePermeability(std::numeric_limits::infinity()) , dFactor(std::numeric_limits::infinity()) , eqWellRadius(std::numeric_limits::infinity()) + , betaFactor(std::numeric_limits::infinity()) , isDataDirty(true) { } @@ -64,6 +65,7 @@ public: double conductivity; double effectivePermeability; double dFactor; + double betaFactor; bool isDataDirty; }; diff --git a/ApplicationCode/ProjectDataModel/Completions/RimFractureTemplate.cpp b/ApplicationCode/ProjectDataModel/Completions/RimFractureTemplate.cpp index ab971e744c..aef0afb088 100644 --- a/ApplicationCode/ProjectDataModel/Completions/RimFractureTemplate.cpp +++ b/ApplicationCode/ProjectDataModel/Completions/RimFractureTemplate.cpp @@ -85,6 +85,16 @@ namespace caf setDefault(RimFractureTemplate::NON_DARCY_NONE); } + + template<> + void caf::AppEnum< RimFractureTemplate::BetaFactorEnum>::setUp() + { + addItem(RimFractureTemplate::USER_DEFINED_BETA_FACTOR, "UserDefinedBetaFactor", "User Defined"); + addItem(RimFractureTemplate::BETA_FACTOR_FROM_FRACTURE, "FractureBetaFactor", "Use Fracture Beta Factor"); + + setDefault(RimFractureTemplate::USER_DEFINED_BETA_FACTOR); + } + } // TODO Move to cafPdmObject.h @@ -138,6 +148,7 @@ RimFractureTemplate::RimFractureTemplate() CAF_PDM_InitFieldNoDefault(&m_fractureWidthType, "FractureWidthType", "Type", "", "", ""); CAF_PDM_InitField_Basic(&m_fractureWidth, "FractureWidth", 0.01, "Fracture Width (h)"); + CAF_PDM_InitFieldNoDefault(&m_betaFactorType, "BetaFactorType", "Type", "", "", ""); CAF_PDM_InitField_Basic(&m_inertialCoefficient, "InertialCoefficient", 0.006083236, "Inertial Coefficient (β) [Forch. unit]"); CAF_PDM_InitFieldNoDefault(&m_permeabilityType, "PermeabilityType", "Type", "", "", ""); @@ -336,7 +347,11 @@ void RimFractureTemplate::defineUiOrdering(QString uiConfigName, caf::PdmUiOrder if (m_nonDarcyFlowType == RimFractureTemplate::NON_DARCY_COMPUTED) { - nonDarcyFlowGroup->add(&m_inertialCoefficient); + { + auto group = nonDarcyFlowGroup->addNewGroup("Inertial Coefficient(β-factor)"); + group->add(&m_betaFactorType); + group->add(&m_inertialCoefficient); + } { auto group = nonDarcyFlowGroup->addNewGroup("Effective Permeability"); @@ -424,6 +439,18 @@ QList RimFractureTemplate::calculateValueOptions(const c 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)); + } + } + return options; } @@ -477,13 +504,24 @@ void RimFractureTemplate::prepareFieldsForUiDisplay() // Non Darcy Flow - if (m_fractureWidthType == RimFractureTemplate::USER_DEFINED_WIDTH) { - m_fractureWidth.uiCapability()->setUiReadOnly(false); - } - else - { - m_fractureWidth.uiCapability()->setUiReadOnly(true); + if (m_fractureWidthType == RimFractureTemplate::USER_DEFINED_WIDTH) + { + m_fractureWidth.uiCapability()->setUiReadOnly(false); + } + else + { + m_fractureWidth.uiCapability()->setUiReadOnly(true); + } + + if (m_betaFactorType == RimFractureTemplate::USER_DEFINED_BETA_FACTOR) + { + m_inertialCoefficient.uiCapability()->setUiReadOnly(false); + } + else + { + m_inertialCoefficient.uiCapability()->setUiReadOnly(true); + } } if (m_permeabilityType == RimFractureTemplate::USER_DEFINED_PERMEABILITY) @@ -545,7 +583,7 @@ QString RimFractureTemplate::dFactorSummary() const auto alpha = RiaDefines::nonDarcyFlowAlpha(m_fractureTemplateUnit()); text += indentedText(QString("α : %1").arg(alpha)); - auto beta = m_inertialCoefficient; + auto beta = getOrComputeBetaFactor(f); text += indentedText(QString("β : %1").arg(beta)); double effPerm = f->nonDarcyProperties().effectivePermeability; @@ -596,7 +634,7 @@ double RimFractureTemplate::computeEffectivePermeability(const RimFracture* frac else { double fracPermeability = 0.0; - auto values = widthAndConductivityAtWellPathIntersection(fractureInstance); + auto values = wellFractureIntersectionData(fractureInstance); if (values.isWidthAndPermeabilityDefined()) { fracPermeability = values.m_permeability; @@ -606,7 +644,7 @@ double RimFractureTemplate::computeEffectivePermeability(const RimFracture* frac auto conductivity = values.m_conductivity; auto width = computeFractureWidth(fractureInstance); - if (fabs(width) < 1e-10) return HUGE_VAL; + if (fabs(width) < 1e-10) return std::numeric_limits::infinity(); fracPermeability = conductivity / width; } @@ -651,7 +689,7 @@ double RimFractureTemplate::computeDFactor(const RimFracture* fractureInstance) { double radius = computeWellRadiusForDFactorCalculation(fractureInstance); double alpha = RiaDefines::nonDarcyFlowAlpha(m_fractureTemplateUnit()); - double beta = m_inertialCoefficient; + double beta = getOrComputeBetaFactor(fractureInstance); double effPerm = computeEffectivePermeability(fractureInstance); double gamma = m_relativeGasDensity; @@ -661,7 +699,7 @@ double RimFractureTemplate::computeDFactor(const RimFracture* fractureInstance) double numerator = alpha * beta * effPerm * gamma; double denumerator = h * radius * mu; - if (denumerator < 1e-10) return HUGE_VAL; + if (denumerator < 1e-10) return std::numeric_limits::infinity(); d = numerator / denumerator; @@ -685,7 +723,7 @@ double RimFractureTemplate::computeKh(const RimFracture* fractureInstance) const // kh = permeability * h // conductivity = permeability * h - auto values = widthAndConductivityAtWellPathIntersection(fractureInstance); + auto values = wellFractureIntersectionData(fractureInstance); if (values.isConductivityDefined()) { // If conductivity is found in stim plan file, use this directly @@ -804,7 +842,7 @@ double RimFractureTemplate::computeFractureWidth(const RimFracture* fractureInst { if (m_fractureWidthType == RimFractureTemplate::WIDTH_FROM_FRACTURE) { - auto values = widthAndConductivityAtWellPathIntersection(fractureInstance); + auto values = wellFractureIntersectionData(fractureInstance); return values.m_width; } @@ -812,6 +850,21 @@ double RimFractureTemplate::computeFractureWidth(const RimFracture* fractureInst return m_fractureWidth; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +double RimFractureTemplate::getOrComputeBetaFactor(const RimFracture* fractureInstance) const +{ + if (m_betaFactorType == RimFractureTemplate::BETA_FACTOR_FROM_FRACTURE) + { + auto values = wellFractureIntersectionData(fractureInstance); + + return values.m_betaFactorInForcheimerUnits; + } + + return m_inertialCoefficient; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -831,6 +884,14 @@ std::vector RimFractureTemplate::fracturesUsingThisTemplate() cons return fractures; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimFractureTemplate::isBetaFactorAvailableOnFile() const +{ + return false; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ProjectDataModel/Completions/RimFractureTemplate.h b/ApplicationCode/ProjectDataModel/Completions/RimFractureTemplate.h index 13c806ef58..049bd38f5d 100644 --- a/ApplicationCode/ProjectDataModel/Completions/RimFractureTemplate.h +++ b/ApplicationCode/ProjectDataModel/Completions/RimFractureTemplate.h @@ -32,7 +32,7 @@ #include "cvfVector3.h" #include -#include +#include class RigFractureGrid; class RimFractureContainment; @@ -40,13 +40,14 @@ class MinMaxAccumulator; class PosNegAccumulator; class RimFracture; -class FractureWidthAndConductivity +class WellFractureIntersectionData { public: - FractureWidthAndConductivity() + WellFractureIntersectionData() : m_width(0.0) , m_permeability(0.0) - , m_conductivity(HUGE_VAL) + , m_conductivity(std::numeric_limits::infinity()) + , m_betaFactorInForcheimerUnits(std::numeric_limits::infinity()) { } @@ -60,7 +61,7 @@ public: bool isConductivityDefined() const { - return (m_conductivity != HUGE_VAL); + return (m_conductivity != std::numeric_limits::infinity()); } // Unit : meter or feet @@ -70,6 +71,9 @@ public: double m_permeability; double m_conductivity; + + // Unit : Forcheimer unit + double m_betaFactorInForcheimerUnits; }; //================================================================================================== @@ -106,6 +110,12 @@ public: WIDTH_FROM_FRACTURE, }; + enum BetaFactorEnum + { + USER_DEFINED_BETA_FACTOR, + BETA_FACTOR_FROM_FRACTURE, + }; + enum NonDarcyFlowEnum { NON_DARCY_NONE, @@ -165,6 +175,7 @@ public: double computeEffectivePermeability(const RimFracture* fractureInstance) const; double computeWellRadiusForDFactorCalculation(const RimFracture* fractureInstance) const; double computeFractureWidth(const RimFracture* fractureInstance) const; + double getOrComputeBetaFactor(const RimFracture* fractureInstance) const; void loadDataAndUpdateGeometryHasChanged(); @@ -177,10 +188,12 @@ protected: std::vector fracturesUsingThisTemplate() const; virtual void onLoadDataAndUpdateGeometryHasChanged() = 0; + + virtual bool isBetaFactorAvailableOnFile() const; private: void prepareFieldsForUiDisplay(); - virtual FractureWidthAndConductivity widthAndConductivityAtWellPathIntersection(const RimFracture* fractureInstance) const = 0; + virtual WellFractureIntersectionData wellFractureIntersectionData(const RimFracture* fractureInstance) const = 0; QString dFactorSummary() const; double dFactorForTemplate() const; @@ -205,6 +218,8 @@ protected: caf::PdmField> m_fractureWidthType; caf::PdmField m_fractureWidth; + + caf::PdmField> m_betaFactorType; caf::PdmField m_inertialCoefficient; caf::PdmField> m_permeabilityType; diff --git a/ApplicationCode/ProjectDataModel/Completions/RimStimPlanFractureTemplate.cpp b/ApplicationCode/ProjectDataModel/Completions/RimStimPlanFractureTemplate.cpp index fbc6fbfbed..4fbd1c4064 100644 --- a/ApplicationCode/ProjectDataModel/Completions/RimStimPlanFractureTemplate.cpp +++ b/ApplicationCode/ProjectDataModel/Completions/RimStimPlanFractureTemplate.cpp @@ -22,6 +22,7 @@ #include "RiaCompletionTypeCalculationScheduler.h" #include "RiaFractureDefines.h" #include "RiaLogging.h" +#include "RiaWeightedGeometricMeanCalculator.h" #include "RiaWeightedMeanCalculator.h" #include "RifStimPlanXmlReader.h" @@ -439,10 +440,9 @@ std::vector //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -FractureWidthAndConductivity - RimStimPlanFractureTemplate::widthAndConductivityAtWellPathIntersection(const RimFracture* fractureInstance) const +WellFractureIntersectionData RimStimPlanFractureTemplate::wellFractureIntersectionData(const RimFracture* fractureInstance) const { - FractureWidthAndConductivity values; + WellFractureIntersectionData values; if (m_fractureGrid.notNull()) { @@ -455,9 +455,11 @@ FractureWidthAndConductivity if (rimWellPath && rimWellPath->wellPathGeometry()) { - double totalLength = 0.0; - double weightedConductivity = 0.0; - double weightedWidth = 0.0; + double totalLength = 0.0; + double weightedConductivity = 0.0; + double weightedWidth = 0.0; + double weightedBetaFactorOnFile = 0.0; + double conversionFactorForBeta = 1.0; { std::vector widthResultValues; @@ -474,8 +476,30 @@ FractureWidthAndConductivity nameUnit.first, nameUnit.second, m_activeTimeStepIndex, fractureTemplateUnit()); } - RiaWeightedMeanCalculator widthCalc; - RiaWeightedMeanCalculator conductivityCalc; + std::vector betaFactorResultValues; + { + auto nameUnit = betaFactorParameterNameAndUnit(); + betaFactorResultValues = m_stimPlanFractureDefinitionData->fractureGridResults( + nameUnit.first, nameUnit.second, m_activeTimeStepIndex); + + 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; + } + } + + RiaWeightedMeanCalculator widthCalc; + RiaWeightedMeanCalculator conductivityCalc; + RiaWeightedGeometricMeanCalculator betaFactorCalc; RigWellPathStimplanIntersector intersector(rimWellPath->wellPathGeometry(), fractureInstance); for (const auto& v : intersector.intersections()) @@ -493,6 +517,11 @@ FractureWidthAndConductivity conductivityCalc.addValueAndWeight(conductivityResultValues[fractureGlobalCellIndex], intersectionLength); } + + if (fractureGlobalCellIndex < betaFactorResultValues.size()) + { + betaFactorCalc.addValueAndWeight(betaFactorResultValues[fractureGlobalCellIndex], intersectionLength); + } } if (conductivityCalc.validAggregatedWeight()) { @@ -503,12 +532,19 @@ FractureWidthAndConductivity 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 betaFactorForcheimer = weightedBetaFactorOnFile / conversionFactorForBeta; + values.m_betaFactorInForcheimerUnits = betaFactorForcheimer; } if (weightedWidth > 1e-7) @@ -601,6 +637,38 @@ std::pair RimStimPlanFractureTemplate::conductivityParameterNa 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(); +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ProjectDataModel/Completions/RimStimPlanFractureTemplate.h b/ApplicationCode/ProjectDataModel/Completions/RimStimPlanFractureTemplate.h index 8979d147d0..534d39ad6e 100644 --- a/ApplicationCode/ProjectDataModel/Completions/RimStimPlanFractureTemplate.h +++ b/ApplicationCode/ProjectDataModel/Completions/RimStimPlanFractureTemplate.h @@ -108,10 +108,12 @@ private: std::vector fractureGridResultsForUnitSystem(const QString& resultName, const QString& unitName, size_t timeStepIndex, RiaEclipseUnitTools::UnitSystem requiredUnitSystem) const; - virtual FractureWidthAndConductivity widthAndConductivityAtWellPathIntersection(const RimFracture* fractureInstance) const override; + virtual WellFractureIntersectionData wellFractureIntersectionData(const RimFracture* fractureInstance) const override; std::pair widthParameterNameAndUnit() const; std::pair conductivityParameterNameAndUnit() const; + std::pair betaFactorParameterNameAndUnit() const; + bool isBetaFactorAvailableOnFile() const override; private: caf::PdmField m_activeTimeStepIndex;