Skip to content

Commit

Permalink
Remove parsing (#255)
Browse files Browse the repository at this point in the history
Removes parsing of the json from the python layer as this is not needed, only micm needs to that. This also corrects conversions from cm-3 to m-3, which were all missing 3 orders of magnitude
  • Loading branch information
K20shores authored Oct 13, 2024
1 parent 3238d4c commit d82d6ea
Show file tree
Hide file tree
Showing 25 changed files with 3,774 additions and 4,798 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/pep8_autoformat.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jobs:
- name: autopep8
uses: peter-evans/autopep8@v2
with:
args: --recursive --in-place --aggressive --aggressive --max-line-length 120 .
args: --recursive --in-place --aggressive --aggressive --max-line-length 180 .

- name: Check for changes
id: check-changes
Expand Down
9 changes: 1 addition & 8 deletions src/acom_music_box/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,10 @@
This package contains modules for handling various aspects of a music box,
including species, products, reactants, reactions, and more.
"""
__version__ = "2.5.2"
__version__ = "2.5.3"

from .utils import convert_time, convert_pressure, convert_temperature, convert_concentration
from .species import Species
from .product import Product
from .reactant import Reactant
from .reaction import Reaction, Branched, Arrhenius, Tunneling, Troe_Ternary
from .species_list import SpeciesList
from .model_options import BoxModelOptions
from .species_concentration import SpeciesConcentration
from .reaction_rate import ReactionRate
from .conditions import Conditions

from .evolving_conditions import EvolvingConditions
Expand Down
142 changes: 49 additions & 93 deletions src/acom_music_box/conditions.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,10 @@
from .utils import convert_pressure, convert_temperature, convert_concentration
from .species_concentration import SpeciesConcentration
from .species import Species
from .reaction_rate import ReactionRate
from typing import List
import csv
import pandas as pd
import os
from typing import List
from .reaction_rate import ReactionRate
from .species import Species
from .species_concentration import SpeciesConcentration

import logging
logger = logging.getLogger(__name__)


class Conditions:
"""
Represents conditions for a simulation with attributes such as pressure, temperature, species concentrations,
Expand All @@ -38,13 +29,13 @@ def __init__(
Args:
pressure (float): The pressure of the conditions in atmospheres.
temperature (float): The temperature of the conditions in Kelvin.
species_concentrations (List[SpeciesConcentration]): A list of species concentrations. Default is an empty list.
reaction_rates (List[ReactionRate]): A list of reaction rates. Default is an empty list.
species_concentrations (Dict[Species, float]): A dictionary of species concentrations.
reaction_rates (Dict[Reaction, float]): A dictionary of reaction rates.
"""
self.pressure = pressure
self.temperature = temperature
self.species_concentrations = species_concentrations if species_concentrations is not None else []
self.reaction_rates = reaction_rates if reaction_rates is not None else []
self.species_concentrations = species_concentrations if species_concentrations is not None else {}
self.reaction_rates = reaction_rates if reaction_rates is not None else {}

def __repr__(self):
return f"Conditions(pressure={self.pressure}, temperature={self.temperature}, species_concentrations={self.species_concentrations}, reaction_rates={self.reaction_rates})"
Expand Down Expand Up @@ -117,9 +108,7 @@ def from_UI_JSON(self, UI_JSON, species_list, reaction_list):
def from_config_JSON(
self,
path_to_json,
config_JSON,
species_list,
reaction_list):
object):
"""
Creates an instance of the class from a configuration JSON object.
Expand All @@ -128,75 +117,51 @@ def from_config_JSON(
Args:
path_to_json (str): The path to the JSON file containing the initial conditions and settings.
config_JSON (dict): The configuration JSON object containing the initial conditions and settings.
species_list (SpeciesList): A SpeciesList containing the species involved in the simulation.
reaction_list (ReactionList): A ReactionList containing the reactions involved in the simulation.
object (dict): The configuration JSON object containing the initial conditions and settings.
Returns:
object: An instance of the Conditions class with the settings from the configuration JSON object.
"""
pressure = convert_pressure(
config_JSON['environmental conditions']['pressure'],
object['environmental conditions']['pressure'],
'initial value')

temperature = convert_temperature(
config_JSON['environmental conditions']['temperature'],
object['environmental conditions']['temperature'],
'initial value')

# Set initial species concentrations
species_concentrations = []
reaction_rates = []
initial_concentrations = {}
reaction_rates = {}

# reads initial conditions from csv if it is given
if 'initial conditions' in config_JSON and len(
list(config_JSON['initial conditions'].keys())) > 0:
if 'initial conditions' in object and len(
list(object['initial conditions'].keys())) > 0:

initial_conditions_path = os.path.join(
os.path.dirname(path_to_json),
list(config_JSON['initial conditions'].keys())[0])
list(object['initial conditions'].keys())[0])

reaction_rates = Conditions.read_initial_rates_from_file(
initial_conditions_path, reaction_list)
initial_conditions_path)

# reads from config file directly if present
if 'chemical species' in config_JSON:
for chem_spec in config_JSON['chemical species']:
species = Species(name=chem_spec)
concentration = convert_concentration(
config_JSON['chemical species'][chem_spec], 'initial value', temperature, pressure)

species_concentrations.append(
SpeciesConcentration(
species, concentration))

for species in species_list.species:
if species.tracer_type == 'THIRD_BODY':
continue
if not any(conc.species.name ==
species.name for conc in species_concentrations):
species_concentrations.append(SpeciesConcentration(species, 0))

# Set initial reaction rates
for reaction in reaction_list.reactions:
if (reaction.name is None):
continue
reaction_exists = False
for rate in reaction_rates:
if rate.reaction.name == reaction.name:
reaction_exists = True
break

if not reaction_exists:
reaction_rates.append(ReactionRate(reaction, 0))
if 'chemical species' in object:
initial_concentrations = {
species: convert_concentration(
object['chemical species'][species], 'initial value', temperature, pressure
)
for species in object['chemical species']
}

return self(
pressure,
temperature,
species_concentrations,
initial_concentrations,
reaction_rates)

@classmethod
def read_initial_rates_from_file(self, file_path, reaction_list):
def read_initial_rates_from_file(cls, file_path):
"""
Reads initial reaction rates from a file.
Expand All @@ -205,30 +170,33 @@ def read_initial_rates_from_file(self, file_path, reaction_list):
Args:
file_path (str): The path to the file containing the initial reaction rates.
reaction_list (ReactionList): A ReactionList containing the reactions involved in the simulation.
Returns:
list: A list where each element represents the initial rate of a reaction.
dict: A dictionary of initial reaction rates.
"""

reaction_rates = []

with open(file_path, 'r') as csv_file:
initial_conditions = list(csv.reader(csv_file))

if (len(initial_conditions) > 1):
# The first row of the CSV contains headers
headers = initial_conditions[0]

# The second row of the CSV contains rates
rates = initial_conditions[1]

for reaction_rate, rate in zip(headers, rates):
type, name, *rest = reaction_rate.split('.')
for reaction in reaction_list.reactions:
if reaction.name == name and reaction.short_type() == type:
reaction_rates.append(ReactionRate(reaction, rate))

reaction_rates = {}

df = pd.read_csv(file_path)
rows, _ = df.shape
if rows > 1:
raise ValueError(f'Initial conditions file ({file_path}) may only have one row of data. There are {rows} rows present.')
for key in df.columns:
parts = key.split('.')
reaction_type, label = None, None
if len(parts) == 3:
reaction_type, label, units = parts
elif len(parts) == 2:
reaction_type, label = parts
else:
error = f"Unexpected format in key: {key}"
logger.error(error)
raise ValueError(error)
rate_name = f'{reaction_type}.{label}'
if rate_name in reaction_rates:
raise ValueError(f"Duplicate reaction rate found: {rate_name}")
reaction_rates[rate_name] = df.iloc[0][key]

return reaction_rates

def add_species_concentration(self, species_concentration):
Expand Down Expand Up @@ -294,18 +262,6 @@ def update_conditions(self, new_conditions):
self.pressure = new_conditions.pressure
if new_conditions.temperature is not None:
self.temperature = new_conditions.temperature
for conc in new_conditions.species_concentrations:
match = filter(
lambda x: x.species.name == conc.species.name,
self.species_concentrations)
for item in list(match):
item.concentration = conc.concentration

for rate in new_conditions.reaction_rates:

match = filter(
lambda x: x.reaction.name == rate.reaction.name,
self.reaction_rates)
self.species_concentrations.update(new_conditions.species_concentrations)

for item in list(match):
item.rate = rate.rate
self.reaction_rates.update(new_conditions.reaction_rates)
Loading

0 comments on commit d82d6ea

Please sign in to comment.