Skip to content

feat: add limits to input attributes#4063

Open
kdrienCG wants to merge 30 commits into
developfrom
feature/kdrienCG/attributeLimitMetadata
Open

feat: add limits to input attributes#4063
kdrienCG wants to merge 30 commits into
developfrom
feature/kdrienCG/attributeLimitMetadata

Conversation

@kdrienCG

@kdrienCG kdrienCG commented May 20, 2026

Copy link
Copy Markdown
Contributor

This PR adds the possibility to specify a min and/or a max value to Wrappers attributes.

The goal is to provide the foundations for two follow-up efforts planned in future PRs:

  • applying this limit feature wherever GEOS has known, constant ranges that can be validated;
  • extending the generated documentation (e.g. with additional text or a dedicated column) to display the limits associated with each attribute.

Usage:

registerWrapper( viewKeysStruct::fooString(), &m_foo )
  .setLimits( 0.0, 1.0 )  // sets a minimal value of 0.0 and a maximal value of 1.0

This will serve as a documentation for values, but also prevents users from making typos that could lead to wrong results, taking time to find (if noticed).

The limits come with 3 modes:

  • Indicative: No validation of the input is made, serves as documentation only.
  • Warning: A warning is emitted if the attribute's value is outside the allowed range.
  • Error: An error is emitted if the attribute's value is outside the allowed range.

The mode can be set when specifying the limit, using this syntax:

  .setLimits( 0.0, 1.0, LimitsMode::Warning )

... or it will default to Error if unset.

Limits also support inclusive and exclusive bounds:

  .setLimits( inclusive( 0.0 ), exclusive( 1.0 ) )

Not using inclusive(...) or exclusive(...) will default to an inclusive limit.


Some examples:

  .setLimits( 0.0, 1.0 )  // [0.0, 1.0]
  .setLimits( 0.0, std::nullopt )  // [0.0, +inf)
  .setLimits( inclusive( 0.0 ), std::nullopt )  // [0.0, +inf)
  .setLimits( std::nullopt, exclusive( 0.0 ) )  // (-inf, 0.0)

@kdrienCG kdrienCG self-assigned this May 20, 2026
@kdrienCG kdrienCG added the type: feature New feature or request label May 20, 2026
@kdrienCG kdrienCG marked this pull request as ready for review May 20, 2026 09:06

@dkachuma dkachuma left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I really like this idea. It will simplify greatly some of the boiler plate validation code.

Will this work for lists of numbers?

Comment thread src/coreComponents/dataRepository/Wrapper.hpp Outdated
Comment thread src/coreComponents/dataRepository/Wrapper.hpp Outdated
@kdrienCG kdrienCG requested a review from OmarDuran as a code owner May 29, 2026 13:36

@MelReyCG MelReyCG left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please apply this feature on at least one (maybe basic) 'Group' to demonstrate usage (array and scalar ideally).

Comment on lines +24 to +25
#include "common/format/Format.hpp"
#include "common/logger/Logger.hpp"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

un-needed inclusion, beware of clangd ;)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are still some,
<type_traits>, <optional>, maybe some more

Comment thread src/coreComponents/dataRepository/AttributeLimits.hpp Outdated
Comment thread src/coreComponents/dataRepository/AttributeLimits.hpp Outdated
Comment thread src/coreComponents/dataRepository/AttributeLimits.hpp Outdated
Comment thread src/coreComponents/dataRepository/AttributeLimits.hpp Outdated
Comment thread src/coreComponents/dataRepository/AttributeLimits.hpp Outdated
Comment thread src/coreComponents/dataRepository/Wrapper.hpp
* // default to true.
* @endcode
*/
Bound( T v, bool inclusive = true )

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we want this constructor explicit?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was made not explicit so we can write .setLimits( 0.0, 1.0 ) instead of .setLimits( WrapperBound{ 0.0 }, WrapperBound{ 1.0 } )

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That implicit conversion from any double to your type, at this (critical) level of the inclusion hierarchy, may cause the compiler to try undesired casts.
Why not an overload or a different signature for setLimits()?

@kdrienCG

Copy link
Copy Markdown
Contributor Author

Please apply this feature on at least one (maybe basic) 'Group' to demonstrate usage (array and scalar ideally).

Applied to BrooksCoreyBakerRelativePermeability that uses arrays in commit 931c469

Comment on lines +24 to +25
#include "common/format/Format.hpp"
#include "common/logger/Logger.hpp"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are still some,
<type_traits>, <optional>, maybe some more

Comment on lines +1234 to +1249
string const msg = GEOS_FMT( "Value {} for attribute '{}' is outside the allowed range {}.",
value, getDataContext(), m_limits.getRangeStr() );

switch( m_limitsMode )
{
case WrapperLimitsMode::Warning:
GEOS_WARNING( msg );
break;

case WrapperLimitsMode::Error:
GEOS_THROW( msg, InputError );
break;

default:
GEOS_LOG_RANK_0( "Unimplemented WrapperLimitsMode" );
break;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What gives the following in the log?

Suggested change
string const msg = GEOS_FMT( "Value {} for attribute '{}' is outside the allowed range {}.",
value, getDataContext(), m_limits.getRangeStr() );
switch( m_limitsMode )
{
case WrapperLimitsMode::Warning:
GEOS_WARNING( msg );
break;
case WrapperLimitsMode::Error:
GEOS_THROW( msg, InputError );
break;
default:
GEOS_LOG_RANK_0( "Unimplemented WrapperLimitsMode" );
break;
string const msg = GEOS_FMT( "Value {} is outside the allowed range {}.",
value, m_limits.getRangeStr() );
switch( m_limitsMode )
{
case WrapperLimitsMode::Warning:
GEOS_WARNING( msg, getDataContext() );
break;
case WrapperLimitsMode::Error:
GEOS_THROW( msg, InputError, getDataContext() );
break;
default:
GEOS_LOG_RANK_0( "Unimplemented WrapperLimitsMode" );
break;

* // default to true.
* @endcode
*/
Bound( T v, bool inclusive = true )

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That implicit conversion from any double to your type, at this (critical) level of the inclusion hierarchy, may cause the compiler to try undesired casts.
Why not an overload or a different signature for setLimits()?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

type: feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants