- Notifications
You must be signed in to change notification settings - Fork3
Programmatic interface to the OpenM++ microsimulation platform
License
Unknown, MIT licenses found
Licenses found
mattwarkentin/openmpp
Folders and files
| Name | Name | Last commit message | Last commit date | |
|---|---|---|---|---|
Repository files navigation
The goal ofopenmpp is to provide a programmatic interface to theOpenM++ API directly from R to simplify creating scenarios, runningmodels, and gathering results for further processing.
You can install the development version ofopenmpp fromGitHub with:
# install.packages("remotes")remotes::install_github("mattwarkentin/openmpp")
If you do not have access to an existing OpenM++ server, you candownload and install OpenM++ locally and run a local server on yourworkstation. Theopenmpp package can then connect to this local serverinstance.
For most users, the best way to install OpenM++ locally is to downloadthe pre-compiled binaries. To install OpenM++, download and unzip the“Source code and binaries” appropriate for your operating system. Thelatest release of OpenM++ can be found here:https://github.com/openmpp/main/releases/latest. Pre-compiled binariesare available for Mac (Intel and Arm), Windows, and several common Linuxdistributions (Debian, Ubuntu, RedHat).
NOTE: Windows may allow you to view the contents of the zip directorywithout extracting, however, the files must be extracted for theinstallation to function properly.
Enter the OpenM++ directory using the File Explorer. Right-clickanywhere inside the folder and select “Open in Terminal”.
In the Windows Terminal, enter the following command:
.\bin\oms.exe
This will start the process responsible for running the OpenM++ webservice (OMS). Note that the local host address will be printed in theconsole and is the address used by theopenmpp R package tocommunicate with the API. This local host address will be set as theOPENMPP_LOCAL_URL. See the Usage section for more details.
Open a new MacOS Terminal window (either by using Spotlight Search or bynavigating to “Applications” and then “Utilities” in Finder).
After unzipping the downloaded directory in Finder, drag the folder intothe terminal and press Enter. This will change your active directory tothe OpenM++ folder.
Enter the following command into the terminal:
bin/oms
Similar to the Windows installation, the web service (OMS) will initiateand the local host address will be shared with the R package for APIcommunication.
Theopenmpp package contains many functions that provide access tonearly every OpenM++ API endpoint. However, users of this package willtypically only use a smaller set of functions for most common tasks.
Each user is required to set their local or remote host address (i.e.,URL) for the OpenM++ API in their global or project-specific.Renvironfile in order for theopenmpp package to authenticate and communicatewith the API on behalf of the user.
If you are working in an IDE (e.g., Positron, RStudio), you may considerusing the following functionusethis::edit_r_environ() to open your.Renviron file for editing. Note that you will need to restart your Rsession after editing the file for the effect to take place.
For an API running locally, set the following environment variable inyour.Renviron file:
OPENMPP_LOCAL_URL=http://localhost:XXXXWhereXXXX is the four digits corresponding to your specific localhost address (typically 4040 is used). The local host address is printedto the console when starting the OpenM++ web service in the terminal.
This package also provides the ability to remotely connect to OpenM++using JWT tokens. For an API running remotely, set the followingenvironment variables in your.Renviron file:
OPENMPP_REMOTE_URL=...OPENMPP_REMOTE_USER=...OPENMPP_REMOTE_PWD=...If you aren’t sure of your remote URL or your username/password, you maycontact your OpenM++ administrator to retrieve this information. Notethat the URL, user name, and password should be kept confidential andnot committed into version control (e.g., git).
Once the environment variables are set, users may register a local orremote API connection in their R scripts.
library(openmpp)use_OpenMpp_local()Or,
library(openmpp)use_OpenMpp_remote()see?use_OpenMpp_local or?use_OpenMpp_remote for more information.
Functions for accessing tables of models, worksets, or model runs
get_models()get_worksets()/get_scenarios()get_model_runs()/get_runs()
Functions for creating new worksets or scenarios
create_scenario()/create_workset()
Functions for loading models, worksets, or model runs
load_model()load_workset()/load_scenario()load_model_run()/load_run()load_model_runs()/load_runs()
Functions for deleting worksets or model runs
delete_workset()/delete_scenario()delete_model_run()/delete_run()
There are 4 main classes you will work with when using theopenmpppackage:OpenMppModel,OpenMppWorkset,OpenMppModelRun, andOpenMppModelRunSet. Each of these areR6 classes.R6 is anencapsulated object-oriented programming (OOP) system for R. Use theload_*() set of functions to load a model, workset/scenario, modelrun, or set of model runs into memory.
Instances of each of these 4 classes have methods (i.e., functions) andfields (i.e., data) associated with them. You can access these functionsand data using the standard$ subset operator (e.g.,obj$function()orobj$data).
Why use R6? We chose to use the R6 OOP as we believe it can simplifythe ability for the R package to communicate with OpenM++ to ensure thatall changes made to the microsimulation objects in the R session arepropagated and synchronized with the OpenM++ database. Encapsulated OOPallows the internal state of the object (i.e., the connection to theactual object in the OpenM++ database) to be accessed and modifiedthrough well-defined and high-level methods, rather than directlymanipulating the data with low-level function calls. This approachenforces data integrity, improves code readability, and simplifiesmaintenance by abstracting away the implementation details of an objectand preventing unintended modifications to its state. More informationaboutR6 can be foundhere.
Developing new microsimulation or agent-based models in OpenM++ isbeyond the scope of this package. In-depth information on modeldevelopment can be found here:https://github.com/openmpp/openmpp.github.io/wiki/Model-Development-Topics.
Next, we will work through a very simple example of creating a newscenario, extracting parameters to change, changing parameters, runningthe model, and extracting results. This example will use theRiskPaths model that comes with the OpenM++ software. RiskPaths is asimple, competing risk, case-based continuous time miscrosimulationmodel (MoreInformation).
To run this example, you must have installed OpenM++, initiated theOpenM++ web service (OMS) in the shell, and configured the R packageusing the instructions above.
library(openmpp)use_OpenMpp_local()Let’s see what models are available:
get_models()#> # A tibble: 9 × 7#> ModelId Name Digest Type Version CreateDateTime DefaultLangCode#> <int> <chr> <chr> <int> <chr> <chr> <chr>#> 1 101 IDMM bd573… 1 2.0.0.0 2025-06-01 17… EN#> 2 101 NewCaseBased be317… 0 1.0.0.0 2025-06-01 17… EN#> 3 101 NewCaseBased_bili… 2a78a… 0 1.0.0.0 2025-06-01 17… EN#> 4 101 NewTimeBased 49cec… 1 1.0.1.0 2025-06-01 17… EN#> 5 101 OzProjGenX 1da1c… 0 0.22.0… 2025-06-01 17… EN#> 6 101 OzProjX 2e697… 0 0.22.0… 2025-06-01 17… EN#> 7 101 RiskPaths d976a… 0 3.0.0.0 2025-06-01 17… EN#> 8 101 SM1 db37c… 0 1.0.0.0 2025-06-01 17… EN#> 9 1 modelOne _2012… 0 1.0 2012-08-17 16… EN
We can now see what worksets and model runs exist for a given model.
get_worksets('RiskPaths')#> # A tibble: 1 × 10#> ModelName ModelDigest ModelVersion ModelCreateDateTime Name BaseRunDigest#> <chr> <chr> <chr> <chr> <chr> <chr>#> 1 RiskPaths d976aa2fb999f0… 3.0.0.0 2025-06-01 17:27:0… Defa… ""#> # ℹ 4 more variables: IsReadonly <lgl>, UpdateDateTime <chr>,#> # IsCleanBaseRun <lgl>, Txt <list>
get_runs('RiskPaths')#> # A tibble: 1 × 15#> ModelName ModelDigest ModelVersion ModelCreateDateTime Name SubCount#> <chr> <chr> <chr> <chr> <chr> <int>#> 1 RiskPaths d976aa2fb999f097468… 3.0.0.0 2025-06-01 17:27:0… Risk… 1#> # ℹ 9 more variables: SubStarted <int>, SubCompleted <int>,#> # CreateDateTime <chr>, Status <chr>, UpdateDateTime <chr>, RunId <int>,#> # RunDigest <chr>, ValueDigest <chr>, RunStamp <chr>
Now we can load theRiskPaths model to inspect.
rp<- load_model('RiskPaths')rp#> ── OpenM++ Model ───────────────────────────────────────────────────────────────#> → ModelName: RiskPaths#> → ModelVersion: 3.0.0.0#> → ModelDigest: d976aa2fb999f097468bb2ea098c4daf
We will now load theDefault set of input parameters for the RiskPathsmodel.
rp_default<- load_scenario('RiskPaths','Default')rp_default#> ── OpenM++ Workset (ReadOnly) ──────────────────────────────────────────────────#> → ModelName: RiskPaths#> → ModelVersion: 3.0.0.0#> → ModelDigest: d976aa2fb999f097468bb2ea098c4daf#> → WorksetName: Default#> → BaseRunDigest:
Finally, we will load the base run for the RiskPaths model.
baserun_digest<-rp$ModelRuns$RunDigest[[1]]rp_baserun<- load_run('RiskPaths',baserun_digest)rp_baserun#> ── OpenM++ ModelRun ────────────────────────────────────────────────────────────#> → ModelName: RiskPaths#> → ModelVersion: 3.0.0.0#> → ModelDigest: d976aa2fb999f097468bb2ea098c4daf#> → RunName: RiskPaths_Default#> → RunDigest: 40669534e0f7ecc1d5ed55652e2e07e3
We will create a new scenario based on the parameters from theRiskPaths_Default model run.
create_scenario('RiskPaths','MyNewScenario',baserun_digest)
We will load the new scenario, copy over theAgeBaselinePreg1parameter from the base run.
my_scenario<- load_scenario('RiskPaths','MyNewScenario')
Let’s reduce the fertility rate by 10% across all age groups…
my_scenario$copy_params('AgeBaselinePreg1')
library(dplyr)current_rates<-my_scenario$Parameters$AgeBaselinePreg1reduced_rates<-current_rates|> mutate(across(-sub_id, \(x)x*0.9))my_scenario$Parameters$AgeBaselinePreg1<-reduced_rates
We will now run the model and give it the name'ExampleRun'. We usethewait = TRUE flag to make sure we want for the model run to finishbefore returning to our R session. We useprogress = FALSE to avoidprinting progress bars in this document. Note that model runs may take along time when the number of simulation cases is large.
my_scenario$ReadOnly<-TRUEmy_scenario$run('ExampleRun',wait=TRUE,progress=FALSE)
Note that we can use theopts argument and theopts_run() functionto configure our run. By default, models are run with 5,000 simulationcases and 12 SubValues. This allows for quick model runs and fasteriteration, but users will want to increase the number of simulationcases when performing a full model run.
Now that our model run is complete, let’s load it into memory.
example_run<- load_run('RiskPaths','ExampleRun')example_run#> ── OpenM++ ModelRun ────────────────────────────────────────────────────────────#> → ModelName: RiskPaths#> → ModelVersion: 3.0.0.0#> → ModelDigest: d976aa2fb999f097468bb2ea098c4daf#> → RunName: ExampleRun#> → RunDigest: e2c64228dbbaeef02e074013aaeebf38
We can now extract an output table from theTables field in the modelrun object (example_run$Tables).
example_run$Tables$T06_BirthsByUnion#> # A tibble: 7 × 3#> expr_name Dim0 expr_value#> <chr> <chr> <dbl>#> 1 Expr0 US_NEVER_IN_UNION 1205.#> 2 Expr0 US_FIRST_UNION_PERIOD1 2944.#> 3 Expr0 US_FIRST_UNION_PERIOD2 333.#> 4 Expr0 US_AFTER_FIRST_UNION 10.0#> 5 Expr0 US_SECOND_UNION 72.0#> 6 Expr0 US_AFTER_SECOND_UNION 1.00#> 7 Expr0 all 4565.
Great, we have created a new scenario, modified some parameters, ran themodel, and extracted output tables. In this last step, we will loadmultiple model runs into memory to compare them.
rp_runs<- load_runs('RiskPaths',rp$ModelRuns$RunDigest)rp_runs#> ── OpenM++ ModelRunSet ─────────────────────────────────────────────────────────#> → ModelName: RiskPaths#> → ModelVersion: 3.0.0.0#> → ModelDigest: d976aa2fb999f097468bb2ea098c4daf#> → RunNames: [RiskPaths_Default, ExampleRun]#> → RunDigests: [40669534e0f7ecc1d5ed55652e2e07e3, e2c64228dbbaeef02e074013aaeebf38]
We will extract a new table from both models. Note that an extra column,RunName is added to indicate which model run the output table datacorresponds to.
births<-rp_runs$Tables$T06_BirthsByUnionbirths#> # A tibble: 14 × 4#> RunName expr_name Dim0 expr_value#> <chr> <chr> <chr> <dbl>#> 1 RiskPaths_Default Expr0 US_NEVER_IN_UNION 1285#> 2 RiskPaths_Default Expr0 US_FIRST_UNION_PERIOD1 2986#> 3 RiskPaths_Default Expr0 US_FIRST_UNION_PERIOD2 293#> 4 RiskPaths_Default Expr0 US_AFTER_FIRST_UNION 11#> 5 RiskPaths_Default Expr0 US_SECOND_UNION 57#> 6 RiskPaths_Default Expr0 US_AFTER_SECOND_UNION 1#> 7 RiskPaths_Default Expr0 all 4633#> 8 ExampleRun Expr0 US_NEVER_IN_UNION 1205.#> 9 ExampleRun Expr0 US_FIRST_UNION_PERIOD1 2944.#> 10 ExampleRun Expr0 US_FIRST_UNION_PERIOD2 333.#> 11 ExampleRun Expr0 US_AFTER_FIRST_UNION 10.0#> 12 ExampleRun Expr0 US_SECOND_UNION 72.0#> 13 ExampleRun Expr0 US_AFTER_SECOND_UNION 1.00#> 14 ExampleRun Expr0 all 4565.
We can even plot this usingggplot2! Note that the number ofsimulation cases forExampleRun islow so the results are not tobe trusted! This is only for demonstration purposes.
library(ggplot2)births|> ggplot(aes(Dim0,expr_value,fill=RunName))+ geom_col(position= position_dodge())+ labs(x=NULL,y='Number of births by union')+ coord_flip()+ theme_minimal()+ theme(legend.position='bottom')
When we are sure we no longer need a scenario or model run, we can usedelete_scenario() ordelete_run() to clean things up!
Contributions to this package are welcome. The preferred method ofcontribution is through a GitHub pull request. Before contributing,please file an issue to discuss the idea with the project team. Moredetails on contributing can be found in theCONTRIBUTINGdocument.
Please note that theopenmpp project is released with aContributorCode ofConduct.By contributing to this project, you agree to abide by its terms.
About
Programmatic interface to the OpenM++ microsimulation platform
Resources
License
Unknown, MIT licenses found
Licenses found
Code of conduct
Contributing
Uh oh!
There was an error while loading.Please reload this page.
Stars
Watchers
Forks
Uh oh!
There was an error while loading.Please reload this page.
Contributors3
Uh oh!
There was an error while loading.Please reload this page.
