mirror of
https://github.com/OPM/ResInsight.git
synced 2025-02-25 18:55:39 -06:00
Streamlines: New generator and UI usability improvements (#7424)
Co-authored-by: jonjenssen <jonjenssen@users.noreply.github.com> Co-authored-by: Magne Sjaastad <magne.sjaastad@ceetronsolutions.com>
This commit is contained in:
@@ -86,6 +86,7 @@ include_directories(
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/ModelVisualization
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/ModelVisualization/GridBox
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/ModelVisualization/Intersections
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/ModelVisualization/Streamlines
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/ModelVisualization/Surfaces
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/UserInterface
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/UserInterface/AnalysisPlots
|
||||
@@ -102,6 +103,7 @@ include_directories(
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/ProjectDataModel/StimPlanModel
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/ProjectDataModel/Summary
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/ProjectDataModel/Surfaces
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/ProjectDataModel/Streamlines
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/ProjectDataModel/CellFilters
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/ProjectDataModelCommands
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/ResultStatisticsCache
|
||||
@@ -164,6 +166,7 @@ list(
|
||||
ProjectDataModel/Measurement/CMakeLists_files.cmake
|
||||
ProjectDataModel/PlotTemplates/CMakeLists_files.cmake
|
||||
ProjectDataModel/StimPlanModel/CMakeLists_files.cmake
|
||||
ProjectDataModel/Streamlines/CMakeLists_files.cmake
|
||||
ProjectDataModel/Surfaces/CMakeLists_files.cmake
|
||||
ProjectDataModel/CellFilters/CMakeLists_files.cmake
|
||||
ProjectDataModelCommands/CMakeLists_files.cmake
|
||||
@@ -171,6 +174,7 @@ list(
|
||||
ModelVisualization/CMakeLists_files.cmake
|
||||
ModelVisualization/GridBox/CMakeLists_files.cmake
|
||||
ModelVisualization/Intersections/CMakeLists_files.cmake
|
||||
ModelVisualization/Streamlines/CMakeLists_files.cmake
|
||||
ModelVisualization/Surfaces/CMakeLists_files.cmake
|
||||
ModelVisualization/WindowEdgeAxesOverlayItem/CMakeLists_files.cmake
|
||||
UserInterface/CMakeLists_files.cmake
|
||||
|
@@ -32,6 +32,7 @@ set(COMMAND_REFERENCED_CMAKE_FILES
|
||||
OperationsUsingObjReferences/CMakeLists_files.cmake
|
||||
SummaryPlotCommands/CMakeLists_files.cmake
|
||||
SsiHubImportCommands/CMakeLists_files.cmake
|
||||
StreamlineCommands/CMakeLists_files.cmake
|
||||
SurfaceCommands/CMakeLists_files.cmake
|
||||
ToggleCommands/CMakeLists_files.cmake
|
||||
ViewLink/CMakeLists_files.cmake
|
||||
|
@@ -0,0 +1,18 @@
|
||||
|
||||
set (SOURCE_GROUP_HEADER_FILES
|
||||
${CMAKE_CURRENT_LIST_DIR}/RicNewStreamlineFeature.h
|
||||
)
|
||||
|
||||
set (SOURCE_GROUP_SOURCE_FILES
|
||||
${CMAKE_CURRENT_LIST_DIR}/RicNewStreamlineFeature.cpp
|
||||
)
|
||||
|
||||
list(APPEND COMMAND_CODE_HEADER_FILES
|
||||
${SOURCE_GROUP_HEADER_FILES}
|
||||
)
|
||||
|
||||
list(APPEND COMMAND_CODE_SOURCE_FILES
|
||||
${SOURCE_GROUP_SOURCE_FILES}
|
||||
)
|
||||
|
||||
source_group( "CommandFeature\\StreamlineCommands" FILES ${SOURCE_GROUP_HEADER_FILES} ${SOURCE_GROUP_SOURCE_FILES} ${CMAKE_CURRENT_LIST_DIR}/CMakeLists_files.cmake )
|
@@ -0,0 +1,62 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2020- Equinor 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 "RicNewStreamlineFeature.h"
|
||||
|
||||
#include "RimStreamlineInViewCollection.h"
|
||||
|
||||
#include "Riu3DMainWindowTools.h"
|
||||
|
||||
#include "cafSelectionManagerTools.h"
|
||||
#include "cafUtils.h"
|
||||
|
||||
#include <QAction>
|
||||
|
||||
CAF_CMD_SOURCE_INIT( RicNewStreamlineFeature, "RicNewStreamlineFeature" );
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool RicNewStreamlineFeature::isCommandEnabled()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RicNewStreamlineFeature::onActionTriggered( bool isChecked )
|
||||
{
|
||||
std::vector<RimStreamlineInViewCollection*> colls = caf::selectedObjectsByTypeStrict<RimStreamlineInViewCollection*>();
|
||||
if ( colls.empty() ) return;
|
||||
RimStreamlineInViewCollection* streamColl = colls[0];
|
||||
|
||||
if ( streamColl )
|
||||
{
|
||||
streamColl->refresh();
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RicNewStreamlineFeature::setupActionLook( QAction* actionToSetup )
|
||||
{
|
||||
actionToSetup->setIcon( QIcon( ":/Refresh-32.png" ) );
|
||||
actionToSetup->setText( "Refresh" );
|
||||
}
|
@@ -0,0 +1,35 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2020- Equinor 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 "cafCmdFeature.h"
|
||||
|
||||
//==================================================================================================
|
||||
///
|
||||
//==================================================================================================
|
||||
class RicNewStreamlineFeature : public caf::CmdFeature
|
||||
{
|
||||
CAF_CMD_HEADER_INIT;
|
||||
|
||||
protected:
|
||||
// Overrides
|
||||
bool isCommandEnabled() override;
|
||||
void onActionTriggered( bool isChecked ) override;
|
||||
void setupActionLook( QAction* actionToSetup ) override;
|
||||
};
|
@@ -22,7 +22,7 @@
|
||||
#include "RigFemScalarResultFrames.h"
|
||||
|
||||
#include "RigStatisticsMath.h"
|
||||
#include <math.h>
|
||||
#include <cmath>
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
|
@@ -24,7 +24,9 @@
|
||||
#include "RigFemPartCollection.h"
|
||||
#include "RigGeoMechCaseData.h"
|
||||
#include "RigStatisticsMath.h"
|
||||
#include <math.h>
|
||||
|
||||
#include <cmath>
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
|
@@ -0,0 +1,18 @@
|
||||
|
||||
set (SOURCE_GROUP_HEADER_FILES
|
||||
${CMAKE_CURRENT_LIST_DIR}/RivStreamlinesPartMgr.h
|
||||
)
|
||||
|
||||
set (SOURCE_GROUP_SOURCE_FILES
|
||||
${CMAKE_CURRENT_LIST_DIR}/RivStreamlinesPartMgr.cpp
|
||||
)
|
||||
|
||||
list(APPEND CODE_HEADER_FILES
|
||||
${SOURCE_GROUP_HEADER_FILES}
|
||||
)
|
||||
|
||||
list(APPEND CODE_SOURCE_FILES
|
||||
${SOURCE_GROUP_SOURCE_FILES}
|
||||
)
|
||||
|
||||
source_group( "ModelVisualization\\Streamlines" FILES ${SOURCE_GROUP_HEADER_FILES} ${SOURCE_GROUP_SOURCE_FILES} ${CMAKE_CURRENT_LIST_DIR}/CMakeLists_files.cmake )
|
@@ -0,0 +1,779 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2020- Equinor 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 "RivStreamlinesPartMgr.h"
|
||||
|
||||
#include "Rim3dView.h"
|
||||
#include "RimEclipseCase.h"
|
||||
#include "RimEclipseView.h"
|
||||
#include "RimRegularLegendConfig.h"
|
||||
#include "RimSimWellInView.h"
|
||||
#include "RimSimWellInViewCollection.h"
|
||||
#include "RimStreamlineInViewCollection.h"
|
||||
|
||||
#include "RigActiveCellInfo.h"
|
||||
#include "RigCaseCellResultsData.h"
|
||||
#include "RigCell.h"
|
||||
#include "RigEclipseCaseData.h"
|
||||
#include "RigMainGrid.h"
|
||||
#include "RigSimulationWellCenterLineCalculator.h"
|
||||
#include "RigTracer.h"
|
||||
#include "RigTracerPoint.h"
|
||||
#include "RigWellResultPoint.h"
|
||||
|
||||
#include "RiuViewer.h"
|
||||
|
||||
#include "cafDisplayCoordTransform.h"
|
||||
#include "cafEffectGenerator.h"
|
||||
|
||||
#include "cvfDrawableGeo.h"
|
||||
#include "cvfModelBasicList.h"
|
||||
#include "cvfPart.h"
|
||||
#include "cvfPrimitiveSetIndexedUInt.h"
|
||||
#include "cvfPrimitiveSetIndexedUIntScoped.h"
|
||||
#include "cvfShaderProgram.h"
|
||||
|
||||
#include "cafPdmPointer.h"
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RivStreamlinesPartMgr::RivStreamlinesPartMgr( RimEclipseView* reservoirView )
|
||||
{
|
||||
m_rimReservoirView = reservoirView;
|
||||
m_count = 0;
|
||||
m_currentT = 0;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RivStreamlinesPartMgr::~RivStreamlinesPartMgr()
|
||||
{
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RivStreamlinesPartMgr::appendDynamicGeometryPartsToModel( cvf::ModelBasicList* model, size_t timeStepIndex )
|
||||
{
|
||||
m_streamlines.clear();
|
||||
|
||||
RimStreamlineInViewCollection* streamlineCollection = m_rimReservoirView->streamlineCollection();
|
||||
|
||||
if ( !streamlineCollection->isActive() ) return;
|
||||
|
||||
CVF_ASSERT( model );
|
||||
if ( m_rimReservoirView.isNull() ) return;
|
||||
|
||||
RimEclipseCase* eclipseCase = m_rimReservoirView->eclipseCase();
|
||||
if ( !eclipseCase ) return;
|
||||
|
||||
RigEclipseCaseData* eclipseCaseData = eclipseCase->eclipseCaseData();
|
||||
if ( !eclipseCaseData ) return;
|
||||
|
||||
cvf::ref<caf::DisplayCoordTransform> displayCordXf = m_rimReservoirView->displayCoordTransform();
|
||||
|
||||
for ( const RigTracer& tracer : streamlineCollection->tracers() )
|
||||
{
|
||||
Streamline streamline;
|
||||
for ( size_t i = 0; i < tracer.tracerPoints().size() - 1; i++ )
|
||||
{
|
||||
streamline.appendTracerPoint( tracer.tracerPoints()[i].position() );
|
||||
streamline.appendAbsVelocity( tracer.tracerPoints()[i].absValue() );
|
||||
streamline.appendDirection( tracer.tracerPoints()[i].direction() );
|
||||
}
|
||||
m_streamlines.push_back( streamline );
|
||||
}
|
||||
for ( Streamline& streamline : m_streamlines )
|
||||
{
|
||||
if ( streamlineCollection->visualizationMode() == RimStreamlineInViewCollection::VisualizationMode::ANIMATION ||
|
||||
streamlineCollection->visualizationMode() == RimStreamlineInViewCollection::VisualizationMode::MANUAL )
|
||||
{
|
||||
if ( streamline.countTracerPoints() > 1 )
|
||||
{
|
||||
model->addPart( createPart( *streamlineCollection, streamline ).p() );
|
||||
}
|
||||
}
|
||||
else if ( streamlineCollection->visualizationMode() == RimStreamlineInViewCollection::VisualizationMode::VECTORS )
|
||||
{
|
||||
model->addPart( createVectorPart( *streamlineCollection, streamline ).p() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RivStreamlinesPartMgr::updateAnimation()
|
||||
{
|
||||
RimStreamlineInViewCollection* streamlineCollection = m_rimReservoirView->streamlineCollection();
|
||||
if ( streamlineCollection &&
|
||||
( streamlineCollection->visualizationMode() == RimStreamlineInViewCollection::VisualizationMode::ANIMATION ||
|
||||
streamlineCollection->visualizationMode() == RimStreamlineInViewCollection::VisualizationMode::MANUAL ) )
|
||||
{
|
||||
for ( Streamline& streamline : m_streamlines )
|
||||
{
|
||||
if ( streamline.getPart().notNull() && dynamic_cast<cvf::DrawableGeo*>( streamline.getPart()->drawable() ) )
|
||||
{
|
||||
auto primitiveSet = dynamic_cast<cvf::PrimitiveSetIndexedUIntScoped*>(
|
||||
static_cast<cvf::DrawableGeo*>( streamline.getPart()->drawable() )->primitiveSet( 0 ) );
|
||||
|
||||
if ( primitiveSet )
|
||||
{
|
||||
size_t startIndex = 0;
|
||||
size_t endIndex = primitiveSet->indices()->size();
|
||||
|
||||
if ( streamlineCollection->visualizationMode() ==
|
||||
RimStreamlineInViewCollection::VisualizationMode::ANIMATION )
|
||||
{
|
||||
streamline.incrementAnimationIndex( streamlineCollection->animationSpeed() );
|
||||
|
||||
startIndex = streamline.getAnimationIndex();
|
||||
|
||||
// Make sure we have an even animation index, as this index is used to define start of a line
|
||||
// segment
|
||||
startIndex /= 2;
|
||||
startIndex *= 2;
|
||||
|
||||
endIndex = std::min( endIndex, startIndex + streamlineCollection->tracerLength() );
|
||||
}
|
||||
else
|
||||
{
|
||||
endIndex = std::min( endIndex, streamlineCollection->animationIndex() * 2 );
|
||||
}
|
||||
|
||||
primitiveSet->setScope( startIndex, endIndex - startIndex );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
cvf::ref<cvf::Part> RivStreamlinesPartMgr::createPart( const RimStreamlineInViewCollection& streamlineCollection,
|
||||
Streamline& streamline )
|
||||
{
|
||||
cvf::ref<caf::DisplayCoordTransform> displayCordXf = m_rimReservoirView->displayCoordTransform();
|
||||
|
||||
std::vector<uint> indices;
|
||||
// Each point is used twice except the first and the last one
|
||||
indices.reserve( streamline.countTracerPoints() * 2 - 2 );
|
||||
|
||||
std::vector<cvf::Vec3f> vertices;
|
||||
vertices.reserve( streamline.countTracerPoints() * 2 - 2 );
|
||||
|
||||
uint count = 0;
|
||||
for ( size_t i = 0; i < streamline.countTracerPoints(); i++ )
|
||||
{
|
||||
vertices.push_back( cvf::Vec3f( displayCordXf->transformToDisplayCoord( streamline.getTracerPoint( i ) ) ) );
|
||||
indices.push_back( count++ );
|
||||
if ( i > 0 && i < streamline.countTracerPoints() - 1 )
|
||||
{
|
||||
vertices.push_back( cvf::Vec3f( displayCordXf->transformToDisplayCoord( streamline.getTracerPoint( i ) ) ) );
|
||||
indices.push_back( count++ );
|
||||
}
|
||||
}
|
||||
|
||||
cvf::ref<cvf::PrimitiveSetIndexedUIntScoped> indexedUIntLine =
|
||||
new cvf::PrimitiveSetIndexedUIntScoped( cvf::PrimitiveType::PT_LINES );
|
||||
cvf::ref<cvf::UIntArray> indexedArrayLine = new cvf::UIntArray( indices );
|
||||
|
||||
cvf::ref<cvf::DrawableGeo> drawable = new cvf::DrawableGeo();
|
||||
|
||||
indexedUIntLine->setIndices( indexedArrayLine.p(), 0, 0 );
|
||||
drawable->addPrimitiveSet( indexedUIntLine.p() );
|
||||
|
||||
cvf::ref<cvf::Vec3fArray> vertexArray = new cvf::Vec3fArray( vertices );
|
||||
drawable->setVertexArray( vertexArray.p() );
|
||||
|
||||
cvf::ref<cvf::Vec2fArray> lineTexCoords = const_cast<cvf::Vec2fArray*>( drawable->textureCoordArray() );
|
||||
|
||||
if ( lineTexCoords.isNull() )
|
||||
{
|
||||
lineTexCoords = new cvf::Vec2fArray;
|
||||
}
|
||||
|
||||
cvf::ref<cvf::Effect> effect;
|
||||
|
||||
const cvf::ScalarMapper* activeScalarMapper = streamlineCollection.legendConfig()->scalarMapper();
|
||||
createResultColorTextureCoords( lineTexCoords.p(), streamline, activeScalarMapper );
|
||||
|
||||
caf::ScalarMapperMeshEffectGenerator meshEffGen( activeScalarMapper );
|
||||
effect = meshEffGen.generateCachedEffect();
|
||||
|
||||
drawable->setTextureCoordArray( lineTexCoords.p() );
|
||||
|
||||
// caf::MeshEffectGenerator effgen( cvf::Color3f( 0.0, 0.0, 0.95 ) );
|
||||
// effgen.setLineWidth( 2 );
|
||||
// cvf::ref<cvf::Effect> effect = effgen.generateCachedEffect();
|
||||
|
||||
cvf::ref<cvf::Part> part = new cvf::Part;
|
||||
part->setDrawable( drawable.p() );
|
||||
part->setEffect( effect.p() );
|
||||
part->updateBoundingBox();
|
||||
streamline.setPart( part );
|
||||
|
||||
return part;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RivStreamlinesPartMgr::createResultColorTextureCoords( cvf::Vec2fArray* textureCoords,
|
||||
const Streamline& streamline,
|
||||
const cvf::ScalarMapper* mapper )
|
||||
{
|
||||
CVF_ASSERT( textureCoords );
|
||||
CVF_ASSERT( mapper );
|
||||
|
||||
RimStreamlineInViewCollection* streamlineCollection = m_rimReservoirView->streamlineCollection();
|
||||
|
||||
size_t vertexCount = streamline.countTracerPoints() * 2 - 2;
|
||||
if ( streamlineCollection &&
|
||||
streamlineCollection->visualizationMode() == RimStreamlineInViewCollection::VisualizationMode::VECTORS )
|
||||
{
|
||||
vertexCount = streamline.countTracerPoints() * 7;
|
||||
}
|
||||
if ( textureCoords->capacity() != vertexCount ) textureCoords->reserve( vertexCount );
|
||||
|
||||
for ( size_t i = 0; i < streamline.countTracerPoints(); i++ )
|
||||
{
|
||||
cvf::Vec2f texCoord = mapper->mapToTextureCoord( streamline.getAbsVelocity( i ) );
|
||||
if ( streamlineCollection &&
|
||||
streamlineCollection->visualizationMode() == RimStreamlineInViewCollection::VisualizationMode::VECTORS )
|
||||
{
|
||||
for ( size_t vxIdx = 0; vxIdx < 7; ++vxIdx )
|
||||
{
|
||||
textureCoords->add( texCoord );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
textureCoords->add( texCoord );
|
||||
if ( i > 0 && i < streamline.countTracerPoints() - 1 )
|
||||
{
|
||||
textureCoords->add( texCoord );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
cvf::ref<cvf::Part> RivStreamlinesPartMgr::createVectorPart( const RimStreamlineInViewCollection& streamlineCollection,
|
||||
Streamline& streamline )
|
||||
{
|
||||
cvf::ref<caf::DisplayCoordTransform> displayCordXf = m_rimReservoirView->displayCoordTransform();
|
||||
|
||||
std::vector<uint> shaftIndices;
|
||||
shaftIndices.reserve( 2 * streamline.countTracerPoints() );
|
||||
|
||||
std::vector<uint> headIndices;
|
||||
headIndices.reserve( 6 * streamline.countTracerPoints() );
|
||||
|
||||
std::vector<cvf::Vec3f> vertices;
|
||||
vertices.reserve( 7 * streamline.countTracerPoints() );
|
||||
|
||||
for ( size_t i = 0; i < streamline.countTracerPoints(); i++ )
|
||||
{
|
||||
cvf::Vec3f anchorPoint = cvf::Vec3f( displayCordXf->transformToDisplayCoord( streamline.getTracerPoint( i ) ) );
|
||||
cvf::Vec3f direction = cvf::Vec3f( streamline.getDirection( i ) ) * streamlineCollection.scaleFactor();
|
||||
|
||||
for ( const cvf::Vec3f& vertex : createArrowVertices( anchorPoint, direction ) )
|
||||
{
|
||||
vertices.push_back( vertex );
|
||||
}
|
||||
|
||||
for ( const uint& index : createArrowShaftIndices( 0 ) )
|
||||
{
|
||||
shaftIndices.push_back( index );
|
||||
}
|
||||
|
||||
for ( const uint& index : createArrowHeadIndices( 0 ) )
|
||||
{
|
||||
headIndices.push_back( index );
|
||||
}
|
||||
}
|
||||
|
||||
cvf::ref<cvf::PrimitiveSetIndexedUInt> indexedUIntShaft =
|
||||
new cvf::PrimitiveSetIndexedUInt( cvf::PrimitiveType::PT_LINES );
|
||||
cvf::ref<cvf::UIntArray> indexArrayShaft = new cvf::UIntArray( shaftIndices );
|
||||
|
||||
cvf::ref<cvf::PrimitiveSetIndexedUInt> indexedUIntHead =
|
||||
new cvf::PrimitiveSetIndexedUInt( cvf::PrimitiveType::PT_TRIANGLES );
|
||||
cvf::ref<cvf::UIntArray> indexArrayHead = new cvf::UIntArray( headIndices );
|
||||
|
||||
cvf::ref<cvf::DrawableGeo> drawable = new cvf::DrawableGeo();
|
||||
|
||||
indexedUIntShaft->setIndices( indexArrayShaft.p() );
|
||||
drawable->addPrimitiveSet( indexedUIntShaft.p() );
|
||||
|
||||
indexedUIntHead->setIndices( indexArrayHead.p() );
|
||||
drawable->addPrimitiveSet( indexedUIntHead.p() );
|
||||
|
||||
cvf::ref<cvf::Vec3fArray> vertexArray = new cvf::Vec3fArray( vertices );
|
||||
drawable->setVertexArray( vertexArray.p() );
|
||||
|
||||
cvf::ref<cvf::Vec2fArray> lineTexCoords = const_cast<cvf::Vec2fArray*>( drawable->textureCoordArray() );
|
||||
|
||||
if ( lineTexCoords.isNull() )
|
||||
{
|
||||
lineTexCoords = new cvf::Vec2fArray;
|
||||
}
|
||||
|
||||
cvf::ref<cvf::Effect> effect;
|
||||
|
||||
const cvf::ScalarMapper* activeScalarMapper = streamlineCollection.legendConfig()->scalarMapper();
|
||||
createResultColorTextureCoords( lineTexCoords.p(), streamline, activeScalarMapper );
|
||||
|
||||
caf::ScalarMapperMeshEffectGenerator meshEffGen( activeScalarMapper );
|
||||
effect = meshEffGen.generateCachedEffect();
|
||||
|
||||
drawable->setTextureCoordArray( lineTexCoords.p() );
|
||||
|
||||
cvf::ref<cvf::Part> part = new cvf::Part;
|
||||
part->setDrawable( drawable.p() );
|
||||
part->setEffect( effect.p() );
|
||||
part->updateBoundingBox();
|
||||
return part;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::array<cvf::Vec3f, 7> RivStreamlinesPartMgr::createArrowVertices( const cvf::Vec3f anchorPoint,
|
||||
const cvf::Vec3f direction ) const
|
||||
{
|
||||
std::array<cvf::Vec3f, 7> vertices;
|
||||
cvf::Vec3f headTop = anchorPoint + direction;
|
||||
|
||||
RimEclipseCase* eclipseCase = m_rimReservoirView->eclipseCase();
|
||||
if ( !eclipseCase ) return vertices;
|
||||
|
||||
float headLength =
|
||||
std::min<float>( eclipseCase->characteristicCellSize() / 3.0f, ( headTop - anchorPoint ).length() / 2.0 );
|
||||
|
||||
// A fixed size is preferred here
|
||||
cvf::Vec3f headBottom = headTop - ( headTop - anchorPoint ).getNormalized() * headLength;
|
||||
|
||||
float arrowWidth = headLength / 2.0f;
|
||||
|
||||
cvf::Vec3f headBottomDirection1 = direction ^ anchorPoint;
|
||||
cvf::Vec3f headBottomDirection2 = headBottomDirection1 ^ direction;
|
||||
cvf::Vec3f arrowBottomSegment1 = headBottomDirection1.getNormalized() * arrowWidth;
|
||||
cvf::Vec3f arrowBottomSegment2 = headBottomDirection2.getNormalized() * arrowWidth;
|
||||
|
||||
vertices[0] = anchorPoint;
|
||||
vertices[1] = headBottom;
|
||||
vertices[2] = headBottom + arrowBottomSegment1;
|
||||
vertices[3] = headBottom - arrowBottomSegment1;
|
||||
vertices[4] = headTop;
|
||||
vertices[5] = headBottom + arrowBottomSegment2;
|
||||
vertices[6] = headBottom - arrowBottomSegment2;
|
||||
|
||||
return vertices;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::array<uint, 2> RivStreamlinesPartMgr::createArrowShaftIndices( uint startIndex ) const
|
||||
{
|
||||
std::array<uint, 2> indices;
|
||||
|
||||
indices[0] = startIndex;
|
||||
indices[1] = startIndex + 1;
|
||||
|
||||
return indices;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::array<uint, 6> RivStreamlinesPartMgr::createArrowHeadIndices( uint startIndex ) const
|
||||
{
|
||||
std::array<uint, 6> indices;
|
||||
|
||||
indices[0] = startIndex + 2;
|
||||
indices[1] = startIndex + 3;
|
||||
indices[2] = startIndex + 4;
|
||||
|
||||
indices[3] = startIndex + 5;
|
||||
indices[4] = startIndex + 6;
|
||||
indices[5] = startIndex + 4;
|
||||
return indices;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RivStreamlinesPartMgr::setAlpha( cvf::ref<cvf::Part> part, float alpha )
|
||||
{
|
||||
if ( part.notNull() )
|
||||
{
|
||||
caf::SurfaceEffectGenerator surfaceGen( cvf::Color4f( alpha, alpha, alpha, 1 ), caf::PO_1 );
|
||||
surfaceGen.enableLighting( false );
|
||||
cvf::ref<cvf::Effect> effect = surfaceGen.generateCachedEffect();
|
||||
part->setEffect( effect.p() );
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RivStreamlinesPartMgr::StreamlineSegment::computeSegments()
|
||||
{
|
||||
a = startPoint;
|
||||
b = startDirection;
|
||||
c = 3.0 * ( endPoint - startPoint ) - 2.0 * startDirection - endDirection;
|
||||
d = 2.0 * ( startPoint - endPoint ) + endDirection + startDirection;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
cvf::Vec3d RivStreamlinesPartMgr::StreamlineSegment::getPointAt( double t ) const
|
||||
{
|
||||
return a + b * t + c * t * t + d * t * t * t;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
cvf::Vec3d RivStreamlinesPartMgr::StreamlineSegment::getDirectionAt( double t ) const
|
||||
{
|
||||
return b + c * t + d * t * t;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
double RivStreamlinesPartMgr::StreamlineSegment::getVelocityAt( double localT ) const
|
||||
{
|
||||
if ( localT == 0 )
|
||||
{
|
||||
return startVelocity;
|
||||
}
|
||||
return startVelocity + ( endVelocity - startVelocity ) / localT;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
double RivStreamlinesPartMgr::StreamlineSegment::getChordLength() const
|
||||
{
|
||||
return startPoint.pointDistance( endPoint );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RivStreamlinesPartMgr::StreamlineVisualization::computeTValues()
|
||||
{
|
||||
double totalLength = getApproximatedTotalLength();
|
||||
double currentLength = 0.0;
|
||||
for ( StreamlineSegment& segment : segments )
|
||||
{
|
||||
segment.globalTStart = currentLength / totalLength;
|
||||
currentLength += segment.getChordLength();
|
||||
segment.globalTEnd = currentLength / totalLength;
|
||||
}
|
||||
areTValuesComputed = true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RivStreamlinesPartMgr::StreamlineVisualization::appendSegment( StreamlineSegment segment )
|
||||
{
|
||||
segments.push_back( segment );
|
||||
areTValuesComputed = false;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RivStreamlinesPartMgr::StreamlineVisualization::prependSegment( StreamlineSegment segment )
|
||||
{
|
||||
segments.push_front( segment );
|
||||
areTValuesComputed = false;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RivStreamlinesPartMgr::StreamlineVisualization::appendPart( cvf::ref<cvf::Part> part, double globalT )
|
||||
{
|
||||
parts.push_back( part.p() );
|
||||
partTValues.push_back( globalT );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
size_t RivStreamlinesPartMgr::StreamlineVisualization::segmentsSize() const
|
||||
{
|
||||
return segments.size();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::list<RivStreamlinesPartMgr::StreamlineSegment> RivStreamlinesPartMgr::StreamlineVisualization::getSegments()
|
||||
{
|
||||
return segments;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RivStreamlinesPartMgr::StreamlineVisualization::clear()
|
||||
{
|
||||
segments.clear();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RivStreamlinesPartMgr::StreamlineVisualization::updateAnimationGlobalT( double timeMs )
|
||||
{
|
||||
double totalLength = getApproximatedTotalLength(); // m
|
||||
double velocity = getVelocityAt( currentAnimationGlobalT ); // m/s
|
||||
currentAnimationGlobalT += velocity * timeMs / 1000.0 / totalLength;
|
||||
|
||||
if ( currentAnimationGlobalT > 1.0 )
|
||||
{
|
||||
currentAnimationGlobalT = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
double RivStreamlinesPartMgr::StreamlineVisualization::getApproximatedTotalLength()
|
||||
{
|
||||
if ( areTValuesComputed ) return approximatedTotalLength;
|
||||
double totalLength = 0.0;
|
||||
for ( auto& segment : segments )
|
||||
{
|
||||
totalLength += segment.getChordLength();
|
||||
}
|
||||
approximatedTotalLength = totalLength;
|
||||
return approximatedTotalLength;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
cvf::Vec3d RivStreamlinesPartMgr::StreamlineVisualization::getPointAt( double globalT ) const
|
||||
{
|
||||
CVF_ASSERT( areTValuesComputed );
|
||||
for ( std::list<StreamlineSegment>::const_iterator it = segments.begin(); it != segments.end(); ++it )
|
||||
{
|
||||
if ( it->globalTStart <= globalT && it->globalTEnd >= globalT )
|
||||
{
|
||||
double localT = ( globalT - it->globalTStart ) / ( it->globalTEnd - it->globalTStart );
|
||||
return it->getPointAt( localT );
|
||||
}
|
||||
}
|
||||
return cvf::Vec3d();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
cvf::Vec3d RivStreamlinesPartMgr::StreamlineVisualization::getDirectionAt( double globalT ) const
|
||||
{
|
||||
CVF_ASSERT( areTValuesComputed );
|
||||
for ( std::list<StreamlineSegment>::const_iterator it = segments.begin(); it != segments.end(); ++it )
|
||||
{
|
||||
if ( it->globalTStart <= globalT && it->globalTEnd >= globalT )
|
||||
{
|
||||
double localT = ( globalT - it->globalTStart ) / ( it->globalTEnd - it->globalTStart );
|
||||
return it->getDirectionAt( localT );
|
||||
}
|
||||
}
|
||||
return cvf::Vec3d();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
double RivStreamlinesPartMgr::StreamlineVisualization::getVelocityAt( double globalT ) const
|
||||
{
|
||||
CVF_ASSERT( areTValuesComputed );
|
||||
for ( std::list<StreamlineSegment>::const_iterator it = segments.begin(); it != segments.end(); ++it )
|
||||
{
|
||||
if ( it->globalTStart <= globalT && it->globalTEnd >= globalT )
|
||||
{
|
||||
double localT = ( globalT - it->globalTStart ) / ( it->globalTEnd - it->globalTStart );
|
||||
return it->getVelocityAt( localT );
|
||||
}
|
||||
}
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
cvf::Collection<cvf::Part> RivStreamlinesPartMgr::StreamlineVisualization::getParts()
|
||||
{
|
||||
return parts;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
cvf::ref<cvf::Part> RivStreamlinesPartMgr::StreamlineVisualization::getPartAtGlobalT( double globalT ) const
|
||||
{
|
||||
CVF_ASSERT( areTValuesComputed );
|
||||
double t = 0.0;
|
||||
for ( size_t index = 0; index < parts.size(); index++ )
|
||||
{
|
||||
t = partTValues[index];
|
||||
if ( t >= globalT )
|
||||
{
|
||||
return parts[index];
|
||||
}
|
||||
}
|
||||
return cvf::ref<cvf::Part>( nullptr );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RivStreamlinesPartMgr::Streamline::appendTracerPoint( cvf::Vec3d point )
|
||||
{
|
||||
tracerPoints.push_back( point );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RivStreamlinesPartMgr::Streamline::appendAbsVelocity( double velocity )
|
||||
{
|
||||
absVelocities.push_back( velocity );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RivStreamlinesPartMgr::Streamline::appendDirection( cvf::Vec3d direction )
|
||||
{
|
||||
directions.push_back( direction );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RivStreamlinesPartMgr::Streamline::clear()
|
||||
{
|
||||
tracerPoints.clear();
|
||||
absVelocities.clear();
|
||||
directions.clear();
|
||||
delete part.p();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
cvf::ref<cvf::Part> RivStreamlinesPartMgr::Streamline::getPart()
|
||||
{
|
||||
return part;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
cvf::Vec3d RivStreamlinesPartMgr::Streamline::getTracerPoint( size_t index ) const
|
||||
{
|
||||
return tracerPoints[index];
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
double RivStreamlinesPartMgr::Streamline::getAbsVelocity( size_t index ) const
|
||||
{
|
||||
return absVelocities[index];
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
cvf::Vec3d RivStreamlinesPartMgr::Streamline::getDirection( size_t index ) const
|
||||
{
|
||||
return directions[index];
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
size_t RivStreamlinesPartMgr::Streamline::countTracerPoints() const
|
||||
{
|
||||
return tracerPoints.size();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RivStreamlinesPartMgr::Streamline::setPart( cvf::ref<cvf::Part> part )
|
||||
{
|
||||
this->part = part;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
size_t RivStreamlinesPartMgr::Streamline::getAnimationIndex() const
|
||||
{
|
||||
return animIndex;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RivStreamlinesPartMgr::Streamline::incrementAnimationIndex( size_t increment )
|
||||
{
|
||||
animIndex += increment;
|
||||
|
||||
// Make sure we have an even animation index, as this index is used to define start of a line segment
|
||||
animIndex /= 2;
|
||||
animIndex *= 2;
|
||||
|
||||
if ( animIndex >= tracerPoints.size() * 2 - 2 )
|
||||
{
|
||||
animIndex = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RivStreamlinesPartMgr::Streamline::setAnimationIndex( size_t index )
|
||||
{
|
||||
animIndex = index;
|
||||
if ( animIndex >= tracerPoints.size() * 2 - 2 )
|
||||
{
|
||||
animIndex = tracerPoints.size() * 2 - 2;
|
||||
}
|
||||
}
|
@@ -0,0 +1,178 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2020- Equinor 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 "cvfObject.h"
|
||||
|
||||
#include "cafPdmPointer.h"
|
||||
#include "cafSignal.h"
|
||||
|
||||
#include "cvfCollection.h"
|
||||
#include "cvfPart.h"
|
||||
#include "cvfVector3.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace cvf
|
||||
{
|
||||
class ModelBasicList;
|
||||
class ScalarMapper;
|
||||
class ScalarMapperDiscreteLinear;
|
||||
} // namespace cvf
|
||||
|
||||
class RimEclipseView;
|
||||
class RimStreamlineInViewCollection;
|
||||
class Rim3dView;
|
||||
|
||||
class RivStreamlinesPartMgr : public cvf::Object, public caf::SignalObserver
|
||||
{
|
||||
public:
|
||||
RivStreamlinesPartMgr( RimEclipseView* reservoirView );
|
||||
~RivStreamlinesPartMgr() override;
|
||||
|
||||
void appendDynamicGeometryPartsToModel( cvf::ModelBasicList* model, size_t timeStepIndex );
|
||||
void updateAnimation();
|
||||
|
||||
private:
|
||||
struct StreamlineSegment
|
||||
{
|
||||
/*
|
||||
x_ij(t) = a_ij + b_ij * t + c_ij * t^2 + d_ij * t^3
|
||||
*/
|
||||
|
||||
StreamlineSegment(){};
|
||||
StreamlineSegment( cvf::Vec3d startPoint,
|
||||
cvf::Vec3d endPoint,
|
||||
cvf::Vec3d startDirection,
|
||||
cvf::Vec3d endDirection,
|
||||
double startVelocity,
|
||||
double endVelocity )
|
||||
: startPoint( startPoint )
|
||||
, endPoint( endPoint )
|
||||
, startDirection( startDirection )
|
||||
, endDirection( endDirection )
|
||||
, startVelocity( startVelocity )
|
||||
, endVelocity( endVelocity )
|
||||
{
|
||||
computeSegments();
|
||||
};
|
||||
|
||||
void computeSegments();
|
||||
|
||||
cvf::Vec3d getPointAt( double localT ) const;
|
||||
cvf::Vec3d getDirectionAt( double localT ) const;
|
||||
double getVelocityAt( double localT ) const;
|
||||
double getChordLength() const;
|
||||
|
||||
cvf::Vec3d startPoint;
|
||||
cvf::Vec3d endPoint;
|
||||
cvf::Vec3d startDirection;
|
||||
cvf::Vec3d endDirection;
|
||||
double globalTStart;
|
||||
double globalTEnd;
|
||||
double startVelocity;
|
||||
double endVelocity;
|
||||
|
||||
private:
|
||||
cvf::Vec3d a;
|
||||
cvf::Vec3d b;
|
||||
cvf::Vec3d c;
|
||||
cvf::Vec3d d;
|
||||
};
|
||||
struct StreamlineVisualization
|
||||
{
|
||||
StreamlineVisualization()
|
||||
{
|
||||
areTValuesComputed = false;
|
||||
currentAnimationGlobalT = 0.0;
|
||||
};
|
||||
|
||||
void computeTValues();
|
||||
void appendSegment( StreamlineSegment segment );
|
||||
void prependSegment( StreamlineSegment segment );
|
||||
void appendPart( cvf::ref<cvf::Part> part, double globalT );
|
||||
size_t segmentsSize() const;
|
||||
std::list<RivStreamlinesPartMgr::StreamlineSegment> getSegments();
|
||||
void clear();
|
||||
void updateAnimationGlobalT( double timeMs );
|
||||
double getApproximatedTotalLength();
|
||||
|
||||
cvf::Vec3d getPointAt( double globalT ) const;
|
||||
cvf::Vec3d getDirectionAt( double globalT ) const;
|
||||
double getVelocityAt( double globalT ) const;
|
||||
cvf::Collection<cvf::Part> getParts();
|
||||
cvf::ref<cvf::Part> getPartAtGlobalT( double globalT ) const;
|
||||
|
||||
double currentAnimationGlobalT;
|
||||
|
||||
private:
|
||||
bool areTValuesComputed;
|
||||
double approximatedTotalLength;
|
||||
std::list<StreamlineSegment> segments;
|
||||
cvf::Collection<cvf::Part> parts;
|
||||
std::vector<double> partTValues;
|
||||
};
|
||||
|
||||
struct Streamline
|
||||
{
|
||||
Streamline() { animIndex = 0; };
|
||||
|
||||
void appendTracerPoint( cvf::Vec3d point );
|
||||
void appendAbsVelocity( double velocity );
|
||||
void appendDirection( cvf::Vec3d direction );
|
||||
void clear();
|
||||
cvf::ref<cvf::Part> getPart();
|
||||
cvf::Vec3d getTracerPoint( size_t index ) const;
|
||||
double getAbsVelocity( size_t index ) const;
|
||||
cvf::Vec3d getDirection( size_t index ) const;
|
||||
size_t countTracerPoints() const;
|
||||
void setPart( cvf::ref<cvf::Part> part );
|
||||
size_t getAnimationIndex() const;
|
||||
void incrementAnimationIndex( size_t increment = 1.0 );
|
||||
void setAnimationIndex( size_t index );
|
||||
|
||||
private:
|
||||
std::vector<cvf::Vec3d> tracerPoints;
|
||||
std::vector<double> absVelocities;
|
||||
std::vector<cvf::Vec3d> directions;
|
||||
cvf::ref<cvf::Part> part;
|
||||
size_t animIndex;
|
||||
};
|
||||
|
||||
private:
|
||||
cvf::ref<cvf::Part> createPart( const RimStreamlineInViewCollection& streamlineCollection,
|
||||
Streamline& streamlineVisualization );
|
||||
|
||||
void createResultColorTextureCoords( cvf::Vec2fArray* textureCoords,
|
||||
const Streamline& streamline,
|
||||
const cvf::ScalarMapper* mapper );
|
||||
|
||||
cvf::ref<cvf::Part> createVectorPart( const RimStreamlineInViewCollection& streamlineCollection, Streamline& segment );
|
||||
|
||||
std::array<cvf::Vec3f, 7> createArrowVertices( const cvf::Vec3f anchorPoint, const cvf::Vec3f direction ) const;
|
||||
std::array<uint, 2> createArrowShaftIndices( uint startIndex ) const;
|
||||
std::array<uint, 6> createArrowHeadIndices( uint startIndex ) const;
|
||||
void setAlpha( cvf::ref<cvf::Part> part, float alpha );
|
||||
|
||||
private:
|
||||
std::list<Streamline> m_streamlines;
|
||||
caf::PdmPointer<RimEclipseView> m_rimReservoirView;
|
||||
uint m_count;
|
||||
size_t m_currentT;
|
||||
bool m_showAsVectors;
|
||||
};
|
@@ -59,6 +59,7 @@
|
||||
#include "cvfCamera.h"
|
||||
#include "cvfModelBasicList.h"
|
||||
#include "cvfPart.h"
|
||||
#include "cvfScene.h"
|
||||
#include "cvfTransform.h"
|
||||
#include "cvfViewport.h"
|
||||
|
||||
@@ -83,8 +84,11 @@ CAF_PDM_XML_ABSTRACT_SOURCE_INIT( Rim3dView, "View", "GenericView" ); // Do not
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
Rim3dView::Rim3dView( void )
|
||||
: m_isCallingUpdateDisplayModelForCurrentTimestepAndRedraw( false )
|
||||
Rim3dView::Rim3dView()
|
||||
: updateAnimations( this )
|
||||
, m_isCallingUpdateDisplayModelForCurrentTimestepAndRedraw( false )
|
||||
, m_animationIntervalMillisec( 50 )
|
||||
, m_animationTimerUsers( 0 )
|
||||
{
|
||||
RiaApplication* app = RiaApplication::instance();
|
||||
RiaPreferences* preferences = app->preferences();
|
||||
@@ -172,12 +176,19 @@ Rim3dView::Rim3dView( void )
|
||||
m_measurementPartManager = new RivMeasurementPartMgr( this );
|
||||
|
||||
this->setAs3DViewMdiWindow();
|
||||
|
||||
// Every timer tick, send a signal for updating animations.
|
||||
// Any animation is supposed to connect to this signal
|
||||
// in order to having only one central animation driver.
|
||||
m_animationTimer = std::make_unique<QTimer>( new QTimer() );
|
||||
m_animationTimer->setInterval( m_animationIntervalMillisec );
|
||||
QObject::connect( m_animationTimer.get(), &QTimer::timeout, [this]() { updateAnimations.send(); } );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
Rim3dView::~Rim3dView( void )
|
||||
Rim3dView::~Rim3dView()
|
||||
{
|
||||
if ( RiaApplication::instance()->activeReservoirView() == this )
|
||||
{
|
||||
@@ -202,6 +213,25 @@ int Rim3dView::id() const
|
||||
return m_id;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void Rim3dView::requestAnimationTimer()
|
||||
{
|
||||
m_animationTimerUsers++;
|
||||
if ( m_animationTimerUsers == 1 ) m_animationTimer->start();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void Rim3dView::releaseAnimationTimer()
|
||||
{
|
||||
m_animationTimerUsers--;
|
||||
CAF_ASSERT( m_animationTimerUsers >= 0 );
|
||||
if ( m_animationTimerUsers == 0 ) m_animationTimer->stop();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
@@ -1430,10 +1460,9 @@ RimViewNameConfig* Rim3dView::nameConfig() const
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QWidget* Rim3dView::viewWidget()
|
||||
{
|
||||
if ( m_viewer )
|
||||
return m_viewer->layoutWidget();
|
||||
else
|
||||
return nullptr;
|
||||
if ( m_viewer ) return m_viewer->layoutWidget();
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
|
@@ -29,6 +29,7 @@
|
||||
#include "cafPdmField.h"
|
||||
#include "cafPdmObject.h"
|
||||
#include "cafPdmPtrField.h"
|
||||
#include "cafSignal.h"
|
||||
|
||||
#include "cafPdmFieldCvfColor.h"
|
||||
#include "cafPdmFieldCvfMat4d.h"
|
||||
@@ -38,6 +39,7 @@
|
||||
#include "cvfObject.h"
|
||||
|
||||
#include <QPointer>
|
||||
#include <QTimer>
|
||||
|
||||
class RimCase;
|
||||
class RimLegendConfig;
|
||||
@@ -84,8 +86,8 @@ class Rim3dView : public RimViewWindow, public RiuViewerToViewInterface, public
|
||||
CAF_PDM_HEADER_INIT;
|
||||
|
||||
public:
|
||||
Rim3dView( void );
|
||||
~Rim3dView( void ) override;
|
||||
Rim3dView();
|
||||
~Rim3dView() override;
|
||||
|
||||
int id() const final;
|
||||
|
||||
@@ -142,7 +144,7 @@ public:
|
||||
void zoomAll() override;
|
||||
void forceShowWindowOn();
|
||||
|
||||
// Animation
|
||||
// Timestep control
|
||||
int currentTimeStep() const;
|
||||
void setCurrentTimeStep( int frameIdx );
|
||||
void setCurrentTimeStepAndUpdate( int frameIdx ) override;
|
||||
@@ -150,6 +152,11 @@ public:
|
||||
size_t timeStepCount();
|
||||
QString timeStepName( int frameIdx ) const override;
|
||||
|
||||
// Animation control
|
||||
caf::Signal<> updateAnimations;
|
||||
void requestAnimationTimer();
|
||||
void releaseAnimationTimer();
|
||||
|
||||
// Updating
|
||||
void scheduleCreateDisplayModelAndRedraw();
|
||||
virtual void scheduleGeometryRegen( RivCellSetEnum geometryType ) = 0;
|
||||
@@ -230,8 +237,8 @@ protected:
|
||||
void fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue ) override;
|
||||
void defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) override;
|
||||
|
||||
virtual QList<caf::PdmOptionItemInfo> calculateValueOptions( const caf::PdmFieldHandle* fieldNeedingOptions,
|
||||
bool* useOptionsOnly ) override;
|
||||
QList<caf::PdmOptionItemInfo> calculateValueOptions( const caf::PdmFieldHandle* fieldNeedingOptions,
|
||||
bool* useOptionsOnly ) override;
|
||||
|
||||
void setupBeforeSave() override;
|
||||
|
||||
@@ -259,7 +266,7 @@ private:
|
||||
QWidget* viewWidget() override;
|
||||
|
||||
// Implementation of RimNameConfigHolderInterface
|
||||
void performAutoNameUpdate() override final;
|
||||
void performAutoNameUpdate() final;
|
||||
|
||||
// Implementation of RiuViewerToViewInterface
|
||||
|
||||
@@ -310,4 +317,9 @@ private:
|
||||
cvf::ref<RivAnnotationsPartMgr> m_annotationsPartManager;
|
||||
cvf::ref<RivMeasurementPartMgr> m_measurementPartManager;
|
||||
cvf::ref<RivCellFilterPartMgr> m_cellfilterPartManager;
|
||||
|
||||
// Timer for animations
|
||||
std::unique_ptr<QTimer> m_animationTimer;
|
||||
const int m_animationIntervalMillisec;
|
||||
int m_animationTimerUsers;
|
||||
};
|
||||
|
@@ -115,6 +115,7 @@
|
||||
#include "RimStimPlanModelPlot.h"
|
||||
#include "RimStimPlanModelTemplate.h"
|
||||
#include "RimStimPlanModelTemplateCollection.h"
|
||||
#include "RimStreamlineInViewCollection.h"
|
||||
#include "RimSummaryCase.h"
|
||||
#include "RimSummaryCaseCollection.h"
|
||||
#include "RimSummaryCaseMainCollection.h"
|
||||
@@ -981,6 +982,11 @@ caf::CmdFeatureMenuBuilder RimContextCommandBuilder::commandsFromSelection()
|
||||
{
|
||||
menuBuilder << "RicSnapshotViewToPdfFeature";
|
||||
}
|
||||
else if ( dynamic_cast<RimStreamlineInViewCollection*>( firstUiItem ) )
|
||||
{
|
||||
menuBuilder << "RicNewStreamlineFeature";
|
||||
}
|
||||
|
||||
if ( dynamic_cast<Rim3dView*>( firstUiItem ) )
|
||||
{
|
||||
menuBuilder << "Separator";
|
||||
|
@@ -73,6 +73,7 @@
|
||||
#include "RimSimWellInView.h"
|
||||
#include "RimSimWellInViewCollection.h"
|
||||
#include "RimStimPlanColors.h"
|
||||
#include "RimStreamlineInViewCollection.h"
|
||||
#include "RimSurfaceInViewCollection.h"
|
||||
#include "RimTernaryLegendConfig.h"
|
||||
#include "RimViewController.h"
|
||||
@@ -94,6 +95,7 @@
|
||||
#include "RivReservoirSimWellsPartMgr.h"
|
||||
#include "RivReservoirViewPartMgr.h"
|
||||
#include "RivSingleCellPartGenerator.h"
|
||||
#include "RivStreamlinesPartMgr.h"
|
||||
#include "RivTernarySaturationOverlayItem.h"
|
||||
#include "RivWellFracturePartMgr.h"
|
||||
#include "RivWellPathsPartMgr.h"
|
||||
@@ -180,6 +182,10 @@ RimEclipseView::RimEclipseView()
|
||||
m_annotationCollection = new RimAnnotationInViewCollection;
|
||||
m_annotationCollection.uiCapability()->setUiHidden( true );
|
||||
|
||||
CAF_PDM_InitFieldNoDefault( &m_streamlineCollection, "StreamlineCollection", "Streamlines", "", "", "" );
|
||||
m_streamlineCollection = new RimStreamlineInViewCollection();
|
||||
m_streamlineCollection.uiCapability()->setUiHidden( true );
|
||||
|
||||
CAF_PDM_InitFieldNoDefault( &m_propertyFilterCollection, "PropertyFilters", "Property Filters", "", "", "" );
|
||||
m_propertyFilterCollection = new RimEclipsePropertyFilterCollection();
|
||||
m_propertyFilterCollection.uiCapability()->setUiHidden( true );
|
||||
@@ -202,6 +208,7 @@ RimEclipseView::RimEclipseView()
|
||||
|
||||
m_reservoirGridPartManager = new RivReservoirViewPartMgr( this );
|
||||
m_simWellsPartManager = new RivReservoirSimWellsPartMgr( this );
|
||||
m_streamlinesPartManager = new RivStreamlinesPartMgr( this );
|
||||
m_eclipseCase = nullptr;
|
||||
|
||||
nameConfig()->setCustomName( "3D View" );
|
||||
@@ -211,6 +218,8 @@ RimEclipseView::RimEclipseView()
|
||||
nameConfig()->hideSampleSpacingField( true );
|
||||
|
||||
setDeletable( true );
|
||||
|
||||
this->updateAnimations.connect( this, &RimEclipseView::onAnimationsUpdate );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
@@ -677,6 +686,19 @@ void RimEclipseView::onCreateDisplayModel()
|
||||
RicExportToSharingServerScheduler::instance()->scheduleUpdateSession();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimEclipseView::onAnimationsUpdate( const caf::SignalEmitter* emitter )
|
||||
{
|
||||
m_streamlinesPartManager->updateAnimation();
|
||||
|
||||
if ( viewer() )
|
||||
{
|
||||
viewer()->update();
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
@@ -687,6 +709,7 @@ void RimEclipseView::onUpdateDisplayModelForCurrentTimeStep()
|
||||
// m_surfaceCollection->clearGeometry();
|
||||
|
||||
m_propertyFilterCollection()->updateFromCurrentTimeStep();
|
||||
m_streamlineCollection()->updateFromCurrentTimeStep( currentTimeStep() );
|
||||
|
||||
updateVisibleGeometries();
|
||||
|
||||
@@ -697,8 +720,8 @@ void RimEclipseView::onUpdateDisplayModelForCurrentTimeStep()
|
||||
wellCollection()->scaleWellDisks();
|
||||
|
||||
appendWellsAndFracturesToModel();
|
||||
|
||||
appendElementVectorResultToModel();
|
||||
appendStreamlinesToModel();
|
||||
|
||||
m_overlayInfoConfig()->update3DInfo();
|
||||
|
||||
@@ -999,6 +1022,29 @@ void RimEclipseView::appendElementVectorResultToModel()
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimEclipseView::appendStreamlinesToModel()
|
||||
{
|
||||
if ( nativeOrOverrideViewer() )
|
||||
{
|
||||
cvf::Scene* frameScene = nativeOrOverrideViewer()->frame( m_currentTimeStep, isUsingOverrideViewer() );
|
||||
if ( frameScene )
|
||||
{
|
||||
cvf::String name = "StreamlinesModel";
|
||||
this->removeModelByName( frameScene, name );
|
||||
|
||||
cvf::ref<cvf::ModelBasicList> frameParts = new cvf::ModelBasicList;
|
||||
frameParts->setName( name );
|
||||
|
||||
m_streamlinesPartManager->appendDynamicGeometryPartsToModel( frameParts.p(), m_currentTimeStep );
|
||||
|
||||
frameScene->addModel( frameParts.p() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
@@ -1468,6 +1514,11 @@ void RimEclipseView::onUpdateLegends()
|
||||
{
|
||||
m_surfaceCollection->updateLegendRangesTextAndVisibility( nativeOrOverrideViewer(), isUsingOverrideViewer() );
|
||||
}
|
||||
|
||||
if ( m_streamlineCollection )
|
||||
{
|
||||
m_streamlineCollection->updateLegendRangesTextAndVisibility( nativeOrOverrideViewer(), isUsingOverrideViewer() );
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
@@ -1510,7 +1561,7 @@ void RimEclipseView::setEclipseCase( RimEclipseCase* reservoir )
|
||||
cellResult()->setEclipseCase( reservoir );
|
||||
faultResultSettings()->customFaultResult()->setEclipseCase( reservoir );
|
||||
cellFilterCollection()->setCase( reservoir );
|
||||
|
||||
m_streamlineCollection->setEclipseCase( reservoir );
|
||||
cellEdgeResult()->setEclipseCase( reservoir );
|
||||
}
|
||||
|
||||
@@ -1614,6 +1665,14 @@ void RimEclipseView::syncronizeLocalAnnotationsFromGlobal()
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RimStreamlineInViewCollection* RimEclipseView::streamlineCollection() const
|
||||
{
|
||||
return m_streamlineCollection;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
@@ -1876,7 +1935,7 @@ void RimEclipseView::defineUiTreeOrdering( caf::PdmUiTreeOrdering& uiTreeOrderin
|
||||
uiTreeOrdering.add( cellEdgeResult() );
|
||||
uiTreeOrdering.add( elementVectorResult() );
|
||||
uiTreeOrdering.add( faultResultSettings() );
|
||||
|
||||
uiTreeOrdering.add( &m_streamlineCollection );
|
||||
addRequiredUiTreeObjects( uiTreeOrdering );
|
||||
|
||||
uiTreeOrdering.add( wellCollection() );
|
||||
|
@@ -60,10 +60,12 @@ class RiuViewer;
|
||||
class RivReservoirSimWellsPartMgr;
|
||||
class RivExtrudedCurveIntersectionPartMgr;
|
||||
class RivReservoirViewPartMgr;
|
||||
class RivStreamlinesPartMgr;
|
||||
class RimRegularLegendConfig;
|
||||
class RimTernaryLegendConfig;
|
||||
class RimEclipseResultDefinition;
|
||||
class RimElementVectorResult;
|
||||
class RimStreamlineInViewCollection;
|
||||
|
||||
namespace cvf
|
||||
{
|
||||
@@ -85,14 +87,15 @@ public:
|
||||
RimEclipseView();
|
||||
~RimEclipseView() override;
|
||||
|
||||
RimEclipseCellColors* cellResult() const;
|
||||
RimCellEdgeColors* cellEdgeResult() const;
|
||||
RimElementVectorResult* elementVectorResult() const;
|
||||
RimEclipseFaultColors* faultResultSettings() const;
|
||||
RimStimPlanColors* fractureColors() const;
|
||||
RimSimWellInViewCollection* wellCollection() const;
|
||||
RimFaultInViewCollection* faultCollection() const;
|
||||
RimVirtualPerforationResults* virtualPerforationResult() const;
|
||||
RimEclipseCellColors* cellResult() const;
|
||||
RimCellEdgeColors* cellEdgeResult() const;
|
||||
RimElementVectorResult* elementVectorResult() const;
|
||||
RimEclipseFaultColors* faultResultSettings() const;
|
||||
RimStimPlanColors* fractureColors() const;
|
||||
RimSimWellInViewCollection* wellCollection() const;
|
||||
RimFaultInViewCollection* faultCollection() const;
|
||||
RimVirtualPerforationResults* virtualPerforationResult() const;
|
||||
RimStreamlineInViewCollection* streamlineCollection() const;
|
||||
|
||||
bool showInvalidCells() const;
|
||||
bool showInactiveCells() const;
|
||||
@@ -167,6 +170,7 @@ protected:
|
||||
|
||||
void appendWellsAndFracturesToModel();
|
||||
void appendElementVectorResultToModel();
|
||||
void appendStreamlinesToModel();
|
||||
|
||||
void onCreateDisplayModel() override;
|
||||
RimPropertyFilterCollection* nativePropertyFilterCollection();
|
||||
@@ -201,6 +205,8 @@ private:
|
||||
void onClampCurrentTimestep() override;
|
||||
size_t onTimeStepCountRequested() override;
|
||||
|
||||
void onAnimationsUpdate( const caf::SignalEmitter* emitter );
|
||||
|
||||
void setVisibleGridParts( const std::vector<RivCellSetEnum>& cellSets );
|
||||
void setVisibleGridPartsWatertight();
|
||||
|
||||
@@ -217,8 +223,9 @@ private:
|
||||
|
||||
caf::PdmProxyValueField<std::vector<double>> m_cellResultData;
|
||||
|
||||
caf::PdmChildField<RimSimWellInViewCollection*> m_wellCollection;
|
||||
caf::PdmChildField<RimFaultInViewCollection*> m_faultCollection;
|
||||
caf::PdmChildField<RimSimWellInViewCollection*> m_wellCollection;
|
||||
caf::PdmChildField<RimFaultInViewCollection*> m_faultCollection;
|
||||
caf::PdmChildField<RimStreamlineInViewCollection*> m_streamlineCollection;
|
||||
|
||||
caf::PdmChildField<RimEclipsePropertyFilterCollection*> m_propertyFilterCollection;
|
||||
caf::PdmPointer<RimEclipsePropertyFilterCollection> m_overridePropertyFilterCollection;
|
||||
@@ -227,6 +234,7 @@ private:
|
||||
|
||||
cvf::ref<RivReservoirViewPartMgr> m_reservoirGridPartManager;
|
||||
cvf::ref<RivReservoirSimWellsPartMgr> m_simWellsPartManager;
|
||||
cvf::ref<RivStreamlinesPartMgr> m_streamlinesPartManager;
|
||||
|
||||
std::vector<RivCellSetEnum> m_visibleGridParts;
|
||||
};
|
||||
|
@@ -0,0 +1,26 @@
|
||||
|
||||
set (SOURCE_GROUP_HEADER_FILES
|
||||
${CMAKE_CURRENT_LIST_DIR}/RimStreamline.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RimStreamlineInViewCollection.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RimStreamlineGeneratorBase.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RimStreamlineDataAccess.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RimStreamlineGenerator2.h
|
||||
)
|
||||
|
||||
set (SOURCE_GROUP_SOURCE_FILES
|
||||
${CMAKE_CURRENT_LIST_DIR}/RimStreamline.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RimStreamlineInViewCollection.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RimStreamlineGeneratorBase.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RimStreamlineDataAccess.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RimStreamlineGenerator2.cpp
|
||||
)
|
||||
|
||||
list(APPEND CODE_HEADER_FILES
|
||||
${SOURCE_GROUP_HEADER_FILES}
|
||||
)
|
||||
|
||||
list(APPEND CODE_SOURCE_FILES
|
||||
${SOURCE_GROUP_SOURCE_FILES}
|
||||
)
|
||||
|
||||
source_group( "ProjectDataModel\\Streamlines" FILES ${SOURCE_GROUP_HEADER_FILES} ${SOURCE_GROUP_SOURCE_FILES} ${CMAKE_CURRENT_LIST_DIR}/CMakeLists_files.cmake )
|
@@ -0,0 +1,123 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2020- Equinor 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 "RimStreamline.h"
|
||||
|
||||
#include "cafPdmFieldScriptingCapability.h"
|
||||
#include "cafPdmObjectScriptingCapability.h"
|
||||
#include "cafPdmUiLineEditor.h"
|
||||
#include "cafPdmUiTextEditor.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
|
||||
CAF_PDM_ABSTRACT_SOURCE_INIT( RimStreamline, "Streamline" );
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RimStreamline::RimStreamline( QString simWellName )
|
||||
{
|
||||
CAF_PDM_InitScriptableObject( "Streamline", ":/Erase.png", "", "" );
|
||||
|
||||
CAF_PDM_InitScriptableField( &m_simWellName, "Name", simWellName, "Name", "", "", "" );
|
||||
m_simWellName.uiCapability()->setUiReadOnly( true );
|
||||
m_simWellName.uiCapability()->setUiHidden( true );
|
||||
|
||||
CAF_PDM_InitScriptableFieldNoDefault( &m_propertiesTable, "PropertiesTable", "Properties Table", "", "", "" );
|
||||
m_propertiesTable.uiCapability()->setUiEditorTypeName( caf::PdmUiTextEditor::uiEditorTypeName() );
|
||||
m_propertiesTable.uiCapability()->setUiLabelPosition( caf::PdmUiItemInfo::HIDDEN );
|
||||
m_propertiesTable.uiCapability()->setUiReadOnly( true );
|
||||
m_propertiesTable.xmlCapability()->disableIO();
|
||||
|
||||
setDeletable( false );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RimStreamline::~RimStreamline()
|
||||
{
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
caf::PdmFieldHandle* RimStreamline::userDescriptionField()
|
||||
{
|
||||
return &m_simWellName;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
const RigTracer& RimStreamline::tracer() const
|
||||
{
|
||||
return m_tracer;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
const QString RimStreamline::simWellName() const
|
||||
{
|
||||
return m_simWellName;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimStreamline::addTracerPoint( cvf::Vec3d position, cvf::Vec3d direction, RiaDefines::PhaseType dominantPhase )
|
||||
{
|
||||
m_tracer.appendPoint( position, direction, dominantPhase );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimStreamline::reverse()
|
||||
{
|
||||
m_tracer.reverse();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimStreamline::generateStatistics()
|
||||
{
|
||||
QString stats;
|
||||
|
||||
stats += "Total distance: ";
|
||||
stats += QString::number( m_tracer.totalDistance(), 'f', 2 );
|
||||
stats += " meters\n";
|
||||
stats += "\n";
|
||||
stats += "Number of points: ";
|
||||
stats += QString::number( m_tracer.size() );
|
||||
stats += "\n";
|
||||
stats += "\n";
|
||||
|
||||
m_propertiesTable = stats;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
size_t RimStreamline::size() const
|
||||
{
|
||||
return m_tracer.size();
|
||||
}
|
@@ -0,0 +1,59 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2020- Equinor 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 "RigTracer.h"
|
||||
|
||||
#include "RiaDefines.h"
|
||||
|
||||
#include "cafPdmField.h"
|
||||
#include "cafPdmObject.h"
|
||||
|
||||
#include "cafPdmFieldCvfColor.h"
|
||||
#include "cafPdmProxyValueField.h"
|
||||
|
||||
#include "cvfObject.h"
|
||||
#include "cvfVector3.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
class RimStreamline : public caf::PdmObject
|
||||
{
|
||||
CAF_PDM_HEADER_INIT;
|
||||
|
||||
public:
|
||||
RimStreamline( QString simwellname );
|
||||
~RimStreamline() override;
|
||||
|
||||
const RigTracer& tracer() const;
|
||||
const QString simWellName() const;
|
||||
size_t size() const;
|
||||
|
||||
void addTracerPoint( cvf::Vec3d position, cvf::Vec3d direction, RiaDefines::PhaseType dominantPhase );
|
||||
void reverse();
|
||||
void generateStatistics();
|
||||
|
||||
protected:
|
||||
caf::PdmFieldHandle* userDescriptionField() override;
|
||||
|
||||
private:
|
||||
RigTracer m_tracer;
|
||||
caf::PdmField<QString> m_simWellName;
|
||||
|
||||
caf::PdmField<QString> m_propertiesTable;
|
||||
};
|
@@ -0,0 +1,235 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2021 Equinor 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 "RimStreamlineDataAccess.h"
|
||||
|
||||
#include "RigCaseCellResultsData.h"
|
||||
#include "RigCell.h"
|
||||
#include "RigEclipseCaseData.h"
|
||||
#include "RigEclipseResultAddress.h"
|
||||
#include "RigMainGrid.h"
|
||||
#include "RigResultAccessor.h"
|
||||
#include "RigResultAccessorFactory.h"
|
||||
|
||||
#include "cafAssert.h"
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RimStreamlineDataAccess::RimStreamlineDataAccess()
|
||||
: m_data( nullptr )
|
||||
, m_grid( nullptr )
|
||||
{
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RimStreamlineDataAccess::~RimStreamlineDataAccess()
|
||||
{
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// Set up data accessors to access the selected flroil/gas/wat data for all faces
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool RimStreamlineDataAccess::setupDataAccess( RigMainGrid* grid,
|
||||
RigEclipseCaseData* data,
|
||||
std::list<RiaDefines::PhaseType> phases,
|
||||
int timeIdx )
|
||||
{
|
||||
m_grid = grid;
|
||||
m_data = data;
|
||||
|
||||
m_dataAccess.clear();
|
||||
|
||||
for ( auto phase : phases )
|
||||
{
|
||||
m_dataAccess[phase] = std::vector<cvf::ref<RigResultAccessor>>();
|
||||
|
||||
// Note: NEG_? accessors are set to POS_? accessors, but will be referring the neighbor cell when used
|
||||
m_dataAccess[phase].push_back( getDataAccessor( cvf::StructGridInterface::FaceType::POS_I, phase, timeIdx ) );
|
||||
m_dataAccess[phase].push_back( getDataAccessor( cvf::StructGridInterface::FaceType::POS_I, phase, timeIdx ) );
|
||||
m_dataAccess[phase].push_back( getDataAccessor( cvf::StructGridInterface::FaceType::POS_J, phase, timeIdx ) );
|
||||
m_dataAccess[phase].push_back( getDataAccessor( cvf::StructGridInterface::FaceType::POS_J, phase, timeIdx ) );
|
||||
m_dataAccess[phase].push_back( getDataAccessor( cvf::StructGridInterface::FaceType::POS_K, phase, timeIdx ) );
|
||||
m_dataAccess[phase].push_back( getDataAccessor( cvf::StructGridInterface::FaceType::POS_K, phase, timeIdx ) );
|
||||
}
|
||||
|
||||
for ( auto& pair : m_dataAccess )
|
||||
{
|
||||
for ( auto& access : pair.second )
|
||||
{
|
||||
if ( access.isNull() ) return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// Return a data accessor for the given phase and face and time step
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
cvf::ref<RigResultAccessor> RimStreamlineDataAccess::getDataAccessor( cvf::StructGridInterface::FaceType faceIdx,
|
||||
RiaDefines::PhaseType phase,
|
||||
int timeIdx )
|
||||
{
|
||||
RiaDefines::PorosityModelType porModel = RiaDefines::PorosityModelType::MATRIX_MODEL;
|
||||
|
||||
RigCaseCellResultsData* data = m_data->results( porModel );
|
||||
|
||||
QString resultname = gridResultNameFromPhase( phase, faceIdx );
|
||||
int gridIdx = 0;
|
||||
|
||||
RigEclipseResultAddress address( RiaDefines::ResultCatType::DYNAMIC_NATIVE, resultname );
|
||||
|
||||
// Make sure we have the data we need loaded for the given phase and time step index
|
||||
data->ensureKnownResultLoadedForTimeStep( address, timeIdx );
|
||||
|
||||
return RigResultAccessorFactory::createFromResultAddress( m_data, gridIdx, porModel, timeIdx, address );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QString RimStreamlineDataAccess::gridResultNameFromPhase( RiaDefines::PhaseType phase,
|
||||
cvf::StructGridInterface::FaceType faceIdx ) const
|
||||
{
|
||||
QString retval = "";
|
||||
switch ( phase )
|
||||
{
|
||||
case RiaDefines::PhaseType::GAS_PHASE:
|
||||
retval += "FLRGAS";
|
||||
break;
|
||||
case RiaDefines::PhaseType::OIL_PHASE:
|
||||
retval += "FLROIL";
|
||||
break;
|
||||
case RiaDefines::PhaseType::WATER_PHASE:
|
||||
retval += "FLRWAT";
|
||||
break;
|
||||
default:
|
||||
CAF_ASSERT( false );
|
||||
break;
|
||||
}
|
||||
|
||||
switch ( faceIdx )
|
||||
{
|
||||
case cvf::StructGridInterface::FaceType::POS_I:
|
||||
retval += "I+";
|
||||
break;
|
||||
case cvf::StructGridInterface::FaceType::POS_J:
|
||||
retval += "J+";
|
||||
break;
|
||||
case cvf::StructGridInterface::FaceType::POS_K:
|
||||
retval += "K+";
|
||||
break;
|
||||
default:
|
||||
CAF_ASSERT( false );
|
||||
break;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// Return the face scalar value for the given cell and NEG_? face, by using the neighbor cell
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
double RimStreamlineDataAccess::negFaceValueDividedByArea( RigCell cell,
|
||||
cvf::StructGridInterface::FaceType faceIdx,
|
||||
RiaDefines::PhaseType phase ) const
|
||||
{
|
||||
double retval = 0.0;
|
||||
|
||||
RigCell neighborCell = cell.neighborCell( faceIdx );
|
||||
if ( neighborCell.isInvalid() ) return retval;
|
||||
|
||||
std::vector<cvf::ref<RigResultAccessor>> access = m_dataAccess.at( phase );
|
||||
retval = access[faceIdx]->cellScalar( neighborCell.mainGridCellIndex() );
|
||||
double area = cell.faceNormalWithAreaLength( faceIdx ).length();
|
||||
if ( area != 0.0 )
|
||||
retval /= area;
|
||||
else
|
||||
retval = 0.0;
|
||||
|
||||
if ( std::isinf( retval ) ) retval = 0.0;
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// Return the face scalar value for the given cell and POS_? face
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
double RimStreamlineDataAccess::posFaceValueDividedByArea( RigCell cell,
|
||||
cvf::StructGridInterface::FaceType faceIdx,
|
||||
RiaDefines::PhaseType phase ) const
|
||||
{
|
||||
std::vector<cvf::ref<RigResultAccessor>> access = m_dataAccess.at( phase );
|
||||
double retval = access[faceIdx]->cellScalar( cell.mainGridCellIndex() );
|
||||
double length = cell.faceNormalWithAreaLength( faceIdx ).length();
|
||||
if ( length != 0.0 )
|
||||
retval /= length;
|
||||
else
|
||||
retval = 0.0;
|
||||
|
||||
if ( std::isinf( retval ) ) retval = 0.0;
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// Return the face scalar value for the given cell and face
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
double RimStreamlineDataAccess::faceValueDividedByArea( RigCell cell,
|
||||
cvf::StructGridInterface::FaceType faceIdx,
|
||||
RiaDefines::PhaseType phase ) const
|
||||
{
|
||||
if ( faceIdx % 2 == 0 ) return posFaceValueDividedByArea( cell, faceIdx, phase );
|
||||
|
||||
// NEG_? face values must be read from the neighbor cells
|
||||
return negFaceValueDividedByArea( cell, faceIdx, phase );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// Return the face scalar value for the given cell and face, by combining flow for all specified phases
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
double RimStreamlineDataAccess::combinedFaceValueByArea( RigCell cell,
|
||||
cvf::StructGridInterface::FaceType faceIdx,
|
||||
std::list<RiaDefines::PhaseType> phases,
|
||||
RiaDefines::PhaseType& outDominantPhase ) const
|
||||
{
|
||||
double retValue = 0.0;
|
||||
outDominantPhase = phases.front();
|
||||
|
||||
double max = 0.0;
|
||||
|
||||
for ( auto phase : phases )
|
||||
{
|
||||
double tmp = 0.0;
|
||||
if ( faceIdx % 2 == 0 )
|
||||
tmp = posFaceValueDividedByArea( cell, faceIdx, phase );
|
||||
else
|
||||
tmp = negFaceValueDividedByArea( cell, faceIdx, phase );
|
||||
if ( abs( tmp ) > max )
|
||||
{
|
||||
outDominantPhase = phase;
|
||||
max = abs( tmp );
|
||||
}
|
||||
retValue += tmp;
|
||||
}
|
||||
|
||||
return retValue;
|
||||
}
|
@@ -0,0 +1,70 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2021 Equinor 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 "RiaDefines.h"
|
||||
|
||||
#include "cvfStructGrid.h"
|
||||
|
||||
#include <QString>
|
||||
|
||||
#include <list>
|
||||
#include <set>
|
||||
|
||||
class RigCell;
|
||||
class RimStreamline;
|
||||
class RigMainGrid;
|
||||
class RigGridBase;
|
||||
class RigResultAccessor;
|
||||
class RigEclipseCaseData;
|
||||
|
||||
class RimStreamlineDataAccess
|
||||
{
|
||||
public:
|
||||
RimStreamlineDataAccess();
|
||||
~RimStreamlineDataAccess();
|
||||
|
||||
bool setupDataAccess( RigMainGrid* grid, RigEclipseCaseData* data, std::list<RiaDefines::PhaseType> phases, int timeIdx );
|
||||
|
||||
double faceValueDividedByArea( RigCell cell, cvf::StructGridInterface::FaceType faceIdx, RiaDefines::PhaseType phase ) const;
|
||||
double combinedFaceValueByArea( RigCell cell,
|
||||
cvf::StructGridInterface::FaceType faceIdx,
|
||||
std::list<RiaDefines::PhaseType> phases,
|
||||
RiaDefines::PhaseType& dominantPhaseOut ) const;
|
||||
|
||||
const RigMainGrid* grid() const { return m_grid; }
|
||||
|
||||
protected:
|
||||
cvf::ref<RigResultAccessor>
|
||||
getDataAccessor( cvf::StructGridInterface::FaceType faceIdx, RiaDefines::PhaseType phase, int timeIdx );
|
||||
QString gridResultNameFromPhase( RiaDefines::PhaseType phase, cvf::StructGridInterface::FaceType faceIdx ) const;
|
||||
|
||||
double posFaceValueDividedByArea( RigCell cell,
|
||||
cvf::StructGridInterface::FaceType faceIdx,
|
||||
RiaDefines::PhaseType phase ) const;
|
||||
double negFaceValueDividedByArea( RigCell cell,
|
||||
cvf::StructGridInterface::FaceType faceIdx,
|
||||
RiaDefines::PhaseType phase ) const;
|
||||
|
||||
private:
|
||||
RigMainGrid* m_grid;
|
||||
RigEclipseCaseData* m_data;
|
||||
|
||||
std::map<RiaDefines::PhaseType, std::vector<cvf::ref<RigResultAccessor>>> m_dataAccess;
|
||||
};
|
@@ -0,0 +1,199 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2021 Equinor 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 "RimStreamlineGenerator2.h"
|
||||
|
||||
#include "RigCell.h"
|
||||
#include "RigMainGrid.h"
|
||||
|
||||
#include "RimStreamline.h"
|
||||
#include "RimStreamlineDataAccess.h"
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RimStreamlineGenerator2::RimStreamlineGenerator2( std::set<size_t>& wellCells )
|
||||
: RimStreamlineGeneratorBase( wellCells )
|
||||
{
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RimStreamlineGenerator2::~RimStreamlineGenerator2()
|
||||
{
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimStreamlineGenerator2::generateTracer( RigCell cell,
|
||||
double direction,
|
||||
QString simWellName,
|
||||
std::list<RimStreamline*>& outStreamlines )
|
||||
{
|
||||
RiaDefines::PhaseType dominantPhase = m_phases.front();
|
||||
|
||||
const size_t cellIdx = cell.gridLocalCellIndex();
|
||||
|
||||
// try to generate a tracer for all faces in the selected cell with positive flow
|
||||
for ( auto faceIdx : m_allFaces )
|
||||
{
|
||||
double flowVelocity = m_dataAccess->combinedFaceValueByArea( cell, faceIdx, m_phases, dominantPhase ) * direction;
|
||||
if ( flowVelocity > m_flowThreshold )
|
||||
{
|
||||
m_seeds.push_back( std::make_pair( cellIdx, faceIdx ) );
|
||||
}
|
||||
}
|
||||
|
||||
while ( m_seeds.size() > 0 )
|
||||
{
|
||||
const size_t cellIdx = m_seeds.front().first;
|
||||
const cvf::StructGridInterface::FaceType faceIdx = m_seeds.front().second;
|
||||
|
||||
RimStreamline* streamline = new RimStreamline( simWellName );
|
||||
|
||||
growStreamline( streamline, cellIdx, faceIdx, direction );
|
||||
|
||||
if ( direction < 0.0 ) streamline->reverse();
|
||||
|
||||
outStreamlines.push_back( streamline );
|
||||
|
||||
m_seeds.pop_front();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimStreamlineGenerator2::growStreamline( RimStreamline* streamline,
|
||||
size_t cellIdx,
|
||||
cvf::StructGridInterface::FaceType faceIdx,
|
||||
double direction )
|
||||
{
|
||||
// get the cell
|
||||
RigCell cell = m_dataAccess->grid()->cell( cellIdx );
|
||||
|
||||
// get rate
|
||||
RiaDefines::PhaseType dominantPhaseOut;
|
||||
double flowVelocity = std::abs( m_dataAccess->combinedFaceValueByArea( cell, faceIdx, m_phases, dominantPhaseOut ) );
|
||||
|
||||
while ( flowVelocity >= m_flowThreshold )
|
||||
{
|
||||
// grow from given face center to cell center, exiting if we reach the max length
|
||||
if ( !growStreamlineFromTo( streamline, cell.faceCenter( faceIdx ), cell.center(), flowVelocity, dominantPhaseOut ) )
|
||||
break;
|
||||
|
||||
// move to next cell
|
||||
RigCell neighbor = cell.neighborCell( faceIdx );
|
||||
if ( neighbor.isInvalid() ) break;
|
||||
|
||||
cvf::StructGridInterface::FaceType neighborFaceIdx = cvf::StructGridInterface::oppositeFace( faceIdx );
|
||||
|
||||
// get rate
|
||||
flowVelocity =
|
||||
std::abs( m_dataAccess->combinedFaceValueByArea( neighbor, neighborFaceIdx, m_phases, dominantPhaseOut ) );
|
||||
|
||||
// grow from face center to cell center, exiting if we reach the max point limit
|
||||
if ( !growStreamlineFromTo( streamline,
|
||||
neighbor.faceCenter( neighborFaceIdx ),
|
||||
neighbor.center(),
|
||||
flowVelocity,
|
||||
dominantPhaseOut ) )
|
||||
break;
|
||||
|
||||
// have we been here?
|
||||
if ( m_visitedCells.count( neighbor.gridLocalCellIndex() ) > 0 ) break;
|
||||
|
||||
// is this a well?
|
||||
if ( m_wellCells.count( neighbor.gridLocalCellIndex() ) > 0 ) break;
|
||||
|
||||
m_visitedCells.insert( neighbor.gridLocalCellIndex() );
|
||||
|
||||
// find the face with max flow where we should exit the cell
|
||||
cvf::StructGridInterface::FaceType exitFace = cvf::StructGridInterface::FaceType::NO_FACE;
|
||||
double maxRate = 0.0;
|
||||
|
||||
std::map<cvf::StructGridInterface::FaceType, double> rateMap;
|
||||
|
||||
for ( auto face : m_allFaces )
|
||||
{
|
||||
RiaDefines::PhaseType dummy;
|
||||
if ( face == neighborFaceIdx ) continue;
|
||||
double faceRate = m_dataAccess->combinedFaceValueByArea( neighbor, face, m_phases, dummy ) * direction;
|
||||
|
||||
if ( ( ( direction < 0.0 ) && ( faceRate < maxRate ) ) || ( ( direction > 0.0 ) && ( faceRate > maxRate ) ) )
|
||||
{
|
||||
exitFace = face;
|
||||
maxRate = faceRate;
|
||||
}
|
||||
|
||||
if ( face % 2 != 0 )
|
||||
rateMap[face] = -1.0 * faceRate * direction;
|
||||
else
|
||||
rateMap[face] = faceRate * direction;
|
||||
}
|
||||
|
||||
flowVelocity = std::abs( maxRate );
|
||||
faceIdx = exitFace;
|
||||
cell = neighbor;
|
||||
|
||||
// add seeds for other faces with flow > threshold
|
||||
for ( auto& kvp : rateMap )
|
||||
{
|
||||
if ( kvp.first == exitFace ) continue;
|
||||
if ( std::abs( kvp.second ) < m_flowThreshold ) continue;
|
||||
m_seeds.push_back( std::make_pair( neighbor.gridLocalCellIndex(), kvp.first ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool RimStreamlineGenerator2::growStreamlineFromTo( RimStreamline* streamline,
|
||||
cvf::Vec3d startPos,
|
||||
cvf::Vec3d endPos,
|
||||
double flowVelocity,
|
||||
RiaDefines::PhaseType dominantPhase )
|
||||
{
|
||||
double totDistance = endPos.pointDistance( startPos );
|
||||
|
||||
if ( totDistance < 0.1 ) return true;
|
||||
if ( flowVelocity < m_flowThreshold ) return false;
|
||||
|
||||
cvf::Vec3d direction = endPos - startPos;
|
||||
direction.normalize();
|
||||
direction *= flowVelocity;
|
||||
|
||||
int nSteps = (int)std::round( ( totDistance / flowVelocity ) / m_resolution );
|
||||
|
||||
cvf::Vec3d curpos = startPos;
|
||||
|
||||
for ( int i = 0; i < nSteps; i++ )
|
||||
{
|
||||
streamline->addTracerPoint( curpos, direction, dominantPhase );
|
||||
curpos = startPos + direction;
|
||||
|
||||
if ( streamline->size() > m_maxPoints ) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
@@ -0,0 +1,55 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2021 Equinor 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 "RiaDefines.h"
|
||||
|
||||
#include "RimStreamlineGeneratorBase.h"
|
||||
|
||||
#include <QString>
|
||||
|
||||
#include <list>
|
||||
#include <set>
|
||||
#include <utility>
|
||||
|
||||
class RigCell;
|
||||
class RimStreamline;
|
||||
|
||||
class RimStreamlineGenerator2 : public RimStreamlineGeneratorBase
|
||||
{
|
||||
public:
|
||||
RimStreamlineGenerator2( std::set<size_t>& wellCells );
|
||||
~RimStreamlineGenerator2();
|
||||
|
||||
void generateTracer( RigCell cell, double direction, QString simWellName, std::list<RimStreamline*>& outStreamlines ) override;
|
||||
|
||||
protected:
|
||||
void growStreamline( RimStreamline* streamline,
|
||||
size_t cellIdx,
|
||||
cvf::StructGridInterface::FaceType faceIdx,
|
||||
double direction );
|
||||
|
||||
bool growStreamlineFromTo( RimStreamline* streamline,
|
||||
cvf::Vec3d startPos,
|
||||
cvf::Vec3d endpos,
|
||||
double flowVelocity,
|
||||
RiaDefines::PhaseType dominantPhase );
|
||||
|
||||
std::list<std::pair<size_t, cvf::StructGridInterface::FaceType>> m_seeds;
|
||||
};
|
@@ -0,0 +1,68 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2021 Equinor 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 "RimStreamlineGeneratorBase.h"
|
||||
|
||||
#include "RigCell.h"
|
||||
#include "RigMainGrid.h"
|
||||
|
||||
#include "RimStreamline.h"
|
||||
#include "RimStreamlineDataAccess.h"
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RimStreamlineGeneratorBase::RimStreamlineGeneratorBase( std::set<size_t>& wellCells )
|
||||
: m_maxDays( 10000 )
|
||||
, m_flowThreshold( 0.0 )
|
||||
, m_resolution( 10.0 )
|
||||
, m_wellCells( wellCells )
|
||||
, m_dataAccess( nullptr )
|
||||
, m_maxPoints( 1 )
|
||||
{
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RimStreamlineGeneratorBase::~RimStreamlineGeneratorBase()
|
||||
{
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimStreamlineGeneratorBase::setLimits( double flowThreshold, int maxDays, double resolutionInDays )
|
||||
{
|
||||
m_flowThreshold = flowThreshold;
|
||||
m_maxDays = maxDays;
|
||||
m_resolution = resolutionInDays;
|
||||
m_maxPoints = maxDays / resolutionInDays;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimStreamlineGeneratorBase::initGenerator( RimStreamlineDataAccess* dataAccess, std::list<RiaDefines::PhaseType> phases )
|
||||
{
|
||||
m_dataAccess = dataAccess;
|
||||
|
||||
m_phases.clear();
|
||||
for ( auto phase : phases )
|
||||
m_phases.push_back( phase );
|
||||
}
|
@@ -0,0 +1,71 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2021 Equinor 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 "RiaDefines.h"
|
||||
|
||||
#include "cvfStructGrid.h"
|
||||
|
||||
#include <list>
|
||||
#include <set>
|
||||
|
||||
#include <QString>
|
||||
|
||||
class RigCell;
|
||||
class RimStreamline;
|
||||
class RigMainGrid;
|
||||
class RigGridBase;
|
||||
class RigResultAccessor;
|
||||
class RigEclipseCaseData;
|
||||
class RimStreamlineDataAccess;
|
||||
|
||||
class RimStreamlineGeneratorBase
|
||||
{
|
||||
public:
|
||||
RimStreamlineGeneratorBase( std::set<size_t>& wellCells );
|
||||
~RimStreamlineGeneratorBase();
|
||||
|
||||
void setLimits( double flowThreshold, int maxDays, double resolutionInDays );
|
||||
|
||||
void initGenerator( RimStreamlineDataAccess* dataAccess, std::list<RiaDefines::PhaseType> phases );
|
||||
|
||||
virtual void
|
||||
generateTracer( RigCell cell, double direction, QString simWellName, std::list<RimStreamline*>& outStreamlines ) = 0;
|
||||
|
||||
protected:
|
||||
double m_flowThreshold;
|
||||
int m_maxDays;
|
||||
double m_resolution;
|
||||
|
||||
size_t m_maxPoints;
|
||||
|
||||
std::set<size_t> m_visitedCells;
|
||||
|
||||
std::set<size_t>& m_wellCells;
|
||||
|
||||
RimStreamlineDataAccess* m_dataAccess;
|
||||
std::list<RiaDefines::PhaseType> m_phases;
|
||||
|
||||
const std::list<cvf::StructGridInterface::FaceType> m_allFaces = { cvf::StructGridInterface::FaceType::POS_I,
|
||||
cvf::StructGridInterface::FaceType::NEG_I,
|
||||
cvf::StructGridInterface::FaceType::POS_J,
|
||||
cvf::StructGridInterface::FaceType::NEG_J,
|
||||
cvf::StructGridInterface::FaceType::POS_K,
|
||||
cvf::StructGridInterface::FaceType::NEG_K };
|
||||
};
|
@@ -0,0 +1,688 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2020- Equinor 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 versio<n.
|
||||
//
|
||||
// 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 "RimStreamlineInViewCollection.h"
|
||||
#include "RigCaseCellResultsData.h"
|
||||
#include "RigCell.h"
|
||||
#include "RigEclipseCaseData.h"
|
||||
#include "RigEclipseResultAddress.h"
|
||||
#include "RigGridBase.h"
|
||||
#include "RigMainGrid.h"
|
||||
#include "RigResultAccessor.h"
|
||||
#include "RigResultAccessorFactory.h"
|
||||
#include "RigSimWellData.h"
|
||||
#include "RigTracerPoint.h"
|
||||
|
||||
#include "RimEclipseCase.h"
|
||||
#include "RimEclipseView.h"
|
||||
#include "RimRegularLegendConfig.h"
|
||||
#include "RimStreamline.h"
|
||||
#include "RimStreamlineDataAccess.h"
|
||||
#include "RimStreamlineGenerator2.h"
|
||||
|
||||
#include "RiaLogging.h"
|
||||
|
||||
#include "RiuViewer.h"
|
||||
|
||||
#include "cafPdmFieldScriptingCapability.h"
|
||||
#include "cafPdmObjectScriptingCapability.h"
|
||||
#include "cafPdmUiDoubleSliderEditor.h"
|
||||
#include "cafPdmUiSliderEditor.h"
|
||||
#include "cafPdmUiTreeOrdering.h"
|
||||
#include "cafProgressInfo.h"
|
||||
|
||||
#include "cvfCollection.h"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
namespace caf
|
||||
{
|
||||
template <>
|
||||
void AppEnum<RimStreamlineInViewCollection::VisualizationMode>::setUp()
|
||||
{
|
||||
addItem( RimStreamlineInViewCollection::VisualizationMode::ANIMATION, "ANIMATION", "Animation" );
|
||||
addItem( RimStreamlineInViewCollection::VisualizationMode::MANUAL, "MANUAL", "Manual control" );
|
||||
addItem( RimStreamlineInViewCollection::VisualizationMode::VECTORS, "VECTORS", "Vectors" );
|
||||
setDefault( RimStreamlineInViewCollection::VisualizationMode::ANIMATION );
|
||||
}
|
||||
|
||||
template <>
|
||||
void AppEnum<RimStreamlineInViewCollection::StreamlinePhaseType>::setUp()
|
||||
{
|
||||
addItem( RimStreamlineInViewCollection::StreamlinePhaseType::OIL, "OIL", "Oil" );
|
||||
addItem( RimStreamlineInViewCollection::StreamlinePhaseType::GAS, "GAS", "Gas" );
|
||||
addItem( RimStreamlineInViewCollection::StreamlinePhaseType::WATER, "WATER", "Water" );
|
||||
addItem( RimStreamlineInViewCollection::StreamlinePhaseType::COMBINED, "COMBINED", "Combined" );
|
||||
setDefault( RimStreamlineInViewCollection::StreamlinePhaseType::OIL );
|
||||
}
|
||||
|
||||
} // namespace caf
|
||||
|
||||
CAF_PDM_SOURCE_INIT( RimStreamlineInViewCollection, "StreamlineInViewCollection" );
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RimStreamlineInViewCollection::RimStreamlineInViewCollection()
|
||||
: m_shouldGenerateTracers( false )
|
||||
, m_currentTimestep( -1 )
|
||||
{
|
||||
CAF_PDM_InitScriptableObject( "Streamlines", ":/Erase.png", "", "" );
|
||||
|
||||
CAF_PDM_InitFieldNoDefault( &m_legendConfig, "LegendDefinition", "Color Legend", "", "", "" );
|
||||
m_legendConfig = new RimRegularLegendConfig();
|
||||
m_legendConfig.uiCapability()->setUiHidden( true );
|
||||
|
||||
CAF_PDM_InitScriptableFieldNoDefault( &m_collectionName, "Name", "Name", "", "", "" );
|
||||
m_collectionName = "Streamlines";
|
||||
m_collectionName.uiCapability()->setUiReadOnly( true );
|
||||
|
||||
CAF_PDM_InitScriptableFieldNoDefault( &m_flowThreshold, "FlowThreshold", "Flow Threshold [m/day]", "", "", "" );
|
||||
m_flowThreshold = 0.001;
|
||||
|
||||
CAF_PDM_InitScriptableFieldNoDefault( &m_lengthThreshold, "LengthThreshold", "Minimum Length [m]", "", "", "" );
|
||||
m_lengthThreshold = 100.0;
|
||||
|
||||
CAF_PDM_InitScriptableFieldNoDefault( &m_resolution, "Resolution", "Resolution [days]", "", "", "" );
|
||||
m_resolution = 20.0;
|
||||
|
||||
CAF_PDM_InitScriptableFieldNoDefault( &m_maxDays, "MaxDays", "Max Days", "", "", "" );
|
||||
m_maxDays = 50000;
|
||||
|
||||
CAF_PDM_InitScriptableFieldNoDefault( &m_useProducers, "UseProducers", "Producer Wells", "", "", "" );
|
||||
m_useProducers = true;
|
||||
|
||||
CAF_PDM_InitScriptableFieldNoDefault( &m_useInjectors, "UseInjectors", "Injector Wells", "", "", "" );
|
||||
m_useInjectors = true;
|
||||
|
||||
CAF_PDM_InitScriptableField( &m_phases, "Phase", StreamlinePhaseTypeEnum( StreamlinePhaseType::OIL ), "Phase", "", "", "" );
|
||||
|
||||
CAF_PDM_InitField( &m_isActive, "isActive", false, "Active", "", "", "" );
|
||||
m_isActive.uiCapability()->setUiHidden( true );
|
||||
|
||||
CAF_PDM_InitFieldNoDefault( &m_visualizationMode, "VisualizationMode", "Visualization Mode", "", "", "" );
|
||||
|
||||
CAF_PDM_InitFieldNoDefault( &m_animationSpeed, "AnimationSpeed", "Animation Speed", "", "", "" );
|
||||
m_animationSpeed.uiCapability()->setUiEditorTypeName( caf::PdmUiSliderEditor::uiEditorTypeName() );
|
||||
m_animationSpeed = 10;
|
||||
|
||||
CAF_PDM_InitFieldNoDefault( &m_animationIndex, "AnimationIndex", "Animation Index", "", "", "" );
|
||||
m_animationIndex.uiCapability()->setUiEditorTypeName( caf::PdmUiSliderEditor::uiEditorTypeName() );
|
||||
m_animationIndex = 0;
|
||||
m_maxAnimationIndex = 0;
|
||||
|
||||
CAF_PDM_InitFieldNoDefault( &m_scaleFactor, "ScaleFactor", "Scale Factor", "", "", "" );
|
||||
m_scaleFactor.uiCapability()->setUiEditorTypeName( caf::PdmUiDoubleSliderEditor::uiEditorTypeName() );
|
||||
m_scaleFactor = 100.0;
|
||||
|
||||
CAF_PDM_InitFieldNoDefault( &m_tracerLength, "TracerLength", "Tracer Length", "", "", "" );
|
||||
m_tracerLength.uiCapability()->setUiEditorTypeName( caf::PdmUiSliderEditor::uiEditorTypeName() );
|
||||
m_tracerLength = 100;
|
||||
|
||||
CAF_PDM_InitFieldNoDefault( &m_injectionDeltaTime, "InjectionDeltaTime", "Pause between injections", "", "", "" );
|
||||
m_injectionDeltaTime.uiCapability()->setUiEditorTypeName( caf::PdmUiSliderEditor::uiEditorTypeName() );
|
||||
m_injectionDeltaTime = 500;
|
||||
|
||||
CAF_PDM_InitScriptableFieldNoDefault( &m_streamlines, "Streamlines", "Streamlines", "", "", "" );
|
||||
m_streamlines.uiCapability()->setUiTreeHidden( true );
|
||||
m_streamlines.xmlCapability()->disableIO();
|
||||
|
||||
m_eclipseCase = nullptr;
|
||||
|
||||
// we are a topmost folder, do not delete us
|
||||
setDeletable( false );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RimStreamlineInViewCollection::~RimStreamlineInViewCollection()
|
||||
{
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
caf::PdmFieldHandle* RimStreamlineInViewCollection::objectToggleField()
|
||||
{
|
||||
return &m_isActive;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimStreamlineInViewCollection::setEclipseCase( RimEclipseCase* reservoir )
|
||||
{
|
||||
m_shouldGenerateTracers = true;
|
||||
m_eclipseCase = reservoir;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RimEclipseCase* RimStreamlineInViewCollection::eclipseCase() const
|
||||
{
|
||||
return m_eclipseCase;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool RimStreamlineInViewCollection::isActive() const
|
||||
{
|
||||
return m_isActive();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::list<RiaDefines::PhaseType> RimStreamlineInViewCollection::phases() const
|
||||
{
|
||||
std::list<RiaDefines::PhaseType> retval;
|
||||
|
||||
switch ( m_phases() )
|
||||
{
|
||||
case StreamlinePhaseType::OIL:
|
||||
retval.push_back( RiaDefines::PhaseType::OIL_PHASE );
|
||||
break;
|
||||
case StreamlinePhaseType::GAS:
|
||||
retval.push_back( RiaDefines::PhaseType::GAS_PHASE );
|
||||
break;
|
||||
case StreamlinePhaseType::WATER:
|
||||
retval.push_back( RiaDefines::PhaseType::WATER_PHASE );
|
||||
break;
|
||||
|
||||
case StreamlinePhaseType::COMBINED:
|
||||
retval.push_back( RiaDefines::PhaseType::OIL_PHASE );
|
||||
retval.push_back( RiaDefines::PhaseType::GAS_PHASE );
|
||||
retval.push_back( RiaDefines::PhaseType::WATER_PHASE );
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RimStreamlineInViewCollection::VisualizationMode RimStreamlineInViewCollection::visualizationMode() const
|
||||
{
|
||||
return m_visualizationMode();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
const std::list<RigTracer>& RimStreamlineInViewCollection::tracers()
|
||||
{
|
||||
m_activeTracers.clear();
|
||||
|
||||
for ( auto& streamline : m_streamlines() )
|
||||
{
|
||||
if ( streamline->tracer().size() > 1 )
|
||||
{
|
||||
m_activeTracers.push_back( streamline->tracer() );
|
||||
}
|
||||
}
|
||||
return m_activeTracers;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
const RimRegularLegendConfig* RimStreamlineInViewCollection::legendConfig() const
|
||||
{
|
||||
return m_legendConfig();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimStreamlineInViewCollection::mappingRange( double& min, double& max ) const
|
||||
{
|
||||
min = HUGE_VAL;
|
||||
max = -HUGE_VAL;
|
||||
|
||||
for ( auto& streamline : m_streamlines() )
|
||||
{
|
||||
const RigTracer& tracer = streamline->tracer();
|
||||
for ( size_t i = 0; i < tracer.tracerPoints().size() - 1; i++ )
|
||||
{
|
||||
min = std::min( min, tracer.tracerPoints()[i].absValue() );
|
||||
max = std::max( max, tracer.tracerPoints()[i].absValue() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimStreamlineInViewCollection::updateLegendRangesTextAndVisibility( RiuViewer* nativeOrOverrideViewer,
|
||||
bool isUsingOverrideViewer )
|
||||
{
|
||||
if ( m_isActive() && ( m_streamlines.size() > 0 ) && m_legendConfig->showLegend() )
|
||||
{
|
||||
QString title = "Streamlines: \n";
|
||||
title += m_phases().uiText() + " flow\n";
|
||||
m_legendConfig->setTitle( title );
|
||||
|
||||
double minResultValue;
|
||||
double maxResultValue;
|
||||
mappingRange( minResultValue, maxResultValue );
|
||||
m_legendConfig->setAutomaticRanges( minResultValue, maxResultValue, minResultValue, maxResultValue );
|
||||
|
||||
double posClosestToZero = HUGE_VAL;
|
||||
double negClosestToZero = -HUGE_VAL;
|
||||
m_legendConfig->setClosestToZeroValues( posClosestToZero, negClosestToZero, posClosestToZero, negClosestToZero );
|
||||
|
||||
nativeOrOverrideViewer->addColorLegendToBottomLeftCorner( m_legendConfig->titledOverlayFrame(),
|
||||
isUsingOverrideViewer );
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// Main entry point for triggering a streamline update
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimStreamlineInViewCollection::updateFromCurrentTimeStep( int timeStep )
|
||||
{
|
||||
if ( timeStep != m_currentTimestep )
|
||||
{
|
||||
m_shouldGenerateTracers = true;
|
||||
m_currentTimestep = timeStep;
|
||||
}
|
||||
|
||||
updateStreamlines();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
size_t RimStreamlineInViewCollection::animationSpeed() const
|
||||
{
|
||||
return m_animationSpeed();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
size_t RimStreamlineInViewCollection::animationIndex() const
|
||||
{
|
||||
return m_animationIndex();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
double RimStreamlineInViewCollection::scaleFactor() const
|
||||
{
|
||||
return m_scaleFactor();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
size_t RimStreamlineInViewCollection::tracerLength() const
|
||||
{
|
||||
return m_tracerLength();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
size_t RimStreamlineInViewCollection::injectionDeltaTime() const
|
||||
{
|
||||
return m_injectionDeltaTime();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimStreamlineInViewCollection::refresh()
|
||||
{
|
||||
m_shouldGenerateTracers = true;
|
||||
updateStreamlines();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimStreamlineInViewCollection::findStartCells( int timeIdx,
|
||||
std::vector<std::pair<QString, RigCell>>& outInjectorCells,
|
||||
std::vector<std::pair<QString, RigCell>>& outProducerCells )
|
||||
{
|
||||
// get the simulation wells
|
||||
const cvf::Collection<RigSimWellData>& simWellData = eclipseCase()->eclipseCaseData()->wellResults();
|
||||
|
||||
std::vector<const RigGridBase*> grids;
|
||||
eclipseCase()->eclipseCaseData()->allGrids( &grids );
|
||||
|
||||
// go through all sim wells and find all open producer and injector cells for the given timestep
|
||||
for ( auto& swdata : simWellData )
|
||||
{
|
||||
if ( !swdata->hasWellResult( timeIdx ) || !swdata->hasAnyValidCells( timeIdx ) ) continue;
|
||||
|
||||
RigWellResultFrame frame = swdata->wellResultFrame( timeIdx );
|
||||
|
||||
for ( auto& branch : frame.m_wellResultBranches )
|
||||
{
|
||||
for ( const auto& point : branch.m_branchResultPoints )
|
||||
{
|
||||
if ( point.isValid() && point.m_isOpen )
|
||||
{
|
||||
RigCell cell = grids[point.m_gridIndex]->cell( point.m_gridCellIndex );
|
||||
if ( frame.m_productionType == RigWellResultFrame::WellProductionType::PRODUCER )
|
||||
{
|
||||
outProducerCells.push_back( std::pair<QString, RigCell>( swdata->m_wellName, cell ) );
|
||||
}
|
||||
else if ( frame.m_productionType != RigWellResultFrame::WellProductionType::UNDEFINED_PRODUCTION_TYPE )
|
||||
{
|
||||
outInjectorCells.push_back( std::pair<QString, RigCell>( swdata->m_wellName, cell ) );
|
||||
}
|
||||
m_wellCellIds.insert( cell.mainGridCellIndex() );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// Main entry point for generating streamlines/tracers
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimStreamlineInViewCollection::updateStreamlines()
|
||||
{
|
||||
bool bNeedRedraw = ( m_streamlines.size() > 0 );
|
||||
|
||||
// get the view
|
||||
RimEclipseView* eclView = nullptr;
|
||||
this->firstAncestorOrThisOfType( eclView );
|
||||
if ( !eclView ) return;
|
||||
|
||||
if ( m_shouldGenerateTracers && isActive() )
|
||||
{
|
||||
// reset generated streamlines
|
||||
m_streamlines().clear();
|
||||
m_wellCellIds.clear();
|
||||
|
||||
// get current simulation timestep
|
||||
int timeIdx = eclView->currentTimeStep();
|
||||
|
||||
// get the well cells we should start growing from
|
||||
std::vector<std::pair<QString, RigCell>> seedCellsInjector;
|
||||
std::vector<std::pair<QString, RigCell>> seedCellsProducer;
|
||||
findStartCells( timeIdx, seedCellsInjector, seedCellsProducer );
|
||||
|
||||
// set up the data access helper
|
||||
RimStreamlineDataAccess dataAccess;
|
||||
bool accessOk = dataAccess.setupDataAccess( eclipseCase()->eclipseCaseData()->mainGrid(),
|
||||
eclipseCase()->eclipseCaseData(),
|
||||
phases(),
|
||||
timeIdx );
|
||||
|
||||
// did we find the data we needed?
|
||||
if ( accessOk )
|
||||
{
|
||||
// setup the streamline generator to use
|
||||
RimStreamlineGenerator2 generator( m_wellCellIds );
|
||||
generator.setLimits( m_flowThreshold, m_maxDays, m_resolution );
|
||||
generator.initGenerator( &dataAccess, phases() );
|
||||
|
||||
const int reverseDirection = -1.0;
|
||||
const int normalDirection = 1.0;
|
||||
|
||||
std::list<RimStreamline*> streamlines;
|
||||
|
||||
size_t seedsCount = 0;
|
||||
if ( m_useInjectors() ) seedsCount += seedCellsInjector.size();
|
||||
if ( m_useProducers() ) seedsCount += seedCellsProducer.size();
|
||||
|
||||
caf::ProgressInfo streamlineProgress( seedsCount, "Generating Streamlines" );
|
||||
|
||||
// generate tracers for all injectors
|
||||
if ( m_useInjectors() )
|
||||
{
|
||||
for ( auto& cellinfo : seedCellsInjector )
|
||||
{
|
||||
generator.generateTracer( cellinfo.second, normalDirection, cellinfo.first, streamlines );
|
||||
streamlineProgress.incrementProgress();
|
||||
}
|
||||
}
|
||||
|
||||
// generate tracers for all producers, make sure to invert the direction to backtrack the traces
|
||||
if ( m_useProducers() )
|
||||
{
|
||||
for ( auto& cellinfo : seedCellsProducer )
|
||||
{
|
||||
generator.generateTracer( cellinfo.second, reverseDirection, cellinfo.first, streamlines );
|
||||
streamlineProgress.incrementProgress();
|
||||
}
|
||||
}
|
||||
|
||||
// get rid of empty and too short streamlines
|
||||
m_maxAnimationIndex = 0;
|
||||
for ( auto& sline : streamlines )
|
||||
{
|
||||
if ( sline && sline->size() > 1 )
|
||||
{
|
||||
double distance = sline->tracer().totalDistance();
|
||||
|
||||
if ( distance >= m_lengthThreshold )
|
||||
{
|
||||
m_maxAnimationIndex = std::max( sline->size(), m_maxAnimationIndex );
|
||||
sline->generateStatistics();
|
||||
m_streamlines.push_back( sline );
|
||||
sline = nullptr;
|
||||
}
|
||||
if ( sline ) delete sline;
|
||||
}
|
||||
}
|
||||
|
||||
bNeedRedraw = true;
|
||||
}
|
||||
m_shouldGenerateTracers = false;
|
||||
}
|
||||
|
||||
if ( bNeedRedraw )
|
||||
{
|
||||
eclView->scheduleCreateDisplayModelAndRedraw();
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// debug output
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimStreamlineInViewCollection::outputSummary() const
|
||||
{
|
||||
qDebug() << "Generated" << m_streamlines.size() << " tracers";
|
||||
|
||||
for ( auto s : m_streamlines )
|
||||
{
|
||||
QString debStr( "Tracer for well " );
|
||||
debStr += s->simWellName();
|
||||
debStr += " of length ";
|
||||
debStr += QString::number( s->tracer().totalDistance(), 'f', 2 );
|
||||
debStr += " meters and ";
|
||||
debStr += QString::number( s->tracer().size() );
|
||||
debStr += " points.";
|
||||
qDebug() << debStr;
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimStreamlineInViewCollection::initAfterRead()
|
||||
{
|
||||
RimEclipseView* eclView = nullptr;
|
||||
this->firstAncestorOrThisOfType( eclView );
|
||||
|
||||
if ( eclView && m_isActive() ) eclView->requestAnimationTimer();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimStreamlineInViewCollection::defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering )
|
||||
{
|
||||
uiOrdering.add( &m_collectionName );
|
||||
|
||||
caf::PdmUiGroup* dataGroup = uiOrdering.addNewGroup( "Data Selection" );
|
||||
dataGroup->add( &m_phases );
|
||||
dataGroup->add( &m_flowThreshold );
|
||||
dataGroup->add( &m_lengthThreshold );
|
||||
dataGroup->add( &m_resolution );
|
||||
dataGroup->add( &m_maxDays );
|
||||
|
||||
caf::PdmUiGroup* wellGroup = uiOrdering.addNewGroup( "Well Selection" );
|
||||
wellGroup->add( &m_useInjectors );
|
||||
wellGroup->add( &m_useProducers );
|
||||
|
||||
caf::PdmUiGroup* visualizationGroup = uiOrdering.addNewGroup( "Visualization Settings" );
|
||||
visualizationGroup->add( &m_visualizationMode );
|
||||
|
||||
if ( m_visualizationMode() == VisualizationMode::ANIMATION )
|
||||
{
|
||||
visualizationGroup->add( &m_animationSpeed );
|
||||
visualizationGroup->add( &m_tracerLength );
|
||||
visualizationGroup->add( &m_injectionDeltaTime );
|
||||
}
|
||||
if ( m_visualizationMode() == VisualizationMode::MANUAL )
|
||||
{
|
||||
visualizationGroup->add( &m_animationIndex );
|
||||
}
|
||||
if ( m_visualizationMode() == VisualizationMode::VECTORS )
|
||||
{
|
||||
visualizationGroup->add( &m_scaleFactor );
|
||||
}
|
||||
|
||||
uiOrdering.skipRemainingFields();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimStreamlineInViewCollection::defineUiTreeOrdering( caf::PdmUiTreeOrdering& uiTreeOrdering,
|
||||
QString uiConfigName /*= "" */ )
|
||||
{
|
||||
uiTreeOrdering.add( &m_legendConfig );
|
||||
uiTreeOrdering.skipRemainingChildren();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimStreamlineInViewCollection::defineEditorAttribute( const caf::PdmFieldHandle* field,
|
||||
QString uiConfigName,
|
||||
caf::PdmUiEditorAttribute* attribute )
|
||||
{
|
||||
if ( field == &m_animationSpeed )
|
||||
{
|
||||
caf::PdmUiSliderEditorAttribute* myAttr = dynamic_cast<caf::PdmUiSliderEditorAttribute*>( attribute );
|
||||
if ( myAttr )
|
||||
{
|
||||
myAttr->m_minimum = 1;
|
||||
myAttr->m_maximum = 100;
|
||||
}
|
||||
}
|
||||
else if ( field == &m_animationIndex )
|
||||
{
|
||||
caf::PdmUiSliderEditorAttribute* myAttr = dynamic_cast<caf::PdmUiSliderEditorAttribute*>( attribute );
|
||||
if ( myAttr )
|
||||
{
|
||||
myAttr->m_minimum = 0;
|
||||
myAttr->m_maximum = static_cast<int>( m_maxAnimationIndex );
|
||||
}
|
||||
}
|
||||
else if ( field == &m_tracerLength )
|
||||
{
|
||||
caf::PdmUiSliderEditorAttribute* myAttr = dynamic_cast<caf::PdmUiSliderEditorAttribute*>( attribute );
|
||||
if ( myAttr )
|
||||
{
|
||||
myAttr->m_minimum = 1;
|
||||
myAttr->m_maximum = static_cast<int>( 1000 );
|
||||
}
|
||||
}
|
||||
else if ( field == &m_injectionDeltaTime )
|
||||
{
|
||||
caf::PdmUiSliderEditorAttribute* myAttr = dynamic_cast<caf::PdmUiSliderEditorAttribute*>( attribute );
|
||||
if ( myAttr )
|
||||
{
|
||||
myAttr->m_minimum = 1;
|
||||
myAttr->m_maximum = static_cast<int>( 1000 );
|
||||
}
|
||||
}
|
||||
else if ( field == &m_scaleFactor )
|
||||
{
|
||||
caf::PdmUiDoubleSliderEditorAttribute* myAttr = dynamic_cast<caf::PdmUiDoubleSliderEditorAttribute*>( attribute );
|
||||
if ( myAttr )
|
||||
{
|
||||
myAttr->m_minimum = 0.1;
|
||||
myAttr->m_maximum = 10000.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimStreamlineInViewCollection::fieldChangedByUi( const caf::PdmFieldHandle* changedField,
|
||||
const QVariant& oldValue,
|
||||
const QVariant& newValue )
|
||||
{
|
||||
if ( changedField == &m_animationSpeed || changedField == &m_animationIndex ||
|
||||
changedField == &m_injectionDeltaTime || changedField == &m_tracerLength )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ( changedField == &m_visualizationMode &&
|
||||
qvariant_cast<int>( newValue ) != static_cast<int>( VisualizationMode::VECTORS ) &&
|
||||
qvariant_cast<int>( oldValue ) != static_cast<int>( VisualizationMode::VECTORS ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ( changedField == &m_lengthThreshold || changedField == &m_flowThreshold || changedField == &m_resolution ||
|
||||
changedField == &m_maxDays || changedField == &m_useProducers || changedField == &m_useInjectors ||
|
||||
changedField == &m_phases )
|
||||
{
|
||||
m_shouldGenerateTracers = true;
|
||||
}
|
||||
|
||||
RimEclipseView* eclView = nullptr;
|
||||
this->firstAncestorOrThisOfType( eclView );
|
||||
|
||||
if ( changedField == &m_isActive )
|
||||
{
|
||||
if ( eclView )
|
||||
{
|
||||
if ( m_isActive() )
|
||||
eclView->requestAnimationTimer();
|
||||
else
|
||||
eclView->releaseAnimationTimer();
|
||||
}
|
||||
}
|
||||
|
||||
if ( eclView ) eclView->scheduleCreateDisplayModelAndRedraw();
|
||||
}
|
@@ -0,0 +1,138 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2020- Equinor 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 "RiaDefines.h"
|
||||
|
||||
#include "cafPdmChildArrayField.h"
|
||||
#include "cafPdmChildField.h"
|
||||
#include "cafPdmField.h"
|
||||
#include "cafPdmObject.h"
|
||||
|
||||
#include <list>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
class RimStreamline;
|
||||
class RimEclipseCase;
|
||||
class RimRegularLegendConfig;
|
||||
|
||||
class RigTracer;
|
||||
class RigCell;
|
||||
|
||||
class RiuViewer;
|
||||
|
||||
class RimStreamlineInViewCollection : public caf::PdmObject
|
||||
{
|
||||
CAF_PDM_HEADER_INIT;
|
||||
|
||||
public:
|
||||
enum class VisualizationMode
|
||||
{
|
||||
ANIMATION = 0,
|
||||
MANUAL,
|
||||
VECTORS
|
||||
};
|
||||
using VisualizationModeEnum = caf::AppEnum<VisualizationMode>;
|
||||
|
||||
enum class StreamlinePhaseType
|
||||
{
|
||||
OIL,
|
||||
GAS,
|
||||
WATER,
|
||||
COMBINED
|
||||
};
|
||||
using StreamlinePhaseTypeEnum = caf::AppEnum<StreamlinePhaseType>;
|
||||
|
||||
public:
|
||||
RimStreamlineInViewCollection();
|
||||
~RimStreamlineInViewCollection() override;
|
||||
|
||||
void setEclipseCase( RimEclipseCase* reservoir );
|
||||
RimEclipseCase* eclipseCase() const;
|
||||
|
||||
std::list<RiaDefines::PhaseType> phases() const;
|
||||
|
||||
VisualizationMode visualizationMode() const;
|
||||
size_t animationSpeed() const;
|
||||
size_t animationIndex() const;
|
||||
double scaleFactor() const;
|
||||
size_t tracerLength() const;
|
||||
size_t injectionDeltaTime() const;
|
||||
|
||||
bool isActive() const;
|
||||
|
||||
void refresh();
|
||||
|
||||
const std::list<RigTracer>& tracers();
|
||||
|
||||
const RimRegularLegendConfig* legendConfig() const;
|
||||
void mappingRange( double& min, double& max ) const;
|
||||
void updateLegendRangesTextAndVisibility( RiuViewer* nativeOrOverrideViewer, bool isUsingOverrideViewer );
|
||||
void updateFromCurrentTimeStep( int timeStep );
|
||||
|
||||
protected:
|
||||
caf::PdmFieldHandle* objectToggleField() override;
|
||||
void updateStreamlines();
|
||||
void initAfterRead() override;
|
||||
|
||||
private:
|
||||
void findStartCells( int timeIdx,
|
||||
std::vector<std::pair<QString, RigCell>>& outInjectorCells,
|
||||
std::vector<std::pair<QString, RigCell>>& outProducerCells );
|
||||
|
||||
void defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) override;
|
||||
void defineUiTreeOrdering( caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName = "" ) override;
|
||||
void defineEditorAttribute( const caf::PdmFieldHandle* field,
|
||||
QString uiConfigName,
|
||||
caf::PdmUiEditorAttribute* attribute ) override;
|
||||
void fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue ) override;
|
||||
|
||||
void outputSummary() const;
|
||||
|
||||
private:
|
||||
caf::PdmField<bool> m_isActive;
|
||||
caf::PdmField<QString> m_collectionName;
|
||||
caf::PdmField<double> m_lengthThreshold;
|
||||
caf::PdmField<double> m_flowThreshold;
|
||||
caf::PdmField<double> m_resolution;
|
||||
caf::PdmField<double> m_maxDays;
|
||||
caf::PdmField<bool> m_useProducers;
|
||||
caf::PdmField<bool> m_useInjectors;
|
||||
caf::PdmPointer<RimEclipseCase> m_eclipseCase;
|
||||
caf::PdmChildArrayField<RimStreamline*> m_streamlines;
|
||||
caf::PdmField<StreamlinePhaseTypeEnum> m_phases;
|
||||
caf::PdmField<VisualizationModeEnum> m_visualizationMode;
|
||||
caf::PdmField<size_t> m_animationSpeed;
|
||||
caf::PdmField<size_t> m_animationIndex;
|
||||
caf::PdmField<double> m_scaleFactor;
|
||||
caf::PdmField<size_t> m_tracerLength;
|
||||
caf::PdmField<size_t> m_injectionDeltaTime;
|
||||
|
||||
size_t m_maxAnimationIndex;
|
||||
|
||||
bool m_shouldGenerateTracers;
|
||||
int m_currentTimestep;
|
||||
|
||||
std::list<RigTracer> m_activeTracers;
|
||||
|
||||
std::set<size_t> m_wellCellIds;
|
||||
|
||||
caf::PdmChildField<RimRegularLegendConfig*> m_legendConfig;
|
||||
};
|
@@ -83,6 +83,8 @@ ${CMAKE_CURRENT_LIST_DIR}/RigGocadData.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RigElasticProperties.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RigHistogramData.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RigVisibleTracerFilter.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RigTracerPoint.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RigTracer.h
|
||||
)
|
||||
|
||||
|
||||
@@ -163,6 +165,8 @@ ${CMAKE_CURRENT_LIST_DIR}/RigGocadData.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RigElasticProperties.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RigHistogramData.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RigVisibleTracerFilter.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RigTracerPoint.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RigTracer.cpp
|
||||
)
|
||||
|
||||
list(APPEND CODE_HEADER_FILES
|
||||
|
@@ -74,6 +74,28 @@ cvf::Vec3d RigCell::center() const
|
||||
return avg;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// Get the coordinates of the 4 corners of the given face
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::array<cvf::Vec3d, 4> RigCell::faceCorners( cvf::StructGridInterface::FaceType face ) const
|
||||
{
|
||||
std::array<cvf::Vec3d, 4> corners;
|
||||
cvf::ubyte faceVertexIndices[4];
|
||||
cvf::StructGridInterface::cellFaceVertexIndices( face, faceVertexIndices );
|
||||
|
||||
const std::vector<cvf::Vec3d>& nodeCoords = m_hostGrid->mainGrid()->nodes();
|
||||
|
||||
for ( size_t i = 0; i < 4; i++ )
|
||||
{
|
||||
corners[i] = nodeCoords[m_cornerIndices[faceVertexIndices[i]]];
|
||||
}
|
||||
|
||||
return corners;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool isNear( const cvf::Vec3d& p1, const cvf::Vec3d& p2, double tolerance )
|
||||
{
|
||||
if ( cvf::Math::abs( p1[0] - p2[0] ) < tolerance && cvf::Math::abs( p1[1] - p2[1] ) < tolerance &&
|
||||
@@ -418,3 +440,52 @@ cvf::BoundingBox RigCell::boundingBox() const
|
||||
}
|
||||
return bb;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// Return the neighbor cell of the given face
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RigCell RigCell::neighborCell( cvf::StructGridInterface::FaceType face ) const
|
||||
{
|
||||
size_t i, j, k;
|
||||
|
||||
m_hostGrid->ijkFromCellIndexUnguarded( mainGridCellIndex(), &i, &j, &k );
|
||||
|
||||
size_t neighborIdx;
|
||||
if ( m_hostGrid->cellIJKNeighbor( i, j, k, face, &neighborIdx ) )
|
||||
{
|
||||
return m_hostGrid->cell( neighborIdx );
|
||||
}
|
||||
|
||||
RigCell retcell;
|
||||
retcell.setInvalid( true );
|
||||
return retcell;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// Find and return the main grid cell index of all up to 26 neighbor cells to the given cell
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::vector<size_t> RigCell::allNeighborMainGridCellIndexes() const
|
||||
{
|
||||
std::vector<size_t> neighbors;
|
||||
|
||||
size_t ni, nj, nk;
|
||||
|
||||
m_hostGrid->ijkFromCellIndexUnguarded( mainGridCellIndex(), &ni, &nj, &nk );
|
||||
|
||||
for ( size_t i = ni - 1; i <= ni + 1; i++ )
|
||||
{
|
||||
for ( size_t j = nj - 1; j <= nj + 1; j++ )
|
||||
{
|
||||
for ( size_t k = nk - 1; k <= nk + 1; k++ )
|
||||
{
|
||||
if ( m_hostGrid->isCellValid( i, j, k ) )
|
||||
{
|
||||
size_t cellIndex = m_hostGrid->cellIndexFromIJK( i, j, k );
|
||||
if ( ( ni == i ) && ( nj == j ) && ( nk == k ) ) continue;
|
||||
neighbors.push_back( cellIndex );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return neighbors;
|
||||
}
|
||||
|
@@ -65,10 +65,11 @@ public:
|
||||
size_t coarseningBoxIndex() const { return m_coarseningBoxIndex; }
|
||||
void setCoarseningBoxIndex( size_t coarseningBoxIndex ) { m_coarseningBoxIndex = coarseningBoxIndex; }
|
||||
|
||||
cvf::Vec3d center() const;
|
||||
cvf::Vec3d faceCenter( cvf::StructGridInterface::FaceType face ) const;
|
||||
cvf::Vec3d faceNormalWithAreaLength( cvf::StructGridInterface::FaceType face ) const;
|
||||
double volume() const;
|
||||
cvf::Vec3d center() const;
|
||||
std::array<cvf::Vec3d, 4> faceCorners( cvf::StructGridInterface::FaceType face ) const;
|
||||
cvf::Vec3d faceCenter( cvf::StructGridInterface::FaceType face ) const;
|
||||
cvf::Vec3d faceNormalWithAreaLength( 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;
|
||||
@@ -76,6 +77,9 @@ public:
|
||||
|
||||
cvf::BoundingBox boundingBox() const;
|
||||
|
||||
RigCell neighborCell( cvf::StructGridInterface::FaceType face ) const;
|
||||
std::vector<size_t> allNeighborMainGridCellIndexes() const;
|
||||
|
||||
private:
|
||||
std::array<size_t, 8> m_cornerIndices;
|
||||
|
||||
|
106
ApplicationLibCode/ReservoirDataModel/RigTracer.cpp
Normal file
106
ApplicationLibCode/ReservoirDataModel/RigTracer.cpp
Normal file
@@ -0,0 +1,106 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2020 - Equinor 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 "RigTracer.h"
|
||||
#include "RigTracerPoint.h"
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RigTracer::RigTracer()
|
||||
{
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RigTracer::RigTracer( const RigTracer& other )
|
||||
: cvf::Object()
|
||||
{
|
||||
for ( auto p : other.m_points )
|
||||
{
|
||||
appendPoint( p.position(), p.direction(), p.phaseType() );
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RigTracer::~RigTracer()
|
||||
{
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RigTracer::appendPoint( cvf::Vec3d position, cvf::Vec3d direction, RiaDefines::PhaseType dominantPhase )
|
||||
{
|
||||
m_points.push_back( RigTracerPoint( position, direction, dominantPhase ) );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
const std::vector<RigTracerPoint>& RigTracer::tracerPoints() const
|
||||
{
|
||||
return m_points;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
size_t RigTracer::size() const
|
||||
{
|
||||
return m_points.size();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
double RigTracer::totalDistance() const
|
||||
{
|
||||
if ( m_points.size() < 2 ) return 0.0;
|
||||
|
||||
cvf::Vec3d sp = m_points.front().position();
|
||||
|
||||
double distance = 0.0;
|
||||
for ( size_t i = 1; i < m_points.size(); i++ )
|
||||
{
|
||||
distance += sp.pointDistance( m_points[i].position() );
|
||||
sp = m_points[i].position();
|
||||
}
|
||||
|
||||
return distance;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RigTracer::reverse()
|
||||
{
|
||||
if ( m_points.empty() ) return;
|
||||
|
||||
// Reverse ordering of all tracer points
|
||||
std::reverse( m_points.begin(), m_points.end() );
|
||||
|
||||
for ( auto& p : m_points )
|
||||
{
|
||||
// Reverse the flow direction in tracer point
|
||||
p.reverse();
|
||||
}
|
||||
}
|
51
ApplicationLibCode/ReservoirDataModel/RigTracer.h
Normal file
51
ApplicationLibCode/ReservoirDataModel/RigTracer.h
Normal file
@@ -0,0 +1,51 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2020 - Equinor 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 "RiaDefines.h"
|
||||
|
||||
#include "cvfObject.h"
|
||||
#include "cvfVector3.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
class RigTracerPoint;
|
||||
|
||||
//==================================================================================================
|
||||
/// Class representing one streamline tracer line, with position and direction given for each
|
||||
/// time increment.
|
||||
//==================================================================================================
|
||||
class RigTracer : public cvf::Object
|
||||
{
|
||||
public:
|
||||
RigTracer();
|
||||
explicit RigTracer( const RigTracer& other );
|
||||
~RigTracer() override;
|
||||
|
||||
void appendPoint( cvf::Vec3d position, cvf::Vec3d direction, RiaDefines::PhaseType dominantPhase );
|
||||
size_t size() const;
|
||||
double totalDistance() const;
|
||||
|
||||
void reverse();
|
||||
|
||||
const std::vector<RigTracerPoint>& tracerPoints() const;
|
||||
|
||||
private:
|
||||
std::vector<RigTracerPoint> m_points;
|
||||
};
|
77
ApplicationLibCode/ReservoirDataModel/RigTracerPoint.cpp
Normal file
77
ApplicationLibCode/ReservoirDataModel/RigTracerPoint.cpp
Normal file
@@ -0,0 +1,77 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2020 - Equinor 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 "RigTracerPoint.h"
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RigTracerPoint::RigTracerPoint( cvf::Vec3d position, cvf::Vec3d direction, RiaDefines::PhaseType phase )
|
||||
: m_position( position )
|
||||
, m_direction( direction )
|
||||
, m_phaseType( phase )
|
||||
{
|
||||
m_absValue = m_direction.length();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RigTracerPoint::~RigTracerPoint()
|
||||
{
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
const cvf::Vec3d& RigTracerPoint::position() const
|
||||
{
|
||||
return m_position;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
const cvf::Vec3d& RigTracerPoint::direction() const
|
||||
{
|
||||
return m_direction;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
double RigTracerPoint::absValue() const
|
||||
{
|
||||
return m_absValue;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RiaDefines::PhaseType RigTracerPoint::phaseType() const
|
||||
{
|
||||
return m_phaseType;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RigTracerPoint::reverse()
|
||||
{
|
||||
m_direction *= -1.0;
|
||||
}
|
48
ApplicationLibCode/ReservoirDataModel/RigTracerPoint.h
Normal file
48
ApplicationLibCode/ReservoirDataModel/RigTracerPoint.h
Normal file
@@ -0,0 +1,48 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2020 - Equinor 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 "RiaDefines.h"
|
||||
#include "cvfVector3.h"
|
||||
|
||||
//==================================================================================================
|
||||
/// Class representing one single point in a streamline tracer. The point has a position and
|
||||
/// and a direction vector. The absolute value of the direction vector is precalculated to save
|
||||
/// some calculation time later on.
|
||||
/// A phaseType flag indicates what was the dominant phase at this position.
|
||||
//==================================================================================================
|
||||
class RigTracerPoint
|
||||
{
|
||||
public:
|
||||
RigTracerPoint( cvf::Vec3d position, cvf::Vec3d direction, RiaDefines::PhaseType phase );
|
||||
~RigTracerPoint();
|
||||
|
||||
const cvf::Vec3d& position() const;
|
||||
const cvf::Vec3d& direction() const;
|
||||
double absValue() const;
|
||||
RiaDefines::PhaseType phaseType() const;
|
||||
|
||||
void reverse();
|
||||
|
||||
private:
|
||||
cvf::Vec3d m_position;
|
||||
cvf::Vec3d m_direction;
|
||||
double m_absValue;
|
||||
RiaDefines::PhaseType m_phaseType;
|
||||
};
|
@@ -21,8 +21,8 @@
|
||||
#include "cvfMath.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// A function to do basic statistical calculations
|
||||
|
Reference in New Issue
Block a user