mirror of
https://github.com/OPM/ResInsight.git
synced 2026-10-26 15:10:22 -05:00
RimStreamlineInViewCollection::findStartCells() dereferences eclipseCase() unchecked. The collection's case pointer can be null while the view's mainGrid() is valid, e.g. during project load before propagateEclipseCaseToChildObjects(). Return early from updateStreamlines() when the case or its data is missing. Call stack: [3] RimEclipseCase::eclipseCaseData() at ResInsight/ApplicationLibCode/ProjectDataModel/RimEclipseCase.cpp:197 [4] RimStreamlineInViewCollection::findStartCells(...) at ResInsight/ApplicationLibCode/ProjectDataModel/Streamlines/RimStreamlineInViewCollection.cpp:394 [5] RimStreamlineInViewCollection::updateStreamlines() at ResInsight/ApplicationLibCode/ProjectDataModel/Streamlines/RimStreamlineInViewCollection.cpp:454 [6] RimEclipseView::onUpdateDisplayModelForCurrentTimeStep() at ResInsight/ApplicationLibCode/ProjectDataModel/RimEclipseView.cpp:932 [7] Rim3dView::updateDisplayModelForCurrentTimeStepAndRedraw() at ResInsight/ApplicationLibCode/ProjectDataModel/Rim3dView.cpp:723 [8] RiuViewer::setCurrentFrame(int) at ResInsight/ApplicationLibCode/UserInterface/RiuViewer.cpp:1059 [9] RimEclipseView::onCreateDisplayModel() at ResInsight/ApplicationLibCode/ProjectDataModel/RimEclipseView.cpp:849 [10] Rim3dView::createDisplayModelAndRedraw() at ResInsight/ApplicationLibCode/ProjectDataModel/Rim3dView.cpp:768 [11] RiaViewRedrawScheduler::updateAndRedrawScheduledViews() at ResInsight/ApplicationLibCode/Application/RiaViewRedrawScheduler.cpp:93 [12] RiaApplication::loadProject(...) at ResInsight/ApplicationLibCode/Application/RiaApplication.cpp:953
675 lines
26 KiB
C++
675 lines
26 KiB
C++
/////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// 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 "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 "RigTracerPoint.h"
|
|
#include "Well/RigSimWellData.h"
|
|
#include "Well/RigWellResultFrame.h"
|
|
|
|
#include "RimEclipseCase.h"
|
|
#include "RimEclipseInputCase.h"
|
|
#include "RimEclipseView.h"
|
|
#include "RimRegularLegendConfig.h"
|
|
#include "RimStreamline.h"
|
|
#include "RimStreamlineDataAccess.h"
|
|
#include "RimStreamlineGenerator.h"
|
|
|
|
#include "RiaLogging.h"
|
|
|
|
#include "RiuViewer.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" );
|
|
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::COMBINED );
|
|
}
|
|
|
|
template <>
|
|
void AppEnum<RimStreamlineInViewCollection::ColorMode>::setUp()
|
|
{
|
|
addItem( RimStreamlineInViewCollection::ColorMode::PHASE_COLORS, "PHASE_COLORS", "Dominant Phase" );
|
|
addItem( RimStreamlineInViewCollection::ColorMode::VELOCITY, "VELOCITY", "Velocity" );
|
|
setDefault( RimStreamlineInViewCollection::ColorMode::PHASE_COLORS );
|
|
}
|
|
|
|
} // namespace caf
|
|
|
|
CAF_PDM_SOURCE_INIT( RimStreamlineInViewCollection, "StreamlineInViewCollection" );
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
RimStreamlineInViewCollection::RimStreamlineInViewCollection()
|
|
: m_shouldGenerateTracers( false )
|
|
, m_currentTimestep( -1 )
|
|
{
|
|
CAF_PDM_InitObject( "Streamlines", ":/Erase.png" );
|
|
|
|
CAF_PDM_InitFieldNoDefault( &m_legendConfig, "LegendDefinition", "Color Legend" );
|
|
m_legendConfig = new RimRegularLegendConfig();
|
|
m_legendConfig->setMappingMode( RimRegularLegendConfig::MappingType::LOG10_CONTINUOUS );
|
|
|
|
CAF_PDM_InitFieldNoDefault( &m_collectionName, "Name", "Name" );
|
|
m_collectionName = "Streamlines";
|
|
m_collectionName.uiCapability()->setUiReadOnly( true );
|
|
|
|
CAF_PDM_InitFieldNoDefault( &m_flowThreshold, "FlowThreshold", "Flow Threshold [m/day]" );
|
|
m_flowThreshold = 0.01;
|
|
|
|
CAF_PDM_InitFieldNoDefault( &m_lengthThreshold, "LengthThreshold", "Minimum Length [m]" );
|
|
m_lengthThreshold = 100.0;
|
|
|
|
CAF_PDM_InitFieldNoDefault( &m_resolution, "Resolution", "Resolution [days]" );
|
|
m_resolution = 20.0;
|
|
|
|
CAF_PDM_InitFieldNoDefault( &m_maxDays, "MaxDays", "Max Days" );
|
|
m_maxDays = 5000;
|
|
|
|
CAF_PDM_InitFieldNoDefault( &m_useProducers, "UseProducers", "Producer Wells" );
|
|
m_useProducers = true;
|
|
|
|
CAF_PDM_InitFieldNoDefault( &m_useInjectors, "UseInjectors", "Injector Wells" );
|
|
m_useInjectors = true;
|
|
|
|
CAF_PDM_InitFieldNoDefault( &m_phases, "Phase", "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_colorMode, "ColorMode", "Colors" );
|
|
|
|
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_streamlines, "Streamlines", "Streamlines" );
|
|
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 )
|
|
{
|
|
if ( reservoir != m_eclipseCase )
|
|
{
|
|
m_shouldGenerateTracers = true;
|
|
m_eclipseCase = reservoir;
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
RimEclipseCase* RimStreamlineInViewCollection::eclipseCase() const
|
|
{
|
|
return m_eclipseCase;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
bool RimStreamlineInViewCollection::isActive() const
|
|
{
|
|
return m_isActive();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
bool RimStreamlineInViewCollection::shouldBeAvailable() const
|
|
{
|
|
if ( ( eclipseCase() == nullptr ) || ( eclipseCase()->eclipseCaseData() == nullptr ) ) return false;
|
|
|
|
return ( dynamic_cast<RimEclipseInputCase*>( eclipseCase() ) == nullptr );
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
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();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
RimStreamlineInViewCollection::ColorMode RimStreamlineInViewCollection::colorMode() const
|
|
{
|
|
return m_colorMode();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
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.empty() ) && 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 );
|
|
|
|
if ( colorMode() == ColorMode::VELOCITY )
|
|
{
|
|
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();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
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;
|
|
|
|
auto frame = swdata->wellResultFrame( timeIdx );
|
|
|
|
for ( const auto& branch : frame->wellResultBranches() )
|
|
{
|
|
for ( const auto& point : branch.branchResultPoints() )
|
|
{
|
|
if ( point.isValid() && point.isOpen() )
|
|
{
|
|
RigCell cell = grids[point.gridIndex()]->cell( point.cellIndex() );
|
|
if ( frame->productionType() == RiaDefines::WellProductionType::PRODUCER )
|
|
{
|
|
outProducerCells.push_back( std::pair<QString, RigCell>( swdata->m_wellName, cell ) );
|
|
}
|
|
else if ( frame->productionType() != RiaDefines::WellProductionType::UNDEFINED_PRODUCTION_TYPE )
|
|
{
|
|
outInjectorCells.push_back( std::pair<QString, RigCell>( swdata->m_wellName, cell ) );
|
|
}
|
|
m_wellCellIds.insert( cell.gridLocalCellIndex() );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
/// Main entry point for generating streamlines/tracers
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimStreamlineInViewCollection::updateStreamlines()
|
|
{
|
|
bool bNeedRedraw = ( !m_streamlines.empty() );
|
|
|
|
// get the view
|
|
auto eclView = firstAncestorOrThisOfType<RimEclipseView>();
|
|
if ( !eclView ) return;
|
|
|
|
auto mainGrid = eclView->mainGrid();
|
|
if ( !mainGrid ) return;
|
|
|
|
if ( !eclipseCase() || !eclipseCase()->eclipseCaseData() ) return;
|
|
|
|
if ( m_shouldGenerateTracers && isActive() )
|
|
{
|
|
// reset generated streamlines
|
|
m_streamlines.deleteChildren();
|
|
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( mainGrid, eclipseCase()->eclipseCaseData(), phases(), timeIdx );
|
|
|
|
// did we find the data we needed?
|
|
if ( accessOk )
|
|
{
|
|
// setup the streamline generator to use
|
|
RimStreamlineGenerator generator( m_wellCellIds );
|
|
generator.setLimits( m_flowThreshold, m_maxDays, m_resolution, m_lengthThreshold );
|
|
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, please wait..." );
|
|
|
|
// 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 )
|
|
{
|
|
m_maxAnimationIndex = std::max( sline->size(), m_maxAnimationIndex );
|
|
m_streamlines.push_back( sline );
|
|
sline = nullptr;
|
|
}
|
|
}
|
|
|
|
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()
|
|
{
|
|
auto eclView = firstAncestorOrThisOfType<RimEclipseView>();
|
|
|
|
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 );
|
|
visualizationGroup->add( &m_colorMode );
|
|
|
|
if ( m_visualizationMode() == VisualizationMode::ANIMATION )
|
|
{
|
|
visualizationGroup->add( &m_animationSpeed );
|
|
visualizationGroup->add( &m_tracerLength );
|
|
}
|
|
else if ( m_visualizationMode() == VisualizationMode::MANUAL )
|
|
{
|
|
visualizationGroup->add( &m_animationIndex );
|
|
}
|
|
|
|
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_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_tracerLength ||
|
|
changedField == &m_visualizationMode )
|
|
{
|
|
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;
|
|
}
|
|
|
|
auto eclView = firstAncestorOrThisOfType<RimEclipseView>();
|
|
if ( changedField == &m_isActive )
|
|
{
|
|
if ( eclView )
|
|
{
|
|
if ( m_isActive() )
|
|
eclView->requestAnimationTimer();
|
|
else
|
|
eclView->releaseAnimationTimer();
|
|
}
|
|
}
|
|
|
|
if ( eclView ) eclView->scheduleCreateDisplayModelAndRedraw();
|
|
}
|