LCOV - code coverage report
Current view: top level - include/userobjects - BatchMaterial.h (source / functions) Hit Total Coverage
Test: idaholab/moose framework: 2bf808 Lines: 60 64 93.8 %
Date: 2025-07-17 01:28:37 Functions: 34 34 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             : #pragma once
      11             : 
      12             : #include "ElementUserObject.h"
      13             : 
      14             : #include "libmesh/int_range.h"
      15             : 
      16             : #include <tuple>
      17             : #include <string>
      18             : #include <vector>
      19             : #include <utility>
      20             : 
      21             : namespace BatchMaterialUtils
      22             : {
      23             : 
      24             : // type wrappers
      25             : template <typename T, unsigned int state>
      26             : struct GatherMatPropTempl
      27             : {
      28             :   typedef T type;
      29             :   typedef const MaterialProperty<T> gather_type;
      30             : 
      31             :   template <typename M>
      32          52 :   static gather_type * getPointer(M & mpi, const MaterialPropertyName & name)
      33             :   {
      34          52 :     return &mpi.template getGenericMaterialProperty<T, false>(name, state);
      35             :   }
      36             : };
      37             : 
      38             : template <typename T>
      39             : using GatherMatProp = GatherMatPropTempl<T, 0>;
      40             : template <typename T>
      41             : using GatherMatPropOld = GatherMatPropTempl<T, 1>;
      42             : 
      43             : struct GatherVariable
      44             : {
      45             :   typedef Real type;
      46             :   typedef const VariableValue gather_type;
      47             : 
      48             :   template <typename C>
      49          13 :   static gather_type * getPointer(const C & coupleable, const VariableName & name)
      50             :   {
      51          13 :     return &coupleable.coupledValue(name);
      52             :   }
      53             : };
      54             : 
      55             : struct GatherVariableOld
      56             : {
      57             :   typedef Real type;
      58             :   typedef const VariableValue gather_type;
      59             : 
      60             :   template <typename C>
      61          13 :   static gather_type * getPointer(const C & coupleable, const VariableName & name)
      62             :   {
      63          13 :     return &coupleable.coupledValueOld(name);
      64             :   }
      65             : };
      66             : 
      67             : // tuple wrappers
      68             : struct TupleStd
      69             : {
      70             :   // the tuple type
      71             :   template <typename... Args>
      72             :   using type = std::tuple<Args...>;
      73             : 
      74             :   // the element access function
      75             :   template <int N, typename T>
      76    17280000 :   static auto & get(T && t)
      77             :   {
      78    17280000 :     return std::get<N>(t);
      79             :   }
      80             : 
      81             :   // tuple size (number of elements)
      82             :   template <typename T>
      83             :   using size = std::tuple_size<T>;
      84             : 
      85             :   // element type access
      86             :   template <int I, typename T>
      87             :   using element = typename std::tuple_element<I, T>::type;
      88             : };
      89             : }
      90             : 
      91             : template <typename Tuple, typename Output, typename... Input>
      92             : class BatchMaterial : public ElementUserObject
      93             : {
      94             :   /// shorthand for the instantiated template type
      95             :   typedef BatchMaterial<Tuple, Output, Input...> BatchMaterialType;
      96             : 
      97             :   /// Helper template for obtainig all variable and material property references
      98             :   template <int I, typename T, typename... Names>
      99             :   void construct(T && name, Names &&... names);
     100             : 
     101             :   /// Helper template for gathering all items into the input data tuples
     102             :   template <int I>
     103             :   void copy(const unsigned int nqp);
     104             : 
     105             : public:
     106       14288 :   static InputParameters validParams() { return ElementUserObject::validParams(); }
     107             : 
     108             :   template <typename... Names>
     109          13 :   BatchMaterial(const InputParameters & params, Names &&... names)
     110          13 :     : ElementUserObject(params), _output_ready(false)
     111             :   {
     112          13 :     construct<0, Names...>(std::forward<Names>(names)...);
     113          13 :   }
     114             : 
     115             :   /// override this method to implement the computation on the batch data
     116             :   virtual void batchCompute() = 0;
     117             : 
     118             :   /// The output type is directly specified as a template parameter
     119             :   typedef Output OutputType;
     120             :   /// The serialized batch data is stored in a vector
     121             :   typedef std::vector<OutputType> OutputVector;
     122             : 
     123             :   /// input data needs to use a flexible tuple type (std::tuple or cuda::std::tuple)
     124             :   typedef typename Tuple::template type<typename Input::type...> InputType;
     125             :   /// The serialized batch data is stored in a vector
     126             :   typedef std::vector<InputType> InputVector;
     127             : 
     128             :   /// Get a read-only reference to the output data
     129          39 :   const OutputVector & getOutputData() const { return _output_data; }
     130             : 
     131             :   /// Get a writable reference to the output data
     132             :   OutputVector & setOutputData() { return _output_data; }
     133             : 
     134             :   /// get a reference to the input data
     135             :   const InputVector & getInputData() const { return _input_data; }
     136             : 
     137             :   /// check if the output is fully computed and ready to be fetched
     138     2160000 :   bool outputReady() const { return _output_ready; }
     139             : 
     140             :   /// get the index for the first qp of a specified element (other qps are at the following indices)
     141             :   std::size_t getIndex(dof_id_type elem_id) const;
     142             : 
     143             :   /// data structures are initialized here
     144             :   void initialize() override final;
     145             : 
     146             :   /// All data is automatically gathered here
     147             :   void execute() override final;
     148             : 
     149             :   /// Assemble data from all threads
     150             :   void threadJoin(const UserObject & uo) override final;
     151             : 
     152             :   /// we call batchCompute() from here
     153             :   void finalize() override final;
     154             : 
     155             :   /// Input data, utilized in batchCompute()
     156             :   InputVector _input_data;
     157             : 
     158             :   /// Output data, written to in batchCompute()
     159             :   OutputVector _output_data;
     160             : 
     161             :   // use regular tuple for the Moose pointers
     162             :   std::tuple<typename Input::gather_type *...> _input_ptr;
     163             : 
     164             :   /// current element index
     165             :   std::size_t _index;
     166             : 
     167             :   /// map from element ID to index
     168             :   std::map<dof_id_type, std::size_t> _index_map;
     169             : 
     170             :   friend struct BatchMaterialUtils::GatherVariable;
     171             : 
     172             :   friend struct BatchMaterialUtils::GatherVariableOld;
     173             : 
     174             : protected:
     175             :   /// Whether we should perform a batch compute
     176      720216 :   virtual bool shouldCompute() { return true; }
     177             : 
     178             : private:
     179             :   /// flag that indicates if _output_data has been fully computed
     180             :   bool _output_ready;
     181             : };
     182             : 
     183             : template <typename Tuple, typename Output, typename... Input>
     184             : template <int I, typename T, typename... Names>
     185             : void
     186          78 : BatchMaterial<Tuple, Output, Input...>::construct(T && name, Names &&... names)
     187             : {
     188             :   // couple the variable or material property
     189             :   typedef typename std::tuple_element<I, std::tuple<Input...>>::type CurrentElement;
     190          78 :   std::get<I>(_input_ptr) = CurrentElement::getPointer(*this, name);
     191             : 
     192             :   // recursively couple the next variable or material property
     193             :   if constexpr (sizeof...(Names) > 0)
     194          65 :     construct<I + 1, Names...>(std::forward<Names>(names)...);
     195          78 : }
     196             : 
     197             : template <typename Tuple, typename Output, typename... Input>
     198             : template <int I>
     199             : void
     200     4320000 : BatchMaterial<Tuple, Output, Input...>::copy(const unsigned int nqp)
     201             : {
     202             :   // copy all qp values for the current item
     203    21600000 :   for (const auto qp : make_range(nqp))
     204    17280000 :     Tuple::template get<I>(_input_data[_index + qp]) = (*std::get<I>(_input_ptr))[qp];
     205             : 
     206             :   // proceed to next item
     207             :   if constexpr (I + 1 < sizeof...(Input))
     208     3600000 :     copy<I + 1>(nqp);
     209     4320000 : }
     210             : 
     211             : template <typename Tuple, typename Output, typename... Input>
     212             : std::size_t
     213     1440000 : BatchMaterial<Tuple, Output, Input...>::getIndex(dof_id_type elem_id) const
     214             : {
     215     1440000 :   const auto it = _index_map.find(elem_id);
     216     1440000 :   if (it == _index_map.end())
     217           0 :     mooseError("Element ", elem_id, " was not found in the index map for ", name(), ".");
     218     1440000 :   return it->second;
     219             : }
     220             : 
     221             : template <typename Tuple, typename Output, typename... Input>
     222             : void
     223         108 : BatchMaterial<Tuple, Output, Input...>::initialize()
     224             : {
     225         108 :   _index = 0;
     226             : 
     227         108 :   if (shouldCompute())
     228         108 :     _output_ready = false;
     229         108 : }
     230             : 
     231             : template <typename Tuple, typename Output, typename... Input>
     232             : void
     233      720000 : BatchMaterial<Tuple, Output, Input...>::execute()
     234             : {
     235      720000 :   if (!shouldCompute())
     236           0 :     return;
     237             : 
     238             :   // update index map
     239      720000 :   _index_map[_current_elem->id()] = _index;
     240             : 
     241             :   // make sure the input data is sized sufficiently big
     242      720000 :   const auto nqp = _qrule->n_points();
     243      720000 :   if (_input_data.size() < _index + nqp)
     244       90000 :     _input_data.resize(_index + nqp);
     245             : 
     246             :   // copy data
     247      720000 :   copy<0>(nqp);
     248      720000 :   _index += nqp;
     249             : }
     250             : 
     251             : template <typename Tuple, typename Output, typename... Input>
     252             : void
     253           9 : BatchMaterial<Tuple, Output, Input...>::threadJoin(const UserObject & uo)
     254             : {
     255           9 :   if (!shouldCompute())
     256           0 :     return;
     257             : 
     258             :   // join maps (with index shift)
     259           9 :   const auto & bm = static_cast<const BatchMaterialType &>(uo);
     260       45009 :   for (const auto & [id, index] : bm._index_map)
     261       45000 :     _index_map[id] = index + _index;
     262             : 
     263             :   // make sure we have enough space
     264           9 :   const auto capacity = _input_data.capacity();
     265           9 :   if (capacity < _index + bm._index)
     266           1 :     _input_data.reserve(_index + bm._index);
     267             : 
     268             :   // concatenate input data
     269          18 :   _input_data.insert(std::begin(_input_data) + _index,
     270           9 :                      std::begin(bm._input_data),
     271           9 :                      std::begin(bm._input_data) + bm._index);
     272           9 :   _index += bm._index;
     273             : }
     274             : 
     275             : template <typename Tuple, typename Output, typename... Input>
     276             : void
     277          99 : BatchMaterial<Tuple, Output, Input...>::finalize()
     278             : {
     279          99 :   if (!shouldCompute())
     280           0 :     return;
     281             : 
     282             :   // resize the input and output data blocks to contain just the gathered items
     283             :   // (should be a no-op mostly)
     284          99 :   _input_data.resize(_index);
     285          99 :   _output_data.resize(_index);
     286          99 :   batchCompute();
     287             : 
     288          99 :   _output_ready = true;
     289             : }

Generated by: LCOV version 1.14