Source code for pycif.plugins.models.lmdz_ico.perturb_model
from __future__ import annotations
from typing import Any
from ....utils.classes.chemistries import Chemistry
from ...chemistries.lmdz.utils import format_reaction, parse_reaction
# Aliases for type hinting
Plugin = Any
[docs]
def append_attribute(plugin: Plugin, key: str, attr: Plugin) -> None:
setattr(plugin, key, attr)
plugin.attributes.append(key)
[docs]
def remove_attribute(plugin: Plugin, key: str) -> None:
delattr(plugin, key)
plugin.attributes.remove(key)
# pylint: disable=unused-argument
[docs]
def perturb_model(self, nsamples: int, transf_mapper):
# raise NotImplementedError("chemistry attribute access not updated yet")
self.nsamples = nsamples
self.perturbed_species = {}
self.original_species = list(self.chemistry.active_species)
self.original_restart_ids = {}
# List of species to not perturb
dont_perturb_spec = getattr(self, "dont_perturb_species", [])
# Perturb active species in the chemical scheme
list_active_species = self.original_species
restart_id = 1
# Looping over active species
for spec in list_active_species:
spec_plg = self.chemistry.active_species[spec]
self.original_restart_ids[spec] = spec_plg.restart_id
if spec in dont_perturb_spec:
spec_plg.restart_id = restart_id
restart_id += 1
else:
# Looping over samples
for i in range(nsamples):
spec_sample = f"{spec}_{i:03d}"
self.perturbed_species[spec_sample] = spec
# Creating sample species
spec_sample_plg = Chemistry(plg_orig=spec_plg)
spec_sample_plg.restart_id = restart_id # type: ignore
restart_id += 1
# Adding sample species to chemical scheme
self.chemistry.active_species[spec_sample] = spec_sample_plg
append_attribute(self.chemistry.acspecies,
spec_sample, spec_sample_plg)
# Removing original species from chemical scheme
self.chemistry.active_species.pop(spec)
remove_attribute(self.chemistry.acspecies, spec)
# Perturb emmited species in the chemical scheme
emitted_species = []
# Looping over emmited species
for spec in self.chemistry.emitted_species:
if spec in dont_perturb_spec:
emitted_species.append(spec)
else:
for i in range(nsamples):
emitted_species.append(f"{spec}_{i:03d}")
# Replacing emmited species from chemical scheme
self.chemistry.emitted_species = emitted_species
# Perturb reactions in the chemical scheme
reactions = []
# Looping over reaction
for reac_str in self.chemistry.reactions:
loss_spec, prod_spec, prod_stoi, rate_type, rate_terms = (
self.chemistry.parse_reaction(reac_str)
)
reac_dont_pertub_spec = [
spec in dont_perturb_spec
for spec in loss_spec + prod_spec
if spec in list_active_species
]
# All active species in reaction be perturbed
if not any(reac_dont_pertub_spec):
# Looping over samples
for i in range(nsamples):
# Replacing losses species with sample species
sample_loss_spec = []
for spec in loss_spec:
if spec in list_active_species and spec not in dont_perturb_spec:
sample_loss_spec.append(f"{spec}_{i:03d}")
else:
sample_loss_spec.append(spec)
# Replacing product species with sample species
sample_prod_spec = []
for spec in prod_spec:
if spec in list_active_species and spec not in dont_perturb_spec:
sample_prod_spec.append(f"{spec}_{i:03d}")
else:
sample_prod_spec.append(spec)
# Making sample reaction string
sample_reac_str = format_reaction(
sample_loss_spec,
sample_prod_spec,
prod_stoi,
rate_type,
rate_terms,
)
# Adding sample reaction to chemical scheme
reactions.append(sample_reac_str)
elif not all(reac_dont_pertub_spec):
# Mix of species to perturb and to not perturb in reaction
raise ValueError(
f"reaction '{reac_str}' contain both species to "
"perturb and to not perturb"
)
else:
# Dont perturb reaction
reactions.append(reac_str)
self.chemistry.reactions = reactions
# Dump updated chemical scheme
self.chemistry.create_chemicalscheme()
if hasattr(self, "approx_thresholds"):
# Perturb 'approx_threshold' input argument
dict_approx = self.approx_thresholds.copy()
# Looping over emmited species
for spec, threshold in dict_approx.items():
if spec in dont_perturb_spec:
continue
# Looping over samples
for i in range(nsamples):
spec_sample = f"{spec}_{i:03d}"
# Adding sample species to 'approx_thresholds'
self.approx_thresholds[spec_sample] = threshold
# Removing original species
self.approx_thresholds.pop(spec)