3. Creating the Reaction Model
The ReactionModel stores information about each elementary reaction step.
Properties
initial(list[str]): Initial configuration (e.g.,['1 CO* 1', '2 * 1']).final(list[str]): Final configuration (e.g.,['1 C* 1', '2 O* 1']).activ_eng(float): Activation energy (eV).vib_energies_is(list[float]): Vibrational energies for the initial state (meV).vib_energies_fs(list[float]): Vibrational energies for the final state (meV).vib_energies_ts(list[float], optional): Vibrational energies for the transition state (meV).
Omit or set to[]for non-activated steps.area_site(float, optional): Site area (Ų); required if a gas species participates.molecule_is(str, optional): Name of gas-phase molecule in the initial state (only for adsorption).molecule_fs(str, optional): Name of gas-phase molecule in the final state (only for desorption).site_types(str, optional): Site types required iflattice_type='periodic_cell').neighboring(str, optional): Connectivity between sites (e.g.,'1-2'; default =None).prox_factor(float, optional): Proximity factor.angles(str, optional): Angle constraints (e.g.,'1-2-3:180'; default =None).graph_multiplicity(intorfloat, optional): Symmetry factor of the step. The computed pre-exponential factor is divided by this value.fixed_pre_expon(float, optional): Fixed forward pre-exponential factor (no scaling or symmetry applied).
Units must follow Zacros conventions:Surface/non-activated desorption →
s⁻¹Adsorption (activated/non-activated) →
bar⁻¹·s⁻¹
fixed_pe_ratio(float, optional): Fixed pre-exponential ratiope_fwd/pe_rev. Must be used withfixed_pre_expon.
Deprecation note: The old
moleculecolumn is deprecated and treated asmolecule_iswith a warning.
How to create it
You can provide a dictionary where each key is a cluster name and each value is a dictionary of elementary step properties:
from zacrostools.reaction_model import ReactionModel
steps_data = {
'CO_adsorption': {
'activ_eng': 0.0,
'area_site': 5.34,
'initial': ['1 * 1'],
'final': ['1 CO* 1'],
'molecule_is': 'CO',
'prox_factor': 0.0,
'site_types': 'top',
'vib_energies_is': [263.427],
'vib_energies_fs': [240.497, 82.738, 60.132, 60.080, 7.271, 6.553],
},
'O2_adsorption': {
'activ_eng': 0.742,
'area_site': 5.34,
'initial': ['1 * 1, 2 * 1'],
'final': ['1 O* 1, 2 O* 1'],
'neighboring': '1-2',
'molecule_is': 'O2',
'prox_factor': 0.5,
'site_types': 'top',
'vib_energies_is': [263.427],
'vib_energies_ts': [244.692, 81.168, 53.342, 30.084, 2.234],
'vib_energies_fs': [240.497, 82.738, 60.132, 60.080, 7.271, 6.553],
},
'CO+O_to_CO2': {
'activ_eng': 1.693,
'initial': ['1 CO* 1', '2 O* 1'],
'final': ['1 CO2* 1', '2 * 1'],
'neighboring': '1-2',
'site_types': 'top top',
'vib_energies_is': [171.188, 145.669, 96.964, 86.255, 56.201, 52.376, 35.933, 24.343, 21.025],
'vib_energies_ts': [217.941, 81.362, 66.833, 56.918, 50.342, 37.430, 19.074, 12.356],
'vib_energies_fs': [240.497, 82.738, 60.133, 60.080, 7.272, 6.553, 78.662, 40.796, 40.349],
},
'CO2_adsorption': { # recommended to define the forward direction as the adsorption
'activ_eng': 0.0,
'area_site': 5.34,
'initial': ['1 * 1'],
'final': ['1 CO2* 1'],
'molecule_is': 'CO2',
'prox_factor': 0.0,
'site_types': 'top',
'vib_energies_is': [293.279, 163.686, 78.019, 77.959],
'vib_energies_fs': [171.188, 145.668, 96.961, 86.214, 56.201, 52.375, 35.932, 24.343, 21.022],
}
}
reaction_model = ReactionModel.from_dict(steps_data)
Alternatively, it can also be created from a CSV file. In this case, the indexes must correspond to the elementary step names:
from zacrostools.reaction_model import ReactionModel
reaction_model = ReactionModel.from_csv('mechanism_data.csv')
Finally, it can also be created from a Pandas dataframe:
import pandas as pd
from zacrostools.reaction_model import ReactionModel
df = pd.read_csv("reactions_data.csv") # or create dataframe directly
reaction_model = ReactionModel.from_df(df)
Adding and removing steps
Use the add_step method to add a new step:
reaction_model.add_step(step_info={
'step_name': 'CO_diffusion',
'activ_eng': 1.156,
'initial': ['1 CO* 1', '2 * 1'],
'final': ['1 * 1', '2 CO* 1'],
'neighboring': '1-2',
'graph_multiplicity': 2.0,
'site_types': 'top top',
'vib_energies_fs': [240.497, 82.738, 60.133, 60.080, 7.272, 6.553],
'vib_energies_is': [240.497, 82.738, 60.133, 60.080, 7.272, 6.553],
'vib_energies_ts': [218.382, 53.527, 47.612, 28.580, 6.600]
})
Use the remove_steps method to remove a step:
steps_to_remove = ['O_diffusion']
reaction_model.remove_steps(steps_to_remove)
Writing the mechanism_input.dat file
The ReactionModel can generate the mechanism_input.dat file required by Zacros.
Required parameters:
output_dir(strorPath): Directory where the file will be written.temperature(float): Temperature in Kelvin for pre-exponential calculations.gas_model(GasModel): Instance ofGasModelcontaining gas-phase species data.manual_scaling(dict, optional): Dictionary of manual scaling factors per step.stiffness_scalable_steps(list, optional): List of steps that are stiffness scalable.stiffness_scalable_symmetric_steps(list, optional): List of steps that are stiffness scalable and symmetric.sig_figs_energies(int, optional): Number of significant figures for activation energies.sig_figs_pe(int, optional): Number of significant figures for pre-exponential factors.
from zacrostools.gas_model import GasModel
gas_model = GasModel.from_csv('gas_data.csv')
reaction_model.write_mechanism_input(
output_dir='kmc_simulation',
temperature=500,
gas_model=gas_model,
sig_figs_energies=8,
sig_figs_pe=8
)
Accessing reaction data
The reaction steps data is stored internally as a Pandas DataFrame, accessible via the df attribute.
print(reaction_model.df)
Full example
Below is a complete example demonstrating the creation and modification of a ReactionModel:
from zacrostools.reaction_model import ReactionModel
from zacrostools.gas_model import GasModel
# Assume gas_model is already defined
gas_model = GasModel.from_csv('gas_data.csv')
# Initial reaction steps data
steps_data = {
'CO_adsorption': {
'activ_eng': 0.0,
'area_site': 5.34,
'initial': ['1 * 1'],
'final': ['1 CO* 1'],
'molecule_is': 'CO',
'prox_factor': 0.0,
'site_types': 'top',
'vib_energies_is': [263.427],
'vib_energies_fs': [240.497, 82.738, 60.132, 60.080, 7.271, 6.553],
}
}
# Create the ReactionModel instance
reaction_model = ReactionModel.from_dict(steps_data)
# Add a new step
reaction_model.add_step(step_info={
'step_name': 'CO_diffusion',
'activ_eng': 1.156,
'initial': ['1 CO* 1', '2 * 1'],
'final': ['1 * 1', '2 CO* 1'],
'neighboring': '1-2',
'graph_multiplicity': 2.0,
'site_types': 'top top',
'vib_energies_is': [240.497, 82.738, 60.133, 60.080, 7.272, 6.553],
'vib_energies_ts': [218.382, 53.527, 47.612, 28.580, 6.600],
'vib_energies_fs': [240.497, 82.738, 60.133, 60.080, 7.272, 6.553],
})
# Remove an existing step
reaction_model.remove_steps(['CO_diffusion'])
# Write the mechanism input file
reaction_model.write_mechanism_input(
output_dir='kmc_simulation',
temperature=500,
gas_model=gas_model,
sig_figs_energies=8,
sig_figs_pe=8
)
# Access the DataFrame
print(reaction_model.df)
Fixing pre-exponential factors
By default, ReactionModel computes the forward pre-exponential factor (pre_expon) and the pre-exponential ratio (pe_ratio) from statistical mechanics.
However, in some cases you may want to fix these values explicitly (for both forward and reverse directions). This can be done by providing two optional parameters:
fixed_pre_expon(float): User-specified forward pre-exponential factor.fixed_pe_ratio(float): User-specified pre-exponential ratio.
⚠️ Important:
If one of these parameters is provided, the other must also be provided.
Using
fixed_pre_expon/fixed_pe_ratiois incompatible with:Setting
stiffness_scalable_steps="all".Including a fixed step in
stiffness_scalable_steps.Including a fixed step in
stiffness_scalable_symmetric_steps.
If any of these conditions occur, a ReactionModelError is raised.
from zacrostools.reaction_model import ReactionModel
reaction_data = {
'CO_adsorption': {
'activ_eng': 0.0,
'area_site': 5.34,
'initial': ['1 * 1'],
'final': ['1 CO* 1'],
'molecule_is': 'CO',
'prox_factor': 0.0,
'site_types': 'top',
'vib_energies_is': [263.427],
'vib_energies_fs': [240.497, 82.738, 60.132, 60.080, 7.271, 6.553],
"fixed_pre_expon": 1.0e13, # in s^-1 or bar^-1·s^-1 depending on type
"fixed_pe_ratio": 2.5
},
}
reaction_model = ReactionModel.from_dict(reaction_data)