mirror of
https://github.com/OPM/ResInsight.git
synced 2025-02-25 18:55:39 -06:00
#3630 Implement volume calculation on grid
This commit is contained in:
@@ -961,6 +961,12 @@ void RigCaseCellResultsData::createPlaceholderResultEntries()
|
||||
}
|
||||
}
|
||||
|
||||
// Cell Volume
|
||||
{
|
||||
addStaticScalarResult(RiaDefines::STATIC_NATIVE, RiaDefines::riCellVolumeResultName(), false, 0);
|
||||
}
|
||||
|
||||
|
||||
// Mobile Pore Volume
|
||||
{
|
||||
if (findScalarResultIndex(RiaDefines::STATIC_NATIVE, "PORV") != cvf::UNDEFINED_SIZE_T)
|
||||
@@ -1140,6 +1146,10 @@ size_t RigCaseCellResultsData::findOrLoadScalarResult(RiaDefines::ResultCatType
|
||||
progressInfo.incrementProgress();
|
||||
}
|
||||
}
|
||||
else if (resultName == RiaDefines::riCellVolumeResultName())
|
||||
{
|
||||
computeCellVolumes();
|
||||
}
|
||||
else if (resultName == RiaDefines::mobilePoreVolumeName())
|
||||
{
|
||||
computeMobilePV();
|
||||
@@ -2404,6 +2414,30 @@ double RigCaseCellResultsData::darchysValue()
|
||||
return RiaEclipseUnitTools::darcysConstant(m_ownerCaseData->unitsType());
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RigCaseCellResultsData::computeCellVolumes()
|
||||
{
|
||||
size_t cellVolIdx = this->findOrCreateScalarResultIndex(RiaDefines::STATIC_NATIVE, RiaDefines::riCellVolumeResultName(), false);
|
||||
|
||||
std::vector<double>& cellVolumeResults = this->cellScalarResults(cellVolIdx)[0];
|
||||
|
||||
size_t cellResultCount = m_activeCellInfo->reservoirCellResultCount();
|
||||
cellVolumeResults.resize(cellResultCount, 0u);
|
||||
|
||||
#pragma omp parallel for
|
||||
for (int nativeResvCellIndex = 0; nativeResvCellIndex < static_cast<int>(m_ownerMainGrid->globalCellArray().size()); nativeResvCellIndex++)
|
||||
{
|
||||
size_t resultIndex = activeCellInfo()->cellResultIndex(nativeResvCellIndex);
|
||||
if (resultIndex != cvf::UNDEFINED_SIZE_T)
|
||||
{
|
||||
const RigCell& cell = m_ownerMainGrid->globalCellArray()[nativeResvCellIndex];
|
||||
cellVolumeResults[resultIndex] = cell.volume();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
|
||||
@@ -154,6 +154,7 @@ private: // from RimReservoirCellResultsStorage
|
||||
void computeCompletionTypeForTimeStep(size_t timeStep);
|
||||
double darchysValue();
|
||||
|
||||
void computeCellVolumes();
|
||||
void computeMobilePV();
|
||||
|
||||
bool isDataPresent(size_t scalarResultIndex) const;
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
|
||||
|
||||
#include "RigCell.h"
|
||||
#include "RigCellGeometryTools.h"
|
||||
#include "RigMainGrid.h"
|
||||
#include "cvfPlane.h"
|
||||
#include "cvfRay.h"
|
||||
@@ -301,6 +302,21 @@ cvf::Vec3d RigCell::faceNormalWithAreaLenght(cvf::StructGridInterface::FaceType
|
||||
( nodeCoords[m_cornerIndices[faceVertexIndices[3]]] - nodeCoords[m_cornerIndices[faceVertexIndices[1]]]);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
double RigCell::volume() const
|
||||
{
|
||||
const std::vector<cvf::Vec3d>& nodeCoords = m_hostGrid->mainGrid()->nodes();
|
||||
|
||||
std::array<cvf::Vec3d, 8> hexCorners;
|
||||
for (size_t i = 0; i < 8; ++i)
|
||||
{
|
||||
hexCorners[i] = nodeCoords.at(m_cornerIndices[i]);
|
||||
}
|
||||
return RigCellGeometryTools::calculateCellVolume(hexCorners);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// Find the intersection between the cell and the ray. The point closest to the ray origin is returned
|
||||
/// in \a intersectionPoint, while the return value is the total number of intersections with the 24 triangles
|
||||
|
||||
@@ -70,6 +70,8 @@ public:
|
||||
cvf::Vec3d center() const;
|
||||
cvf::Vec3d faceCenter(cvf::StructGridInterface::FaceType face) const;
|
||||
cvf::Vec3d faceNormalWithAreaLenght(cvf::StructGridInterface::FaceType face) const;
|
||||
double volume() const;
|
||||
|
||||
|
||||
int firstIntersectionPoint(const cvf::Ray& ray, cvf::Vec3d* intersectionPoint) const;
|
||||
bool isLongPyramidCell(double maxHeightFactor = 5, double nodeNearTolerance = 1e-3 ) const;
|
||||
|
||||
@@ -23,12 +23,64 @@
|
||||
|
||||
#include "cafHexGridIntersectionTools/cafHexGridIntersectionTools.h"
|
||||
#include "cvfBoundingBox.h"
|
||||
#include "cvfMatrix3.h"
|
||||
|
||||
#include "clipper/clipper.hpp"
|
||||
|
||||
#include <vector>
|
||||
#include <array>
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// Efficient Computation of Volume of Hexahedral Cells
|
||||
/// Jeffrey Grandy, Lawrence Livermore National Laboratory
|
||||
/// https://www.osti.gov/servlets/purl/632793/
|
||||
///
|
||||
/// Note that in the paper the following vertex numbering is used
|
||||
/// 6---------7
|
||||
/// /| /| |k
|
||||
/// / | / | | /j
|
||||
/// 4---------5 | |/
|
||||
/// | 2------|--3 *---i
|
||||
/// | / | /
|
||||
/// |/ |/
|
||||
/// 0---------1
|
||||
///
|
||||
/// While in ResInsight, this is the numbering. Thus 2<->3, 6<->7 from the paper.
|
||||
/// Note the negative k!
|
||||
/// 7---------6
|
||||
/// /| /| |-k
|
||||
/// / | / | | /j
|
||||
/// 4---------5 | |/
|
||||
/// | 3------|--2 *---i
|
||||
/// | / | /
|
||||
/// |/ |/
|
||||
/// 0---------1
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
double RigCellGeometryTools::calculateCellVolume(const std::array<cvf::Vec3d, 8>& x)
|
||||
{
|
||||
// 6 * 3 flops = 18 flops
|
||||
|
||||
// Perform index swap when retrieving corners but keep indices in variable names matching paper.
|
||||
cvf::Vec3d x3mx0 = x[6] - x[4]; // Swap 3->2, then negate z by 2->6 and 0->4
|
||||
cvf::Vec3d x5mx0 = x[1] - x[4]; // Negate z by Swap 5->1 and 0->4
|
||||
cvf::Vec3d x6mx0 = x[3] - x[4]; // Swap 6->7, then negate z by 7->3 and 0->4
|
||||
cvf::Vec3d x7mx1 = x[2] - x[5]; // Swap 7->6, then negate z by 6->2 and 1->5
|
||||
cvf::Vec3d x7mx2 = x[2] - x[7]; // Swap 7->6, 2->3, then negate z by 6->2 and 3->7
|
||||
cvf::Vec3d x7mx4 = x[2] - x[0]; // Swap 7->6 then negate z by 6->2 and 4->0
|
||||
|
||||
// 3 flops for summation + 5 for dot product + 9 flops for cross product = 17 flops
|
||||
double det1 = (x7mx1 + x6mx0) * (x7mx2 ^ x3mx0);
|
||||
// 3 flops for summation + 5 for dot product + 9 flops for cross product = 17 flops
|
||||
double det2 = x6mx0 * ((x7mx2 + x5mx0) ^ x7mx4);
|
||||
// 3 flops for summation + 5 for dot product + 9 flops for cross product = 17 flops
|
||||
double det3 = x7mx1 * (x5mx0 ^ (x7mx4 + x3mx0));
|
||||
|
||||
// 2 flops for summation + 1 for division = 3 flops
|
||||
double volume = (det1 + det2 + det3) / 12.0;
|
||||
CVF_ASSERT(volume > 0.0);
|
||||
return volume;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
class RigCellGeometryTools
|
||||
{
|
||||
public:
|
||||
static double calculateCellVolume(const std::array<cvf::Vec3d, 8>& hexCorners);
|
||||
|
||||
static void createPolygonFromLineSegments(std::list<std::pair<cvf::Vec3d, cvf::Vec3d>> &intersectionLineSegments, std::vector<std::vector<cvf::Vec3d>> &polygons);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user