///////////////////////////////////////////////////////////////////////////////// // // 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 // for more details. // ///////////////////////////////////////////////////////////////////////////////// #include "RimEnsembleWellLogCurveSet.h" #include "RiaColorTools.h" #include "RiaLogging.h" #include "RiaOptionItemFactory.h" #include "RiaResultNames.h" #include "RimEnsembleCurveFilter.h" #include "RimEnsembleCurveFilterCollection.h" #include "RimEnsembleCurveSet.h" #include "RimEnsembleStatistics.h" #include "RimEnsembleWellLogStatistics.h" #include "RimEnsembleWellLogStatisticsCurve.h" #include "RimEnsembleWellLogs.h" #include "RimEnsembleWellLogsCollection.h" #include "RimFormationNames.h" #include "RimFormationNamesCollection.h" #include "RimMainPlotCollection.h" #include "RimOilField.h" #include "RimProject.h" #include "RimSummaryCase.h" #include "RimSummaryCaseCollection.h" #include "RimWellLogCurve.h" #include "RimWellLogFile.h" #include "RimWellLogFileChannel.h" #include "RimWellLogFileCurve.h" #include "RimWellLogPlot.h" #include "RimWellLogTrack.h" #include "RimWellPath.h" #include "RigFormationNames.h" #include "RigWellLogIndexDepthOffset.h" #include "RiuAbstractLegendFrame.h" #include "RiuDraggableOverlayFrame.h" #include "RiuPlotMainWindow.h" #include "RiuQwtPlotCurveDefines.h" #include "RiuQwtPlotWidget.h" #include "RiuQwtSymbol.h" #include "RiuTextContentFrame.h" #include "cafPdmObject.h" #include "cafPdmUiItem.h" #include "cafPdmUiTreeOrdering.h" #include "cvfObject.h" #include "qwt_plot.h" #include "qwt_plot_curve.h" #include "qwt_symbol.h" #include #include //-------------------------------------------------------------------------------------------------- /// Internal functions //-------------------------------------------------------------------------------------------------- int statisticsCurveSymbolSize( RiuPlotCurveSymbol::PointSymbolEnum symbol ); namespace caf { template <> void AppEnum::setUp() { addItem( RimEnsembleWellLogCurveSet::ColorMode::SINGLE_COLOR, "SINGLE_COLOR", "Single Color" ); addItem( RimEnsembleWellLogCurveSet::ColorMode::COLOR_BY_ENSEMBLE_CURVE_SET, "BY_ENSEMBLE_CURVE_SET", "Color by Ensemble Curve Set" ); setDefault( RimEnsembleWellLogCurveSet::ColorMode::SINGLE_COLOR ); } }; // namespace caf CAF_PDM_SOURCE_INIT( RimEnsembleWellLogCurveSet, "RimEnsembleWellLogCurveSet" ); //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RimEnsembleWellLogCurveSet::RimEnsembleWellLogCurveSet() : filterChanged( this ) { CAF_PDM_InitObject( "Ensemble Curve Set", ":/EnsembleCurveSet16x16.png" ); CAF_PDM_InitFieldNoDefault( &m_curves, "EnsembleCurveSet", "Ensemble Curve Set" ); m_curves.uiCapability()->setUiHidden( true ); m_curves.uiCapability()->setUiTreeChildrenHidden( false ); CAF_PDM_InitField( &m_showCurves, "IsActive", true, "Show Curves" ); m_showCurves.uiCapability()->setUiHidden( true ); CAF_PDM_InitFieldNoDefault( &m_ensembleWellLogs, "EnsembleWellLogs", "Ensemble Well Logs" ); m_ensembleWellLogs.uiCapability()->setUiTreeChildrenHidden( true ); CAF_PDM_InitField( &m_wellLogChannelName, "WellLogChannelName", QString( "None" ), "Well Log Channel Name" ); CAF_PDM_InitFieldNoDefault( &m_ensembleCurveSet, "FilterEnsembleCurveSet", "Filter by Ensemble Curve Set" ); CAF_PDM_InitFieldNoDefault( &m_depthEqualization, "DepthEqualization", "Depth Equalization" ); CAF_PDM_InitField( &m_colorMode, "ColorMode", caf::AppEnum( ColorMode::SINGLE_COLOR ), "Coloring Mode" ); CAF_PDM_InitField( &m_color, "Color", RiaColorTools::textColor3f(), "Color" ); CAF_PDM_InitFieldNoDefault( &m_statistics, "Statistics", "Statistics" ); m_statistics = new RimEnsembleStatistics( this ); m_statistics.uiCapability()->setUiTreeHidden( true ); CAF_PDM_InitField( &m_userDefinedName, "UserDefinedName", QString( "Ensemble Curve Set" ), "Curve Set Name" ); CAF_PDM_InitFieldNoDefault( &m_autoGeneratedName, "AutoGeneratedName", "Curve Set Name" ); m_autoGeneratedName.registerGetMethod( this, &RimEnsembleWellLogCurveSet::createAutoName ); m_autoGeneratedName.uiCapability()->setUiReadOnly( true ); m_autoGeneratedName.xmlCapability()->disableIO(); CAF_PDM_InitField( &m_isUsingAutoName, "AutoName", true, "Auto Name" ); CAF_PDM_InitFieldNoDefault( &m_curveAppearance, "PlotCurveAppearance", "PlotCurveAppearance" ); m_curveAppearance = new RimPlotCurveAppearance; m_curveAppearance.uiCapability()->setUiTreeHidden( true ); m_curveAppearance->setInterpolationVisible( false ); m_curveAppearance->setColorVisible( false ); m_curveAppearance->setFillOptionsVisible( false ); m_curveAppearance->setSymbol( RiuPlotCurveSymbol::PointSymbolEnum::SYMBOL_ELLIPSE ); m_curveAppearance->setSymbolSize( 5 ); m_curveAppearance->setLineStyle( RiuQwtPlotCurveDefines::LineStyleEnum::STYLE_NONE ); m_curveAppearance->setSymbolEdgeColor( cvf::Color3f::BLACK ); m_curveAppearance->appearanceChanged.connect( this, &RimEnsembleWellLogCurveSet::onEnsembleCurvesAppearanceChanged ); m_qwtPlotCurveForLegendText = new QwtPlotCurve; m_qwtPlotCurveForLegendText->setLegendAttribute( QwtPlotCurve::LegendShowSymbol, true ); m_ensembleWellLogStatistics.reset( new RimEnsembleWellLogStatistics ); m_disableStatisticCurves = false; m_isCurveSetFiltered = false; setDeletable( true ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RimEnsembleWellLogCurveSet::~RimEnsembleWellLogCurveSet() { auto plotTrack = firstAncestorOrThisOfType(); if ( plotTrack && plotTrack->viewer() ) { if ( m_legendOverlayFrame ) { plotTrack->viewer()->removeOverlayFrame( m_legendOverlayFrame ); } } if ( m_legendOverlayFrame ) { m_legendOverlayFrame->setParent( nullptr ); delete m_legendOverlayFrame; } if ( m_filterOverlayFrame ) { m_filterOverlayFrame->setParent( nullptr ); delete m_filterOverlayFrame; } delete m_qwtPlotCurveForLegendText; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- bool RimEnsembleWellLogCurveSet::isCurvesVisible() { return m_showCurves(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimEnsembleWellLogCurveSet::setColor( cvf::Color3f color ) { m_color = color; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimEnsembleWellLogCurveSet::loadDataAndUpdate( bool updateParentPlot ) { updateAllCurves(); updateFilterLegend(); updateAllTextInPlot(); if ( updateParentPlot ) { auto parentPlot = firstAncestorOrThisOfTypeAsserted(); parentPlot->viewer()->scheduleReplot(); } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimEnsembleWellLogCurveSet::setParentPlotNoReplot( RiuPlotWidget* plot ) { for ( RimWellLogCurve* curve : m_curves ) { curve->setParentPlotNoReplot( plot ); } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimEnsembleWellLogCurveSet::detachPlotCurves() { for ( RimWellLogCurve* curve : m_curves ) { curve->detach(); } m_qwtPlotCurveForLegendText->detach(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimEnsembleWellLogCurveSet::reattachPlotCurves() { for ( RimWellLogCurve* curve : m_curves ) { curve->reattach(); } m_qwtPlotCurveForLegendText->detach(); auto plot = firstAncestorOrThisOfType(); if ( plot ) { m_qwtPlotCurveForLegendText->attach( plot->viewer()->qwtPlot() ); } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- std::vector RimEnsembleWellLogCurveSet::curves() const { return m_curves.ptrReferencedObjectsByType(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimEnsembleWellLogCurveSet::deleteEnsembleCurves() { auto plotTrack = firstAncestorOrThisOfTypeAsserted(); std::vector curvesIndexesToDelete; for ( size_t c = 0; c < m_curves.size(); c++ ) { RimWellLogCurve* curve = m_curves[c]; if ( dynamic_cast( curve ) == nullptr ) { plotTrack->removeCurve( m_curves[c] ); curvesIndexesToDelete.push_back( c ); } } while ( curvesIndexesToDelete.size() > 0 ) { size_t currIndex = curvesIndexesToDelete.back(); m_curves.erase( currIndex ); curvesIndexesToDelete.pop_back(); } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimEnsembleWellLogCurveSet::deleteStatisticsCurves() { auto plotTrack = firstAncestorOrThisOfTypeAsserted(); std::vector curvesIndexesToDelete; for ( size_t c = 0; c < m_curves.size(); c++ ) { RimWellLogCurve* curve = m_curves[c]; if ( dynamic_cast( curve ) != nullptr ) { plotTrack->removeCurve( m_curves[c] ); curvesIndexesToDelete.push_back( c ); } } while ( curvesIndexesToDelete.size() > 0 ) { size_t currIndex = curvesIndexesToDelete.back(); m_curves.erase( currIndex ); curvesIndexesToDelete.pop_back(); } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RiuDraggableOverlayFrame* RimEnsembleWellLogCurveSet::legendFrame() const { return m_legendOverlayFrame; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RimEnsembleWellLogCurveSet::ColorMode RimEnsembleWellLogCurveSet::colorMode() const { return m_colorMode(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimEnsembleWellLogCurveSet::setColorMode( ColorMode mode ) { m_colorMode = mode; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimEnsembleWellLogCurveSet::onEnsembleCurvesAppearanceChanged( const caf::SignalEmitter* emitter ) { loadDataAndUpdate( true ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimEnsembleWellLogCurveSet::updateAllCurves() { RimEnsembleWellLogs* group = m_ensembleWellLogs; if ( group ) { std::vector allWellLogFiles = group->wellLogFiles(); std::vector filteredCases = filterEnsembleCases( allWellLogFiles ); m_isCurveSetFiltered = filteredCases.size() < allWellLogFiles.size(); updateEnsembleCurves( filteredCases ); updateStatisticsCurves( m_statistics->basedOnFilteredCases() ? filteredCases : allWellLogFiles ); } filterChanged.send(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimEnsembleWellLogCurveSet::updateEditors() { updateConnectedEditors(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimEnsembleWellLogCurveSet::fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue ) { bool updateTextInPlot = false; if ( changedField == &m_showCurves ) { loadDataAndUpdate( true ); updateConnectedEditors(); auto plot = firstAncestorOrThisOfTypeAsserted(); plot->updateConnectedEditors(); updateTextInPlot = true; } else if ( changedField == &m_ensembleWellLogs ) { updateAllCurves(); updateTextInPlot = true; } else if ( changedField == &m_ensembleCurveSet ) { connectEnsembleCurveSetFilterSignals(); updateAllCurves(); loadDataAndUpdate( true ); updateTextInPlot = true; } else if ( changedField == &m_wellLogChannelName ) { updateAllCurves(); updateTextInPlot = true; } else if ( changedField == &m_depthEqualization ) { updateAllCurves(); updateTextInPlot = true; } else if ( changedField == &m_color ) { updateCurveColors(); updateTextInPlot = true; } else if ( changedField == &m_colorMode ) { updateCurveColors(); updateTextInPlot = true; } else if ( changedField == &m_isUsingAutoName ) { if ( !m_isUsingAutoName ) { m_userDefinedName = createAutoName(); } updateTextInPlot = true; } else if ( changedField == &m_userDefinedName ) { updateTextInPlot = true; } if ( updateTextInPlot ) { updateAllTextInPlot(); } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimEnsembleWellLogCurveSet::defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) { uiOrdering.add( &m_ensembleWellLogs ); uiOrdering.add( &m_wellLogChannelName ); uiOrdering.add( &m_ensembleCurveSet ); uiOrdering.add( &m_depthEqualization ); bool hasKLayerIndex = hasPropertyInFile( RiaResultNames::indexKResultName() ); m_depthEqualization.uiCapability()->setUiReadOnly( !hasKLayerIndex ); appendColorGroup( uiOrdering ); { caf::PdmUiGroup* nameGroup = uiOrdering.addNewGroup( "Curve Name" ); nameGroup->setCollapsedByDefault(); nameGroup->add( &m_isUsingAutoName ); if ( m_isUsingAutoName ) { nameGroup->add( &m_autoGeneratedName ); } else { nameGroup->add( &m_userDefinedName ); } } caf::PdmUiGroup* statGroup = uiOrdering.addNewGroup( "Statistics" ); m_statistics->defineUiOrdering( uiConfigName, *statGroup ); caf::PdmUiGroup* curveAppearanceGroup = uiOrdering.addNewGroup( "Curve Appearance" ); QString configName = "AppearanceOrdering"; m_curveAppearance->uiOrdering( configName, *curveAppearanceGroup ); uiOrdering.skipRemainingFields( true ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimEnsembleWellLogCurveSet::appendColorGroup( caf::PdmUiOrdering& uiOrdering ) { caf::PdmUiGroup* colorsGroup = uiOrdering.addNewGroup( "Colors" ); colorsGroup->add( &m_colorMode ); if ( m_colorMode == ColorMode::SINGLE_COLOR ) { colorsGroup->add( &m_color ); } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimEnsembleWellLogCurveSet::defineUiTreeOrdering( caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName /*= ""*/ ) { uiTreeOrdering.skipRemainingChildren( true ); caf::IconProvider iconProvider = uiIconProvider(); if ( !iconProvider.valid() ) return; setUiIcon( iconProvider ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- caf::PdmFieldHandle* RimEnsembleWellLogCurveSet::userDescriptionField() { if ( m_isUsingAutoName ) { return &m_autoGeneratedName; } else { return &m_userDefinedName; } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- caf::PdmFieldHandle* RimEnsembleWellLogCurveSet::objectToggleField() { return &m_showCurves; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- QList RimEnsembleWellLogCurveSet::calculateValueOptions( const caf::PdmFieldHandle* fieldNeedingOptions ) { QList options; if ( fieldNeedingOptions == &m_ensembleWellLogs ) { RimProject* proj = RimProject::current(); std::vector groups = proj->activeOilField()->ensembleWellLogsCollection()->ensembleWellLogs(); for ( RimEnsembleWellLogs* ensemble : groups ) { options.push_back( caf::PdmOptionItemInfo( ensemble->name(), ensemble ) ); } options.push_front( caf::PdmOptionItemInfo( "None", nullptr ) ); } else if ( fieldNeedingOptions == &m_wellLogChannelName ) { if ( m_ensembleWellLogs ) { std::set wellLogChannelNames; for ( auto wellLogFile : m_ensembleWellLogs->wellLogFiles() ) { std::vector fileLogs = wellLogFile->wellLogChannels(); for ( size_t i = 0; i < fileLogs.size(); i++ ) { QString wellLogChannelName = fileLogs[i]->name(); wellLogChannelNames.insert( wellLogChannelName ); } } for ( auto wellLogChannelName : wellLogChannelNames ) { options.push_back( caf::PdmOptionItemInfo( wellLogChannelName, wellLogChannelName ) ); } } if ( options.size() == 0 ) { options.push_back( caf::PdmOptionItemInfo( "None", "None" ) ); } } else if ( fieldNeedingOptions == &m_ensembleCurveSet ) { RiaOptionItemFactory::appendOptionItemsForEnsembleCurveSets( &options ); } else if ( fieldNeedingOptions == &m_colorMode ) { auto singleColorOption = caf::AppEnum( ColorMode::SINGLE_COLOR ); options.push_back( caf::PdmOptionItemInfo( singleColorOption.uiText(), ColorMode::SINGLE_COLOR ) ); if ( m_ensembleWellLogs && m_ensembleCurveSet ) { auto byEnsembleOption = caf::AppEnum( ColorMode::COLOR_BY_ENSEMBLE_CURVE_SET ); options.push_back( caf::PdmOptionItemInfo( byEnsembleOption.uiText(), ColorMode::COLOR_BY_ENSEMBLE_CURVE_SET ) ); } } return options; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimEnsembleWellLogCurveSet::updateFilterLegend() { auto plotTrack = firstAncestorOrThisOfType(); if ( plotTrack && plotTrack->viewer() ) { if ( m_ensembleCurveSet != nullptr && m_ensembleCurveSet->isFiltered() ) { if ( !m_filterOverlayFrame ) { m_filterOverlayFrame = new RiuDraggableOverlayFrame( plotTrack->viewer()->qwtPlot()->canvas(), plotTrack->viewer()->overlayMargins() ); } m_filterOverlayFrame->setContentFrame( m_ensembleCurveSet->curveFilters()->makeFilterDescriptionFrame() ); plotTrack->viewer()->addOverlayFrame( m_filterOverlayFrame ); } else { if ( m_filterOverlayFrame ) { plotTrack->viewer()->removeOverlayFrame( m_filterOverlayFrame ); } } plotTrack->viewer()->scheduleReplot(); } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RimSummaryCase* RimEnsembleWellLogCurveSet::findMatchingSummaryCase( RimWellLogFileCurve* wellLogCurve ) const { RimSummaryCaseCollection* summaryCaseCollection = m_ensembleCurveSet->summaryCaseCollection(); std::vector sumCases = summaryCaseCollection->allSummaryCases(); for ( auto sumCase : sumCases ) { if ( isSameRealization( sumCase, wellLogCurve->wellLogFile() ) ) { return sumCase; } } return nullptr; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimEnsembleWellLogCurveSet::updateCurveColors() { if ( m_colorMode == ColorMode::COLOR_BY_ENSEMBLE_CURVE_SET ) { if ( m_ensembleCurveSet != nullptr ) { // Fint the curves to color (skip the statistics) std::vector curvesToColor; std::vector summaryCases; for ( auto& curve : m_curves ) { // Statistics curves have separate color settings if ( dynamic_cast( curve.p() ) == nullptr ) { // Look for a matching summary case RimSummaryCase* summaryCase = findMatchingSummaryCase( dynamic_cast( curve.p() ) ); if ( summaryCase ) { summaryCases.push_back( summaryCase ); curvesToColor.push_back( curve.p() ); } } } // Get the colors std::vector caseColors = m_ensembleCurveSet->generateColorsForCases( summaryCases ); // Apply the colors if ( caseColors.size() != curvesToColor.size() ) return; for ( size_t i = 0; i < curvesToColor.size(); i++ ) { curvesToColor[i]->setColor( caseColors[i] ); curvesToColor[i]->updateCurveAppearance(); } } } else if ( m_colorMode == ColorMode::SINGLE_COLOR ) { for ( auto& curve : m_curves ) { // Statistics curves have separate color settings if ( dynamic_cast( curve.p() ) == nullptr ) { curve->setColor( m_color ); curve->updateCurveAppearance(); } } } auto plotTrack = firstAncestorOrThisOfType(); if ( plotTrack && plotTrack->viewer() ) { if ( m_colorMode != ColorMode::SINGLE_COLOR && m_ensembleCurveSet != nullptr && m_ensembleCurveSet->colorMode() != RimEnsembleCurveSet::ColorMode::SINGLE_COLOR ) { if ( !m_legendOverlayFrame ) { m_legendOverlayFrame = new RiuDraggableOverlayFrame( plotTrack->viewer()->getParentForOverlay(), plotTrack->viewer()->overlayMargins() ); } m_legendOverlayFrame->setContentFrame( m_ensembleCurveSet->legendConfig()->makeLegendFrame() ); plotTrack->viewer()->addOverlayFrame( m_legendOverlayFrame ); } else { if ( m_legendOverlayFrame ) { plotTrack->viewer()->removeOverlayFrame( m_legendOverlayFrame ); } } plotTrack->viewer()->scheduleReplot(); } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimEnsembleWellLogCurveSet::updateEnsembleCurves( const std::vector& sumCases ) { auto plotTrack = firstAncestorOrThisOfTypeAsserted(); auto wellLogPlot = firstAncestorOrThisOfTypeAsserted(); deleteEnsembleCurves(); m_qwtPlotCurveForLegendText->detach(); deleteStatisticsCurves(); if ( m_statistics->hideEnsembleCurves() ) return; std::shared_ptr offsets; cvf::ref wellPathFormations; if ( m_depthEqualization() == RimEnsembleWellLogStatistics::DepthEqualization::K_LAYER ) { offsets = RimEnsembleWellLogStatistics::calculateIndexDepthOffset( sumCases ); wellPathFormations = createWellPathFormations( offsets ); } m_qwtPlotCurveForLegendText->attach( plotTrack->viewer()->qwtPlot() ); QString wellLogChannelName = m_wellLogChannelName(); if ( plotTrack && wellLogChannelName != "None" ) { if ( isCurvesVisible() ) { bool isFirst = true; for ( auto& wellLogFile : sumCases ) { RimWellLogFileCurve* curve = new RimWellLogFileCurve; curve->setUiTreeHidden( true ); curve->setUiTreeChildrenHidden( true ); plotTrack->addCurve( curve ); QString errorMessage; if ( wellLogFile->readFile( &errorMessage ) ) { RigWellLogFile* wellLogDataFile = wellLogFile->wellLogFileData(); CVF_ASSERT( wellLogDataFile ); if ( isFirst ) { // Initialize plot with depth unit from the first log file wellLogPlot->setDepthUnit( wellLogDataFile->depthUnit() ); isFirst = false; } } else { RiaLogging::warning( errorMessage ); } RimWellPath* wellPath = RimProject::current()->wellPathByName( wellLogFile->wellName() ); if ( wellPathFormations.notNull() ) wellPath->setFormationsGeometry( wellPathFormations ); curve->setWellPath( wellPath ); curve->setWellLogChannelName( wellLogChannelName ); curve->setWellLogFile( wellLogFile ); curve->setSymbol( m_curveAppearance->symbol() ); curve->setSymbolSize( m_curveAppearance->symbolSize() ); curve->setSymbolSkipDistance( m_curveAppearance->symbolSkipDistance() ); curve->setSymbolEdgeColor( m_curveAppearance->symbolEdgeColor() ); curve->setLineStyle( m_curveAppearance->lineStyle() ); curve->setLineThickness( m_curveAppearance->lineThickness() ); if ( offsets ) curve->setIndexDepthOffsets( offsets ); curve->loadDataAndUpdate( true ); curve->updateCurveVisibility(); curve->setShowInLegend( false ); m_curves.push_back( curve ); } updateCurveColors(); setLogScaleFromSelectedResult( wellLogChannelName ); } } plotTrack->updateLegend(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimEnsembleWellLogCurveSet::setLogScaleFromSelectedResult( const QString resVar ) { if ( RiaResultNames::isLogarithmicResult( resVar ) ) { auto track = firstAncestorOrThisOfType(); if ( track ) track->setLogarithmicScale( true ); } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- bool RimEnsembleWellLogCurveSet::updateStatistics() { return updateStatistics( std::vector() ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- bool RimEnsembleWellLogCurveSet::updateStatistics( const std::vector& sumCases ) { RimEnsembleWellLogs* ensembleWellLogs = m_ensembleWellLogs; QString wellLogChannelName = m_wellLogChannelName(); if ( !isCurvesVisible() || m_disableStatisticCurves || !ensembleWellLogs || wellLogChannelName == "None" ) { m_ensembleWellLogStatistics->clearData(); return false; } // Calculate std::vector wellLogFiles = sumCases; if ( wellLogFiles.empty() ) { if ( m_statistics->basedOnFilteredCases() ) wellLogFiles = filterEnsembleCases( ensembleWellLogs->wellLogFiles() ); else wellLogFiles = ensembleWellLogs->wellLogFiles(); } m_ensembleWellLogStatistics->calculate( wellLogFiles, wellLogChannelName, m_depthEqualization() ); return true; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimEnsembleWellLogCurveSet::updateStatisticsCurves( const std::vector& sumCases ) { deleteStatisticsCurves(); if ( !updateStatistics( sumCases ) ) return; std::vector statisticsTypes; if ( m_statistics->isActive() ) { if ( m_statistics->showP10Curve() && m_ensembleWellLogStatistics->hasP10Data() ) statisticsTypes.push_back( RimEnsembleWellLogStatistics::StatisticsType::P10 ); if ( m_statistics->showP50Curve() && m_ensembleWellLogStatistics->hasP50Data() ) statisticsTypes.push_back( RimEnsembleWellLogStatistics::StatisticsType::P50 ); if ( m_statistics->showP90Curve() && m_ensembleWellLogStatistics->hasP90Data() ) statisticsTypes.push_back( RimEnsembleWellLogStatistics::StatisticsType::P90 ); if ( m_statistics->showMeanCurve() && m_ensembleWellLogStatistics->hasMeanData() ) statisticsTypes.push_back( RimEnsembleWellLogStatistics::StatisticsType::MEAN ); } auto statisticsCurveSymbolFromStatistics = []( RimEnsembleWellLogStatistics::StatisticsType statisticsType ) { if ( statisticsType == RimEnsembleWellLogStatistics::StatisticsType::P10 ) return RiuPlotCurveSymbol::SYMBOL_DOWN_TRIANGLE; if ( statisticsType == RimEnsembleWellLogStatistics::StatisticsType::P90 ) return RiuPlotCurveSymbol::SYMBOL_TRIANGLE; if ( statisticsType == RimEnsembleWellLogStatistics::StatisticsType::P50 ) return RiuPlotCurveSymbol::SYMBOL_DIAMOND; return RiuPlotCurveSymbol::SYMBOL_ELLIPSE; }; auto plotTrack = firstAncestorOrThisOfTypeAsserted(); for ( auto statisticsType : statisticsTypes ) { auto curve = new RimEnsembleWellLogStatisticsCurve(); curve->setUiTreeHidden( true ); curve->setUiTreeChildrenHidden( true ); curve->setEnsembleWellLogCurveSet( this ); curve->setStatisticsType( statisticsType ); m_curves.push_back( curve ); curve->setColor( m_statistics->color() ); auto symbol = statisticsCurveSymbolFromStatistics( statisticsType ); curve->setSymbol( symbol ); curve->setSymbolSize( statisticsCurveSymbolSize( symbol ) ); curve->setSymbolSkipDistance( 150 ); if ( m_statistics->showCurveLabels() ) { curve->setSymbolLabel( caf::AppEnum::uiText( statisticsType ) ); } curve->setLineStyle( RiuQwtPlotCurveDefines::LineStyleEnum::STYLE_SOLID ); curve->setShowInLegend( m_statistics->showStatisticsCurveLegends() ); plotTrack->addCurve( curve ); curve->updateCurveVisibility(); curve->loadDataAndUpdate( false ); } updateCurveColors(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimEnsembleWellLogCurveSet::updateStatisticsCurves() { updateStatisticsCurves( std::vector() ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimEnsembleWellLogCurveSet::showCurves( bool show ) { m_showCurves = show; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RimEnsembleWellLogStatistics::DepthEqualization RimEnsembleWellLogCurveSet::depthEqualization() const { return m_depthEqualization(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimEnsembleWellLogCurveSet::setDepthEqualization( RimEnsembleWellLogStatistics::DepthEqualization depthEqualization ) { m_depthEqualization = depthEqualization; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimEnsembleWellLogCurveSet::setFilterByEnsembleCurveSet( RimEnsembleCurveSet* ensembleCurveSet ) { m_ensembleCurveSet = ensembleCurveSet; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimEnsembleWellLogCurveSet::updateAllTextInPlot() { auto plotTrack = firstAncestorOrThisOfTypeAsserted(); plotTrack->viewer()->setPlotTitle( name() ); updateEnsembleLegendItem(); plotTrack->updateLegend(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- std::vector RimEnsembleWellLogCurveSet::filterEnsembleCases( const std::vector& wellLogFiles ) { std::vector filteredCases; if ( m_ensembleCurveSet != nullptr && m_statistics->basedOnFilteredCases() ) { // Get the summary cases from the related ensemble summary curve set. RimSummaryCaseCollection* summaryCaseCollection = m_ensembleCurveSet->summaryCaseCollection(); // std::vector sumCases = m_ensembleCurveSet->filterEnsembleCases( summaryCaseCollection->allSummaryCases() ); for ( auto sumCase : sumCases ) { for ( auto wellLogFile : wellLogFiles ) { if ( isSameRealization( sumCase, wellLogFile ) ) { filteredCases.push_back( wellLogFile ); } } } } else { filteredCases = wellLogFiles; } return filteredCases; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- bool RimEnsembleWellLogCurveSet::isSameRealization( RimSummaryCase* summaryCase, RimWellLogFile* wellLogFile ) const { QString wellLogFileName = wellLogFile->fileName(); // if ( summaryCase->hasCaseRealizationParameters() ) { // TODO: make less naive.. int realizationNumber = summaryCase->caseRealizationParameters()->realizationNumber(); QString summaryCaseFileName = summaryCase->summaryHeaderFilename(); if ( wellLogFileName.contains( QString( "realization-%1" ).arg( realizationNumber ) ) ) { return true; } } return false; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimEnsembleWellLogCurveSet::disableStatisticCurves() { m_disableStatisticCurves = true; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- bool RimEnsembleWellLogCurveSet::isFiltered() const { return m_isCurveSetFiltered; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- bool RimEnsembleWellLogCurveSet::hasP10Data() const { return m_ensembleWellLogStatistics->hasP10Data(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- bool RimEnsembleWellLogCurveSet::hasP50Data() const { return m_ensembleWellLogStatistics->hasP50Data(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- bool RimEnsembleWellLogCurveSet::hasP90Data() const { return m_ensembleWellLogStatistics->hasP90Data(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- bool RimEnsembleWellLogCurveSet::hasMeanData() const { return m_ensembleWellLogStatistics->hasMeanData(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- const RimEnsembleWellLogStatistics* RimEnsembleWellLogCurveSet::ensembleWellLogStatistics() const { return m_ensembleWellLogStatistics.get(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimEnsembleWellLogCurveSet::updateEnsembleLegendItem() { m_qwtPlotCurveForLegendText->setTitle( name() ); { QwtSymbol* symbol = nullptr; if ( m_colorMode == ColorMode::SINGLE_COLOR ) { symbol = new QwtSymbol( QwtSymbol::HLine ); QColor curveColor( m_color.value().rByte(), m_color.value().gByte(), m_color.value().bByte() ); QPen curvePen( curveColor ); curvePen.setWidth( 2 ); symbol->setPen( curvePen ); symbol->setSize( 6, 6 ); } else if ( m_colorMode == ColorMode::COLOR_BY_ENSEMBLE_CURVE_SET ) { QPixmap p = QPixmap( ":/Legend.png" ); symbol = new QwtSymbol; symbol->setPixmap( p ); symbol->setSize( 8, 8 ); } m_qwtPlotCurveForLegendText->setSymbol( symbol ); } bool showLegendItem = isCurvesVisible(); m_qwtPlotCurveForLegendText->setItemAttribute( QwtPlotItem::Legend, showLegendItem ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- QString RimEnsembleWellLogCurveSet::name() const { QString curveSetName; if ( m_isUsingAutoName ) { curveSetName = m_autoGeneratedName(); } else { curveSetName += m_userDefinedName(); } return curveSetName; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- QString RimEnsembleWellLogCurveSet::createAutoName() const { QStringList nameParts; if ( m_ensembleWellLogs() ) { nameParts.append( m_ensembleWellLogs->name() ); nameParts.append( m_wellLogChannelName() ); } if ( !nameParts.isEmpty() ) return nameParts.join( " - " ); else return "Ensemble Well Log Curve Set"; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimEnsembleWellLogCurveSet::connectEnsembleCurveSetFilterSignals() { if ( m_ensembleCurveSet() ) { m_ensembleCurveSet()->filterChanged.connect( this, &RimEnsembleWellLogCurveSet::onFilterSourceChanged ); } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimEnsembleWellLogCurveSet::onFilterSourceChanged( const caf::SignalEmitter* emitter ) { if ( m_ensembleCurveSet() ) loadDataAndUpdate( true ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimEnsembleWellLogCurveSet::initAfterRead() { connectEnsembleCurveSetFilterSignals(); // Hide the ensemble and statistics curves in the project tree on reload for ( auto c : m_curves() ) { c->setUiTreeHidden( true ); } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimEnsembleWellLogCurveSet::setEnsembleWellLogs( RimEnsembleWellLogs* ensembleWellLogs ) { m_ensembleWellLogs = ensembleWellLogs; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimEnsembleWellLogCurveSet::setWellLogChannelName( const QString& wellLogChannelName ) { m_wellLogChannelName = wellLogChannelName; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- cvf::ref RimEnsembleWellLogCurveSet::createWellPathFormations( std::shared_ptr offsets ) { RimFormationNamesCollection* formationNamesCollection = RimProject::current()->activeOilField()->formationNamesCollection.v(); if ( !formationNamesCollection ) return nullptr; if ( formationNamesCollection->formationNamesList().empty() ) return nullptr; RimFormationNames* rimFormationNames = formationNamesCollection->formationNamesList()[0]; if ( !rimFormationNames ) return nullptr; RigFormationNames* formationNames = rimFormationNames->formationNamesData(); if ( !formationNames ) return nullptr; std::vector wellPathFormationItems; for ( int kLayer : offsets->sortedIndexes() ) { RigWellPathFormation wellPathFormation; wellPathFormation.mdTop = offsets->getTopMd( kLayer ); wellPathFormation.mdBase = offsets->getBottomMd( kLayer ); wellPathFormation.formationName = formationNames->formationNameFromKLayerIdx( kLayer - 1 ); wellPathFormationItems.push_back( wellPathFormation ); } QString unusedFilePath = ""; cvf::ref wellPathFormations = new RigWellPathFormations( wellPathFormationItems, unusedFilePath, "Ensemble formation" ); return wellPathFormations; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- bool RimEnsembleWellLogCurveSet::hasPropertyInFile( const QString& property ) const { RimEnsembleWellLogs* group = m_ensembleWellLogs; if ( !group ) return false; std::vector allWellLogFiles = group->wellLogFiles(); for ( auto& wellLogFile : allWellLogFiles ) { QString errorMessage; if ( !wellLogFile->readFile( &errorMessage ) ) return false; RigWellLogFile* wellLogDataFile = wellLogFile->wellLogFileData(); CVF_ASSERT( wellLogDataFile ); std::vector values = wellLogDataFile->values( RiaResultNames::indexKResultName() ); if ( values.empty() ) return false; } return true; }