Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

v2.5.3 #259

Merged
merged 2 commits into from
Oct 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
139 changes: 48 additions & 91 deletions src/acom_music_box/conditions.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,6 @@
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__)
Expand Down Expand Up @@ -38,13 +30,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 +109,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 +118,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,29 +171,32 @@ 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

Expand Down Expand Up @@ -294,18 +263,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
Loading