mirror of
https://github.com/OPM/ResInsight.git
synced 2025-02-25 18:55:39 -06:00
This commit is contained in:
parent
b4e2a58327
commit
4c84bbb8a3
@ -45,6 +45,7 @@
|
||||
#include "RimTools.h"
|
||||
#include "RimWellLogFile.h"
|
||||
#include "RimWellLogFileChannel.h"
|
||||
#include "RimWellLogExtractionCurve.h"
|
||||
#include "RimWellPath.h"
|
||||
|
||||
#include "cafUtils.h"
|
||||
@ -220,6 +221,9 @@ void Rim3dWellLogExtractionCurve::curveValuesAndMdsAtTimeStep(std::vector<double
|
||||
else if (geomExtractor.notNull())
|
||||
{
|
||||
*measuredDepthValues = geomExtractor->measuredDepth();
|
||||
|
||||
RimWellLogExtractionCurve::findAndLoadWbsParametersFromLasFiles(wellPath, geomExtractor.p());
|
||||
|
||||
m_geomResultDefinition->loadResult();
|
||||
geomExtractor->setRkbDiff(rkbDiff());
|
||||
geomExtractor->curveData(m_geomResultDefinition->resultAddress(), timeStep, values);
|
||||
|
@ -47,11 +47,14 @@
|
||||
#include "RimProject.h"
|
||||
#include "RimTools.h"
|
||||
#include "RimWellLogCurve.h"
|
||||
#include "RimWellLogFile.h"
|
||||
#include "RimWellLogFileChannel.h"
|
||||
#include "RimWellLogPlot.h"
|
||||
#include "RimWellLogPlotCollection.h"
|
||||
#include "RimWellLogTrack.h"
|
||||
#include "RimWellPath.h"
|
||||
#include "RimWellPathCollection.h"
|
||||
#include "RimWellPlotTools.h"
|
||||
|
||||
#include "RiuLineSegmentQwtPlotCurve.h"
|
||||
#include "RiuWellLogTrack.h"
|
||||
@ -396,8 +399,11 @@ void RimWellLogExtractionCurve::onLoadDataAndUpdate(bool updateParentPlot)
|
||||
measuredDepthValues = geomExtractor->measuredDepth();
|
||||
tvDepthValues = geomExtractor->trueVerticalDepth();
|
||||
|
||||
m_geomResultDefinition->loadResult();
|
||||
findAndLoadWbsParametersFromLasFiles(m_wellPath(), geomExtractor.p());
|
||||
|
||||
geomExtractor->setRkbDiff(rkbDiff());
|
||||
|
||||
m_geomResultDefinition->loadResult();
|
||||
geomExtractor->curveData(m_geomResultDefinition->resultAddress(), m_timeStep, &values);
|
||||
}
|
||||
|
||||
@ -462,6 +468,43 @@ void RimWellLogExtractionCurve::onLoadDataAndUpdate(bool updateParentPlot)
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// Search well path for LAS-files containing Well Bore Stability data and set them in the extractor.
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimWellLogExtractionCurve::findAndLoadWbsParametersFromLasFiles(const RimWellPath* wellPath, RigGeoMechWellLogExtractor* geomExtractor)
|
||||
{
|
||||
std::vector<std::pair<double, double>> logFileMudWeights = RimWellLogFile::findMdAndChannelValuesForWellPath(wellPath, "PP");
|
||||
if (!logFileMudWeights.empty())
|
||||
{
|
||||
// Log file pressures come in SG units (g / cm^3).
|
||||
// We need SI as input (kg / m^3), so multiply by 1000:
|
||||
for (auto& mudWeight : logFileMudWeights)
|
||||
{
|
||||
mudWeight.second *= 1000.0;
|
||||
}
|
||||
geomExtractor->setWellLogMdAndMudWeightKgPerM3(logFileMudWeights);
|
||||
}
|
||||
|
||||
std::vector<std::pair<double, double>> logFileUcs = RimWellLogFile::findMdAndChannelValuesForWellPath(wellPath, "UCS");
|
||||
if (!logFileUcs.empty())
|
||||
{
|
||||
// TODO: UCS is typically in MPa, but not necessarily.
|
||||
// We need to at least give a warning if the units don't match
|
||||
// ... and preferable do a conversion.
|
||||
for (auto& ucsValue : logFileUcs)
|
||||
{
|
||||
ucsValue.second *= 10.0; // MPa -> Bar
|
||||
}
|
||||
geomExtractor->setWellLogMdAndUcsBar(logFileUcs);
|
||||
}
|
||||
|
||||
std::vector<std::pair<double, double>> logFilePoissonRatio = RimWellLogFile::findMdAndChannelValuesForWellPath(wellPath, "POISSON_RATIO");
|
||||
if (!logFilePoissonRatio.empty())
|
||||
{
|
||||
geomExtractor->setWellLogMdAndPoissonRatio(logFilePoissonRatio);
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "cafPdmPtrField.h"
|
||||
#include "cafPdmChildField.h"
|
||||
|
||||
class RigGeoMechWellLogExtractor;
|
||||
class RigWellPath;
|
||||
class RimCase;
|
||||
class RimEclipseResultDefinition;
|
||||
@ -78,6 +79,7 @@ public:
|
||||
void setBranchDetection(bool branchDetection);
|
||||
void setBranchIndex(int index);
|
||||
|
||||
static void findAndLoadWbsParametersFromLasFiles(const RimWellPath* wellPath, RigGeoMechWellLogExtractor* geomExtractor);
|
||||
protected:
|
||||
virtual QString createCurveAutoName() override;
|
||||
virtual void onLoadDataAndUpdate(bool updateParentPlot) override;
|
||||
|
@ -259,6 +259,33 @@ void RimWellLogFile::updateFilePathsFromProjectPath(const QString& newProjectPat
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::vector<std::pair<double, double>> RimWellLogFile::findMdAndChannelValuesForWellPath(const RimWellPath* wellPath, const QString& channelName)
|
||||
{
|
||||
CVF_ASSERT(wellPath);
|
||||
std::vector<RimWellLogFile*> wellLogFiles;
|
||||
wellPath->descendantsIncludingThisOfType(wellLogFiles);
|
||||
for (RimWellLogFile* wellLogFile : wellLogFiles)
|
||||
{
|
||||
RigWellLogFile* fileData = wellLogFile->wellLogFileData();
|
||||
std::vector<double> channelValues = fileData->values(channelName);
|
||||
if (!channelValues.empty())
|
||||
{
|
||||
std::vector<double> depthValues = fileData->depthValues();
|
||||
CVF_ASSERT(depthValues.size() == channelValues.size());
|
||||
std::vector<std::pair<double, double>> depthValuePairs;
|
||||
for (size_t i = 0; i < depthValues.size(); ++i)
|
||||
{
|
||||
depthValuePairs.push_back(std::make_pair(depthValues[i], channelValues[i]));
|
||||
}
|
||||
return depthValuePairs;
|
||||
}
|
||||
}
|
||||
return std::vector<std::pair<double, double>>();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
|
@ -31,6 +31,7 @@
|
||||
|
||||
|
||||
class RimWellLogFileChannel;
|
||||
class RimWellPath;
|
||||
|
||||
class QString;
|
||||
|
||||
@ -74,6 +75,8 @@ public:
|
||||
|
||||
void updateFilePathsFromProjectPath(const QString& newProjectPath, const QString& oldProjectPath);
|
||||
|
||||
static std::vector<std::pair<double, double>> findMdAndChannelValuesForWellPath(const RimWellPath* wellPath, const QString& channelName);
|
||||
|
||||
private:
|
||||
virtual void setupBeforeSave() override;
|
||||
virtual void defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) override;
|
||||
|
@ -38,7 +38,9 @@
|
||||
#include "cvfGeometryTools.h"
|
||||
#include "cvfMath.h"
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
const double RigGeoMechWellLogExtractor::UNIT_WEIGHT_OF_WATER = 9.81 * 1000.0; // N / m^3
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
@ -101,9 +103,97 @@ void RigGeoMechWellLogExtractor::curveData(const RigFemResultAddress& resAddr, i
|
||||
{
|
||||
(*values)[intersectionIdx] = static_cast<double>(interpolateGridResultValue<float>(convResAddr.resultPosType, resultValues, intersectionIdx, false));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
float RigGeoMechWellLogExtractor::calculatePorePressureInSegment(int64_t intersectionIdx, float averageSegmentPorePressureBars, double hydroStaticPorePressureBars, double effectiveDepthMeters, const std::vector<float>& poreElementPressuresPascal) const
|
||||
{
|
||||
double porePressure = hydroStaticPorePressureBars;
|
||||
// 1: Try mud weight from LAS-file to generate pore pressure
|
||||
if (!m_wellLogMdAndMudWeightKgPerM3.empty())
|
||||
{
|
||||
double lasMudWeightKgPerM3 = getWellLogSegmentValue(intersectionIdx, m_wellLogMdAndMudWeightKgPerM3);
|
||||
if (lasMudWeightKgPerM3 != std::numeric_limits<double>::infinity())
|
||||
{
|
||||
double specificMudWeightNPerM3 = lasMudWeightKgPerM3 * 9.81;
|
||||
double porePressurePascal = specificMudWeightNPerM3 * effectiveDepthMeters;
|
||||
porePressure = pascalToBar(porePressurePascal);
|
||||
}
|
||||
}
|
||||
size_t elmIdx = m_intersectedCellsGlobIdx[intersectionIdx];
|
||||
// 2: Try pore pressure from element property tables
|
||||
if (porePressure == hydroStaticPorePressureBars && elmIdx < poreElementPressuresPascal.size())
|
||||
{
|
||||
// Pore pressure from element property tables are in pascal.
|
||||
porePressure = pascalToBar(poreElementPressuresPascal[elmIdx]);
|
||||
}
|
||||
// 3: Try pore pressure from the grid
|
||||
if (porePressure == hydroStaticPorePressureBars && averageSegmentPorePressureBars != std::numeric_limits<float>::infinity())
|
||||
{
|
||||
porePressure = averageSegmentPorePressureBars;
|
||||
}
|
||||
// 4: If no pore-pressure was found, the default value of hydrostatic pore pressure is used.
|
||||
return porePressure;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
float RigGeoMechWellLogExtractor::calculatePoissonRatio(int64_t intersectionIdx, const std::vector<float>& poissonRatios) const
|
||||
{
|
||||
const double defaultPoissonRatio = 0.25;
|
||||
|
||||
double poissonRatio = defaultPoissonRatio;
|
||||
|
||||
if (!m_wellLogMdAndPoissonRatios.empty())
|
||||
{
|
||||
double lasPoissionRatio = getWellLogSegmentValue(intersectionIdx, m_wellLogMdAndPoissonRatios);
|
||||
if (lasPoissionRatio != std::numeric_limits<double>::infinity())
|
||||
{
|
||||
poissonRatio = lasPoissionRatio;
|
||||
}
|
||||
}
|
||||
|
||||
size_t elmIdx = m_intersectedCellsGlobIdx[intersectionIdx];
|
||||
if (poissonRatio == defaultPoissonRatio && elmIdx < poissonRatios.size())
|
||||
{
|
||||
poissonRatio = poissonRatios[elmIdx];
|
||||
}
|
||||
return poissonRatio;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
float RigGeoMechWellLogExtractor::calculateUcs(int64_t intersectionIdx, const std::vector<float>& ucsValuesPascal) const
|
||||
{
|
||||
// Typical UCS: http://ceae.colorado.edu/~amadei/CVEN5768/PDF/NOTES8.pdf
|
||||
// Typical UCS for Shale is 5 - 100 MPa -> 50 - 1000 bar.
|
||||
const double defaultUniaxialStrengthInBars = 100.0;
|
||||
|
||||
double uniaxialStrengthInBars = defaultUniaxialStrengthInBars;
|
||||
if (!m_wellLogMdAndUcsBar.empty())
|
||||
{
|
||||
double lasUniaxialStrengthInBars = getWellLogSegmentValue(intersectionIdx, m_wellLogMdAndUcsBar);
|
||||
if (lasUniaxialStrengthInBars != std::numeric_limits<double>::infinity())
|
||||
{
|
||||
uniaxialStrengthInBars = lasUniaxialStrengthInBars;
|
||||
}
|
||||
}
|
||||
|
||||
size_t elmIdx = m_intersectedCellsGlobIdx[intersectionIdx];
|
||||
if (uniaxialStrengthInBars == defaultUniaxialStrengthInBars && elmIdx < ucsValuesPascal.size())
|
||||
{
|
||||
// Read UCS from element table in Pascal
|
||||
uniaxialStrengthInBars = pascalToBar(ucsValuesPascal[elmIdx]);
|
||||
}
|
||||
return uniaxialStrengthInBars;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
@ -165,13 +255,12 @@ void RigGeoMechWellLogExtractor::wellPathScaledCurveData(const RigFemResultAddre
|
||||
CVF_ASSERT(values);
|
||||
|
||||
const RigFemPart* femPart = m_caseData->femParts()->part(0);
|
||||
const RigFemPartGrid* femPartGrid = femPart->structGrid();
|
||||
const RigFemPartGrid* femPartGrid = femPart->getOrCreateStructGrid();
|
||||
const std::vector<cvf::Vec3f>& nodeCoords = femPart->nodes().coordinates;
|
||||
RigFemPartResultsCollection* resultCollection = m_caseData->femPartResults();
|
||||
|
||||
std::string nativeFieldName;
|
||||
std::string nativeCompName;
|
||||
double scalingFactor = 1000 * 9.81 / 1.0e5;
|
||||
if (resAddr.fieldName == "PP")
|
||||
{
|
||||
nativeFieldName = "POR-Bar"; // More likely to be in memory than POR
|
||||
@ -188,13 +277,32 @@ void RigGeoMechWellLogExtractor::wellPathScaledCurveData(const RigFemResultAddre
|
||||
}
|
||||
|
||||
RigFemResultAddress nativeAddr(RIG_ELEMENT_NODAL, nativeFieldName, nativeCompName);
|
||||
std::vector<float> unscaledResult = resultCollection->resultValues(nativeAddr, 0, frameIndex);
|
||||
RigFemResultAddress porElementResAddr(RIG_ELEMENT, "POR", "");
|
||||
|
||||
std::vector<float> unscaledResultValues = resultCollection->resultValues(nativeAddr, 0, frameIndex);
|
||||
std::vector<float> poreElementPressuresPascal = resultCollection->resultValues(porElementResAddr, 0, frameIndex);
|
||||
|
||||
std::vector<float> interpolatedInterfaceValues;
|
||||
interpolatedInterfaceValues.resize(m_intersections.size(), std::numeric_limits<double>::infinity());
|
||||
|
||||
#pragma omp parallel for
|
||||
for (int64_t intersectionIdx = 0; intersectionIdx < (int64_t)m_intersections.size(); ++intersectionIdx)
|
||||
{
|
||||
size_t elmIdx = m_intersectedCellsGlobIdx[intersectionIdx];
|
||||
RigElementType elmType = femPart->elementType(elmIdx);
|
||||
if (!(elmType == HEX8 || elmType == HEX8P)) continue;
|
||||
|
||||
interpolatedInterfaceValues[intersectionIdx] = interpolateGridResultValue<float>(nativeAddr.resultPosType, unscaledResultValues, intersectionIdx, false);
|
||||
}
|
||||
|
||||
values->resize(m_intersections.size(), 0.0f);
|
||||
|
||||
#pragma omp parallel for
|
||||
for (int64_t intersectionIdx = 0; intersectionIdx < (int64_t)m_intersections.size(); ++intersectionIdx)
|
||||
{
|
||||
// Set the value to invalid by default
|
||||
(*values)[intersectionIdx] = std::numeric_limits<double>::infinity();
|
||||
|
||||
size_t elmIdx = m_intersectedCellsGlobIdx[intersectionIdx];
|
||||
RigElementType elmType = femPart->elementType(elmIdx);
|
||||
|
||||
@ -205,17 +313,20 @@ void RigGeoMechWellLogExtractor::wellPathScaledCurveData(const RigFemResultAddre
|
||||
|
||||
double trueVerticalDepth = -centroid.z();
|
||||
|
||||
double effectiveDepth = trueVerticalDepth + m_rkbDiff;
|
||||
double hydroStaticPorePressure = effectiveDepth * 9.81 / 100.0;
|
||||
double effectiveDepthMeters = trueVerticalDepth + m_rkbDiff;
|
||||
double hydroStaticPorePressureBars = pascalToBar(effectiveDepthMeters * UNIT_WEIGHT_OF_WATER);
|
||||
|
||||
double unscaledValue = static_cast<double>(interpolateGridResultValue<float>(nativeAddr.resultPosType, unscaledResult, intersectionIdx, false));
|
||||
if (resAddr.fieldName == "PP" && (unscaledValue == std::numeric_limits<float>::infinity() ||
|
||||
unscaledValue == -std::numeric_limits<float>::infinity()))
|
||||
float averageUnscaledValue = std::numeric_limits<float>::infinity();
|
||||
bool validAverage = averageIntersectionValuesToSegmentValue(intersectionIdx, interpolatedInterfaceValues, std::numeric_limits<float>::infinity(), &averageUnscaledValue);
|
||||
|
||||
if (resAddr.fieldName == "PP")
|
||||
{
|
||||
unscaledValue = hydroStaticPorePressure;
|
||||
double segmentPorePressureFromGrid = averageUnscaledValue;
|
||||
averageUnscaledValue = calculatePorePressureInSegment(intersectionIdx, segmentPorePressureFromGrid, hydroStaticPorePressureBars, effectiveDepthMeters, poreElementPressuresPascal);
|
||||
|
||||
}
|
||||
double scaledValue = unscaledValue / (scalingFactor * effectiveDepth);
|
||||
(*values)[intersectionIdx] = scaledValue;
|
||||
|
||||
(*values)[intersectionIdx] = static_cast<double>(averageUnscaledValue) / hydroStaticPorePressureBars;
|
||||
}
|
||||
}
|
||||
|
||||
@ -224,26 +335,23 @@ void RigGeoMechWellLogExtractor::wellPathScaledCurveData(const RigFemResultAddre
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RigGeoMechWellLogExtractor::wellBoreWallCurveData(const RigFemResultAddress& resAddr, int frameIndex, std::vector<double>* values)
|
||||
{
|
||||
// TODO: Read in these values:
|
||||
const double poissonRatio = 0.25; // TODO: Read this in.
|
||||
// Typical UCS: http://ceae.colorado.edu/~amadei/CVEN5768/PDF/NOTES8.pdf
|
||||
// Typical UCS for Shale is 5 - 100 MPa -> 50 - 1000 bar.
|
||||
const double uniaxialStrengthInBars = 100.0;
|
||||
|
||||
CVF_ASSERT(values);
|
||||
CVF_ASSERT(resAddr.fieldName == RiaDefines::wellPathFGResultName().toStdString() || resAddr.fieldName == RiaDefines::wellPathSFGResultName().toStdString());
|
||||
|
||||
// The result addresses needed
|
||||
RigFemResultAddress stressResAddr(RIG_ELEMENT_NODAL, "ST", "");
|
||||
RigFemResultAddress porBarResAddr(RIG_ELEMENT_NODAL, "POR-Bar", "");
|
||||
// Allow POR as an element property value
|
||||
RigFemResultAddress porElementResAddr(RIG_ELEMENT, "POR", "");
|
||||
RigFemResultAddress poissonResAddr(RIG_ELEMENT, "POISSONS_RATIO", "");
|
||||
RigFemResultAddress ucsResAddr(RIG_ELEMENT, "UCS", "");
|
||||
|
||||
const RigFemPart* femPart = m_caseData->femParts()->part(0);
|
||||
const std::vector<cvf::Vec3f>& nodeCoords = femPart->nodes().coordinates;
|
||||
RigFemPartResultsCollection* resultCollection = m_caseData->femPartResults();
|
||||
|
||||
RigFemResultAddress stressResAddr(RIG_ELEMENT_NODAL, std::string("ST"), "");
|
||||
stressResAddr.fieldName = std::string("ST");
|
||||
|
||||
RigFemResultAddress porBarResAddr(RIG_ELEMENT_NODAL, std::string("POR-Bar"), "");
|
||||
|
||||
std::vector<caf::Ten3f> vertexStressesFloat = resultCollection->tensors(stressResAddr, 0, frameIndex);
|
||||
|
||||
// Load results
|
||||
std::vector<caf::Ten3f> vertexStressesFloat = resultCollection->tensors(stressResAddr, 0, frameIndex);
|
||||
if (!vertexStressesFloat.size()) return;
|
||||
|
||||
std::vector<caf::Ten3d> vertexStresses; vertexStresses.reserve(vertexStressesFloat.size());
|
||||
@ -251,11 +359,29 @@ void RigGeoMechWellLogExtractor::wellBoreWallCurveData(const RigFemResultAddress
|
||||
{
|
||||
vertexStresses.push_back(caf::Ten3d(floatTensor));
|
||||
}
|
||||
std::vector<float> porePressures = resultCollection->resultValues(porBarResAddr, 0, frameIndex);
|
||||
std::vector<float> poreElementPressuresPascal = resultCollection->resultValues(porElementResAddr, 0, frameIndex);
|
||||
std::vector<float> poissonRatios = resultCollection->resultValues(poissonResAddr, 0, frameIndex);
|
||||
std::vector<float> ucsValuesPascal = resultCollection->resultValues(ucsResAddr, 0, frameIndex);
|
||||
|
||||
std::vector<float> interpolatedInterfacePP;
|
||||
interpolatedInterfacePP.resize(m_intersections.size(), std::numeric_limits<double>::infinity());
|
||||
|
||||
std::vector<caf::Ten3d> interpolatedInterfaceStress;
|
||||
interpolatedInterfaceStress.resize(m_intersections.size());
|
||||
#pragma omp parallel for
|
||||
for (int64_t intersectionIdx = 0; intersectionIdx < (int64_t)m_intersections.size(); ++intersectionIdx)
|
||||
{
|
||||
size_t elmIdx = m_intersectedCellsGlobIdx[intersectionIdx];
|
||||
RigElementType elmType = femPart->elementType(elmIdx);
|
||||
if (!(elmType == HEX8 || elmType == HEX8P)) continue;
|
||||
|
||||
interpolatedInterfacePP[intersectionIdx] = interpolateGridResultValue(porBarResAddr.resultPosType, porePressures, intersectionIdx, false);
|
||||
interpolatedInterfaceStress[intersectionIdx] = interpolateGridResultValue(stressResAddr.resultPosType, vertexStresses, intersectionIdx, false);
|
||||
}
|
||||
|
||||
values->resize(m_intersections.size(), 0.0f);
|
||||
|
||||
std::vector<float> porePressures = resultCollection->resultValues(porBarResAddr, 0, frameIndex);
|
||||
|
||||
|
||||
#pragma omp parallel for
|
||||
for (int64_t intersectionIdx = 0; intersectionIdx < (int64_t) m_intersections.size(); ++intersectionIdx)
|
||||
{
|
||||
@ -268,23 +394,24 @@ void RigGeoMechWellLogExtractor::wellBoreWallCurveData(const RigFemResultAddress
|
||||
cvf::Vec3f centroid = cellCentroid(elmNodeIndices, nodeCoords);
|
||||
|
||||
double trueVerticalDepth = -centroid.z();
|
||||
double porePressure = trueVerticalDepth * 9.81 / 100.0;
|
||||
if (!porePressures.empty())
|
||||
{
|
||||
float interpolatedPorePressure = interpolateGridResultValue(porBarResAddr.resultPosType, porePressures, intersectionIdx, false);
|
||||
if (interpolatedPorePressure != std::numeric_limits<float>::infinity() &&
|
||||
interpolatedPorePressure != -std::numeric_limits<float>::infinity())
|
||||
{
|
||||
porePressure = static_cast<double>(interpolatedPorePressure);
|
||||
}
|
||||
}
|
||||
double effectiveDepthMeters = trueVerticalDepth + m_rkbDiff;
|
||||
double hydroStaticPorePressureBars = pascalToBar(effectiveDepthMeters * UNIT_WEIGHT_OF_WATER);
|
||||
|
||||
float averageUnscaledPP = std::numeric_limits<float>::infinity();
|
||||
averageIntersectionValuesToSegmentValue(intersectionIdx, interpolatedInterfacePP, std::numeric_limits<float>::infinity(), &averageUnscaledPP);
|
||||
|
||||
double porePressureBars = calculatePorePressureInSegment(intersectionIdx, averageUnscaledPP, hydroStaticPorePressureBars, effectiveDepthMeters, poreElementPressuresPascal);
|
||||
double poissonRatio = calculatePoissonRatio(intersectionIdx, poissonRatios);
|
||||
double ucsBars = calculateUcs(intersectionIdx, ucsValuesPascal);
|
||||
|
||||
caf::Ten3d segmentStress;
|
||||
bool validSegmentStress = averageIntersectionValuesToSegmentValue(intersectionIdx, interpolatedInterfaceStress, caf::Ten3d::invalid(), &segmentStress);
|
||||
|
||||
caf::Ten3d interpolatedStress = interpolateGridResultValue(stressResAddr.resultPosType, vertexStresses, intersectionIdx, false);
|
||||
cvf::Vec3d wellPathTangent = calculateWellPathTangent(intersectionIdx, TangentConstantWithinCell);
|
||||
caf::Ten3d wellPathStressFloat = transformTensorToWellPathOrientation(wellPathTangent, interpolatedStress);
|
||||
caf::Ten3d wellPathStressFloat = transformTensorToWellPathOrientation(wellPathTangent, segmentStress);
|
||||
caf::Ten3d wellPathStressDouble(wellPathStressFloat);
|
||||
|
||||
RigGeoMechBoreHoleStressCalculator sigmaCalculator(wellPathStressDouble, porePressure, poissonRatio, uniaxialStrengthInBars, 32);
|
||||
RigGeoMechBoreHoleStressCalculator sigmaCalculator(wellPathStressDouble, porePressureBars, poissonRatio, ucsBars, 32);
|
||||
double resultValue = 0.0;
|
||||
if (resAddr.fieldName == RiaDefines::wellPathFGResultName().toStdString())
|
||||
{
|
||||
@ -295,10 +422,9 @@ void RigGeoMechWellLogExtractor::wellBoreWallCurveData(const RigFemResultAddress
|
||||
CVF_ASSERT(resAddr.fieldName == RiaDefines::wellPathSFGResultName().toStdString());
|
||||
resultValue = sigmaCalculator.solveStassiDalia();
|
||||
}
|
||||
double effectiveDepth = trueVerticalDepth + m_rkbDiff;
|
||||
if (effectiveDepth > 1.0e-8)
|
||||
if (hydroStaticPorePressureBars > 1.0e-8)
|
||||
{
|
||||
resultValue *= 100.0 / (effectiveDepth * 9.81);
|
||||
resultValue /= hydroStaticPorePressureBars;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -325,14 +451,38 @@ void RigGeoMechWellLogExtractor::setRkbDiff(double rkbDiff)
|
||||
m_rkbDiff = rkbDiff;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RigGeoMechWellLogExtractor::setWellLogMdAndMudWeightKgPerM3(const std::vector<std::pair<double, double>>& porePressures)
|
||||
{
|
||||
m_wellLogMdAndMudWeightKgPerM3 = porePressures;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RigGeoMechWellLogExtractor::setWellLogMdAndUcsBar(const std::vector<std::pair<double, double>>& ucsValues)
|
||||
{
|
||||
m_wellLogMdAndUcsBar = ucsValues;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RigGeoMechWellLogExtractor::setWellLogMdAndPoissonRatio(const std::vector<std::pair<double, double>>& poissonRatios)
|
||||
{
|
||||
m_wellLogMdAndPoissonRatios = poissonRatios;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
template<typename T>
|
||||
T RigGeoMechWellLogExtractor::interpolateGridResultValue(RigFemResultPosEnum resultPosType,
|
||||
const std::vector<T>& gridResultValues,
|
||||
int64_t intersectionIdx,
|
||||
bool averageNodeElementResults) const
|
||||
const std::vector<T>& gridResultValues,
|
||||
int64_t intersectionIdx,
|
||||
bool averageNodeElementResults) const
|
||||
{
|
||||
const RigFemPart* femPart = m_caseData->femParts()->part(0);
|
||||
const std::vector<cvf::Vec3f>& nodeCoords = femPart->nodes().coordinates;
|
||||
@ -596,3 +746,73 @@ cvf::Vec3f RigGeoMechWellLogExtractor::cellCentroid(const int* elmNodeIndices, c
|
||||
return centroid / 8.0;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
double RigGeoMechWellLogExtractor::getWellLogSegmentValue(size_t intersectionIdx, const std::vector<std::pair<double, double>>& wellLogValues) const
|
||||
{
|
||||
double startMD, endMD;
|
||||
if (intersectionIdx % 2 == 0)
|
||||
{
|
||||
startMD = m_intersectionMeasuredDepths[intersectionIdx];
|
||||
endMD = m_intersectionMeasuredDepths[intersectionIdx + 1];
|
||||
}
|
||||
else
|
||||
{
|
||||
startMD = m_intersectionMeasuredDepths [intersectionIdx - 1];
|
||||
endMD = m_intersectionMeasuredDepths[intersectionIdx];
|
||||
}
|
||||
|
||||
int nValuesWithinSegment = 0;
|
||||
double sumValuesWithinSegment = 0.0;
|
||||
for (auto& depthAndValue : wellLogValues)
|
||||
{
|
||||
if (cvf::Math::valueInRange(depthAndValue.first, startMD, endMD))
|
||||
{
|
||||
sumValuesWithinSegment += depthAndValue.second;
|
||||
nValuesWithinSegment++;
|
||||
}
|
||||
}
|
||||
if (nValuesWithinSegment)
|
||||
{
|
||||
// TODO: Could do average weighted by inverse distance to center of element.
|
||||
return sumValuesWithinSegment / nValuesWithinSegment;
|
||||
}
|
||||
|
||||
return std::numeric_limits<double>::infinity();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
double RigGeoMechWellLogExtractor::pascalToBar(double pascalValue)
|
||||
{
|
||||
return pascalValue * 1.0e-5;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
template<typename T>
|
||||
bool RigGeoMechWellLogExtractor::averageIntersectionValuesToSegmentValue(size_t intersectionIdx, const std::vector<T>& values, const T& invalidValue, T* averagedCellValue)
|
||||
{
|
||||
CVF_ASSERT(values.size() >= 2);
|
||||
T value1, value2;
|
||||
if (intersectionIdx % 2 == 0)
|
||||
{
|
||||
value1 = values[intersectionIdx];
|
||||
value2 = values[intersectionIdx + 1];
|
||||
}
|
||||
else {
|
||||
value1 = values[intersectionIdx - 1];
|
||||
value2 = values[intersectionIdx];
|
||||
}
|
||||
|
||||
if (invalidValue == value1 || invalidValue == value2)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
*averagedCellValue = (value1 + value2) * 0.5;
|
||||
return true;
|
||||
}
|
||||
|
@ -53,6 +53,12 @@ public:
|
||||
void curveData(const RigFemResultAddress& resAddr, int frameIndex, std::vector<double>* values );
|
||||
const RigGeoMechCaseData* caseData();
|
||||
void setRkbDiff(double rkbDiff);
|
||||
|
||||
void setWellLogMdAndMudWeightKgPerM3(const std::vector<std::pair<double, double>>& mudWeightKgPerM3);
|
||||
void setWellLogMdAndUcsBar(const std::vector<std::pair<double, double>>& ucsValues);
|
||||
void setWellLogMdAndPoissonRatio(const std::vector<std::pair<double, double>>& poissonRatio);
|
||||
|
||||
|
||||
private:
|
||||
enum WellPathTangentCalculation
|
||||
{
|
||||
@ -60,11 +66,16 @@ private:
|
||||
TangentConstantWithinCell
|
||||
};
|
||||
|
||||
float calculatePorePressureInSegment(int64_t intersectionIdx, float averageSegmentPorePressureBars, double hydroStaticPorePressureBars, double effectiveDepthMeters, const std::vector<float>& poreElementPressuresPascal) const;
|
||||
float calculatePoissonRatio(int64_t intersectionIdx, const std::vector<float>& poissonRatios) const;
|
||||
float calculateUcs(int64_t intersectionIdx, const std::vector<float>& ucsValuesPascal) const;
|
||||
|
||||
void wellPathAngles(const RigFemResultAddress& resAddr, std::vector<double>* values);
|
||||
void wellPathScaledCurveData(const RigFemResultAddress& resAddr, int frameIndex, std::vector<double>* values);
|
||||
|
||||
|
||||
void wellBoreWallCurveData(const RigFemResultAddress& resAddr, int frameIndex, std::vector<double>* values);
|
||||
|
||||
|
||||
template<typename T>
|
||||
T interpolateGridResultValue(RigFemResultPosEnum resultPosType, const std::vector<T>& gridResultValues, int64_t intersectionIdx, bool averageNodeElementResults) const;
|
||||
size_t gridResultIndexFace(size_t elementIdx, cvf::StructGridInterface::FaceType cellFace, int faceLocalNodeIdx) const;
|
||||
@ -78,8 +89,18 @@ private:
|
||||
const caf::Ten3d& wellPathTensor);
|
||||
|
||||
static cvf::Vec3f cellCentroid(const int* elmNodeIndices, const std::vector<cvf::Vec3f>& nodeCoords);
|
||||
double getWellLogSegmentValue(size_t intersectionIdx, const std::vector<std::pair<double, double>>& wellLogValues) const;
|
||||
|
||||
template<typename T>
|
||||
static bool averageIntersectionValuesToSegmentValue(size_t intersectionIdx, const std::vector<T>& intersectionValues, const T& invalidValue, T* averagedSegmentValue);
|
||||
static double pascalToBar(double pascalValue);
|
||||
private:
|
||||
cvf::ref<RigGeoMechCaseData> m_caseData;
|
||||
double m_rkbDiff;
|
||||
std::vector<std::pair<double, double>> m_wellLogMdAndMudWeightKgPerM3;
|
||||
std::vector<std::pair<double, double>> m_wellLogMdAndUcsBar;
|
||||
std::vector<std::pair<double, double>> m_wellLogMdAndPoissonRatios;
|
||||
|
||||
static const double UNIT_WEIGHT_OF_WATER;
|
||||
};
|
||||
|
||||
|
||||
|
@ -57,8 +57,8 @@ std::vector<WellPathCellIntersectionInfo> RigWellLogExtractor::cellIntersectionI
|
||||
cellInfo.globCellIndex = m_intersectedCellsGlobIdx[i];
|
||||
cellInfo.startPoint = m_intersections[i];
|
||||
cellInfo.endPoint = m_intersections[i+1];
|
||||
cellInfo.startMD = m_measuredDepth[i];
|
||||
cellInfo.endMD = m_measuredDepth[i+1];
|
||||
cellInfo.startMD = m_intersectionMeasuredDepths[i];
|
||||
cellInfo.endMD = m_intersectionMeasuredDepths[i+1];
|
||||
|
||||
cellInfo.intersectedCellFaceIn = m_intersectedCellFaces[i];
|
||||
cellInfo.intersectedCellFaceOut = m_intersectedCellFaces[i+1];
|
||||
@ -280,8 +280,8 @@ void RigWellLogExtractor::populateReturnArrays(std::map<RigMDCellIdxEnterLeaveKe
|
||||
|
||||
void RigWellLogExtractor::appendIntersectionToArrays(double measuredDepth, const HexIntersectionInfo& intersection)
|
||||
{
|
||||
m_measuredDepth.push_back (measuredDepth);
|
||||
m_trueVerticalDepth.push_back (fabs(intersection.m_intersectionPoint[2]));
|
||||
m_intersectionMeasuredDepths.push_back (measuredDepth);
|
||||
m_intersectionTVDs.push_back (fabs(intersection.m_intersectionPoint[2]));
|
||||
m_intersections.push_back (intersection.m_intersectionPoint);
|
||||
m_intersectedCellsGlobIdx.push_back (intersection.m_hexIndex);
|
||||
m_intersectedCellFaces.push_back(intersection.m_face);
|
||||
|
@ -59,8 +59,8 @@ public:
|
||||
RigWellLogExtractor(const RigWellPath* wellpath, const std::string& wellCaseErrorMsgName);
|
||||
virtual ~RigWellLogExtractor();
|
||||
|
||||
const std::vector<double>& measuredDepth() { return m_measuredDepth; }
|
||||
const std::vector<double>& trueVerticalDepth() { return m_trueVerticalDepth; }
|
||||
const std::vector<double>& measuredDepth() { return m_intersectionMeasuredDepths; }
|
||||
const std::vector<double>& trueVerticalDepth() { return m_intersectionTVDs; }
|
||||
const std::vector<size_t>& intersectedCellsGlobIdx();
|
||||
|
||||
const RigWellPath* wellPathData() { return m_wellPath.p();}
|
||||
@ -89,10 +89,10 @@ protected:
|
||||
|
||||
cvf::cref<RigWellPath> m_wellPath;
|
||||
|
||||
private:
|
||||
std::vector<double> m_measuredDepth;
|
||||
std::vector<double> m_trueVerticalDepth;
|
||||
std::vector<double> m_intersectionMeasuredDepths;
|
||||
std::vector<double> m_intersectionTVDs;
|
||||
|
||||
private:
|
||||
std::string m_wellCaseErrorMsgName;
|
||||
};
|
||||
|
||||
|
@ -35,6 +35,8 @@ public:
|
||||
template<typename T>
|
||||
explicit Tensor3(const Tensor3<T>& other);
|
||||
|
||||
static Tensor3 invalid();
|
||||
|
||||
inline Tensor3& operator=(const Tensor3& rhs);
|
||||
inline Tensor3 operator+(const Tensor3& rhs) const;
|
||||
inline Tensor3 operator*(S scale) const;
|
||||
|
@ -67,6 +67,17 @@ Tensor3<S>::Tensor3(S sxx, S syy, S szz, S sxy, S syz, S szx)
|
||||
m_tensor[5] = szx;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
template <typename S>
|
||||
Tensor3<S> caf::Tensor3<S>::invalid()
|
||||
{
|
||||
return caf::Tensor3<S>(std::numeric_limits<S>::infinity(), std::numeric_limits<S>::infinity(),
|
||||
std::numeric_limits<S>::infinity(), std::numeric_limits<S>::infinity(),
|
||||
std::numeric_limits<S>::infinity(), std::numeric_limits<S>::infinity());
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
/// Assignment operator
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
|
Loading…
Reference in New Issue
Block a user