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.

name: "Name of the Case"

workflow:
    Allrun:
      container: "oras://<registry>/<image>:<tag>.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:

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.<rule_name>

Configuration for the given rule.

Available rule names are:

  • Allpre

  • Allrun

  • Allvalidate

  • Allupdate

  • Allclean

  • custom_command

Example:

workflow:
  Allrun:
    ...
workflow.<rule_name>.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 (<target_dir>)/path/to/case/.<rule_name>. 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:

# case.yml
workflow:
  Allpre:
    input:
      - "../<regular-source-case>/.init"

This will pause execution of the Allpre script until the source case has been initialized. The corresponding Allpre script should look like this

#!/bin/bash
cd "${0%/*}" || exit 1    # Run from this directory

# Source run functions
. "$WM_PROJECT_DIR/bin/tools/RunFunctions"

runApplication foamMergeCase ../<regular-source-case>

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

#!/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
# case.yml.jinja
workflow:
  Allpre:
    input:
      - "../../<templated-source-case>/{{case}}/.init"

Here the execution of the Allpre script depends on initialization of the matching <templated-source-case>/{{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

#!/bin/bash
cd "${0%/*}" || exit 1    # Run from this directory

# Source run functions
. "$WM_PROJECT_DIR/bin/tools/RunFunctions"

runApplication foamMergeCase ../../<templated-source-case>/{{case}}
Example for a regular case depending on a template case
# case.yml
workflow:
  Allpre:
    input:
      - "../<regular-source-case>/<case-variant>/.init"

Here the execution of the Allpre script depends on the matching <templated-source-case>/<case-variant> variant, with <case-variant> being the actual name of the case variant in the caseParameterTable.ecsv of the <templated-source-case> forming the dependency. The corresponding Allpre script should look like this

#!/bin/bash
cd "${0%/*}" || exit 1    # Run from this directory

# Source run functions
. "$WM_PROJECT_DIR/bin/tools/RunFunctions"

runApplication foamMergeCase ../<templated-source-case>/<case-variant>
workflow.<rule_name>.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:

workflow:
  Allrun:
    container: "oras://<registry>/<image>:<tag>.sif"

Example with Docker:

workflow:
  Allrun:
    container: "docker://<registry>/<image>:<tag>"

Note that the selected container can be a template parameter as well to test different versions of a simulation software.

# case.yml.jinja
workflow:
    container: {{image}}
workflow.<rule_name>.resources

Rule resources configuration, resources include: cores, runtime, partition, mem, gpu

workflow.<rule_name>.resources.cores

Number of CPU cores to use for the simulation.

Type: integer

Example:

workflow:
  Allrun:
    resources:
      cores: 4
workflow.<rule_name>.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:

workflow:
  Allrun:
    resources:
      runtime: 1h
workflow.<rule_name>.resources.partition

Cluster partition name for job scheduling.

Type: string

Example:

workflow:
  Allrun:
    resources:
      partition: "cpu"
workflow.<rule_name>.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:

workflow:
  Allrun:
    resources:
      mem: 100GB
workflow.<rule_name>.resources.gpu

Number of GPU cards to use for the simulation.

Type: integer

Example:

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 <field> (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:

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:

keywords:
  BUBBLE SIZE: "monodisperse"
  BUBBLE SIZE CHANGES: "coalescence-breakup"