Configuration file#

The general structure of the .yaml configuration file is

simulations:
  # Series of simulations
  - name: SimulationName
    # False if you don't wish to run the simulation
    # Defaults to true
    run_simul: true
    # Number of time steps to run
    n_steps: 50000
    # Folder to use as base for saving output
    save_path: "output/path/save"
    # Frequency to report simulation status
    report: {start_step: 0, end_step: 0, frequency: 1000}

    # Domain's properties and specifications
    domain: ...
    # Data for export
    data: ...
    # Models to use
    models: ...

  # Another simulation in the same file
  - name: AnotherSimulation

    n_steps: 20000
    save_path: "another/output/path/save"
    report: {start_step: 0, end_step: 0, frequency: 1000}

    domain: ...
    data: ...
    models: ...

Note

For a full example of a configuration, check the kitchensink.

It has a series of simulations, each one describing its configurations. Each simulation has, among other things, a name, that must be unique in the file, and three important fields:

These fields configure some important aspects that are described in their specific topics. But there are other very important fields and inside logic for the configuration file that we must explain first.

Parent simulation#

It’s very common to have two very similar simulations, that differs only in some configurations. Nassu supports using a parent simulation for that.

simulations:
  # Parent simulation
  - name: parentSimulation
    ...

  # Simulation that inheritages values from parent
  - name: childSimulation
    parent: parentSimulation
    ...
    # Key value to overwrite
    key_to_overwrite: value

In this configuration, the child simulation inherits all configuration from the parent and overwrites only the specifics keys present in its configuration. The rules for overwriting are:

  • If the key in the child is a dicitonary and exists in the parent, it proceeds to check its dictionary keys

  • If the key in the child is a dicitonary and not exists in the parent, it adds this key to the configuration

  • If the key in the child is not a dictionary, it’s overwritten or added to the configuration

For example

simulations:
  - name: parentSimulation
    domain:
      domain_size:
        x: 16
        y: 16
        z: 32
      bodies:
        sphere:
          ...

  - name: childSimulation
    parent: parentSimulation
    domain:
      domain_size:
        x: 32
      bodies:
        cube:
          ...

In this case the data.domain_size.x will be overwritten in the child simulation, mantaining the y and z value the same. For the data.bodies field, the child simulation will have both the sphere and the cube as its keys.

Preveting inheritage (!not-inherit)#

There are times when we want to inheritage most fields, but sometimes we don’t want to. In the previous example, suppose we didn’t want the sphere to be present in the child simulation. Then we can use the !not-inherit tag

simulations:
  - name: parentSimulation
    domain:
      bodies:
        sphere:
          ...

  - name: childSimulation
    parent: parentSimulation
    domain:
      bodies: !not-inherit
        cube:
          ...

In this case it prevents any inheritage in the data.bodies field, so that we have only the cube in it. This is very useful when you want to prevent just some specific fields of being inherited.

Simulation series (!unroll)#

One common use case is when we want to make the same simulation, but just change some reference values or configuration. Suppose that the only difference between two cases are the velocity, or the domain size in x, or the viscosity. For these cases we use the !unroll tag

simulations:
  - name: mySimulation
    models:
      LBM:
        tau: !unroll [0.51, 0.505]
      F:
        x: !unroll [1e-5, 5e-6]

Here two simulations will be generated, one using tau=0.51 and F.x=1e-5 and the other one with tau=0.505 and F.x=5e-6. They will both have the same name, but the first one will have ID 0 and the other ID 1.

Note

Every simulation has an ID. If it doesn’t use any unroll, it will be 0. If it unrolls any fields, the ID will be the index in the unroll list.

Note that the two !unroll tags have the same length, this is required. If any list has a different size than the other ones, the configuration will raise an error.

Note

For parent simulations, everything is inherited, including the tags such as !unroll. If you don’t wish to use any key, you must overwrite it.

Variables substitution (!sub)#

There is a field in the simulation, variables, that is used to define the simulation variables and other values that may be used for other fields. These ones can be referenced in other places as ${key_name} when using the !sub tag (it also works for the !math tag).

variables:
  base_path: /home/ubuntu/my_user
  u_ref: 0.05
  height_ref: 8
  time_scale:
    reference_cst: !math ${height_ref}/${u_ref}
    n_csts_run: 300
    time_steps_develop: 5000
  domain:
    sizes: [32, 48, 64]

simulations:
  - name: mySimulation
    save_path: !sub ${base_path}/simulation0/results/
    time_steps: !math ${time_scale.time_steps_develop} + ${time_scale.n_csts_run}*${time_scale.reference_cst}

    domain:
      domain_size:
        x: !math ${domain.sizes[0]}
        y: !math ${domain.sizes[2]}
        z: !math ${domain.sizes[1]}

Special Variables#

There are some internal special variables that you can use for substitution:

variables:
  version: !sub "${NASSU_VERSION}" # x.y.z
  filepath: !sub "${NASSU_FILE_PATH}" # docs/source/user_guide/02_config/file/kitchensink.nassu.yaml
  foldername: !sub "${NASSU_FILE_FOLDER}" # docs/source/user_guide/02_config/file

  save_folder: !sub "${NASSU_FILE_FOLDER}/results/${NASSU_VERSION}/"

Custom tags#

YAML support the use of custom tags that can have a custom behavior when loading the file. We’ve already showed example of this using !unroll and !not-inherit. But there are other custom tags that we support, these are:

!math to evaluate mathematical expressions

my_45_angle_in_radians: !math 45 * (3.1415 / 180)
works_on_lists_too: !math [1/2, (5*1.125)^2, 0.9*0.49]
can_use_variables: !math ${my_reference_variable}*2/3
or_variables_in_lists: !math [${domain.size[0]}, ${domain.size[1]}*2, ${domain.size[2]}/4]
functions_and_constants_too: !math cos(45*pi/180)
number_of_euler_in_case: !math log(e^10)
# The functions are the one from `math` module
# https://docs.python.org/3/library/math.html
available_constants: ["e", "pi"]
# If there's any error, check if `math` in your python version has the function you tried to use
available_functions: [
  # Trigonometric functions
  "cos", "sin", "tan", "acos", "asin", "atan", "atan2", "degrees", "radians",
  # Log and exp functions
  "log", "log1p", "log2", "log10", "exp", "exp2", "expm1",
  # Other utils functions
  "ceil", "floor", "fabs", "fmod", "prod",
  # Python functions
  "min", "max",
]

!concat to concatenate strings

simple_concat: !concat ["first_string/", "second_one"]
# results in "first_string/second_one"

!range to generate a range of values

# Note that the end is exclusive [start, end)
range_end: !range [5] # [0, 1, 2, 3, 4]
range_start_end: !range [2, 6] # [2, 3, 4, 5]
range_start_end_step: !range [-1, 1, 0.5] # [-1, -0.5, 0, 0.5]

Important

These tags can be used in any value of the configuration. Their combination may not be compatible (as a !math inside a !concat), but it’s encouraged to try out if desired.

Anchors and aliases#

Suppose that we have a value or series of fields that are used in multiple parts of the file. It would be good if it was possible for us to create in one place and let the other fields reference it. Using YAML anchors and aliases allows us to do just that. They serve as a reference that can be pointed to by anywhere in the file

variables:
  base_path: &ANCHOR_BASE_PATH my/path/to/use
  interval_export: &ANCHOR_INTERVAL_EXPORT 5000
  report_cfg: &ANCHOR_REPORT_CFG:
    start_step: 1000
    end_step: !math 1000*20
    frequency: 100

simulation:
  - name: mySimulation
    output: !concat [*ANCHOR_BASE_PATH, "output/"]
    report: *ANCHOR_REPORT_CFG
    domain:
      bodies:
        building:
          lnas_path: !sub "${base_path}/lnas/building.yaml"
    data:
      instantaneous:
        default: { interval: { frequency: *ANCHOR_INTERVAL_EXPORT }, macrs: [rho, u] }

Using this feature it is easier to reference a common information in the file and do tricks as the example presents. It’s important to notice that we create a special key for these anchors, variables, to keep all the anchors centralized.

The other tags also work in the anchors, so you can use !math, !concat or !range and it will work as expected.

Configuration from other file (dependencies)#

It’s also possible to distribute the configurations among different files. Suppose you have a file that defines a base configuration for multiple purposes or cases. One way to reference these configurations would be to simply copy and paste this configuration into the other cases. But if anything changes in the default configuration, all files must be manually updated.

To facilitate this job of referencing a common configuration, it’s possible to load the configurations from other files before starting our own.

# ./base_simul.yaml
simulations:
  - name: baseSimulation
    models:
      LBM:
        vel_set: D2Q9
        coll_oper: RRBGK
        tau: 0.501
      F:
        x: 1e-6

# ./my_simul.yaml
dependencies:
  sim_cfg_files: [./base_simul.yaml]

simulation:
  - name: actualSimulation
    parent: baseSimulation

    domain:
      bodies:
        building: ...

The dependencies.sim_cfg_files consists of a list of configuration files with simulations to load. These loaded simulations can be used as parent of our own. Important to mention that the simulations from other files are not added to the list of simulations of the current file.

Important

The path used must be relative to the current path of your shell, not to the file itself.

The loading algorithm is able to check for cyclic dependencies and the order in which the simulations must be stated.

Full structure example#

A full example, using all presented capabilities, is presented below

dependencies:
  sim_cfg_files: [parent_cfg.yaml]

variables:
  base_path: &MY_BASE_PATH: "building_case"
  interval_export: &INTERVAL_EXPORT: 5000
  report_cfg: &REPORT_CFG:
    start_step: 1000
    end_step: !math ${report_cfg.start_step}*20
    frequency: 100

simulation:
  - name: BuildingSimulation
    parent: baseSimulation # Defined in parent_cfg.yaml

    output: !sub ${base_path}/output/"
    report: *REPORT_CFG

    domain:
      bodies:
        building:
          lnas_path: !concat [*MY_BASE_PATH, "/lnas/building.yaml"]
      refinement: !not-inherit
        static:
          default:
            bodies:
              - body_name: building
                lvl: 5
                normal_offsets: !range [-0.25, 2.1, 0.25]

    data:
      instantaneous:
        default: { interval: { frequency: *INTERVAL_EXPORT }, macrs: [rho, u] }

    models:
      LBM:
        vel_set: !unroll [D3Q27, D3Q19]
        coll_oper: !unroll [RRBGK, HRRBGK]