Skip to content

Commit bf55368

Browse files
committed
TMP
1 parent d676a05 commit bf55368

File tree

5 files changed

+116
-113
lines changed

5 files changed

+116
-113
lines changed

t3/common.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -284,7 +284,9 @@ def determine_concentrations_by_equivalence_ratios(species: List[dict]):
284284
inchi=objects['fuel']['inchi'] if 'inchi' in objects['fuel'].keys() else None
285285
)
286286
objects['oxygen']['concentration'] = [eq_ratio * o2_stoichiometry for eq_ratio in objects['fuel']['equivalence_ratios']]
287-
if objects['nitrogen'] is not None and objects['nitrogen']['concentration'] == 0:
287+
if objects['nitrogen'] is not None and not ('concentration' in objects['nitrogen']
288+
and isinstance(objects['nitrogen']['concentration'], list)
289+
and len(objects['nitrogen']['concentration']) > 1):
288290
objects['nitrogen']['concentration'] = [o2 * 3.76 for o2 in objects['oxygen']['concentration']]
289291
return objects
290292

@@ -337,5 +339,6 @@ def remove_numeric_parentheses(input_string: str) -> str:
337339
Returns:
338340
str: The string without numeric parentheses.
339341
"""
342+
print(input_string, type(input_string))
340343
result = re.sub(r'\(\d+\)$', '', input_string)
341344
return result

t3/schema.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ def check_ranged_concentration_not_constant(cls, value, values):
198198
return value
199199

200200
@validator('role')
201-
def check_species_role(cls, value, values):
201+
def check_species_role(cls, value):
202202
"""RMGSpecies.role validator"""
203203
if value not in ['fuel', 'oxygen', 'nitrogen', None]:
204204
raise ValueError(f'The species role must be either "fuel", "oxygen", or "nitrogen".\nGot: {value}')

t3/simulate/cantera_IDT.py

Lines changed: 48 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
from arc.common import save_yaml_file
1616

17-
from t3.common import determine_concentrations_by_equivalence_ratios
17+
from t3.common import determine_concentrations_by_equivalence_ratios, remove_numeric_parentheses
1818
from t3.logger import Logger
1919
from t3.simulate.adapter import SimulateAdapter
2020
from t3.simulate.factory import register_simulate_adapter
@@ -84,12 +84,11 @@ def __init__(self,
8484
self.spc_identifier_lookup, self.rxn_identifier_lookup = dict(), dict()
8585
self.num_ct_reactions = None
8686
self.num_ct_species = None
87-
self.T_list, self.P_list, self.reaction_time_list = list(), list(), list()
87+
self.T_list, self.P_list, self.reaction_time_list, self.species_names_without_indices = list(), list(), list(), list()
8888
self.idt_dict = dict()
8989

9090
self.set_up()
9191
self.radical_label = self.determine_radical_label()
92-
print(f'radical label: {self.radical_label}')
9392

9493
def set_up(self):
9594
"""
@@ -106,7 +105,8 @@ def set_up(self):
106105
self.spc_identifier_lookup[spc.name] = i
107106
for i, rxn in enumerate(self.model.reactions()):
108107
self.rxn_identifier_lookup[rxn.equation] = i
109-
self.species_names_without_indices = [self.model.species()[i].name.split('(')[0] for i in range(self.num_ct_species)] # Todo: what about HNO(T)(21)? make more robust
108+
self.species_names_without_indices = [remove_numeric_parentheses(self.model.species()[i].name)
109+
for i in range(self.num_ct_species)]
110110

111111
self.T_list = ([self.rmg['reactors'][0]['T']], 'K')
112112
self.P_list = ([self.rmg['reactors'][0]['P']], 'bar')
@@ -119,29 +119,34 @@ def simulate(self):
119119
self.logger.info('Running a simulation using CanteraIDT...')
120120

121121
equivalence_ratios, concentration_combinations = self.get_concentration_combinations()
122+
print(f'equivalence_ratios: {equivalence_ratios}\nconcentration_combinations: {concentration_combinations}')
122123
reactor_idt_dict = dict()
123124
for r, reactor in enumerate(self.rmg['reactors']):
124125
T_list, P_list = get_t_and_p_lists(reactor)
125126
if equivalence_ratios is not None and concentration_combinations is not None:
126127
for i, X in enumerate(concentration_combinations):
128+
if self.idt_dict.get(equivalence_ratios[i]) is None:
129+
self.idt_dict[equivalence_ratios[i]] = dict()
127130
for P in P_list:
131+
if self.idt_dict[equivalence_ratios[i]].get(P) is None:
132+
self.idt_dict[equivalence_ratios[i]][P] = dict()
128133
for T in T_list:
129134
print(f'T: {T}, P: {P},\nX: {X}')
130135
self.model.TPX = T, P * 1e5, X
131-
self.idt_dict[(equivalence_ratios[i], P, T)] = \
132-
self.simulate_idt(fig_name=f'R{r}_{equivalence_ratios[i]}_{round(P,2)}_bar_{round(T,2)}_K.png')
136+
self.idt_dict[equivalence_ratios[i]][P][T] = \
137+
self.simulate_idt(fig_name=f'R{r}_{equivalence_ratios[i]}_{P:.2f}_bar_{round(T,2)}_K.png')
133138
else:
134139
X = {spc['label']: spc['concentration'] for spc in self.rmg['species'] if spc['concentration']}
135140
for P in P_list:
136141
for T in T_list:
137142
print(f'T: {T}, P: {P},\nX: {X}')
138143
self.model.TPX = T, P * 1e5, X
139144
if equivalence_ratios is None:
140-
self.idt_dict[(0, P, T)] = \
141-
self.simulate_idt(fig_name=f'R{r}_{round(P,2)}_bar_{round(T,2)}_K.png')
145+
self.idt_dict[0][P][T] = \
146+
self.simulate_idt(fig_name=f'R{r}_{round(P,2)}_bar_{T:.2f}_K.png')
142147
else:
143-
self.idt_dict[(equivalence_ratios[i], P, T)] = \
144-
self.simulate_idt(fig_name=f'R{r}_{equivalence_ratios[i]}_{round(P,2)}_bar_{round(T,2)}_K.png')
148+
self.idt_dict[equivalence_ratios[i]][P][T] = \
149+
self.simulate_idt(fig_name=f'R{r}_{equivalence_ratios[i]}_{P:.2f}_bar_{T:.2f}_K.png')
145150
if len(T_list) >= 3:
146151
plot_idt_vs_temperature(self.idt_dict, figs_path=self.paths['figs'], reactor_index=r)
147152
reactor_idt_dict[r] = self.idt_dict
@@ -212,6 +217,8 @@ def get_cantera_species_label(self, rmg_label: str) -> Optional[str]:
212217
for i, label in enumerate(self.species_names_without_indices):
213218
if label == rmg_label:
214219
return self.model.species()[i].name
220+
if label == remove_numeric_parentheses(rmg_label):
221+
return self.model.species()[i].name
215222
return None
216223

217224
def get_concentration_combinations(self) -> Tuple[Optional[List[float]], Optional[List[dict]]]:
@@ -236,8 +243,8 @@ def get_concentration_combinations(self) -> Tuple[Optional[List[float]], Optiona
236243
concentration_dict = dict()
237244
for spc in self.rmg['species']:
238245
if spc['role'] is None:
239-
cantera_label = self.get_cantera_species_label(spc['label'])
240-
if cantera_label is not None:
246+
cantera_label = self.get_cantera_species_label(spc['label']) # can take out of loop
247+
if cantera_label is not None and spc['concentration'] != 0:
241248
concentration_dict[cantera_label] = spc['concentration']
242249
if spc['role'] == 'fuel':
243250
cantera_label = self.get_cantera_species_label(spc['label'])
@@ -307,7 +314,7 @@ def compute_idt(time_history: ct.SolutionArray,
307314
Optional[float]: The IDT in seconds.
308315
309316
Todo:
310-
- solve possible noice in dc/dt. ** add IDT(1000/T) figure.
317+
- solve possible noise in dc/dt. ** add IDT(1000/T) figure.
311318
"""
312319
figs_path = os.path.join(figs_path, 'IDTs')
313320
if not os.path.isdir(figs_path):
@@ -317,7 +324,7 @@ def compute_idt(time_history: ct.SolutionArray,
317324
dc_dt = np.diff(concentration) / np.diff(times)
318325
idt_index_dc_dt = np.argmax(dc_dt)
319326
idt_index_c = np.argmax(concentration)
320-
idt = times[idt_index_dc_dt]
327+
idt = float(times[idt_index_dc_dt])
321328
if idt_index_dc_dt > len(times) - 10 or idt < 1e-12 or max(concentration) < concentration[0] * 100:
322329
return None
323330
try:
@@ -354,80 +361,72 @@ def get_t_and_p_lists(reactor: dict) -> Tuple[List[float], List[float]]:
354361
"""
355362
if isinstance(reactor['T'], (int, float)):
356363
T_list = [reactor['T']]
357-
else:
364+
elif len(reactor['T']) == 2:
358365
inverse_ts = np.linspace(1 / reactor['T'][1],
359-
1 / reactor['T'][0], num=100) # 15 inverse T points
366+
1 / reactor['T'][0], num=min(int(abs(reactor['T'][1] - reactor['T'][0]) / 10), 50))
360367
T_list = [1 / inverse_t for inverse_t in inverse_ts[::-1]]
368+
else:
369+
T_list = [float(t) for t in reactor['T']]
361370
if isinstance(reactor['P'], (int, float)):
362371
P_list = [reactor['P']]
363-
else:
372+
elif len(reactor['P']) == 2:
364373
base = 10
365374
log_p = np.linspace(math.log(reactor['P'][0], base),
366375
math.log(reactor['P'][1], base), num=3) # 3 pressure in log10 space
367376
P_list = [base ** p for p in log_p]
377+
else:
378+
P_list = [float(p) for p in reactor['P']]
379+
T_list = [float(t) for t in T_list]
380+
P_list = [float(p) for p in P_list]
368381
return T_list, P_list
369382

370383

371384
def plot_idt_vs_temperature(idt_dict: dict,
372385
figs_path: str,
373386
reactor_index: int = 0,
374-
exp_data: tuple = None,
387+
exp_data: dict = None,
375388
) -> None:
376389
"""
377390
Plot IDT vs. 1000/T per phi and P condition combination.
391+
If exp_data is provided, plot the experimental data as well and only consider phi and P values that appear in it.
378392
379-
idt_dict[(equivalence_ratios[i], P, T)]
393+
idt_dict[equivalence_ratios[i]][P][T]
380394
381395
Args:
382396
idt_dict (dict): A dictionary containing IDT values.
383397
figs_path (str): The path to the figures' directory.
384398
reactor_index (int, optional): The reactor index.
385-
exp_data (tuple): Experimental data in lists for IDT [sec] and 1000/T [K]
399+
exp_data (dict): Experimental data in the same format as idt_dict, IDT units are in s.
386400
"""
387401
figs_path = os.path.join(figs_path, 'IDT_vs_T')
388402
if not os.path.isdir(figs_path):
389403
os.makedirs(figs_path)
390-
data = get_idt_per_phi_p_condition(idt_dict)
391-
392-
for phi, phi_data in data.items():
404+
for phi, phi_data in idt_dict.items():
405+
print(f'phi: {phi}')
406+
if exp_data is not None and phi not in exp_data:
407+
print(f'phi {phi} not in exp_data')
408+
continue
393409
for p, phi_p_data in phi_data.items():
394-
fig_name = f'R{reactor_index}_{phi}_{round(p,2)}_bar.png'
410+
if exp_data is not None and p not in exp_data[phi]:
411+
print(f'p {p} not in exp_data')
412+
continue
413+
fig_name = f'R{reactor_index}_{phi}_{p:.2f}_bar.png'
414+
print(f'fig_name: {fig_name}')
395415
try:
396416
fig, ax = plt.subplots()
397417
ax.set_xlabel('1000/T (1/K)')
398418
ax.set_ylabel('IDT (s)')
399-
ax.set_title(f'IDT vs. 1000/T, phi = {phi}, P = {p} bar')
400-
ax.scatter(phi_p_data.keys(), phi_p_data.values(), label='simulation', color='blue', marker="o")
419+
ax.set_title(f'IDT vs. 1000/T, phi = {phi}, P = {p:.2f} bar')
420+
ax.scatter([1000 / t for t in phi_p_data.keys()], phi_p_data.values(), label='simulation', color='blue', marker='o', linestyle='-')
401421
ax.set_yscale('log')
402422
if exp_data is not None:
403-
ax.scatter(exp_data[0], exp_data[1], label='experiment', color='orange', marker="D")
423+
ax.scatter([1000 / t for t in exp_data[phi][p].keys()], [e * 1e-6 for e in exp_data[phi][p].values()], label='experiment', color='orange', marker="D")
404424
ax.set_yscale('log')
405425
ax.legend(loc='lower right')
406426
fig.savefig(os.path.join(figs_path, fig_name))
407427
except (AttributeError, ValueError):
428+
raise
408429
pass
409430

410431

411-
def get_idt_per_phi_p_condition(idt_dict: dict) -> dict:
412-
"""
413-
Get IDT values per phi, P, and 1000/T condition combination.
414-
415-
Args:
416-
idt_dict (dict): A dictionary containing IDT values.
417-
418-
Returns:
419-
dict: A dictionary containing IDT values per phi and P condition combination corresponding to the 1000/T list.
420-
"""
421-
data = dict()
422-
for triple_key in idt_dict.keys():
423-
phi, p, _ = triple_key
424-
if phi not in data.keys():
425-
data[phi] = dict()
426-
if p not in data[phi].keys():
427-
data[phi][p] = dict()
428-
for triple_key, value in idt_dict.items():
429-
data[triple_key[0]][triple_key[1]][1000 / triple_key[2]] = value
430-
return data
431-
432-
433432
register_simulate_adapter("CanteraIDT", CanteraIDT)

tests/test_common.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,4 +180,5 @@ def test_remove_numeric_parentheses():
180180
assert common.remove_numeric_parentheses('CH2(S)') == 'CH2(S)'
181181
assert common.remove_numeric_parentheses('C2H5(547)') == 'C2H5'
182182
assert common.remove_numeric_parentheses('C2H5(547)H') == 'C2H5(547)H'
183+
assert common.remove_numeric_parentheses('HNO(T)(21)') == 'HNO(T)'
183184

0 commit comments

Comments
 (0)