From c8adaac60b908898daf51ee7ae08b9b63c5b6523 Mon Sep 17 00:00:00 2001 From: kdrienCG Date: Wed, 22 Apr 2026 10:11:16 +0200 Subject: [PATCH 01/23] add scales and functionNames attributes --- .../FieldSpecificationBase.cpp | 12 +++++ .../FieldSpecificationBase.hpp | 54 +++++++++++++++++++ 2 files changed, 66 insertions(+) diff --git a/src/coreComponents/fieldSpecification/FieldSpecificationBase.cpp b/src/coreComponents/fieldSpecification/FieldSpecificationBase.cpp index 94e78e7e06a..e2b18e189c9 100644 --- a/src/coreComponents/fieldSpecification/FieldSpecificationBase.cpp +++ b/src/coreComponents/fieldSpecification/FieldSpecificationBase.cpp @@ -61,6 +61,13 @@ FieldSpecificationBase::FieldSpecificationBase( string const & name, Group * par setInputFlag( InputFlags::OPTIONAL ). setDescription( "Name of function that specifies variation of the boundary condition." ); + registerWrapper( viewKeyStruct::functionNamesString(), &m_functionNames ). + setRTTypeName( rtTypes::CustomTypes::groupNameRefArray ). + setInputFlag( InputFlags::OPTIONAL ). + setSizedFromParent( 0 ). + setDescription( "Names of per-component functions that specifies variation of the boundary condition.\n" + "Either left empty or sized exactly like 'scales'.\n" ); + registerWrapper( viewKeyStruct::bcApplicationTableNameString(), &m_bcApplicationFunctionName ). setRTTypeName( rtTypes::CustomTypes::groupNameRef ). setInputFlag( InputFlags::OPTIONAL ). @@ -71,6 +78,11 @@ FieldSpecificationBase::FieldSpecificationBase( string const & name, Group * par setInputFlag( InputFlags::OPTIONAL ). setDescription( "Apply a scaling factor for the value of the boundary condition." ); + registerWrapper( viewKeyStruct::scalesString(), &m_scales ). + setInputFlag( InputFlags::OPTIONAL ). + setSizedFromParent( 0 ). + setDescription( "Apply scaling factors for the values of every component of the boundary condition.\n" ); + registerWrapper( viewKeyStruct::initialConditionString(), &m_initialCondition ). setApplyDefaultValue( 0 ). setInputFlag( InputFlags::OPTIONAL ). diff --git a/src/coreComponents/fieldSpecification/FieldSpecificationBase.hpp b/src/coreComponents/fieldSpecification/FieldSpecificationBase.hpp index 1905a4e5c36..0b75a696ac3 100644 --- a/src/coreComponents/fieldSpecification/FieldSpecificationBase.hpp +++ b/src/coreComponents/fieldSpecification/FieldSpecificationBase.hpp @@ -394,8 +394,12 @@ class FieldSpecificationBase : public dataRepository::Group constexpr static char const * bcApplicationTableNameString() { return "bcApplicationTableName"; } /// @return The key for scale constexpr static char const * scaleString() { return "scale"; } + /// @return The key for scales + constexpr static char const * scalesString() { return "scales"; } /// @return The key for functionName constexpr static char const * functionNameString() { return "functionName"; } + /// @return The key for functionNames + constexpr static char const * functionNamesString() { return "functionNames"; } /// @return The key for initialCondition constexpr static char const * initialConditionString() { return "initialCondition"; } /// @return The key for beginTime @@ -415,6 +419,15 @@ class FieldSpecificationBase : public dataRepository::Group return m_functionName; } + /** + * Accessor + * @return const reference to m_functionNames + */ + string_array const & getFunctionNames() const + { + return m_functionNames; + } + /** * Accessor * @return const reference to m_objectPath @@ -497,6 +510,15 @@ class FieldSpecificationBase : public dataRepository::Group return m_scale; } + /** + * Accessor + * @return const m_scales + */ + array1d< real64 > getScales() const + { + return m_scales; + } + /** * Mutator * @param[in] fieldName The name of the field @@ -524,6 +546,31 @@ class FieldSpecificationBase : public dataRepository::Group m_scale = scale; } + /** + * Mutator + * @brief Set the per-component scale factors + * @param[in] scales The tensor-valued scale + */ + void setScales( arrayView1d< real64 const > const & scales ) + { + m_scales.resize( scales.size() ); + for( localIndex comp = 0; comp < scales.size(); ++comp ) + { + m_scales[ comp ] = scales[ comp ]; + } + } + + /** + * Mutator + * @brief Set the per-component function names + * @param[in] functionNames The per-component function names. Must have the same + * size as @p m_scales or be empty. + */ + void setFunctionNames( string_array const & functionNames ) + { + m_functionNames = functionNames; + } + /** * Mutator * @param[in] isInitialCondition Logical value to indicate if it is an initial condition @@ -591,9 +638,16 @@ class FieldSpecificationBase : public dataRepository::Group /// The name of the function used to generate values for application. string m_functionName; + /// Per-component function names used when @p m_scales.size() > 1 + /// Either empty or sized exactly like @p m_scales + string_array m_functionNames; + /// The scale factor to use on the value of the boundary condition. real64 m_scale; + /// Per-component scale factors + array1d< real64 > m_scales; + /// Time after which the bc is allowed to be applied real64 m_beginTime; From 67da13f258d0b60ee2df07bd6b351bf1875df756 Mon Sep 17 00:00:00 2001 From: kdrienCG Date: Wed, 22 Apr 2026 11:11:55 +0200 Subject: [PATCH 02/23] modify applyFieldValueKernel to accept non-scalar applications --- .../FieldSpecificationBase.hpp | 54 ++++++++++++++----- 1 file changed, 40 insertions(+), 14 deletions(-) diff --git a/src/coreComponents/fieldSpecification/FieldSpecificationBase.hpp b/src/coreComponents/fieldSpecification/FieldSpecificationBase.hpp index 0b75a696ac3..55f44e8c76c 100644 --- a/src/coreComponents/fieldSpecification/FieldSpecificationBase.hpp +++ b/src/coreComponents/fieldSpecification/FieldSpecificationBase.hpp @@ -606,6 +606,15 @@ class FieldSpecificationBase : public dataRepository::Group return *(m_meshObjectPaths.get()); } + /** + * @brief Query whether this field specification uses non-scalar scales + * @return true if @p m_scales holds more than one entry + */ + bool isVectorMode() const + { + return m_scales.size() > 1; + } + protected: @@ -668,25 +677,28 @@ void FieldSpecificationBase::applyFieldValueKernel( ArrayView< T, N, USD > const real64 const time, Group & dataGroup ) const { - integer const component = getComponent(); FunctionManager & functionManager = FunctionManager::getInstance(); - if( m_functionName.empty() ) + auto applyOneComponent = [&]( integer const component, + real64 const scale, + string const & functionName ) { - real64 const value = m_scale; - forAll< POLICY >( targetSet.size(), [=] GEOS_HOST_DEVICE ( localIndex const i ) + if( functionName.empty() ) { - localIndex const a = targetSet[ i ]; - FIELD_OP::SpecifyFieldValue( field, a, component, value ); - } ); - } - else - { + real64 const value = scale; + forAll< POLICY >( targetSet.size(), [=] GEOS_HOST_DEVICE ( localIndex const i ) + { + localIndex const a = targetSet[ i ]; + FIELD_OP::SpecifyFieldValue( field, a, component, value ); + } ); + return; + } + FunctionBase const & function = [&]() -> FunctionBase const & { try { - return functionManager.getGroup< FunctionBase >( m_functionName ); + return functionManager.getGroup< FunctionBase >( functionName ); } catch( std::exception const & e ) { @@ -702,7 +714,7 @@ void FieldSpecificationBase::applyFieldValueKernel( ArrayView< T, N, USD > const if( function.isFunctionOfTime()==2 ) { - real64 const value = m_scale * function.evaluate( &time ); + real64 const value = scale * function.evaluate( &time ); forAll< POLICY >( targetSet.size(), [=] GEOS_HOST_DEVICE ( localIndex const i ) { localIndex const a = targetSet[ i ]; @@ -714,13 +726,27 @@ void FieldSpecificationBase::applyFieldValueKernel( ArrayView< T, N, USD > const real64_array result( static_cast< localIndex >( targetSet.size() ) ); function.evaluate( dataGroup, time, targetSet, result ); arrayView1d< real64 const > const & resultView = result.toViewConst(); - real64 const scale = m_scale; + real64 const localScale = scale; forAll< POLICY >( targetSet.size(), [=] GEOS_HOST_DEVICE ( localIndex const i ) { localIndex const a = targetSet[ i ]; - FIELD_OP::SpecifyFieldValue( field, a, component, scale * resultView[i] ); + FIELD_OP::SpecifyFieldValue( field, a, component, localScale * resultView[i] ); } ); } + }; + + if( isVectorMode() ) + { + localIndex const numComponents = m_scales.size(); + for( localIndex c = 0; c < numComponents; ++c ) + { + string const & compFunctionName = m_functionNames.empty() ? string{} : m_functionNames[ c ]; + applyOneComponent( c, m_scales[ c ], compFunctionName ); + } + } + else + { + applyOneComponent( getComponent(), m_scale, m_functionName ); } } From e133dd24c747470b739d1d7ddbec1164a191edf6 Mon Sep 17 00:00:00 2001 From: kdrienCG Date: Wed, 22 Apr 2026 14:46:26 +0200 Subject: [PATCH 03/23] add validations against scale(s) and functionName(s) --- .../FieldSpecificationBase.cpp | 32 +++++++++++++++++++ .../FieldSpecificationBase.hpp | 2 ++ 2 files changed, 34 insertions(+) diff --git a/src/coreComponents/fieldSpecification/FieldSpecificationBase.cpp b/src/coreComponents/fieldSpecification/FieldSpecificationBase.cpp index e2b18e189c9..fff25b3cf3c 100644 --- a/src/coreComponents/fieldSpecification/FieldSpecificationBase.cpp +++ b/src/coreComponents/fieldSpecification/FieldSpecificationBase.cpp @@ -15,6 +15,7 @@ #include "FieldSpecificationBase.hpp" +#include "common/logger/Logger.hpp" #include "fieldSpecification/FieldSpecificationManager.hpp" namespace geos @@ -122,6 +123,37 @@ FieldSpecificationBase::getCatalog() } +void FieldSpecificationBase::postInputInitialization() +{ + GEOS_THROW_IF( !m_functionNames.empty() && + m_functionNames.size() != static_cast< string_array::size_type >( m_scales.size() ), + GEOS_FMT ( "Size mismatch: '{}' has {} entries but '{}' has {}. " + "Either leave '{}' empty or size it exactly like '{}'", + viewKeyStruct::functionNameString(), m_functionNames.size(), + viewKeyStruct::scalesString(), m_scales.size(), + viewKeyStruct::functionNamesString(), viewKeyStruct::scalesString() ), + InputError, + getDataContext() ); + + if( isVectorMode() ) + { + GEOS_THROW_IF( m_component != -1, + GEOS_FMT ( "'{}' must not be set when '{}' has more than one entry", + viewKeyStruct::componentString(), + viewKeyStruct::scalesString() ), + InputError, + getDataContext() ); + + GEOS_THROW_IF( !m_functionName.empty(), + GEOS_FMT ( "'{}' must not be set when '{}' has more than one entry. " + "Use '{}' to provide one function per component instead", + viewKeyStruct::functionNameString(), + viewKeyStruct::scalesString(), + viewKeyStruct::functionNamesString() ), + InputError, + getDataContext() ); + } +} void FieldSpecificationBase::setMeshObjectPath( Group const & meshBodies ) { diff --git a/src/coreComponents/fieldSpecification/FieldSpecificationBase.hpp b/src/coreComponents/fieldSpecification/FieldSpecificationBase.hpp index 55f44e8c76c..91ff87d8a3a 100644 --- a/src/coreComponents/fieldSpecification/FieldSpecificationBase.hpp +++ b/src/coreComponents/fieldSpecification/FieldSpecificationBase.hpp @@ -618,6 +618,8 @@ class FieldSpecificationBase : public dataRepository::Group protected: + virtual void postInputInitialization() override; + private: From 7c183528ebf7f028bed73a614ca04315ffe3ff44 Mon Sep 17 00:00:00 2001 From: kdrienCG Date: Thu, 23 Apr 2026 15:29:23 +0200 Subject: [PATCH 04/23] add regionNames attribute to field specifications --- .../FieldSpecificationBase.cpp | 18 ++++++++++++++++++ .../FieldSpecificationBase.hpp | 14 ++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/src/coreComponents/fieldSpecification/FieldSpecificationBase.cpp b/src/coreComponents/fieldSpecification/FieldSpecificationBase.cpp index fff25b3cf3c..0892ca0072e 100644 --- a/src/coreComponents/fieldSpecification/FieldSpecificationBase.cpp +++ b/src/coreComponents/fieldSpecification/FieldSpecificationBase.cpp @@ -15,6 +15,7 @@ #include "FieldSpecificationBase.hpp" +#include "common/format/StringUtilities.hpp" #include "common/logger/Logger.hpp" #include "fieldSpecification/FieldSpecificationManager.hpp" @@ -40,6 +41,11 @@ FieldSpecificationBase::FieldSpecificationBase( string const & name, Group * par setInputFlag( InputFlags::OPTIONAL ). setDescription( "Path to the target field" ); + registerWrapper( viewKeyStruct::regionNamesString(), &m_regionNames ). + setRTTypeName( rtTypes::CustomTypes::groupNameRefArray ). + setInputFlag( InputFlags::OPTIONAL ). + setDescription( "Names of the regions where the field specification is applied." ); + registerWrapper( viewKeyStruct::fieldNameString(), &m_fieldName ). setRTTypeName( rtTypes::CustomTypes::groupNameRef ). setInputFlag( InputFlags::OPTIONAL ). @@ -153,6 +159,18 @@ void FieldSpecificationBase::postInputInitialization() InputError, getDataContext() ); } + + if( !m_regionNames.empty() ) + { + GEOS_THROW_IF( !m_objectPath.empty(), + GEOS_FMT ( "'{}' must not be set when '{}' is set. ", + viewKeyStruct::objectPathString(), + viewKeyStruct::regionNamesString() ), + InputError, + getDataContext() ); + + m_objectPath = "ElementRegions/{" + stringutilities::join( m_regionNames, ' ' ) + "}"; + } } void FieldSpecificationBase::setMeshObjectPath( Group const & meshBodies ) diff --git a/src/coreComponents/fieldSpecification/FieldSpecificationBase.hpp b/src/coreComponents/fieldSpecification/FieldSpecificationBase.hpp index 91ff87d8a3a..1c83660448c 100644 --- a/src/coreComponents/fieldSpecification/FieldSpecificationBase.hpp +++ b/src/coreComponents/fieldSpecification/FieldSpecificationBase.hpp @@ -382,6 +382,8 @@ class FieldSpecificationBase : public dataRepository::Group constexpr static char const * constitutivePathString() { return "constitutivePath"; } /// @return The key for objectPath constexpr static char const * objectPathString() { return "objectPath"; } + /// @return The key for regionNames + constexpr static char const * regionNamesString() { return "regionNames"; } /// @return The key for fieldName constexpr static char const * fieldNameString() { return "fieldName"; } /// @return The key for dataType @@ -437,6 +439,15 @@ class FieldSpecificationBase : public dataRepository::Group return m_objectPath; } + /** + * Accessor + * @return const reference to m_regionNames + */ + string_array const & getRegionNames() const + { + return m_regionNames; + } + /** * Accessor * @return const reference to m_fieldName @@ -632,6 +643,9 @@ class FieldSpecificationBase : public dataRepository::Group std::unique_ptr< MeshObjectPath > m_meshObjectPaths; + /// the region names where the field specification is applied + string_array m_regionNames; + /// the name of the field the boundary condition is applied to or a key string to use for /// determining whether or not to apply the boundary condition. string m_fieldName; From 2dc1751b203d0aac4567856f4124706d4375c5d6 Mon Sep 17 00:00:00 2001 From: kdrienCG Date: Mon, 27 Apr 2026 10:18:59 +0200 Subject: [PATCH 05/23] add setRegionNames method --- .../fieldSpecification/FieldSpecificationBase.hpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/coreComponents/fieldSpecification/FieldSpecificationBase.hpp b/src/coreComponents/fieldSpecification/FieldSpecificationBase.hpp index 1c83660448c..e048c832992 100644 --- a/src/coreComponents/fieldSpecification/FieldSpecificationBase.hpp +++ b/src/coreComponents/fieldSpecification/FieldSpecificationBase.hpp @@ -548,6 +548,16 @@ class FieldSpecificationBase : public dataRepository::Group m_objectPath = objectPath; } + /** + * Mutator + * @param[in] regionNames The region names + */ + void setRegionNames( string_array const & regionNames ) + { + setObjectPath( "ElementRegions/{" + stringutilities::join( regionNames, ' ' ) + "}" ); + m_regionNames = regionNames; + } + /** * Mutator * @param[in] scale Scaling factor From d5fbc7fa592b37232812b8ed30e8c61a690df09d Mon Sep 17 00:00:00 2001 From: kdrienCG Date: Mon, 27 Apr 2026 15:01:09 +0200 Subject: [PATCH 06/23] fix typo in log message parameter --- .../fieldSpecification/FieldSpecificationBase.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreComponents/fieldSpecification/FieldSpecificationBase.cpp b/src/coreComponents/fieldSpecification/FieldSpecificationBase.cpp index 0892ca0072e..778f11e5102 100644 --- a/src/coreComponents/fieldSpecification/FieldSpecificationBase.cpp +++ b/src/coreComponents/fieldSpecification/FieldSpecificationBase.cpp @@ -135,7 +135,7 @@ void FieldSpecificationBase::postInputInitialization() m_functionNames.size() != static_cast< string_array::size_type >( m_scales.size() ), GEOS_FMT ( "Size mismatch: '{}' has {} entries but '{}' has {}. " "Either leave '{}' empty or size it exactly like '{}'", - viewKeyStruct::functionNameString(), m_functionNames.size(), + viewKeyStruct::functionNamesString(), m_functionNames.size(), viewKeyStruct::scalesString(), m_scales.size(), viewKeyStruct::functionNamesString(), viewKeyStruct::scalesString() ), InputError, From e7af0f54afba837877073950469a744cde0a5bfa Mon Sep 17 00:00:00 2001 From: kdrienCG Date: Tue, 28 Apr 2026 09:09:57 +0200 Subject: [PATCH 07/23] modify scales setter and getter --- .../fieldSpecification/FieldSpecificationBase.hpp | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/coreComponents/fieldSpecification/FieldSpecificationBase.hpp b/src/coreComponents/fieldSpecification/FieldSpecificationBase.hpp index e048c832992..565f19dbaff 100644 --- a/src/coreComponents/fieldSpecification/FieldSpecificationBase.hpp +++ b/src/coreComponents/fieldSpecification/FieldSpecificationBase.hpp @@ -525,9 +525,9 @@ class FieldSpecificationBase : public dataRepository::Group * Accessor * @return const m_scales */ - array1d< real64 > getScales() const + arrayView1d< real64 const > getScales() const { - return m_scales; + return m_scales.toViewConst(); } /** @@ -572,13 +572,9 @@ class FieldSpecificationBase : public dataRepository::Group * @brief Set the per-component scale factors * @param[in] scales The tensor-valued scale */ - void setScales( arrayView1d< real64 const > const & scales ) + void setScales( array1d< real64 > const & scales ) { - m_scales.resize( scales.size() ); - for( localIndex comp = 0; comp < scales.size(); ++comp ) - { - m_scales[ comp ] = scales[ comp ]; - } + m_scales = scales; } /** From 663a1682e68c2fd899297ef1c86a1a983ca0a5e3 Mon Sep 17 00:00:00 2001 From: kdrienCG Date: Tue, 28 Apr 2026 09:13:40 +0200 Subject: [PATCH 08/23] modify application methods to accept non-scalar field specifications --- .../FieldSpecificationBase.hpp | 213 +++++++++++++----- 1 file changed, 154 insertions(+), 59 deletions(-) diff --git a/src/coreComponents/fieldSpecification/FieldSpecificationBase.hpp b/src/coreComponents/fieldSpecification/FieldSpecificationBase.hpp index 565f19dbaff..64e0ee09e53 100644 --- a/src/coreComponents/fieldSpecification/FieldSpecificationBase.hpp +++ b/src/coreComponents/fieldSpecification/FieldSpecificationBase.hpp @@ -371,6 +371,25 @@ class FieldSpecificationBase : public dataRepository::Group arrayView1d< globalIndex const > const & dofMap, CRSMatrixView< real64, globalIndex const > const & matrix ) const; + /** + * + */ + template< typename FIELD_OP, typename POLICY, typename LAMBDA > + void + computeRhsContribution( integer const component, + real64 const scale, + string const & functionName, + SortedArrayView< localIndex const > const & targetSet, + real64 const time, + real64 const dt, + dataRepository::Group const & dataGroup, + arrayView1d< globalIndex const > const & dofMap, + globalIndex const dofRankOffset, + CRSMatrixView< real64, globalIndex const > const & matrix, + arrayView1d< globalIndex > const & dof, + arrayView1d< real64 > const & rhsContribution, + LAMBDA && lambda ) const; + /** * @brief View keys */ @@ -625,11 +644,29 @@ class FieldSpecificationBase : public dataRepository::Group /** * @brief Query whether this field specification uses non-scalar scales - * @return true if @p m_scales holds more than one entry */ bool isVectorMode() const { - return m_scales.size() > 1; + return !m_scales.empty(); + } + + template< typename LAMBDA > + void forEachComponent( LAMBDA && lambda ) const + { + if( isVectorMode() ) + { + localIndex const numComponents = m_scales.size(); + for( localIndex comp = 0; comp < numComponents; ++comp ) + { + string const & functionName = m_functionName.empty() ? string{} + : m_functionNames[ comp ]; + lambda( comp, m_scales[ comp ], functionName ); + } + } + else + { + lambda( getComponent(), m_scale, m_functionName ); + } } @@ -701,9 +738,9 @@ void FieldSpecificationBase::applyFieldValueKernel( ArrayView< T, N, USD > const { FunctionManager & functionManager = FunctionManager::getInstance(); - auto applyOneComponent = [&]( integer const component, - real64 const scale, - string const & functionName ) + forEachComponent( [&]( integer const component, + real64 const scale, + string const & functionName ) { if( functionName.empty() ) { @@ -755,21 +792,7 @@ void FieldSpecificationBase::applyFieldValueKernel( ArrayView< T, N, USD > const FIELD_OP::SpecifyFieldValue( field, a, component, localScale * resultView[i] ); } ); } - }; - - if( isVectorMode() ) - { - localIndex const numComponents = m_scales.size(); - for( localIndex c = 0; c < numComponents; ++c ) - { - string const & compFunctionName = m_functionNames.empty() ? string{} : m_functionNames[ c ]; - applyOneComponent( c, m_scales[ c ], compFunctionName ); - } - } - else - { - applyOneComponent( getComponent(), m_scale, m_functionName ); - } + } ); } @@ -805,13 +828,38 @@ void FieldSpecificationBase::applyBoundaryConditionToSystemKernel( SortedArrayVi arrayView1d< real64 > const & rhs, ArrayView< T const, NDIM, USD > const & fieldView ) const { - integer const component = getComponent(); - this->applyBoundaryConditionToSystem< FIELD_OP, POLICY >( targetSet, time, dataGroup, dofMap, dofRankOffset, matrix, rhs, - [fieldView, component] GEOS_HOST_DEVICE ( localIndex const a ) + forEachComponent( [&]( integer const component, + real64 const scale, + string const & functionName ) { - real64 value = 0.0; - FieldSpecificationEqual::readFieldValue( fieldView, a, component, value ); - return value; + integer const comp = ( component >= 0 ) ? component : 0; + + array1d< globalIndex > dofArray( targetSet.size() ); + arrayView1d< globalIndex > const & dof = dofArray.toView(); + + array1d< real64 > rhsContributionArray( targetSet.size() ); + arrayView1d< real64 > const & rhsContribution = rhsContributionArray.toView(); + + computeRhsContribution< FIELD_OP, POLICY >( comp, + scale, + functionName, + targetSet, + time, + 1.0, + dataGroup, + dofMap, + dofRankOffset, + matrix, + dof, + rhsContribution, + [fieldView, component] GEOS_HOST_DEVICE ( localIndex const a ) + { + real64 value = 0.0; + FieldSpecificationEqual::readFieldValue( fieldView, a, component, value ); + return value; + } ); + + FIELD_OP::template prescribeRhsValues< POLICY >( rhs, dof, dofRankOffset, rhsContribution ); } ); } @@ -881,30 +929,43 @@ FieldSpecificationBase:: arrayView1d< real64 > const & rhs, LAMBDA && lambda ) const { - array1d< globalIndex > dofArray( targetSet.size() ); - arrayView1d< globalIndex > const & dof = dofArray.toView(); - - array1d< real64 > rhsContributionArray( targetSet.size() ); - arrayView1d< real64 > const & rhsContribution = rhsContributionArray.toView(); - - computeRhsContribution< FIELD_OP, POLICY, LAMBDA >( targetSet, - time, - dt, - dataGroup, - dofMap, - dofRankOffset, - matrix, - dof, - rhsContribution, - std::forward< LAMBDA >( lambda ) ); - - FIELD_OP::template prescribeRhsValues< POLICY >( rhs, dof, dofRankOffset, rhsContribution ); + forEachComponent( [&]( integer const component, + real64 const scale, + string const & functionName ) + { + integer const comp = ( component >= 0 ) ? component : 0; + + array1d< globalIndex > dofArray( targetSet.size() ); + arrayView1d< globalIndex > const & dof = dofArray.toView(); + + array1d< real64 > rhsContributionArray( targetSet.size() ); + arrayView1d< real64 > const & rhsContribution = rhsContributionArray.toView(); + + computeRhsContribution< FIELD_OP, POLICY >( comp, + scale, + functionName, + targetSet, + time, + dt, + dataGroup, + dofMap, + dofRankOffset, + matrix, + dof, + rhsContribution, + lambda ); + + FIELD_OP::template prescribeRhsValues< POLICY >( rhs, dof, dofRankOffset, rhsContribution ); + } ); } template< typename FIELD_OP, typename POLICY, typename LAMBDA > void FieldSpecificationBase:: - computeRhsContribution( SortedArrayView< localIndex const > const & targetSet, + computeRhsContribution( integer const component, + real64 const scale, + string const & functionName, + SortedArrayView< localIndex const > const & targetSet, real64 const time, real64 const dt, dataRepository::Group const & dataGroup, @@ -915,8 +976,6 @@ FieldSpecificationBase:: arrayView1d< real64 > const & rhsContribution, LAMBDA && lambda ) const { - integer const component = ( getComponent() >=0 ) ? getComponent() : 0; - string const & functionName = getReference< string >( viewKeyStruct::functionNameString() ); FunctionManager & functionManager = FunctionManager::getInstance(); // Compute the value of the rhs terms, and collect the dof numbers @@ -924,7 +983,7 @@ FieldSpecificationBase:: if( functionName.empty() || functionManager.getGroup< FunctionBase >( functionName ).isFunctionOfTime() == 2 ) { - real64 value = m_scale * dt; + real64 value = scale * dt; if( !functionName.empty() ) { FunctionBase const & function = functionManager.getGroup< FunctionBase >( functionName ); @@ -951,7 +1010,7 @@ FieldSpecificationBase:: real64_array resultsArray( targetSet.size() ); function.evaluate( dataGroup, time, targetSet, resultsArray ); arrayView1d< real64 const > const & results = resultsArray.toViewConst(); - real64 const value = m_scale * dt; + real64 const value = scale * dt; forAll< POLICY >( targetSet.size(), [targetSet, dof, dofMap, dofRankOffset, component, matrix, rhsContribution, results, value, lambda] GEOS_HOST_DEVICE ( @@ -969,6 +1028,36 @@ FieldSpecificationBase:: } } +template< typename FIELD_OP, typename POLICY, typename LAMBDA > +void +FieldSpecificationBase:: + computeRhsContribution( SortedArrayView< localIndex const > const & targetSet, + real64 const time, + real64 const dt, + dataRepository::Group const & dataGroup, + arrayView1d< globalIndex const > const & dofMap, + globalIndex const dofRankOffset, + CRSMatrixView< real64, globalIndex const > const & matrix, + arrayView1d< globalIndex > const & dof, + arrayView1d< real64 > const & rhsContribution, + LAMBDA && lambda ) const +{ + computeRhsContribution< FIELD_OP, POLICY, LAMBDA >( ( getComponent() >= 0 ) ? getComponent() : 0, + m_scale, + m_functionName, + targetSet, + time, + dt, + dataGroup, + dofMap, + dofRankOffset, + matrix, + dof, + rhsContribution, + std::forward< LAMBDA >( lambda ) ); + +} + template< typename POLICY > void FieldSpecificationBase::zeroSystemRowsForBoundaryCondition( SortedArrayView< localIndex const > const & targetSet, @@ -976,19 +1065,25 @@ void FieldSpecificationBase::zeroSystemRowsForBoundaryCondition( SortedArrayView CRSMatrixView< real64, globalIndex const > const & matrix ) const { - integer const component = ( getComponent() >=0 ) ? getComponent() : 0; - forAll< POLICY >( targetSet.size(), [targetSet, dofMap, matrix, component] GEOS_HOST_DEVICE ( localIndex const i ) + forEachComponent( [&]( integer const component, + real64 const scale, + string const & functionName ) { - localIndex const a = targetSet[ i ]; - globalIndex const dof = dofMap[ a ] + component; + GEOS_UNUSED_VAR( scale, functionName ); + integer const comp = ( component >= 0 ) ? component : 0; + forAll< POLICY >( targetSet.size(), [targetSet, dofMap, matrix, component] GEOS_HOST_DEVICE ( localIndex const i ) + { + localIndex const a = targetSet[ i ]; + globalIndex const dof = dofMap[ a ] + component; - arraySlice1d< real64 > const entries = matrix.getEntries( dof ); - localIndex const numEntries = matrix.numNonZeros( dof ); + arraySlice1d< real64 > const entries = matrix.getEntries( dof ); + localIndex const numEntries = matrix.numNonZeros( dof ); - for( localIndex j = 0; j < numEntries; ++j ) - { - entries[ j ] = 0; - } + for( localIndex j = 0; j < numEntries; ++j ) + { + entries[ j ] = 0; + } + } ); } ); } From 7e4f6a5873e97a07084dcaec41b099897a8ce825 Mon Sep 17 00:00:00 2001 From: kdrienCG Date: Tue, 28 Apr 2026 09:15:15 +0200 Subject: [PATCH 09/23] move region names construction --- .../fieldSpecification/FieldSpecificationBase.cpp | 11 ++++++----- .../fieldSpecification/FieldSpecificationBase.hpp | 1 - 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/coreComponents/fieldSpecification/FieldSpecificationBase.cpp b/src/coreComponents/fieldSpecification/FieldSpecificationBase.cpp index 778f11e5102..ef6727998da 100644 --- a/src/coreComponents/fieldSpecification/FieldSpecificationBase.cpp +++ b/src/coreComponents/fieldSpecification/FieldSpecificationBase.cpp @@ -168,26 +168,27 @@ void FieldSpecificationBase::postInputInitialization() viewKeyStruct::regionNamesString() ), InputError, getDataContext() ); - - m_objectPath = "ElementRegions/{" + stringutilities::join( m_regionNames, ' ' ) + "}"; } } void FieldSpecificationBase::setMeshObjectPath( Group const & meshBodies ) { + string const path = m_regionNames.empty() + ? m_objectPath + : "ElementRegions/{" + stringutilities::join( m_regionNames, ' ' ) + "}"; try { - m_meshObjectPaths = std::make_unique< MeshObjectPath >( m_objectPath, meshBodies ); + m_meshObjectPaths = std::make_unique< MeshObjectPath >( path, meshBodies ); } catch( std::exception const & e ) { ErrorLogger::global().modifyCurrentExceptionMessage() .addToMsg( getWrapperDataContext( viewKeyStruct::objectPathString() ).toString() + - " is a wrong objectPath: " + m_objectPath + "\n" ) + " is a wrong objectPath: " + path + "\n" ) .addContextInfo( getWrapperDataContext( viewKeyStruct::objectPathString() ).getContextInfo() .setPriority( 2 ) ); throw InputError( e, getWrapperDataContext( viewKeyStruct::objectPathString() ).toString() + - " is a wrong objectPath: " + m_objectPath + "\n" ); + " is a wrong objectPath: " + path + "\n" ); } } diff --git a/src/coreComponents/fieldSpecification/FieldSpecificationBase.hpp b/src/coreComponents/fieldSpecification/FieldSpecificationBase.hpp index 64e0ee09e53..93d2d31a5bd 100644 --- a/src/coreComponents/fieldSpecification/FieldSpecificationBase.hpp +++ b/src/coreComponents/fieldSpecification/FieldSpecificationBase.hpp @@ -573,7 +573,6 @@ class FieldSpecificationBase : public dataRepository::Group */ void setRegionNames( string_array const & regionNames ) { - setObjectPath( "ElementRegions/{" + stringutilities::join( regionNames, ' ' ) + "}" ); m_regionNames = regionNames; } From 839d653feae725713f00aa15270e1bad4b32e276 Mon Sep 17 00:00:00 2001 From: kdrienCG Date: Tue, 28 Apr 2026 09:15:51 +0200 Subject: [PATCH 10/23] call FieldSpecification validations in subclasses --- .../fieldSpecification/AquiferBoundaryCondition.cpp | 2 ++ .../fieldSpecification/EquilibriumInitialCondition.cpp | 1 + src/coreComponents/fieldSpecification/PerfectlyMatchedLayer.cpp | 2 ++ .../fieldSpecification/TractionBoundaryCondition.cpp | 2 ++ 4 files changed, 7 insertions(+) diff --git a/src/coreComponents/fieldSpecification/AquiferBoundaryCondition.cpp b/src/coreComponents/fieldSpecification/AquiferBoundaryCondition.cpp index 4a9c99a7b2f..391171c0872 100644 --- a/src/coreComponents/fieldSpecification/AquiferBoundaryCondition.cpp +++ b/src/coreComponents/fieldSpecification/AquiferBoundaryCondition.cpp @@ -114,6 +114,8 @@ AquiferBoundaryCondition::AquiferBoundaryCondition( string const & name, Group * void AquiferBoundaryCondition::postInputInitialization() { + FieldSpecificationBase::postInputInitialization(); + GEOS_THROW_IF_LE_MSG( m_permeability, 0.0, "The aquifer permeability cannot be equal to zero or negative", InputError, getDataContext() ); diff --git a/src/coreComponents/fieldSpecification/EquilibriumInitialCondition.cpp b/src/coreComponents/fieldSpecification/EquilibriumInitialCondition.cpp index 6e0f1181e6e..21e12864c45 100644 --- a/src/coreComponents/fieldSpecification/EquilibriumInitialCondition.cpp +++ b/src/coreComponents/fieldSpecification/EquilibriumInitialCondition.cpp @@ -96,6 +96,7 @@ EquilibriumInitialCondition::EquilibriumInitialCondition( string const & name, G void EquilibriumInitialCondition::postInputInitialization() { + FieldSpecificationBase::postInputInitialization(); FunctionManager const & functionManager = FunctionManager::getInstance(); diff --git a/src/coreComponents/fieldSpecification/PerfectlyMatchedLayer.cpp b/src/coreComponents/fieldSpecification/PerfectlyMatchedLayer.cpp index 7e71480536c..ae56811c914 100644 --- a/src/coreComponents/fieldSpecification/PerfectlyMatchedLayer.cpp +++ b/src/coreComponents/fieldSpecification/PerfectlyMatchedLayer.cpp @@ -78,6 +78,8 @@ PerfectlyMatchedLayer::PerfectlyMatchedLayer( string const & name, Group * const void PerfectlyMatchedLayer::postInputInitialization() { + FieldSpecificationBase::postInputInitialization(); + GEOS_THROW_IF( (m_xMax[0]( getDirection() ) < 1e-20, From b0ae8d2fe99493b6928a406b5aab6b54c46f91cb Mon Sep 17 00:00:00 2001 From: kdrienCG Date: Tue, 28 Apr 2026 17:28:22 +0200 Subject: [PATCH 11/23] add doxygen comment for overloaded computeRhsContribution --- .../FieldSpecificationBase.hpp | 54 ++++++++++++++----- 1 file changed, 42 insertions(+), 12 deletions(-) diff --git a/src/coreComponents/fieldSpecification/FieldSpecificationBase.hpp b/src/coreComponents/fieldSpecification/FieldSpecificationBase.hpp index 93d2d31a5bd..5b4654ef812 100644 --- a/src/coreComponents/fieldSpecification/FieldSpecificationBase.hpp +++ b/src/coreComponents/fieldSpecification/FieldSpecificationBase.hpp @@ -355,24 +355,38 @@ class FieldSpecificationBase : public dataRepository::Group arrayView1d< real64 > const & rhsContribution, LAMBDA && lambda ) const; - /** - * @brief Function to zero matrix rows to apply boundary conditions - * @tparam POLICY the execution policy to use when zeroing rows + * @brief Compute the contributions that will be added/enforced to the right-hand side, + * and collect the corresponding dof numbers + * @tparam FIELD_OP A wrapper struct to define how the boundary condition operates on the variables. + * Either \ref OpEqual or \ref OpAdd. + * @tparam POLICY Execution policy to use when iterating over target set. + * @tparam LAMBDA The type of lambda function passed into the parameter list. + * @param[in] component The field component to apply the boundary condition to. + * @param[in] scale The scale factor to apply to the boundary condition value. + * @param[in] functionName The name of the function used to evaluate the boundary condition value. * @param[in] targetSet The set of indices which the boundary condition will be applied. + * @param[in] time The time at which any time dependent functions are to be evaluated as part of the + * application of the boundary condition. + * @param[in] dt time step size which is applied as a factor to bc values + * @param[in] dataGroup The Group that contains the field to apply the boundary condition to. * @param[in] dofMap The map from the local index of the primary field to the global degree of * freedom number. - * @param[inout] matrix the local system matrix + * @param[in] dofRankOffset Offset of dof indices on current rank. + * @param[inout] matrix Local part of the system matrix. + * @param[inout] dof array storing the degrees of freedom of the rhsContribution, to know where + * in the rhs they will be added/enforced + * @param[inout] rhsContribution array storing the values that will be added/enforced to the right-hand side + * @param[in] lambda A lambda function which defines how the value that is passed into the functions + * provided by the FIELD_OP templated type. * - * This function zeroes the rows of the matrix that correspond to boundary conditions. - */ - template< typename POLICY > - void zeroSystemRowsForBoundaryCondition( SortedArrayView< localIndex const > const & targetSet, - arrayView1d< globalIndex const > const & dofMap, - CRSMatrixView< real64, globalIndex const > const & matrix ) const; - - /** + * This overload behaves like the legacy computeRhsContribution, but takes the component, scale + * and functionName as explicit arguments rather than reading them from the corresponding members. + * This is the variant called when using non-scalar valued field specifications/boundary conditions, + * where each component is applied in turn. * + * Note that this function only computes the rhs contributions, but does not apply them to the right-hand side. + * The application of these rhs contributions is done in applyBoundaryConditionToSystem. */ template< typename FIELD_OP, typename POLICY, typename LAMBDA > void @@ -390,6 +404,22 @@ class FieldSpecificationBase : public dataRepository::Group arrayView1d< real64 > const & rhsContribution, LAMBDA && lambda ) const; + /** + * @brief Function to zero matrix rows to apply boundary conditions + * @tparam POLICY the execution policy to use when zeroing rows + * @param[in] targetSet The set of indices which the boundary condition will be applied. + * @param[in] dofMap The map from the local index of the primary field to the global degree of + * freedom number. + * @param[inout] matrix the local system matrix + * + * This function zeroes the rows of the matrix that correspond to boundary conditions. + */ + template< typename POLICY > + void zeroSystemRowsForBoundaryCondition( SortedArrayView< localIndex const > const & targetSet, + arrayView1d< globalIndex const > const & dofMap, + CRSMatrixView< real64, globalIndex const > const & matrix ) const; + + /** * @brief View keys */ From e073b5f75b8d346c89affb09c72bb129b19a7b12 Mon Sep 17 00:00:00 2001 From: kdrienCG Date: Thu, 30 Apr 2026 10:14:35 +0200 Subject: [PATCH 12/23] rename isVectorMode() to usesNonScalarValues() --- .../fieldSpecification/FieldSpecificationBase.cpp | 2 +- .../fieldSpecification/FieldSpecificationBase.hpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/coreComponents/fieldSpecification/FieldSpecificationBase.cpp b/src/coreComponents/fieldSpecification/FieldSpecificationBase.cpp index ef6727998da..8b11f0fdd44 100644 --- a/src/coreComponents/fieldSpecification/FieldSpecificationBase.cpp +++ b/src/coreComponents/fieldSpecification/FieldSpecificationBase.cpp @@ -141,7 +141,7 @@ void FieldSpecificationBase::postInputInitialization() InputError, getDataContext() ); - if( isVectorMode() ) + if( usesNonScalarValues() ) { GEOS_THROW_IF( m_component != -1, GEOS_FMT ( "'{}' must not be set when '{}' has more than one entry", diff --git a/src/coreComponents/fieldSpecification/FieldSpecificationBase.hpp b/src/coreComponents/fieldSpecification/FieldSpecificationBase.hpp index 5b4654ef812..75a49ccfe44 100644 --- a/src/coreComponents/fieldSpecification/FieldSpecificationBase.hpp +++ b/src/coreComponents/fieldSpecification/FieldSpecificationBase.hpp @@ -674,7 +674,7 @@ class FieldSpecificationBase : public dataRepository::Group /** * @brief Query whether this field specification uses non-scalar scales */ - bool isVectorMode() const + bool usesNonScalarValues() const { return !m_scales.empty(); } @@ -682,7 +682,7 @@ class FieldSpecificationBase : public dataRepository::Group template< typename LAMBDA > void forEachComponent( LAMBDA && lambda ) const { - if( isVectorMode() ) + if( usesNonScalarValues() ) { localIndex const numComponents = m_scales.size(); for( localIndex comp = 0; comp < numComponents; ++comp ) From 156ffc7466423f86d135f8944c4131f3ca7ece50 Mon Sep 17 00:00:00 2001 From: kdrienCG Date: Thu, 30 Apr 2026 10:32:35 +0200 Subject: [PATCH 13/23] add functionNames check to usesNonScalarValues() --- .../fieldSpecification/FieldSpecificationBase.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreComponents/fieldSpecification/FieldSpecificationBase.hpp b/src/coreComponents/fieldSpecification/FieldSpecificationBase.hpp index 75a49ccfe44..c0206a7b456 100644 --- a/src/coreComponents/fieldSpecification/FieldSpecificationBase.hpp +++ b/src/coreComponents/fieldSpecification/FieldSpecificationBase.hpp @@ -676,7 +676,7 @@ class FieldSpecificationBase : public dataRepository::Group */ bool usesNonScalarValues() const { - return !m_scales.empty(); + return !m_scales.empty() || !m_functionNames.empty(); } template< typename LAMBDA > From bfb53d540442d693d4cce42bf7cc617e06fd75fe Mon Sep 17 00:00:00 2001 From: kdrienCG Date: Thu, 30 Apr 2026 10:33:27 +0200 Subject: [PATCH 14/23] update warning messages when combining scalars and non-scalars --- .../fieldSpecification/FieldSpecificationBase.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/coreComponents/fieldSpecification/FieldSpecificationBase.cpp b/src/coreComponents/fieldSpecification/FieldSpecificationBase.cpp index 8b11f0fdd44..210defcd825 100644 --- a/src/coreComponents/fieldSpecification/FieldSpecificationBase.cpp +++ b/src/coreComponents/fieldSpecification/FieldSpecificationBase.cpp @@ -144,14 +144,14 @@ void FieldSpecificationBase::postInputInitialization() if( usesNonScalarValues() ) { GEOS_THROW_IF( m_component != -1, - GEOS_FMT ( "'{}' must not be set when '{}' has more than one entry", + GEOS_FMT ( "'{}' must not be set when '{}' is set.", viewKeyStruct::componentString(), viewKeyStruct::scalesString() ), InputError, getDataContext() ); GEOS_THROW_IF( !m_functionName.empty(), - GEOS_FMT ( "'{}' must not be set when '{}' has more than one entry. " + GEOS_FMT ( "'{}' must not be set when '{}' is set." "Use '{}' to provide one function per component instead", viewKeyStruct::functionNameString(), viewKeyStruct::scalesString(), @@ -163,7 +163,7 @@ void FieldSpecificationBase::postInputInitialization() if( !m_regionNames.empty() ) { GEOS_THROW_IF( !m_objectPath.empty(), - GEOS_FMT ( "'{}' must not be set when '{}' is set. ", + GEOS_FMT ( "'{}' must not be set when '{}' is set.", viewKeyStruct::objectPathString(), viewKeyStruct::regionNamesString() ), InputError, From d74a3d12f14a373843654975ce56d7ff51d46c96 Mon Sep 17 00:00:00 2001 From: kdrienCG Date: Thu, 30 Apr 2026 10:48:50 +0200 Subject: [PATCH 15/23] remove newline --- src/coreComponents/fieldSpecification/FieldSpecificationBase.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/coreComponents/fieldSpecification/FieldSpecificationBase.hpp b/src/coreComponents/fieldSpecification/FieldSpecificationBase.hpp index c0206a7b456..3ff274ada99 100644 --- a/src/coreComponents/fieldSpecification/FieldSpecificationBase.hpp +++ b/src/coreComponents/fieldSpecification/FieldSpecificationBase.hpp @@ -419,7 +419,6 @@ class FieldSpecificationBase : public dataRepository::Group arrayView1d< globalIndex const > const & dofMap, CRSMatrixView< real64, globalIndex const > const & matrix ) const; - /** * @brief View keys */ From f684f70884033f09007bdfc225fd4263a3a04c22 Mon Sep 17 00:00:00 2001 From: kdrienCG Date: Mon, 4 May 2026 09:06:25 +0200 Subject: [PATCH 16/23] fix wrong variable used --- .../fieldSpecification/FieldSpecificationBase.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/coreComponents/fieldSpecification/FieldSpecificationBase.hpp b/src/coreComponents/fieldSpecification/FieldSpecificationBase.hpp index 3ff274ada99..4078957660c 100644 --- a/src/coreComponents/fieldSpecification/FieldSpecificationBase.hpp +++ b/src/coreComponents/fieldSpecification/FieldSpecificationBase.hpp @@ -686,8 +686,8 @@ class FieldSpecificationBase : public dataRepository::Group localIndex const numComponents = m_scales.size(); for( localIndex comp = 0; comp < numComponents; ++comp ) { - string const & functionName = m_functionName.empty() ? string{} - : m_functionNames[ comp ]; + string const & functionName = m_functionNames.empty() ? string{} + : m_functionNames[ comp ]; lambda( comp, m_scales[ comp ], functionName ); } } From 28dbcff28949fa22a90926c647a05acf60c8d523 Mon Sep 17 00:00:00 2001 From: kdrienCG Date: Mon, 4 May 2026 09:47:55 +0200 Subject: [PATCH 17/23] add rst documentation --- .../docs/FieldSpecification.rst | 2 + .../docs/FieldSpecificationBase.rst | 81 +++++++++++++++++++ 2 files changed, 83 insertions(+) create mode 100644 src/coreComponents/fieldSpecification/docs/FieldSpecificationBase.rst diff --git a/src/coreComponents/fieldSpecification/docs/FieldSpecification.rst b/src/coreComponents/fieldSpecification/docs/FieldSpecification.rst index 7752ed84863..a609bdbcd44 100644 --- a/src/coreComponents/fieldSpecification/docs/FieldSpecification.rst +++ b/src/coreComponents/fieldSpecification/docs/FieldSpecification.rst @@ -6,6 +6,8 @@ Initial and Boundary Conditions .. toctree:: :maxdepth: 1 + FieldSpecificationBase + EquilibriumInitialCondition AquiferBoundaryCondition diff --git a/src/coreComponents/fieldSpecification/docs/FieldSpecificationBase.rst b/src/coreComponents/fieldSpecification/docs/FieldSpecificationBase.rst new file mode 100644 index 00000000000..e62e0893d3c --- /dev/null +++ b/src/coreComponents/fieldSpecification/docs/FieldSpecificationBase.rst @@ -0,0 +1,81 @@ +.. _FieldSpecificationBase: + +#################################################### +FieldSpecification Options +#################################################### + +Overview +====================== + +`FieldSpecification` entries live under the `FieldSpecifications` block and are used to define initial and boundary conditions for fields registered on mesh managers (nodes, faces, or element subregions). +This page documents options added for per-component values and region-based targeting. + +Region-based targetting +====================== + +Use `regionNames` to target one or more element regions without specifying an explicit `objectPath`. +When `regionNames` is provided, GEOS builds the `objectPath` internally and applies the specification to all regions. +You can also specify subregions in `regionNames` by using a syntax similar to the objectPath (cf. examples). + +.. note:: + `regionNames` and `objectPath` are mutually exclusive. Use one or the other. + +Non-scalar values +====================== + +Use `scales` and (optionally) `functionNames` to apply per-component values. + +- `scales` replaces `scale` when you want one value per component. +- `functionNames` is optional and must be empty or have the same size as `scales`. +- When `scales` is used, do not set `component` or `functionName`. + +For scalar fields, you can use `scale`, or `scales` with a single value. + +Examples +====================== + +The snippet below shows a specification using `scales` and `functionNames`. + +.. code-block:: xml + + + + + +The snippet below shows a specification using `regionNames` on a single region. + +.. code-block:: xml + + + + + +The snippet below shows a specification using `regionNames` on a multiple subregions. + +.. code-block:: xml + + + + \ No newline at end of file From 0ecdd93c044312ec772e8a397654d7d7289da61f Mon Sep 17 00:00:00 2001 From: kdrienCG Date: Mon, 4 May 2026 10:01:16 +0200 Subject: [PATCH 18/23] modify one inputFiles to use the new feature --- inputFiles/singlePhaseFlow/sourceFlux_2d.xml | 23 ++------------------ 1 file changed, 2 insertions(+), 21 deletions(-) diff --git a/inputFiles/singlePhaseFlow/sourceFlux_2d.xml b/inputFiles/singlePhaseFlow/sourceFlux_2d.xml index 4a0d5cf3a28..991417ed719 100644 --- a/inputFiles/singlePhaseFlow/sourceFlux_2d.xml +++ b/inputFiles/singlePhaseFlow/sourceFlux_2d.xml @@ -145,31 +145,12 @@ scale="5e6"/> - - - - + scales="{ 2.0e-22, 2.0e-22, 2.0e-22 }"/> Date: Mon, 4 May 2026 10:01:25 +0200 Subject: [PATCH 19/23] uncrustify --- .../fieldSpecification/TractionBoundaryCondition.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreComponents/fieldSpecification/TractionBoundaryCondition.cpp b/src/coreComponents/fieldSpecification/TractionBoundaryCondition.cpp index d7f4b75aa52..6724c861423 100644 --- a/src/coreComponents/fieldSpecification/TractionBoundaryCondition.cpp +++ b/src/coreComponents/fieldSpecification/TractionBoundaryCondition.cpp @@ -78,7 +78,7 @@ TractionBoundaryCondition::TractionBoundaryCondition( string const & name, Group void TractionBoundaryCondition::postInputInitialization() { FieldSpecificationBase::postInputInitialization(); - + if( m_tractionType == TractionType::vector ) { GEOS_ERROR_IF( LvArray::tensorOps::l2Norm< 3 >( getDirection() ) < 1e-20, From 27a5eb897249d2951dd04580a627c362e574c22b Mon Sep 17 00:00:00 2001 From: kdrienCG Date: Mon, 4 May 2026 10:04:30 +0200 Subject: [PATCH 20/23] remove unnecessary newline character in Wrapper doc --- .../fieldSpecification/FieldSpecificationBase.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/coreComponents/fieldSpecification/FieldSpecificationBase.cpp b/src/coreComponents/fieldSpecification/FieldSpecificationBase.cpp index 210defcd825..06ed3c8438a 100644 --- a/src/coreComponents/fieldSpecification/FieldSpecificationBase.cpp +++ b/src/coreComponents/fieldSpecification/FieldSpecificationBase.cpp @@ -73,7 +73,7 @@ FieldSpecificationBase::FieldSpecificationBase( string const & name, Group * par setInputFlag( InputFlags::OPTIONAL ). setSizedFromParent( 0 ). setDescription( "Names of per-component functions that specifies variation of the boundary condition.\n" - "Either left empty or sized exactly like 'scales'.\n" ); + "Either left empty or sized exactly like 'scales'." ); registerWrapper( viewKeyStruct::bcApplicationTableNameString(), &m_bcApplicationFunctionName ). setRTTypeName( rtTypes::CustomTypes::groupNameRef ). @@ -88,7 +88,7 @@ FieldSpecificationBase::FieldSpecificationBase( string const & name, Group * par registerWrapper( viewKeyStruct::scalesString(), &m_scales ). setInputFlag( InputFlags::OPTIONAL ). setSizedFromParent( 0 ). - setDescription( "Apply scaling factors for the values of every component of the boundary condition.\n" ); + setDescription( "Apply scaling factors for the values of every component of the boundary condition." ); registerWrapper( viewKeyStruct::initialConditionString(), &m_initialCondition ). setApplyDefaultValue( 0 ). From d766df1e87f54492af2512b1671244e346f831cd Mon Sep 17 00:00:00 2001 From: kdrienCG Date: Mon, 4 May 2026 10:10:27 +0200 Subject: [PATCH 21/23] add schema --- src/coreComponents/schema/schema.xsd | 49 ++++++++++++++++++++++ src/coreComponents/schema/schema.xsd.other | 4 +- 2 files changed, 51 insertions(+), 2 deletions(-) diff --git a/src/coreComponents/schema/schema.xsd b/src/coreComponents/schema/schema.xsd index 9a9bb51d843..580fd27ba05 100644 --- a/src/coreComponents/schema/schema.xsd +++ b/src/coreComponents/schema/schema.xsd @@ -1363,13 +1363,20 @@ When set to "error", output a throw. + + + + + + @@ -1405,12 +1412,19 @@ A field can represent a physical variable. (pressure, temperature, global compos + + + + + + @@ -1441,12 +1455,19 @@ A field can represent a physical variable. (pressure, temperature, global compos + + + + + + @@ -1483,6 +1504,9 @@ When set to "error", output a throw. + + @@ -1491,8 +1515,12 @@ When set to "error", output a throw. + + + + @@ -1518,12 +1546,19 @@ When set to "error", output a throw. + + + + + + @@ -1563,12 +1598,19 @@ When set to "error", output a throw. + + + + + + @@ -1593,6 +1635,9 @@ When set to "error", output a throw. + + @@ -1601,10 +1646,14 @@ When set to "error", output a throw. + + + + diff --git a/src/coreComponents/schema/schema.xsd.other b/src/coreComponents/schema/schema.xsd.other index c7434b7b99c..384d1e4a799 100644 --- a/src/coreComponents/schema/schema.xsd.other +++ b/src/coreComponents/schema/schema.xsd.other @@ -526,7 +526,7 @@ A field can represent a physical variable. (pressure, temperature, global compos - + @@ -1603,7 +1603,7 @@ A field can represent a physical variable. (pressure, temperature, global compos - + From 4c708e061f64beb295763626e3aea5727a56f1f5 Mon Sep 17 00:00:00 2001 From: kdrienCG Date: Mon, 4 May 2026 11:26:09 +0200 Subject: [PATCH 22/23] fix too short title underline --- .../fieldSpecification/docs/FieldSpecificationBase.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreComponents/fieldSpecification/docs/FieldSpecificationBase.rst b/src/coreComponents/fieldSpecification/docs/FieldSpecificationBase.rst index e62e0893d3c..2dfd21fdf45 100644 --- a/src/coreComponents/fieldSpecification/docs/FieldSpecificationBase.rst +++ b/src/coreComponents/fieldSpecification/docs/FieldSpecificationBase.rst @@ -11,7 +11,7 @@ Overview This page documents options added for per-component values and region-based targeting. Region-based targetting -====================== +=============================== Use `regionNames` to target one or more element regions without specifying an explicit `objectPath`. When `regionNames` is provided, GEOS builds the `objectPath` internally and applies the specification to all regions. From b0b3df93e5873a8f505b727358924a07bb6008bf Mon Sep 17 00:00:00 2001 From: kdrienCG Date: Mon, 4 May 2026 12:41:28 +0200 Subject: [PATCH 23/23] add doxygen documentation --- .../fieldSpecification/FieldSpecificationBase.hpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/coreComponents/fieldSpecification/FieldSpecificationBase.hpp b/src/coreComponents/fieldSpecification/FieldSpecificationBase.hpp index 4078957660c..53044d3a466 100644 --- a/src/coreComponents/fieldSpecification/FieldSpecificationBase.hpp +++ b/src/coreComponents/fieldSpecification/FieldSpecificationBase.hpp @@ -672,12 +672,19 @@ class FieldSpecificationBase : public dataRepository::Group /** * @brief Query whether this field specification uses non-scalar scales + * @return True if the field specification uses the non-scalar 'scales' attribute + * or the non-scalar 'functionNames' attribute */ bool usesNonScalarValues() const { return !m_scales.empty() || !m_functionNames.empty(); } + /** + * @brief Apply the lambda to each component of the field specification + * @tparam LAMBDA The type of lambda function passed into the parameter list. + * @param lambda The lambda being executed + */ template< typename LAMBDA > void forEachComponent( LAMBDA && lambda ) const {