Skip to content

Well manager#4064

Open
dkachuma wants to merge 12 commits into
feature/byer3/wm_wefrom
dkachuma/well-manager
Open

Well manager#4064
dkachuma wants to merge 12 commits into
feature/byer3/wm_wefrom
dkachuma/well-manager

Conversation

@dkachuma
Copy link
Copy Markdown
Contributor

@dkachuma dkachuma commented May 21, 2026

The purpose of this is mainly to avoid duplicating methods that are already defined in the dataRepository.

@dkachuma dkachuma self-assigned this May 22, 2026
Comment on lines -29 to -35
#include "physicsSolvers/fluidFlow/wells/WellInjectionConstraint.hpp"
#include "physicsSolvers/fluidFlow/wells/WellProductionConstraint.hpp"
#include "physicsSolvers/fluidFlow/wells/WellBHPConstraints.hpp"
#include "physicsSolvers/fluidFlow/wells/WellVolumeRateConstraint.hpp"
#include "physicsSolvers/fluidFlow/wells/WellPhaseVolumeRateConstraint.hpp"
#include "physicsSolvers/fluidFlow/wells/WellMassRateConstraint.hpp"
#include "physicsSolvers/fluidFlow/wells/WellLiquidRateConstraint.hpp"
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.

I have moved these includes to the .cpp files that require them. An attempt to improve compile times.

Comment on lines -388 to -494
/**@}*/
/**
* @brief Apply a given functor to a container if the container can be
* cast to one of the specified types.
* @tparam CASTTYPE the first type that will be used in the attempted casting of container
* @tparam CASTTYPES a variadic list of types that will be used in the attempted casting of container
* @tparam CONTAINERTYPE the type of container
* @tparam LAMBDA the type of lambda function to call in the function
* @param[in] container a pointer to the container which will be passed to the lambda function
* @param[in] lambda the lambda function to call in the function
* @return a boolean to indicate whether the lambda was successfully applied to the container.
*/
template< typename T0, typename T1, typename ... CASTTYPES, typename CONTAINERTYPE, typename LAMBDA >
static bool applyLambdaToContainer( CONTAINERTYPE container, LAMBDA && lambda )
{
using Pointee = std::remove_pointer_t< std::remove_reference_t< CONTAINERTYPE > >;
using T = std::conditional_t< std::is_const< Pointee >::value, T0 const, T0 >;
T * const castedContainer = dynamic_cast< T * >( container );

if( castedContainer != nullptr )
{
lambda( *castedContainer );
return true;
}

return applyLambdaToContainer< T1, CASTTYPES... >( container, std::forward< LAMBDA >( lambda ) );
}

// Base case: no more types to try
template< typename CONTAINERTYPE, typename LAMBDA >
static bool applyLambdaToContainer( CONTAINERTYPE /*container*/, LAMBDA && /*lambda*/ )
{
return false;
}

// Single-type overload: try only T0 and stop
template< typename T0, typename CONTAINERTYPE, typename LAMBDA >
static bool applyLambdaToContainer( CONTAINERTYPE container, LAMBDA && lambda )
{
using Pointee = std::remove_pointer_t< std::remove_reference_t< CONTAINERTYPE > >;
using T = std::conditional_t< std::is_const< Pointee >::value, T0 const, T0 >;
T * const castedContainer = dynamic_cast< T * >( container );

if( castedContainer != nullptr )
{
lambda( *castedContainer );
return true;
}

return false;
}


/**
* @copydoc forInjectionConstraints(LAMBDA &&)
*/
template< typename GROUPTYPE = Group, typename ... GROUPTYPES, typename LAMBDA >
void forInjectionConstraints( LAMBDA && lambda ) const
{
for( auto const * constraintIter : m_injectionRateConstraintList )
{
applyLambdaToContainer< GROUPTYPE, GROUPTYPES... >( constraintIter, [&]( auto const & castedSubGroup )
{
lambda( castedSubGroup );
} );
}
}

// non-const overload
template< typename GROUPTYPE = Group, typename ... GROUPTYPES, typename LAMBDA >
void forInjectionConstraints( LAMBDA && lambda )
{
for( auto * constraintIter : m_injectionRateConstraintList )
{
applyLambdaToContainer< GROUPTYPE, GROUPTYPES... >( constraintIter, [&]( auto & castedSubGroup )
{
lambda( castedSubGroup );
} );
}
}
/**
* @copydoc forProductionConstraints(LAMBDA &&)
*/
template< typename GROUPTYPE = Group, typename ... GROUPTYPES, typename LAMBDA >
void forProductionConstraints( LAMBDA && lambda ) const
{
for( auto const * constraintIter : m_productionRateConstraintList )
{
applyLambdaToContainer< GROUPTYPE, GROUPTYPES... >( constraintIter, [&]( auto const & castedSubGroup )
{
lambda( castedSubGroup );
} );
}
}

// non-const overload
template< typename GROUPTYPE = Group, typename ... GROUPTYPES, typename LAMBDA >
void forProductionConstraints( LAMBDA && lambda )
{
for( auto * constraintIter : m_productionRateConstraintList )
{
applyLambdaToContainer< GROUPTYPE, GROUPTYPES... >( constraintIter, [&]( auto & castedSubGroup )
{
lambda( castedSubGroup );
} );
}
}
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.

The main idea is not to repeat these methods which are already implemented by the dataRepository. We will leave those methods and simply use them here.

Comment on lines -842 to -859
/// string key for the minimum BHP presssure for a producer
static constexpr char const * minimumBHPConstraintString() { return "MinimumBHPConstraint"; }
/// string key for the maximum BHP presssure for a injection
static constexpr char const * maximumBHPConstraintString() { return "MaximumBHPConstraint"; }
/// string key for the maximum phase rate for a producer
static constexpr char const * productionPhaseVolumeRateConstraintString() { return "ProductionPhaseVolumeRateConstraint"; }
/// string key for the maximum phase rate for a injection
static constexpr char const * injectionPhaseVolumeRateConstraint() { return "InjectionPhaseVolumeRateConstraint"; }
/// string key for the maximum volume rate for a producer
static constexpr char const * productionVolumeRateConstraint() { return "ProductionVolumeRateConstraint"; }
/// string key for the maximum volume rate for a injector
static constexpr char const * injectionVolumeRateConstraint() { return "InjectionVolumeRateConstraint"; }
/// string key for the maximum mass rate for a producer
static constexpr char const * productionMassRateConstraint() { return "ProductionMassRateConstraint"; }
/// string key for the maximum mass rate for a injector
static constexpr char const * injectionMassRateConstraint() { return "InjectionMassRateConstraint"; }
/// string key for the liquid rate for a producer
static constexpr char const * productionLiquidRateConstraint() { return "ProductionLiquidRateConstraint"; }
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.

Each of these keys is defined by it's own class. So we don't need to repeat them here.

Comment on lines +746 to +750
struct groupKeyStruct
{
/// string key for the well Newton solver
static constexpr char const * wellNewtonSolverString() { return "WellNewtonSolver"; }
};
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.

I have split this out from the viewStruct just to highlight that this isn't an xml field but rather a subGroup.

std::vector< WellConstraintBase * > getInjRateConstraints() { return m_injectionRateConstraintList; }
std::vector< WellConstraintBase * > getInjRateConstraints() const { return m_injectionRateConstraintList; }
stdVector< WellConstraintBase const * > getAllConstraints() const;
stdVector< WellConstraintBase * > getAllConstraints();
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.

Here I am assuming that a well can only be a producer or an injector. So only constraints that apply to the type of well are relevant.

m_isProducer( wellControls.isProducer() ),
m_currentControl( wellControls.getControl() ),
m_constraintValue ( wellControls.getCurrentConstraint()->getConstraintValue( time )),
m_targetBHP( wellControls.getTargetBHP( time ) ),
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.

I'm enforcing the inclusion of a BHP constraint at all times. So this should always be defined. The decision of whether it's a producer or injector is in the WellControls already.

m_iwelemControl( subRegion.getTopWellElementIndex() ),
m_isProducer( wellControls.isProducer() ),
m_currentControl( wellControls.getControl() ),
m_targetBHP( wellControls.getTargetBHP( time ) ),
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.

I'm enforcing the inclusion of a BHP constraint at all times. So this should always be defined. The decision of whether it's a producer or injector is in the WellControls already.

Comment on lines +531 to +535
auto const * rateConstraint = wellControls.getRateConstraints().front();
if( rateConstraint != nullptr )
{
m_constraintValue = rateConstraint->getConstraintValue( time );
}
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.

This takes the first rate constraint regardless of whether that's mass, totalVolume or phaseVolume.

Comment on lines +572 to +575
else if( control == WellControls::Control::MASSRATE )
{
connRate[iwelem] = constraintVal;
}
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.

I added this here but I'm not sure if this is correct.

{

// create list of all constraints to process
std::vector< WellConstraintBase * > constraintList;
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.

I am quite confused by the procedure here. I can't tell what the difference between a limiting constraint and a current constraint is and how this interacts with the BHP constraint. I think in some cases we end up with the same constraint being added to the list twice.

@dkachuma dkachuma marked this pull request as ready for review May 22, 2026 17:01
@dkachuma dkachuma requested review from Copilot and removed request for OmarDuran and rrsettgast May 22, 2026 17:01
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR refactors well constraint creation and access to rely more on the dataRepository::Group catalog/subgroup mechanisms, reducing duplicated “manager” logic inside WellControls. It also centralizes reference-region validation and adds stronger constraint validation during input initialization.

Changes:

  • Replace bespoke constraint factory/list management in WellControls with catalog-based createChild() and subgroup iteration helpers (getBHPConstraint(), getRateConstraints(), getAllConstraints()).
  • Add input-time validation for constraint consistency (producer vs injector constraints, duplicates, and required presence of BHP + at least one rate constraint).
  • Centralize reference-reservoir-region checks and statistics retrieval via WellControls helpers, used by both single-phase and compositional wells.

Reviewed changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
src/coreComponents/physicsSolvers/fluidFlow/wells/WellInjectionConstraint.cpp Adjusts catalog registration/instantiation for injection constraints (liquid-rate registration currently commented out).
src/coreComponents/physicsSolvers/fluidFlow/wells/WellControls.hpp Removes constraint header includes, adds forward decls and new constraint accessors/validation helpers; minor include cleanup needed.
src/coreComponents/physicsSolvers/fluidFlow/wells/WellControls.cpp Moves constraint includes to .cpp; implements catalog-based child creation, constraint validation, logging helper, and reference-region validation/statistics helpers.
src/coreComponents/physicsSolvers/fluidFlow/wells/WellConstraintsBase.hpp Makes setNextDtFromTables const and setNextDtFromTable static for safer use via const pointers.
src/coreComponents/physicsSolvers/fluidFlow/wells/WellConstraintsBase.cpp Updates implementations to match const/static signature changes.
src/coreComponents/physicsSolvers/fluidFlow/wells/SinglePhaseWell.cpp Uses centralized reference-region statistics validation instead of duplicating logic.
src/coreComponents/physicsSolvers/fluidFlow/wells/kernels/ThermalSinglePhaseWellKernels.hpp Switches BHP target normalization to use WellControls::getTargetBHP().
src/coreComponents/physicsSolvers/fluidFlow/wells/kernels/ThermalCompositionalMultiphaseWellKernels.hpp Uses getTargetBHP() and rate-constraint accessor for normalization.
src/coreComponents/physicsSolvers/fluidFlow/wells/kernels/SinglePhaseWellKernels.hpp Uses getTargetBHP() for normalization.
src/coreComponents/physicsSolvers/fluidFlow/wells/kernels/SinglePhaseWellKernels.cpp Uses new rate-constraint accessor and adds explicit MASSRATE handling in rate initialization.
src/coreComponents/physicsSolvers/fluidFlow/wells/kernels/CompositionalMultiphaseWellKernels.hpp Uses getTargetBHP() and rate-constraint accessor for normalization.
src/coreComponents/physicsSolvers/fluidFlow/wells/kernels/CompositionalMultiphaseWellKernels.cpp Uses new rate-constraint accessor for rate initialization.
src/coreComponents/physicsSolvers/fluidFlow/wells/CompositionalMultiphaseWell.cpp Removes duplicated reference-region validation/statistics logic in favor of WellControls helpers.

Comment on lines 23 to 31
#include "physicsSolvers/PhysicsSolverBase.hpp"
#include "common/format/EnumStrings.hpp"
#include "dataRepository/Group.hpp"
#include "functions/TableFunction.hpp"
#include "constitutive/fluid/multifluid/MultiFluidBase.hpp"

#include "physicsSolvers/fluidFlow/wells/WellInjectionConstraint.hpp"
#include "physicsSolvers/fluidFlow/wells/WellProductionConstraint.hpp"
#include "physicsSolvers/fluidFlow/wells/WellBHPConstraints.hpp"
#include "physicsSolvers/fluidFlow/wells/WellVolumeRateConstraint.hpp"
#include "physicsSolvers/fluidFlow/wells/WellPhaseVolumeRateConstraint.hpp"
#include "physicsSolvers/fluidFlow/wells/WellMassRateConstraint.hpp"
#include "physicsSolvers/fluidFlow/wells/WellLiquidRateConstraint.hpp"
#include "constitutive/fluid/multifluid/MultiFluidBase.hpp"
#include "constitutive/fluid/singlefluid/SingleFluidBase.hpp"
#include "physicsSolvers/fluidFlow/wells/WellNewtonSolver.hpp"
child = &liquidConstraint;
}
return child;
GEOS_LOG_RANK_0( GEOS_FMT( "{}: adding {} {}", getName(), childKey, childName ) );
Comment thread src/coreComponents/physicsSolvers/fluidFlow/wells/WellControls.cpp Outdated
Comment thread src/coreComponents/physicsSolvers/fluidFlow/wells/WellControls.cpp Outdated
dkachuma and others added 2 commits May 22, 2026 12:08
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants