Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions ApplicationLibCode/Application/CMakeLists_files.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ set(SOURCE_GROUP_SOURCE_FILES
${CMAKE_CURRENT_LIST_DIR}/RiaPreferencesGeoMech.cpp
${CMAKE_CURRENT_LIST_DIR}/RiaPreferencesGrid.cpp
${CMAKE_CURRENT_LIST_DIR}/RiaPreferencesSystem.cpp
${CMAKE_CURRENT_LIST_DIR}/RiaExperimentalFeatures.cpp
${CMAKE_CURRENT_LIST_DIR}/RiaPreferencesOsdu.cpp
${CMAKE_CURRENT_LIST_DIR}/RiaPreferencesOpm.cpp
${CMAKE_CURRENT_LIST_DIR}/RiaPreferencesSumo.cpp
Expand Down
40 changes: 40 additions & 0 deletions ApplicationLibCode/Application/RiaExperimentalFeatures.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2026 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 "RiaExperimentalFeatures.h"

//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
const std::vector<RiaExperimentalFeatures::Feature>& RiaExperimentalFeatures::availableFeatures()
{
// Register experimental features here. Each entry automatically becomes a checkbox in
// Preferences -> System -> Experimental Features. Gate the related code path behind
// RiaPreferencesSystem::isFeatureEnabled( "<keyword>" ).
//
// Example:
// { "my-feature", "My Feature", "Short description of what it does." },
static const std::vector<Feature> features = {
{ "osdu-well-logs", "OSDU Well Logs", "Enable import of well logs from OSDU." },
{ "undo-redo-view", "Undo/Redo View", "Show the command undo/redo history view." },
{ "export-dock-layout", "Export Dock Layout", "Add a window menu action to export the dock layout to the clipboard." },
{ "oil-volume-result", "Oil Volume Result", "Compute the derived oil volume cell result." },
};

return features;
}
44 changes: 44 additions & 0 deletions ApplicationLibCode/Application/RiaExperimentalFeatures.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2026 Equinor ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////

#pragma once

#include <QString>

#include <vector>

//--------------------------------------------------------------------------------------------------
/// Central, discoverable registry of experimental features.
///
/// To add a new experimental feature, append an entry to the list returned by availableFeatures()
/// (see RiaExperimentalFeatures.cpp) and gate the code path behind
/// RiaPreferencesSystem::isFeatureEnabled( "<keyword>" ).
//--------------------------------------------------------------------------------------------------
class RiaExperimentalFeatures
{
public:
struct Feature
{
QString keyword; ///< Stable identifier, passed to RiaPreferencesSystem::isFeatureEnabled().
QString displayName; ///< Human readable name shown as the checkbox label.
QString description; ///< Short explanation, appended to the checkbox label.
};

/// The single, discoverable list of all experimental features.
static const std::vector<Feature>& availableFeatures();
};
13 changes: 13 additions & 0 deletions ApplicationLibCode/Application/RiaPreferences.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -531,6 +531,10 @@ void RiaPreferences::defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering&
openTelemetryGroup->setCollapsedByDefault();
m_openTelemetryPreferences()->uiOrdering( uiConfigName, *openTelemetryGroup );
}
else if ( uiConfigName == RiaPreferences::tabNameExperimental() )
{
m_systemPreferences()->appendExperimentalFeaturesItems( uiOrdering );
}
else if ( RiaApplication::enableDevelopmentFeatures() && uiConfigName == RiaPreferences::tabNameSystem() )
{
m_systemPreferences()->uiOrdering( uiConfigName, uiOrdering );
Expand Down Expand Up @@ -674,6 +678,14 @@ QString RiaPreferences::tabNameImportExport()
return "Import/Export";
}

//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RiaPreferences::tabNameExperimental()
{
return "Experimental";
}

//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
Expand Down Expand Up @@ -707,6 +719,7 @@ QStringList RiaPreferences::tabNames()
names << tabNameGeomech();
#endif
names << tabNameImportExport();
names << tabNameExperimental();

if ( RiaApplication::enableDevelopmentFeatures() )
{
Expand Down
1 change: 1 addition & 0 deletions ApplicationLibCode/Application/RiaPreferences.h
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@ class RiaPreferences : public caf::PdmObject
static QString tabNameSystem();
static QString tabNameImportExport();
static QString tabNameOpmFlow();
static QString tabNameExperimental();

static double defaultMarginSize( QPageSize::PageSizeId pageSizeId );

Expand Down
111 changes: 106 additions & 5 deletions ApplicationLibCode/Application/RiaPreferencesSystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,17 @@

#include "RiaApplication.h"

#include "RiaExperimentalFeatures.h"
#include "RiaPreferences.h"
#include "RiaPreferencesSystem.h"

#include "cafPdmUiCheckBoxAndTextEditor.h"
#include "cafPdmUiCheckBoxEditor.h"
#include "cafPdmUiFilePathEditor.h"
#include "cafPdmUiTextEditor.h"
#include "cafPdmUiTreeSelectionEditor.h"

#include <algorithm>

namespace caf
{
Expand Down Expand Up @@ -92,10 +97,25 @@ RiaPreferencesSystem::RiaPreferencesSystem()
QString(),
"Keywords to enable debug logging, separated by semicolon.\nType 'enable-all' to enable logging for all objects." );

CAF_PDM_InitFieldNoDefault( &m_enabledFeatures, "EnabledFeatures", "Experimental Features" );
m_enabledFeatures.uiCapability()->setUiEditorTypeName( caf::PdmUiTreeSelectionEditor::uiEditorTypeName() );

// Transient UI helper fields, not stored in the preferences file.
CAF_PDM_InitFieldNoDefault( &m_currentFeatureKeyword, "currentFeatureKeyword", "" );
m_currentFeatureKeyword.uiCapability()->setUiHidden( true );
m_currentFeatureKeyword.xmlCapability()->disableIO();

CAF_PDM_InitFieldNoDefault( &m_selectedFeatureDescription, "selectedFeatureDescription", "Description" );
m_selectedFeatureDescription.uiCapability()->setUiEditorTypeName( caf::PdmUiTextEditor::uiEditorTypeName() );
m_selectedFeatureDescription.uiCapability()->setUiReadOnly( true );
m_selectedFeatureDescription.xmlCapability()->disableIO();

// Legacy free-text field, kept only to migrate older preference files into m_enabledFeatures.
CAF_PDM_InitField( &m_featureKeywords,
"FeatureKeywords",
QString(),
"Keywords to enable experimental features separated by semicolon.\nType 'enable-all' for all." );
m_featureKeywords.uiCapability()->setUiHidden( true );

CAF_PDM_InitField( &m_maximumNumberOfThreads, "maximumNumberOfThreads", std::make_pair( false, QString( "4" ) ), "Maximum Number of Threads" );
m_maximumNumberOfThreads.uiCapability()->setUiEditorTypeName( caf::PdmUiCheckBoxAndTextEditor::uiEditorTypeName() );
Expand Down Expand Up @@ -283,11 +303,9 @@ bool RiaPreferencesSystem::isFeatureEnabled( const QString& keyword ) const
{
if ( keyword.isEmpty() ) return false;

const QStringList keywords = m_featureKeywords().split( ";", Qt::SkipEmptyParts );
const std::vector<QString>& enabled = m_enabledFeatures();

if ( keywords.contains( "enable-all" ) ) return true;

return keywords.contains( keyword );
return std::find( enabled.begin(), enabled.end(), keyword ) != enabled.end();
}

//--------------------------------------------------------------------------------------------------
Expand Down Expand Up @@ -326,11 +344,24 @@ void RiaPreferencesSystem::defineUiOrdering( QString uiConfigName, caf::PdmUiOrd
{
caf::PdmUiGroup* group = uiOrdering.addNewGroup( "Developer Settings" );
group->add( &m_keywordsForLogging );
group->add( &m_featureKeywords );
group->add( &m_gtestFilter );
}

uiOrdering.add( &m_maximumNumberOfThreads );

// The experimental feature fields are shown on the dedicated Experimental tab, so do not let
// them auto-append to the System tab.
uiOrdering.skipRemainingFields( true );
}

//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RiaPreferencesSystem::appendExperimentalFeaturesItems( caf::PdmUiOrdering& uiOrdering )
{
caf::PdmUiGroup* group = uiOrdering.addNewGroup( "Experimental Features" );
group->add( &m_enabledFeatures );
group->add( &m_selectedFeatureDescription );
}

//--------------------------------------------------------------------------------------------------
Expand All @@ -340,9 +371,41 @@ QList<caf::PdmOptionItemInfo> RiaPreferencesSystem::calculateValueOptions( const
{
QList<caf::PdmOptionItemInfo> options;

if ( fieldNeedingOptions == &m_enabledFeatures )
{
for ( const auto& feature : RiaExperimentalFeatures::availableFeatures() )
{
options.push_back( caf::PdmOptionItemInfo( feature.displayName, feature.keyword ) );
}
}

return options;
}

//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RiaPreferencesSystem::initAfterRead()
{
// Migrate the legacy semicolon-separated keyword string into the checkbox-based field.
if ( !m_featureKeywords().isEmpty() )
{
std::vector<QString> enabled = m_enabledFeatures();

const QStringList legacyKeywords = m_featureKeywords().split( ";", Qt::SkipEmptyParts );
for ( const QString& keyword : legacyKeywords )
{
if ( std::find( enabled.begin(), enabled.end(), keyword ) == enabled.end() )
{
enabled.push_back( keyword );
}
}

m_enabledFeatures = enabled;
m_featureKeywords = QString();
}
}

//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
Expand All @@ -356,4 +419,42 @@ void RiaPreferencesSystem::defineEditorAttribute( const caf::PdmFieldHandle* fie
myAttr->m_selectDirectory = true;
}
}
else if ( field == &m_enabledFeatures )
{
// Report the highlighted (clicked) feature so its description can be shown below the list.
if ( auto* myAttr = dynamic_cast<caf::PdmUiTreeSelectionEditorAttribute*>( attribute ) )
{
myAttr->currentIndexFieldHandle = &m_currentFeatureKeyword;
}
}
else if ( field == &m_selectedFeatureDescription )
{
if ( auto* myAttr = dynamic_cast<caf::PdmUiTextEditorAttribute*>( attribute ) )
{
myAttr->wrapMode = caf::PdmUiTextEditorAttribute::WordWrap;
myAttr->heightHint = 60;
}
}
}

//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RiaPreferencesSystem::fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue )
{
if ( changedField == &m_currentFeatureKeyword )
{
QString description;
for ( const auto& feature : RiaExperimentalFeatures::availableFeatures() )
{
if ( feature.keyword == m_currentFeatureKeyword() )
{
description = feature.description;
break;
}
}

m_selectedFeatureDescription = description;
m_selectedFeatureDescription.uiCapability()->updateConnectedEditors();
}
}
10 changes: 9 additions & 1 deletion ApplicationLibCode/Application/RiaPreferencesSystem.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,14 @@ class RiaPreferencesSystem : public caf::PdmObject
bool isLoggingActivatedForKeyword( const QString& keyword ) const;
bool isFeatureEnabled( const QString& keyword ) const;

void appendExperimentalFeaturesItems( caf::PdmUiOrdering& uiOrdering );

protected:
void defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) override;
QList<caf::PdmOptionItemInfo> calculateValueOptions( const caf::PdmFieldHandle* fieldNeedingOptions ) override;
void defineEditorAttribute( const caf::PdmFieldHandle* field, QString uiConfigName, caf::PdmUiEditorAttribute* attribute ) override;
void fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue ) override;
void initAfterRead() override;

private:
caf::PdmField<bool> m_appendClassNameToUiText;
Expand All @@ -96,7 +100,11 @@ class RiaPreferencesSystem : public caf::PdmObject
caf::PdmField<EclipseTextFileReaderModeType> m_eclipseReaderMode;

caf::PdmField<QString> m_keywordsForLogging;
caf::PdmField<QString> m_featureKeywords;

caf::PdmField<std::vector<QString>> m_enabledFeatures;
caf::PdmField<QString> m_currentFeatureKeyword; // Transient: keyword of the highlighted feature row
caf::PdmField<QString> m_selectedFeatureDescription; // Transient: description shown below the list
caf::PdmField<QString> m_featureKeywords; // Legacy free-text field, kept for migration only

caf::PdmField<std::pair<bool, QString>> m_maximumNumberOfThreads;
};
37 changes: 14 additions & 23 deletions ApplicationLibCode/FileInterface/RifRoffFileTools.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -149,12 +149,9 @@ bool RifRoffFileTools::openGridFile( const QString& fileName, RigEclipseCaseData
float yScale = getFloat( values, "scale.yscale" );
float zScale = getFloat( values, "scale.zscale" );

if ( RiaApplication::enableDevelopmentFeatures() )
{
RiaLogging::info( std::format( "Grid dimensions: {} {} {}", nx, ny, nz ) );
RiaLogging::info( std::format( "Offset: {} {} {}", xOffset, yOffset, zOffset ) );
RiaLogging::info( std::format( "Scale: {} {} {}", xScale, yScale, zScale ) );
}
RiaLogging::debug( std::format( "Grid dimensions: {} {} {}", nx, ny, nz ) );
RiaLogging::debug( std::format( "Offset: {} {} {}", xOffset, yOffset, zOffset ) );
RiaLogging::debug( std::format( "Scale: {} {} {}", xScale, yScale, zScale ) );

std::vector<float> cornerLines = reader.getFloatArray( "cornerLines" + roff::Parser::postFixData() );
std::vector<float> zValues = reader.getFloatArray( "zvalues" + roff::Parser::postFixData() );
Expand Down Expand Up @@ -259,22 +256,19 @@ bool RifRoffFileTools::openGridFile( const QString& fileName, RigEclipseCaseData
activeCellInfo->computeDerivedData();
fractureActiveCellInfo->computeDerivedData();

if ( RiaApplication::enableDevelopmentFeatures() )
{
auto gridConstructionDone = high_resolution_clock::now();
auto gridConstructionDone = high_resolution_clock::now();

auto tokenizeDuration = duration_cast<milliseconds>( tokenizeDone - totalStart );
RiaLogging::info( std::format( "Tokenizing: {} ms", tokenizeDuration.count() ) );
auto tokenizeDuration = duration_cast<milliseconds>( tokenizeDone - totalStart );
RiaLogging::debug( std::format( "Tokenizing: {} ms", tokenizeDuration.count() ) );

auto parsingDuration = duration_cast<milliseconds>( parsingDone - tokenizeDone );
RiaLogging::info( std::format( "Parsing: {} ms", parsingDuration.count() ) );
auto parsingDuration = duration_cast<milliseconds>( parsingDone - tokenizeDone );
RiaLogging::debug( std::format( "Parsing: {} ms", parsingDuration.count() ) );

auto gridConstructionDuration = duration_cast<milliseconds>( gridConstructionDone - parsingDone );
RiaLogging::info( std::format( "Grid Construction: {} ms", gridConstructionDuration.count() ) );
auto gridConstructionDuration = duration_cast<milliseconds>( gridConstructionDone - parsingDone );
RiaLogging::debug( std::format( "Grid Construction: {} ms", gridConstructionDuration.count() ) );

auto totalDuration = duration_cast<milliseconds>( gridConstructionDone - totalStart );
RiaLogging::info( std::format( "Total: {} ms", totalDuration.count() ) );
}
auto totalDuration = duration_cast<milliseconds>( gridConstructionDone - totalStart );
RiaLogging::debug( std::format( "Total: {} ms", totalDuration.count() ) );
}
catch ( std::runtime_error& err )
{
Expand Down Expand Up @@ -541,11 +535,8 @@ std::pair<bool, std::map<QString, QString>> RifRoffFileTools::createInputPropert
for ( auto [keyword, kind] : arrayTypes )
{
size_t keywordLength = reader.getArrayLength( keyword );
if ( RiaApplication::enableDevelopmentFeatures() )
{
RiaLogging::info(
std::format( "Array found: '{}'. Type: {} with size: {}.", keyword, roff::Token::kindToString( kind ), keywordLength ) );
}
RiaLogging::debug(
std::format( "Array found: '{}'. Type: {} with size: {}.", keyword, roff::Token::kindToString( kind ), keywordLength ) );

QString keywordUpperCase = QString::fromStdString( keyword ).toUpper();

Expand Down
Loading
Loading