diff --git a/include/bout/options_io.hxx b/include/bout/options_io.hxx index 509305aad0..19bc7430b1 100644 --- a/include/bout/options_io.hxx +++ b/include/bout/options_io.hxx @@ -1,3 +1,17 @@ +#pragma once + +#ifndef OPTIONS_IO_H +#define OPTIONS_IO_H + +#include "bout/build_defines.hxx" +#include "bout/generic_factory.hxx" +#include "bout/options.hxx" + +#include +#include + +namespace bout { + /// Parent class for IO to binary files and streams /// /// @@ -29,21 +43,6 @@ /// auto file = OptionsIO::create("some_file.nc"); /// /// - -#pragma once - -#ifndef OPTIONS_IO_H -#define OPTIONS_IO_H - -#include "bout/build_defines.hxx" -#include "bout/generic_factory.hxx" -#include "bout/options.hxx" - -#include -#include - -namespace bout { - class OptionsIO { public: /// No default constructor, as settings are required @@ -51,7 +50,7 @@ public: /// Constructor specifies the kind of file, and options to control /// the name of file, mode of operation etc. - OptionsIO(Options&) {} + OptionsIO(Options& /*unused*/) {} virtual ~OptionsIO() = default; @@ -73,6 +72,9 @@ public: /// ADIOS: Indicate completion of an output step. virtual void verifyTimesteps() const = 0; + /// NetCDF: Flush file to disk + virtual void flush() {} + /// Create an OptionsIO for I/O to the given file. /// This uses the default file type and default options. static std::unique_ptr create(const std::string& file); diff --git a/include/bout/physicsmodel.hxx b/include/bout/physicsmodel.hxx index 9fa25d8b0f..fa24af8c47 100644 --- a/include/bout/physicsmodel.hxx +++ b/include/bout/physicsmodel.hxx @@ -376,6 +376,9 @@ protected: PhysicsModel* model; }; + /// Set timestep counter for flushing file + void setFlushCounter(std::size_t iteration) { flush_counter = iteration; } + private: /// State for outputs Options output_options; @@ -399,6 +402,10 @@ private: bool initialised{false}; /// write restarts and pass outputMonitor method inside a Monitor subclass PhysicsModelMonitor modelMonitor{this}; + /// How often to flush to disk + std::size_t flush_frequency{1}; + /// Current timestep counter + std::size_t flush_counter{0}; }; /*! diff --git a/src/physics/physicsmodel.cxx b/src/physics/physicsmodel.cxx index f4be3bde2a..a6d1c44733 100644 --- a/src/physics/physicsmodel.cxx +++ b/src/physics/physicsmodel.cxx @@ -34,12 +34,14 @@ #include "bout/version.hxx" #include +#include #include #include #include #include +#include #include using namespace std::literals; @@ -67,9 +69,10 @@ PhysicsModel::PhysicsModel() .withDefault(true)), restart_enabled(Options::root()["restart_files"]["enabled"] .doc("Write restart files") - .withDefault(true)) - -{ + .withDefault(true)), + flush_frequency(Options::root()["output"]["flush_frequency"] + .doc("How often to flush to disk") + .withDefault(1)) { if (output_enabled) { output_file = bout::OptionsIOFactory::getInstance().createOutput(); } @@ -189,7 +192,7 @@ int PhysicsModel::postInit(bool restarting) { } void PhysicsModel::outputVars(Options& options) { - Timer time("io"); + const Timer time("io"); for (const auto& item : dump.getData()) { bout::utils::visit(bout::OptionsConversionVisitor{options, item.name}, item.value); if (item.repeat) { @@ -199,7 +202,7 @@ void PhysicsModel::outputVars(Options& options) { } void PhysicsModel::restartVars(Options& options) { - Timer time("io"); + const Timer time("io"); for (const auto& item : restart.getData()) { bout::utils::visit(bout::OptionsConversionVisitor{options, item.name}, item.value); if (item.repeat) { @@ -217,9 +220,7 @@ void PhysicsModel::writeRestartFile() { void PhysicsModel::writeOutputFile() { writeOutputFile(output_options); } void PhysicsModel::writeOutputFile(const Options& options) { - if (output_enabled) { - output_file->write(options, "t"); - } + writeOutputFile(options, "t"); } void PhysicsModel::writeOutputFile(const Options& options, @@ -230,13 +231,19 @@ void PhysicsModel::writeOutputFile(const Options& options, } void PhysicsModel::finishOutputTimestep() const { - if (output_enabled) { + const Timer timer("io"); + + if (output_enabled and (flush_counter % flush_frequency == 0)) { + output_file->flush(); output_file->verifyTimesteps(); } } int PhysicsModel::PhysicsModelMonitor::call(Solver* solver, BoutReal simtime, int iteration, int nout) { + + model->setFlushCounter(static_cast(iteration)); + // Restart file variables solver->outputVars(model->restart_options, false); model->restartVars(model->restart_options); @@ -255,5 +262,8 @@ int PhysicsModel::PhysicsModelMonitor::call(Solver* solver, BoutReal simtime, model->outputVars(model->output_options); model->writeOutputFile(); + // Reset output options, this avoids rewriting time-independent data + model->output_options = Options{}; + return monitor_result; } diff --git a/src/sys/options/options_netcdf.cxx b/src/sys/options/options_netcdf.cxx index 60dfba2102..a043aa1d13 100644 --- a/src/sys/options/options_netcdf.cxx +++ b/src/sys/options/options_netcdf.cxx @@ -733,10 +733,10 @@ void OptionsNetCDF::write(const Options& options, const std::string& time_dim) { } writeGroup(options, *data_file, time_dim); - - data_file->sync(); } +void OptionsNetCDF::flush() { data_file->sync(); } + } // namespace bout #endif // BOUT_HAS_NETCDF diff --git a/src/sys/options/options_netcdf.hxx b/src/sys/options/options_netcdf.hxx index 09a2da3220..9a9645c35a 100644 --- a/src/sys/options/options_netcdf.hxx +++ b/src/sys/options/options_netcdf.hxx @@ -39,7 +39,7 @@ public: /// - "append" File mode, default is false OptionsNetCDF(Options& options); - ~OptionsNetCDF() {} + ~OptionsNetCDF() override = default; OptionsNetCDF(const OptionsNetCDF&) = delete; OptionsNetCDF(OptionsNetCDF&&) noexcept = default; @@ -50,7 +50,6 @@ public: Options read(bool lazy = true) override; /// Write options to file - void write(const Options& options) { write(options, "t"); } void write(const Options& options, const std::string& time_dim) override; /// Check that all variables with the same time dimension have the @@ -58,6 +57,9 @@ public: /// any differences, otherwise is silent void verifyTimesteps() const override; + /// Flush file to disk + void flush() override; + private: enum class FileMode { replace, ///< Overwrite file when writing @@ -74,7 +76,7 @@ private: }; namespace { -RegisterOptionsIO registeroptionsnetcdf("netcdf"); +const inline RegisterOptionsIO registeroptionsnetcdf("netcdf"); } } // namespace bout