Saddle Search#
A saddle search is initiated by making a local displacement of atoms from their
position at the minimum of the current state. This displacement can be done
using the different strategies indicated by the client_displace_type
option, and the following parameters. If the user knows something about the
local environment where reactions are likely to take place in the system, this
information can be used to make saddle searches more efficient by getting them
started in the right part of configuration space.
Displacement Strategies#
Epicenters and Weight-Based Selection#
Each saddle search begins by choosing an epicenter — a single atom around which the initial displacement is constructed. The epicenter is selected probabilistically from several strategies, each controlled by a relative weight:
Weight parameter |
Strategy |
|---|---|
|
Pick any atom at random |
|
Pick an atom with the lowest coordination number |
|
Pick an atom whose local environment is neither FCC nor HCP |
|
Pick an atom with coordination ≤ |
|
Pick an atom from |
|
Pick an atom whose type is in |
The weights do not need to sum to 1 — they are normalised internally. Setting a
weight to 0 disables that strategy. For example, setting only
displace_listed_atom_weight = 1.0 and all other weights to 0 ensures that
every saddle search starts from an atom in the explicit list.
Radius and Magnitude#
Once the epicenter is chosen, all atoms within displace_radius of the
epicenter are displaced. Each displaced atom receives a random perturbation
drawn from a Gaussian distribution with standard deviation
displace_magnitude (in Ångströms) independently in each Cartesian direction.
Displacing All Listed Atoms#
When displace_all_listed is true and a listed-atom strategy is selected,
every atom in displace_atom_list (or displace_type_list) is displaced —
not just one chosen at random. Atoms within displace_radius of any
displaced atom are also included. Set displace_radius to 0 to restrict the
displacement strictly to the listed atoms.
Dynamic Atom Lists via Scripts#
For systems where the relevant atoms change from state to state (e.g. a
migrating vacancy), a static list is insufficient. The
displace_atom_kmc_state_script option lets you specify a Python script that
is executed once per new AKMC state to determine the atom list dynamically. See
the Targeted Displacement for Saddle Searches tutorial for worked examples
covering vacancy diffusion and adsorbate-on-surface scenarios.
Client-Side Displacement#
The client_displace_type option selects how the client (C++ code) picks
the epicenter when the displacement is performed client-side rather than by the
server:
random— uniform random atomlast_atom— the last atom in the configurationmin_coordinated— the atom with the fewest neighboursnot_fcc_or_hcp— an atom whose local structure is neither FCC nor HCPlisted_atoms— an atom fromdisplace_atom_list(parsed from the INI config; no server displacement file needed)load— read a displacement vector from a file written by the server
Configuration#
[Saddle Search]
Changed in version 3.1_TBA: In TOML, this will be [Saddle_Search]
- pydantic model eon.schema.SaddleSearchConfig[source]#
Show JSON schema
{ "title": "SaddleSearchConfig", "type": "object", "properties": { "method": { "default": "min_mode", "description": "Method to locate the saddle point.", "enum": [ "min_mode", "dynamics" ], "title": "Method", "type": "string" }, "min_mode_method": { "default": "dimer", "description": "Min-mode method to use.", "enum": [ "dimer", "lanczos", "gprdimer" ], "title": "Min Mode Method", "type": "string" }, "max_energy": { "default": 20.0, "description": "The energy at which a saddle search is considered bad and terminated.", "title": "Max Energy", "type": "number" }, "displace_radius": { "default": 5.0, "description": "Atoms within this distance of the epicenter will be displaced.", "title": "Displace Radius", "type": "number" }, "displace_magnitude": { "default": 0.1, "description": "The standard deviation of the Gaussian displacement in each degree of freedom for the selected atoms.", "title": "Displace Magnitude", "type": "number" }, "displace_random_weight": { "default": 1.0, "description": "Relative probability to displace with a random epicenter.", "title": "Displace Random Weight", "type": "number" }, "displace_not_FCC_HCP_weight": { "default": 0.0, "description": "Relative probability to displace with an epicenter that is not FCC or HCP coordinated.", "title": "Displace Not Fcc Hcp Weight", "type": "number" }, "displace_least_coordinated_weight": { "default": 0.0, "description": "Relative probability to displace with an epicenter that has a coordination number equal to the least-coordinated atom in the configuration.", "title": "Displace Least Coordinated Weight", "type": "number" }, "displace_under_coordinated_weight": { "default": 0.0, "description": "Relative probability to displace with an epicenter with a coordination equal to or less than displace_max_coordination.", "title": "Displace Under Coordinated Weight", "type": "number" }, "displace_listed_atom_weight": { "default": 0.0, "description": "Relative probability to displace with an epicenter listed in displace_atom_list.", "title": "Displace Listed Atom Weight", "type": "number" }, "displace_atom_list": { "default": [ -1 ], "description": "0-based atom indices to use as displacement epicenters, separated by commas. Example: 10, 20, -1 would be atoms 10, 20, and the last atom. When displace_atom_kmc_state_script is set, this list is populated dynamically per AKMC state from the script's output.", "items": { "type": "integer" }, "title": "Displace Atom List", "type": "array" }, "displace_atom_kmc_state_script": { "default": "", "description": "Path to a Python script that determines which atoms to displace. The script receives the path to a .con file as its sole positional argument and must print a comma-separated list of 0-based atom indices to stdout. It is executed once per new AKMC state; the result is cached in state.info. The path can be relative (resolved against the eOn root directory) or absolute. See the displacement scripts tutorial for worked examples.", "title": "Displace Atom Kmc State Script", "type": "string" }, "displace_listed_type_weight": { "default": 0.0, "description": "Relative probability to displace with an epicenter listed in displace_type_list.", "title": "Displace Listed Type Weight", "type": "number" }, "displace_type_list": { "default": [], "description": "The atom types should be separated by a comma.", "items": { "type": "string" }, "title": "Displace Type List", "type": "array" }, "displace_all_listed": { "default": false, "description": "If true, displace all atoms in displace_atom_list (or displace_type_list) simultaneously. If false, one atom is chosen at random from the list per saddle search. In either case, atoms within displace_radius of any displaced atom are also included. Set displace_radius to 0 to restrict displacement strictly to listed atoms.", "title": "Displace All Listed", "type": "boolean" }, "displace_max_coordination": { "default": 11, "description": "When using under_coordinated as the displacement type, choose only atoms with a coordination equal to or less than this.", "title": "Displace Max Coordination", "type": "integer" }, "converged_force": { "anyOf": [ { "type": "number" }, { "type": "null" } ], "default": null, "description": "When the maximum force (in eV/A) on any one atom is smaller than this value, the structure is considered converged onto a saddle point.", "title": "Converged Force" }, "max_iterations": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "description": "The maximum number of translation steps to be taken.", "title": "Max Iterations" }, "nonlocal_count_abort": { "default": 0, "description": "If this is not zero, the saddle search will abort when this many atoms have moved more than nonlocal_distance_abort from the initial displacement.", "title": "Nonlocal Count Abort", "type": "integer" }, "nonlocal_distance_abort": { "default": 0.0, "description": "If nonlocal_count_abort is not zero, the saddle search will abort when nonlocal_count_abort atoms have moved more than this distance.", "title": "Nonlocal Distance Abort", "type": "number" }, "client_displace_type": { "default": "random", "description": "Epicenter selection method used by the C++ client. 'random': uniform random atom. 'last_atom': the last atom in the configuration. 'min_coordinated': the atom with the fewest neighbours. 'not_fcc_or_hcp': an atom whose local structure is neither FCC nor HCP. 'listed_atoms': an atom from displace_atom_list (parsed from config, no server displacement file needed). 'load': read a displacement vector from a file written by the server.", "enum": [ "load", "random", "last_atom", "min_coordinated", "not_fcc_or_hcp", "listed_atoms" ], "title": "Client Displace Type", "type": "string" }, "zero_mode_abort_curvature": { "default": 0.0, "description": "The saddle search will abort when the magnitude of the minmode curvature is less than this value.", "title": "Zero Mode Abort Curvature", "type": "number" }, "confine_positive": { "default": false, "description": "Activates a confinement scheme when the search is within a positive region of the PES.", "title": "Confine Positive", "type": "boolean" }, "bowl_breakout": { "default": false, "description": "When activated, the search within positive regions of PES is confined to a subset of atoms.", "title": "Bowl Breakout", "type": "boolean" }, "bowl_active_atoms": { "default": 20, "description": "Size of the applied confinement in the bowl breakout scheme.", "title": "Bowl Active Atoms", "type": "integer" }, "dynamics_temperature": { "anyOf": [ { "type": "number" }, { "type": "null" } ], "default": null, "description": "The temperature, in Kelvin, for the molecular dynamics run.", "title": "Dynamics Temperature" }, "dynamics_state_check_interval": { "default": 100.0, "description": "The time interval, in femtoseconds, to minimize the geometry and check if the system has left the initial state.", "title": "Dynamics State Check Interval", "type": "number" }, "dynamics_record_interval": { "default": 10.0, "description": "The time interval, in femtoseconds, between snapshots of the molecular dynamics trajectory.", "title": "Dynamics Record Interval", "type": "number" }, "dynamics_linear_interpolation": { "default": true, "description": "- If true, then the band connecting the initial and final states will be\n initialized using a linear interpolation.\n- If false, then the band is interpolated through the first snapshot that\n minimizes to the final state.", "title": "Dynamics Linear Interpolation", "type": "boolean" }, "dynamics_max_init_curvature": { "default": 0.0, "description": "The maximum initial curvature for the dynamics method in eV/\u00c5^2.", "title": "Dynamics Max Init Curvature", "type": "number" }, "nonnegative_displacement_abort": { "default": false, "description": "Abort the search if a non-negative displacement is detected.", "title": "Nonnegative Displacement Abort", "type": "boolean" }, "max_single_displace": { "default": 10.0, "description": "The maximum single displacement value.", "title": "Max Single Displace", "type": "number" }, "remove_rotation": { "default": false, "description": "Remove rotational components from the displacement.", "title": "Remove Rotation", "type": "boolean" }, "perp_force_ratio": { "default": 0.0, "description": "The ratio of perpendicular force, undocumented.", "title": "Perp Force Ratio", "type": "number" }, "confine_positive_min_force": { "default": 0.5, "description": "The minimum force for confining the positive region of the PES, undocumented.", "title": "Confine Positive Min Force", "type": "number" }, "confine_positive_scale_ratio": { "default": 0.9, "description": "The scaling ratio for confining the positive region of the PES, undocumented.", "title": "Confine Positive Scale Ratio", "type": "number" }, "confine_positive_boost": { "default": 10.0, "description": "The boost factor for confining the positive region of the PES, undocumented.", "title": "Confine Positive Boost", "type": "number" }, "confine_positive_min_active": { "default": 30, "description": "The minimum number of active atoms for confining the positive region of the PES, undocumented.", "title": "Confine Positive Min Active", "type": "integer" } } }
- Config:
use_attribute_docstrings: bool = True
- Fields:
- field bowl_breakout: bool = False#
Determines
bowl_active_atomsthat are subject to the largest forces. To activate,confine_positivemust also be true. Method of Pedersen and Luiser [SS_PL14].When activated, the search within positive regions of PES is confined to a subset of atoms.
- field client_displace_type: Literal['load', 'random', 'last_atom', 'min_coordinated', 'not_fcc_or_hcp', 'listed_atoms'] = 'random'#
Epicenter selection method used by the C++ client. ‘random’: uniform random atom. ‘last_atom’: the last atom in the configuration. ‘min_coordinated’: the atom with the fewest neighbours. ‘not_fcc_or_hcp’: an atom whose local structure is neither FCC nor HCP. ‘listed_atoms’: an atom from displace_atom_list (parsed from config, no server displacement file needed). ‘load’: read a displacement vector from a file written by the server.
- field confine_positive: bool = False#
Activates a confinement scheme when the search is within a positive region of the PES.
- field confine_positive_boost: float = 10.0#
The boost factor for confining the positive region of the PES, undocumented.
- field confine_positive_min_active: int = 30#
The minimum number of active atoms for confining the positive region of the PES, undocumented.
- field confine_positive_min_force: float = 0.5#
The minimum force for confining the positive region of the PES, undocumented.
- field confine_positive_scale_ratio: float = 0.9#
The scaling ratio for confining the positive region of the PES, undocumented.
- field converged_force: float | None = None#
When the maximum force (in eV/A) on any one atom is smaller than this value, the structure is considered converged onto a saddle point.
- field displace_all_listed: bool = False#
This can be disabled by setting displace_radius to 0. Otherwise:
If true, each displacement will include all of the degrees of freedom of all of the listed atoms in displace_atom_list or displace_type_list.
If false, one of the atoms in displace_atom_list or displace_type_list will be selected at random for each displacement.
In either case, all atoms up to displace_radius distance away from any displaced atom will be included in the displacement.
If true, displace all atoms in displace_atom_list (or displace_type_list) simultaneously. If false, one atom is chosen at random from the list per saddle search. In either case, atoms within displace_radius of any displaced atom are also included. Set displace_radius to 0 to restrict displacement strictly to listed atoms.
- field displace_atom_kmc_state_script: str = ''#
Path to a Python script that determines which atoms to displace. The script receives the path to a .con file as its sole positional argument and must print a comma-separated list of 0-based atom indices to stdout. It is executed once per new AKMC state; the result is cached in state.info. The path can be relative (resolved against the eOn root directory) or absolute. See the displacement scripts tutorial for worked examples.
- field displace_atom_list: list[int] = [-1]#
0-based atom indices to use as displacement epicenters, separated by commas. Example: 10, 20, -1 would be atoms 10, 20, and the last atom. When displace_atom_kmc_state_script is set, this list is populated dynamically per AKMC state from the script’s output.
- field displace_least_coordinated_weight: float = 0.0#
Relative probability to displace with an epicenter that has a coordination number equal to the least-coordinated atom in the configuration.
- field displace_listed_atom_weight: float = 0.0#
Relative probability to displace with an epicenter listed in displace_atom_list.
- field displace_listed_type_weight: float = 0.0#
Relative probability to displace with an epicenter listed in displace_type_list.
- field displace_magnitude: float = 0.1#
The standard deviation of the Gaussian displacement in each degree of freedom for the selected atoms.
- field displace_max_coordination: int = 11#
When using under_coordinated as the displacement type, choose only atoms with a coordination equal to or less than this.
- field displace_not_FCC_HCP_weight: float = 0.0#
Relative probability to displace with an epicenter that is not FCC or HCP coordinated.
- field displace_random_weight: float = 1.0#
Relative probability to displace with a random epicenter.
- field displace_under_coordinated_weight: float = 0.0#
Relative probability to displace with an epicenter with a coordination equal to or less than displace_max_coordination.
- field dynamics_linear_interpolation: bool = True#
If true, then the band connecting the initial and final states will be initialized using a linear interpolation.
If false, then the band is interpolated through the first snapshot that minimizes to the final state.
If true, then the band connecting the initial and final states will be initialized using a linear interpolation.
If false, then the band is interpolated through the first snapshot that minimizes to the final state.
- field dynamics_max_init_curvature: float = 0.0#
The maximum initial curvature for the dynamics method in eV/Å^2.
- field dynamics_record_interval: float = 10.0#
Snapshots of MD trajectories are used to locate when the system first left the initial state. A binary search is used to locate the first snapshot that minimizes to a new geometry.
The time interval, in femtoseconds, between snapshots of the molecular dynamics trajectory.
- field dynamics_state_check_interval: float = 100.0#
The time interval, in femtoseconds, to minimize the geometry and check if the system has left the initial state.
- field dynamics_temperature: float | None = None#
A good initial choice might be near the melting temperature of the material.
The temperature, in Kelvin, for the molecular dynamics run.
- field max_energy: float = 20.0#
The energy at which a saddle search is considered bad and terminated.
- field method: Literal['min_mode', 'dynamics'] = 'min_mode'#
- Options:
min_mode: Use a min-mode following scheme to locate the saddle point.dynamics: Experimental method that uses molecular dynamics to find new states and then runs a climbing image NEB calculation to find the saddle and a dimer calculation to estimate the eigenmode at the saddle.
Method to locate the saddle point.
- field min_mode_method: Literal['dimer', 'lanczos', 'gprdimer'] = 'dimer'#
- Options:
dimer: Use the dimer min-mode method from Henkelman and Jónsson [SS_HJonsson99]lanczos: Use the Lanczos min-mode method from Malek and Mousseau [SS_MM00]gprdimer: Use the GP accelerated dimer method.
Min-mode method to use.
- field nonlocal_count_abort: int = 0#
If this is not zero, the saddle search will abort when this many atoms have moved more than nonlocal_distance_abort from the initial displacement.
- field nonlocal_distance_abort: float = 0.0#
If nonlocal_count_abort is not zero, the saddle search will abort when nonlocal_count_abort atoms have moved more than this distance.
- field nonnegative_displacement_abort: bool = False#
Abort the search if a non-negative displacement is detected.
References#
Graeme Henkelman and Hannes Jónsson. A dimer method for finding saddle points on high dimensional potential surfaces using only first derivatives. The Journal of Chemical Physics, 111(15):7010–7022, October 1999. doi:10.1063/1.480097.
Rachid Malek and Normand Mousseau. Dynamics of Lennard-Jones clusters: A characterization of the activation-relaxation technique. Physical Review E, 62(6):7723–7728, December 2000. doi:10.1103/PhysRevE.62.7723.
Andreas Pedersen and Mathieu Luiser. Bowl breakout: Escaping the positive region when searching for saddle points. The Journal of Chemical Physics, 141(2):024109, July 2014. doi:10.1063/1.4885852.