Symbol Labels and Notes - openmpp/openmpp.github.io GitHub Wiki
Home > Model Development Topics > Symbol Labels and Notes
This topic describes human-language labels and notes associated with model symbols. These labels and notes are used in a model's UI, documentation, and the IDE.
- Model Documentation: Home topic on model documentation
- Authored Model Documentation: The autonomous authored component of model documentation
- Generated Model Documentation: The symbol reference component of model documentation
- Model Languages: The human languages supported by a model
- Model Symbols: Symbols in model code and in the user interface
- Introduction and outline
- Symbol labels A label provides a one-line short description of a model symbol
- Symbol notes A note provides in-depth information about a model symbol
- Identifying missing symbol documentation Describes options to identify missing symbol documentation
This topic describes how to provide human-readable documentation for model symbols using labels and notes. Symbol labels and notes are used in the model's UI and in the model's generated Symbol Reference.
Labels and notes are described in separate subtopics. A final subtopic describes a family of options understood by the OpenM++ compiler which can help identify missing labels, notes, or translations.
This subtopic is organized into the following sections:
- Symbol labels: introduction
- Symbol labels: inline with declaration, e.g.
//EN
- Symbol labels:
//LABEL
- Symbol labels:
//LABEL
with two-part name - Symbol labels:
//LABEL
with two-part name (explicit short name) - Symbol labels:
//LABEL
with two-part name (Modgen scheme) - Symbol labels:
LABEL
text file
Labels for model symbols play an important role in the UI for a model, providing comprehensible human-language text for
- parameters,
- parameter dimensions,
- enumerations (classifications, ranges, partitions),
- enumerators of classifications,
- tables,
- table dimensions,
- table expressions,
- parameter groups (parameter hierarchy)
- table groups (table hierarchy),
- attributes.
Labels for model symbols are also used to aid a model developer using C++ symbols in an IDE. The OpenM++ compiler uses a model's labels to construct doxygen comments in generated C++ code, which can be used by an IDE to display contextual pop-ups for symbols in the model's C++ code, as described below.
See the subtopic identifying missing symbol documentation in this topic for functionality to help identify missing labels or translations. This can be helpful when publishing a model for external users.
A symbol label can also be used in the authored component of model documentation
if that content uses GetLabel
, as described
here.
[back to symbol labels]
[back to topic contents]
Model symbols are declared in syntactic islands in model code.
A model symbol can have a label for each human language
declared in the languages
statement.
A symbol label can be provided where the symbol is declared using an in-line comment,
for example
actor Person
{
//EN Union counter
int unions = {0};
...
To be recognized as a language label,
there must be no white space between //
and the language code,
and some white space is required between the language code and the label text.
OpenM++ silently ignores unrecognized language codes.
In this example, a label is provided for the symbol unions
by a comment
on the line immediately preceding the symbol declaration.
It can also be provided on the same line as the declaration by placing the trailing //
comment there.
Model code sometimes declares a symbol positionally rather than using a name.
A label can be provided for a positionally-delcared symbol on the same line
or on the immediately preceding line,
just like for symbols with names.
For example the table declaration
table Person T01_LifeExpectancy //EN Life Expectancy
{
{
unit, //EN Total simulated cases
duration(), //EN Total duration
duration()/unit //EN Life expectancy decimals=3
} //EN Quantities
};
provides a label for the table itself,
for each of the the three expressions in the table,
and for the expression dimension of the table,
all in the EN
language of the model.
Notice that the positional location of the table expression dimension is
the trailing closing }
of the expression dimension,
after all expressions.
[back to symbol labels]
[back to topic contents]
A symbol label can also be provided by a //LABEL
comment in model code.
This is particularly useful for models which support more than one language.
In the following example,
the EN
label for the SimulationCases
parameter is provided where it is declared
parameters {
//EN Number of cases in run (over all members)
long long SimulationCases;
};
and the French language version of the label is provided elsewhere using //LABEL
//LABEL(SimulationCases,FR) Nombre de cas (dans tous les membres de l'execution)
To be recognized as a human-language label,
there must be no white space between //
and LABEL
.
Subsequent white space is optional.
The arguments to //LABEL
are the symbol name and the language code,
which to be recognized must be one of those declared in the
languages
statement.
A label supplied
inline with the symbol declaration
in model code takes precedence over a label supplied through a //LABEL
comment in model code.
OpenM++ silently ignores unrecognized symbol names and language codes in //LABEL
comments.
Modgen-specific: Modgen treats a LABEL
comment with an unrecognized symbol or language as an error.
Note that OpenM++ has other mechanisms to help model devs identify missing or mistyped labels described
here.
[back to symbol labels]
[back to topic contents]
The //LABEL
syntax uses a two-part name to provide a label for the dimension of a parameter or table,
for an expression of a table,
for the expression dimension of a table,
and for classification levels (enumerators).
The first part of a two-part name is the name of the parameter, table, or classification.
The second part of a two-part name denotes the dimension, expression, or enumerator.
The separator for a two-part name in a LABEL
comment can be either ::
or .
.
Modgen-specific: Modgen recognizes only .
as a separator in two-part names.
There are two ways to specify the second part of a two-part name:
- the explicit short name, or
- the Modgen naming scheme.
[back to symbol labels]
[back to topic contents]
In the following example,
the dimensions and expressions of the table TotalPopulationByYear
have been given
explicit short names:
table Person TotalPopulationByYear //EN Life table
{
//EN Curtate age
age => integer_age +
*
{
pop => unit, //EN Population start of year
py => duration() //EN Average population in year
} //EN Quantity
};
The following //LABEL
statements provide a French language label
for the table dimensions and expressions using their explicit short names age
, pop
, and py
:
//LABEL(TotalPopulationByYear.age,FR) Âge intègre
//LABEL(TotalPopulationByYear.pop,FR) Population au début de l'année
//LABEL(TotalPopulationByYear.py,FR) Population moyenne pendant l'année
The expression dimension of a table is a special case.
It uses the fixed name expression_dimension
as the second part of the two-part name.
Continuing the above example, a French version of the expression dimension of the table is supplied by
//LABEL(T01_LifeExpectancy.expression_dimension,FR) Quantité
This string is displayed in the UI in the header of the table's expressions.
Here's another example showing //LABEL
comments with
explicit short names
to provide French versions for the dimensions
of the parameter UnionDurationBaseline
in RiskPaths
:
double UnionDurationBaseline
union_order => [UNION_ORDER] //EN Union order
union_dur => [UNION_DURATION]; //EN Union duration
//LABEL(UnionDurationBaseline.union_order,FR) Ordre d'union
//LABEL(UnionDurationBaseline.union_dur,FR) Durée d'union
Here's an example showing //LABEL
comments with
explicit short names
to provide the translation for the levels (enumerators)
of the classification UnionDurationBaseline
in RiskPaths
:
classification UNION_ORDER //EN Union order
{
first => UO_FIRST, //EN First union
second => UO_SECOND //EN Second union
};
//LABEL(UNION_ORDER.first,FR) Première
//LABEL(UNION_ORDER.second,FR) Deuxième
[back to symbol labels]
[back to topic contents]
The other method to specify the second part of a two-part name in a //LABEL
comment uses the naming scheme used in Modgen for //LABEL
.
In the Modgen naming scheme,
a LABEL
comment for a parameter dimension has the form
//LABEL(ParameterName.DimN,LANG) text
where N
is {0,1,...,rank-1}
,
rank
is the number of parameter dimensions,
LANG
is the language code,
and text
is the label.
and a LABEL
comment for a table dimension has the form
//LABEL(TableName.DimN,LANG) text
where N
is {0,1,...,rank}
,
rank
is the number of classificatory dimensions in the table,
LANG
is the language code,
and text
is the label.
NB: The naming scheme for table dimensions differs from that used for default
short names.
Unlike a default short name, it includes the expression dimension of the table in the numbering.
In the Modgen naming scheme,
a LABEL
comment for a table expression has the form
//LABEL(TableName.ExprN,LANG) text
where N
is {0,1,...,expressions}
,
expressions
is the number of expressions in the table,
LANG
is the language code,
and text
is the label.
Here's the version of the French translation for the labels of the previous example using the Modgen naming scheme:
//LABEL(TotalPopulationByYear.Dim0,FR) Âge intègre
//LABEL(TotalPopulationByYear.Expr0,FR) Nombre total de cas simulés
//LABEL(TotalPopulationByYear.Expr1,FR) Durée totale
//LABEL(TotalPopulationByYear.Expr2,FR) Espérance de vie
[back to symbol labels]
[back to topic contents]
A symbol label can be supplied as a .txt
file in the doc
sub-directory of the model.
For example, the file
RiskPaths/doc/LABEL.ProbMort.FR.txt
provides a French language version of the label of the ProbMort
parameter.
The file contents is a single line, which in this example is
Probabilités de décès
To be recognized as a LABEL
text file,
the filename must be named as in the example:
LABEL
, followed by the symbol name, followed by the code of a model language, followed by txt
,
with these parts separated by the .
character.
If both //LABEL
and a LABEL
text file are present,
the LABEL
text file takes precedence.
A label supplied
inline with the symbol declaration
in model code takes precedence over a label supplied through a LABEL
text file.
[back to symbol labels]
[back to topic contents]
A model symbol can have an associated descriptive note. The note for a published symbol such as a parameter, table, or classification can be viewed in the UI in context by clicking the information icon. A symbol note may also be incorporated into Generated Model Documentation in the model's Symbol Reference.
The content of a note can be provided in one of two ways: through a /*NOTE
comment in model code,
or through a .md
markdown file in the doc
sub-directory of the model.
Model notes are authored using markdown, with some augmentations and limitations, as described in writing content.
This subtopic is organized into the following sections:
- Symbol notes:
/*NOTE
in model code - Symbol notes:
NOTE
markdown file - Symbol notes: The special
model
symbol - Symbol notes: Modgen formatting indicators
The text for a note can be given in model code using a NOTE
comment,
For example, in RiskPaths
,
/*NOTE(Person.FirstPregEvent, EN)
The first pregnancy event. This is the main event of analysis and
censors all future union events.
*/
in the Fertility.mpp
model code module provides a note in the human language EN
for the event FirstPregEvent
in the Person
entity.
The rules for two-part symbol names in NOTE
comments are the same as those for //LABEL
given in
symbol labels.
To be recognized as a human-language note,
there must be no white space between /*
and NOTE
.
Subsequent white space is optional.
[back to symbol notes]
[back to topic contents]
A symbol note can be supplied as a .md
markdown file in the doc
sub-directory of the model.
For example, the file
RiskPaths/doc/NOTE.ProbMort.EN.md
provides the English language version of the descriptive note for the ProbMort
parameter.
The file content uses the markdown syntax,
which for NOTE.ProbMort.EN.md
is:
* The values in `ProbMort` have no effect if [`CanDie`](#CanDie) is `false`.
* The [GetLabel(Person::DeathEvent)](#DeathEvent) function in `RiskPaths`
treats the values in `ProbMort` as though they are hazards.
Arguably, the annual probabilities of death in `ProbMort` should be converted to hazards
using the formula
\(h_{x}=-\ln(1-q_{x})\).
where
\(h_{x}\) is the hazard of death and \(q_{x}\) is the annual mortality rate.
and, depending on browser capabilities and environment,
might render like this in the RiskPaths
Symbol Reference, towards the top of the topic,
after the hierarchy and
before the dimensions table:
See writing content for more information about note content and rendering.
[back to symbol notes]
[back to topic contents]
A note provided for the special symbol model
will be displayed
as introductory text in the model UI and in
the model's generated Symbol Reference.
For example, the Info.mpp
module in the OzProj
model provides the following note for the model
symbol:
/*NOTE(model, EN)
A series of OzProj model versions accompany the on-line course "Practical Microsimulation".
That course presents how to use Modgen to construct a microsimulation model
to produce detailed demographic projections from a large heterogenous microdata population.
The course content also teaches how to use Modgen through concrete self-contained examples.
The model is based on data from the web site of the Australian Bureau of Statistics.
*/
Clicking the information icon for the OzProj
model in the UI displays a pop-up like
If provided, the note for the model
symbol is incorporated into the model's Symbol Reference,
but this can be disabled using the
symref_model_symbol
option, as described in
customizing the symbol reference.
If the model has autonomous authored documentation with a home page,
a note for the model
symbol might be redundant in model documentation.
[back to symbol notes]
[back to topic contents]
Modgen formatting indicators in notes are described in the Modgen Developer’s Guide
in section “Formatting of symbol notes” on page 217.
By default, the OpenM++ compiler identifies and converts Modgen formatting indicators
to equivalent markdown when it encounters a note in model code
in /*NOTE
.
If a model uses markdown exclusively in notes in model code, this conversion can be disabled using the following statement:
options convert_modgen_note_syntax = off;
In practice, markdown and Modgen formatting indicators
can co-exist in a /*NOTE
comment without interfering.
Modgen formatting indicators are ignored and not converted in NOTE
markdown files.
[back to symbol notes]
[back to topic contents]
A common issue for model developers is to identify undocumented symbols, and, once identified, insert the missing documentation in the model source code.
The OpenM++ compiler supports a family of options to aid that process.
Each member of the family targets a specific kind of missing documentation.
When an option is set to on
,
the compiler will generate a warning for each occurrence of missing documentation of that kind.
The warning includes the model code file and line where the symbol was declared,
except for missing translation warnings which instead give the location of the untranslated text.
In an IDE like Visual Studio, double-clicking on the warning in the log window
navigates immediately to that model source code location in the IDE editor.
By default these options are off
.
Multiple options can be turned on
at the same time.
Here's an example to identify all published parameters in RiskPaths
which have no descriptive note in the model's default language.
Inserting the following line in ompp_framework.ompp
options missing_note_warning_published_parameter = on;
causes the compiler to emit warnings like:
1>../code/Unions.mpp(39): warning : missing note for published parameter 'AgeBaselineForm1'
1>../code/Fertility.mpp(21): warning : missing note for published parameter 'AgeBaselinePreg1'
1>../code/Mortality.mpp(25): warning : missing note for published parameter 'CanDie'
1>../code/Mortality.mpp(26): warning : missing note for published parameter 'ProbMort'
1>../code/Unions.mpp(45): warning : missing note for published parameter 'SeparationDurationBaseline'
1>../code/Unions.mpp(42): warning : missing note for published parameter 'UnionDurationBaseline'
1>../code/Fertility.mpp(24): warning : missing note for published parameter 'UnionStatusPreg1'
Here's an example which identifies all published symbols in IDMM
which have a descriptive label or note in the default language,
but whose translation is missing in one of the model's other languages.
The source of IDMM
was changed for this example to deliberately create missing translations.
Inserting the following lines in ompp_framework.ompp
options missing_translated_label_warning_published_any = on;
options missing_translated_note_warning_published_any = on;
causes the compiler to emit warnings like:
1>../code/HostCore.mpp(89): warning : missing 'FR' translated label for published symbol 'event_count'
1>../code/HostCore.mpp(82): warning : missing 'FR' translated note for published symbol 'NumberOfHosts'
For missing translation warnings, the warning code location is the location of the label or note in the default language, not the location of the symbol declaration. That's so the warning can be used to navigate to the text to be translated.
The missing translated note warning above gave the code location HostCore.mpp(82)
.
Here's an extract of the code starting at that location (line 82):
/*NOTE(NumberOfHosts,EN)
This number does not change during the simulation
because there are no births, immigration, or deaths.
*/
Double-clicking the warning in an IDE navigates directly to that NOTE
in the IDE editor.
The associated parameter NumberOfHosts
is declared elsewhere.
The following table lists the available options to emit warnings for missing symbol documentation,
grouped by category.
The Scope column shows what produces a warning for the given option.
For example, the missing_label_parameter
option produces a warning for
a missing label for a parameter or for a parameter group.
It does not produce a missing label warning for a parameter dimension.
That's because the default label for a parameter dimension
is copied from the label of the enumeration for the dimension,
and is usually sufficient.
The scope of each option is deliberately restricted to produce useful actionable warnings.
Option | Scope |
---|---|
Labels | |
missing_label_warning_enumeration | classification, classification level, range, partition |
missing_label_warning_parameter | parameter, parameter group |
missing_label_warning_table | table, table expression, table group |
missing_label_warning_attribute | attribute |
Labels - Published | |
missing_label_warning_published_enumeration | as above, but only if published |
missing_label_warning_published_parameter | as above, but only if published |
missing_label_warning_published_table | as above, but only if published |
missing_label_warning_published_attribute | as above, but only if published |
Notes - Published | |
missing_note_warning_published_parameter | published parameter |
missing_note_warning_published_table | published table |
missing_note_warning_published_attribute | published attribute |
Translated Labels and Notes | |
missing_translated_label_warning_any | any symbol with an explicit label provided in the model's default language |
missing_translated_note_warning_any | any symbol with a note provided in the model's default language |
Translated Labels and Notes - Published | |
missing_translated_label_warning_published_any | as above, but only for published symbols |
missing_translated_note_warning_published_any | as above, but only for published symbols |