LCOV - code coverage report
Current view: top level - include/problems - TensorProblem.h (source / functions) Hit Total Coverage
Test: idaholab/swift: #92 (25e020) with base b3cd84 Lines: 36 75 48.0 %
Date: 2025-09-10 17:10:32 Functions: 7 11 63.6 %
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             : #pragma once
      10             : 
      11             : #include "FEProblem.h"
      12             : #include "DomainInterface.h"
      13             : #include "InputParameters.h"
      14             : #include "SwiftTypes.h"
      15             : #include "SwiftUtils.h"
      16             : #include "TensorBuffer.h"
      17             : 
      18             : // list tensor buffer includes here
      19             : #include "PlainTensorBuffer.h"
      20             : #include "NEML2TensorBuffer.h"
      21             : 
      22             : #include "AuxiliarySystem.h"
      23             : #include "libmesh/petsc_vector.h"
      24             : #include "libmesh/print_trace.h"
      25             : 
      26             : #include <cstddef>
      27             : #include <list>
      28             : #include <memory>
      29             : #include <torch/torch.h>
      30             : #include <type_traits>
      31             : 
      32             : class UniformTensorMesh;
      33             : class TensorOperatorBase;
      34             : template <typename T = torch::Tensor>
      35             : class TensorTimeIntegrator;
      36             : class TensorOutput;
      37             : class TensorSolver;
      38             : class CreateTensorSolverAction;
      39             : 
      40             : namespace Swift
      41             : {
      42             : struct ConstantBase
      43             : {
      44             :   virtual ~ConstantBase() = default;
      45             :   virtual std::string getType() = 0;
      46             : };
      47             : 
      48             : template <typename T>
      49          10 : struct Constant : public ConstantBase
      50             : {
      51           0 :   virtual std::string getType() override { return libMesh::demangle(typeid(T).name()); }
      52             :   T _value;
      53             : };
      54             : }
      55             : 
      56             : /**
      57             :  * Problem for solving eigenvalue problems
      58             :  */
      59             : class TensorProblem : public FEProblem, public DomainInterface
      60             : {
      61             : public:
      62             :   static InputParameters validParams();
      63             : 
      64             :   TensorProblem(const InputParameters & parameters);
      65             :   ~TensorProblem() override;
      66             : 
      67             :   // setup stuff
      68             :   void init() override;
      69             : 
      70             :   // run compute objects
      71             :   void execute(const ExecFlagType & exec_type) override;
      72             : 
      73             :   // move tensors in time
      74             :   void advanceState() override;
      75             : 
      76             :   // recompute quantities on grid size change
      77             :   virtual void gridChanged();
      78             : 
      79             :   virtual void addTensorBuffer(const std::string & buffer_type,
      80             :                                const std::string & buffer_name,
      81             :                                InputParameters & parameters);
      82             : 
      83             :   template <typename T>
      84             :   std::shared_ptr<TensorBuffer<T>> addTensorBuffer(const std::string & buffer_name);
      85             : 
      86             :   virtual void addTensorComputeInitialize(const std::string & compute_name,
      87             :                                           const std::string & name,
      88             :                                           InputParameters & parameters);
      89             :   virtual void addTensorComputeSolve(const std::string & compute_name,
      90             :                                      const std::string & name,
      91             :                                      InputParameters & parameters);
      92             :   virtual void addTensorComputePostprocess(const std::string & compute_name,
      93             :                                            const std::string & name,
      94             :                                            InputParameters & parameters);
      95             : 
      96             :   virtual void addTensorOutput(const std::string & output_name,
      97             :                                const std::string & name,
      98             :                                InputParameters & parameters);
      99             : 
     100             :   /// check if a tensor buffer with the given type exists
     101             :   template <typename T>
     102             :   bool hasBuffer(const std::string & buffer_name);
     103             : 
     104             :   /// returns the current state of the tensor
     105             :   template <typename T = torch::Tensor>
     106             :   T & getBuffer(const std::string & buffer_name);
     107             : 
     108             :   /// requests a tensor regardless of type
     109             :   TensorBufferBase & getBufferBase(const std::string & buffer_name);
     110             : 
     111             :   /// return the old states of the tensor
     112             :   template <typename T = torch::Tensor>
     113             :   const std::vector<T> & getBufferOld(const std::string & buffer_name, unsigned int max_states);
     114             : 
     115             :   /// returns a reference to a raw torch::Tensor view of buffer_name
     116             :   const torch::Tensor & getRawBuffer(const std::string & buffer_name);
     117             : 
     118             :   /// returns a reference to a copy of buffer_name that is guaranteed to be contiguous and located on the CPU device
     119             :   const torch::Tensor & getRawCPUBuffer(const std::string & buffer_name);
     120             : 
     121         110 :   virtual Real & subDt() { return _sub_dt; }
     122        1298 :   virtual Real & subTime() { return _sub_time; }
     123          12 :   virtual Real & outputTime() { return _output_time; }
     124             : 
     125             :   /// align a 1d tensor in a specific dimension
     126             :   torch::Tensor align(torch::Tensor t, unsigned int dim) const;
     127             : 
     128             :   /// get the domain shape (to build tensors from scratch) TODO: make sure this is local
     129          32 :   const torch::IntArrayRef & getShape() { return _shape; }
     130             : 
     131             :   typedef std::vector<std::shared_ptr<TensorOperatorBase>> TensorComputeList;
     132             :   const TensorComputeList & getComputes() const { return _computes; }
     133             : 
     134             :   template <typename T = TensorOperatorBase>
     135             :   T & getCompute(const std::string & name) const;
     136             : 
     137             :   typedef std::vector<std::shared_ptr<TensorOutput>> TensorOutputList;
     138             :   const TensorOutputList & getOutputs() const { return _outputs; }
     139             : 
     140             :   template <typename T>
     141             :   const T & getConstant(const std::string & name);
     142             : 
     143             :   template <typename T>
     144             :   void declareConstant(const std::string & name, const T & value);
     145             : 
     146             :   /// The CreateTensorSolverAction calls this to set the active solver
     147             :   void setSolver(std::shared_ptr<TensorSolver> solver,
     148             :                  const MooseTensor::Key<CreateTensorSolverAction> &);
     149             : 
     150             :   /// get a reference to the current solver
     151             :   template <typename T>
     152             :   T & getSolver() const;
     153             : 
     154             :   static TensorProblem & cast(MooseObject * moose_object, Problem & problem);
     155             : 
     156             : protected:
     157             :   void updateDOFMap();
     158             : 
     159             :   template <typename FLOAT_TYPE>
     160             :   void mapBuffersToAux();
     161             : 
     162             :   template <typename FLOAT_TYPE>
     163             :   void mapAuxToBuffers();
     164             : 
     165             :   virtual void addTensorCompute(const std::string & compute_name,
     166             :                                 const std::string & name,
     167             :                                 InputParameters & parameters,
     168             :                                 TensorComputeList & list);
     169             : 
     170             :   /// execute initial conditionobjects
     171             :   void executeTensorInitialConditions();
     172             : 
     173             :   /// perform output tasks
     174             :   void executeTensorOutputs(const ExecFlagType & exec_type);
     175             : 
     176             :   /// helper to get the TensorBuffer wrapper object that holds the actual tensor data
     177             :   template <typename T = torch::Tensor>
     178             :   TensorBuffer<T> & getBufferHelper(const std::string & buffer_name);
     179             : 
     180             :   /// tensor options
     181             :   const torch::TensorOptions _options;
     182             : 
     183             :   /// show debug ouput
     184             :   const bool _debug;
     185             : 
     186             :   /// solver substeps
     187             :   const unsigned int _substeps;
     188             : 
     189             :   /// substepping timestep
     190             :   Real _sub_dt;
     191             :   Real _sub_time;
     192             : 
     193             :   /// simulation time for the currently running output thread
     194             :   Real _output_time;
     195             : 
     196             :   /// list of TensorBuffers (i.e. tensors)
     197             :   std::map<std::string, std::shared_ptr<TensorBufferBase>> _tensor_buffer;
     198             : 
     199             :   /// old timesteps
     200             :   std::vector<Real> _old_dt;
     201             : 
     202             :   const unsigned int & _dim;
     203             : 
     204             :   /// grid spacing
     205             :   const RealVectorValue & _grid_spacing;
     206             : 
     207             :   /// global grid size
     208             :   const std::array<int64_t, 3> & _n;
     209             : 
     210             :   /// domain shape
     211             :   const torch::IntArrayRef & _shape;
     212             : 
     213             :   /// solve objects
     214             :   TensorComputeList _computes;
     215             : 
     216             :   /// initialization objects
     217             :   TensorComputeList _ics;
     218             : 
     219             :   /// postprocessing objects
     220             :   TensorComputeList _pps;
     221             : 
     222             :   /// on demand objects that are explicitly triggered by other objects
     223             :   TensorComputeList _on_demand;
     224             : 
     225             :   ///  time integrator objects
     226             :   std::vector<std::shared_ptr<TensorTimeIntegrator<>>> _time_integrators;
     227             : 
     228             :   std::vector<std::shared_ptr<TensorOutput>> _outputs;
     229             : 
     230             :   /// map from buffer name to variable name
     231             :   std::map<std::string, AuxVariableName> _buffer_to_var_name;
     232             : 
     233             :   /// buffers to solution vector indices
     234             :   std::map<std::string, std::tuple<const MooseVariableFieldBase *, std::vector<std::size_t>, bool>>
     235             :       _buffer_to_var;
     236             :   std::map<std::string, std::tuple<const MooseVariableFieldBase *, std::vector<std::size_t>, bool>>
     237             :       _var_to_buffer;
     238             : 
     239             :   /// The [TensorSolver]
     240             :   std::shared_ptr<TensorSolver> _solver;
     241             : 
     242             :   /// parameters
     243             :   std::map<std::string, std::unique_ptr<Swift::ConstantBase>> _constants;
     244             :   std::set<std::string> _fetched_constants;
     245             :   std::list<Real> _literal_constants;
     246             :   bool _can_fetch_constants;
     247             : 
     248             : private:
     249             :   std::list<InputParameters> _buffer_params;
     250             : };
     251             : 
     252             : template <typename T>
     253             : T &
     254           0 : TensorProblem::getSolver() const
     255             : {
     256           0 :   if (_solver)
     257             :   {
     258           0 :     const auto specialized_solver = dynamic_cast<T *>(_solver.get());
     259           0 :     if (specialized_solver)
     260           0 :       return *specialized_solver;
     261           0 :     mooseError(
     262           0 :         "No TensorSolver supporting the requested type '", typeid(T).name(), "' has been set up.");
     263             :   }
     264           0 :   mooseError("No TensorSolver has been set up.");
     265             : }
     266             : 
     267             : template <typename T>
     268             : bool
     269             : TensorProblem::hasBuffer(const std::string & buffer_name)
     270             : {
     271             :   auto it = _tensor_buffer.find(buffer_name);
     272             :   return (it != _tensor_buffer.end() && !dynamic_cast<TensorBuffer<T> *>(it->second.get()));
     273             : }
     274             : 
     275             : template <typename T>
     276             : TensorBuffer<T> &
     277           0 : TensorProblem::getBufferHelper(const std::string & buffer_name)
     278             : {
     279             :   auto it = _tensor_buffer.find(buffer_name);
     280             : 
     281           0 :   if (it == _tensor_buffer.end())
     282           0 :     return *addTensorBuffer<T>(buffer_name);
     283             :   else
     284             :   {
     285           0 :     auto tensor_buffer = dynamic_cast<TensorBuffer<T> *>(it->second.get());
     286           0 :     if (!tensor_buffer)
     287           0 :       mooseError("TensorBuffer '",
     288             :                  buffer_name,
     289             :                  "' of the requested type '",
     290             :                  libMesh::demangle(typeid(T).name()),
     291             :                  "' was previously declared as '",
     292             :                  it->second->type(),
     293             :                  "'.");
     294             :     return *tensor_buffer;
     295             :   }
     296             : }
     297             : 
     298             : template <typename T>
     299             : T &
     300             : TensorProblem::getBuffer(const std::string & buffer_name)
     301             : {
     302        1422 :   return getBufferHelper<T>(buffer_name).getTensor();
     303             : }
     304             : 
     305             : template <typename T>
     306             : const std::vector<T> &
     307         130 : TensorProblem::getBufferOld(const std::string & buffer_name, unsigned int max_states)
     308             : {
     309         130 :   return getBufferHelper<T>(buffer_name).getOldTensor(max_states);
     310             : }
     311             : 
     312             : template <typename T>
     313             : std::shared_ptr<TensorBuffer<T>>
     314           0 : TensorProblem::addTensorBuffer(const std::string & buffer_name)
     315             : {
     316           0 :   if (_debug)
     317           0 :     mooseInfoRepeated("Automatically adding tensor '",
     318             :                       buffer_name,
     319             :                       "' of type '",
     320             :                       libMesh::demangle(typeid(T).name()),
     321             :                       "'");
     322             : 
     323           0 :   _buffer_params.push_back(TensorBufferSpecialization<T>::type::validParams());
     324             :   auto & params = _buffer_params.back();
     325           0 :   params.template set<std::string>("_object_name") = buffer_name;
     326           0 :   params.template set<FEProblem *>("_fe_problem") = this;
     327           0 :   params.template set<FEProblemBase *>("_fe_problem_base") = this;
     328           0 :   params.template set<THREAD_ID>("_tid") = 0;
     329           0 :   params.template set<std::string>("_type") = "TensorBufferBase";
     330           0 :   params.template set<MooseApp *>("_moose_app") = &getMooseApp();
     331           0 :   params.finalize(buffer_name);
     332             :   auto tensor_buffer = std::make_shared<typename TensorBufferSpecialization<T>::type>(params);
     333             : 
     334           0 :   _tensor_buffer.try_emplace(buffer_name, tensor_buffer);
     335           0 :   return tensor_buffer;
     336             : }
     337             : 
     338             : template <typename T>
     339             : const T &
     340         332 : TensorProblem::getConstant(const std::string & name)
     341             : {
     342         332 :   if (!_can_fetch_constants)
     343           0 :     mooseError("Constants must be gotten during object construction.");
     344             : 
     345             :   // deal with literal scalars
     346             :   if constexpr (std::is_same_v<T, Real>)
     347             :   {
     348             :     // check if we are able to convert the name into a Real
     349             :     Real real_value;
     350         332 :     std::istringstream ss(name);
     351         332 :     if (ss >> real_value && ss.eof())
     352             :     {
     353         322 :       _literal_constants.push_back(real_value);
     354             :       return _literal_constants.back();
     355             :     }
     356         332 :   }
     357             : 
     358             :   const auto it = _constants.find(name);
     359          10 :   if (it != _constants.end())
     360             :   {
     361           4 :     auto * t_param = dynamic_cast<Swift::Constant<T> *>(it->second.get());
     362           4 :     if (t_param == nullptr)
     363           0 :       mooseError("Fetching constant '",
     364             :                  name,
     365             :                  "' (which is of type ",
     366           0 :                  it->second->getType(),
     367             :                  ") with the wrong type (",
     368             :                  libMesh::demangle(typeid(T).name()),
     369             :                  ").");
     370           4 :     return t_param->_value;
     371             :   }
     372             :   else
     373             :   {
     374           6 :     auto param = std::make_unique<Swift::Constant<T>>();
     375           6 :     const auto & ref = param->_value;
     376           6 :     _constants[name] = std::move(param);
     377           6 :     _fetched_constants.insert(name);
     378             :     return ref;
     379           6 :   }
     380             : }
     381             : 
     382             : template <typename T>
     383             : void
     384           4 : TensorProblem::declareConstant(const std::string & name, const T & value)
     385             : {
     386           4 :   if (!_can_fetch_constants)
     387           0 :     mooseError("Constants must be declared during object construction.");
     388             : 
     389             :   const auto it = _constants.find(name);
     390           4 :   if (it != _constants.end())
     391             :   {
     392           0 :     auto * t_param = dynamic_cast<Swift::Constant<T> *>(it->second.get());
     393           0 :     if (t_param == nullptr)
     394           0 :       mooseError("Declaring constant '",
     395             :                  name,
     396             :                  "' (which was already fetched as type ",
     397           0 :                  it->second->getType(),
     398             :                  ") with the wrong type (",
     399             :                  libMesh::demangle(typeid(T).name()),
     400             :                  ").");
     401             : 
     402             :     if (_fetched_constants.count(name))
     403             :     {
     404             :       // placeholder parameter created by getParameter
     405           0 :       t_param->_value = value;
     406             :       _fetched_constants.erase(name);
     407             :     }
     408             :     else
     409           0 :       mooseError("Parameter '", name, "' has already been declared.");
     410             :   }
     411             :   else
     412             :   {
     413           4 :     auto param = std::make_unique<Swift::Constant<T>>();
     414           4 :     param->_value = value;
     415           4 :     _constants[name] = std::move(param);
     416           4 :   }
     417           4 : }
     418             : 
     419             : template <typename T>
     420             : T &
     421           4 : TensorProblem::getCompute(const std::string & name) const
     422             : {
     423           4 :   for (const auto & tcb : _computes)
     424           8 :     if (std::dynamic_pointer_cast<MooseObject>(tcb)->name() == name)
     425           4 :       if (const auto ptr = std::dynamic_pointer_cast<T>(tcb); ptr)
     426           4 :         return *ptr;
     427             : 
     428           0 :   mooseError("No compute with name '",
     429             :              name,
     430             :              "' of type ",
     431             :              libMesh::demangle(typeid(T).name()),
     432             :              " found.");
     433             : }

Generated by: LCOV version 1.14