Reading output files
Overview
After completing a Zacros simulation, zacrostools can be used to parse and analyze the results.
Extract data from a single simulation
The KMCOutput class provides a convenient interface to load simulation data from output files, compute averages and coverages, and extract key performance indicators like turnover frequencies (TOFs) and selectivities.
Example
from zacrostools.kmc_output import KMCOutput
# Create a KMCOutput object to read data from the current directory.
# Here, we consider the last 50% of the simulation time and apply time-weighted averaging.
kmc_output = KMCOutput(path='simulation_files', analysis_range=[50, 100], range_type='time', weights='time')
Arguments
Mandatory:
path(str): Path to the directory containing the Zacros output files (e.g.,simulation_input.dat,general_output.txt,specnum_output.txt, etc.).
Optional:
analysis_range(list, default:[0.0, 100.0]): Defines the segment of the simulation considered for averaging and analysis. The two-element list[start_percent, end_percent]specifies the portion of the simulation to use. For instance,[50, 100]focuses on the last half of the simulation.range_type(str, default:'time'): Determines howanalysis_rangeis interpreted:'time': The percentages refer to segments of total simulated time.'nevents': The percentages refer to segments of the total number of simulated events.
weights(str, default:None): Sets the weighting scheme for averaging:'time': Weighted by the time interval between data points.'nevents': Weighted by the number of events between data points.None: No weighting (all data points are equally weighted).
Accessing simulation data
Once you have created a KMCOutput object, you can access a variety of data fields, as summarized below.
General simulation data
random_seed(int): Random seed used by Zacros.temperature(float): Simulation temperature (K).pressure(float): Total pressure (bar).n_gas_species(int): Number of gas-phase species.gas_specs_names(list of str): Names of the gas-phase species.gas_molar_fracs(list of float): Molar fractions of each gas species.n_surf_species(int): Number of surface-bound species.surf_specs_names(list of str): Names of the surface species.n_sites(int): Total number of lattice sites.area(float): Catalyst surface area (Ų).site_types(dict): Mapping of site types to the number of sites of each type (e.g.,{'top': 50, 'bridge': 50}).
Events and time
nevents(np.ndarray): Array of integers representing the cumulative number of KMC events at each recorded data point.time(np.ndarray): Simulated time at each data point (s).finaltime(float): Final simulation time (s).
Lattice energy
energy(np.ndarray): Lattice energy over time (eV·Å⁻²).av_energy(float): Time/Events-weighted average lattice energy (eV·Å⁻²).final_energy(float): Final lattice energy (eV·Å⁻²).energyslope(float): Slope of energy vs. events (eV·Å⁻²·step⁻¹). A large slope may suggest the simulation did not reach steady-state.
Gas production and TOF
production(dict): Dictionary of arrays tracking the cumulative production of each gas species over time (in molecules). For example,kmc_output.production['CO']gives an array of CO production values.total_production(dict): Total number of molecules produced for each gas species by the end of the simulation. Example:kmc_output.total_production['CO'].tof(dict): Turnover frequency of each gas species (molecules·s⁻¹·Å⁻²), indicating production rate normalized by the catalyst area. For example,kmc_output.tof['CO2'].
Surface coverage
coverage(dict): Coverage of each surface species over time, expressed as a percentage of total sites. Example:kmc_output.coverage['CO']gives an array of CO coverage values.av_coverage(dict): Weighted average coverage of each surface species over the analysis window. Example:kmc_output.av_coverage['CO'].total_coverage(np.ndarray): Total coverage of all surface species combined, over time (%).av_total_coverage(float): Average total coverage (%).dominant_ads(str): The surface species with the highest average coverage.
Coverage per site type
To gain more detailed insight, you can also access coverage data broken down by site type:
coverage_per_site_type(dict): Nested dictionaries of coverage by site type and species over time. Example:kmc_output.coverage_per_site_type['top']['CO'].av_coverage_per_site_type(dict): Weighted average coverage per site type and species. Example:kmc_output.av_coverage_per_site_type['top']['CO'].total_coverage_per_site_type(dict): Total coverage per site type over time (%).av_total_coverage_per_site_type(dict): Average total coverage per site type (%).dominant_ads_per_site_type(dict): Dominant adsorbed species on each site type.
Methods
get_selectivity()
The get_selectivity() method calculates the selectivity of a main product relative to other side products, providing a measure of reaction specificity.
Parameters:
main_product(str): Main product species name.side_products(list of str): List of side product species names.
Returns:
(float): Selectivity (in %) of the main product over the side products.
Notes:
The selectivity is defined as:
selectivity = (TOF_main_product / (TOF_main_product + sum(TOF_side_products))) * 100
If the denominator is zero (no products formed), the method returns NaN.
Example:
selectivity = kmc_output.get_selectivity(main_product='CH4', side_products=['CO2', 'CH3OH'])
print(f"CH4 Selectivity: {selectivity:.2f} %")
Examples of usage
Printing TOFs
for gas_species in kmc_output.gas_specs_names:
tof = kmc_output.tof[gas_species]
print(f"TOF of {gas_species}: {tof:.3e} molecules·s⁻¹·Å⁻²")
Checking selectivity
selectivity = kmc_output.get_selectivity(main_product='CH4', side_products=['CO2', 'CH3OH'])
print(f"Selectivity for CH4: {selectivity:.2f} %")
Average coverage on total sites
for surf_species in kmc_output.surf_specs_names:
avg_cov = kmc_output.av_coverage[surf_species]
print(f"Average coverage of {surf_species}: {avg_cov:.3f} % of total sites")
Average coverage per site type
for stype in kmc_output.site_types:
for sps in kmc_output.av_coverage_per_site_type[stype]:
avg_cov = kmc_output.av_coverage_per_site_type[stype][sps]
print(f"Average coverage of {sps} on {stype} sites: {avg_cov:.3f} %")
Complete example
from zacrostools.kmc_output import KMCOutput
# Read simulation output
kmc_output = KMCOutput(
path='temp_600K',
analysis_range=[50, 100],
range_type='time',
weights='time')
# Print TOF of all gas-phase species
for gas_spec in kmc_output.gas_specs_names:
tof = kmc_output.tof[gas_spec]
print(f"{gas_spec}: {tof:.3e} molec·s⁻¹·Å⁻²")
# Compute selectivity of CH4 vs CO2 and CH3OH
select_ch4 = kmc_output.get_selectivity(
main_product='CH4',
side_products=['CO2', 'CH3OH'])
print(f"Selectivity of CH4: {select_ch4:.2f}%")
# Print average coverage of all surface species
for surf_spec in kmc_output.surf_specs_names:
avg_cov = kmc_output.av_coverage[surf_spec]
print(f"{surf_spec}: {avg_cov:.2f}%")
Extract data from multiple simulations
The read_scan function can be used to read the results of all KMC simulations in a given scan directory. This function returns a Pandas DataFrame containing key observables for each simulation.
Example
from zacrostools.read_scan import read_scan
data_scan = read_scan(
scan_path='path_to_scan',
analysis_range=[50, 100],
range_type='time')
data_scan.to_csv('data_scan.csv', index=True)