#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
RigWellPathStimplanIntersector wellFractureIntersector(wellPath->wellPathGeometry(), fracture);
const std::map<size_t, RigWellPathStimplanIntersector::WellCellIntersection >& fractureWellCells = wellFractureIntersector.intersections();
for (const auto& fracCellIdxIsectDataPair : fractureWellCells)
////
//If fracture has orientation Azimuth or Transverse, assume only radial inflow
if (fracture->attachedFractureDefinition()->orientation() == RimFractureTemplate::AZIMUTH
|| fracture->attachedFractureDefinition()->orientation() == RimFractureTemplate::TRANSVERSE_WELL_PATH)
{
size_t fracWellCellIdx = fracCellIdxIsectDataPair.first;
RigWellPathStimplanIntersector::WellCellIntersection intersection = fracCellIdxIsectDataPair.second;
const RigFractureGrid* fracGrid = fracture->attachedFractureDefinition()->fractureGrid();
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;
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);
transCondenser.addNeighborTransmissibility({ true, RigTransmissibilityCondenser::CellAddress::WELL, 1 },
{ false, RigTransmissibilityCondenser::CellAddress::STIMPLAN, wellCellIndex },
radialTrans);
}
////
//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

View File

@ -497,11 +497,6 @@ QStringList RimContextCommandBuilder::commandsFromSelection()
commandIds << "RicNewSimWellFractureFeature";
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 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:

View File

@ -27,8 +27,9 @@ RigWellPathStimplanIntersector::RigWellPathStimplanIntersector(const RigWellPath
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,
const std::vector<cvf::Vec3d>& wellPathPointsOrg,
double wellRadius,
double perforationLength,
const std::vector<std::vector<cvf::Vec3d> >& stpCellPolygons,
std::map<size_t, WellCellIntersection>& m_stimPlanCellIdxToIntersectionInfoMap)
{
cvf::Mat4d toFractureXf = cvf::Mat4d(fractureXf.getInverted());
//Find bounding box
cvf::BoundingBox polygonBBox;
for (std::vector<cvf::Vec3d> fracCellPolygon : stpCellPolygons)
{
for (cvf::Vec3d nodeCoord : fracCellPolygon) polygonBBox.add(nodeCoord);
}
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]);
}
std::vector<cvf::Vec3d> perforationLengthBoundingBoxPolygon;
perforationLengthBoundingBoxPolygon.push_back(cvf::Vec3d(-perforationLength / 2, -perforationLength / 2, 0));
perforationLengthBoundingBoxPolygon.push_back(cvf::Vec3d( perforationLength / 2, -perforationLength / 2, 0));
perforationLengthBoundingBoxPolygon.push_back(cvf::Vec3d( perforationLength / 2, perforationLength / 2, 0));
perforationLengthBoundingBoxPolygon.push_back(cvf::Vec3d(-perforationLength / 2, perforationLength / 2, 0));
// Convert well path to fracture template system
@ -69,7 +60,7 @@ void RigWellPathStimplanIntersector::calculate(const cvf::Mat4f &fractureXf,
// Clip well path to fracture domain
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

View File

@ -47,6 +47,7 @@ private:
static void calculate(const cvf::Mat4f& fractureXf,
const std::vector<cvf::Vec3d>& wellPathPoints,
double wellRadius,
double perforationLength,
const std::vector<std::vector<cvf::Vec3d> >& stpCellPolygons,
std::map<size_t, WellCellIntersection>& stimPlanCellIdxToIntersectionInfoMap);
@ -58,13 +59,13 @@ class RigWellPathStimplanIntersectorTester
{
public:
static void testCalculate(const cvf::Mat4f& fractureXf,
const std::vector<cvf::Vec3f>& fracturePolygon,
const std::vector<cvf::Vec3d>& wellPathPoints,
double wellRadius,
double perforationLength,
const std::vector<std::vector<cvf::Vec3d> >& stpCellPolygons,
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;
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} };
double wellRadius = 1.5;
std::vector<std::vector<cvf::Vec3d> > stpCellPolygons =
@ -329,9 +330,9 @@ TEST(RigWellPathStimplanIntersector, intersection)
std::map<size_t, RigWellPathStimplanIntersector::WellCellIntersection> stimPlanCellIdxToIntersectionInfoMap;
RigWellPathStimplanIntersectorTester::testCalculate(fractureXf,
fracturePolygon,
wellPathPoints,
wellRadius,
perforationLength,
stpCellPolygons,
stimPlanCellIdxToIntersectionInfoMap);
@ -344,11 +345,11 @@ TEST(RigWellPathStimplanIntersector, intersection)
EXPECT_EQ(1, it->second.endpointCount);
}
{
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;
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} };
RigWellPathStimplanIntersectorTester::testCalculate(fractureXf,
fracturePolygon,
wellPathPoints,
wellRadius,
perforationLength,
stpCellPolygons,
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} };
RigWellPathStimplanIntersectorTester::testCalculate(fractureXf,
fracturePolygon,
wellPathPoints,
wellRadius,
perforationLength,
stpCellPolygons,
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}};
RigWellPathStimplanIntersectorTester::testCalculate(fractureXf,
fracturePolygon,
wellPathPoints,
wellRadius,
perforationLength,
stpCellPolygons,
stimPlanCellIdxToIntersectionInfoMap);