/******************************************************************************** DAE Tools: cDAE module, www.daetools.com Copyright (C) Dragan Nikolic ********************************************************************************* DAE Tools is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 3 as published by the Free Software Foundation. DAE Tools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the DAE Tools software; if not, see <http://www.gnu.org/licenses/>. *********************************************************************************/ /* What is the time? (AKA Hello world!) is a very simple model. The model consists of a single variable ('time') and a single differential equation:: d(time)/dt = 1 This way, the value of the variable 'time' is equal to the elapsed time in the simulation. This tutorial presents the basic structure of daeModel and daeSimulation classes. A typical DAETools simulation requires the following 8 tasks: 1. Importing DAE Tools pyDAE module(s) 2. Importing or declaration of units and variable types (unit and daeVariableType classes) 3. Developing a model by deriving a class from the base daeModel class and: - Declaring domains, parameters and variables in the daeModel.__init__ function - Declaring equations and their residual expressions in the daeModel.DeclareEquations function 4. Setting up a simulation by deriving a class from the base daeSimulation class and: - Specifying a model to be used in the simulation in the daeSimulation.__init__ function - Setting the values of parameters in the daeSimulation.SetUpParametersAndDomains function - Setting initial conditions in the daeSimulation.SetUpVariables function 5. Declaring auxiliary objects required for the simulation - DAE solver object - Data reporter object - Log object 6. Setting the run-time options for the simulation: - ReportingInterval - TimeHorizon 7. Connecting a data reporter 8. Initializing, running and finalizing the simulation */ /* 1. Include daetools.h header (DAE Tools API is defined in several C++ namespaces). */ #include <daetools.h> using namespace daetools::logging; using namespace daetools::core; using namespace daetools::solver; using namespace daetools::datareporting; using namespace daetools::activity; /* Predefined base and derived units are defined in units::units_pool namespace. */ using units_pool::s; /* 2. Define variable types * Variable types are typically declared outside of model classes since they define common, reusable types. * Pre-defined variable types are located in the 'variable_types.h' header (namespace variable_types). * The daeVariable constructor takes 7 arguments: * - Name: string * - Units: string * - LowerBound: float * - UpperBound: float * - InitialGuess: float * - AbsoluteTolerance: float * - valueConstraint: daeeVariableValueConstraint * eNoConstraint - no constraint imposed on a variabe value (the default), * eValueGTEQ - value constrainted to >= 0 * eValueLTEQ - value constrainted to <= 0 * eValueGT - value constrainted to > 0 * eValueLT - value constrainted to < 0 * Here, a very simple variable type is declared. */ namespace vt = daetools::core::variable_types; daeVariableType typeTime("typeTime", s, 0, 1E10, 0, 1e-5); /* 3. Define a model by deriving a new class from the base daeModel class. */ class modWhatsTheTime : public daeModel { public: daeVariable tau; /* 3.1 Declare domains/parameters/variables/ports * All domains, parameters, variables, ports etc has to be declared as members of * the new model class (except equations which are handled by the framework), since the base class * keeps only their references. * Domains, parameters, variables, ports, etc has to be defined in the constructor * First, the base class constructor has to be called. * In this example we declare only one variable: tau. * daeVariable constructor accepts 3 arguments: * - Name: std::string * - VariableType: daeVariableType * - Parent: daeModel object (indicating the model where the variable will be added) * - Description: std::string (optional argument - the variable description; the default value is an empty std::string) * Variable names can consists of letters, numbers, underscore ('_') and no other special characters (' ', '.', ',', '/', '-', etc). * However, there is an exception. You can use the standards html code names, such as Greek characters: α β γ etc. * Internally they will be used without '&' and ';' characters: alpha, beta, gamma, ...; * but, in the equations exported in the MathML or Latex format they will be shown as native Greek letters. * Also if you write the variable name as: Name_1 it will be transformed into Name with the subscript 1. * In this example we use Greek character 'τ' to name the variable 'tau'. */ modWhatsTheTime(std::string strName, daeModel* pParent = NULL, std::string strDescription = "") : daeModel(strName, pParent, strDescription), tau("τ", typeTime, this, "Time elapsed in the process") { } void DeclareEquations(void) { /* 3.2 Declare equations and state transition networks * Here we declare only one equation. Equations are created by the function CreateEquation in daeModel class. * It accepts two arguments: equation name and description (optional). All naming conventions apply here as well. * Equations are written in the form of a residual, which is accepted by DAE equation system solvers: * 'residual expression' = 0 * Residuals are defined by creating the above expression by using the basic mathematical operations (+, -, * and /) * and functions (sqrt, log, sin, cos, max, min, ...) on variables and parameters. Variables define several useful functions: * - operator () which calculates the variable value * - function dt() which calculates a time derivative of the variable * - function d() and d2() which calculate a partial derivative of the variable of the 1st and the 2nd order, respectively * In this example we simply write that the variable time derivative is equal to 1: * d(tau) / dt = 1 * which calculates the time as the current time elapsed in the simulation (which is a common way to obtain the current time within the model). * Note that the variables should be accessed through the model object, therefore we use self.tau */ daeEquation* eq; eq = CreateEquation("Time", "Differential equation to calculate the time elapsed in the process."); eq->SetResidual(tau.dt() - Constant(1)); } }; /* 4. Define a simulation by deriving a new class from the base daeSimulation class. */ class simWhatsTheTime : public daeSimulation { public: modWhatsTheTime model; public: /* 4.1 The model to be simulated has to be instantiated and set. */ simWhatsTheTime(void) : model("cdaeWhatsTheTime") { SetModel(&model); } public: void SetUpParametersAndDomains(void) { /* 4.2 Define the domains and parameters * Every simulation class must implement SetUpParametersAndDomains method, even if it is empty. * It is used to set the values of the parameters, create domains etc. In this example nothing has to be done. */ } void SetUpVariables(void) { /* 4.3 Set initial conditions, initial guesses, fix degreees of freedom, etc. * Every simulation class must implement SetUpVariables method, even if it is empty. * In this example the only thing needed to be done is to set the initial condition for the variable tau to 0. * That can be done by using SetInitialCondition function: */ model.tau.SetInitialCondition(0 * s); } }; int main(int argc, char *argv[]) { /* 5. Create Log, Solver, DataReporter and Simulation object * Every simulation requires the following four objects: * - log is used to send the messages from other parts of the framework, informs us about the simulation progress or errors * - solver is DAE solver used to solve the underlying system of differential and algebraic equations * - datareporter is used to send the data from the solver to daePlotter * - simulation object */ std::unique_ptr<daeSimulation_t> simulation (new simWhatsTheTime); std::unique_ptr<daeDataReporter_t> datareporter(daeCreateTCPIPDataReporter()); std::unique_ptr<daeDAESolver_t> daesolver (daeCreateIDASolver()); std::unique_ptr<daeLog_t> pLog (daeCreateStdOutLog()); /* 6. Additional settings * Here some additional information can be entered. The most common are: * - TimeHorizon: the duration of the simulation * - ReportingInterval: the interval to send the variable values * - Selection of the variables which values will be reported. It can be set individually for each variable by using the property var.ReportingOn = True/False, * or by the function SetReportingOn in daeModel class which enables reporting of all variables in that model */ simulation->SetTimeHorizon(500); simulation->SetReportingInterval(10); simulation->GetModel()->SetReportingOn(true); /* 7. Connect the data reporter * daeTCPIPDataReporter data reporter uses TCP/IP protocol to send the results to the daePlotter. * It contains the function Connect which accepts two arguments: * - TCP/IP address and port as a std::string in the following form: '127.0.0.1:50000'. * The default is an empty std::string which allows the data reporter to connect to the local (on this machine) daePlotter listening on the port 50000. * - Process name; in this example we use the combination of the simulation name and the current date and time. */ datareporter->Connect("", "cdae_whats_the_time-" + daetools::getFormattedDateTime()); /* 8. Run the simulation * 8.1 The simulation initialization * The first task is to initialize the simulation by calling the function Initialize. As the 4th argument, it accepts an optional * CalculateSensitivities (bool; default is False) which can enable calculation of sensitivities for given opt. variables. * After the successful initialization the model report can be saved. * The function SaveModelReport exports the model report in the XML format which can be opened in a web browser * (like Mozilla Firefox, or others that support XHTML+MathMl standard). * The function SaveRuntimeModelReport creates a runtime sort of the model report (with the equations fully expanded). */ simulation->Initialize(daesolver.get(), datareporter.get(), pLog.get()); /* Optional: save the model report and the runtime model report. */ //simulation->GetModel()->SaveModelReport(simulation->GetModel()->GetName() + ".xml"); //simulation->GetModel()->SaveRuntimeModelReport(simulation->GetModel()->GetName() + "-rt.xml"); /* 8.2 Calculate corected initial conditions at time = 0. */ simulation->SolveInitial(); /* 8.3 Call the function Run from the daeSimulation class to start the simulation. * It will last for TimeHorizon seconds and the results will be reported after every ReportingInterval number of seconds. */ simulation->Run(); /* 8.4 Finally, call the function Finalize to clean-up. */ simulation->Finalize(); }