LCOV - code coverage report
Current view: top level - include/reporters - ReporterState.h (source / functions) Hit Total Coverage
Test: idaholab/moose framework: 2bf808 Lines: 47 50 94.0 %
Date: 2025-07-17 01:28:37 Functions: 135 465 29.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             : #pragma once
      10             : 
      11             : #include <iostream>
      12             : 
      13             : #include "libmesh/parallel.h"
      14             : #include "libmesh/parallel_object.h"
      15             : #include "libmesh/simple_range.h"
      16             : 
      17             : #include "ReporterName.h"
      18             : #include "RestartableData.h"
      19             : #include "ReporterMode.h"
      20             : 
      21             : // Forward declarations
      22             : class MooseObject;
      23             : class ReporterContextBase;
      24             : 
      25             : /**
      26             :  * The base class for storing a Reporter's state
      27             :  *
      28             :  * The base class is needed in order to store the states without a template
      29             :  * parameter so that they can be iterated through to observe the producers
      30             :  * and consumers.
      31             :  */
      32             : class ReporterStateBase
      33             : {
      34             : public:
      35             :   ReporterStateBase(const ReporterName & name);
      36     1243875 :   virtual ~ReporterStateBase() = default;
      37             : 
      38             :   /**
      39             :    * Return the ReporterName that this state is associated with
      40             :    */
      41      686204 :   const ReporterName & getReporterName() const { return _reporter_name; }
      42             : 
      43             :   /**
      44             :    * Add a consumer for this ReporterState
      45             :    * @param mode The mode that the object will consume the Reporter value
      46             :    * @param moose_object The MooseObject doing the consuming (for error reporting)
      47             :    * @see ReporterData
      48             :    */
      49             :   void addConsumer(ReporterMode mode, const MooseObject & moose_object);
      50             : 
      51             :   /**
      52             :    * Returns the consumers for this state; a pair that consists of the mode
      53             :    * that the state is being consumed by, and the object consuming it
      54             :    * @see ReporterContext
      55             :    */
      56      574955 :   const std::set<std::pair<ReporterMode, const MooseObject *>> & getConsumers() const
      57             :   {
      58      574955 :     return _consumers;
      59             :   }
      60             : 
      61             :   /**
      62             :    * @returns The type associated with this state
      63             :    */
      64             :   virtual std::string valueType() const = 0;
      65             : 
      66             :   /**
      67             :    * Sets the special Reporter type to a Postprocessor.
      68             :    *
      69             :    * See ReporterData::declareReporterValue.
      70             :    */
      71          12 :   void setIsPostprocessor() { _reporter_name.setIsPostprocessor(); }
      72             :   /**
      73             :    * Sets the special Reporter type to a VectorPostprocessor.
      74             :    *
      75             :    * See ReporterData::declareReporterValue.
      76             :    */
      77          12 :   void setIsVectorPostprocessor() { _reporter_name.setIsVectorPostprocessor(); }
      78             : 
      79             : private:
      80             :   /// Name of data that state is associated
      81             :   ReporterName _reporter_name;
      82             : 
      83             :   /// The consumers for this state; we store the MooseObject for detailed error reporting
      84             :   std::set<std::pair<ReporterMode, const MooseObject *>> _consumers;
      85             : };
      86             : 
      87             : /**
      88             :  * Custom sort for ReporterState::_consumers so that they are sorted by
      89             :  * object type, object name, and then mode, which makes for pretty output.
      90             :  */
      91             : bool operator<(const std::pair<ReporterMode, const MooseObject *> & a,
      92             :                const std::pair<ReporterMode, const MooseObject *> & b);
      93             : 
      94             : /**
      95             :  * A special version of RestartableData to aid in storing Reporter values. This object is
      96             :  * used by the ReporterData object. The objects provides a convenient method to define
      97             :  * Reporter data that has a value as well as some number of old data values. Please refer to
      98             :  * ReporterData.h for more information regarding the use of this class.
      99             :  *
     100             :  * @param name The name of the Reporter value
     101             :  *
     102             :  * This class stores the current/old/older/... data using a std::list to allow values to be inserted
     103             :  * into the data structure without corrupting references to the other values. This allows for
     104             :  * arbitrary time data to be stored.
     105             :  *
     106             :  * NOTE:
     107             :  * Access to the data should be through the value() method to ensure the data is allocated correctly
     108             :  */
     109             : template <typename T>
     110             : class ReporterState : public ReporterStateBase, public RestartableData<std::list<T>>
     111             : {
     112             : public:
     113             :   ReporterState(const ReporterName & name);
     114             : 
     115             :   ///@{
     116             :   /**
     117             :    * Return a reference to the current value or one of the old values.
     118             :    *
     119             :    * The time_index of 0 returns the current value, 1 returns old, 2 returns older, etc.
     120             :    */
     121             :   T & value(const std::size_t time_index = 0);
     122             :   const T & value(const std::size_t time_index = 0) const;
     123             :   ///@}
     124             : 
     125             :   /**
     126             :    * Copy stored values back in time to old/older etc.
     127             :    */
     128             :   void copyValuesBack();
     129             : 
     130             :   /**
     131             :    * Restore values to their old values, i.e. value(0) = value(1). This only occurs if old values
     132             :    * have been declared, which happens automatically for postprocessors.
     133             :    *
     134             :    * @return true State was restored
     135             :    * @return false State was NOT restored
     136             :    */
     137             :   bool restoreState();
     138             : 
     139          62 :   std::string valueType() const override final { return MooseUtils::prettyCppType<T>(); }
     140             : 
     141             :   /**
     142             :    * Loads and stores the data from/to a stream for restart
     143             :    *
     144             :    * This is a special version that handles the fact that the calls declare/getReporterValue
     145             :    * occur within the constructor of objects. As such, the storage list already contains data
     146             :    * and the references to this data must remain valid.
     147             :    *
     148             :    * The default dataLoad assumes the list being populated is empty and simply uses push_back.
     149             :    * Therefore, this function loads the data directly into the container to avoid this problem
     150             :    * and unnecessary copies.
     151             :    *
     152             :    * The default dataStore is very similar, but to ensure consistency (because we're re-defining
     153             :    * the load), we implement it again here.
     154             :    */
     155             :   ///@{
     156             :   void storeInternal(std::ostream & stream) override final;
     157             :   void loadInternal(std::istream & stream) override final;
     158             :   ///@}
     159             : };
     160             : 
     161             : template <typename T>
     162     1247515 : ReporterState<T>::ReporterState(const ReporterName & name)
     163     1247515 :   : ReporterStateBase(name), RestartableData<std::list<T>>(name.getRestartableName(), nullptr)
     164             : {
     165     1247515 : }
     166             : 
     167             : template <typename T>
     168             : T &
     169      148539 : ReporterState<T>::value(const std::size_t time_index)
     170             : {
     171             :   // Initialize the data; the first entry is the "current" data
     172      148539 :   if (this->get().empty())
     173       77633 :     this->set().resize(1);
     174             : 
     175             :   // If we are a postprocessor, we want to always store an old value so that we can restore the data
     176             :   // if needed. See restoreState.
     177             :   // Note: This can easily be extended to other states like vector-postprocessors or any other
     178             :   // reporter value. However, these states have indeterminate sizes and could create significant,
     179             :   // unecessary memory overhead. In the future, we can extend this to other reporter types if
     180             :   // the need justifies the overhead.
     181      148539 :   if (this->getReporterName().isPostprocessor() && time_index == 0 && this->get().size() <= 1)
     182       50342 :     this->set().push_back(this->get().back());
     183             : 
     184             :   // Initialize old, older, ... data
     185      148539 :   if (this->get().size() <= time_index)
     186        5222 :     this->set().resize(time_index + 1, this->get().back());
     187             : 
     188      148539 :   return *(std::next(this->set().begin(), time_index));
     189             : }
     190             : 
     191             : template <typename T>
     192             : const T &
     193     1114238 : ReporterState<T>::value(const std::size_t time_index) const
     194             : {
     195     1114238 :   if (this->get().size() <= time_index)
     196           0 :     mooseError("The desired time index ",
     197             :                time_index,
     198             :                " does not exists for the '",
     199             :                getReporterName(),
     200             :                "' Reporter value, which contains ",
     201           0 :                this->get().size(),
     202             :                " old value(s). The getReporterValue method must be called with the desired time "
     203             :                "index to be able to access data.");
     204     1114238 :   return *(std::next(this->get().begin(), time_index));
     205             : }
     206             : 
     207             : template <typename T>
     208             : void
     209      229607 : ReporterState<T>::copyValuesBack()
     210             : {
     211      229607 :   std::list<T> & values = this->set();
     212      229607 :   for (typename std::list<T>::reverse_iterator iter = values.rbegin();
     213      431264 :        std::next(iter) != values.rend();
     214      201657 :        ++iter)
     215      201657 :     (*iter) = (*std::next(iter));
     216      229607 : }
     217             : 
     218             : template <typename T>
     219             : bool
     220        9618 : ReporterState<T>::restoreState()
     221             : {
     222        9618 :   if (this->get().size() <= 1)
     223         530 :     return false;
     224             : 
     225        9088 :   this->set().front() = *std::next(this->get().begin());
     226        9088 :   return true;
     227             : }
     228             : 
     229             : template <typename T>
     230             : void
     231       41400 : ReporterState<T>::storeInternal(std::ostream & stream)
     232             : {
     233             :   // Store the container size
     234       41400 :   std::size_t size = this->get().size();
     235       41400 :   dataStore(stream, size, nullptr);
     236             : 
     237             :   // Store each entry of the list directly into the storage
     238      128662 :   for (auto & val : this->set())
     239       87262 :     storeHelper(stream, val, nullptr);
     240       41400 : }
     241             : 
     242             : template <typename T>
     243             : void
     244       10814 : ReporterState<T>::loadInternal(std::istream & stream)
     245             : {
     246             :   // Read the container size
     247       10814 :   std::size_t size = 0;
     248       10814 :   dataLoad(stream, size, nullptr);
     249             : 
     250       10814 :   auto & values = this->set();
     251             : 
     252             :   // If the current container is undersized, expand it to fit the loaded data
     253       10814 :   if (values.size() < size)
     254           0 :     values.resize(size);
     255             : 
     256             :   // Load each entry of the list directly into the storage
     257             :   // Because we don't shrink the container if the stored size is smaller than
     258             :   // our declared size, we have the odd iterator combo you see below
     259       32819 :   for (auto & val : as_range(values.begin(), std::next(values.begin(), size)))
     260       22005 :     loadHelper(stream, val, nullptr);
     261       10814 : }

Generated by: LCOV version 1.14