![]() |
As mentioned in the previous section, a simulator is a C++ class which defines mandatory methods (see Mandatory methods to be defined). These methods are called by the OpenFLUID framework at the right time during the simulation, following the interactions sequence in the figure below.
Among these methods, the initializeRun() and runStep() methods have a special behaviour: these two methods must return the simulation time when the simulator will be called again.
This simulation time can be
Example for a fixed time step simulator, with a time step equal to the default DeltaT value given in the input dataset:
Example for a variable time step simulator, based on the internal computation of the simulator:
For fully synchronized coupled simulators, all simulators must return the same duration for the next calling, usually DefaultDeltaT() .
Simulation data exchanged through the OpenFLUID framework should be typed with an OpenFLUID defined type.
The available simple types are:
The available compound types are:
A specific type is available for storing non-existing values:
Simulation data are stored using these types :
Each data type can be converted to and from openfluid::core::StringValue (as far as the string format is correct). String representations of values are (see String representation of values)
Simulation variables can be typed or untyped. This is set at the declaration of these variables (see Simulation variables).
In case of typed variables, each value of the variable must be of the type of the variable. In case of untyped variables, values for the variable can be of any type.
The spatial graph represents the spatial domain where coupled simulators will operate. Parsing this graph in different ways is a common task in simulators. This graph can be browsed using predefined macros.
Spatial units can be parsed following the process order by using the following OpenFLUID macros:
To parse a specific list of of spatial units, you can use the macro:
The source code below shows spatial graph parsing examples. The first part of the source code shows how to browse all units of the SU units class, and how to browse the "From" units for each SU unit. The second part of the source code shows how to browse all units of the spatial domain.
A process defined as a method of a simulator class can be applied in parallel to the spatial graph, following the process order, using the following methods:
The first argument of the method passed to the macro must be a pointer to an as it represents the currently processed spatial unit.
The code below shows how to apply a method in parallel over the spatial graph:
Please note:
Concurrent parsing using multithreading should improve computing performance, reducing simulations durations. But in case of very short computing durations, the cost of multithreading management may counterbalance the speed improvements of concurrent computing.
The spatial domain graph can be queried during simulations, in order to get informations about spatial units and connections.
The following methods are available:
The spatial graph can be statically defined through the input dataset. It can also be defined and modified dynamically during simulations, using primitives to create and delete spatial units, and also to add and remove connections between these spatial units.
Although the creation, deletion and modification of connections are allowed at any stage of the simulation, the creation, deletion and modification of spatial units are currently allowed only during the data preparation stage (i.e. in the prepareData() method of the simulator).
For consistent use of simulators which modify the spatial domain graph, please fill the signature with the correct directives. See Spatial units graph.
In order to create and delete units, you can use the following methods:
Connections between spatial units can be of two types:
In order to add and remove connections, you can use the following methods, whenever during simulations:
Example:
A spatial domain graph can be automatically built or extended using a provided method to create a matrix-like graph:
Simulators can access to informations about simulation time. There are constant time informations, such as simulation duration or begin and end date, and evolutive informations such as current time index.
Constant time informations can be accessed from any part of the simulator (except from the constructor), using the following methods:
Evolutive time informations can be accessed only from specific parts of the simulator, using the following methods:
Example of code:
Simulators parameters can be accessed in the source code from the initParams method of the simulator. Values of simulators parameters can be retreived using:
The requested parameter name must be the same as the one used in the model.fluidx file (see Model section), or be filled from the OpenFLUID-Builder graphical interface.
Example of initParams method:
To be reused in other part of the simulator, the variable storing a simulator parameter should be declared as class member. The types of parameters can be string, double, integer, boolean, vector of string, vector of double (see API documentation of OPENFLUID_GetSimulatorParameter method to get more informations about other available types, available on OpenFLUID web site).
In order to access or update values of spatial attributes, or to test if a spatial attribute is present, you can use the following methods:
The methods to test if an attribute exists or to access to an attribute value are usable from any simulators part except from the initParams() part. The methods to update an attribute value are only usable from the prepareData() and checkConsistency() parts of the simulator.
The names of the attributes must match the names in the input dataset (see Spatial domain section), or the name of an attribute created by a simulator.
Example of use:
The values for the simulation variables are attached to the spatial units.
The available methods to access to simulation variables are:
The available methods to add or update a value of a simulation variable are:
The available methods to test if a simulation variable exists are:
These methods can be accessed only from the initializeRun(), runStep() and finalizeRun() parts of the simulator.
Example:
A discrete event is defined by the class. It is made of a date and a set of key-value informations that can be accessed by methods proposed by the openfluid::core::Event class.
A collection of discrete events can be contained in an openfluid::core::EventsCollection class.
A collection of events occuring during a period on a given spatial unit can be acessed using
This method returns an that can be processed.
The returned event collection can be parsed using the specific loop macro:
At each loop iteration, the next event can be processed.
An event can be added on a specific spatial unit at a given date using:
Example of process of events occurring on the current time step:
In order to keep the status of the simulation function between calls (from the run step to the next one for example), internal variables can be stored as class members. The class members are persistant during the whole life of the simulator.
To store distributed values, data structures are available to associate a spatial unit ID to a storedvalue. These data structures exist for different types of data:
Example of declaration of ID-map structures in private members of the simulator class:
Example of usage of the ID-map structures:
The runtime environment of the simulator are informations about the context during execution of the simulation: input and output directories, temporary directory,...
They are accessible from simulators using:
Example:
The keys for requesting runtime environment information are:
Simulators can emit informations and warnings to both console and files using various methods
Using these methods is the recommended way to log and display messages. Please avoid using std::cout or similar C++ facilities in production or released simulators.
Example:
The messages logged to file are put in the openfluid-messages.log
file placed in the simulation output directory. This file can be browsed using the openfluid-logexplorer
program or using the OpenFLUID-Builder application.
Simulators can raise errors to notify the OpenFLUID framework that something wrong or critical had happened. An error stops the simulation the next time the OpenFLUID framework has the control.
Errors can be raised using OPENFLUID_RaiseError
Example:
Debugging macros allow developpers to trace various information during simulations.
They are enabled only when debug is enabled at simulators builds. They are ignored for other build types.
In order to enable debug build mode, the option -DCMAKE_BUILD_TYPE=Debug
must be added to the cmake command (e.g. cmake <srcpath> -DCMAKE_BUILD_TYPE=Debug
).
Example of build configuration:
cmake .. -DCMAKE_BUILD_TYPE=Debug
This debug build mode is disabled using the release build mode, with the option -DCMAKE_BUILD_TYPE=Release
.
Simulators can emit debug information to both console and files using various methods
Example:
Additional macros are available for debugging:
Example:
The C++ - Fortran interface is defined in the openfluid/tools/FortranCPP.hpp file. In order to execute Fortran code from a simulator, this Fortran source code have to be wrapped into subroutines that will be called from the C++ code of the simulation function.
To help developers of simulators to achieve this wrapping operation, the FortranCPP.hpp file defines macros. These macros allows calls of Fortran77 and Fortran90 source code. You are invited to read the FortranCPP.hpp file to get more information about these macros.
Example of Fortran source code (FSubr.f90):
Example of declaration block int the .cpp file (MySim.cpp):
Example of call of the fortran subroutine from the initializeRun method (MySim.cpp):
The compilation and linking of Fortran source code is automatically done when adding fortran source files to the SIM_FORTRAN variable in the CMake.in.config file (See File CMake.in.config containing the build configuration).
The OpenFLUID API provides miscellaneous functions and classes to help simulators developpers in their setup of data processing or numerical computation. They are available in various namespaces:
In order to use these helpers, the corresponding headers files must be included in the simulator source code.
As they are not detailed here in this manual, more informations about these helpers are available in the provided header files (.hpp), located in the corresponding include directories.