diff --git a/ApplicationLibCode/Application/RiaWellLogTrackDefines.cpp b/ApplicationLibCode/Application/RiaWellLogTrackDefines.cpp index 40970e0e47..53c017513a 100644 --- a/ApplicationLibCode/Application/RiaWellLogTrackDefines.cpp +++ b/ApplicationLibCode/Application/RiaWellLogTrackDefines.cpp @@ -18,6 +18,8 @@ #include "RiaWellLogTrackDefines.h" +#include "cafAppEnum.h" + namespace caf { template <> @@ -33,6 +35,7 @@ void AppEnum::setUp() { addItem( RiaDefines::WellLogTrackFormationSource::CASE, "CASE", "Case" ); addItem( RiaDefines::WellLogTrackFormationSource::WELL_PICK_FILTER, "WELL_PICK_FILTER", "Well Picks for Well Path" ); + addItem( RiaDefines::WellLogTrackFormationSource::WELL_PICKS_NO_TRAJECTORY, "WELL_PICKS_NO_TRAJECTORY", "Well Picks (no trajectory)" ); setDefault( RiaDefines::WellLogTrackFormationSource::CASE ); } diff --git a/ApplicationLibCode/Application/RiaWellLogTrackDefines.h b/ApplicationLibCode/Application/RiaWellLogTrackDefines.h index 04ab396ef4..93605c1418 100644 --- a/ApplicationLibCode/Application/RiaWellLogTrackDefines.h +++ b/ApplicationLibCode/Application/RiaWellLogTrackDefines.h @@ -18,8 +18,6 @@ #pragma once -#include "cafAppEnum.h" - namespace RiaDefines { @@ -32,7 +30,8 @@ enum class WellLogTrackTrajectoryType enum class WellLogTrackFormationSource { CASE, - WELL_PICK_FILTER + WELL_PICK_FILTER, + WELL_PICKS_NO_TRAJECTORY }; enum class WellLogTrackFormationLevel diff --git a/ApplicationLibCode/Commands/RicWellLogTools.cpp b/ApplicationLibCode/Commands/RicWellLogTools.cpp index 7ae8cc2280..351ce52355 100644 --- a/ApplicationLibCode/Commands/RicWellLogTools.cpp +++ b/ApplicationLibCode/Commands/RicWellLogTools.cpp @@ -19,6 +19,7 @@ #include "RicWellLogTools.h" #include "RiaGuiApplication.h" +#include "RiaWellLogTrackDefines.h" #include "RigEclipseCaseData.h" #include "Well/RigWellLogCurveData.h" diff --git a/ApplicationLibCode/Commands/WellLogCommands/RicNewWellLogExtractionCurveFeature.cpp b/ApplicationLibCode/Commands/WellLogCommands/RicNewWellLogExtractionCurveFeature.cpp index 69bb093904..c1fc7a1cc6 100644 --- a/ApplicationLibCode/Commands/WellLogCommands/RicNewWellLogExtractionCurveFeature.cpp +++ b/ApplicationLibCode/Commands/WellLogCommands/RicNewWellLogExtractionCurveFeature.cpp @@ -24,6 +24,7 @@ #include "RicWellLogTools.h" #include "RiaApplication.h" +#include "RiaWellLogTrackDefines.h" #include "Well/RigWellLogCurveData.h" diff --git a/ApplicationLibCode/Commands/WellLogCommands/RicNewWellLogPlotFeatureImpl.cpp b/ApplicationLibCode/Commands/WellLogCommands/RicNewWellLogPlotFeatureImpl.cpp index 44c00bf98f..5e18600cbb 100644 --- a/ApplicationLibCode/Commands/WellLogCommands/RicNewWellLogPlotFeatureImpl.cpp +++ b/ApplicationLibCode/Commands/WellLogCommands/RicNewWellLogPlotFeatureImpl.cpp @@ -20,6 +20,7 @@ #include "RicNewWellLogPlotFeatureImpl.h" #include "RiaGuiApplication.h" +#include "RiaWellLogTrackDefines.h" #include "Formations/RimFormationNames.h" #include "RimCase.h" diff --git a/ApplicationLibCode/ProjectDataModel/Flow/RimWellRftPlot.cpp b/ApplicationLibCode/ProjectDataModel/Flow/RimWellRftPlot.cpp index 65b946f6d4..deb40450e1 100644 --- a/ApplicationLibCode/ProjectDataModel/Flow/RimWellRftPlot.cpp +++ b/ApplicationLibCode/ProjectDataModel/Flow/RimWellRftPlot.cpp @@ -36,6 +36,7 @@ #include "RimEclipseResultCase.h" #include "RimEnsembleCurveSetColorManager.h" #include "RimObservedFmuRftData.h" +#include "RimOilField.h" #include "RimPressureDepthData.h" #include "RimProject.h" #include "RimRegularLegendConfig.h" @@ -57,6 +58,9 @@ #include "RimWellPlotTools.h" #include "RimWellRftEnsembleCurveSet.h" +#include "Formations/RimWellFormationsCollection.h" +#include "Formations/RimWellFormationsFile.h" + #include "RiuAbstractLegendFrame.h" #include "RiuDraggableOverlayFrame.h" #include "RiuQwtCurveSelectorFilter.h" @@ -268,16 +272,48 @@ void RimWellRftPlot::updateFormationsOnPlot() const } } - if ( wellPath ) + // Prefer well-pick (formations.csv) zone bands over case-derived formation names when + // they are available for the selected well, so the RFT profile shows the same zone + // bands used by other well log tracks and the RFT correlation/cross plots. + RimWellFormationsFile* wellFormationsFile = nullptr; + QString wellNameInFile = associatedSimWellName(); + + if ( wellPath && wellPath->formationsGeometry() ) + { + wellFormationsFile = wellPath->wellFormationsFile(); + } + + if ( wellFormationsFile ) + { + track->setAndUpdateWellPickFormationsData( wellPath ); + } + else if ( wellPath ) { track->setAndUpdateWellPathFormationNamesData( formationNamesCase, wellPath ); } else { - track->setAndUpdateSimWellFormationNamesAndBranchData( formationNamesCase, - associatedSimWellName(), - m_branchIndex, - m_branchDetection ); + // No well path trajectory is available (e.g. a purely simulation-well based RFT + // entry). Prefer a formations file with explicit, depth-based zone picks for this + // well over the case/K-layer based formation names, since there is no trajectory to + // extract K-layers along. + RimWellFormationsFile* formationsFileForWell = nullptr; + if ( proj->activeOilField() && proj->activeOilField()->wellFormationsCollection() ) + { + formationsFileForWell = proj->activeOilField()->wellFormationsCollection()->findFileForWell( wellNameInFile ); + } + + if ( formationsFileForWell ) + { + track->setAndUpdateFormationFileData( formationsFileForWell, wellNameInFile ); + } + else + { + track->setAndUpdateSimWellFormationNamesAndBranchData( formationNamesCase, + associatedSimWellName(), + m_branchIndex, + m_branchDetection ); + } } } } diff --git a/ApplicationLibCode/ProjectDataModel/WellLog/RimWellLogCurveCommonDataSource.cpp b/ApplicationLibCode/ProjectDataModel/WellLog/RimWellLogCurveCommonDataSource.cpp index 3201cff7ef..0774b00cb1 100644 --- a/ApplicationLibCode/ProjectDataModel/WellLog/RimWellLogCurveCommonDataSource.cpp +++ b/ApplicationLibCode/ProjectDataModel/WellLog/RimWellLogCurveCommonDataSource.cpp @@ -19,6 +19,7 @@ #include "RimWellLogCurveCommonDataSource.h" #include "RiaSimWellBranchTools.h" +#include "RiaWellLogTrackDefines.h" #include "Summary/RiaSummaryTools.h" #include "RifReaderOpmRft.h" diff --git a/ApplicationLibCode/ProjectDataModel/WellLog/WellLogTrack/RimWellLogFormationSettings.cpp b/ApplicationLibCode/ProjectDataModel/WellLog/WellLogTrack/RimWellLogFormationSettings.cpp index d2d734f3b1..ce759bb1e6 100644 --- a/ApplicationLibCode/ProjectDataModel/WellLog/WellLogTrack/RimWellLogFormationSettings.cpp +++ b/ApplicationLibCode/ProjectDataModel/WellLog/WellLogTrack/RimWellLogFormationSettings.cpp @@ -23,12 +23,18 @@ #include "RiaWellLogTrackDefines.h" #include "RimCase.h" #include "RimEclipseCase.h" +#include "RimOilField.h" +#include "RimProject.h" #include "RimTools.h" #include "RimWellLogTrack.h" #include "RimWellPath.h" +#include "Formations/RimWellFormationsCollection.h" +#include "Formations/RimWellFormationsFile.h" + #include "RigEclipseCaseData.h" +#include "cafPdmUiComboBoxEditor.h" #include "cafPdmUiGroup.h" CAF_PDM_SOURCE_INIT( RimWellLogFormationSettings, "RimWellLogFormationSettings" ); @@ -50,6 +56,12 @@ RimWellLogFormationSettings::RimWellLogFormationSettings() CAF_PDM_InitFieldNoDefault( &m_formationWellPathForSourceWellPath, "FormationWellPathForSourceWellPath", "Well Path" ); m_formationWellPathForSourceWellPath.uiCapability()->setUiTreeChildrenHidden( true ); + CAF_PDM_InitFieldNoDefault( &m_wellFormationsFile, "FormationWellFormationsFile", "Formations File" ); + m_wellFormationsFile.uiCapability()->setUiTreeChildrenHidden( true ); + + CAF_PDM_InitField( &m_wellNameInFormationsFile, "FormationWellNameInFile", QString(), "Well" ); + m_wellNameInFormationsFile.uiCapability()->setUiEditorTypeName( caf::PdmUiComboBoxEditor::uiEditorTypeName() ); + CAF_PDM_InitField( &m_formationSimWellName, "FormationSimulationWellName", QString( "None" ), "Simulation Well" ); CAF_PDM_InitField( &m_formationBranchIndex, "FormationBranchIndex", 0, " " ); CAF_PDM_InitField( &m_formationBranchDetection, @@ -148,6 +160,59 @@ void RimWellLogFormationSettings::setWellPathForSourceWellPath( RimWellPath* wel m_formationWellPathForSourceWellPath = wellPath; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimWellFormationsFile* RimWellLogFormationSettings::wellFormationsFile() const +{ + return m_wellFormationsFile(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimWellLogFormationSettings::setWellFormationsFile( RimWellFormationsFile* file ) +{ + m_wellFormationsFile = file; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RimWellLogFormationSettings::wellNameInFormationsFile() const +{ + return m_wellNameInFormationsFile(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimWellLogFormationSettings::setWellNameInFormationsFile( const QString& wellName ) +{ + m_wellNameInFormationsFile = wellName; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::optional RimWellLogFormationSettings::resolveWellPickFormations() const +{ + if ( m_formationSource() == RiaDefines::WellLogTrackFormationSource::WELL_PICK_FILTER && m_formationWellPathForSourceWellPath() ) + { + const RigWellPathFormations* formations = m_formationWellPathForSourceWellPath->formationsGeometry(); + if ( formations ) return *formations; + return std::nullopt; + } + + if ( m_formationSource() == RiaDefines::WellLogTrackFormationSource::WELL_PICKS_NO_TRAJECTORY && m_wellFormationsFile() && + !m_wellNameInFormationsFile().isEmpty() ) + { + return m_wellFormationsFile->formationsForWell( m_wellNameInFormationsFile() ); + } + + return std::nullopt; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -264,8 +329,24 @@ void RimWellLogFormationSettings::uiOrdering( const QString& uiConfigName, caf:: } else if ( m_formationSource() == RiaDefines::WellLogTrackFormationSource::WELL_PICK_FILTER ) { + // The direct Formations File fallback (no well path selected) has moved to the dedicated + // WELL_PICKS_NO_TRAJECTORY source, so this source only ever shows the well path picker. uiOrdering.add( &m_formationWellPathForSourceWellPath ); - if ( m_formationWellPathForSourceWellPath() ) + + if ( resolveWellPickFormations().has_value() ) + { + uiOrdering.add( &m_formationLevel ); + uiOrdering.add( &m_showFormationFluids ); + } + } + else if ( m_formationSource() == RiaDefines::WellLogTrackFormationSource::WELL_PICKS_NO_TRAJECTORY ) + { + // Well picks use explicit top/base depths and do not require a well path trajectory, so + // this source can be used e.g. for an RFT well with no associated/modelled well path. + uiOrdering.add( &m_wellFormationsFile ); + if ( m_wellFormationsFile() ) uiOrdering.add( &m_wellNameInFormationsFile ); + + if ( resolveWellPickFormations().has_value() ) { uiOrdering.add( &m_formationLevel ); uiOrdering.add( &m_showFormationFluids ); @@ -291,6 +372,20 @@ void RimWellLogFormationSettings::fieldChangedByUi( const caf::PdmFieldHandle* c } } } + else if ( changedField == &m_formationSource && m_formationSource() == RiaDefines::WellLogTrackFormationSource::WELL_PICKS_NO_TRAJECTORY ) + { + // The WELL_PICKS_NO_TRAJECTORY source always resolves formations directly from + // m_wellFormationsFile, so clear any well path left over from a previous WELL_PICK_FILTER + // selection. + m_formationWellPathForSourceWellPath = nullptr; + } + else if ( changedField == &m_wellFormationsFile ) + { + // Reset the selected well name when the file changes, picking the first well as a + // convenient default (mirrors RimWellPath's behavior when linking a formations file). + QStringList wellNames = m_wellFormationsFile() ? m_wellFormationsFile->wellNames() : QStringList(); + m_wellNameInFormationsFile = wellNames.isEmpty() ? QString() : wellNames.first(); + } auto track = firstAncestorOrThisOfType(); if ( track ) @@ -315,6 +410,29 @@ QList RimWellLogFormationSettings::calculateValueOptions { RimTools::wellPathWithFormationsOptionItems( &options ); } + else if ( fieldNeedingOptions == &m_wellFormationsFile ) + { + options.push_back( caf::PdmOptionItemInfo( "None", static_cast( nullptr ) ) ); + + RimProject* proj = RimProject::current(); + if ( proj && proj->activeOilField() && proj->activeOilField()->wellFormationsCollection() ) + { + for ( RimWellFormationsFile* file : proj->activeOilField()->wellFormationsCollection()->wellFormationsFiles() ) + { + options.push_back( caf::PdmOptionItemInfo( file->shortName(), file, false, file->uiCapability()->uiIconProvider() ) ); + } + } + } + else if ( fieldNeedingOptions == &m_wellNameInFormationsFile ) + { + if ( m_wellFormationsFile() ) + { + for ( const QString& wellName : m_wellFormationsFile->wellNames() ) + { + options.push_back( caf::PdmOptionItemInfo( wellName, wellName ) ); + } + } + } else if ( fieldNeedingOptions == &m_formationCase ) { RimTools::caseOptionItems( &options ); @@ -342,23 +460,19 @@ QList RimWellLogFormationSettings::calculateValueOptions } else if ( fieldNeedingOptions == &m_formationLevel ) { - if ( m_formationWellPathForSourceWellPath ) + if ( auto formations = resolveWellPickFormations() ) { - const RigWellPathFormations* formations = m_formationWellPathForSourceWellPath->formationsGeometry(); - if ( formations ) + using FormationLevelEnum = caf::AppEnum; + + options.push_back( caf::PdmOptionItemInfo( FormationLevelEnum::uiText( RiaDefines::WellLogTrackFormationLevel::NONE ), + RiaDefines::WellLogTrackFormationLevel::NONE ) ); + + options.push_back( caf::PdmOptionItemInfo( FormationLevelEnum::uiText( RiaDefines::WellLogTrackFormationLevel::ALL ), + RiaDefines::WellLogTrackFormationLevel::ALL ) ); + + for ( const auto& level : formations->formationsLevelsPresent() ) { - using FormationLevelEnum = caf::AppEnum; - - options.push_back( caf::PdmOptionItemInfo( FormationLevelEnum::uiText( RiaDefines::WellLogTrackFormationLevel::NONE ), - RiaDefines::WellLogTrackFormationLevel::NONE ) ); - - options.push_back( caf::PdmOptionItemInfo( FormationLevelEnum::uiText( RiaDefines::WellLogTrackFormationLevel::ALL ), - RiaDefines::WellLogTrackFormationLevel::ALL ) ); - - for ( const auto& level : formations->formationsLevelsPresent() ) - { - options.push_back( caf::PdmOptionItemInfo( FormationLevelEnum::uiText( level ), level ) ); - } + options.push_back( caf::PdmOptionItemInfo( FormationLevelEnum::uiText( level ), level ) ); } } } diff --git a/ApplicationLibCode/ProjectDataModel/WellLog/WellLogTrack/RimWellLogFormationSettings.h b/ApplicationLibCode/ProjectDataModel/WellLog/WellLogTrack/RimWellLogFormationSettings.h index 20d6e97b98..c5a677bba6 100644 --- a/ApplicationLibCode/ProjectDataModel/WellLog/WellLogTrack/RimWellLogFormationSettings.h +++ b/ApplicationLibCode/ProjectDataModel/WellLog/WellLogTrack/RimWellLogFormationSettings.h @@ -18,8 +18,6 @@ #pragma once -#include "RiaWellLogTrackDefines.h" - #include "Well/RigWellPathFormations.h" #include "cafAppEnum.h" @@ -27,9 +25,17 @@ #include "cafPdmObject.h" #include "cafPdmPtrField.h" +namespace RiaDefines +{ +enum class WellLogTrackFormationSource; +enum class WellLogTrackTrajectoryType; +enum class WellLogTrackFormationLevel; +} // namespace RiaDefines + class RimCase; class RimWellPath; class RimWellLogTrack; +class RimWellFormationsFile; //================================================================================================== /// @@ -62,6 +68,18 @@ public: RimWellPath* wellPathForSourceWellPath() const; void setWellPathForSourceWellPath( RimWellPath* wellPath ); + // Direct well formations file + well name, used by the WELL_PICK_FILTER source when no well + // path is selected (e.g. tracks not associated with a RimWellPath). + RimWellFormationsFile* wellFormationsFile() const; + void setWellFormationsFile( RimWellFormationsFile* file ); + + QString wellNameInFormationsFile() const; + void setWellNameInFormationsFile( const QString& wellName ); + + // Resolves the formations to show for the WELL_PICK_FILTER source: the selected well path's + // own formations if present, otherwise the well looked up directly in wellFormationsFile(). + std::optional resolveWellPickFormations() const; + // Simulation well QString simWellName() const; void setSimWellName( const QString& simWellName ); @@ -93,6 +111,8 @@ private: caf::PdmField> m_formationTrajectoryType; caf::PdmPtrField m_formationWellPathForSourceCase; caf::PdmPtrField m_formationWellPathForSourceWellPath; + caf::PdmPtrField m_wellFormationsFile; + caf::PdmField m_wellNameInFormationsFile; caf::PdmField m_formationSimWellName; caf::PdmField m_formationBranchIndex; caf::PdmField m_formationBranchDetection; diff --git a/ApplicationLibCode/ProjectDataModel/WellLog/WellLogTrack/RimWellLogTrack.cpp b/ApplicationLibCode/ProjectDataModel/WellLog/WellLogTrack/RimWellLogTrack.cpp index 75d74717af..1c1ff3da96 100644 --- a/ApplicationLibCode/ProjectDataModel/WellLog/WellLogTrack/RimWellLogTrack.cpp +++ b/ApplicationLibCode/ProjectDataModel/WellLog/WellLogTrack/RimWellLogTrack.cpp @@ -28,6 +28,7 @@ #include "RiaResultNames.h" #include "RiaSimWellBranchTools.h" #include "RiaWellLogCurveMerger.h" +#include "RiaWellLogTrackDefines.h" #include "RigEclipseCaseData.h" #include "RigEclipseResultAddress.h" @@ -1289,6 +1290,41 @@ void RimWellLogTrack::setAndUpdateSimWellFormationNamesData( RimCase* rimCase, c } } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimWellLogTrack::setAndUpdateWellPickFormationsData( RimWellPath* wellPath ) +{ + m_formationSettings->setFormationSource( RiaDefines::WellLogTrackFormationSource::WELL_PICK_FILTER ); + m_formationSettings->setWellPathForSourceWellPath( wellPath ); + + updateConnectedEditors(); + + if ( m_regionAnnotationSettings->annotationType() != RiaDefines::RegionAnnotationType::NO_ANNOTATIONS ) + { + updateRegionAnnotationsOnPlot(); + } +} + +//-------------------------------------------------------------------------------------------------- +/// Shows formation zone bands using the explicit top/base depths from a formations file, without +/// requiring a well path trajectory (e.g. for an RFT well with no modelled well path). +//-------------------------------------------------------------------------------------------------- +void RimWellLogTrack::setAndUpdateFormationFileData( RimWellFormationsFile* wellFormationsFile, const QString& wellNameInFile ) +{ + m_formationSettings->setFormationSource( RiaDefines::WellLogTrackFormationSource::WELL_PICKS_NO_TRAJECTORY ); + m_formationSettings->setWellPathForSourceWellPath( nullptr ); + m_formationSettings->setWellFormationsFile( wellFormationsFile ); + m_formationSettings->setWellNameInFormationsFile( wellNameInFile ); + + updateConnectedEditors(); + + if ( m_regionAnnotationSettings->annotationType() != RiaDefines::RegionAnnotationType::NO_ANNOTATIONS ) + { + updateRegionAnnotationsOnPlot(); + } +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -2567,9 +2603,11 @@ void RimWellLogTrack::updateFormationNamesOnPlot() auto orientation = plot->depthOrientation(); - if ( m_formationSettings->formationSource() == RiaDefines::WellLogTrackFormationSource::WELL_PICK_FILTER ) + if ( m_formationSettings->formationSource() == RiaDefines::WellLogTrackFormationSource::WELL_PICK_FILTER || + m_formationSettings->formationSource() == RiaDefines::WellLogTrackFormationSource::WELL_PICKS_NO_TRAJECTORY ) { - if ( m_formationSettings->wellPathForSourceWellPath() == nullptr ) return; + auto formations = m_formationSettings->resolveWellPickFormations(); + if ( !formations.has_value() ) return; if ( plot->depthType() != RiaDefines::DepthType::MEASURED_DEPTH && plot->depthType() != RiaDefines::DepthType::TRUE_VERTICAL_DEPTH && plot->depthType() != RiaDefines::DepthType::TRUE_VERTICAL_DEPTH_RKB ) @@ -2577,24 +2615,87 @@ void RimWellLogTrack::updateFormationNamesOnPlot() return; } - const RigWellPathFormations* formations = m_formationSettings->wellPathForSourceWellPath()->formationsGeometry(); - if ( !formations ) return; - auto formationLevel = static_cast( m_formationSettings->formationLevel() ); - auto [formationNamesToPlot, yValues] = - formations->depthAndFormationNamesUpToLevel( formationLevel, m_formationSettings->showFormationFluids(), plot->depthType() ); - if ( plot->depthType() == RiaDefines::DepthType::TRUE_VERTICAL_DEPTH_RKB ) + double rkbDiff = 0.0; + if ( plot->depthType() == RiaDefines::DepthType::TRUE_VERTICAL_DEPTH_RKB && m_formationSettings->wellPathForSourceWellPath() ) { - for ( double& depthValue : yValues ) - { - depthValue += m_formationSettings->wellPathForSourceWellPath()->wellPathGeometry()->rkbDiff(); - } + rkbDiff = m_formationSettings->wellPathForSourceWellPath()->wellPathGeometry()->rkbDiff(); } - std::vector convertedYValues = RiaWellLogUnitTools::convertDepths( yValues, fromDepthUnit, toDepthUnit ); + // Fluid contacts are single-depth picks (no zone thickness); keep these as simple pick lines. + // depthAndFormationNamesUpToLevel() only produces fluid picks when the formation level is NONE. + auto [fluidNamesToPlot, fluidYValues] = formations->depthAndFormationNamesUpToLevel( RigWellPathFormations::FormationLevel::NONE, + m_formationSettings->showFormationFluids(), + plot->depthType() ); + for ( double& depthValue : fluidYValues ) + depthValue += rkbDiff; + std::vector convertedFluidYValues = RiaWellLogUnitTools::convertDepths( fluidYValues, fromDepthUnit, toDepthUnit ); - m_annotationTool->attachWellPicks( m_plotWidget->qwtPlot(), formationNamesToPlot, convertedYValues ); + // attachWellPicks() clears all existing plot annotations, so call it first and add the + // shaded formation zones (if any) afterwards. + m_annotationTool->attachWellPicks( m_plotWidget->qwtPlot(), fluidNamesToPlot, convertedFluidYValues ); + + // Formations have a top/base depth range, so they can be drawn as shaded zones (or plain + // lines) using the same region-display machinery as the CASE-based formation names below. + auto depthRanges = formations->depthRangesUpToLevel( formationLevel, plot->depthType() ); + if ( !depthRanges.empty() ) + { + std::vector zoneNamesToPlot; + std::vector> zoneYValues; + for ( const auto& [name, top, base] : depthRanges ) + { + zoneNamesToPlot.push_back( name ); + zoneYValues.emplace_back( top + rkbDiff, base + rkbDiff ); + } + + std::vector> convertedZoneYValues = + RiaWellLogUnitTools::convertDepths( zoneYValues, fromDepthUnit, toDepthUnit ); + + // Build color table ordered by formation name to ensure correct color mapping + // when using a legend based on a LYR-file. Falls back to palette index for + // formations not found in the legend (e.g., when using a generic color palette). + RimColorLegend* legend = m_regionAnnotationSettings->colorShadingLegend(); + if ( !legend ) legend = RimRegularLegendConfig::mapToColorLegend( RimRegularLegendConfig::ColorRangesType::NORMAL ); + + if ( legend ) + { + std::map nameToColor; + for ( auto* item : legend->colorLegendItems() ) + { + nameToColor[item->categoryName()] = cvf::Color3ub( item->color() ); + } + + cvf::Color3ubArray paletteColors = legend->colorArray(); + size_t colorCount = std::max( size_t( 2 ), zoneNamesToPlot.size() ); + cvf::Color3ubArray orderedColors( colorCount ); + orderedColors.setAll( cvf::Color3ub::GRAY ); + + for ( size_t i = 0; i < zoneNamesToPlot.size(); i++ ) + { + auto it = nameToColor.find( zoneNamesToPlot[i] ); + if ( it != nameToColor.end() ) + { + orderedColors.set( i, it->second ); + } + else if ( paletteColors.size() > 0 ) + { + orderedColors.set( i, paletteColors[i % paletteColors.size()] ); + } + } + + caf::ColorTable colorTable( orderedColors ); + + m_annotationTool->attachNamedRegions( m_plotWidget->qwtPlot(), + zoneNamesToPlot, + orientation, + convertedZoneYValues, + m_regionAnnotationSettings->annotationDisplay(), + colorTable, + ( ( 100 - m_regionAnnotationSettings->colorShadingTransparency() ) * 255 ) / 100, + m_regionAnnotationSettings->showRegionLabels() ); + } + } } else { diff --git a/ApplicationLibCode/ProjectDataModel/WellLog/WellLogTrack/RimWellLogTrack.h b/ApplicationLibCode/ProjectDataModel/WellLog/WellLogTrack/RimWellLogTrack.h index f3ef0952cb..31296c04c1 100644 --- a/ApplicationLibCode/ProjectDataModel/WellLog/WellLogTrack/RimWellLogTrack.h +++ b/ApplicationLibCode/ProjectDataModel/WellLog/WellLogTrack/RimWellLogTrack.h @@ -19,7 +19,6 @@ #pragma once -#include "RiaWellLogTrackDefines.h" #include "RimWellLogPlot.h" #include "RiaPlotDefines.h" @@ -42,10 +41,18 @@ #include #include +namespace RiaDefines +{ +enum class WellLogTrackFormationSource; +enum class WellLogTrackTrajectoryType; +enum class WellLogTrackFormationLevel; +} // namespace RiaDefines + class RigWellPath; class RimCase; class RimWellPathAttributeCollection; class RimWellFlowRateCurve; +class RimWellFormationsFile; class RimWellLogCurve; class RimWellPath; class RimDepthTrackPlot; @@ -133,6 +140,10 @@ public: void setAndUpdateSimWellFormationNamesAndBranchData( RimCase* rimCase, const QString& simWellName, int branchIndex, bool useBranchDetection ); void setAndUpdateSimWellFormationNamesData( RimCase* rimCase, const QString& simWellName ); + void setAndUpdateWellPickFormationsData( RimWellPath* wellPath ); + + void setAndUpdateFormationFileData( RimWellFormationsFile* wellFormationsFile, const QString& wellNameInFile ); + [[deprecated( "Use setAutoScalePropertyValuesEnabled() instead." )]] void setAutoScaleXEnabled( bool enabled ) override; [[deprecated( "Use setAutoScaleDepthValuesEnabled() instead." )]] void setAutoScaleYEnabled( bool enabled ) override;