-
Notifications
You must be signed in to change notification settings - Fork 0
Model Code
Home > Model Development Topics > Model Code
This topic contains general information about the source code of an OpenM++ model. It describes model source code in broad terms, the contents of the model source code folder, and the Default scenario. It also briefly outlines the build process which transforms model source code and a Default scenario into an executable and accompanying database.
- Coding a model
- Code folder and source files
- Doc folder and documentation files
- Source file content
- Default scenario
- Model build
- Hiding syntactic islands
Modgen-specific: References to Modgen in this documentation refer to the Statistics Canada Modgen↗ platform. In this wiki, a model with common source code from which either a Modgen executable or an OpenM++ executable can be built is called a cross-compatible model. Wiki content apecific to existing Modgen users, cross-compatible models, or models originally developed in Modgen is highlighted Modgen-specific in the text.
OpenM++ models are written in two languages: the OpenM++ language and the C++ language. The OpenM++ language is used to specify the declarative aspects of a model, for example the model's classifications, parameters, entities, attributes, events, tables, labels, and notes. The C++ language is used to specify the procedural aspects of a model, for example the sequentially executed statements which change an entity's attributes when an event occurs in the simulation.
The OpenM++ language consists of declarative statements. The location and ordering of those statements in model source code files is arbitrary and has no effect on the model specification. This provides a high level of modularity in model source code which can be particularly useful in large and complex models.
A statement in the OpenM++ language starts with an opening keyword which specifies the nature of the declaration and ends with a closing ;
. The syntax between the opening keyword and the closing ;
depends on the nature of the declaration.
For example, the classification
keyword is used to declare a named ordered list of symbolic values:
classification SEX //EN Sex
{
//EN Male
MALE,
//EN Female
FEMALE
};
This example declares an OpenM++ classification
named SEX
. It has two possible values MALE
and FEMALE
.
The declaration of SEX
means that SEX
can be used as the dimension of a parameter or table, or as the type (characteristic) of an attribute of an entity in the simulation.
The OpenM++ language also recognizes specially formatted //
and /* ... */
comments. Recognized comments are optional and do not affect the model specification. They contain textual information stored with the model which can be used to produce more human-readable input and output and a generated user interface for the model. OpenM++ is multilingual, and the human language of the textual information is specified inside the comment using a two-letter code.
The //EN
comments in the example provide English-language labels for the SEX
classification and its values. These labels will appear in the user interface of the model, for example as row or column headings and labels of multi-dimensional parameters and tables.
The C++ language portion of model code consists mostly or entirely of C++ function definitions. Here's an example:
// The implement function of MortalityEvent
void Person::MortalityEvent()
{
alive = false;
// Remove the entity from the simulation.
Finish();
}
This C++ model code defines the function which implements mortality in the simulation. The Person
entity, its attribute alive
, its event MortalityEvent
, and the helper function Finish
are all declared elsewhere in the OpenM++ language code of the model.
Typically only a small, limited portion of the C++ language is used in model code. Note that it is usually neither useful nor recommended for a model developer to create C++ classes and class hierarchies in model code. The C++ classes and objects required for simulation are pre-generated by OpenM++ from the model specification given in the OpenM++ language.
The C++ language elements most used in model code are expressions↗ to compute values, assignments↗ to store those values, if statements↗ to implement branching logic, and for statements↗ or range for↗ statements for iteration. C++ functions↗ are used to specify when events occur and what happens when they do. Functions are also used to compute derived parameters and derived tables. Functions can also be used facultatively to organize code in complex models.
The C++ standard library can be used in model code. It includes useful and powerful components such as array↗ and vector↗ in the containers↗ library, and supports string operations.
The limited dialect of C++ used for coding models can be explored by perusing the source code of existing models and referring to comprehensive C++ documentation↗ when necessary, or to the many C++ tutorials available on the web.
Modgen-specific: Unlike Modgen, OpenM++ does not modify the C++ language portions of model code. This provides logical clarity and allows an IDE and other tools to function correctly with the C++ code of a model.
Many of the named symbols declared in the OpenM++ code of a model are transformed by OpenM++ into identically named C++ symbols for use in the C++ code of the model. The alive
attribute of the Person
entity in the previous example is such a symbol. These C++ symbols can usually be used transparently in C++ model code even though they may be implemented as more complex C++ objects 'under the hood'. So, when alive
is assigned the value false
in the example, the C++ symbol alive
will silently implement side-effects to update any tables, derived attributes, or events which depend on the change in its value. Incidentally, these wrapped objects have no memory overhead (the alive
attribute consumes a single byte of memory) and little computational overhead.
There are some situations where the objects which implement entity attributes can produce unexpected C++ compiler error messages in C++ model code. For more on this issue and how to address it, see Entity Attributes in C++.
OpenM++ ignores function definitions in the C++ language portions of model code, with several exceptions:
- Event time function definitions in model code are parsed by OpenM++ to determine which attributes can affect the event time. An event time function will be called to recompute the event time if any of those attributes change value.
-
PreSimulation
function definitions are recognized by OpenM++ and will be called before the simulation starts.PreSimulation
functions are used to validate input parameters and assign values to derived parameters. -
UserTables
function definitions are recognized by OpenM++ and will be called after the simulation completes.UserTables
functions are used to compute the values of derived tables.
The source code of an OpenM++ model is in one or more source files (also called modules) located in a single model code folder, eg Alpha2/code
for the Alpha2 model. Each model source file has a name and extension which determine its language and role when the model is built, as follows:
-
*.h
C++ header files included by other source files. -
*.cpp
C++ source files, can also contain OpenM++ code NOT YET IMPLEMENTED -
*.mpp
OpenM++ source files, can also contain C++ code -
*.ompp
OpenM++ source files, can also contain C++ code -
Modgen-specific:
modgen_*.mpp
Modgen source files explicitly ignored by OpenM++
Modgen-specific: Only model source files with the .mpp extension are recognized by Modgen.
The names and extensions *.ompp
and modgen_*.mpp
allow selected model source code files to be processed exclusively by OpenM++ or exclusively by Modgen. This can be useful in cross-compatible models. For example, tables which use the median statistic (which is not supported by Modgen) could be declared in a model source file named OrdinalStatistics.ompp
. Those tables would be present in the OpenM++ version of the model, but absent in the Modgen version. Declaring those tables in a file with extension .ompp
means that they will not cause Modgen to stop with a syntax error when building the Modgen version of the model.
The following model-specific source files must be present:
-
custom.h
C++ header file containing model-specific declarations. -
custom_early.h
C++ header file containing model-specific declarations early in header file inclusion order.
The following model source files are present, by convention:
-
ompp_framework.ompp
Model-specific source file containinguse
statements which specify the names of framework source code modules to be incorporated when the model is built. Framework source code modules are supplied with OpenM++ and are located in theOM_ROOT/use
folder. For more information, see OpenM++ Framework Library. -
ompp_options.ompp
Model-specific source file containingoptions
statements which specify commonly modified model options, such as Model Documentation options.
Some source files in the OpenM++ model code folder have fixed names and fixed content. Typically a model developer copies them to the model code
folder from an example model in the OpenM++ distribution, for example from OM_ROOT/models/NewCaseBased/code
or OM_ROOT/models/NewTimeBased/code
. They are:
-
case_based.h
Model-independent declaration of a structure present in case-based models, included incustom.h
. -
Modgen-specific:
modgen_case_based.mpp
Model-independent implementation of the simulation core of a case-based Modgen model. -
Modgen-specific:
modgen_time_based.mpp
Model-independent implementation of the simulation core of a time-based Modgen model.
The human language documentation of an OpenM++ model can be embedded in the model source code in Label and Note comments or in files in a single model documentation folder, e.g. RiskPaths/doc
for the RiskPaths
model.
Each model documentation file has a name and extension which determine its language and role when model documentation is built, for example:
-
NOTE.SymbolName.EN.md
Markdown file documenting the model symbolSymbolName
in English. -
NOTE.SymbolName.FR.md
Markdown file documenting the model symbolSymbolName
in French. -
LABEL.SymbolName.EN.txt
Text file containing the label of the model symbolSymbolName
in English. -
LABEL.SymbolName.FR.txt
Text file containing the label of the model symbolSymbolName
in French. -
Home.EN.md
Markdown file containing the Home topic of the Authored Model Documentation in English. -
Home.FR.md
Markdown file containing the Home topic of the Authored Model Documentation in French. -
TopicName.EN.md
Markdown file containing the autonomous authored topicTopicName
in English. -
TopicName.FR.md
Markdown file containing the autonomous authored topicTopicName
in English. -
*.pdf
Auxiliary downloadable PDF documentation file
See Model Documentation for more about model documentation.
A model source file can contain only C++ content, only OpenM++ language content, or a mixture of both. OpenM++ uses keywords at the outermost level of code to recognize OpenM++ syntactic islands which contain declarative information about the model. Here's an example of an OpenM++ syntactic island in a model source file:
parameters
{
//EN Annual hazard of death
double MortalityHazard;
/* NOTE(MortalityHazard, EN)
A constant hazard of death results in an exponential
survival function.
*/
};
This syntactic island starts with the OpenM++ keyword parameters
and ends with the terminating ;
.
All code outside of a syntactic island is C++ code.
When processing .mpp
and .ompp
model code files, OpenM++ extracts all C++ code found outside of syntactic islands and assembles it into the single C++ file src/om_developer.cpp
for subsequent processing by the C++ compiler. By default, OpenM++ inserts
#line directives↗
into this file so that any errors or warnings from the C++ compiler will refer back to the original model source file and line rather than to the assembled file src/om_developer.cpp
.
When processing a .cpp
model code file, OpenM++ processes any syntactic islands, but does not extract C++ code outside of syntactic islands. This lets one organize all model code into .cpp
files in the model code folder, and pass those files directly to the C++ compiler in Step 2 of the model build process (see below). Alternatively one could organize all OpenM++ language content in .ompp
files, and all C++ language content in .cpp
files. NOT YET IMPLEMENTED
C++ directives can be inserted into model code to improve the usability of an IDE. For more information, see the subtopic Hiding syntactic islands.
Modgen-specific: Modgen processes only .mpp
files, not .cpp
files.
The model build process requires a starting scenario containing values for all model input parameters, which is normally named Default
. The parameter values for the Default scenario are in the model subfolder parameters/Default
. It is also possible to publish multiple scenarios, not just the Default scenario, when a model is built, see Model Run: How model finds input parameters.
Selected Default parameters can be made invariant and incorporated directly into the model executable. This is done either by placing parameter files into the model subfolder parameters/Fixed
, or using parameters_retain
or parameters_suppress
statements in model code.
The following file types for input parameters are recognized:
-
.dat
Contains values for one or more parameters in Modgen format -
.odat
Contains values for one or more parameters in Modgen format -
.csv
Contains values for one parameter in csv format -
.tsv
Contains values for one parameter in tsv format
Modgen-specific: Only parameter files with the .dat
extension are recognized by Modgen.
The .odat
extension lets a selected parameter file be processed only by OpenM++. This can be useful in cross-compatible models. It is used in OpenM++ sample cross-compatible models to provide values for parameters which are implemented by scenario properties in Modgen. For example, for the NewCaseBased model, the parameter input file OM_ROOT/models/NewCaseBased/parameters/Default/Framework.odat
provides values for the SimulationSeed
and SimulationCases
parameters. The file OM_ROOT/models/NewCaseBased/parameters/Default/scenario_info.odat
contains no parameters but provides a label and note for the scenario. Those structured comments would generate an error in Modgen if they were in a .dat
file.
The model build process uses the model source code and the Default scenario to construct an executable and accompanying database which implement the model. The model build process can be launched by issuing a command inside an Integrated Development Environment (IDE) such as Visual Studio on Windows, or Visual Studio Code on Linux or MacOS. The build process can also be launched by a command line utility such as msbuild
on Windows or make
in Linux. For more information please see Model development in OpenM++. The model build process consists of two steps. Bpth steps can produce warning and error messages. These messages explain the nature of the warning or error and contain the file and line in the model source code. In an IDE, these messages can usually be clicked to navigate directly to the error or wanring location in the IDE code editor.
Many aspects of the OpenM++ framework can be adapted or replaced to work differently or to support other environments. It is also possible to publish models to an existing database and to move or copy published models and scenarios from one database to another. For more information, see subtopics at Home.
OpenM++ reads and parses all files in the model source subfolder code
and the files for the Default scenario in parameters\Default
(and possibly in parameters\Fixed
), checks for errors, and performs the following steps:
- Extracts the C++ portions of model code from all
.mpp
and.ompp
files and assembles them into a single C++ source file. - Generates several C++ header files and a C++ source file which implements the model specification.
- Generates a C++ source file which contains the values of invariant parameters.
- Creates a new empty database for the model.
- Publishes the model's metadata to the database, including classifications, parameter properties, table properties, parameter and table hierarchies, labels and notes, etc.
- Publishes the Default scenario to the database, ie values of all modifiable parameters in the Default scenario.
After Step 1 completes, the C++ compiler is invoked. The input to the C++ compiler consists of all C++ files in the model source code folder (*.cpp
, *.h
), together with the C++ files generated by OpenM++ in Step 1. Additional general purpose code is included from the OpenM++ distribution and from the C++ standard library.
The results of the C++ compilation are linked with standard C++ libraries and an OpenM++ support library to create the model executable. Because OpenM++ integrates with C++, it is possible to link in other components such as a math library, or even a complete additional model, possibly written in a different language like Fortran.
Modern IDEs have powerful abilities to parse and navigate C++ code, e.g. context sensitive popup menus which identify all uses of a symbol in a project. However, these abilities require that the project consist of valid C++. OpenM++ syntactic islands are not valid C++, and will cause errors when processed by an IDE (or an extenral tool like doxygen). Syntactic islands can be hidden from a C++ compiler or IDE by using C++ preprocessor conditional inclusion↗ directives. Here's an example showing how the syntactic island in the earlier example can be hidden from the C++ compiler or IDE.
#if 0 // Hide from C++ compiler or IDE
parameters
{
//EN Annual hazard of death
double MortalityHazard;
/* NOTE(MortalityHazard, EN)
A constant hazard of death results in an exponential
survival function.
*/
};
#endif // Hide from C++ compiler or IDE
OpenM++ will still process the syntactic island because it ignores C++ preprocessor directives.
An IDE may display a hidden syntactic island differently as a visual cue that it's an inactive code block, for example by reducing the opacity of characters in the block to make them fade into the background compared to normal characters. That can make it more difficult to read and edit code in syntactic islands.
To change the display of inactive code blocks in Visual Studio 2022, do
Tools > Options > Text Editor > C/C++ > View
and modify the settings in 'Inactive Code' as desired.
C++ code in model code files will not be considered valid by a C++ compiler or IDE if a required master header file is missing.
That's because C++ requires that a symbol be declared before being used in code.
That requirement can be met by including the optional include file
omc/optional_IDE_helper.h
at the top of the model code file, as follows:
#include "omc/optional_IDE_helper.h" // help an IDE editor recognize model symbols
Modgen-specific: The optional helper include file omc/optional_IDE_helper.h
is x-compatible and will not interfere with a Modgen build.
- Windows: Quick Start for Model Users
- Windows: Quick Start for Model Developers
- Linux: Quick Start for Model Users
- Linux: Quick Start for Model Developers
- MacOS: Quick Start for Model Users
- MacOS: Quick Start for Model Developers
- Model Run: How to Run the Model
- MIT License, Copyright and Contribution
- Model Code: Programming a model
- Windows: Create and Debug Models
- Linux: Create and Debug Models
- MacOS: Create and Debug Models
- MacOS: Create and Debug Models using Xcode
- Modgen: Convert case-based model to openM++
- Modgen: Convert time-based model to openM++
- Modgen: Convert Modgen models and usage of C++ in openM++ code
- Model Localization: Translation of model messages
- How To: Set Model Parameters and Get Results
- Model Run: How model finds input parameters
- Model Output Expressions
- Model Run Options and ini-file
- OpenM++ Compiler (omc) Run Options
- OpenM++ ini-file format
- UI: How to start user interface
- UI: openM++ user interface
- UI: Create new or edit scenario
- UI: Upload input scenario or parameters
- UI: Run the Model
- UI: Use ini-files or CSV parameter files
- UI: Compare model run results
- UI: Aggregate and Compare Microdata
- UI: Filter run results by value
- UI: Disk space usage and cleanup
- UI Localization: Translation of openM++
- Authored Model Documentation
- Built-in Attributes
- Censor Event Time
- Create Import Set
- Derived Tables
- Entity Attributes in C++
- Entity Function Hooks
- Entity Member Packing
- Entity Tables
- Enumerations
- Events
- Event Trace
- External Names
- Generated Model Documentation
- Groups
- Illustrative Model
Align1
- Lifecycle Attributes
- Local Random Streams
- Memory Use
- Microdata Output
- Model Code
- Model Documentation
- Model Languages
- Model Localization
- Model Metrics Report
- Model Resource Use
- Model Symbols
- Parameter and Table Display and Content
- Population Size and Scaling
- Screened Tables
- Symbol Labels and Notes
- Tables
- Test Models
- Time-like and Event-like Attributes
- Use Modules
- Weighted Tabulation
- File-based Parameter Values
- Oms: openM++ web-service
- Oms: openM++ web-service API
- Oms: How to prepare model input parameters
- Oms: Cloud and model runs queue
- Use R to save output table into CSV file
- Use R to save output table into Excel
- Run model from R: simple loop in cloud
- Run RiskPaths model from R: advanced run in cloud
- Run RiskPaths model in cloud from local PC
- Run model from R and save results in CSV file
- Run model from R: simple loop over model parameter
- Run RiskPaths model from R: advanced parameters scaling
- Run model from Python: simple loop over model parameter
- Run RiskPaths model from Python: advanced parameters scaling
- Windows: Use Docker to get latest version of OpenM++
- Linux: Use Docker to get latest version of OpenM++
- RedHat 8: Use Docker to get latest version of OpenM++
- Quick Start for OpenM++ Developers
- Setup Development Environment
- 2018, June: OpenM++ HPC cluster: Test Lab
- Development Notes: Defines, UTF-8, Databases, etc.
- 2012, December: OpenM++ Design
- 2012, December: OpenM++ Model Architecture, December 2012
- 2012, December: Roadmap, Phase 1
- 2013, May: Prototype version
- 2013, September: Alpha version
- 2014, March: Project Status, Phase 1 completed
- 2016, December: Task List
- 2017, January: Design Notes. Subsample As Parameter problem. Completed
GET Model Metadata
- GET model list
- GET model list including text (description and notes)
- GET model definition metadata
- GET model metadata including text (description and notes)
- GET model metadata including text in all languages
GET Model Extras
GET Model Run results metadata
- GET list of model runs
- GET list of model runs including text (description and notes)
- GET status of model run
- GET status of model run list
- GET status of first model run
- GET status of last model run
- GET status of last completed model run
- GET model run metadata and status
- GET model run including text (description and notes)
- GET model run including text in all languages
GET Model Workset metadata: set of input parameters
- GET list of model worksets
- GET list of model worksets including text (description and notes)
- GET workset status
- GET model default workset status
- GET workset including text (description and notes)
- GET workset including text in all languages
Read Parameters, Output Tables or Microdata values
- Read parameter values from workset
- Read parameter values from workset (enum id's)
- Read parameter values from model run
- Read parameter values from model run (enum id's)
- Read output table values from model run
- Read output table values from model run (enum id's)
- Read output table calculated values from model run
- Read output table calculated values from model run (enum id's)
- Read output table values and compare model runs
- Read output table values and compare model runs (enun id's)
- Read microdata values from model run
- Read microdata values from model run (enum id's)
- Read aggregated microdata from model run
- Read aggregated microdata from model run (enum id's)
- Read microdata run comparison
- Read microdata run comparison (enum id's)
GET Parameters, Output Tables or Microdata values
- GET parameter values from workset
- GET parameter values from model run
- GET output table expression(s) from model run
- GET output table calculated expression(s) from model run
- GET output table values and compare model runs
- GET output table accumulator(s) from model run
- GET output table all accumulators from model run
- GET microdata values from model run
- GET aggregated microdata from model run
- GET microdata run comparison
GET Parameters, Output Tables or Microdata as CSV
- GET csv parameter values from workset
- GET csv parameter values from workset (enum id's)
- GET csv parameter values from model run
- GET csv parameter values from model run (enum id's)
- GET csv output table expressions from model run
- GET csv output table expressions from model run (enum id's)
- GET csv output table accumulators from model run
- GET csv output table accumulators from model run (enum id's)
- GET csv output table all accumulators from model run
- GET csv output table all accumulators from model run (enum id's)
- GET csv calculated table expressions from model run
- GET csv calculated table expressions from model run (enum id's)
- GET csv model runs comparison table expressions
- GET csv model runs comparison table expressions (enum id's)
- GET csv microdata values from model run
- GET csv microdata values from model run (enum id's)
- GET csv aggregated microdata from model run
- GET csv aggregated microdata from model run (enum id's)
- GET csv microdata run comparison
- GET csv microdata run comparison (enum id's)
GET Modeling Task metadata and task run history
- GET list of modeling tasks
- GET list of modeling tasks including text (description and notes)
- GET modeling task input worksets
- GET modeling task run history
- GET status of modeling task run
- GET status of modeling task run list
- GET status of modeling task first run
- GET status of modeling task last run
- GET status of modeling task last completed run
- GET modeling task including text (description and notes)
- GET modeling task text in all languages
Update Model Profile: set of key-value options
- PATCH create or replace profile
- DELETE profile
- POST create or replace profile option
- DELETE profile option
Update Model Workset: set of input parameters
- POST update workset read-only status
- PUT create new workset
- PUT create or replace workset
- PATCH create or merge workset
- DELETE workset
- POST delete multiple worksets
- DELETE parameter from workset
- PATCH update workset parameter values
- PATCH update workset parameter values (enum id's)
- PATCH update workset parameter(s) value notes
- PUT copy parameter from model run into workset
- PATCH merge parameter from model run into workset
- PUT copy parameter from workset to another
- PATCH merge parameter from workset to another
Update Model Runs
- PATCH update model run text (description and notes)
- DELETE model run
- POST delete model runs
- PATCH update run parameter(s) value notes
Update Modeling Tasks
Run Models: run models and monitor progress
Download model, model run results or input parameters
- GET download log file
- GET model download log files
- GET all download log files
- GET download files tree
- POST initiate entire model download
- POST initiate model run download
- POST initiate model workset download
- DELETE download files
- DELETE all download files
Upload model runs or worksets (input scenarios)
- GET upload log file
- GET all upload log files for the model
- GET all upload log files
- GET upload files tree
- POST initiate model run upload
- POST initiate workset upload
- DELETE upload files
- DELETE all upload files
Download and upload user files
- GET user files tree
- POST upload to user files
- PUT create user files folder
- DELETE file or folder from user files
- DELETE all user files
User: manage user settings
Model run jobs and service state
- GET service configuration
- GET job service state
- GET disk usage state
- POST refresh disk space usage info
- GET state of active model run job
- GET state of model run job from queue
- GET state of model run job from history
- PUT model run job into other queue position
- DELETE state of model run job from history
Administrative: manage web-service state
- POST a request to refresh models catalog
- POST a request to close models catalog
- POST a request to close model database
- POST a request to delete the model
- POST a request to open database file
- POST a request to cleanup database file
- GET the list of database cleanup log(s)
- GET database cleanup log file(s)
- POST a request to pause model run queue
- POST a request to pause all model runs queue
- PUT a request to shutdown web-service