# Customizing the model run form This document specifies how an expert user would setup their `project.ini` file so that it's easier for non-expert users to configure and run models in the RiskScape Platform. Currently we define a parameter and its default value in the `project.ini`. Defining parameters is currently only supported for *pipeline* models. For example, to define a parameter called `perils`, we can use: ```ini param.perils = ['EQ', 'TS', 'TC'] ``` ## Labels and help descriptions By default the parameter name will be displayed in the UI. This will be improved somewhat, e.g. by default, the `loss-type` parameter would be displayed in the web UI as *Loss type*. To display a nicer label for a parameter in the UI, you could add something like the following line to your `project.ini` file: ```ini param.perils.label = Select which perils to include in the analysis. ``` You could also specify more detailed help text that would be available, e.g. ```ini param.perils.description = \ Tropical Cyclone includes wind and storm surge \ losses produced by tropical cyclones. \ Earthquake includes losses from ground shaking... ``` .. |help-icon| image:: ../icons/help.png This will appear as a |help-icon| help icon in the RiskScape Platform. When the user clicks on the icon, it will bring up the description as a pop-up modal. When the description spans multiple-lines you will need a `\` backslash at the end of each line, except for the last line. The `\` is a line-continuation character that is part of the standard INI file format. It can be simpler to specify the description across multiple lines like this: ```ini param.perils.description = Tropical Cyclone includes wind and storm surge param.perils.description = losses produced by tropical cyclones. param.perils.description = Earthquake includes losses from ground shaking... ``` The description may include [Markdown](https://www.markdownguide.org/basic-syntax/). Markdown syntax requires the use of line breaks(`\n`). An example which contains a bullet points is: ```ini param.use.description = \ Building use category. One of: \n \ - Residential \n \ - Commercial ``` ## Properties Properties give you a flexible way to control the input fields on the UI. For example, you could use the parameter properties to hide a parameter you don't really want users to know about: ```ini param.return_periods.properties = hidden ``` Or you could mark the field as read-only, so users can see the setting, but cannot change the value by default. ```ini param.return_periods.properties = readonly ``` .. tip:: Properties can also convey information about the *type* of value we expect, which we will look at next. ## Numeric values Currently pipeline parameters can be any expression, e.g. they could be `exposure.foo`, `'bar'`, or `3.14`. There is no checking that the parameter is the correct type, which means the user could specify a text string where a numeric value is expected. To improve this, you can specify the type of value that you want the expression to be. For example, where you require something to be a numeric value, you can specify: ```ini param.shaking_percentile.properties = numeric ``` .. note:: These type-based properties do not 100% match the RiskScape types. For example, many RiskScape expressions would accept *either* an ``integer`` or a ``floating``, but the RiskScape type system forces you to explicitly pick one, rather than instead just saying it should be a numeric value. .. tip:: Type-based properties like this only work for *constant* or fixed values (also known as *literal* values in programming languages). This means that for a ``properties = numeric`` parameter, the constant value ``10`` would be accepted, but an *expression* that results in an integer, such as ``exposure.road_length``, would be rejected. .. tip:: In some situations, RiskScape will display large numbers with commas for readability (e.g. 1,024). If you wish to disable this behaviour, you can simply add the `unformatted` property to the parameter. This is useful for displaying years - 2024 rather than 2,024. ## Select/drop-down parameters In the `perils` example, there is a predefined list of possible choices that the user can enter. Instead of the user having to type out `'EQ'` manually and getting it exactly right, it'd be nicer to give them a drop-down list of choices. Adding the following would turn the UI parameter into a drop-down/select box: ```ini param.perils.choices = 'TC' param.perils.choices = 'EQ' param.perils.choices = 'TS' ``` The choices would be displayed to the user with the `'`s stripped off, i.e. `TC`, `EQ`, or `TS`. However, to make this more meaningful, you can specify a more user-friendly label for each option, E.g. ```ini param.perils.choices = "Tropical Cyclone": 'TC' param.perils.choices = Earthquake: 'EQ' param.perils.choices = Tsunami: 'TS' ``` Here, the UI user will see the `Tropical Cyclone` label instead of `TC` in the drop-down. .. note:: Labels containing spaces will need ``""`` double-quotes around them. The label ``"Tropical Cyclone"`` is valid, but specifying the same thing without quotes (i.e. ``Tropical Cyclone``) would be rejected. You can alternatively specify all the choices together on the same line. Just make sure a comma separates each choice, e.g. ```ini param.perils.choices = "Tropical Cyclone": 'TC', Earthquake: 'EQ', Tsunami: 'TS' ``` Generally, it is simpler and clearer to specify each choice on a separate line. .. note:: Specifying the choices is *similar* syntax to RiskScape ``struct`` and ``list`` expressions, however, it is not *exactly* the same. Do not use ``{ }`` or ``[ ]`` characters when specifying choices in the ``project.ini`` file, unless the underlying pipeline specifically requires the expressions to be in that form. ## Multi-select parameters In this case the `perils` parameter can have a list of values. So we want the user to be able to make multiple selections in the UI, i.e. a set of check-boxes instead of a drop-down. We could control this behaviour via a property, e.g. ```ini # for a multiselect input: param.perils.properties = multiselect # or for checkbox inputs: param.perils.properties = checkbox ``` .. note:: Your pipeline code **always** needs to accept a `list` type when `multiselect` or `checkbox` is used for a parameter. ## Inferring properties from default values If you do not specify any properties for a parameter, RiskScape will sometimes infer properties from the default value. For example, take the following parameter: ```ini param.return_periods = [ 50, 100, 500 ] ``` RiskScape can infer this is a `list` and `numeric`, and therefore it should probably be a `multiselect` input field in the Platform UI. Currently these inferred properties are used in the Platform UI, but they will *not* result in model run errors if you enter a different value. For example, you can still enter something like `-p "return_periods=exposure.return_periods"`, where the value is *not* a numeric list, without any errors. If you do not like the inferred properties, you can override them by specifying *any* property for a parameter. For example: ```ini param.foo.properties = expression # or alternatively just use a plain text-box input field in the Platform UI: param.foo.properties = textbox ``` ## Parameter templates In order to avoid repetition in your `project.ini` file, you can define a parameter _template_ separately that then gets reused for multiple parameters in your models. For example: ```ini [parameter percentile] properties = integer, min: 1, max: 99 label = Enter a percentile description = This should be a whole number between 1 and 99 ``` Everywhere a model takes a percentile parameter, you can simply refer to this template, e.g. ```ini param.shaking_percentile.template = percentile ``` This means we only had to enter one line of configuration for this parameter instead of three lines. .. tip:: If your parameter has the same name as a parameter template, it will automatically use that template, i.e. any ``$percentile`` model parameters will automatically use the ``percentile`` template. You can also override parts of the template with more specific details for a parameter. This lets you refine the label or description used for a parameter, e.g. ```ini param.shaking_percentile.template = percentile # this next line overrides the parameter's label with a more specific one param.shaking_percentile.label = Enter the percentile of shaking to model ``` You can also give templates a default value. This will be used if the parameter does not provide a value. If the value is a file path (i.e. has the property `bookmark` or `file`), and begins with `./`, then it will be resolved relative to the file it was defined in. This means you can have your shared parameter template and default data in a different location to the models that use it. ## Bookmark parameters By specifying a parameter is a 'bookmark' type, it means you no longer need to specify single-quotes for the file-path. For example: ```ini param.portfolio = buildings.csv param.portfolio.properties = bookmark ``` The validation of the `portfolio` parameter now behaves the same way as specifying an input file for a wizard model - RiskScape checks that the specified value is a valid file that can be successfully read as input data. The main benefit to using the `bookmark` property is that it will give you an 'input file chooser' widget on the model run form. For example, when opened, the file chooser will look like this: .. image:: ../screenshots/select-input-default.png :target: ../_images/select-input-default.png :alt: The view when the 'Choose An Input' dialog box is first opened The other thing to note is the value inserted into your model pipeline will always be a bookmark *expression* when this property is used, e.g. `bookmark('buildings.csv')` will be inserted into the pipeline code in this case. This will generally result in your pipeline code being slightly simpler, as it means one less `bookmark()` function call you have to write yourself. For example, instead of writing: ``` select({ *, sample_one(exposure, to_coverage(bookmark($regions))) as region }) ``` You can now instead simply use: ``` select({ *, sample_one(exposure, to_coverage($regions)) as region }) ``` .. note:: The ``file`` parameter property will also give you the file input chooser widget, but it won't try to turn the given value into a bookmark expression. This can be handy if you want to build the bookmark expression in your pipeline - for example, you might also want to use other model parameters in the same bookmark expression. ### Bookmark templates You can also specify a *template* bookmark that represents the format that you expect the input data to be in. This is useful when the input data always follows the *exact* same layout, but the values within the file may differ. For example, if you had a building portfolio that gets updated yearly, then you might have several different files that all contain very similar data. These files may share common qualities, such as CSV files that contain well-known-text (WKT) in EPSG:4326 `long`,`lat` format, as well as a `Replacement_Cost` column name that contains integer values. You could define this using the following bookmark: ```ini [bookmark building_data] location = placeholder.csv crs-name = EPSG:4326 crs-longitude-first = true set-attribute.geom = geom_from_wkt(WKT) set-attribute.Replacement_Cost = int(Replacement_Cost) ``` You could then add the following model parameter, which will expect a CSV file-path that conforms to the `building_data` bookmark: ```ini param.portfolio = buildings.csv param.portfolio.properties = bookmark-template: building_data ``` In this case, the `location` of the `building_data` bookmark will be swapped out for the file-path specified. For example, the default parameter value of `buildings.csv` will be inserted into the pipeline code as `bookmark('building_data', { location: 'buildings.csv' })`. ### Bookmark types The `bookmark-template` approach is useful in some cases, but can be limiting in others. For example, say you had alternative building data, but it was a *shapefile* rather than a CSV file, or say the data contained a replacement cost, but the attribute was called `Rateable_Value`. In these cases, your model would be *incompatible* with the alternative building data. In this case, we want to support uploading bookmark data, but also map the data format to what we expect. We can do this by using a RiskScape `type` that describes the data we expect, e.g. ```ini [type building] type.geom = geometry type.Replacement_Cost = integer ``` In the parameter properties, you then specify the type that you expect the bookmark data to have, e.g. ```ini param.portfolio = building_data param.portfolio.properties = bookmark, type: building ``` If the user uploads a data source with different attributes, they will be presented with UI widgets for mapping the attributes in the input data to the type that is expected. For example: .. image:: ../screenshots/attribute-mapping.png :target: ../_images/attribute-mapping.png :alt: Mapping attributes from one input data source to match what the model expects This is useful for dealing with geospatial data (GeoPackage, GeoJSON, etc) where the names used for the input data attributes can vary. However, it is less useful for CSV-based data, as it does not support WKT or `lat`,`long` conversion into geometry currently. ## Available properties Below is a list of the properties that you can configure for parameters. ### Properties for constant values These properties are useful when you want the user to specify a *constant* or fixed value of a particular type (e.g. they should always enter a numeric value). Typically you only want to pick *one* property from the table below. | Property | Description | |-----------|--------------| | expression| The parameter accepts *any* expression. RiskScape can sometimes *infer* what type of values should be accepted (e.g. numeric values). Specifying `expression` will override anything RiskScape tries to do automatically | | integer | The parameter *only* accepts whole numbers, e.g. year of construction. | | list | The parameter only accepts list expressions, e.g. `[ 1, 2, 3]` | | numeric | The parameter only accepts *constant* numeric values (can be `integer` or `floating`) | | text | The parameter only accepts *constant* text strings. RiskScape will automatically add single-quotes so that it is a valid expression, e.g. entering `foo` would become `'foo'` | .. note:: Using these parameter properties will result in model run errors if the user enters an incorrect value, such as text instead of a numeric value, or if a non-constant expression is used, such as ``exposure.road_length`` or ``3.14 * 2``. ### Input field properties These properties describe what sort of input field the user should get in the web UI form for a given parameter, e.g. `textbox`, `dropdown`, etc. Typically you only want to pick *one* property from the table below. | Property | Description | |-----------|--------------| | `bookmark` | Adds a file input chooser to the UI. The user-specified value will be turned into a `bookmark()` expression | | `checkbox` | Requires that `choices` are defined. Similar to `multiselect`, except the choices appear as check-boxes in the web UI | | `dropdown` | Requires that `choices` are defined. Specify explicitly that the UI should be a drop-down select box. Normally this is inferred when `choices` are present | | `file` | Adds a file input chooser to the UI. The user-specified value will be turned into a text string | | `hidden` | Hide the parameter by default, so it does not appear in the web UI form | | `multiselect` | The user can enter *multiple* values. These either come from a set of pre-defined *choices*, or as free-form *numeric* values | | `readonly` | The user can see this parameter by default, but cannot change its value in the web UI | | `textbox` | A simple `textbox` (the default input field). You can specify this explicitly to prevent RiskScape inferring that the input field should be `multiselect` | .. tip:: To get the 'attribute mapping' widget for an input data file, use the ``type`` property in the next section below. ### Key-value properties These properties help validate that the user has provided an appropriate input value. For example, when specifying a percentile parameter, `-1` is a valid integer, but not an appropriate value to use. These properties are typically specified as a key-value pair, e.g. `min: 1` or `max: 99`. You can generally specify *multiple* properties from the table below. However, some properties are incompatible with other type-based properties, e.g. `min` and `bookmark` cannot be used together. | Property | Description | |-----------|--------------| | bookmark-template | Specifies the ID of an existing bookmark. The value specified for the parameter must conform to (i.e. be compatible with) that bookmark | | type | Specifies the ID of an existing type. The bookmark value specified for the parameter must conform to (i.e. be compatible with) that type | | min | Only supported for *numeric* parameters. Checks that the user enters a value that is greater than or equal to a specified minimum | | max | Only supported for *numeric* parameters. Checks that the user enters a value that is less than or equal to a specified maximum | | step | Only supported for *numeric* parameters, when `min` and `max` are specified. This controls the 'step' increment for the 'slider' UI widget | .. note:: Some of these properties, like ``min`` and ``max``, will result in model run errors if the user enters a value that falls outside that range. .