HIGHLIGHT Simplified iteration of range, classification, partition - openmpp/openmpp.github.io GitHub Wiki

Home > Model Development Topics > Highlight Topic

OpenM++ implements enhancements which can simplify model code which iterates ranges, classifications, or partitions. This was implemented some time ago, when ranges, classifications, and partitions were originally implemented in OpenM++ circa 2015.

The enhancement is not Modgen-compatible, so was of limited interest at the time. But it’s of greater interest now, with Modgen in the rear-view mirror.

The wiki reference subtopic is Iterating enumerations. Here’s a sketch and some examples:

In OpenM++, any range, classification, or partition has a special member function indices(), which is designed to be used in a C++ “range-based for” statement. Here’s an example from GMM, where RISK_FACTOR is a classification:

// Verify that SimulateRiskFactor is true if the risk factor is passed to Boadicea in RA_BoadiceaUseRiskFactor.
for (auto j : RISK_FACTOR::indices()) {
    if (RA_BoadiceaUseRiskFactor[j] && !SimulateRiskFactor[j]) {
        ModelExit("Risk factors passed to Boadicea in RA_BoadiceaUseRiskFactor must be simulated in SimulateRiskFactor");
        break; // not reached
    }
}

The auto keyword is not required, one could use int (or size_t for the illuminati). It can make sense to use auto wherever it works, for code simplicity and generality. auto is a message from the coder to the C++ compiler which says: “You know what I mean, figure it out yourself”.

Here’s another example, where ONCOGENESIS_AGE_GROUP is a partition, and ONCOGENESIS_LAG is a range:

for (auto j : ONCOGENESIS_AGE_GROUP::indices()) {
    for (auto k : ONCOGENESIS_LAG::indices()) {
        double dValue = OncogenesisLags[j][k];
        SetTableValue("IM_OncogenesisLags.VALUE", dValue, j, k);
    }
}

For ranges, OpenM++ also includes the member function values(), which iterates the values of the range rather than the indices. Here’s an example where YEAR is a range:

for (auto year : YEAR::values()) {
    if (year == 1970) {
        theLog->logMsg("begin peak disco decade");
    }
}

A possible OpenM++ enhancement might be a member function for ranges which iterates indices and values as a std::pair, allowing one to access either inside the same range-based for, something like:

for (auto pr : YEAR::indices_values()) {
    auto j = pr.first();
    auto year = pr.second();
    …
}
⚠️ **GitHub.com Fallback** ⚠️