LCOV - code coverage report
Current view: top level - src/solvers - adaptive_time_solver.C (source / functions) Hit Total Coverage
Test: libMesh/libmesh: #4229 (6a9aeb) with base 727f46 Lines: 68 74 91.9 %
Date: 2025-08-19 19:27:09 Functions: 12 16 75.0 %
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             : #include "libmesh/adaptive_time_solver.h"
      19             : #include "libmesh/diff_system.h"
      20             : #include "libmesh/dof_map.h"
      21             : #include "libmesh/numeric_vector.h"
      22             : #include "libmesh/no_solution_history.h"
      23             : 
      24             : // Debug
      25             : #include "libmesh/system_norm.h"
      26             : #include "libmesh/enum_norm_type.h"
      27             : 
      28             : namespace libMesh
      29             : {
      30             : 
      31             : 
      32             : 
      33         420 : AdaptiveTimeSolver::AdaptiveTimeSolver (sys_type & s)
      34             :   : FirstOrderUnsteadySolver(s),
      35         396 :     core_time_solver(),
      36         396 :     target_tolerance(1.e-3),
      37         396 :     upper_tolerance(0.0),
      38         396 :     max_deltat(0.),
      39         396 :     min_deltat(0.),
      40         396 :     max_growth(0.),
      41         420 :     completed_timestep_size(s.deltat),
      42         432 :     global_tolerance(true)
      43             : {
      44             :   // the child class must populate core_time_solver
      45             :   // with whatever actual time solver is to be used
      46         420 : }
      47             : 
      48             : 
      49             : 
      50         396 : AdaptiveTimeSolver::~AdaptiveTimeSolver () = default;
      51             : 
      52             : 
      53             : 
      54         420 : void AdaptiveTimeSolver::init()
      55             : {
      56          12 :   libmesh_assert(core_time_solver.get());
      57             : 
      58             :   // We override this because our core_time_solver is the one that
      59             :   // needs to handle new vectors, diff_solver->init(), etc
      60         420 :   core_time_solver->init();
      61             : 
      62             :   // Set the core_time_solver's solution history object to be the same one as
      63             :   // that for the outer adaptive time solver
      64         420 :   core_time_solver->set_solution_history((this->get_solution_history()));
      65             : 
      66             :   // Now that we have set the SolutionHistory object for the coretimesolver,
      67             :   // we set the SolutionHistory type for the timesolver to be NoSolutionHistory
      68             :   // All storage and retrieval will be handled by the coretimesolver directly.
      69          24 :   NoSolutionHistory outersolver_solution_history;
      70         420 :   this->set_solution_history(outersolver_solution_history);
      71             : 
      72             :   // As an UnsteadySolver, we have an old_local_nonlinear_solution, but it
      73             :   // isn't pointing to the right place - fix it
      74          12 :   old_local_nonlinear_solution = core_time_solver->old_local_nonlinear_solution;
      75         420 : }
      76             : 
      77             : 
      78             : 
      79         560 : void AdaptiveTimeSolver::reinit()
      80             : {
      81          16 :   libmesh_assert(core_time_solver.get());
      82             : 
      83             :   // We override this because our core_time_solver is the one that
      84             :   // needs to handle new vectors, diff_solver->reinit(), etc
      85         560 :   core_time_solver->reinit();
      86         560 : }
      87             : 
      88             : 
      89        4200 : void AdaptiveTimeSolver::advance_timestep ()
      90             : {
      91             :   // The first access of advance_timestep happens via solve, not user code
      92             :   // It is used here to store any initial conditions data
      93        4200 :   if (!first_solve)
      94             :     {
      95        3780 :       _system.time += this->completed_timestep_size;
      96             :     }
      97             :   else
      98             :     {
      99             :     // We are here because of a call to advance_timestep that happens
     100             :     // via solve, the very first solve. All we are doing here is storing
     101             :     // the initial condition. The actual solution computed via this solve
     102             :     // will be stored when we call advance_timestep in the user's timestep loop
     103         420 :     first_solve = false;
     104          12 :     core_time_solver->set_first_solve(false);
     105             :     }
     106             : 
     107             :   // For the adaptive time solver, all SH operations
     108             :   // are handled by the core_time_solver's SH object
     109             :   // Sub solution storage is handled internally by the core time solver,
     110             :   // but the 'full step' solution is stored here to maintain consistency
     111             :   // with the fixed timestep scheme.
     112        4200 :   core_time_solver->get_solution_history().store(false, _system.time);
     113             : 
     114             :   NumericVector<Number> & old_nonlinear_soln =
     115        4200 :     _system.get_vector("_old_nonlinear_solution");
     116             :   NumericVector<Number> & nonlinear_solution =
     117        4200 :     *(_system.solution);
     118             : 
     119        4200 :   old_nonlinear_soln = nonlinear_solution;
     120             : 
     121             :   old_nonlinear_soln.localize
     122        4200 :     (*old_local_nonlinear_solution,
     123        4200 :      _system.get_dof_map().get_send_list());
     124        4200 : }
     125             : 
     126        4200 : void AdaptiveTimeSolver::adjoint_advance_timestep ()
     127             : {
     128             :   // Store the computed full step adjoint solution for future use (sub steps are handled internally by the core time solver)
     129        4200 :   core_time_solver->get_solution_history().store(true, _system.time);
     130             : 
     131             :   // For the first adjoint step ensure that we use the last primal timestep.
     132        4200 :   if (first_adjoint_step)
     133             :   {
     134         432 :     _system.deltat = dynamic_cast<DifferentiableSystem &>(_system).time_solver->TimeSolver::last_completed_timestep_size();
     135         420 :     first_adjoint_step = false;
     136             :   }
     137             : 
     138             :   // Before moving to the next time instant, copy over the current adjoint solutions into _old_adjoint_solutions
     139       11480 :   for(auto i : make_range(_system.n_qois()))
     140             :   {
     141        7488 :    std::string old_adjoint_solution_name = "_old_adjoint_solution";
     142        7072 :    old_adjoint_solution_name+= std::to_string(i);
     143        7488 :    NumericVector<Number> & old_adjoint_solution_i = _system.get_vector(old_adjoint_solution_name);
     144        7280 :    NumericVector<Number> & adjoint_solution_i = _system.get_adjoint_solution(i);
     145        7280 :    old_adjoint_solution_i = adjoint_solution_i;
     146             :   }
     147             : 
     148        4200 :   _system.time -= _system.deltat;
     149             : 
     150             :   // For the adaptive time solver, all SH operations
     151             :   // are handled by the core_time_solver's SH object
     152             :   // Retrieve the primal solution for the next adjoint calculation,
     153             :   // by using the core time solver's solution history object.
     154        4200 :   core_time_solver->get_solution_history().retrieve(true, _system.time);
     155             : 
     156             :   // We also need to tell the core time solver that the adjoint initial conditions have been set
     157         120 :   core_time_solver->set_first_adjoint_step(false);
     158             : 
     159             :   // Dont forget to localize the old_nonlinear_solution !
     160        4200 :   _system.get_vector("_old_nonlinear_solution").localize
     161        4200 :     (*old_local_nonlinear_solution,
     162        4200 :     _system.get_dof_map().get_send_list());
     163        4200 : }
     164             : 
     165         700 : void AdaptiveTimeSolver::retrieve_timestep ()
     166             : {
     167             :   // Ask the core time solver to retrieve all the stored vectors
     168             :   // at the current time
     169         700 :   core_time_solver->retrieve_timestep();
     170         700 : }
     171             : 
     172           0 : Real AdaptiveTimeSolver::error_order () const
     173             : {
     174           0 :   libmesh_assert(core_time_solver.get());
     175             : 
     176           0 :   return core_time_solver->error_order();
     177             : }
     178             : 
     179             : 
     180             : 
     181    10128536 : bool AdaptiveTimeSolver::element_residual (bool request_jacobian,
     182             :                                            DiffContext & context)
     183             : {
     184      920776 :   libmesh_assert(core_time_solver.get());
     185             : 
     186    10128536 :   return core_time_solver->element_residual(request_jacobian, context);
     187             : }
     188             : 
     189             : 
     190             : 
     191     1277760 : bool AdaptiveTimeSolver::side_residual (bool request_jacobian,
     192             :                                         DiffContext & context)
     193             : {
     194       63888 :   libmesh_assert(core_time_solver.get());
     195             : 
     196      702768 :   return core_time_solver->side_residual(request_jacobian, context);
     197             : }
     198             : 
     199             : 
     200             : 
     201           0 : bool AdaptiveTimeSolver::nonlocal_residual (bool request_jacobian,
     202             :                                             DiffContext & context)
     203             : {
     204           0 :   libmesh_assert(core_time_solver.get());
     205             : 
     206           0 :   return core_time_solver->nonlocal_residual(request_jacobian, context);
     207             : }
     208             : 
     209             : 
     210             : 
     211       16660 : std::unique_ptr<DiffSolver> & AdaptiveTimeSolver::diff_solver()
     212             : {
     213       16660 :   return core_time_solver->diff_solver();
     214             : }
     215             : 
     216             : 
     217             : 
     218      101360 : std::unique_ptr<LinearSolver<Number>> & AdaptiveTimeSolver::linear_solver()
     219             : {
     220      101360 :   return core_time_solver->linear_solver();
     221             : }
     222             : 
     223             : 
     224             : 
     225       11340 : Real AdaptiveTimeSolver::calculate_norm(System & s,
     226             :                                         NumericVector<Number> & v)
     227             : {
     228       11340 :   return s.calculate_norm(v, component_norm);
     229             : }
     230             : 
     231             : } // namespace libMesh

Generated by: LCOV version 1.14