Skip to content

Commit ce6d8d6

Browse files
committed
Various minor repo-wide fixes
1 parent ff2d176 commit ce6d8d6

14 files changed

Lines changed: 77 additions & 27 deletions

CODE_OF_CONDUCT.md

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
# The Tandem Tool (T3) for automated chemical kinetic model development
2-
3-
# Code of Conduct
1+
# T3 Code of Conduct
42

53
## Our Pledge
64

t3/main.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1152,13 +1152,13 @@ def get_reaction_key(self,
11521152
try:
11531153
if label == t3_reaction.get_reaction_smiles_label():
11541154
return key
1155-
except Exception:
1155+
except (AttributeError, ValueError):
11561156
pass
11571157
elif label_type == 'Chemkin':
11581158
try:
11591159
if label == t3_reaction.to_chemkin():
11601160
return key
1161-
except Exception:
1161+
except (AttributeError, ValueError):
11621162
pass
11631163
return None
11641164

t3/runners/rmg_runner.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,11 @@
44
"""
55

66
import datetime
7+
import logging
78
import os
89
import shlex
910
import shutil
11+
import subprocess
1012
import time
1113
from typing import TYPE_CHECKING, List, Optional, Tuple
1214

@@ -171,7 +173,10 @@ def _parse_walltime_to_seconds(walltime: str) -> int:
171173
parts = walltime.split(':')
172174
if len(parts) != 4:
173175
return 0
174-
days, hours, minutes, seconds = (int(p) for p in parts)
176+
try:
177+
days, hours, minutes, seconds = (int(p) for p in parts)
178+
except ValueError:
179+
return 0
175180
return days * 86400 + hours * 3600 + minutes * 60 + seconds
176181

177182

@@ -218,6 +223,9 @@ def run_rmg_incore(rmg_input_file_path: str,
218223
except subprocess.TimeoutExpired:
219224
logger.error(f'RMG incore timed out after {timeout_s}s')
220225
return True
226+
if result.returncode != 0:
227+
logger.error(f'RMG incore exited with code {result.returncode}')
228+
return True
221229
if 'RMG threw an exception and did not converge.' in stderr_text:
222230
return True
223231
return False

t3/schema.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -477,7 +477,7 @@ class Config:
477477
@classmethod
478478
def check_units(cls, value):
479479
"""RMGOptions.units validator"""
480-
if value.lower() is not None and value != 'si':
480+
if value.lower() != 'si':
481481
raise ValueError(f'Currently RMG only supports SI units, got "{value}"')
482482
return value.lower()
483483

t3/simulate/cantera_base.py

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
different reactor configuration.
99
"""
1010

11+
import logging
1112
import cantera as ct
1213
import numpy as np
1314
from abc import abstractmethod
@@ -331,6 +332,9 @@ def simulate(self):
331332
non_inert_mask = np.ones(self.num_ct_species, dtype=bool)
332333
non_inert_mask[self.inert_index_list] = False
333334

335+
if not np.all(np.isfinite(mass_frac_sa)):
336+
logging.getLogger(__name__).warning(
337+
'NaN/inf detected in mass fraction SA matrix — check for numerical issues')
334338
kin_correction = mass_frac_sa[non_inert_mask, :self.num_ct_reactions].sum(axis=0)
335339
thermo_correction = mass_frac_sa[non_inert_mask, self.num_ct_reactions:].sum(axis=0)
336340

@@ -462,9 +466,17 @@ def get_idt_by_T(self):
462466
time, data_list, reaction_sensitivity_data, thermodynamic_sensitivity_data = condition_data
463467
T_data = data_list[0]
464468

465-
dTdt = np.diff(T_data.data) / np.diff(time.data)
466-
idt_dict['idt_index'].append(int(np.argmax(dTdt)))
467-
idt_dict['idt'].append(time.data[idt_dict['idt_index'][i]])
469+
dt = np.diff(time.data)
470+
dt = np.where(dt == 0, np.finfo(float).tiny, dt)
471+
dTdt = np.diff(T_data.data) / dt
472+
valid = np.isfinite(dTdt)
473+
if valid.any():
474+
masked = np.where(valid, dTdt, -np.inf)
475+
idx = int(np.argmax(masked))
476+
else:
477+
idx = 0
478+
idt_dict['idt_index'].append(idx)
479+
idt_dict['idt'].append(time.data[min(idx + 1, len(time.data) - 1)])
468480

469481
return idt_dict
470482

t3/simulate/cantera_jsr.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,8 @@ def reinitialize_simulation(self, T0=None, P0=None, X0=None, V0=None):
114114
self._jsr_exhaust = ct.Reservoir(self.model)
115115
self.cantera_reactor = ct.IdealGasReactor(self.model, energy='off', volume=VOLUME)
116116

117+
if residence_time <= 0:
118+
raise ValueError(f'Invalid residence time: {residence_time}')
117119
self._jsr_mfc = ct.MassFlowController(
118120
upstream=self._jsr_inlet,
119121
downstream=self.cantera_reactor,

t3/simulate/cantera_pfr.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ def _compute_distance(self):
129129
# Velocity: u = u_0 * mean_MW_0 / mean_MW (P, T, A all cancel)
130130
total_residence_time = self.conditions[idx].reaction_time.value_si
131131
u_0 = LENGTH / total_residence_time
132+
mean_MW = np.where(mean_MW > 0, mean_MW, np.finfo(float).tiny)
132133
u = u_0 * mean_MW[0] / mean_MW
133134

134135
# Axial distance [m] via cumulative integration
@@ -203,6 +204,8 @@ def _simulate_chain(self):
203204
sim.advance_to_steady_state()
204205

205206
# Residence time in this cell
207+
if mass_flow_rate <= 0:
208+
raise ValueError(f'Invalid mass flow rate: {mass_flow_rate}')
206209
cell_residence_time = reactor.mass / mass_flow_rate
207210
cumulative_time += cell_residence_time
208211

t3/simulate/cantera_pfr_t_profile.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,11 @@
107107
T_HOT = 900.0 # K, isothermal plateau temperature
108108
T_OUTLET = 500.0 # K, outlet temperature
109109

110+
if not (0 < RAMP_UP_END < ISO_END < LENGTH):
111+
raise ValueError(
112+
f'Temperature profile constants must satisfy 0 < RAMP_UP_END ({RAMP_UP_END}) < ISO_END ({ISO_END}) < LENGTH ({LENGTH})'
113+
)
114+
110115

111116
def temperature_profile(z):
112117
"""
@@ -307,7 +312,11 @@ def simulate(self):
307312
# Local velocity at the new (T, rho) and the corresponding
308313
# time step to traverse one segment.
309314
rho = self.model.density
315+
if rho * AREA <= 0:
316+
raise ValueError(f'Invalid density ({rho}) or area ({AREA}) in PFR T-profile cell {n}')
310317
u = mass_flow_rate / (rho * AREA)
318+
if u <= 0:
319+
raise ValueError(f'Invalid velocity ({u}) in PFR T-profile cell {n}')
311320
dt = dz / u
312321

313322
sim.advance(sim.time + dt)

t3/simulate/rmg_constant_tp.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
import datetime
77
import itertools
8+
import logging
89
import os
910
import numpy as np
1011
from typing import List, Optional, TYPE_CHECKING
@@ -131,6 +132,7 @@ def simulate(self):
131132

132133
if not success:
133134
self.logger.error(f"RMG SA subprocess failed.\nDetails: {error_msg}")
135+
raise RuntimeError(f"RMG SA subprocess failed: {error_msg}")
134136
else:
135137
self.logger.info("RMG SA subprocess completed successfully.")
136138
else:
@@ -279,6 +281,12 @@ def get_species_concentration_lists_from_ranged_params(self) -> List[List[dict]]
279281
species_lists.append(new_species_list)
280282

281283
for species_list in species_lists:
284+
total = sum(s['concentration'] for s in species_list
285+
if isinstance(s['concentration'], (int, float)))
286+
if total > 1.0 or total <= 0:
287+
logging.getLogger(__name__).warning(
288+
f'Species concentrations sum to {total:.4f}, expected (0, 1]. '
289+
f'Cantera will normalize mole fractions.')
282290
species_list.sort(key=lambda spc: spc['concentration'][0] if isinstance(spc['concentration'], (tuple, list))
283291
else spc['concentration'], reverse=True)
284292
return species_lists

t3/utils/libraries.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@
2121
from t3.logger import Logger
2222

2323

24-
_LOCK_TIMEOUT_S = 3600 # 1 hour wait for lock acquisition
25-
_LOCK_STALE_S = 3600 # 1 hour before breaking a stale lock
24+
_LOCK_TIMEOUT_S = 300 # 5 min wait for lock acquisition
25+
_LOCK_STALE_S = 300 # 5 min before breaking a stale lock
2626
_LOCK_POLL_S = 10.0 # Poll every 10 seconds
2727

2828

0 commit comments

Comments
 (0)