LCOV - code coverage report
Current view: top level - src/executioners - TransientAndAdjoint.C (source / functions) Hit Total Coverage
Test: idaholab/moose optimization: #31405 (292dce) with base fef103 Lines: 41 44 93.2 %
Date: 2025-09-04 07:54:57 Functions: 5 5 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : //* This file is part of the MOOSE framework
       2             : //* https://mooseframework.inl.gov
       3             : //*
       4             : //* All rights reserved, see COPYRIGHT for full restrictions
       5             : //* https://github.com/idaholab/moose/blob/master/COPYRIGHT
       6             : //*
       7             : //* Licensed under LGPL 2.1, please see LICENSE for details
       8             : //* https://www.gnu.org/licenses/lgpl-2.1.html
       9             : 
      10             : // MOOSE includes
      11             : #include "TransientAndAdjoint.h"
      12             : #include "OptimizationAppTypes.h"
      13             : #include "FEProblemBase.h"
      14             : 
      15             : registerMooseObject("OptimizationApp", TransientAndAdjoint);
      16             : 
      17             : InputParameters
      18         244 : TransientAndAdjoint::validParams()
      19             : {
      20         244 :   InputParameters params = Transient::validParams();
      21         244 :   params += AdjointTransientSolve::validParams();
      22         244 :   params.addClassDescription("Executioner for evaluating transient simulations and their adjoint.");
      23             : 
      24             :   // We need to full matrix for the adjoint solve, so set this to NEWTON
      25         488 :   params.set<MooseEnum>("solve_type") = "newton";
      26         244 :   params.suppressParameter<MooseEnum>("solve_type");
      27             : 
      28             :   // The adjoint system (second one) is solved by _adjoint_solve
      29             :   // This is a parameter of the MultiSystemSolveObject, which we set from here, the executioner.
      30             :   // We seek to prevent the MultiSystemSolveObject from solving both systems
      31             :   // This is abusing input parameters, but SolveObjects do not have their own syntax
      32             :   // and we need to send this parameter from the executioner to the default nested SolveObject
      33         488 :   params.renameParam("system_names", "forward_system", "");
      34             : 
      35         244 :   return params;
      36           0 : }
      37             : 
      38         122 : TransientAndAdjoint::TransientAndAdjoint(const InputParameters & parameters)
      39             :   : Transient(parameters),
      40         122 :     _adjoint_solve(*this),
      41         122 :     _forward_times(declareRecoverableData<std::vector<Real>>("forward_times"))
      42             : {
      43             :   // Error out on unsupported time integration schemes
      44         122 :   switch (getTimeScheme())
      45             :   {
      46             :     case Moose::TI_IMPLICIT_EULER:
      47             :       break;
      48           0 :     default:
      49           0 :       paramError(
      50             :           "scheme", getParam<MooseEnum>("scheme"), " is not supported for computing adjoint.");
      51             :       break;
      52             :   }
      53         122 : }
      54             : 
      55             : void
      56         563 : TransientAndAdjoint::preExecute()
      57             : {
      58         563 :   Transient::preExecute();
      59             : 
      60             :   // Save the forward initial condition
      61         563 :   _adjoint_solve.insertForwardSolution(_t_step);
      62             : 
      63             :   // Save the time of the initial condition
      64             :   // The vector of times should be reset unless we are recovering
      65         563 :   if (!_app.isRecovering())
      66         538 :     _forward_times = {_time};
      67             :   else
      68          25 :     _forward_times.push_back(_time);
      69         563 : }
      70             : 
      71             : void
      72        5147 : TransientAndAdjoint::postStep()
      73             : {
      74        5147 :   Transient::postStep();
      75             : 
      76             :   // Save the converged forward solution and time
      77        5147 :   if (lastSolveConverged())
      78             :   {
      79        5142 :     _adjoint_solve.insertForwardSolution(_t_step);
      80        5142 :     _forward_times.push_back(_time);
      81             :   }
      82        5147 : }
      83             : 
      84             : void
      85         563 : TransientAndAdjoint::postExecute()
      86             : {
      87         563 :   Transient::postExecute();
      88             : 
      89             :   // If it is a half transient, then the app is meant to be run with recovery. Therefore, it doesn't
      90             :   // make sense to run the adjoint calculation since we aren't getting to the final time required
      91             :   // for a consistent adjoint.
      92         563 :   if (_app.testCheckpointHalfTransient())
      93             :     return;
      94             : 
      95             :   // Looping backward through forward time steps
      96        5680 :   for (const auto n : make_range(_forward_times.size() - 1))
      97             :   {
      98             :     // Set important time information so the Jacobian is properly computed in the forward system
      99        5142 :     _t_step = _forward_times.size() - 1 - n;
     100        5142 :     _time = _forward_times[_t_step];
     101        5142 :     _time_old = _forward_times[_t_step - 1];
     102        5142 :     _dt = _time - _time_old;
     103        5142 :     _dt_old = _t_step < 2 ? _dt : _time_old - _forward_times[_t_step - 2];
     104             : 
     105             :     // Set the forward solution to the time step that is currently being solved
     106        5142 :     _adjoint_solve.setForwardSolution(_t_step);
     107             : 
     108             :     // Incase there are some residual objects that need this call
     109        5142 :     _problem.timestepSetup();
     110        5142 :     _problem.onTimestepBegin();
     111             : 
     112             :     // Solve the adjoint system
     113        5142 :     _last_solve_converged = _adjoint_solve.solve();
     114        5142 :     if (!lastSolveConverged())
     115             :       break;
     116             : 
     117             :     // FIXME: This works well enough for console and CSV output, but exodus is a mess since I don't
     118             :     // think it knows what to do with backward timestepping or duplicate outputs at a given time
     119       10284 :     _problem.outputStep(OptimizationAppTypes::EXEC_ADJOINT_TIMESTEP_END);
     120             :   }
     121             : }

Generated by: LCOV version 1.14