Well CF Visualization: Add viz of connection factors on sim wells

This commit is contained in:
Magne Sjaastad 2018-04-05 13:54:15 +02:00
parent c0054cff91
commit 9b0427aba9
9 changed files with 341 additions and 51 deletions

View File

@ -42,6 +42,7 @@ ${CMAKE_CURRENT_LIST_DIR}/Riv3dWellLogCurveGeomertyGenerator.h
${CMAKE_CURRENT_LIST_DIR}/RivWellConnectionFactorPartMgr.h
${CMAKE_CURRENT_LIST_DIR}/RivWellConnectionFactorGeometryGenerator.h
${CMAKE_CURRENT_LIST_DIR}/RivWellConnectionSourceInfo.h
${CMAKE_CURRENT_LIST_DIR}/RivSimWellConnectionSourceInfo.h
${CMAKE_CURRENT_LIST_DIR}/Riv3dWellLogGridGeomertyGenerator.h
)
@ -83,6 +84,7 @@ ${CMAKE_CURRENT_LIST_DIR}/Riv3dWellLogCurveGeomertyGenerator.cpp
${CMAKE_CURRENT_LIST_DIR}/RivWellConnectionFactorPartMgr.cpp
${CMAKE_CURRENT_LIST_DIR}/RivWellConnectionFactorGeometryGenerator.cpp
${CMAKE_CURRENT_LIST_DIR}/RivWellConnectionSourceInfo.cpp
${CMAKE_CURRENT_LIST_DIR}/RivSimWellConnectionSourceInfo.cpp
${CMAKE_CURRENT_LIST_DIR}/Riv3dWellLogGridGeomertyGenerator.cpp
)

View File

@ -0,0 +1,60 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2018 Statoil ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RivSimWellConnectionSourceInfo.h"
#include "RimSimWellInView.h"
#include "RivWellConnectionFactorGeometryGenerator.h"
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RivSimWellConnectionSourceInfo::RivSimWellConnectionSourceInfo(RimSimWellInView* simWellInView,
RivWellConnectionFactorGeometryGenerator* geometryGenerator)
: m_simWellInView(simWellInView)
, m_geometryGenerator(geometryGenerator)
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimSimWellInView* RivSimWellConnectionSourceInfo::simWellInView() const
{
return m_simWellInView;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
size_t RivSimWellConnectionSourceInfo::globalCellIndexFromTriangleIndex(cvf::uint triangleIndex) const
{
if (m_geometryGenerator.isNull()) return 0;
return m_geometryGenerator->globalCellIndexFromTriangleIndex(triangleIndex);
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
double RivSimWellConnectionSourceInfo::connectionFactorFromTriangleIndex(cvf::uint triangleIndex) const
{
if (m_geometryGenerator.isNull()) return 0.0;
return m_geometryGenerator->connectionFactor(triangleIndex);
}

View File

@ -0,0 +1,47 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2018 Statoil ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "cafPdmPointer.h"
#include "cvfBase.h"
#include "cvfObject.h"
#include <vector>
class RimSimWellInView;
class RivWellConnectionFactorGeometryGenerator;
//==================================================================================================
///
//==================================================================================================
class RivSimWellConnectionSourceInfo : public cvf::Object
{
public:
explicit RivSimWellConnectionSourceInfo(RimSimWellInView* simWellInView, RivWellConnectionFactorGeometryGenerator* geometryGenerator);
RimSimWellInView* simWellInView() const;
size_t globalCellIndexFromTriangleIndex(cvf::uint triangleIndex) const;
double connectionFactorFromTriangleIndex(cvf::uint triangleIndex) const;
private:
caf::PdmPointer<RimSimWellInView> m_simWellInView;
cvf::ref<RivWellConnectionFactorGeometryGenerator> m_geometryGenerator;
};

View File

@ -20,16 +20,29 @@
#include "RivSimWellPipesPartMgr.h"
#include "RiaExtractionTools.h"
#include "RigEclipseWellLogExtractor.h"
#include "RigVirtualPerforationTransmissibilities.h"
#include "RigWellLogExtractor.h"
#include "RigWellPath.h"
#include "Rim3dView.h"
#include "RimEclipseView.h"
#include "RimLegendConfig.h"
#include "RimSimWellInView.h"
#include "RimSimWellInViewCollection.h"
#include "RimVirtualPerforationResults.h"
#include "RivPipeGeometryGenerator.h"
#include "RivSimWellPipeSourceInfo.h"
#include "RivSectionFlattner.h"
#include "RivSimWellConnectionSourceInfo.h"
#include "RivSimWellPipeSourceInfo.h"
#include "RivWellConnectionFactorGeometryGenerator.h"
#include "RivWellConnectionSourceInfo.h"
#include "cafEffectGenerator.h"
#include "cafDisplayCoordTransform.h"
#include "cafEffectGenerator.h"
#include "cvfDrawableGeo.h"
#include "cvfModelBasicList.h"
@ -74,7 +87,7 @@ void RivSimWellPipesPartMgr::appendDynamicGeometryPartsToModel(cvf::ModelBasicLi
if (!m_rimWell->isWellPipeVisible(frameIndex)) return;
buildWellPipeParts(displayXf, false, 0.0, -1);
buildWellPipeParts(displayXf, false, 0.0, -1, frameIndex);
std::list<RivPipeBranchData>::iterator it;
for (it = m_wellBranches.begin(); it != m_wellBranches.end(); ++it)
@ -88,6 +101,11 @@ void RivSimWellPipesPartMgr::appendDynamicGeometryPartsToModel(cvf::ModelBasicLi
{
model->addPart(it->m_centerLinePart.p());
}
if (it->m_connectionFactorsPart.notNull())
{
model->addPart(it->m_connectionFactorsPart.p());
}
}
}
@ -104,7 +122,7 @@ void RivSimWellPipesPartMgr::appendFlattenedDynamicGeometryPartsToModel(cvf::Mod
if (!m_rimWell->isWellPipeVisible(frameIndex)) return;
buildWellPipeParts(displayXf, true, flattenedIntersectionExtentLength, branchIndex);
buildWellPipeParts(displayXf, true, flattenedIntersectionExtentLength, branchIndex, frameIndex);
std::list<RivPipeBranchData>::iterator it;
for (it = m_wellBranches.begin(); it != m_wellBranches.end(); ++it)
@ -127,7 +145,8 @@ void RivSimWellPipesPartMgr::appendFlattenedDynamicGeometryPartsToModel(cvf::Mod
void RivSimWellPipesPartMgr::buildWellPipeParts(const caf::DisplayCoordTransform* displayXf,
bool doFlatten,
double flattenedIntersectionExtentLength,
int branchIndex)
int branchIndex,
size_t frameIndex)
{
if (!this->viewWithSettings()) return;
@ -237,9 +256,91 @@ void RivSimWellPipesPartMgr::buildWellPipeParts(const caf::DisplayCoordTransform
pbd.m_largeSurfaceDrawable = pbd.m_pipeGeomGenerator->createPipeSurface();
}
pbd.m_connectionFactorGeometryGenerator = nullptr;
pbd.m_connectionFactorsPart = nullptr;
RimEclipseView* eclipseView = nullptr;
m_rimWell->firstAncestorOrThisOfType(eclipseView);
if (eclipseView && eclipseView->isVirtualConnectionFactorGeometryVisible())
{
RigSimWellData* simWellData = m_rimWell->simWellData();
if (simWellData && simWellData->hasWellResult(frameIndex))
{
const RigWellResultFrame& wResFrame = simWellData->wellResultFrame(frameIndex);
std::vector<CompletionVizData> completionVizDataItems;
RimVirtualPerforationResults* virtualPerforationResult = eclipseView->virtualPerforationResult();
{
auto wellPaths = m_rimWell->wellPipeBranches();
const RigWellPath* wellPath = wellPaths[brIdx];
RigEclipseWellLogExtractor* extractor = RiaExtractionTools::findOrCreateSimWellExtractor(m_rimWell, wellPath);
if (extractor)
{
std::vector<WellPathCellIntersectionInfo> wellPathCellIntersections = extractor->cellIntersectionInfosAlongWellPath();
for (const auto& intersectionInfo : wellPathCellIntersections)
{
size_t globalCellIndex = intersectionInfo.globCellIndex;
for (const auto& wellResultPoint : pbd.m_cellIds)
{
if (wellResultPoint.m_gridCellIndex == globalCellIndex)
{
double startMD = intersectionInfo.startMD;
double endMD = intersectionInfo.endMD;
double middleMD = (startMD + endMD) / 2.0;
cvf::Vec3d defaultLocationInDomainCoord = wellPath->interpolatedPointAlongWellPath(middleMD);
cvf::Vec3d p1;
cvf::Vec3d p2;
wellPath->twoClosestPoints(defaultLocationInDomainCoord, &p1, &p2);
cvf::Vec3d defaultWellPathDirection = (p2 - p1).getNormalized();
cvf::Vec3d anchor = displayXf->transformToDisplayCoord(defaultLocationInDomainCoord);;
const RigWellResultPoint* wResCell = wResFrame.findResultCell(wellResultPoint.m_gridIndex, wellResultPoint.m_gridCellIndex);
if (wResCell && wResCell->m_isOpen)
{
CompletionVizData data(anchor, defaultWellPathDirection, wResCell->connectionFactor(), globalCellIndex);
completionVizDataItems.push_back(data);
}
}
}
}
}
}
if (!completionVizDataItems.empty())
{
double radius = pipeRadius * virtualPerforationResult->geometryScaleFactor();
radius *= 2.0; // Enlarge the radius slightly to make the connection factor visible if geometry scale factor is set to 1.0
pbd.m_connectionFactorGeometryGenerator = new RivWellConnectionFactorGeometryGenerator(completionVizDataItems, radius);
cvf::ScalarMapper* scalarMapper = virtualPerforationResult->legendConfig()->scalarMapper();
cvf::ref<cvf::Part> part = pbd.m_connectionFactorGeometryGenerator->createSurfacePart(scalarMapper, eclipseView->isLightingDisabled());
if (part.notNull())
{
cvf::ref<RivSimWellConnectionSourceInfo> sourceInfo = new RivSimWellConnectionSourceInfo(m_rimWell, pbd.m_connectionFactorGeometryGenerator.p());
part->setSourceInfo(sourceInfo.p());
}
pbd.m_connectionFactorsPart = part;
}
}
}
if (doFlatten) flattenedStartOffset += { 2*flattenedIntersectionExtentLength, 0.0, 0.0};
}
}
//--------------------------------------------------------------------------------------------------

View File

@ -43,6 +43,7 @@ namespace caf
class RivPipeGeometryGenerator;
class Rim3dView;
class RimSimWellInView;
class RivWellConnectionFactorGeometryGenerator;
class RivSimWellPipesPartMgr : public cvf::Object
{
@ -70,7 +71,8 @@ private:
void buildWellPipeParts(const caf::DisplayCoordTransform* displayXf,
bool doFlatten,
double flattenedIntersectionExtentLength,
int branchIndex);
int branchIndex,
size_t frameIndex);
caf::PdmPointer<RimSimWellInView> m_rimWell;
@ -85,6 +87,8 @@ private:
cvf::ref<cvf::Part> m_centerLinePart;
cvf::ref<cvf::DrawableGeo> m_centerLineDrawable;
cvf::ref<RivWellConnectionFactorGeometryGenerator> m_connectionFactorGeometryGenerator;
cvf::ref<cvf::Part> m_connectionFactorsPart;
};
std::list<RivPipeBranchData> m_wellBranches;

View File

@ -18,17 +18,20 @@
#include "RivWellConnectionFactorGeometryGenerator.h"
#include "cafEffectGenerator.h"
#include "cvfArray.h"
#include "cvfDrawableGeo.h"
#include "cvfPart.h"
#include "cvfPrimitiveSetIndexedUInt.h"
#include "cvfScalarMapper.h"
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RivWellConnectionFactorGeometryGenerator::RivWellConnectionFactorGeometryGenerator(
std::vector<CompletionVizData>& centerColorPairs,
std::vector<CompletionVizData>& completionVizData,
float radius)
: m_completionVizData(centerColorPairs)
: m_completionVizData(completionVizData)
, m_radius(radius)
, m_trianglesPerConnection(0)
{
@ -39,6 +42,56 @@ RivWellConnectionFactorGeometryGenerator::RivWellConnectionFactorGeometryGenerat
//--------------------------------------------------------------------------------------------------
RivWellConnectionFactorGeometryGenerator::~RivWellConnectionFactorGeometryGenerator() {}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
cvf::ref<cvf::Part> RivWellConnectionFactorGeometryGenerator::createSurfacePart(const cvf::ScalarMapper* scalarMapper, bool disableLighting)
{
if (!scalarMapper) return nullptr;
cvf::ref<cvf::DrawableGeo> drawable = createSurfaceGeometry();
if (drawable.notNull())
{
cvf::ref<cvf::Part> part = new cvf::Part;
part->setDrawable(drawable.p());
// Compute texture coords
cvf::ref<cvf::Vec2fArray> textureCoords = new cvf::Vec2fArray();
{
textureCoords->reserve(drawable->vertexArray()->size());
size_t verticesPerItem = drawable->vertexArray()->size() / m_completionVizData.size();
textureCoords->setAll(cvf::Vec2f(0.5f, 1.0f));
for (const auto& item : m_completionVizData)
{
cvf::Vec2f textureCoord = cvf::Vec2f(0.5f, 1.0f);
if (item.m_connectionFactor != HUGE_VAL)
{
textureCoord = scalarMapper->mapToTextureCoord(item.m_connectionFactor);
}
for (size_t i = 0; i < verticesPerItem; i++)
{
textureCoords->add(textureCoord);
}
}
}
drawable->setTextureCoordArray(textureCoords.p());
caf::ScalarMapperEffectGenerator effGen(scalarMapper, caf::PO_1);
effGen.disableLighting(disableLighting);
cvf::ref<cvf::Effect> eff = effGen.generateCachedEffect();
part->setEffect(eff.p());
return part;
}
return nullptr;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------

View File

@ -28,6 +28,8 @@
namespace cvf
{
class DrawableGeo;
class Part;
class ScalarMapper;
} // namespace cvf
//--------------------------------------------------------------------------------------------------
@ -55,16 +57,18 @@ struct CompletionVizData
class RivWellConnectionFactorGeometryGenerator : public cvf::Object
{
public:
RivWellConnectionFactorGeometryGenerator(std::vector<CompletionVizData>& centerColorPairs, float radius);
RivWellConnectionFactorGeometryGenerator(std::vector<CompletionVizData>& completionVizData, float radius);
~RivWellConnectionFactorGeometryGenerator();
cvf::ref<cvf::DrawableGeo> createSurfaceGeometry();
cvf::ref<cvf::Part> createSurfacePart(const cvf::ScalarMapper* scalarMapper, bool disableLighting);
double connectionFactor(cvf::uint triangleIndex) const;
size_t globalCellIndexFromTriangleIndex(cvf::uint triangleIndex) const;
private:
size_t mapFromTriangleToConnectionIndex(cvf::uint triangleIndex) const;
cvf::ref<cvf::DrawableGeo> createSurfaceGeometry();
static cvf::Mat4f rotationMatrixBetweenVectors(const cvf::Vec3d& v1, const cvf::Vec3d& v2);
static void
createStarGeometry(std::vector<cvf::Vec3f>* vertices, std::vector<cvf::uint>* indices, float radius, float thickness);

View File

@ -149,52 +149,21 @@ void RivWellConnectionFactorPartMgr::appendDynamicGeometryPartsToModel(cvf::Mode
if (!completionVizDataItems.empty())
{
double radius = mainGrid->characteristicIJCellSize() * m_virtualPerforationResult->geometryScaleFactor();
double characteristicCellSize = eclView->ownerCase()->characteristicCellSize();
double radius = m_rimWell->wellPathRadius(characteristicCellSize) * m_virtualPerforationResult->geometryScaleFactor();
radius *= 2.0; // Enlarge the radius slightly to make the connection factor visible if geometry scale factor is set to 1.0
m_geometryGenerator = new RivWellConnectionFactorGeometryGenerator(completionVizDataItems, radius);
auto drawable = m_geometryGenerator->createSurfaceGeometry();
cvf::ref<cvf::Part> part = new cvf::Part;
part->setDrawable(drawable.p());
auto scalarMapper = m_virtualPerforationResult->legendConfig()->scalarMapper();
// Compute texture coords
cvf::ref<cvf::Vec2fArray> textureCoords = new cvf::Vec2fArray();
cvf::ref<cvf::Part> part = m_geometryGenerator->createSurfacePart(scalarMapper, eclView->isLightingDisabled());
if (part.notNull())
{
textureCoords->reserve(drawable->vertexArray()->size());
size_t verticesPerItem = drawable->vertexArray()->size() / completionVizDataItems.size();
cvf::ref<RivWellConnectionSourceInfo> sourceInfo = new RivWellConnectionSourceInfo(m_rimWell, m_geometryGenerator.p());
part->setSourceInfo(sourceInfo.p());
textureCoords->setAll(cvf::Vec2f(0.5f, 1.0f));
for (const auto& item : completionVizDataItems)
{
cvf::Vec2f textureCoord = cvf::Vec2f(0.5f, 1.0f);
if (item.m_connectionFactor != HUGE_VAL)
{
textureCoord = scalarMapper->mapToTextureCoord(item.m_connectionFactor);
}
for (size_t i = 0; i < verticesPerItem; i++)
{
textureCoords->add(textureCoord);
}
}
model->addPart(part.p());
}
drawable->setTextureCoordArray(textureCoords.p());
caf::ScalarMapperEffectGenerator effGen(scalarMapper, caf::PO_1);
bool disableLighting = eclView->isLightingDisabled();
effGen.disableLighting(disableLighting);
cvf::ref<cvf::Effect> eff = effGen.generateCachedEffect();
part->setEffect(eff.p());
cvf::ref<RivWellConnectionSourceInfo> sourceInfo = new RivWellConnectionSourceInfo(m_rimWell, m_geometryGenerator.p());
part->setSourceInfo(sourceInfo.p());
model->addPart(part.p());
}
}

View File

@ -71,12 +71,14 @@
#include "RivIntersectionBoxSourceInfo.h"
#include "RivIntersectionSourceInfo.h"
#include "RivObjectSourceInfo.h"
#include "RivSimWellConnectionSourceInfo.h"
#include "RivSimWellPipeSourceInfo.h"
#include "RivSourceInfo.h"
#include "RivTernarySaturationOverlayItem.h"
#include "RivWellConnectionSourceInfo.h"
#include "RivWellFracturePartMgr.h"
#include "RivWellPathSourceInfo.h"
#include "cafCmdExecCommandManager.h"
#include "cafCmdFeatureManager.h"
#include "cafCmdFeatureMenuBuilder.h"
@ -690,6 +692,54 @@ void RiuViewerCommands::handlePickAction(int winPosX, int winPosY, Qt::KeyboardM
RiuMainWindow::instance()->selectAsCurrentItem(wellConnectionSourceInfo->wellPath(), allowActiveViewChange);
}
else if (dynamic_cast<const RivSimWellConnectionSourceInfo*>(firstHitPart->sourceInfo()))
{
const RivSimWellConnectionSourceInfo* simWellConnectionSourceInfo = dynamic_cast<const RivSimWellConnectionSourceInfo*>(firstHitPart->sourceInfo());
bool allowActiveViewChange = dynamic_cast<Rim2dIntersectionView*>(m_viewer->ownerViewWindow()) == nullptr;
size_t globalCellIndex = simWellConnectionSourceInfo->globalCellIndexFromTriangleIndex(firstPartTriangleIndex);
double connectionFactor = simWellConnectionSourceInfo->connectionFactorFromTriangleIndex(firstPartTriangleIndex);
RimEclipseView* eclipseView = dynamic_cast<RimEclipseView*>(m_reservoirView.p());
if (eclipseView)
{
RimEclipseCase* eclipseCase = nullptr;
eclipseView->firstAncestorOrThisOfTypeAsserted(eclipseCase);
if (eclipseCase->eclipseCaseData() &&
eclipseCase->eclipseCaseData()->virtualPerforationTransmissibilities())
{
auto connectionFactors = eclipseCase->eclipseCaseData()->virtualPerforationTransmissibilities();
size_t timeStep = eclipseView->currentTimeStep();
const auto& completionData = connectionFactors->completionsForSimWell(simWellConnectionSourceInfo->simWellInView()->simWellData(), timeStep);
for (const auto& compData : completionData)
{
if (compData.completionDataGridCell().globalCellIndex() == globalCellIndex)
{
{
QString resultInfoText = QString("<b>Simulation Well Connection Factor :</b> %1<br><br>").arg(connectionFactor);
{
RiuResultTextBuilder textBuilder(eclipseView, globalCellIndex, eclipseView->currentTimeStep());
resultInfoText += textBuilder.geometrySelectionText("<br>");
}
RiuMainWindow::instance()->setResultInfo(resultInfoText);
}
break;
}
}
}
}
RiuMainWindow::instance()->selectAsCurrentItem(simWellConnectionSourceInfo->simWellInView(), allowActiveViewChange);
}
}
if (firstNncHitPart && firstNncHitPart->sourceInfo())