mirror of
https://github.com/OPM/ResInsight.git
synced 2025-01-01 03:37:15 -06:00
354 lines
18 KiB
C++
354 lines
18 KiB
C++
/////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Copyright (C) 2016- 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 "RivWellConnectionsPartMgr.h"
|
|
|
|
#include "RimEclipseResultCase.h"
|
|
#include "RimEclipseView.h"
|
|
#include "RimSimWellInView.h"
|
|
#include "RimSimWellInViewCollection.h"
|
|
|
|
#include "RigActiveCellInfo.h"
|
|
#include "RigEclipseCaseData.h"
|
|
#include "RigFlowDiagResults.h"
|
|
#include "RigMainGrid.h"
|
|
#include "Well/RigSimWellData.h"
|
|
#include "Well/RigWellResultFrame.h"
|
|
|
|
#include "cafDisplayCoordTransform.h"
|
|
#include "cafEffectGenerator.h"
|
|
|
|
#include "cvfDrawableGeo.h"
|
|
#include "cvfModelBasicList.h"
|
|
#include "cvfPart.h"
|
|
|
|
#include <cmath>
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
RivWellConnectionsPartMgr::RivWellConnectionsPartMgr( RimEclipseView* reservoirView, RimSimWellInView* well )
|
|
{
|
|
m_rimReservoirView = reservoirView;
|
|
m_rimWell = well;
|
|
m_useCurvedArrows = true;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
RivWellConnectionsPartMgr::~RivWellConnectionsPartMgr()
|
|
{
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RivWellConnectionsPartMgr::appendDynamicGeometryPartsToModel( cvf::ModelBasicList* model, size_t frameIndex )
|
|
{
|
|
if ( m_rimReservoirView.isNull() ) return;
|
|
if ( !m_rimReservoirView->eclipseCase() ) return;
|
|
if ( !m_rimWell->showWell() ) return;
|
|
if ( !m_rimWell->simWellData()->hasWellResult( frameIndex ) ) return;
|
|
if ( !m_rimWell->simWellData()->wellResultFrame( frameIndex )->isOpen() ) return;
|
|
if ( m_rimWell->simWellData()->wellResultFrame( frameIndex )->productionType() == RiaDefines::WellProductionType::UNDEFINED_PRODUCTION_TYPE )
|
|
return;
|
|
|
|
bool isProducer = ( m_rimWell->simWellData()->wellResultFrame( frameIndex )->productionType() == RiaDefines::WellProductionType::PRODUCER );
|
|
double pipeRadius = m_rimWell->pipeRadius();
|
|
|
|
cvf::Vec3d wellHeadTop;
|
|
cvf::Vec3d wellHeadBottom;
|
|
double characteristicCellSize;
|
|
double mainArrowZHeight;
|
|
cvf::ref<caf::DisplayCoordTransform> displayCordXf;
|
|
RigFlowDiagResults* flowResults;
|
|
|
|
std::string injectorName;
|
|
std::string producerName;
|
|
std::string crossFlowInjectorName;
|
|
std::string crossFlowProducerName;
|
|
|
|
double fluxWidthScale = 0.0;
|
|
|
|
{
|
|
RimEclipseResultCase* eclResCase = dynamic_cast<RimEclipseResultCase*>( m_rimReservoirView->eclipseCase() );
|
|
if ( !eclResCase ) return;
|
|
|
|
if ( !eclResCase->defaultFlowDiagSolution() ) return;
|
|
|
|
flowResults = eclResCase->defaultFlowDiagSolution()->flowDiagResults();
|
|
displayCordXf = m_rimReservoirView->displayCoordTransform();
|
|
RigEclipseCaseData* rigReservoir = m_rimReservoirView->eclipseCase()->eclipseCaseData();
|
|
|
|
characteristicCellSize = rigReservoir->mainGrid()->characteristicIJCellSize();
|
|
|
|
m_rimWell->wellHeadTopBottomPosition( static_cast<int>( frameIndex ), &wellHeadTop, &wellHeadBottom );
|
|
wellHeadTop = displayCordXf->transformToDisplayCoord( wellHeadTop );
|
|
wellHeadBottom = displayCordXf->transformToDisplayCoord( wellHeadBottom );
|
|
wellHeadTop.z() += characteristicCellSize;
|
|
|
|
cvf::Vec3d activeCellsBoundingBoxMax =
|
|
displayCordXf->transformToDisplayCoord( m_rimReservoirView->currentActiveCellInfo()->geometryBoundingBox().max() );
|
|
mainArrowZHeight = activeCellsBoundingBoxMax.z() + 1.5 * characteristicCellSize; // Above the bbox somewhat;
|
|
|
|
if ( isProducer )
|
|
{
|
|
producerName = m_rimWell->name().toStdString();
|
|
crossFlowInjectorName = RimFlowDiagSolution::addCrossFlowEnding( m_rimWell->name() ).toStdString();
|
|
}
|
|
else
|
|
{
|
|
injectorName = m_rimWell->name().toStdString();
|
|
crossFlowProducerName = RimFlowDiagSolution::addCrossFlowEnding( m_rimWell->name() ).toStdString();
|
|
}
|
|
|
|
double maxAbsFlux = flowResults->maxAbsPairFlux( static_cast<int>( frameIndex ) );
|
|
if ( maxAbsFlux != 0.0 ) fluxWidthScale = characteristicCellSize / maxAbsFlux;
|
|
}
|
|
|
|
bool enableLighting = !m_rimReservoirView->isLightingDisabled();
|
|
RimSimWellInViewCollection* wellColl = m_rimReservoirView->wellCollection();
|
|
|
|
// Create potentially two the arrows to/from m_rimWell for each of the other wells in the model.
|
|
// One arrow for the "official" state of the well, and one to account for cross flow contributions
|
|
|
|
for ( RimSimWellInView* otherWell : wellColl->wells )
|
|
{
|
|
if ( otherWell == m_rimWell ) continue;
|
|
if ( !otherWell->simWellData()->hasWellResult( frameIndex ) ) continue;
|
|
if ( !otherWell->simWellData()->wellResultFrame( frameIndex )->isOpen() ) continue;
|
|
if ( otherWell->simWellData()->wellResultFrame( frameIndex )->productionType() ==
|
|
RiaDefines::WellProductionType::UNDEFINED_PRODUCTION_TYPE )
|
|
continue;
|
|
|
|
bool isOtherProducer =
|
|
( otherWell->simWellData()->wellResultFrame( frameIndex )->productionType() == RiaDefines::WellProductionType::PRODUCER );
|
|
|
|
{
|
|
std::string otherWellName = otherWell->name().toStdString();
|
|
std::string otherWellXfName = RimFlowDiagSolution::addCrossFlowEnding( otherWell->name() ).toStdString();
|
|
|
|
if ( isProducer != isOtherProducer )
|
|
{
|
|
if ( isOtherProducer )
|
|
{
|
|
producerName = otherWellName;
|
|
crossFlowInjectorName = otherWellXfName;
|
|
}
|
|
else
|
|
{
|
|
injectorName = otherWellName;
|
|
crossFlowProducerName = otherWellXfName;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( isProducer )
|
|
{
|
|
injectorName = otherWellXfName;
|
|
crossFlowProducerName = otherWellName;
|
|
}
|
|
else
|
|
{
|
|
producerName = otherWellXfName;
|
|
crossFlowInjectorName = otherWellName;
|
|
}
|
|
}
|
|
}
|
|
|
|
std::pair<double, double> injProdFluxPair =
|
|
flowResults->injectorProducerPairFluxes( injectorName, producerName, static_cast<int>( frameIndex ) );
|
|
std::pair<double, double> injProdFluxPairXF =
|
|
flowResults->injectorProducerPairFluxes( crossFlowInjectorName, crossFlowProducerName, static_cast<int>( frameIndex ) );
|
|
|
|
const double fluxThreshold = 0.0; // Todo : Needs threshold in Gui
|
|
|
|
if ( fabs( injProdFluxPair.first ) <= fluxThreshold && fabs( injProdFluxPair.second ) <= fluxThreshold &&
|
|
fabs( injProdFluxPairXF.first ) <= fluxThreshold && fabs( injProdFluxPairXF.second ) <= fluxThreshold )
|
|
continue;
|
|
|
|
float width = fluxWidthScale * ( isProducer ? injProdFluxPair.second : injProdFluxPair.first );
|
|
float widthXf = fluxWidthScale * ( !isProducer ? injProdFluxPairXF.second : injProdFluxPairXF.first );
|
|
|
|
cvf::Vec3d otherWellHeadTop;
|
|
cvf::Vec3d otherWellHeadBottom;
|
|
{
|
|
otherWell->wellHeadTopBottomPosition( static_cast<int>( frameIndex ), &otherWellHeadTop, &otherWellHeadBottom );
|
|
otherWellHeadTop = displayCordXf->transformToDisplayCoord( otherWellHeadTop );
|
|
otherWellHeadBottom = displayCordXf->transformToDisplayCoord( otherWellHeadBottom );
|
|
otherWellHeadTop.z() += characteristicCellSize;
|
|
}
|
|
|
|
{
|
|
cvf::Vec3f startPoint = cvf::Vec3f( 0.5 * ( wellHeadTop + otherWellHeadTop ) );
|
|
if ( m_useCurvedArrows ) startPoint.z() = mainArrowZHeight;
|
|
cvf::Vec3f endPoint = cvf::Vec3f( wellHeadTop + ( 3 * pipeRadius * ( otherWellHeadTop - wellHeadTop ).getNormalized() ) );
|
|
cvf::Color4f arrowColor( otherWell->wellPipeColor() );
|
|
|
|
if ( fabs( injProdFluxPair.first ) > fluxThreshold && fabs( injProdFluxPair.second ) > fluxThreshold )
|
|
{
|
|
if ( isProducer == isOtherProducer )
|
|
{
|
|
startPoint.z() -= 0.5 * characteristicCellSize;
|
|
endPoint.z() -= 0.5 * characteristicCellSize;
|
|
}
|
|
cvf::ref<cvf::Part> arrowPart = createArrowPart( startPoint, endPoint, width, isProducer, arrowColor, enableLighting );
|
|
model->addPart( arrowPart.p() );
|
|
}
|
|
|
|
if ( fabs( injProdFluxPairXF.first ) > fluxThreshold && fabs( injProdFluxPairXF.second ) > fluxThreshold )
|
|
{
|
|
startPoint.z() -= 0.5 * characteristicCellSize;
|
|
endPoint.z() -= 0.5 * characteristicCellSize;
|
|
cvf::ref<cvf::Part> arrowPart = createArrowPart( startPoint, endPoint, widthXf, !isProducer, arrowColor, enableLighting );
|
|
model->addPart( arrowPart.p() );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
cvf::ref<cvf::Part> RivWellConnectionsPartMgr::createArrowPart( const cvf::Vec3f& startPoint,
|
|
const cvf::Vec3f& endPoint,
|
|
float width,
|
|
bool isProducer,
|
|
const cvf::Color4f& arrowColor,
|
|
bool enableLighting )
|
|
{
|
|
cvf::ref<cvf::Part> part = new cvf::Part;
|
|
part->setName( "RivWellConnectionsPartMgr::createArrowPart" );
|
|
|
|
cvf::ref<cvf::DrawableGeo> geo = createArrowGeometry( startPoint, endPoint, width, isProducer );
|
|
|
|
part->setDrawable( geo.p() );
|
|
caf::SurfaceEffectGenerator surfaceGen( arrowColor, caf::PO_1 );
|
|
surfaceGen.enableLighting( enableLighting );
|
|
|
|
cvf::ref<cvf::Effect> eff = surfaceGen.generateCachedEffect();
|
|
|
|
part->setEffect( eff.p() );
|
|
|
|
return part;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
cvf::ref<cvf::DrawableGeo>
|
|
RivWellConnectionsPartMgr::createArrowGeometry( const cvf::Vec3f& startPoint, const cvf::Vec3f& endPoint, double width, bool useArrowEnd )
|
|
{
|
|
// Vertex layout
|
|
// _ - _
|
|
// __________ - - _
|
|
// - Producer end: Injector end
|
|
// 0 2 4 6 8 10 20 12 14 16 16
|
|
// : flat : : : : : : : : end 18 18
|
|
// 1 3 5 7 9 11 19 13 15 17 17
|
|
|
|
static const cvf::uint producerArrowFaceList[8 * 5 + 4] = { 4, 0, 1, 3, 2, 4, 2, 3, 5, 4, 4, 4, 5, 7, 6,
|
|
4, 6, 7, 9, 8, 4, 8, 9, 11, 10, 4, 10, 11, 20, 19,
|
|
4, 19, 20, 13, 12, 4, 12, 13, 15, 14, 3, 16, 17, 18 };
|
|
|
|
static const cvf::uint injectorArrowFaceList[8 * 5 + 8] = { 4, 0, 1, 3, 2, 4, 2, 3, 5, 4, 4, 4, 5, 7, 6, 4,
|
|
6, 7, 9, 8, 4, 8, 9, 11, 10, 4, 10, 11, 20, 19, 4, 19,
|
|
20, 13, 12, 4, 12, 13, 15, 14, 3, 14, 18, 16, 3, 18, 15, 17 };
|
|
|
|
cvf::Vec3f endPointInTopPlane = endPoint;
|
|
if ( m_useCurvedArrows ) endPointInTopPlane.z() = startPoint.z();
|
|
|
|
cvf::Vec3f heightDiff = cvf::Vec3f::ZERO;
|
|
if ( m_useCurvedArrows ) heightDiff.z() = ( startPoint.z() - endPoint.z() );
|
|
|
|
cvf::Vec3f fromTo = endPointInTopPlane - startPoint;
|
|
float length = fromTo.length();
|
|
|
|
float halfWidth = width * 0.5;
|
|
cvf::Vec3f widthVector = halfWidth * ( fromTo.getNormalized() ^ -cvf::Vec3f::Z_AXIS );
|
|
|
|
float heightScale = 0.3 * length * 0.15;
|
|
cvf::Vec3f heightScaleVec = cvf::Vec3f::ZERO;
|
|
|
|
if ( m_useCurvedArrows ) heightScaleVec.z() = heightScale;
|
|
|
|
float endStart = 0.4f;
|
|
float endStep = ( 1.0f - endStart ) / 7.5f;
|
|
|
|
cvf::ref<cvf::Vec3fArray> arrowVertexArray = new cvf::Vec3fArray;
|
|
arrowVertexArray->resize( 18 + 3 );
|
|
|
|
( *arrowVertexArray )[0] = 0.0f * fromTo + startPoint + widthVector;
|
|
( *arrowVertexArray )[1] = 0.0f * fromTo + startPoint - widthVector;
|
|
( *arrowVertexArray )[2] = endStart * fromTo + startPoint + widthVector;
|
|
( *arrowVertexArray )[3] = endStart * fromTo + startPoint - widthVector;
|
|
|
|
( *arrowVertexArray )[4] = ( 1 * endStep + endStart ) * fromTo + startPoint + widthVector + 0.250f * heightScaleVec; // 0.0250f *
|
|
// heightDiff;
|
|
( *arrowVertexArray )[5] = ( 1 * endStep + endStart ) * fromTo + startPoint - widthVector + 0.250f * heightScaleVec; // 0.0250f *
|
|
// heightDiff;
|
|
( *arrowVertexArray )[6] = ( 2 * endStep + endStart ) * fromTo + startPoint + widthVector + 0.750f * heightScaleVec; // 0.0750f *
|
|
// heightDiff;
|
|
( *arrowVertexArray )[7] = ( 2 * endStep + endStart ) * fromTo + startPoint - widthVector + 0.750f * heightScaleVec; // 0.0750f *
|
|
// heightDiff;
|
|
( *arrowVertexArray )[8] = ( 3 * endStep + endStart ) * fromTo + startPoint + widthVector + 1.000f * heightScaleVec; // 0.1000f *
|
|
// heightDiff;
|
|
( *arrowVertexArray )[9] = ( 3 * endStep + endStart ) * fromTo + startPoint - widthVector + 1.000f * heightScaleVec; // 0.1000f *
|
|
// heightDiff;
|
|
( *arrowVertexArray )[10] = ( 4 * endStep + endStart ) * fromTo + startPoint + widthVector + 0.875f * heightScaleVec; // 0.0875f *
|
|
// heightDiff;
|
|
( *arrowVertexArray )[11] = ( 4 * endStep + endStart ) * fromTo + startPoint - widthVector + 0.875f * heightScaleVec; // 0.0875f *
|
|
// heightDiff;
|
|
( *arrowVertexArray )[19] = ( 4.7f * endStep + endStart ) * fromTo + startPoint + widthVector + 0.400f * heightScaleVec; // 0.0875f *
|
|
// heightDiff;
|
|
( *arrowVertexArray )[20] = ( 4.7f * endStep + endStart ) * fromTo + startPoint - widthVector + 0.400f * heightScaleVec; // 0.0875f *
|
|
// heightDiff;
|
|
|
|
( *arrowVertexArray )[12] = ( 5 * endStep + endStart ) * fromTo + startPoint + widthVector;
|
|
( *arrowVertexArray )[13] = ( 5 * endStep + endStart ) * fromTo + startPoint - widthVector;
|
|
|
|
( *arrowVertexArray )[14] = ( 6 * endStep + endStart ) * fromTo + startPoint + widthVector - 0.5f * heightDiff;
|
|
( *arrowVertexArray )[15] = ( 6 * endStep + endStart ) * fromTo + startPoint - widthVector - 0.5f * heightDiff;
|
|
|
|
if ( useArrowEnd )
|
|
{
|
|
( *arrowVertexArray )[16] = ( 6 * endStep + endStart ) * fromTo + startPoint + 1.6f * widthVector - 0.5f * heightDiff;
|
|
( *arrowVertexArray )[17] = ( 6 * endStep + endStart ) * fromTo + startPoint - 1.6f * widthVector - 0.5f * heightDiff;
|
|
( *arrowVertexArray )[18] = 1.0f * fromTo + startPoint - 1.0f * heightDiff;
|
|
}
|
|
else
|
|
{
|
|
( *arrowVertexArray )[16] = 1.0f * fromTo + startPoint + 0.5f * widthVector - 1.0f * heightDiff;
|
|
( *arrowVertexArray )[17] = 1.0f * fromTo + startPoint - 0.5f * widthVector - 1.0f * heightDiff;
|
|
( *arrowVertexArray )[18] = ( 6 * endStep + endStart ) * fromTo + startPoint - 0.5f * heightDiff;
|
|
}
|
|
|
|
cvf::ref<cvf::DrawableGeo> geo = new cvf::DrawableGeo;
|
|
geo->setVertexArray( arrowVertexArray.p() );
|
|
|
|
if ( useArrowEnd )
|
|
geo->setFromFaceList( cvf::UIntArray( producerArrowFaceList, 8 * 5 + 4 ) );
|
|
else
|
|
geo->setFromFaceList( cvf::UIntArray( injectorArrowFaceList, 8 * 5 + 8 ) );
|
|
|
|
geo->computeNormals();
|
|
|
|
return geo;
|
|
}
|