LCOV - code coverage report
Current view: top level - src/problems - TensorProblem.C (source / functions) Hit Total Coverage
Test: idaholab/swift: #92 (25e020) with base b3cd84 Lines: 223 252 88.5 %
Date: 2025-09-10 17:10:32 Functions: 24 25 96.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /**********************************************************************/
       2             : /*                    DO NOT MODIFY THIS HEADER                       */
       3             : /*             Swift, a Fourier spectral solver for MOOSE             */
       4             : /*                                                                    */
       5             : /*            Copyright 2024 Battelle Energy Alliance, LLC            */
       6             : /*                        ALL RIGHTS RESERVED                         */
       7             : /**********************************************************************/
       8             : 
       9             : #include "Moose.h"
      10             : #include "MooseError.h"
      11             : #include "TensorProblem.h"
      12             : #include "TensorSolver.h"
      13             : #include "UniformTensorMesh.h"
      14             : 
      15             : #include "TensorOperatorBase.h"
      16             : #include "TensorTimeIntegrator.h"
      17             : #include "TensorOutput.h"
      18             : #include "DomainAction.h"
      19             : 
      20             : #include "SwiftUtils.h"
      21             : #include "DependencyResolverInterface.h"
      22             : #include <memory>
      23             : 
      24             : registerMooseObject("SwiftApp", TensorProblem);
      25             : 
      26             : InputParameters
      27         256 : TensorProblem::validParams()
      28             : {
      29         256 :   InputParameters params = FEProblem::validParams();
      30         256 :   params.addClassDescription(
      31             :       "A normal Problem object that adds the ability to perform spectral solves.");
      32         256 :   params.set<bool>("skip_nl_system_check") = true;
      33         512 :   params.addParam<bool>("print_debug_output", false, "Show Tensor specific debug outputs");
      34         512 :   params.addParam<unsigned int>(
      35             :       "spectral_solve_substeps",
      36         512 :       1,
      37             :       "How many substeps to divide the spectral solve for each MOOSE timestep into.");
      38         512 :   params.addParam<std::vector<std::string>>("scalar_constant_names", "Scalar constant names");
      39         512 :   params.addParam<std::vector<Real>>("scalar_constant_values", "Scalar constant values");
      40         256 :   return params;
      41           0 : }
      42             : 
      43         128 : TensorProblem::TensorProblem(const InputParameters & parameters)
      44             :   : FEProblem(parameters),
      45             :     DomainInterface(this),
      46         128 :     _options(MooseTensor::floatTensorOptions()),
      47         256 :     _debug(getParam<bool>("print_debug_output")),
      48         256 :     _substeps(getParam<unsigned int>("spectral_solve_substeps")),
      49         128 :     _dim(_domain.getDim()),
      50         128 :     _grid_spacing(_domain.getGridSpacing()),
      51         128 :     _n((_domain.getGridSize())),
      52         128 :     _shape(_domain.getShape()),
      53             :     _solver(nullptr),
      54         128 :     _can_fetch_constants(true)
      55             : {
      56             :   // get constants (for scalar constants we provide a shortcut in the problem block)
      57         128 :   for (const auto & [name, value] :
      58         260 :        getParam<std::string, Real>("scalar_constant_names", "scalar_constant_values"))
      59         132 :     declareConstant<Real>(name, value);
      60             : 
      61             :   // make sure AuxVariables are contiguous in the solution vector
      62         128 :   getAuxiliarySystem().sys().identify_variable_groups(false);
      63         128 : }
      64             : 
      65         244 : TensorProblem::~TensorProblem()
      66             : {
      67             :   // wait for outputs to be completed (otherwise resources might get freed that the output thread
      68             :   // depends on)
      69         130 :   for (auto & output : _outputs)
      70           8 :     output->waitForCompletion();
      71         366 : }
      72             : 
      73             : void
      74         126 : TensorProblem::init()
      75             : {
      76         126 :   unsigned int n_threads = libMesh::n_threads();
      77         126 :   if (n_threads != 1)
      78             :   {
      79          63 :     mooseInfo("Setting libTorch to use ", n_threads, " threads on the CPU.");
      80          63 :     torch::set_num_threads(n_threads);
      81             :   }
      82             : 
      83             :   // initialize tensors
      84         986 :   for (auto pair : _tensor_buffer)
      85         860 :     pair.second->init();
      86             : 
      87             :   // compute grid dependent quantities
      88         126 :   gridChanged();
      89             : 
      90             :   // init computes (must happen before dependency update)
      91         630 :   for (auto & initializer : _ics)
      92         504 :     initializer->init();
      93             : 
      94             :   // init computes (must happen before dependency update)
      95         652 :   for (auto & cmp : _computes)
      96         526 :     cmp->init();
      97             : 
      98             :   // update dependencies
      99         126 :   if (_solver)
     100         110 :     _solver->updateDependencies();
     101             :   else
     102             :   {
     103             :     // dependency resolution of TensorComputes
     104          16 :     DependencyResolverInterface::sort(_computes);
     105             :   }
     106             : 
     107             :   // dependency resolution of TensorICs
     108         126 :   DependencyResolverInterface::sort(_ics);
     109             : 
     110             :   // dependency resolution of Tensor Postprocessors
     111         126 :   DependencyResolverInterface::sort(_pps);
     112             : 
     113             :   // show computes
     114         126 :   if (_debug)
     115             :   {
     116           0 :     _console << COLOR_CYAN << "Compute object execution order:\n" << COLOR_DEFAULT;
     117           0 :     for (auto & cmp : _computes)
     118             :     {
     119           0 :       _console << "  " << cmp->name() << '\n' << COLOR_YELLOW;
     120           0 :       for (const auto & ri : cmp->getRequestedItems())
     121           0 :         _console << "    <- " << ri << '\n';
     122           0 :       _console << COLOR_GREEN;
     123           0 :       for (const auto & si : cmp->getSuppliedItems())
     124           0 :         _console << "    -> " << si << '\n';
     125           0 :       _console << COLOR_DEFAULT;
     126             :     }
     127             :   }
     128             : 
     129             :   // call base class init
     130         126 :   FEProblem::init();
     131             : 
     132             :   // init outputs
     133         134 :   for (auto & output : _outputs)
     134           8 :     output->init();
     135             : 
     136             :   // check computes (after dependency update)
     137         652 :   for (auto & cmp : _computes)
     138         526 :     cmp->check();
     139             : 
     140         126 :   updateDOFMap();
     141             : 
     142             :   // debug output
     143             :   std::string variable_mapping;
     144         166 :   for (const auto & [buffer_name, tuple] : _buffer_to_var)
     145         100 :     variable_mapping += (std::get<bool>(tuple) ? "NODAL     " : "ELEMENTAL ") + buffer_name + '\n';
     146         126 :   if (!variable_mapping.empty())
     147          20 :     mooseInfo("Direct buffer to solution vector mappings:\n", variable_mapping);
     148         126 : }
     149             : 
     150             : void
     151        8494 : TensorProblem::execute(const ExecFlagType & exec_type)
     152             : {
     153        8494 :   if (exec_type == EXEC_INITIAL)
     154             :   {
     155             :     // check for constants
     156         126 :     if (_fetched_constants.size() == 1)
     157           2 :       mooseError(
     158           2 :           "Constant ", Moose::stringify(_fetched_constants), " was requested but never declared.");
     159         124 :     if (_fetched_constants.size() > 1)
     160           2 :       mooseError("Constants ",
     161           2 :                  Moose::stringify(_fetched_constants),
     162             :                  " were requested but never declared.");
     163         122 :     _can_fetch_constants = false;
     164             : 
     165             :     // update time
     166         122 :     _sub_time = FEProblem::time();
     167             : 
     168         122 :     executeTensorInitialConditions();
     169             : 
     170         122 :     executeTensorOutputs(EXEC_INITIAL);
     171             :   }
     172             : 
     173        8490 :   if (exec_type == EXEC_TIMESTEP_BEGIN)
     174             :   {
     175             :     // update time
     176        1624 :     _sub_time = FEProblem::timeOld();
     177             : 
     178             :     // run solver
     179        1624 :     if (_solver)
     180        1572 :       _solver->computeBuffer();
     181             :     else
     182          92 :       for (auto & cmp : _computes)
     183          40 :         cmp->computeBuffer();
     184             :   }
     185             : 
     186        8490 :   if (exec_type == EXEC_TIMESTEP_END)
     187             :   {
     188             :     // run outputs
     189        1624 :     executeTensorOutputs(EXEC_TIMESTEP_END);
     190             :   }
     191             : 
     192        8490 :   FEProblem::execute(exec_type);
     193        8490 : }
     194             : 
     195             : void
     196         122 : TensorProblem::executeTensorInitialConditions()
     197             : {
     198             :   // run ICs
     199         610 :   for (auto & ic : _ics)
     200         488 :     ic->computeBuffer();
     201             : 
     202             :   // compile ist of compute output tensors
     203             :   std::set<std::string> _is_output;
     204         636 :   for (auto & cmp : _computes)
     205        1028 :     _is_output.insert(cmp->getSuppliedItems().begin(), cmp->getSuppliedItems().end());
     206             : 
     207             :   // // check for uninitialized tensors
     208             :   // for (auto & [name, t] : _tensor_buffer)
     209             :   //   if (!t.defined() && _is_output.count(name) == 0)
     210             :   //     mooseWarning(name, " is not initialized and not an output of any [Solve] compute.");
     211         122 : }
     212             : 
     213             : /// perform output tasks
     214             : void
     215        1746 : TensorProblem::executeTensorOutputs(const ExecFlagType & exec_flag)
     216             : {
     217             :   // run postprocessing before output
     218        1876 :   for (auto & pp : _pps)
     219         130 :     pp->computeBuffer();
     220             : 
     221             :   // wait for prior asynchronous activity on CPU buffers to complete
     222             :   // (this is a synchronization barrier for the threaded CPU activity)
     223        1834 :   for (auto & output : _outputs)
     224          88 :     output->waitForCompletion();
     225             : 
     226             :   // update output time
     227        1746 :   _output_time = _time;
     228             : 
     229             :   // prepare CPU buffers (this is a synchronization barrier for the GPU)
     230       16130 :   for (const auto & pair : _tensor_buffer)
     231       14384 :     pair.second->makeCPUCopy();
     232             : 
     233             :   // run direct buffer outputs (asynchronous in threads)
     234        1834 :   for (auto & output : _outputs)
     235          88 :     if (output->shouldRun(exec_flag))
     236          88 :       output->startOutput();
     237             : 
     238        1746 :   if (_options.dtype() == torch::kFloat64)
     239        1746 :     mapBuffersToAux<double>();
     240           0 :   else if (_options.dtype() == torch::kFloat32)
     241           0 :     mapBuffersToAux<float>();
     242             :   else
     243           0 :     mooseError("torch::Dtype unsupported by mapBuffersToAux.");
     244        1746 : }
     245             : 
     246             : void
     247         126 : TensorProblem::updateDOFMap()
     248             : {
     249         252 :   TIME_SECTION("update", 3, "Updating Tensor DOF Map", true);
     250         126 :   const auto & min_global = _domain.getDomainMin();
     251             : 
     252             :   // variable mapping
     253             :   const auto & aux = getAuxiliarySystem();
     254         126 :   if (!const_cast<libMesh::System &>(aux.system()).is_initialized())
     255           0 :     mooseError("Aux system is not initialized :(");
     256             : 
     257         126 :   auto sys_num = aux.number();
     258         166 :   for (auto & [buffer_name, tuple] : _buffer_to_var)
     259             :   {
     260             :     auto & [var, dofs, is_nodal] = tuple;
     261          40 :     if (var->isArray() || var->isVector() || var->isFV())
     262           0 :       mooseError("Unsupported variable type for mapping");
     263          40 :     auto var_num = var->number();
     264             : 
     265       65940 :     auto compute_iteration_index = [this](Point p, long int n0, long int n1)
     266             :     {
     267      131880 :       return static_cast<long int>(p(0) / _grid_spacing(0)) +
     268       65940 :              (_dim > 1 ? static_cast<long int>(p(1) / _grid_spacing(1)) * n0 : 0) +
     269       65940 :              (_dim > 2 ? static_cast<long int>(p(2) / _grid_spacing(2)) * n0 * n1 : 0);
     270          40 :     };
     271             : 
     272          40 :     if (is_nodal)
     273             :     {
     274          20 :       long int n0 = _n[0] + 1;
     275          20 :       long int n1 = _n[1] + 1;
     276          20 :       long int n2 = _n[2] + 1;
     277          36 :       dofs.resize(n0 * (_dim > 1 ? n1 : 1) * (_dim > 2 ? n2 : 1));
     278             : 
     279             :       // loop over nodes
     280          20 :       const static Point shift = _grid_spacing / 2.0 - min_global;
     281       67720 :       for (const auto & node : _mesh.getMesh().node_ptr_range())
     282             :       {
     283       33840 :         const auto dof_index = node->dof_number(sys_num, var_num, 0);
     284       33840 :         const auto iteration_index = compute_iteration_index(*node + shift, n0, n1);
     285       33840 :         dofs[iteration_index] = dof_index;
     286          20 :       }
     287             :     }
     288             :     else
     289             :     {
     290          20 :       long int n0 = _n[0];
     291          20 :       long int n1 = _n[1];
     292          20 :       long int n2 = _n[2];
     293          20 :       dofs.resize(n0 * n1 * n2);
     294             : 
     295             :       // loop over elements
     296          20 :       const static Point shift = -min_global;
     297       64240 :       for (const auto & elem : _mesh.getMesh().element_ptr_range())
     298             :       {
     299       32100 :         const auto dof_index = elem->dof_number(sys_num, var_num, 0);
     300             :         const auto iteration_index =
     301       32100 :             compute_iteration_index(elem->vertex_average() + shift, n0, n1);
     302       32100 :         dofs[iteration_index] = dof_index;
     303          20 :       }
     304             :     }
     305             :   }
     306         126 : }
     307             : 
     308             : template <typename FLOAT_TYPE>
     309             : void
     310        1746 : TensorProblem::mapBuffersToAux()
     311             : {
     312             :   // nothing to map?
     313        1746 :   if (_buffer_to_var.empty())
     314             :     return;
     315             : 
     316        1320 :   TIME_SECTION("update", 3, "Mapping Tensor buffers to Variables", true);
     317             : 
     318         660 :   auto * current_solution = &getAuxiliarySystem().solution();
     319         660 :   auto * solution_vector = dynamic_cast<PetscVector<Number> *>(current_solution);
     320         660 :   if (!solution_vector)
     321           0 :     mooseError(
     322             :         "Cannot map directly to the solution vector because NumericVector is not a PetscVector!");
     323             : 
     324             :   auto value = solution_vector->get_array();
     325             : 
     326             :   // const monomial variables
     327        1980 :   for (const auto & [buffer_name, tuple] : _buffer_to_var)
     328             :   {
     329             :     const auto & [var, dofs, is_nodal] = tuple;
     330             :     libmesh_ignore(var);
     331        1320 :     const long int n0 = is_nodal ? _n[0] + 1 : _n[0];
     332        1320 :     const long int n1 = is_nodal ? _n[1] + 1 : _n[1];
     333        1320 :     const long int n2 = is_nodal ? _n[2] + 1 : _n[2];
     334             : 
     335             :     // TODO: better design that works for NEML2 tensors as well
     336        1320 :     const auto buffer = getRawCPUBuffer(buffer_name);
     337        1320 :     if (buffer.sizes().size() != _dim)
     338           0 :       mooseError("Buffer '",
     339             :                  buffer_name,
     340             :                  "' is not a scalar tensor field and is not yet supported for AuxVariable mapping");
     341             :     std::size_t idx = 0;
     342        1320 :     switch (_dim)
     343             :     {
     344             :       {
     345           0 :         case 1:
     346           0 :           const auto b = buffer.template accessor<FLOAT_TYPE, 1>();
     347           0 :           for (const auto i : make_range(n0))
     348           0 :             value[dofs[idx++]] = b[i % _n[0]];
     349             :           break;
     350             :       }
     351        1232 :       case 2:
     352             :       {
     353        1232 :         const auto b = buffer.template accessor<FLOAT_TYPE, 2>();
     354       60808 :         for (const auto j : make_range(n1))
     355     3014352 :           for (const auto i : make_range(n0))
     356     2954776 :             value[dofs[idx++]] = b[i % _n[0]][j % _n[1]];
     357             :         break;
     358             :       }
     359          88 :       case 3:
     360             :       {
     361          88 :         const auto b = buffer.template accessor<FLOAT_TYPE, 3>();
     362         572 :         for (const auto k : make_range(n2))
     363        3168 :           for (const auto j : make_range(n1))
     364       17688 :             for (const auto i : make_range(n0))
     365       15004 :               value[dofs[idx++]] = b[i % _n[0]][j % _n[1]][k % _n[2]];
     366             :         break;
     367             :       }
     368           0 :       default:
     369           0 :         mooseError("Unsupported dimension");
     370             :     }
     371             :   }
     372             : 
     373             :   solution_vector->restore_array();
     374         660 :   getAuxiliarySystem().sys().update();
     375             : }
     376             : 
     377             : template <typename FLOAT_TYPE>
     378             : void
     379             : TensorProblem::mapAuxToBuffers()
     380             : {
     381             :   // nothing to map?
     382             :   if (_var_to_buffer.empty())
     383             :     return;
     384             : 
     385             :   TIME_SECTION("update", 3, "Mapping Variables to Tensor buffers", true);
     386             : 
     387             :   const auto * current_solution = &getAuxiliarySystem().solution();
     388             :   const auto * solution_vector = dynamic_cast<const PetscVector<Number> *>(current_solution);
     389             :   if (!solution_vector)
     390             :     mooseError(
     391             :         "Cannot map directly to the solution vector because NumericVector is not a PetscVector!");
     392             : 
     393             :   const auto value = solution_vector->get_array_read();
     394             : 
     395             :   // const monomial variables
     396             :   for (const auto & [buffer_name, tuple] : _var_to_buffer)
     397             :   {
     398             :     const auto & [var, dofs, is_nodal] = tuple;
     399             :     libmesh_ignore(var);
     400             :     const auto buffer = getBufferBase(buffer_name).getRawCPUTensor();
     401             :     std::size_t idx = 0;
     402             :     switch (_dim)
     403             :     {
     404             :       {
     405             :         case 1:
     406             :           auto b = buffer.template accessor<FLOAT_TYPE, 1>();
     407             :           for (const auto i : make_range(_n[0]))
     408             :             b[i % _n[0]] = value[dofs[idx++]];
     409             :           break;
     410             :       }
     411             :       case 2:
     412             :       {
     413             :         auto b = buffer.template accessor<FLOAT_TYPE, 2>();
     414             :         for (const auto j : make_range(_n[1]))
     415             :         {
     416             :           for (const auto i : make_range(_n[0]))
     417             :             b[i % _n[0]][j % _n[1]] = value[dofs[idx++]];
     418             :           if (is_nodal)
     419             :             idx++;
     420             :         }
     421             :         break;
     422             :       }
     423             :       case 3:
     424             :       {
     425             :         auto b = buffer.template accessor<FLOAT_TYPE, 3>();
     426             :         for (const auto k : make_range(_n[2]))
     427             :         {
     428             :           for (const auto j : make_range(_n[1]))
     429             :           {
     430             :             for (const auto i : make_range(_n[0]))
     431             :               b[i % _n[0]][j % _n[1]][k % _n[2]] = value[dofs[idx++]];
     432             :             if (is_nodal)
     433             :               idx++;
     434             :           }
     435             :           if (is_nodal)
     436             :             idx += _n[0] + 1;
     437             :         }
     438             :         break;
     439             :       }
     440             :       default:
     441             :         mooseError("Unsupported dimension");
     442             :     }
     443             :   }
     444             : }
     445             : 
     446             : void
     447       77836 : TensorProblem::advanceState()
     448             : {
     449       77836 :   FEProblem::advanceState();
     450             : 
     451       77836 :   if (timeStep() <= 1)
     452        5162 :     return;
     453             : 
     454             :   // move buffers in time
     455       72674 :   std::size_t total_max = 0;
     456      899618 :   for (auto & pair : _tensor_buffer)
     457      869298 :     total_max = std::max(total_max, pair.second->advanceState());
     458             : 
     459             :   // move dt in time (UGH, we need the _substep_dt!!!!)
     460       72674 :   if (_old_dt.size() < total_max)
     461          82 :     _old_dt.push_back(0.0);
     462       72674 :   if (!_old_dt.empty())
     463             :   {
     464       83134 :     for (std::size_t i = _old_dt.size() - 1; i > 0; --i)
     465       40780 :       _old_dt[i] = _old_dt[i - 1];
     466       42354 :     _old_dt[0] = _dt;
     467             :   }
     468             : }
     469             : 
     470             : void
     471         126 : TensorProblem::gridChanged()
     472             : {
     473             :   // _domain.gridChanged();
     474         126 : }
     475             : 
     476             : void
     477         340 : TensorProblem::addTensorBuffer(const std::string & buffer_type,
     478             :                                const std::string & buffer_name,
     479             :                                InputParameters & parameters)
     480             : {
     481             :   // add buffer
     482         340 :   if (_tensor_buffer.find(buffer_name) != _tensor_buffer.end())
     483           0 :     mooseError("TensorBuffer '", buffer_name, "' already exists in the system");
     484             : 
     485             :   // Add a pointer to the TensorProblem and the Domain
     486         340 :   parameters.addPrivateParam<TensorProblem *>("_tensor_problem", this);
     487             :   // parameters.addPrivateParam<const DomainAction *>("_domain", &_domain);
     488             : 
     489             :   // Create the object
     490         340 :   auto tensor_buffer = _factory.create<TensorBufferBase>(buffer_type, buffer_name, parameters, 0);
     491         340 :   logAdd("TensorBufferBase", buffer_name, buffer_type, parameters);
     492             : 
     493         340 :   _tensor_buffer.try_emplace(buffer_name, tensor_buffer);
     494             : 
     495             :   // store variable mapping
     496         340 :   const auto & var_names = parameters.get<std::vector<AuxVariableName>>("map_to_aux_variable");
     497         340 :   if (!var_names.empty())
     498             :   {
     499             :     const auto & aux = getAuxiliarySystem();
     500             :     const auto var_name = var_names[0];
     501          40 :     if (!aux.hasVariable(var_name))
     502           0 :       mooseError("AuxVariable '", var_name, "' does not exist in the system.");
     503             : 
     504             :     bool is_nodal;
     505          40 :     const auto & var = aux.getVariable(0, var_name);
     506             :     if (var.feType() == FEType(FIRST, LAGRANGE))
     507             :       is_nodal = true;
     508             :     else if (var.feType() == FEType(CONSTANT, MONOMIAL))
     509             :       is_nodal = false;
     510             :     else
     511           0 :       mooseError("Only first order lagrange and constant monomial variables are supported for "
     512             :                  "direct transfer. Try using the ProjectTensorAux kernel to transfer buffers to "
     513             :                  "variables of any other type.");
     514             : 
     515          80 :     _buffer_to_var[buffer_name] = std::make_tuple(&var, std::vector<std::size_t>{}, is_nodal);
     516             : 
     517             :     // call this to mark the CPU copy as requested
     518          40 :     getRawCPUBuffer(buffer_name);
     519             :   }
     520         340 : }
     521             : 
     522             : void
     523         536 : TensorProblem::addTensorComputeSolve(const std::string & compute_type,
     524             :                                      const std::string & compute_name,
     525             :                                      InputParameters & parameters)
     526             : {
     527         536 :   addTensorCompute(compute_type, compute_name, parameters, _computes);
     528         536 : }
     529             : 
     530             : void
     531         512 : TensorProblem::addTensorComputeInitialize(const std::string & compute_type,
     532             :                                           const std::string & compute_name,
     533             :                                           InputParameters & parameters)
     534             : {
     535         512 :   addTensorCompute(compute_type, compute_name, parameters, _ics);
     536         512 : }
     537             : 
     538             : void
     539          30 : TensorProblem::addTensorComputePostprocess(const std::string & compute_name,
     540             :                                            const std::string & name,
     541             :                                            InputParameters & parameters)
     542             : {
     543          30 :   addTensorCompute(compute_name, name, parameters, _pps);
     544          30 : }
     545             : 
     546             : void
     547        1078 : TensorProblem::addTensorCompute(const std::string & compute_type,
     548             :                                 const std::string & compute_name,
     549             :                                 InputParameters & parameters,
     550             :                                 TensorComputeList & list)
     551             : {
     552             :   // Add a pointer to the TensorProblem and the Domain
     553        1078 :   parameters.addPrivateParam<TensorProblem *>("_tensor_problem", this);
     554        1078 :   parameters.addPrivateParam<const DomainAction *>("_domain", &_domain);
     555             : 
     556             :   // Create the object
     557             :   auto compute_object =
     558        1078 :       _factory.create<TensorOperatorBase>(compute_type, compute_name, parameters, 0);
     559        1078 :   logAdd("TensorOperatorBase", compute_name, compute_type, parameters);
     560        1078 :   list.push_back(compute_object);
     561        1078 : }
     562             : 
     563             : void
     564          12 : TensorProblem::addTensorOutput(const std::string & output_type,
     565             :                                const std::string & output_name,
     566             :                                InputParameters & parameters)
     567             : {
     568             :   // Add a pointer to the TensorProblem and the Domain
     569          12 :   parameters.addPrivateParam<TensorProblem *>("_tensor_problem", this);
     570          12 :   parameters.addPrivateParam<const DomainAction *>("_domain", &_domain);
     571             : 
     572             :   // Create the object
     573          12 :   auto output_object = _factory.create<TensorOutput>(output_type, output_name, parameters, 0);
     574          10 :   logAdd("TensorInitialCondition", output_name, output_type, parameters);
     575          10 :   _outputs.push_back(output_object);
     576          10 : }
     577             : 
     578             : void
     579         110 : TensorProblem::setSolver(std::shared_ptr<TensorSolver> solver,
     580             :                          const MooseTensor::Key<CreateTensorSolverAction> &)
     581             : {
     582         110 :   if (_solver)
     583           0 :     mooseError("A solver has already been set up.");
     584             : 
     585             :   _solver = solver;
     586         110 : }
     587             : 
     588             : TensorBufferBase &
     589        1990 : TensorProblem::getBufferBase(const std::string & buffer_name)
     590             : {
     591             :   auto it = _tensor_buffer.find(buffer_name);
     592        1990 :   if (it == _tensor_buffer.end())
     593           0 :     mooseError("TensorBuffer '", buffer_name, " does not exist in the system.");
     594        1990 :   return *it->second.get();
     595             : }
     596             : 
     597             : const torch::Tensor &
     598         588 : TensorProblem::getRawBuffer(const std::string & buffer_name)
     599             : {
     600         588 :   return getBufferBase(buffer_name).getRawTensor();
     601             : }
     602             : 
     603             : const torch::Tensor &
     604        1372 : TensorProblem::getRawCPUBuffer(const std::string & buffer_name)
     605             : {
     606        1372 :   return getBufferBase(buffer_name).getRawCPUTensor();
     607             : }
     608             : 
     609             : TensorProblem &
     610         298 : TensorProblem::cast(MooseObject * moose_object, Problem & problem)
     611             : {
     612         298 :   if (auto tensor_problem = dynamic_cast<TensorProblem *>(&problem); tensor_problem)
     613         298 :     return *tensor_problem;
     614           0 :   moose_object->mooseError("Object requires a TensorProblem.");
     615             : }

Generated by: LCOV version 1.14