Proposed structure for coupled solvers #1631
Replies: 2 comments 9 replies
-
Is it scientifically possible to deal with solvers agnostically like private:
std::list< Solver * > m_solvers; instead of private:
FLOW_SOLVER * m_flow;
SOLID_SOLVER * m_mech;
CONTACT_SOLVER * m_contact;
THERMAL_SOLVER * m_thermal; Or does that make no sense? Another flavor: is it possible to rely on private:
FlowSolver * m_flow;
SolidSolver * m_mech;
ContactSolver * m_contact;
ThermalSolver * m_thermal; If so, that would surely help understanding what we want for a these |
Beta Was this translation helpful? Give feedback.
-
(Q to everyone) What are the pros and cons vs an even more generic definition template< typename ... SOLVERS >
class CoupledSolver
{
private:
std::tuple< SOLVERS ... * > m_solvers;
} The one major drawback I can think of is having to re-define the ordering in every derived coupled solver: class SinglePhaseSolidMechanicsLagrangeContact : public CoupledSolver< SinglePhaseFlow,
SolidMechanics,
LagrangeContact >
{
enum SolverTypes
{
Flow,
Mechanics,
Contact
};
...
void foo()
{
getSolver< Mechanics >()->foo();
// instead of m_mech->foo();
}
} On the plus side, generic for-loop over tuple elements is a solved problem. This will come up a lot when calling operations on sub-solvers. We can still do it with the original definition: template< typename LAMBDA >
void forEachSolver( LAMBDA && lambda ) const
{
std::tuple< ... > solvers { m_flow, m_mech, m_contact, m_thermal }; // must be modified for each pointer added
for_each_element( solvers, [lambda = std::forward< LAMBDA >( lambda )] ( auto * solver )
{
lambda( solver );
} );
} But now think about e.g. printing the nonlinear residuals for each solver. We don't want to see them printed for null solvers. So we'll have to work around it: forEachSolver( []( auto * solver )
{
real64 const norm = solver->calculateResidualNorm(); // can be outside the branch, since it's a no-op for NullSolver
if( !std::is_same( TYPEOFPTR( solver ), NullSolver )
{
GEOSX_LOG_RANK0( GEOSX_FMT( "R[{}] = {}" ), solver->getName(), norm ) );
}
} ); All in all, this just leaves a slightly sour taste (but I'll admit there's no perfect solution here in any case). Moreover, |
Beta Was this translation helpful? Give feedback.
-
The expanding number of coupled solvers warrants a pause to consider how we would like to handle the relationship between coupled solvers and single physics solvers. In case it is not clear, there are quite a few coupled solvers now with varying levels of coupling between different components (e.g. FlowProppantTransportSolver, HydrofractureSolver, LagrangianContactSolver, MultiphasePoromechanicsSolver, PhaseFieldFractureSolver, SinglePhasePoromechanicsEFEMKernel, SinglePhasePoromechanicsSolver, etc.)
Some of these use composition, some use inheritance, some use a combination of composition and inheritance. In short, it is kind of a free-for-all. Now that we have several good use cases to drive design, time has come to enforce a structured design. We propose the following:
Propose composition/inheritance rules for physics solvers:
SolverBase
). No inheritance...more on thisGeneric Templated Coupled solvers (GTCS). We define a generic coupled solver structure
The goal is to provide a truly generic coupled solver strategy for tying different single physics components together...or even multiple coupled physics components. For instance a tight coupling may warrant a tight coupling and custom kernels be created, and reused by other coupled solvers that are composed of the tight coupled solver.
There are implications for clean/strict interfaces for solver classes in general. We should keep a tighter grip on public/protected/private interfaces.
Introduction of a
NullSolver
to avoid GTCS definitions for different numbers of component types.NullSolver
will just be a no-op for all interface functions.Inheritance specialization mechanism for GTCS. There will be cases where the generic class will work, but may not take advantages of fusing redundant kernel operations into a single algorithm. In cases like this we may specialize the GTCS
In the specialized solver, we can call custom kernels, or make whatever optimizations that we would like. This retains the generic capability while giving the opportunity for specialized improvements.
The good news is we can try something like this out and not break anything.
@CusiniM @klevzoff @corbett5 @castelletto1 @TotoGaz @joshua-white
Beta Was this translation helpful? Give feedback.
All reactions