SpECTRE Documentation Coverage Report
Current view: top level - IO/Observer - Tags.hpp Hit Total Coverage
Commit: 3ffcbc8ecf43797401b60bcca17d6040ee06f013 Lines: 23 64 35.9 %
Date: 2026-03-03 02:01:44
Legend: Lines: hit not hit

          Line data    Source code
       1           0 : // Distributed under the MIT License.
       2             : // See LICENSE.txt for details.
       3             : 
       4             : #pragma once
       5             : 
       6             : #include <atomic>
       7             : #include <converse.h>
       8             : #include <cstddef>
       9             : #include <memory>
      10             : #include <set>
      11             : #include <string>
      12             : #include <unordered_map>
      13             : #include <unordered_set>
      14             : #include <vector>
      15             : 
      16             : #include "DataStructures/DataBox/Tag.hpp"
      17             : #include "DataStructures/DataVector.hpp"
      18             : #include "IO/H5/TensorData.hpp"
      19             : #include "IO/Observer/ObservationId.hpp"
      20             : #include "Options/String.hpp"
      21             : #include "Parallel/ArrayComponentId.hpp"
      22             : #include "Parallel/NodeLock.hpp"
      23             : #include "Parallel/Reduction.hpp"
      24             : #include "Utilities/PrettyType.hpp"
      25             : 
      26             : namespace observers {
      27             : /// \ingroup ObserversGroup
      28             : /// %Tags used on the observer parallel component
      29           1 : namespace Tags {
      30             : /// \brief The set of `ArrayComponentId`s that will contribute to each
      31             : /// `ObservationId` for reduction.
      32             : ///
      33             : /// This is set during registration is only read from later on in the
      34             : /// simulation, except for possibly during migration of an `ArrayComponentId`
      35             : /// component.
      36           1 : struct ExpectedContributorsForObservations : db::SimpleTag {
      37           0 :   using type =
      38             :       std::unordered_map<ObservationKey,
      39             :                          std::unordered_set<Parallel::ArrayComponentId>>;
      40             : };
      41             : 
      42             : /// \brief The set of `ArrayComponentId` that have contributed to each
      43             : /// `ObservationId` for reductions
      44             : ///
      45             : /// The tag is used both on the `Observer` and on the `ObserverWriter`
      46             : /// components since all we need to do is keep track of array component IDs in
      47             : /// both cases.
      48           1 : struct ContributorsOfReductionData : db::SimpleTag {
      49           0 :   using type =
      50             :       std::unordered_map<ObservationId,
      51             :                          std::unordered_set<Parallel::ArrayComponentId>>;
      52             : };
      53             : 
      54             : /// \brief The set of nodes that have contributed to each `ObservationId` for
      55             : /// writing reduction data
      56             : ///
      57             : /// This is used on node 0 (or whichever node has been designated as the one to
      58             : /// write the reduction files). The `unordered_set` is the node IDs that have
      59             : /// contributed so far.
      60           1 : struct NodesThatContributedReductions : db::SimpleTag {
      61           0 :   using type = std::unordered_map<ObservationId, std::unordered_set<size_t>>;
      62             : };
      63             : 
      64             : /// \brief The set of nodes that are registered with each
      65             : /// `ObservationIdRegistrationKey` for writing reduction data
      66             : ///
      67             : /// The set contains all the nodes that have been registered.
      68             : ///
      69             : /// We need to keep track of this separately from the local reductions on the
      70             : /// node that are contributing so we need a separate tag. Since nodes are easily
      71             : /// indexed by an unsigned integer, we use `size_t` to keep track of them.
      72           1 : struct NodesExpectedToContributeReductions : db::SimpleTag {
      73           0 :   using type = std::unordered_map<ObservationKey, std::set<size_t>>;
      74             : };
      75             : 
      76             : /// \brief Lock used when contributing reduction data.
      77             : ///
      78             : /// A separate lock from the node lock of the nodegroup is used in order to
      79             : /// allow other cores to contribute volume data, write to disk, etc.
      80           1 : struct ReductionDataLock : db::SimpleTag {
      81           0 :   using type = Parallel::NodeLock;
      82             : };
      83             : 
      84             : /// \brief The set of `ArrayComponentId` that have contributed to each
      85             : /// `ObservationId` for volume observation
      86             : ///
      87             : /// The tag is used both on the `Observer` and on the `ObserverWriter`
      88             : /// components since all we need to do is keep track of array component IDs in
      89             : /// both cases.
      90           1 : struct ContributorsOfTensorData : db::SimpleTag {
      91           0 :   using type =
      92             :       std::unordered_map<ObservationId,
      93             :                          std::unordered_set<Parallel::ArrayComponentId>>;
      94             : };
      95             : 
      96             : /// Volume tensor data to be written to disk.
      97           1 : struct TensorData : db::SimpleTag {
      98           0 :   using type = std::unordered_map<
      99             :       observers::ObservationId,
     100             :       std::unordered_map<Parallel::ArrayComponentId, ElementVolumeData>>;
     101             : };
     102             : 
     103             : /// Volume tensor data to be written to disk from the Interpolator
     104           1 : struct InterpolatorTensorData : db::SimpleTag {
     105           0 :   using type =
     106             :       std::unordered_map<observers::ObservationId,
     107             :                          std::unordered_map<Parallel::ArrayComponentId,
     108             :                                             std::vector<ElementVolumeData>>>;
     109             : };
     110             : 
     111             : /// Map of serialized FunctionOfTime data for volume data to be written.
     112           1 : struct SerializedFunctionsOfTime : db::SimpleTag {
     113           0 :   using type =
     114             :       std::unordered_map<ObservationId, std::optional<std::vector<char>>>;
     115             : };
     116             : 
     117             : /// Map of ObservationIds that have dependencies for volume data to be written
     118             : /// and whether or not the dependency has the volume data being written or
     119             : /// discarded.
     120           1 : struct Dependencies : db::SimpleTag {
     121           0 :   using type = std::unordered_map<ObservationId, std::pair<std::string, bool>>;
     122             : };
     123             : 
     124             : /// \cond
     125             : template <class... ReductionDatums>
     126             : struct ReductionDataNames;
     127             : /// \endcond
     128             : 
     129             : /// Reduction data to be written to disk.
     130             : ///
     131             : /// If we have `M` `ArrayComponentIds` registered with a given `Observer`
     132             : /// for a given `ObservationId`, then we expect the `Observer` to receive
     133             : /// `M` contributions with the given `ObservationId`. We combine the reduction
     134             : /// data as we receive it, so we only need one copy for each `ObservationId`.
     135             : template <class... ReductionDatums>
     136           1 : struct ReductionData : db::SimpleTag {
     137           0 :   using type = std::unordered_map<observers::ObservationId,
     138             :                                   Parallel::ReductionData<ReductionDatums...>>;
     139           0 :   using names_tag = ReductionDataNames<ReductionDatums...>;
     140             : };
     141             : 
     142             : /// Names of the reduction data to be written to disk.
     143             : template <class... ReductionDatums>
     144           1 : struct ReductionDataNames : db::SimpleTag {
     145           0 :   using type =
     146             :       std::unordered_map<observers::ObservationId, std::vector<std::string>>;
     147           0 :   using data_tag = ReductionData<ReductionDatums...>;
     148             : };
     149             : 
     150             : /// Node lock used when needing to read/write to H5 files on disk.
     151             : ///
     152             : /// The reason for only having one lock for all files is that we currently don't
     153             : /// require a thread-safe HDF5 installation. In the future we will need to
     154             : /// experiment with different HDF5 configurations.
     155           1 : struct H5FileLock : db::SimpleTag {
     156           0 :   using type = Parallel::NodeLock;
     157             : };
     158             : 
     159             : /*!
     160             :  * \brief A string identifying observations related to the `Tag`.
     161             :  *
     162             :  * For example, the `Tag` could refer to the block in the computational domain
     163             :  * and the `ObservationKey` holds the name of the block, so reduction
     164             :  * observations can be registered per-block. A value of `std::nullopt` means
     165             :  * that the element doesn't participate in observations related to the `Tag`.
     166             :  *
     167             :  * This tag only provides a way to store and share the observation key related
     168             :  * to the `Tag`. How it is used to construct composite observation keys or
     169             :  * subfile paths is up to the code that performs the observations.
     170             :  */
     171             : template <typename Tag>
     172           1 : struct ObservationKey : db::SimpleTag {
     173           0 :   using type = std::optional<std::string>;
     174           0 :   static std::string name() {
     175             :     return "ObservationKey(" + pretty_type::name<Tag>() + ")";
     176             :   }
     177             : };
     178             : 
     179             : }  // namespace Tags
     180             : 
     181             : /// \ingroup ObserversGroup
     182             : /// Option tags related to recording data
     183           1 : namespace OptionTags {
     184             : /// Groups option tags related to recording data, e.g. file names.
     185           1 : struct Group {
     186           0 :   static std::string name() { return "Observers"; }
     187           0 :   static constexpr Options::String help = {"Options for recording data"};
     188             : };
     189             : 
     190             : /// The name of the H5 file on disk to which all volume data is written.
     191           1 : struct VolumeFileName {
     192           0 :   using type = std::string;
     193           0 :   static constexpr Options::String help = {
     194             :       "Name of the volume data file without extension"};
     195           0 :   using group = Group;
     196             : };
     197             : 
     198             : /// The name of the H5 file on disk to which all reduction data is written.
     199           1 : struct ReductionFileName {
     200           0 :   using type = std::string;
     201           0 :   static constexpr Options::String help = {
     202             :       "Name of the reduction data file without extension"};
     203           0 :   using group = Group;
     204             : };
     205             : 
     206             : /// The name of the H5 file on disk to which all surface data is written.
     207           1 : struct SurfaceFileName {
     208           0 :   using type = std::string;
     209           0 :   static constexpr Options::String help = {
     210             :       "Name of the surface data file without extension"};
     211           0 :   using group = Group;
     212             : };
     213             : }  // namespace OptionTags
     214             : 
     215             : namespace Tags {
     216             : /// \brief The name of the HDF5 file on disk into which volume data is
     217             : /// written.
     218             : ///
     219             : /// By volume data we mean any data that is not written once across all nodes.
     220             : /// For example, data on a 2d surface written from a 2d simulation is
     221             : /// considered volume data, while an integral over the entire (or a subset of
     222             : /// the) domain is considered reduction data. Data for a 2d surface in
     223             : /// a 3d simulation, such as a horizon, is considered surface data and
     224             : /// is written to a file specified by SurfaceFileName.
     225           1 : struct VolumeFileName : db::SimpleTag {
     226           0 :   using type = std::string;
     227           0 :   using option_tags = tmpl::list<::observers::OptionTags::VolumeFileName>;
     228             : 
     229           0 :   static constexpr bool pass_metavariables = false;
     230           0 :   static std::string create_from_options(const std::string& volume_file_name) {
     231             :     return volume_file_name;
     232             :   }
     233             : };
     234             : 
     235             : /// \brief The name of the HDF5 file on disk into which reduction data is
     236             : /// written.
     237             : ///
     238             : /// By reduction data we mean any data that is written once across all nodes.
     239             : /// For example, an integral over the entire (or a subset of the) domain
     240             : /// is considered reduction data, while data on a 3d surface written from a 3d
     241             : /// simulation is considered volume data. Data for a 2d surface in
     242             : /// a 3d simulation, such as a horizon, is considered surface data and
     243             : /// is written to a file specified by SurfaceFileName.
     244           1 : struct ReductionFileName : db::SimpleTag {
     245           0 :   using type = std::string;
     246           0 :   using option_tags = tmpl::list<::observers::OptionTags::ReductionFileName>;
     247             : 
     248           0 :   static constexpr bool pass_metavariables = false;
     249           0 :   static std::string create_from_options(
     250             :       const std::string& reduction_file_name) {
     251             :     return reduction_file_name;
     252             :   }
     253             : };
     254             : 
     255             : /// \brief The name of the HDF5 file on disk into which surface data is
     256             : /// written.
     257             : ///
     258             : /// By surface data we mean data for a 2d surface in
     259             : /// a 3d simulation, such as a horizon. Surface data is written once across
     260             : /// all nodes. For example, data on a 2d surface written from a 2d simulation is
     261             : /// considered volume data, while an integral over the entire (or a subset of
     262             : /// the) domain is considered reduction data.
     263           1 : struct SurfaceFileName : db::SimpleTag {
     264           0 :   using type = std::string;
     265           0 :   using option_tags = tmpl::list<::observers::OptionTags::SurfaceFileName>;
     266             : 
     267           0 :   static constexpr bool pass_metavariables = false;
     268           0 :   static std::string create_from_options(const std::string& surface_file_name) {
     269             :     return surface_file_name;
     270             :   }
     271             : };
     272             : }  // namespace Tags
     273             : }  // namespace observers

Generated by: LCOV version 1.14