Thank you for contributing to our project.
This document needs quite a bit of work, but the section on Development Tools
should be useful – please stay tuned …
dockerfile
for details on Debian Linux)make dependencies
or running /misc/dependencies.R
make build-package
make doc-update
to update the .Rd
files.make pkgcheck
and make pkgtest
from the shell or devtools::check()
and devtools::test()
from within R). (Tests are also run on GitHub Actions; if you want to skip CI testing, e.g. for a trivial commit, put [skip ci]
somewhere in your commit message.) Please don’t make a habit of pushing without testing.make style
or run misc/macpan_style.R
. make style
(or running misc/macpan_lint.R
) also creates a new file, misc/lints.csv
, which contains stylistic and other lints that styler
cannot automatically fix.pkgdown
site using GitHub Actions: click “run workflow” on the link to rebuild.refactor
folder.MACPAN_TEST_LEVEL
environment (shell) variable. Many of the test files contain this code:
testLevel <- if (nzchar(s <- Sys.getenv("MACPAN_TEST_LEVEL"))) as.numeric(s) else 1
which sets testLevel
to a default value of 1 unless the environment variable is found. You can set this environment variable outside of your R session (e.g. via export MACPAN_TEST_LEVEL=2
in a bash shell), or via Sys.setenv(MACPAN_TEST_LEVEL=2)
from within R. In principle this mechanism allows for a hierarchy of slowness; at present only 1 and >1 are distinguished.
We try to be disciplined in how we maintain the C++
code, in that the correctness of this code can in principle be judged against this specification document. These specifications are versioned with the reference implementation for each version located in inst/tmb. The currently recommended version is saved in inst/tmb/recommended_spec_version.
The package itself can only use one of these reference implementations at a time. The default spec version can be set by copying the appropriate versioned cpp
file into src/McMasterPandemic.cpp
, and this can be accomplished using the following make
rule.
make src/McMasterPandemic.cpp
This make
rule copies the currently recommended version into src/McMasterPandemic.cpp
.
One may also switch the spec version being used during an R
session by using set_spec_version
function. For example, if executed from the project root directory the following line will update the spec version and associated C++
code being used.
set_spec_version('0.1.0', 'inst/tmb')
Note that this will also likely trigger compilation of the C++
code unless the objects, shared objects, and/or DLLs can be found in the same directory as the associated .cpp
file or some method of caching has been established. One may find the spec version that they are using at any time with the following function.
spec_version()
On the R
side one may also test for a particular spec version using the following family of functions: spec_ver_eq
, spec_ver_gt
, spec_ver_lt
, spec_ver_btwn
. Similarly, one may assert a certain spec version using the spec_check
and feature_check
functions.
TODO: describe global options, tmb_mode
, R_mode
, etc …
TODO: describe compare_*
family of functions …on
flexmodel
ClassTODO: point to a help file (not yet written) that describes the flexmodel
class
TODO: describe the get_*
family of functions and how they should be used to create functions like rate_summary
flexmodel
flexmodel
flexmodel_obs_error
observed$loss_params
flexmodel_obs_data
observed$data
flexmodel_obs_info
observed$loss_params
observed$data
flexmodel_to_calibrate
observed$loss_params
observed$data
opt_params
and/or opt_tv_params
flexmodel
base classflexmodel_to_calibrate
used to pass to an optimizerflexmodel_calibrated
used to simulate from a calibrated modelflexmodel_for_forecasts
flexmodel_obs_error
flexmodel_optim
flexmodel_nlminb
flexmodel_bbmle
flexmodel_failed_calibration
S3 class vectors that appear in the package:
c( 'flexmodel')
c( 'flexmodel_scenario', 'flexmodel')
(this is not necessary)c('flexmodel_obs_error', 'flexmodel')
c('flexmodel_obs_error' 'flexmodel_to_calibrate', 'flexmodel')
c('flexmodel_obs_error', 'flexmodel_scenario', 'flexmodel')
c( 'flexmodel_bbmle', 'flexmodel_scenario', 'flexmodel')
(what’s this??)c('flexmodel_obs_error', 'flexmodel_optim', 'flexmodel_calibrated', 'flexmodel')
c('flexmodel_obs_error', 'flexmodel_nlminb', 'flexmodel_calibrated', 'flexmodel')
c('flexmodel_obs_error', 'flexmodel_bbmle', 'flexmodel_calibrated', 'flexmodel')
c('flexmodel_obs_error', 'flexmodel_bbmle', 'flexmodel_scenario', 'flexmodel')
c( 'flexmodel_failed_calibration', 'flexmodel')
To identify McMasterPandemic-specific global options on the R
side we prefix their names with MP_
. For example, the MP_use_state_rounding
option is used to indicate whether the R engine should ever round the state variable. The defaults for all McMasterPandemic-specific options should be set in R/zzz.R.
There are several ways for the objective function to come back as a NaN. When this happens it can be used to run the simulate method within the TMB object. This simulate method might return a series of warnings, which can be useful for generating hypotheses about why the likelihood came out as a NaN. It can also be helpful in these cases to set options(warn = 2)
so that warnings halt execution. By halting, one may inspect the parameters that were used during at the time of the warning, by looking in the env$last.par
component within the TMB object.
See https://kaskr.github.io/adcomp/_book/Errors.html#floating-point-exception for another approach using GDB. Unfortunately this doesn’t appear to be available for mac os (related discussion: https://github.com/ArduPilot/ardupilot/issues/1941), so I prefer just using the simulate method.
There are two functions that take a flexmodel
and return a vector of parameters
Simulation functions are all driven by the simulate
method of TMB objects. These functions have optional sim_params
arguments, which should give a vector to pass to TMB simulate methods. If there are no sim_params
provided by the user, the tmb_params
function is used to attempt to guess.
flexmodel
objects contain two parameter vectors: params
and tv_mult
When one only wants to test the TMB refactored functionality, please use the following commands.
export MACPAN_TEST_LEVEL=1
make test-tmb-all
The test level can be increased to >1
to run tests that are slower because they compare refactored TMB/C++ results with equivalent jobs that use the original R-engine.
It is also possible to only run tests associated with specific areas.
make test-tmb
make test-tmb-forecast
make test-tmb-struc
make test-tmb-calibrate
make test-tmb-make-state
make test-tmb-timevar
See the area of code with sumSize
for example.
// more code ...
int powSize = powidx.size(); // powers
// more code ...
matrix<Type> simulation_history(numIterations+1, \
stateSize+tvElementsNum+sumSize+factrSize+powSize+extraExprNum+lagNum+convNum);
// more code ...
vector<Type> sp(state.size()+params.size()+sumSize+factrSize+powSize);
// more code ...
vector<Type> place_holder_pow(powSize);
sp << state, params, place_holder, place_holder_factr, place_holder_pow;
// more code ...
if (powSize>0)
simulation_history.block(0, stateSize+tvElementsNum+sumSize+factrSize, 1, powSize) = \
sp.segment(stateSize+params.size()+sumSize+factrSize, powSize).transpose();
sp
handling in update_state_functor
(similar to previous step)
template <class Type>
struct update_state_functor{
// Data members
vector<Type> params_;
vector<int> from_;
// more code ...
vector<int> powidx_;
vector<int> powarg1idx_;
vector<int> powarg2idx_;
// more code ...
// Constructor
update_state_functor(
vector<Type> params,
vector<int> from,
// more code ...
vector<int> powidx,
vector<int> powarg1idx,
vector<int> powarg2idx,
// more code ...
int do_approx_hazard) : params_(params), from_(from), to_(to), count_(count),
// more code ...
powidx_(powidx),
powarg1idx_(powarg1idx),
powarg2idx_(powarg2idx),
// more code ...
// Concatenate state and params
vector<T> sp(state_.size()+params.size()+sumidx_.size()+factr_spi_.size()+powidx_.size());
// more code ...
vector<T> place_holder_pow(powidx_.size());
sp << state_, params, place_holder, place_holder_factr, place_holder_pow;
sp
such as update_sum_in_sp
template<class Type>
void update_pow_in_sp(
vector<Type>& sp,
const vector<int>& powidx,
const vector<int>& powarg1idx,
const vector<int>& powarg2idx
)
{
for (int j=0; j<powidx.size(); j++) {
sp[powidx-1] = pow(sp[powarg1idx-1], [powarg2idx-1])
}
}