Skip to content

ODE Class

Jacob Fields edited this page Jun 9, 2020 · 1 revision

The abstract ODE class handles anything to do with setting up and managing a system of differential equations. The name itself may seem to be somewhat of a misnomer, but it refers to the fact that the Solver class it interacts with is a traditional time integrator designed for ODEs, whether those are pure ODEs or PDEs discretized into a system of tightly-coupled ODEs with finite-difference methods.

Protected Fields

Field Description
const unsigned int nEqs This particular variable is deprecated and will be removed in a later release. It's a leftover from the old Solver system that could only handle one group of equations. This has been superseded by the FieldMap class and the FieldInfo struct.
Domain *domain A pointer to the Domain this ODE should be solved on.
std::shared_ptr<FieldMap> fieldData A smart pointer to a FieldMap containing the data for all the separate fields of equations.
std::map<std::string, std::vector<varPair>> fieldOutput A map set up in conjunction with fieldData that contains some output information for every field and its variables. The length of the std::vector is however many equations a particular field inside fieldData has. The varPair type is a shorthand for std::pair<bool, std::string>, where the bool controls whether or not a variable is written during output, and the std::string is the name that will be used in output files.
Solver *solver A pointer to the Solver object that ODE should use to evolve its equations forward in time.
double time This is the current evolution time for the ODE. This makes it possible to solve problems with coefficients or sources containing an explicit time dependence. It is updated in evolveStep via the setStageTime method to ensure it is always accurate.

Protected Methods

Method Description
ODE(const ODE&) Because ODE is a large, complicated structure that contains references and pointers to large sets of data and other complicated objects, the copy constructor is explicitly defined to do nothing and declared as protected.
virtual void applyBoundaries() This method, which is empty by default, is called during evolveStep to apply fluid-style boundaries.
virtual void doAfterStage() This method, which is empty by default, is called after the Solver stage completes but before a grid exchange occurs.
virtual void doAfterExchange() This method, which is empty by default, is called after the grid exchange occurs but before applyBoundaries is called.
virtual void doAfterBoundaries() This method, which is empty by default, is called after applyBoundaries.
Result addField(std::string name, unsigned int neqs, bool isEvolved, bool isComm) Add a new field to fieldData by specifying the name (name), the number of equations (neqs), whether or not to use a Solver to evolve the equations forward (isEvolved), and whether or not these variables need to be communicated across processor boundaries (isComm). These last two parameters are important because some fields, such as constraint equations, are not explicitly time-dependent, and others may not need to be communicated across other processors because they can be calculated from data that is. If a field with name already exists, this returns FIELD_EXISTS. Otherwise, it returns SUCCESS.
Result removeField(std::string name) Remove a field with name from fieldData. If fieldData cannot find name, it returns UNRECOGNIZED_FIELD. Otherwise, it returns SUCCESS.
bool hasField(std::string name) Check if fieldData contains a field matching name.
Result reallocateData() This rebuilds fieldData with the most current list of fields constructed using addField and removeField. This function must be called any time the list of fields changes in order for those changed to take effect.
void performGridExchange() Exchange the ghost zones between all processors. This also handles the periodic boundary for polar coordinates in multiprocessor runs.
void performPeriodicExchange() This is a special function for handling the periodic boundary in polar coordinates for serial runs.

Public Methods

Method Description
ODE(const unsigned int n, Domain *d, Solver *s) The constructor for ODE. This must be called in the initialization list for any derived ODE class. The first argument, n, is the number of variables, and d and s are the Domain and Solver pointers that should be associated with this ODE.
~ODE() The destructor for ODE. Since the transition to using smart pointers, it no longer does anything.
setDomain(Domain *domain) Set the Domain for the ODE. This also calls reallocateData.
setSolver(Solver *solver) Set the Solver for the ODE. This also calls reallocateData.
void setVariableOutput(std::string field, unsigned int var, bool output) For variable index var inside field, decide whether or not (output) it should be included in the output files.
void setVariableName(std::string field, unsigned int var, std::string name) Assign the name name to variable index var inside field. If the variable's output is set to true, this is the name that will show up in output files.
virtual Result evolveStep(double dt) Evolve all fields a single step of size dt. This is declared virtual for flexibility, but the doAfter functions should preclude any need to rewrite this function short of rewriting for better efficiency or compatibility with a time integrator that doesn't work well with the Solver interface.
virtual void initData() This is a pure virtual function that sets up the initial data for the ODE equations.
virtual void rhs(std::shared_ptr<FieldMap>& fieldMap) The right-hand side for the ODE equations. Technically speaking, the fieldMap argument is not necessary because any code executed in rhs has access to fieldData. This is a holdover from OOPS, which supports multiple Grid objects, and is maintained both for consistency and to minimize code rewrites when OOPS-2D eventually supports multiple Grid objects.
unsigned int getNEqs() const Get the value of nEqs. This is deprecated and will eventually be removed.
Domain* getDomain() Get the Domain pointer for this ODE.
const std::map<std::string, FieldInfo>& getFieldInfo() Get the information about all the fields available to this ODE. The FieldInfo object is a struct containing some very basic information used for building the FieldMap and determining which fields are evolved or communicated.
double getTime() Get the current evolution time for the ODE.
void setTime(double t) Set the current time in the ODE.
void dumpField(std::string field, char* name, double t, unsigned int var) Dump a variable index var inside field to a CSV file named name at a time t. This output is not generally recommended, particularly in parallel. Because most visualization programs do not expect parallel CSV output, all output per frame is collated into a single file, which takes a significant amount of time.
void outputVTK(char* name, double t) Write a structured grid VTK (.vts) file with the name name.vts at a time t. This will traverse fieldOutput to determine which variables need to be output. In parallel, files are renamed name.vts.#, where # is the outputting processor's rank. A name.pvts file is saved as well to facilitate reading in each frame.

Implementation Details

Any concrete derived ODE class must implement initData and rhs. Additionally, the constructor should call ODE() in its initialization list. It's generally recommended that all fields be initialized in the derived class's constructor and that reallocateData() be called as the last line. The Scalar Wave Equation tutorial is a good example of a basic implementation.

Clone this wiki locally