Data output in Schnek is handled by ``Diagnostic`` classes. These classes inherit from the ``Block`` class and thus can be controlled by the simulation's setup file. The typical behaviour of ``Diagnostic`` classes is to write some data to files at specified intervals. In general the ``Diagnostic`` classes do not have to be called directly as this is handled by the ``DiagnosticManager``. DiagnosticManager is a singleton class that defines a number of methods used to control diagnostic output. It stores all instances of the ``Diagnostic`` class and keeps track of the current time. :: class DiagnosticManager { public: static const DiagnosticManager& instance(); void setTimeCounter(int *timecounter); void setPhysicalTime(double *physicalTime); void execute(); double adjustDeltaT(double deltaT); // the following functions are not usually called directly void addIntervalDiagnostic(IntervalDiagnostic*); void addDeltaTimeDiagnostic(DeltaTimeDiagnostic*); }; Being a singleton you can not create instances of the ``DiagnosticManager`` directly. Instead you need to access the singleton instance through the static ``instance()`` method. The ``Diagnostic`` class has two sub-classes that handle two different types of diagnotic. ``IntervalDiagnostic`` will write out data after a given number of simulation steps, whereas ``DeltaTimeDiagnostic`` will write out data after a specified physical time. The functions ``addIntervalDiagnostic()`` and ``addDeltaTimeDiagnostic()`` are used to add diagnostic instances to the manager. These functions are not usually called directly. Every instance of the ``IntervalDiagnostic`` or ``DeltaTimeDiagnostic`` will automatically call the relevant function to add itself to the ``DiagnosticManager``. The simulation code should, however, supply a reference to either a time counter or a physical time through the functions ``setTimeCounter()`` and ``setPhysicalTime()``. The argument is a pointer to the global simulation time step or the global physical simulation time. The pointer must be valid throughout the duration of the simulation. Usually these functions should be called once during the startup of the simulation. Note that only one of the two functions must be set if the simulation defines only ``IntervalDiagnostic`` or only ``DeltaTimeDiagnostic`` classes. On the other hand it is allowed to mix the two types in a single simulation. While the simulation is running the global time step counter or the physical simulation time (or both) should be during after each simulation step. After carrying out the numerical simulation step, a call to ``execute()`` will iterate through all registered ``Diagnostic`` output objects and check if any data needs to be written. A skeleton of a simulation loop is outlined below. :: int timeStep = 0; double time = 0.0; void run() { DiagnosticManager::instance().setTimeCounter(&timeStep); DiagnosticManager::instance().setPhysicalTime(&time); while (time <= simulationEndTime) { doSimulationStep(); ++timeStep; time += dt; DiagnosticManager::instance().execute(); } } Another function that can be useful when using the physical simulation time is ``adjustDeltaT()``. This function is intended to be called before the numerical simulation step. Consider the case in which the natural simulation time step ``dt`` is 0.2 but one of the diagnostic outputs is requested through the setup file after a physical time interval of 0.5. When the simulation time is 0.4 the next time step would take it to 0.6, way beyond the desired output time of 0.5. The ``adjustDeltaT()`` calculates the next simulation time step, based on the base time step and the time of the next diagnotic outputs. The code skeleton below illustrates how it can be used. :: int timeStep = 0; double time = 0.0; double dt = 0.2; void run() { DiagnosticManager::instance().setTimeCounter(&timeStep); DiagnosticManager::instance().setPhysicalTime(&time); while (time <= simulationEndTime) { double dtAdjust = DiagnosticManager::instance().adjustDeltaT(dt); doSimulationStep(dtAdjust); ++timeStep; time += dtAdjust; DiagnosticManager::instance().execute(); } } A **serious warning** comes with this feature. Many numerical schemes use staggered time steps, such as leap-frog schemes. Changing the time step during the simulation can reduce the accuracy of the numerical scheme drastically. It is therefore advised to only use the ``adjustDeltaT()`` function if you **know** that your numerical scheme is not affected by this.