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

Compute IDT and IDT SA using Cantera #150

Open
wants to merge 40 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
231a2a3
Print values if the test helper function `almost_equal()` fails
alongd Jan 22, 2024
e051789
RMG Cantera files are now in the updated YAML format
alongd Jan 19, 2024
ec3e9b6
Fix Cantera files after running RMG
alongd Jan 19, 2024
00e34af
Removed global_observables from adapters and factory
alongd Jan 24, 2024
dbd660c
Added get_o2_stoichiometry() to common
alongd Jan 19, 2024
1d10501
Tests: get_o2_stoichiometry()
alongd Jan 19, 2024
456f12c
Added 'role' to species in schema
alongd Jan 24, 2024
0675d18
Added determine_concentrations_by_equivalence_ratios() to common
alongd Jan 22, 2024
f50595e
Tests: determine_concentrations_by_equivalence_ratios()
alongd Jan 20, 2024
1ea8b57
Added update_species_concentrations() in main
alongd Apr 16, 2024
d2ae8c3
Tests: update_species_concentrations()
alongd Jan 20, 2024
658f6c4
Added the Cantra IDT adapter
NellyMitnik Feb 14, 2024
00384b3
Tests: Cantera IDT
alongd Jan 24, 2024
9e0c6c1
Removed get_idt_by_T from adapter.py and from the RMG adapter
alongd Jan 20, 2024
65429b8
Compute IDT SA in main T3 loop
alongd Jan 22, 2024
5645b08
Tests: Modifications to main tests
alongd Jan 24, 2024
dd1e24b
Added common.remove_numeric_parentheses()
alongd Oct 28, 2024
b68fba8
Tests: common.remove_numeric_parentheses()
alongd Oct 28, 2024
74c1af6
Minor: add exception message in rmg incore script
alongd Nov 12, 2024
5ba291f
Modified the signature of get_sa_coefficients()
alongd Dec 3, 2024
3145a24
f schema
alongd Dec 4, 2024
2daa1ed
f main test
alongd Dec 4, 2024
47521d0
f schema test
alongd Dec 4, 2024
7887aef
f common
alongd Dec 4, 2024
5fb8835
f main
alongd Dec 4, 2024
4ae5bb8
f rmg runner
alongd Dec 4, 2024
0f2c129
f schema
alongd Dec 4, 2024
b4f0acf
f rmg constant TP
alongd Dec 4, 2024
aa3541b
f main
alongd Dec 4, 2024
afaff17
f ctIDT init
alongd Dec 4, 2024
c273073
f ct IDT
alongd Dec 4, 2024
9741fa1
f tst idt
alongd Dec 4, 2024
631d51b
Added numpy_to_list() to common
alongd Dec 4, 2024
a8bc69b
Tests: common numpy_to_list()
alongd Dec 4, 2024
d55277c
Use numpy_to_list() in rmg_constantTP to save human readable YAML files
alongd Dec 4, 2024
c11d3ef
Check file exists before fixing Cantera file
alongd Dec 4, 2024
730ad24
Modularize restart()
alongd Dec 4, 2024
1b80838
f rmg runner ?
alongd Dec 4, 2024
76b864b
f main idt
alongd Dec 4, 2024
f9a9282
f schema
alongd Dec 4, 2024
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
6 changes: 5 additions & 1 deletion examples/commented/input.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ t3:
adapter: RMGConstantTP # *required* (this is how SA is requested), can use any implemented simulation adapter
atol: 1e-6 # optional, default: 1e-6
rtol: 1e-4 # optional, default: 1e-4
global_observables: ['IgD', 'ESR', 'SL'] # optional, only implemented in the Cantera adapter, default: ``None``
global_observables: ['IDT', 'ESR', 'SL'] # optional, only implemented in the Cantera adapter, default: ``None``
SA_threshold: 0.01 # optional, default: 0.01
pdep_SA_threshold: 0.001 # optional, used to determine wells and reactions (to be implemented) to calculate
# thermo and rates for from a PES of a sensitive reaction, default: 0.001
Expand Down Expand Up @@ -93,6 +93,8 @@ rmg:
reactive: true # optional, default: ``True``
xyz: [ethane.log] # each entry could be a string/dictionary XYZ format or a file path to parse the information from
seed_all_rads: ['radical', 'alkoxyl', 'peroxyl'] # radical derivatives that will be added the RMG input file
role: 'fuel' # optional mark if this is a 'fuel', 'oxygen', or 'nitrogen' **instead** of specifying concentration, default: ``None``
equivalence_ratios: [0.5, 1.0, 1.5] # optional, but must be given if the role is 'fuel', default: ``None``
- label: OH
smiles: '[OH]'
observable: true # optional, will be used as both SA and UA observable, default: ``False``
Expand All @@ -101,13 +103,15 @@ rmg:
- label: O2
smiles: '[O][O]'
concentration: 3.5
role: 'oxygen' # optional mark if this is a 'fuel', 'oxygen', or 'nitrogen' **instead** of specifying concentration, default: ``None``
- label: N2
adjlist: |
1 N u0 p1 c0 {2,T}
2 N u0 p1 c0 {1,T}
concentration: 3.5 * 3.76
constant: true # optional, only allowed to be ``True`` in liquid phase simulations, default: ``False``
balance: true # optional, only allowed to be ``True`` in gas phase simulations, default: ``False``
role: 'nitrogen' # optional mark if this is a 'fuel', 'oxygen', or 'nitrogen' **instead** of specifying concentration, default: ``None``
- label: water
smiles: O
solvent: true # optional, only allowed to be ``True`` in liquid phase simulations, required for one species for liquid phase simulations, default: ``False``
Expand Down
106 changes: 105 additions & 1 deletion t3/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@
"""

import datetime
import numpy as np
import os
import re
import string
from typing import Dict, Optional, Tuple, Union
from typing import Dict, List, Optional, Tuple, Union

from rmgpy.species import Species

Expand Down Expand Up @@ -302,3 +304,105 @@ def get_parameter_from_header(header: str) -> Optional[str]:
text.append(header[i])
return ''.join(text)


def determine_concentrations_by_equivalence_ratios(species: List[dict]):
"""
Determine species concentrations based on the equivalence ratios if given.

Args:
species (list): Entries are species dictionaries following the schema format for RMG species.

Returns:
dict: A species dictionary with the concentrations as a list (not a range).
"""
objects = {'fuel': None, 'oxygen': None, 'nitrogen': None}
for spc in species:
if spc['role'] == 'fuel':
objects['fuel'] = spc.copy()
elif spc['role'] == 'oxygen':
objects['oxygen'] = spc.copy()
elif spc['role'] == 'nitrogen':
objects['nitrogen'] = spc.copy()
if objects['fuel'] is None or 'equivalence_ratios' not in objects['fuel'] or objects['fuel']['equivalence_ratios'] is None:
return objects
if objects['fuel'] is not None and objects['oxygen'] is not None:
objects['fuel']['concentration'] = objects['fuel']['concentration'] if 'concentration' in objects['fuel'] \
and objects['fuel']['concentration'] else 1
o2_stoichiometry = get_o2_stoichiometry(smiles=objects['fuel']['smiles'],
adjlist=objects['fuel']['adjlist'] if 'adjlist' in objects['fuel'].keys() else None,
inchi=objects['fuel']['inchi'] if 'inchi' in objects['fuel'].keys() else None
)
objects['oxygen']['concentration'] = [eq_ratio * o2_stoichiometry for eq_ratio in objects['fuel']['equivalence_ratios']]
if objects['nitrogen'] is not None and not ('concentration' in objects['nitrogen']
and isinstance(objects['nitrogen']['concentration'], list)
and len(objects['nitrogen']['concentration']) > 1):
objects['nitrogen']['concentration'] = [o2 * 3.76 for o2 in objects['oxygen']['concentration']]
return objects


def get_o2_stoichiometry(smiles: Optional[str] = None,
adjlist: Optional[str] = None,
inchi: Optional[str] = None,
) -> float:
"""
Get the stoichiometry number of O2 for complete combustion of the ``fuel`` molecule.

Args:
smiles (Optional[str]): A SMILES string for the fuel molecule.
adjlist (Optional[str]): An adjacency list string for the fuel molecule.
inchi (Optional[str]): An InChI string for the fuel molecule.

Returns:
float: The stoichiometry of O2 for complete combustion.
"""
if smiles is None and adjlist is None and inchi is None:
raise ValueError('Must provide either a SMILES, an adjacency list, or an InChI string for the fuel molecule.')
if adjlist is None:
fuel = Species(smiles=smiles, inchi=inchi)
else:
fuel = Species().from_adjacency_list(adjlist)
c, h, n, o, other = 0, 0, 0, 0, 0
for atom in fuel.molecule[0].atoms:
if atom.is_carbon():
c += 1
elif atom.is_hydrogen():
h += 1
elif atom.is_nitrogen():
n += 1
elif atom.is_oxygen():
o += 1
else:
other += 1
if other:
raise ValueError(f'Cannot calculate O2 stoichiometry for {fuel.label} with {other} atoms which are not C/H/N/O.')
return 0.5 * (2 * c + 0.5 * h - o)


def remove_numeric_parentheses(input_string: str) -> str:
"""
Remove numeric parentheses from the end of a string.

Args:
input_string (str): The input string.

Returns:
str: The string without numeric parentheses.
"""
result = re.sub(r'\(\d+\)$', '', input_string)
return result


def numpy_to_list(data) -> list:
"""
A helper function to convert NumPy arrays to lists.

Args:
data: The data to convert.

Returns:
list: The converted data.
"""
if isinstance(data, np.ndarray):
return data.tolist()
return data

Loading
Loading