LCOV - code coverage report
Current view: top level - include/systems - diff_system.h (source / functions) Hit Total Coverage
Test: libMesh/libmesh: #4229 (6a9aeb) with base 727f46 Lines: 25 30 83.3 %
Date: 2025-08-19 19:27:09 Functions: 9 14 64.3 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // The libMesh Finite Element Library.
       2             : // Copyright (C) 2002-2025 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
       3             : 
       4             : // This library is free software; you can redistribute it and/or
       5             : // modify it under the terms of the GNU Lesser General Public
       6             : // License as published by the Free Software Foundation; either
       7             : // version 2.1 of the License, or (at your option) any later version.
       8             : 
       9             : // This library is distributed in the hope that it will be useful,
      10             : // but WITHOUT ANY WARRANTY; without even the implied warranty of
      11             : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      12             : // Lesser General Public License for more details.
      13             : 
      14             : // You should have received a copy of the GNU Lesser General Public
      15             : // License along with this library; if not, write to the Free Software
      16             : // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
      17             : 
      18             : 
      19             : 
      20             : #ifndef LIBMESH_DIFF_SYSTEM_H
      21             : #define LIBMESH_DIFF_SYSTEM_H
      22             : 
      23             : // Local Includes
      24             : #include "libmesh/diff_context.h"
      25             : #include "libmesh/diff_physics.h"
      26             : #include "libmesh/diff_qoi.h"
      27             : #include "libmesh/implicit_system.h"
      28             : #include "libmesh/time_solver.h"
      29             : 
      30             : // C++ includes
      31             : #include <memory>
      32             : #include <stack>
      33             : 
      34             : namespace libMesh
      35             : {
      36             : 
      37             : // Forward Declarations
      38             : class TimeSolver;
      39             : 
      40             : template <typename T> class NumericVector;
      41             : 
      42             : /**
      43             :  * This class provides a specific system class.  It aims
      44             :  * to generalize any system, linear or nonlinear, which
      45             :  * provides both a residual and a Jacobian.
      46             :  *
      47             :  * This class is part of the new DifferentiableSystem framework,
      48             :  * which is still experimental.  Users of this framework should
      49             :  * beware of bugs and future API changes.
      50             :  *
      51             :  * \author Roy H. Stogner
      52             :  * \date 2006
      53             :  */
      54         450 : class DifferentiableSystem : public ImplicitSystem,
      55             :                              public virtual DifferentiablePhysics,
      56             :                              public virtual DifferentiableQoI
      57             : {
      58             : public:
      59             : 
      60             :   /**
      61             :    * Constructor.
      62             :    */
      63             :   DifferentiableSystem (EquationSystems & es,
      64             :                         const std::string & name,
      65             :                         const unsigned int number);
      66             : 
      67             :   /**
      68             :    * Special functions.
      69             :    * - This class has the same restrictions as its base class.
      70             :    * - The destructor is defaulted out-of-line.
      71             :    */
      72             :   DifferentiableSystem (const DifferentiableSystem &) = delete;
      73             :   DifferentiableSystem & operator= (const DifferentiableSystem &) = delete;
      74             :   DifferentiableSystem (DifferentiableSystem &&) = default;
      75             :   DifferentiableSystem & operator= (DifferentiableSystem &&) = delete;
      76             :   virtual ~DifferentiableSystem ();
      77             : 
      78             :   /**
      79             :    * The type of system.
      80             :    */
      81             :   typedef DifferentiableSystem sys_type;
      82             : 
      83             :   /**
      84             :    * The type of the parent.
      85             :    */
      86             :   typedef ImplicitSystem Parent;
      87             : 
      88             :   /**
      89             :    * Clear all the data structures associated with
      90             :    * the system.
      91             :    */
      92             :   virtual void clear () override;
      93             : 
      94             :   /**
      95             :    * Reinitializes the member data fields associated with
      96             :    * the system, so that, e.g., \p assemble() may be used.
      97             :    */
      98             :   virtual void reinit () override;
      99             : 
     100             :   /**
     101             :    * Prepares \p matrix and \p rhs for matrix assembly.
     102             :    * Users should not reimplement this.
     103             :    * Note that in some cases only
     104             :    * \link current_local_solution \endlink is used during assembly,
     105             :    * and, therefore, if \link solution \endlink has been altered
     106             :    * without \link update() \endlink being called, then the
     107             :    * user must call \link update() \endlink before calling
     108             :    * this function.
     109             :    */
     110             :   virtual void assemble () override;
     111             : 
     112             :   /**
     113             :    * \returns A pointer to a linear solver appropriate for use in
     114             :    * adjoint and/or sensitivity solves
     115             :    */
     116             :   virtual LinearSolver<Number> * get_linear_solver() const override;
     117             : 
     118             :   /**
     119             :    * \returns An integer corresponding to the upper iteration count
     120             :    * limit and a Real corresponding to the convergence tolerance to
     121             :    * be used in linear adjoint and/or sensitivity solves
     122             :    */
     123             :   virtual std::pair<unsigned int, Real>
     124             :   get_linear_solve_parameters() const override;
     125             : 
     126             :   /**
     127             :    * Assembles a residual in \p rhs and/or a jacobian in \p matrix,
     128             :    * as requested.
     129             :    * Note that in some cases only
     130             :    * \link current_local_solution \endlink is used during assembly,
     131             :    * and, therefore, if \link solution \endlink has been altered
     132             :    * without \link update() \endlink being called, then the
     133             :    * user must call \link update() \endlink before calling
     134             :    * this function.
     135             :    */
     136             :   virtual void assembly (bool get_residual,
     137             :                          bool get_jacobian,
     138             :                          bool apply_heterogeneous_constraints = false,
     139             :                          bool apply_no_constraints = false) override = 0;
     140             : 
     141             :   /**
     142             :    * Invokes the solver associated with the system.  For steady state
     143             :    * solvers, this will find a root x where F(x) = 0.  For transient
     144             :    * solvers, this will integrate dx/dt = F(x).
     145             :    */
     146             :   virtual void solve () override;
     147             : 
     148             :   /**
     149             :    * This function sets the _is_adjoint boolean member of TimeSolver to
     150             :    * true and then calls the adjoint_solve in implicit system
     151             :    */
     152             :   virtual std::pair<unsigned int, Real>
     153             :   adjoint_solve (const QoISet & qoi_indices = QoISet()) override;
     154             : 
     155             :   /**
     156             :    * We don't allow systems to be attached to each other
     157             :    */
     158           0 :   virtual std::unique_ptr<DifferentiablePhysics> clone_physics() override
     159             :   {
     160           0 :     libmesh_not_implemented();
     161             :     // dummy to avoid compiler warnings, not a real implementation
     162             :     return std::unique_ptr<DifferentiablePhysics>(nullptr);
     163             :   }
     164             : 
     165             :   /**
     166             :    * We don't allow systems to be attached to each other
     167             :    */
     168           0 :   virtual std::unique_ptr<DifferentiableQoI> clone() override
     169             :   {
     170           0 :     libmesh_not_implemented();
     171             :     // dummy to avoid compiler warnings, not a real implementation
     172             :     return std::unique_ptr<DifferentiableQoI>(nullptr);
     173             :   }
     174             : 
     175             :   /**
     176             :    * \returns A const reference to a DifferentiablePhysics object.
     177             :    *
     178             :    * \note If no external Physics objects have been attached, the default is
     179             :    * \p this.
     180             :    */
     181     7569832 :   const DifferentiablePhysics * get_physics() const
     182    84593108 :   { if (this->_diff_physics.empty())
     183    84449492 :       return this;
     184      130560 :     return this->_diff_physics.top().get(); }
     185             : 
     186             :   /**
     187             :    * \returns A reference to a DifferentiablePhysics object.
     188             :    *
     189             :    * \note If no external Physics object is attached, the default is
     190             :    * \p this.
     191             :    */
     192     9444366 :   DifferentiablePhysics * get_physics()
     193   104827488 :   { if (this->_diff_physics.empty())
     194   104326176 :       return this;
     195      461184 :     return this->_diff_physics.top().get(); }
     196             : 
     197             :   /**
     198             :    * Attach external Physics object.
     199             :    */
     200             :   void attach_physics( DifferentiablePhysics * physics_in )
     201             :   { this->_diff_physics.push(physics_in->clone_physics());
     202             :     this->_diff_physics.top()->init_physics(*this);}
     203             : 
     204             : #ifdef LIBMESH_ENABLE_DEPRECATED
     205             :   /**
     206             :    * Swap current physics object with external object.  This is
     207             :    * \deprecated for being too unsafe for easy use.
     208             :    */
     209             :   void swap_physics ( DifferentiablePhysics * & swap_physics );
     210             : #endif // LIBMESH_ENABLE_DEPRECATED
     211             : 
     212             :   /**
     213             :    * Push a clone of a new physics object onto our stack, overriding
     214             :    * the current physics until the new physics is popped off again (or
     215             :    * until something else is pushed on top of it).
     216             :    */
     217             :   void push_physics ( DifferentiablePhysics & new_physics );
     218             : 
     219             :   /**
     220             :    * Pop a physics object off of our stack.
     221             :    */
     222             :   void pop_physics ();
     223             : 
     224             :   /**
     225             :    * \returns A const reference to a DifferentiableQoI object.
     226             :    *
     227             :    * \note If no external QoI object is attached, the default is \p this.
     228             :    */
     229             :   const DifferentiableQoI * get_qoi() const
     230             :   { if (this->_diff_qoi.empty())
     231             :       return this;
     232             :     return this->_diff_qoi.top().get(); }
     233             : 
     234             :   /**
     235             :    * \returns A reference to a DifferentiableQoI object.
     236             :    *
     237             :    * \note If no external QoI object is attached, the default is this.
     238             :    */
     239        3500 :   DifferentiableQoI * get_qoi()
     240      117781 :   { if (this->_diff_qoi.empty())
     241      111981 :       return this;
     242        5636 :     return this->_diff_qoi.top().get(); }
     243             : 
     244             :   /**
     245             :    * Attach external QoI object.
     246             :    */
     247             :   void attach_qoi( DifferentiableQoI * qoi_in );
     248             : 
     249             :   /**
     250             :    * A pointer to the solver object we're going to use.
     251             :    * This must be instantiated by the user before solving!
     252             :    */
     253             :   std::unique_ptr<TimeSolver> time_solver;
     254             : 
     255             :   /**
     256             :    * Sets the time_solver
     257             :    * FIXME: This code is a little dangerous as it transfers ownership
     258             :    * from the TimeSolver creator to this class.  The user must no longer
     259             :    * access his original TimeSolver object after calling this function.
     260             :    */
     261             :   void set_time_solver(std::unique_ptr<TimeSolver> _time_solver)
     262             :   {
     263             :     time_solver.reset(_time_solver.release());
     264             :   }
     265             : 
     266             :   /**
     267             :    * \returns A pointer to the time solver attached to the calling system
     268             :    */
     269             :   TimeSolver & get_time_solver();
     270             : 
     271             :   /**
     272             :    * Non-const version of the above
     273             :    */
     274             :   const TimeSolver & get_time_solver() const;
     275             : 
     276             :   /**
     277             :    * For time-dependent problems, this is the amount delta t to advance the
     278             :    * solution in time.
     279             :    */
     280             :   Real deltat;
     281             : 
     282             :   /**
     283             :    * Builds a DiffContext object with enough information to do
     284             :    * evaluations on each element.
     285             :    *
     286             :    * For most problems, the default "Let FEMSystem build an * FEMContext"
     287             :    * reimplementation is correct; users who subclass FEMContext will need to
     288             :    * also reimplement this method to build it.
     289             :    */
     290             :   virtual std::unique_ptr<DiffContext> build_context();
     291             : 
     292             :   /**
     293             :    * Executes a postprocessing loop over all elements, and if
     294             :    * \p postprocess_sides is true over all sides.
     295             :    */
     296           0 :   virtual void postprocess () {}
     297             : 
     298             :   /**
     299             :    * Does any work that needs to be done on \p elem in a postprocessing loop.
     300             :    */
     301       20482 :   virtual void element_postprocess (DiffContext &) {}
     302             : 
     303             :   /**
     304             :    * Does any work that needs to be done on \p side of \p elem in a
     305             :    * postprocessing loop.
     306             :    */
     307        1232 :   virtual void side_postprocess (DiffContext &) {}
     308             : 
     309             :   /**
     310             :    * For a given second order (in time) variable var, this method will return
     311             :    * the index to the corresponding "dot" variable. For FirstOrderUnsteadySolver
     312             :    * classes, the "dot" variable would automatically be added and the returned
     313             :    * index will correspond to that variable. For SecondOrderUnsteadySolver classes,
     314             :    * this method will return var as there this is no "dot" variable per se, but
     315             :    * having this function allows one to use the interface to treat both
     316             :    * FirstOrderUnsteadySolver and SecondOrderUnsteadySolver simultaneously.
     317             :    */
     318             :   unsigned int get_second_order_dot_var( unsigned int var ) const;
     319             : 
     320             :   /**
     321             :    * Check for any first order vars that are also belong to FEFamily::SCALAR
     322             :    */
     323             :   bool have_first_order_scalar_vars() const;
     324             : 
     325             :   /**
     326             :    * Check for any second order vars that are also belong to FEFamily::SCALAR
     327             :    */
     328             :   bool have_second_order_scalar_vars() const;
     329             : 
     330             :   /**
     331             :    * If \p postprocess_sides is true (it is false by default), the
     332             :    * postprocessing loop will loop over all sides as well as all elements.
     333             :    */
     334             :   bool postprocess_sides;
     335             : 
     336             :   /**
     337             :    * Set print_residual_norms to true to print |U| whenever it is
     338             :    * used in an assembly() call
     339             :    */
     340             :   bool print_solution_norms;
     341             : 
     342             :   /**
     343             :    * Set print_solutions to true to print U whenever it is used in an
     344             :    * assembly() call
     345             :    */
     346             :   bool print_solutions;
     347             : 
     348             :   /**
     349             :    * Set print_residual_norms to true to print |F| whenever it is assembled.
     350             :    */
     351             :   bool print_residual_norms;
     352             : 
     353             :   /**
     354             :    * Set print_residuals to true to print F whenever it is assembled.
     355             :    */
     356             :   bool print_residuals;
     357             : 
     358             :   /**
     359             :    * Set print_jacobian_norms to true to print |J| whenever it is assembled.
     360             :    */
     361             :   bool print_jacobian_norms;
     362             : 
     363             :   /**
     364             :    * Set print_jacobians to true to print J whenever it is assembled.
     365             :    */
     366             :   bool print_jacobians;
     367             : 
     368             :   /**
     369             :    * Set print_element_solutions to true to print each U_elem input.
     370             :    */
     371             :   bool print_element_solutions;
     372             : 
     373             :   /**
     374             :    * Set print_element_residuals to true to print each R_elem contribution.
     375             :    */
     376             :   bool print_element_residuals;
     377             : 
     378             :   /**
     379             :    * Set print_element_jacobians to true to print each J_elem contribution.
     380             :    */
     381             :   bool print_element_jacobians;
     382             : 
     383             :   /**
     384             :    * set_constrain_in_solver to false to apply constraints only via
     385             :    * residual terms in the systems to be solved.
     386             :    */
     387             :   virtual void set_constrain_in_solver(bool enable);
     388             : 
     389    19155839 :   virtual bool get_constrain_in_solver()
     390             :   {
     391    19155839 :     return _constrain_in_solver;
     392             :   }
     393             : 
     394             : protected:
     395             : 
     396             :   /**
     397             :    * Initializes the member data fields associated with
     398             :    * the system, so that, e.g., \p assemble() may be used.
     399             :    *
     400             :    * If the TimeSolver is a FirstOrderUnsteadySolver,
     401             :    * we check for second order in time variables and then add them
     402             :    * to the System as dot_<varname>. Then, during assembly, the
     403             :    * TimeSolver will populate the elem_accel vectors with the
     404             :    * dot_<varname> values so the user's element assembly function
     405             :    * can still treat the variable as a second order in time variable.
     406             :    */
     407             :   virtual void init_data () override;
     408             : 
     409             :   /**
     410             :    * Helper function to add "velocity" variables that are cousins to
     411             :    * second order-in-time variables in the DifferentiableSystem. This
     412             :    * function is only called if the TimeSolver is a FirstOrderUnsteadySolver.
     413             :    */
     414             :   void add_second_order_dot_vars();
     415             : 
     416             : #ifdef LIBMESH_ENABLE_DIRICHLET
     417             :   /**
     418             :    * Helper function to and Dirichlet boundary conditions to "dot" variable
     419             :    * cousins of second order variables in the system. The function takes the
     420             :    * second order variable index, it's corresponding "dot" variable index and
     421             :    * then searches for DirichletBoundary objects for var_idx and then adds a
     422             :    * DirichletBoundary object for dot_var_idx using the same boundary ids and
     423             :    * functors for the var_idx DirichletBoundary.
     424             :    */
     425             :   void add_dot_var_dirichlet_bcs( unsigned int var_idx, unsigned int dot_var_idx);
     426             : #endif
     427             : 
     428             :   /**
     429             :    * _constrain_in_solver defaults to true; if false then we apply
     430             :    * constraints only via residual terms in the systems to be solved.
     431             :    */
     432             :   bool _constrain_in_solver;
     433             : 
     434             : private:
     435             :   /**
     436             :    * Stack of pointers to objects to use for physics assembly
     437             :    * evaluations.  Physics assembly defaults to \p this for backwards
     438             :    * compatibility if the stack is empty; for the most flexibility
     439             :    * users should create separate physics objects.
     440             :    */
     441             :   std::stack<std::unique_ptr<DifferentiablePhysics>,
     442             :     std::vector<std::unique_ptr<DifferentiablePhysics>>> _diff_physics;
     443             : 
     444             :   /**
     445             :    * Pointer to object to use for quantity of interest assembly
     446             :    * evaluations.  Defaults to \p this for backwards compatibility; in
     447             :    * the future users should create separate physics objects.
     448             :    */
     449             :   std::stack<std::unique_ptr<DifferentiableQoI>,
     450             :     std::vector<std::unique_ptr<DifferentiableQoI>>> _diff_qoi;
     451             : };
     452             : 
     453             : // --------------------------------------------------------------
     454             : // DifferentiableSystem inline methods
     455             : inline
     456       15334 : TimeSolver & DifferentiableSystem::get_time_solver()
     457             : {
     458       15334 :   libmesh_assert(time_solver.get());
     459       15334 :   libmesh_assert_equal_to (&(time_solver->system()), this);
     460       15334 :   return *time_solver;
     461             : }
     462             : 
     463             : inline
     464    14932578 : const TimeSolver & DifferentiableSystem::get_time_solver() const
     465             : {
     466    14932578 :   libmesh_assert(time_solver.get());
     467    14932578 :   libmesh_assert_equal_to (&(time_solver->system()), this);
     468    14932578 :   return *time_solver;
     469             : }
     470             : 
     471             : } // namespace libMesh
     472             : 
     473             : 
     474             : #endif // LIBMESH_DIFF_SYSTEM_H

Generated by: LCOV version 1.14