I would like to use a YAML file to store parameters used by computational models developed in Python. An example of such a file is below:
params.yaml
reactor:
diameter_inner: 2.89 cm
temperature: 773 kelvin
gas_mass_flow: 1.89 kg/s
biomass:
diameter: 2.5 mm # mean Sauter diameter (1)
density: 540 kg/m^3 # source unknown
sphericity: 0.89 unitless # assumed value
thermal_conductivity: 1.4 W/mK # based on value for pine (2)
catalyst:
density: 1200 kg/m^3 # from MSDS sheet
sphericity: 0.65 unitless # assumed value
diameters: [[86.1, 124, 159.03, 201], microns] # sieve screen diameters
surface_areas:
values:
- 12.9
- 15
- 18
- 24.01
- 31.8
- 38.51
- 42.6
units: square micron
Parameters for the Python model are organized based on the type of computations they apply to. For example, parameters used by the reactor model are listed in the reactor section. Units are important for the calculations so the YAML file needs to convey that information too.
I'm using the PyYAML package to read the YAML file into a Python dictionary. To allow easier access to the nested parameters, I use an intermediate Python class to parse the dictionary values into class attributes. The class attributers are then used to obtain the values associated with the parameters. Below is an example of how I envision using the approach for a much larger project:
params.py
import yaml
class Reactor:
def __init__(self, rdict):
self.diameter_inner = float(rdict['diameter_inner'].split()[0])
self.temperature = float(rdict['temperature'].split()[0])
self.gas_mass_flow = float(rdict['gas_mass_flow'].split()[0])
class Biomass:
def __init__(self, bdict):
self.diameter = float(bdict['diameter'].split()[0])
self.density = float(bdict['density'].split()[0])
self.sphericity = float(bdict['sphericity'].split()[0])
class Catalyst:
def __init__(self, cdict):
self.diameters = cdict['diameters'][0]
self.density = float(cdict['density'].split()[0])
self.sphericity = float(cdict['sphericity'].split()[0])
self.surface_areas = cdict['surface_areas']['values']
class Parameters:
def __init__(self, file):
with open(file, 'r') as f:
params = yaml.safe_load(f)
# reactor parameters
rdict = params['reactor']
self.reactor = Reactor(rdict)
# biomass parameters
bdict = params['biomass']
self.biomass = Biomass(bdict)
# catalyst parameters
cdict = params['catalyst']
self.catalyst = Catalyst(cdict)
example.py
from params import Parameters
pm = Parameters('params.yaml')
# reactor
d_inner = pm.reactor.diameter_inner
temp = pm.reactor.temperature
mf_gas = pm.reactor.gas_mass_flow
# biomass
d_bio = pm.biomass.diameter
rho_bio = pm.biomass.density
# catalyst
rho_cat = pm.catalyst.density
sp_cat = pm.catalyst.sphericity
d_cat = pm.catalyst.diameters
sa_cat = pm.catalyst.surface_areas
print('\n--- Reactor Parameters ---')
print(f'd_inner = {d_inner}')
print(f'temp = {temp}')
print(f'mf_gas = {mf_gas}')
print('\n--- Biomass Parameters ---')
print(f'd_bio = {d_bio}')
print(f'rho_bio = {rho_bio}')
print('\n--- Catalyst Parameters ---')
print(f'rho_cat = {rho_cat}')
print(f'sp_cat = {sp_cat}')
print(f'd_cat = {d_cat}')
print(f'sa_cat = {sa_cat}')
This approach works fine but when more parameters are added to the YAML file it requires additional code to be added to the class objects. I could just use the dictionary returned from the YAML package but I find it easier and cleaner to get the parameter values with a class interface.
So I would like to know if there is a better approach that I should use to parse the YAML file? Or should I organize the YAML file with a different structure to more easily parse it?