#1542 Always using radial transmissibility calculation if the fracture is transverse to well or azimuth. If alog well: Perforation length for fracture limits the intersection fracture/well.

This commit is contained in:
astridkbjorke 2017-06-02 15:04:32 +02:00
parent 56579e7b3e
commit 1f87681d7e
6 changed files with 87 additions and 70 deletions

View File

@ -147,48 +147,77 @@ std::vector<RigCompletionData> RicExportFractureCompletionsImpl::generateFractur
///// /////
// Calculate transmissibility into the well // Calculate transmissibility into the well
RigWellPathStimplanIntersector wellFractureIntersector(wellPath->wellPathGeometry(), fracture); ////
const std::map<size_t, RigWellPathStimplanIntersector::WellCellIntersection >& fractureWellCells = wellFractureIntersector.intersections(); //If fracture has orientation Azimuth or Transverse, assume only radial inflow
if (fracture->attachedFractureDefinition()->orientation() == RimFractureTemplate::AZIMUTH
for (const auto& fracCellIdxIsectDataPair : fractureWellCells) || fracture->attachedFractureDefinition()->orientation() == RimFractureTemplate::TRANSVERSE_WELL_PATH)
{ {
size_t fracWellCellIdx = fracCellIdxIsectDataPair.first; const RigFractureGrid* fracGrid = fracture->attachedFractureDefinition()->fractureGrid();
RigWellPathStimplanIntersector::WellCellIntersection intersection = fracCellIdxIsectDataPair.second; std::pair<size_t, size_t> wellCellIJ = fracGrid->fractureCellAtWellCenter();
size_t wellCellIndex = fracGrid->getGlobalIndexFromIJ(wellCellIJ.first, wellCellIJ.second);
const RigFractureCell wellCell = fractureGrid->cellFromIndex(wellCellIndex);
const RigFractureCell fractureWellCell = fractureGrid->cellFromIndex(fracWellCellIdx); double radialTrans = RigFractureTransmissibilityEquations::fractureCellToWellRadialTrans(wellCell.getConductivtyValue(),
wellCell.cellSizeX(),
wellCell.cellSizeZ(),
fracture->wellRadius(),
fracTemplate->skinFactor(),
cDarcyInCorrectUnit);
double radialTrans = 0.0; transCondenser.addNeighborTransmissibility({ true, RigTransmissibilityCondenser::CellAddress::WELL, 1 },
if (intersection.endpointCount) { false, RigTransmissibilityCondenser::CellAddress::STIMPLAN, wellCellIndex },
{ radialTrans);
radialTrans = RigFractureTransmissibilityEquations::fractureCellToWellRadialTrans(fractureWellCell.getConductivtyValue(),
fractureWellCell.cellSizeX(),
fractureWellCell.cellSizeZ(),
fracture->wellRadius(),
fracTemplate->skinFactor(),
cDarcyInCorrectUnit);
}
double linearTrans = 0.0;
if (intersection.hlength > 0.0 || intersection.vlength > 0.0 )
{
linearTrans = RigFractureTransmissibilityEquations::fractureCellToWellLinearTrans(fractureWellCell.getConductivtyValue(),
fractureWellCell.cellSizeX(),
fractureWellCell.cellSizeZ(),
intersection.vlength,
intersection.hlength ,
fracture->perforationEfficiency,
fracTemplate->skinFactor(),
cDarcyInCorrectUnit);
}
double totalWellTrans = 0.5 * intersection.endpointCount * radialTrans + linearTrans;
transCondenser.addNeighborTransmissibility( { true, RigTransmissibilityCondenser::CellAddress::WELL, 1},
{ false, RigTransmissibilityCondenser::CellAddress::STIMPLAN, fracWellCellIdx },
totalWellTrans);
} }
////
//If fracture has orientation along well, assume only linear inflow
if (fracture->attachedFractureDefinition()->orientation() == RimFractureTemplate::ALONG_WELL_PATH)
{
RigWellPathStimplanIntersector wellFractureIntersector(wellPath->wellPathGeometry(), fracture);
const std::map<size_t, RigWellPathStimplanIntersector::WellCellIntersection >& fractureWellCells = wellFractureIntersector.intersections();
for (const auto& fracCellIdxIsectDataPair : fractureWellCells)
{
size_t fracWellCellIdx = fracCellIdxIsectDataPair.first;
RigWellPathStimplanIntersector::WellCellIntersection intersection = fracCellIdxIsectDataPair.second;
const RigFractureCell fractureWellCell = fractureGrid->cellFromIndex(fracWellCellIdx);
double radialTrans = 0.0;
if (intersection.endpointCount)
{
radialTrans = RigFractureTransmissibilityEquations::fractureCellToWellRadialTrans(fractureWellCell.getConductivtyValue(),
fractureWellCell.cellSizeX(),
fractureWellCell.cellSizeZ(),
fracture->wellRadius(),
fracTemplate->skinFactor(),
cDarcyInCorrectUnit);
}
double linearTrans = 0.0;
if (intersection.hlength > 0.0 || intersection.vlength > 0.0 )
{
linearTrans = RigFractureTransmissibilityEquations::fractureCellToWellLinearTrans(fractureWellCell.getConductivtyValue(),
fractureWellCell.cellSizeX(),
fractureWellCell.cellSizeZ(),
intersection.vlength,
intersection.hlength ,
fracture->perforationEfficiency,
fracTemplate->skinFactor(),
cDarcyInCorrectUnit);
}
double totalWellTrans = 0.5 * intersection.endpointCount * radialTrans + linearTrans;
transCondenser.addNeighborTransmissibility( { true, RigTransmissibilityCondenser::CellAddress::WELL, 1},
{ false, RigTransmissibilityCondenser::CellAddress::STIMPLAN, fracWellCellIdx },
totalWellTrans);
}
}
///// /////
// Insert total transmissibility from eclipse-cell to well for this fracture into the map // Insert total transmissibility from eclipse-cell to well for this fracture into the map

View File

@ -497,11 +497,6 @@ QStringList RimContextCommandBuilder::commandsFromSelection()
commandIds << "RicNewSimWellFractureFeature"; commandIds << "RicNewSimWellFractureFeature";
commandIds << "RicExportSelectedSimWellFractureWellCompletionFeature"; commandIds << "RicExportSelectedSimWellFractureWellCompletionFeature";
} }
else if (dynamic_cast<RimWellPath*>(uiItem))
{
commandIds << "RicExportSelectedWellPathFractureWellCompletionFeature";
}
} }

View File

@ -47,7 +47,7 @@ public:
size_t jCellCount() const { return m_jCellCount; } size_t jCellCount() const { return m_jCellCount; }
size_t iCellCount() const { return m_iCellCount; } size_t iCellCount() const { return m_iCellCount; }
std::pair<size_t, size_t> fractureCellAtWellCenter() const { return m_wellCenterFractureCellIJ; } std::pair<size_t, size_t> fractureCellAtWellCenter() const { return m_wellCenterFractureCellIJ; }
private: private:

View File

@ -27,8 +27,9 @@ RigWellPathStimplanIntersector::RigWellPathStimplanIntersector(const RigWellPath
for ( const auto& stpCell: stpCells ) stpCellPolygons.push_back(stpCell.getPolygon()); for ( const auto& stpCell: stpCells ) stpCellPolygons.push_back(stpCell.getPolygon());
} }
} }
double perforationLength = rimFracture->perforationLength();
calculate(fractureXf, wellPathPoints, wellRadius, stpCellPolygons, m_stimPlanCellIdxToIntersectionInfoMap); calculate(fractureXf, wellPathPoints, wellRadius, perforationLength, stpCellPolygons, m_stimPlanCellIdxToIntersectionInfoMap);
} }
@ -39,27 +40,17 @@ RigWellPathStimplanIntersector::RigWellPathStimplanIntersector(const RigWellPath
void RigWellPathStimplanIntersector::calculate(const cvf::Mat4f &fractureXf, void RigWellPathStimplanIntersector::calculate(const cvf::Mat4f &fractureXf,
const std::vector<cvf::Vec3d>& wellPathPointsOrg, const std::vector<cvf::Vec3d>& wellPathPointsOrg,
double wellRadius, double wellRadius,
double perforationLength,
const std::vector<std::vector<cvf::Vec3d> >& stpCellPolygons, const std::vector<std::vector<cvf::Vec3d> >& stpCellPolygons,
std::map<size_t, WellCellIntersection>& m_stimPlanCellIdxToIntersectionInfoMap) std::map<size_t, WellCellIntersection>& m_stimPlanCellIdxToIntersectionInfoMap)
{ {
cvf::Mat4d toFractureXf = cvf::Mat4d(fractureXf.getInverted()); cvf::Mat4d toFractureXf = cvf::Mat4d(fractureXf.getInverted());
//Find bounding box std::vector<cvf::Vec3d> perforationLengthBoundingBoxPolygon;
cvf::BoundingBox polygonBBox; perforationLengthBoundingBoxPolygon.push_back(cvf::Vec3d(-perforationLength / 2, -perforationLength / 2, 0));
for (std::vector<cvf::Vec3d> fracCellPolygon : stpCellPolygons) perforationLengthBoundingBoxPolygon.push_back(cvf::Vec3d( perforationLength / 2, -perforationLength / 2, 0));
{ perforationLengthBoundingBoxPolygon.push_back(cvf::Vec3d( perforationLength / 2, perforationLength / 2, 0));
for (cvf::Vec3d nodeCoord : fracCellPolygon) polygonBBox.add(nodeCoord); perforationLengthBoundingBoxPolygon.push_back(cvf::Vec3d(-perforationLength / 2, perforationLength / 2, 0));
}
cvf::Vec3d bboxCorners[8];
polygonBBox.cornerVertices(bboxCorners);
//put BB corners into polygon, to use clipPolylineByPolygon function below
//Since we are in 2D, the 4 corners of the boundingbox are repeated so only 4 are included in the polygon
std::vector<cvf::Vec3d> boundingBoxPolygon;
for (int i = 0; i < 4; i++)
{
boundingBoxPolygon.push_back(bboxCorners[i]);
}
// Convert well path to fracture template system // Convert well path to fracture template system
@ -69,7 +60,7 @@ void RigWellPathStimplanIntersector::calculate(const cvf::Mat4f &fractureXf,
// Clip well path to fracture domain // Clip well path to fracture domain
std::vector<std::vector<cvf::Vec3d> > wellPathPartsWithinFracture = std::vector<std::vector<cvf::Vec3d> > wellPathPartsWithinFracture =
RigCellGeometryTools::clipPolylineByPolygon(fractureRelativeWellPathPoints, boundingBoxPolygon, RigCellGeometryTools::INTERPOLATE_LINE_Z); RigCellGeometryTools::clipPolylineByPolygon(fractureRelativeWellPathPoints, perforationLengthBoundingBoxPolygon, RigCellGeometryTools::INTERPOLATE_LINE_Z);
// Remove the part of the well path that is more than well radius away from the fracture plane // Remove the part of the well path that is more than well radius away from the fracture plane

View File

@ -47,6 +47,7 @@ private:
static void calculate(const cvf::Mat4f& fractureXf, static void calculate(const cvf::Mat4f& fractureXf,
const std::vector<cvf::Vec3d>& wellPathPoints, const std::vector<cvf::Vec3d>& wellPathPoints,
double wellRadius, double wellRadius,
double perforationLength,
const std::vector<std::vector<cvf::Vec3d> >& stpCellPolygons, const std::vector<std::vector<cvf::Vec3d> >& stpCellPolygons,
std::map<size_t, WellCellIntersection>& stimPlanCellIdxToIntersectionInfoMap); std::map<size_t, WellCellIntersection>& stimPlanCellIdxToIntersectionInfoMap);
@ -58,13 +59,13 @@ class RigWellPathStimplanIntersectorTester
{ {
public: public:
static void testCalculate(const cvf::Mat4f& fractureXf, static void testCalculate(const cvf::Mat4f& fractureXf,
const std::vector<cvf::Vec3f>& fracturePolygon,
const std::vector<cvf::Vec3d>& wellPathPoints, const std::vector<cvf::Vec3d>& wellPathPoints,
double wellRadius, double wellRadius,
double perforationLength,
const std::vector<std::vector<cvf::Vec3d> >& stpCellPolygons, const std::vector<std::vector<cvf::Vec3d> >& stpCellPolygons,
std::map<size_t, RigWellPathStimplanIntersector::WellCellIntersection>& stimPlanCellIdxToIntersectionInfoMap) std::map<size_t, RigWellPathStimplanIntersector::WellCellIntersection>& stimPlanCellIdxToIntersectionInfoMap)
{ {
RigWellPathStimplanIntersector::calculate(fractureXf, wellPathPoints, wellRadius, stpCellPolygons, stimPlanCellIdxToIntersectionInfoMap); RigWellPathStimplanIntersector::calculate(fractureXf, wellPathPoints, wellRadius, perforationLength, stpCellPolygons, stimPlanCellIdxToIntersectionInfoMap);
} }
}; };

View File

@ -315,7 +315,8 @@ TEST(RigWellPathStimplanIntersector, intersection)
cvf::Mat4f fractureXf = cvf::Mat4f::IDENTITY; cvf::Mat4f fractureXf = cvf::Mat4f::IDENTITY;
fractureXf.setTranslation({ 50.0f, 0.0f, 0.0f }); fractureXf.setTranslation({ 50.0f, 0.0f, 0.0f });
std::vector<cvf::Vec3f> fracturePolygon ={ {0.0f, 0.0f, 0.0f}, {5.0f, 10.0f, 0.0f}, {10.0f, 0.0f, 0.0f} }; //std::vector<cvf::Vec3f> fracturePolygon ={ {0.0f, 0.0f, 0.0f}, {5.0f, 10.0f, 0.0f}, {10.0f, 0.0f, 0.0f} };
double perforationLength = 25.0;
std::vector<cvf::Vec3d> wellPathPoints ={ {50.0f-4.0f, 6.0f, 10.0f}, {50.0f+6.0f, 6.0f, 0.0f}, {50.0f+10.0f, 10.0f, -100.0f} }; std::vector<cvf::Vec3d> wellPathPoints ={ {50.0f-4.0f, 6.0f, 10.0f}, {50.0f+6.0f, 6.0f, 0.0f}, {50.0f+10.0f, 10.0f, -100.0f} };
double wellRadius = 1.5; double wellRadius = 1.5;
std::vector<std::vector<cvf::Vec3d> > stpCellPolygons = std::vector<std::vector<cvf::Vec3d> > stpCellPolygons =
@ -329,9 +330,9 @@ TEST(RigWellPathStimplanIntersector, intersection)
std::map<size_t, RigWellPathStimplanIntersector::WellCellIntersection> stimPlanCellIdxToIntersectionInfoMap; std::map<size_t, RigWellPathStimplanIntersector::WellCellIntersection> stimPlanCellIdxToIntersectionInfoMap;
RigWellPathStimplanIntersectorTester::testCalculate(fractureXf, RigWellPathStimplanIntersectorTester::testCalculate(fractureXf,
fracturePolygon,
wellPathPoints, wellPathPoints,
wellRadius, wellRadius,
perforationLength,
stpCellPolygons, stpCellPolygons,
stimPlanCellIdxToIntersectionInfoMap); stimPlanCellIdxToIntersectionInfoMap);
@ -344,11 +345,11 @@ TEST(RigWellPathStimplanIntersector, intersection)
EXPECT_EQ(1, it->second.endpointCount); EXPECT_EQ(1, it->second.endpointCount);
} }
{ {
cvf::Mat4f fractureXf = cvf::Mat4f::IDENTITY; cvf::Mat4f fractureXf = cvf::Mat4f::IDENTITY;
std::vector<cvf::Vec3f> fracturePolygon ={ {0.0f, 0.0f, 0.0f}, {5.0f, 10.0f, 0.0f}, {10.0f, 0.0f, 0.0f} }; // std::vector<cvf::Vec3f> fracturePolygon ={ {0.0f, 0.0f, 0.0f}, {5.0f, 10.0f, 0.0f}, {10.0f, 0.0f, 0.0f} };
double perforationLength = 10;
double wellRadius = 1.5; double wellRadius = 1.5;
std::vector<std::vector<cvf::Vec3d> > stpCellPolygons = std::vector<std::vector<cvf::Vec3d> > stpCellPolygons =
{ {
@ -364,9 +365,9 @@ TEST(RigWellPathStimplanIntersector, intersection)
std::vector<cvf::Vec3d> wellPathPoints ={ {1.0f, 0.5f, 10.0f}, {1.0f, 1.5f, -10.0f} }; std::vector<cvf::Vec3d> wellPathPoints ={ {1.0f, 0.5f, 10.0f}, {1.0f, 1.5f, -10.0f} };
RigWellPathStimplanIntersectorTester::testCalculate(fractureXf, RigWellPathStimplanIntersectorTester::testCalculate(fractureXf,
fracturePolygon,
wellPathPoints, wellPathPoints,
wellRadius, wellRadius,
perforationLength,
stpCellPolygons, stpCellPolygons,
stimPlanCellIdxToIntersectionInfoMap); stimPlanCellIdxToIntersectionInfoMap);
@ -383,9 +384,9 @@ TEST(RigWellPathStimplanIntersector, intersection)
std::vector<cvf::Vec3d> wellPathPoints ={ {1.0f, 0.5f, 10.0f}, {1.0f, 1.0f, 0.5f} }; std::vector<cvf::Vec3d> wellPathPoints ={ {1.0f, 0.5f, 10.0f}, {1.0f, 1.0f, 0.5f} };
RigWellPathStimplanIntersectorTester::testCalculate(fractureXf, RigWellPathStimplanIntersectorTester::testCalculate(fractureXf,
fracturePolygon,
wellPathPoints, wellPathPoints,
wellRadius, wellRadius,
perforationLength,
stpCellPolygons, stpCellPolygons,
stimPlanCellIdxToIntersectionInfoMap); stimPlanCellIdxToIntersectionInfoMap);
@ -402,9 +403,9 @@ TEST(RigWellPathStimplanIntersector, intersection)
std::vector<cvf::Vec3d> wellPathPoints ={ {1.0f, 0.5f, 10.0f}, {1.0f, 1.0f, 0.5f}, {1.0f, 1.5f, -0.5f}, {1.0f, 2.0f, -10.0f}}; std::vector<cvf::Vec3d> wellPathPoints ={ {1.0f, 0.5f, 10.0f}, {1.0f, 1.0f, 0.5f}, {1.0f, 1.5f, -0.5f}, {1.0f, 2.0f, -10.0f}};
RigWellPathStimplanIntersectorTester::testCalculate(fractureXf, RigWellPathStimplanIntersectorTester::testCalculate(fractureXf,
fracturePolygon,
wellPathPoints, wellPathPoints,
wellRadius, wellRadius,
perforationLength,
stpCellPolygons, stpCellPolygons,
stimPlanCellIdxToIntersectionInfoMap); stimPlanCellIdxToIntersectionInfoMap);