.. _program_listing_file_src_io_OutputManagerH5.hpp: Program Listing for File OutputManagerH5.hpp ============================================ |exhale_lsh| :ref:`Return to documentation for file ` (``src/io/OutputManagerH5.hpp``) .. |exhale_lsh| unicode:: U+021B0 .. UPWARDS ARROW WITH TIP LEFTWARDS .. code-block:: cpp #ifndef OUTPUTMANAGERH5_HPP #define OUTPUTMANAGERH5_HPP #include "../utils/ThreadVec.hpp" #include "OutputManager.hpp" #include "SimControls.hpp" #include "hdf5.h" // NOLINT(misc-include-cleaner) #include #include #include namespace core { class Cluster; class Galaxy; } // namespace core namespace io { class OutputManagerH5 : public OutputManager { public: explicit OutputManagerH5(const SimControls& simControls, bool restart = false); ~OutputManagerH5() override; OutputManagerH5(const OutputManagerH5&) = delete; auto operator=(const OutputManagerH5&) -> OutputManagerH5& = delete; OutputManagerH5(OutputManagerH5&&) = delete; auto operator=(OutputManagerH5&&) -> OutputManagerH5& = delete; void writeCluster(unsigned long trial, const core::Cluster& cluster) override; void writeClusterSpec(unsigned long trial, double time, core::Cluster& cluster) override; void writeClusterPhot(unsigned long trial, double time, core::Cluster& cluster) override; void writeClusterYields(unsigned long trial, double time, core::Cluster& cluster) override; void writeGalaxy(unsigned long trial, double time, core::Galaxy& galaxy) override; void writeGalaxySpec(unsigned long trial, double time, core::Galaxy& galaxy) override; void writeGalaxyPhot(unsigned long trial, double time, core::Galaxy& galaxy) override; void writeGalaxyYields(unsigned long trial, double time, core::Galaxy& galaxy) override; void writeClusterFeedback(unsigned long trial, double time, core::Cluster& cluster) override; void writeGalaxyFeedback(unsigned long trial, double time, core::Galaxy& galaxy) override; void checkpoint(unsigned long trialsCompleted) override; [[nodiscard]] auto restartTrialsDone() const -> unsigned long override { return restartTrialsDone_; } [[nodiscard]] auto restartMaxTrial() const -> unsigned long override { return restartMaxTrial_; } void notifyEarlyTermination(unsigned long trialsCompleted) override { earlyTerminationTrialsCompleted_ = trialsCompleted; } private: void restartSetup(); [[nodiscard]] auto findRestartUidForRank(unsigned long maxCheckpoint) const -> std::optional; void openNewOutputFiles(); [[nodiscard]] auto checkpointModelName(unsigned long checkpointNum) const -> std::string; void openOutputFile(const std::filesystem::path& path); void closeOutputFile(unsigned long trialsCompleted); void syncCheckpoints(unsigned long trialsCompleted); static void consolidateFiles(const std::filesystem::path& path); void openClustersGroup(); void openClusterSpectraGroup(); void openClusterPhotGroup(); void openClusterYieldsGroup(); void openGalaxyGroup(); void openGalaxySpectraGroup(); void openGalaxyPhotGroup(); void openGalaxyYieldsGroup(); void openClusterFeedbackGroup(); void openGalaxyFeedbackGroup(); // Number of times checkpoint() has rolled over to a new // checkpoint; 0 until the first call. Only meaningful if // SimControls::checkpointInterval() is non-zero -- see // checkpointModelName()/openNewOutputFiles(). Not a ThreadVec // like the handles below, despite (like them) being read/ // written from inside a "#pragma omp parallel" region: unlike // those, this is one single, shared value describing the // whole checkpoint set every thread's own file currently // belongs to, not a separate value per thread -- and it is // only ever mutated between parallel regions (see // checkpoint()'s own comment for why), never concurrently, so // it needs no locking of its own either. unsigned long checkpointNumber_ = 0; // The largest trial number ever actually passed to any write* // method over this object's own whole lifetime (0 before the // first one, or if this is a restart with nothing written yet // this session -- see below) -- unlike checkpointNumber_/ // restartTrialsDone_ above, this genuinely is touched // concurrently, from inside every write* method's own // "#pragma omp critical(h5ThreadSafety)" block (see e.g. // writeCluster()'s own comment), which is exactly why it is // safe without any locking of its own: only one thread is ever // inside that critical section at a time, regardless of which // write* method it entered through. // // Deliberately never reset between checkpoints (unlike // checkpointNumber_, which advances by one every rollover): // if this object's constructor set restartMaxTrial_ (restart // = true and a previous checkpoint was found), it also // initializes this to that same value, so it already reflects // every trial number the run being restarted ever wrote, // before this session writes any of its own -- otherwise, if a // restarted session were itself interrupted again having // written nothing new yet, its own checkpoint's "max_trial" // attribute (see closeOutputFile()'s own comment) would // wrongly read back as 0 on a later restart, colliding new // numbering with everything already written in earlier // sessions. See restartSetup()'s own comment for how the // value written here gets read back in. unsigned long maxTrial_ = 0; // Number of trials the run being restarted had already // completed, as of the checkpoint restartSetup() found and // resumed from -- 0 if this OutputManagerH5 was not // constructed with restart = true, or if restartSetup() found // no checkpoint to resume from. Set once, by restartSetup(), // before openNewOutputFiles() is ever called, and never // written again afterward, so (like checkpointNumber_ above) // it needs no locking of its own despite being read from // inside a "#pragma omp parallel" region by restartTrialsDone()'s // own callers. unsigned long restartTrialsDone_ = 0; // The largest trial number restartSetup() found the run being // restarted had ever actually written, as of the checkpoint it // resumed from -- 0 under the same conditions restartTrialsDone_ // is 0 (see its own comment). Same locking rationale as // restartTrialsDone_ (set once, before openNewOutputFiles()). unsigned long restartMaxTrial_ = 0; // Set by notifyEarlyTermination(), from outside any active // parallel region, at most once, strictly before this object // is ever destroyed (see its own comment) -- read only by the // destructor itself, single-threaded, so (like // checkpointNumber_/restartTrialsDone_ above) needs no locking // of its own. std::nullopt (the default) means this run ended // normally, having completed every trial -- the destructor's // own long-standing assumption, unchanged from before this // existed. std::optional earlyTerminationTrialsCompleted_; // Each thread's own copy of every HDF5 handle below is // private to it -- see this class's own header comment on why // -- reset to -1 (the "not open" sentinel) by openOutputFile() // itself, for the calling thread's own slot alone, just before // that thread's own file is opened; see openNewOutputFiles()'s // own comment for why this happens there rather than as a // separate, whole-ThreadVec reset up front the way earlier, // pre-checkpointing code did. utils::ThreadVec file_; // NOLINT(misc-include-cleaner) utils::ThreadVec clustersGroup_; // NOLINT(misc-include-cleaner) utils::ThreadVec clusterSpectraGroup_; // NOLINT(misc-include-cleaner) utils::ThreadVec clusterPhotGroup_; // NOLINT(misc-include-cleaner) utils::ThreadVec clusterYieldsGroup_; // NOLINT(misc-include-cleaner) utils::ThreadVec galaxyGroup_; // NOLINT(misc-include-cleaner) utils::ThreadVec galaxySpectraGroup_; // NOLINT(misc-include-cleaner) utils::ThreadVec galaxyPhotGroup_; // NOLINT(misc-include-cleaner) utils::ThreadVec galaxyYieldsGroup_; // NOLINT(misc-include-cleaner) utils::ThreadVec clusterFeedbackGroup_; // NOLINT(misc-include-cleaner) utils::ThreadVec galaxyFeedbackGroup_; // NOLINT(misc-include-cleaner) }; } // namespace io #endif // OUTPUTMANAGERH5_HPP