Editing configs in loops

It can often be useful to update config files “on the fly”, for example within a for loop. Here, we demonstrate how this can best be done using OpenAirClim’s internal tools.

Let’s say that we have three emission inventories invA.nc, invB.nc and invC.nc, corresponding to three different aircraft designs. We would like to run each inventory in turn with generally the same underlying settings, modifying for example only the aircraft design variables, and then compare the results. In this case, we could prepare a config template that is shared between all of the inventories and then update the necessary parameters within a python loop.

Let’s assume that the example config provided in the OpenAirClim repository is sufficient for our purposes, and that we have saved it as example.toml in our working directory. The three emission inventories are assumed to be in a folder data/.

Example config file
# Species considered
[species]
inv = ["CO2", "H2O", "NOx", "distance"]
nox = "NO2"
out = ["CO2", "H2O", "O3", "CH4", "PMO", "cont", "SWV"]

# Emission inventories
[inventories]
dir = "data/"
files = []  # updated in loop

rel_to_base = false
base.dir = "data/"
base.files = []

# Output options
[output]
# Switch on/off parts of the program
run_oac = true
run_metrics = false
run_plots = false
dir = ""  # updated in loop
name = "res"
overwrite = true
concentrations = false

# Time settings
[time]
dir = "../input/"
range = [1940, 2020, 1]

# Global background concentrations
[background]
# use shared repository data cache
# dir = ""
CO2.file = "co2_bg.nc"
CO2.scenario = "SSP2-4.5"
CH4.file = "ch4_bg.nc"
CH4.scenario = "SSP2-4.5"
N2O.file = "n2o_bg.nc"
N2O.scenario = "SSP2-4.5"

# Response options
[responses]
# use shared repository data cache
# dir = ""
CO2.response_grid = "0D"
CO2.conc.method = "Sausen&Schumann"
H2O.response_grid = "2D"
H2O.rf.file = "resp_RF_H2O.nc" # AirClim response surface
O3.response_grid = "2D"
O3.rf.approach = "perturbation"
O3.rf.file = "resp_RF_O3_pert.nc" # perturbation response surface (AirClim)
CH4.response_grid = "2D"
CH4.tau.approach = "perturbation"
CH4.tau.file = "resp_CH4_pert.nc" # perturbation response surface (AirClim)
cont.response_grid = "cont"
cont.resp.file = "resp_cont_lf.nc"
SWV.file = "ch4_for_swv_calc.nc"

# Temperature options
[temperature]
method = "Boucher&Reddy"
CO2.lambda = 1.06
H2O.efficacy = 1.0    # expected range: [0.7, 1.3]
O3.efficacy = 1.05    # expected range: [0.74, 1.36]
PMO.efficacy = 1.0    # expected range: [0.7, 1.3]
CH4.efficacy = 1.04   # expected range: [0.84, 1.26]
cont.efficacy = 0.4  # expected range: [0.21, 0.59]
SWV.efficacy = 1.0

# Climate metrics options
[metrics]
# iterate over elements in lists types t_0 and H
types = []   # valid climate metrics: AGTP, AGWP, AEGWP, ATR
H = []       # Time horizon, t_final = t_0 + H - 1
t_0 = []     # Start time for metrics calculation

# aircraft defined in inventory
[aircraft]
types = ["DEFAULT"]
DEFAULT.G_250 = 1.8  # updated in loop
DEFAULT.PMrel = 1.0  # updated in loop
DEFAULT.b = 50.0     # updated in loop

# Configuration for the parametric scenario module.
[parametric]
enabled = false

We start by loading the necessary modules and defining the simulations and aircraft design parameters. Make sure that you have a working OpenAirClim installation.

import tomllib

import openairclim as oac
from openairclim.utils.config_files import write_toml

# simulation definitions
sim_def = {
    "sim-A": {"file": "invA.nc", "G_250": 1.6, "PMrel": 1.1, "b": 50},
    "sim-B": {"file": "invB.nc", "G_250": 1.8, "PMrel": 1.0, "b": 50},
    "sim-C": {"file": "invC.nc", "G_250": 2.0, "PMrel": 0.9, "b": 50},
}

Now, we can set up the for loop. We use tomllib (standard package in Python from 3.11 onwards) to open the config file, then use OpenAirClim’s inbuilt TOML writer to save the config file in a human- and machine-readable style.

Warning

All file and folder paths must be relative to the config file’s location. To run a config file located in a different folder, make sure to first change working directory to that location. This can be done within a python script using for example os.chdir("/path/to/folder").

for name, vals in sim_def.items():

    with open("example.toml", "rb") as f:
        config = tomllib.load(f)

    # update inventory and aircraft parameters
    config["inventories"]["files"] = [vals["file"]]
    config["aircraft"]["DEFAULT"]["G_250"] = vals["G_250"]
    config["aircraft"]["DEFAULT"]["PMrel"] = vals["PMrel"]
    config["aircraft"]["DEFAULT"]["b"] = vals["b"]

    # save config file
    write_toml(config, f"{name}-cfg.toml")

    # run OpenAirClim
    oac.run(f"{name}-cfg.toml")