# Case Metadata Format The `case.yml` file contains metadata for simulation cases. This file is used by multiphasepy to manage case information, validation data, and workflow parameters. ```yaml name: "Name of the Case" workflow: Allrun: container: "oras:///:.sif" resources: cores: 4 # Ignored for OpenFOAM Foundation Software setups which obtain # number of cores from number of subdomains in # `system/decomposeParDict` runtime: 1h partition: "cpu-skylake" validation: "alpha.air": experiment: "validation/experiment/alpha.dat" reference: "validation/reference/line.csv" simulation: "postProcessing/../line.csv" keywords: BUBBLE SIZE: "monodisperse" BUBBLE SIZE CHANGES: "coalescence-breakup" ``` ## File Location The metadata file should be placed in the root directory of a simulation case: ```text simulation-case/ ├── Allrun ├── case.yml # Metadata file ├── system/ ├── constant/ └── validation/ ``` ## File Format The `case.yml` uses YAML format and supports the following top-level keys: ## Schema ### name Human-readable name for the simulation case. **Type:** `string` ### workflow Workflow-related configuration for job scheduling and execution. #### workflow.\ Configuration for the given rule. Available rule names are: - Allpre - Allrun - Allvalidate - Allupdate - Allclean - custom_command **Example:** ```yaml workflow: Allrun: ... ``` ##### workflow.\.input Declaration of case-to-case dependencies. **Type:** `list[string]` To understand the syntax it is necessary to understand that the successful execution of a rule for a case produces a marker file of the form `()/path/to/case/.`. A dependency is considered as resolved if this marker file is present in the case that is the dependency. It is possible to have a list of dependencies. The path to the marker file has to be specified relative to the dependent case, with the consequence that it must be updated when the case is moved within the case database. The path definition also depends on whether the source and the target case are regular or template cases or a mixture thereof. Examples are given for the scenario of using the OpenFOAM Foundation Software utility `foamMergeCase` to manage case variations. The concept also applies for mapping of results from one case to another. **Example for two regular case setups:** ```yaml # case.yml workflow: Allpre: input: - "..//.init" ``` This will pause execution of the `Allpre` script until the source case has been initialized. The corresponding `Allpre` script should look like this ```shell #!/bin/bash cd "${0%/*}" || exit 1 # Run from this directory # Source run functions . "$WM_PROJECT_DIR/bin/tools/RunFunctions" runApplication foamMergeCase ../ ``` Note that for applying `foamMergeCase` it is mandatory that it is placed in `Allpre` to keep the `single_timestep` workflow option functioning, which adjusts the (OpenFOAM Foundation Software) case when the `Allrun` rule is executed. This however happens before the corresponding case-level `Allrun` is executed, so the case has to be complete and executable before the `Allrun` rule. For the use case of mapping of simulation results, the dependency can be encoded into the `Allrun` script. Also note that because of the additional requirement that cases should also be executable standalone merely be running the `Allrun` script, a safeguard is required in `Allrun` to keep the `Allpre` script from being executed in a workflow ```shell #!/bin/bash cd "${0%/*}" || exit 1 # Run from this directory # Source run functions . "$WM_PROJECT_DIR/bin/tools/RunFunctions" if [ -z "${SNAKEMAKE_WORKFLOW:-}" ]; then ./Allpre fi ``` which implies that the `Allpre` script will execute if the `SNAKEMAKE_WORKFLOW` variable has a zero length. ###### Example for two templated case setups ```yaml # case.yml.jinja workflow: Allpre: input: - "../..//{{case}}/.init" ``` Here the execution of the `Allpre` script depends on initialization of the matching `/{{case}}` variant, with `{{case}}` being the place holder (template parameter) of the case variant in `caseParameterTable.ecsv`. Because the cases derived from a template live inside subdirectories, the path needs two `../` segments. The corresponding `Allpre.jinja` script should look like this ```shell #!/bin/bash cd "${0%/*}" || exit 1 # Run from this directory # Source run functions . "$WM_PROJECT_DIR/bin/tools/RunFunctions" runApplication foamMergeCase ../..//{{case}} ``` ###### Example for a regular case depending on a template case ```yaml # case.yml workflow: Allpre: input: - "..///.init" ``` Here the execution of the `Allpre` script depends on the matching `/` variant, with `` being the actual name of the case variant in the `caseParameterTable.ecsv` of the `` forming the dependency. The corresponding `Allpre` script should look like this ```shell #!/bin/bash cd "${0%/*}" || exit 1 # Run from this directory # Source run functions . "$WM_PROJECT_DIR/bin/tools/RunFunctions" runApplication foamMergeCase ..// ``` ##### workflow.\.container Container image URL for running the simulation in a containerized environment. Set the container to `false` to force the rule to run without container, even if a default container is set. To explicitly use the default container, set the container to `true`. **Type:** `string | bool` **Example with Apptainer|Singularity:** ```yaml workflow: Allrun: container: "oras:///:.sif" ``` **Example with Docker:** ```yaml workflow: Allrun: container: "docker:///:" ``` Note that the selected container can be a template parameter as well to test different versions of a simulation software. ```yaml # case.yml.jinja workflow: container: {{image}} ``` ##### workflow.\.resources Rule resources configuration, resources include: cores, runtime, partition, mem, gpu ##### workflow.\.resources.cores Number of CPU cores to use for the simulation. **Type:** `integer` **Example:** ```yaml workflow: Allrun: resources: cores: 4 ``` ##### workflow.\.resources.runtime Amount of wall clock time a job needs to run. It can be given as an integer defining minutes or as a string defining a time span. A time span is a number followed by a unit (`s`, `m`, `h`, `d` for seconds, minutes, hours, days). **Type:** `integer | string` **Example:** ```yaml workflow: Allrun: resources: runtime: 1h ``` ##### workflow.\.resources.partition Cluster partition name for job scheduling. **Type:** `string` **Example:** ```yaml workflow: Allrun: resources: partition: "cpu" ``` ##### workflow.\.resources.mem Amount of memory needed for the job. They are given as strings with a number followed by a unit (`B`, `KB`, `MB`, `GB`, `TB`). **Type:** `string` **Example:** ```yaml workflow: Allrun: resources: mem: 100GB ``` ##### workflow.\.resources.gpu Number of GPU cards to use for the simulation. **Type:** `integer` **Example:** ```yaml workflow: Allrun: resources: gpu: 2 ``` ### validation Validation data configuration for comparing simulation results with experimental or reference data. **Type:** `object` Each field in the validation section represents a physical quantity to be validated. The key format is typically `` (e.g., `alpha.air`, `U.water`). **Properties for each field:** - `experiment` (string): Path to experimental data file - `reference` (string): Path to reference/baseline data file - `simulation` (string): Path to simulation output data file **Example:** ```yaml validation: "alpha.air": experiment: "validation/alpha.dat" reference: "validation/reference/line.csv" simulation: "postProcessing/sampleFields/4/line.csv" "U.water": experiment: "validation/velocity.dat" reference: "validation/reference/velocity.csv" simulation: "postProcessing/sampleFields/4/velocity.csv" ``` ### keywords Keywords for categorizing and searching simulation cases. Keywords follow a controlled vocabulary defined in the reference keywords file. **Type:** `object` Each keyword category contains an applicable value. **Example:** ```yaml keywords: BUBBLE SIZE: "monodisperse" BUBBLE SIZE CHANGES: "coalescence-breakup" ```