String Path
The string method is a common approach for simulating pathways between energy minima. It models these paths as "strings" that are composed of a discrete set of points, called "images," which each correspond to a different geometry of the system along the reaction path. The simulation begins with a guess for the geometry of each image. Over the course of multiple iterations, the string is relaxed by allowing the individual images to descend along the potential energy surface. The images at the endpoints (which correspond to "reactant" and "product" states) are permitted to fully relax into energy minima, while the intermediate images are constrained to occupy a position between their neighboring images.
Upon convergence, the images form a discrete string that follows the minimal energy path from the reactant state to the product state. The string method is conceptually similar to the Nudged Elastic Band (NEB) method, differing primarily in the manner in which the images interact: while the NEB method applies a spring force between adjacent images in order to ensure that they are properly spaced, the string method accomplishes this using a Lagrange multiplier.
As with other iterative relaxation methods, the number of steps required for convergence is dependent upon the quality of the initial guess. It can sometimes be preferable to perform independent geometry relaxations of the endpoints before utilizing the string method.
By default, images are aligned (the RMSD is minimized) towards the starting image. In general this will produce a lower energy string. For some images this may not be desirable and can be turned off by setting align_initial_images
to False
in the details
section.
Examples
The following example simulates the reaction path for isomerization of HCN into CNH:
import sierra
from sierra.inputs import *
import numpy as np
# Construct an initial guess for the reaction path
symbols = ["H", "C", "N"]
cn_geometry = [0, 0, 1.1, 0, 0, -1.1]
initial_images = []
for degree in np.linspace(0, np.pi, 8):
geometry = [0, np.sin(degree) * 2.3, np.cos(degree) * 2.3] + cn_geometry
initial_images.append(Molecule(symbols=symbols, geometry=geometry))
# Run the String Path Workflow
inp = StringPathInput(
initial_string=initial_images,
details={"max_iterations": 60, "time_step": 0.1, "trust_radius": 0.2},
)
ret = sierra.run(inp)
# Print the geometry of each image in the reaction path
for index, image in enumerate(ret.final_string):
print("Image " + str(index + 1) + " geometry:")
#> Image 1 geometry:
#> Image 2 geometry:
"""
[[ 0. 0. 2.75347514]
[ 0. 0. 0.83881242]
[ 0. 0. -1.29228756]]
"""
#> Image 3 geometry:
"""
[[ 0. 0.32186689 2.61230172]
[ 0. -0.444149 0.87550359]
[ 0. 0.12228211 -1.18780531]]
"""
#> Image 4 geometry:
"""
[[ 0. 0.56509899 2.3375639 ]
[ 0. -0.82405571 0.93343731]
[ 0. 0.25895671 -0.97100121]]
"""
#> Image 5 geometry:
"""
[[ 0. 0.76609393 2.06966877]
[ 0. -1.18002147 0.91048689]
[ 0. 0.41392754 -0.68015566]]
"""
#> Image 6 geometry:
"""
[[ 0. 0.99679701 1.87166118]
[ 0. -1.50195635 0.76048018]
[ 0. 0.50515933 -0.33214135]]
"""
#> Image 7 geometry:
"""
[[ 0. 1.2850534 1.73364462]
[ 0. -1.74491802 0.53346002]
[ 0. 0.45986462 0.03289536]]
"""
#> Image 8 geometry:
"""
[[ 0. 1.611249 1.59015843]
[ 0. -1.89487198 0.32486507]
[ 0. 0.28362298 0.3849765 ]]
"""
print(image.geometry)
"""
[[ 0. 1.83570771 1.32879427]
[ 0. -1.9487609 0.16992009]
[ 0. 0.11305319 0.80128564]]
"""
The following example examines the dissociation curve of H2. It provides only the starting and ending images, with an additional 9 images being automatically generated to form a string between these endpoints. The endpoints are frozen in order to prevent them from relaxing to the minimum energy bond length for H2.
import sierra
from sierra.inputs import *
start = {"symbols": ["H", "H"], "geometry": [0, 0, 0, 0, 0, 1.0]}
end = {"symbols": ["H", "H"], "geometry": [0, 0, 0, 0, 0, 2.0]}
inp = StringPathInput(
initial_string=[start, end],
details={
"n_intermediates": 9,
"freeze_start_image": True,
"freeze_end_image": True,
},
)
ret = sierra.run(inp)
# Print the geometry of each of the images
for index, image in enumerate(ret.final_string):
print("Image " + str(index + 1) + " geometry:")
#> Image 1 geometry:
#> Image 2 geometry:
#> [[0. 0. 0.]
#> [0. 0. 1.]]
#> Image 3 geometry:
#> [[ 0. 0. -0.05]
#> [ 0. 0. 1.05]]
#> Image 4 geometry:
#> [[ 0. 0. -0.1]
#> [ 0. 0. 1.1]]
#> Image 5 geometry:
#> [[ 0. 0. -0.15]
#> [ 0. 0. 1.15]]
#> Image 6 geometry:
#> [[ 0. 0. -0.2]
#> [ 0. 0. 1.2]]
#> Image 7 geometry:
#> [[ 0. 0. -0.25]
#> [ 0. 0. 1.25]]
#> Image 8 geometry:
#> [[ 0. 0. -0.3]
#> [ 0. 0. 1.3]]
#> Image 9 geometry:
#> [[ 0. 0. -0.35]
#> [ 0. 0. 1.35]]
#> Image 10 geometry:
#> [[ 0. 0. -0.4]
#> [ 0. 0. 1.4]]
#> Image 11 geometry:
#> [[ 0. 0. -0.45]
#> [ 0. 0. 1.45]]
print(image.geometry)
#> [[ 0. 0. -0.5]
#> [ 0. 0. 1.5]]
StringPathInput
- Class for describing input for the String Path workflow
Fields
energy_method
-
The method for final energy evaluation. If None the final energies are computed using the level of theory specified by optimization_method.
- Type: One of: [MethodBase, CustomMethod, XTBMethod, HFMethod, DFTMethod, EMFTMethod, OrbNetMethod]
initial_string
-
An initial guess for every image in the reaction path, provided in order from the first (e.g., reactant) image to the last (e.g., product) image. If 'n_intermediates' is specified, this number of intermediates will be created between each image in the current string.
- Type: List[Molecule]
optimization_method
-
The method with which to optimize the string.
- Type: One of: [MethodBase, CustomMethod, XTBMethod, HFMethod, DFTMethod, EMFTMethod, OrbNetMethod]
- Default: XTBMethod(model='GFN0')
workflow
-
- Type: WorkflowIdentifier
- Default: WorkflowIdentifier(name='string_path', image=None)
details
-
Detail Fields
align_initial_string
-
If true, align the initial string towards the first (e.g. reactant) images.
- Type: bool
- Default: True
convergence_threshold
-
A convergence threshold that indicates the maximum geometry change for each image between iterations that will be considered converged.
- Type: LengthQuantity
- Default: "0.0026 angstrom"
freeze_end_image
-
If true, the geometry of the last (e.g., product) image is not permitted to relax.
- Type: bool
- Default: False
freeze_start_image
-
If true, the geometry of the first (e.g., reactant) image is not permitted to relax.
- Type: bool
- Default: False
initial_string_coordinates
-
Coordinate system to use for building initial strings.
- Type: InitialStringCoordinates
- Default: InitialStringCoordinates.irc
max_iterations
-
The maximum number of iterations to complete.
- Type: int
- Default: 60
n_intermediates
-
The number of intermediate images that will be automatically generated when the user does not specify the intermediate images via the
initial_intermediates
option.- Type: int
- Default: 0
smooth_factor
-
The degree to which a "smooth" progression between the geometries of adjacent images is enforced. This parameter does not affect the geometries of the endpoints. Values must be in the range [0, 1], with 0 corresponding to no smoothing and 1 forcing the geometries of non-endpoint images to an average of the geometries of adjacent images.
- Type: float
- Default: 0.01
step_size
-
The step size (\(\Delta t\)) used to evolve the string (\(\psi\)).
Given the gradients (\(\nabla V\)) the string evolves using steepest-decent dynamics. The new position of the i-th image before re-parameterization can be computed [ \psi^*_i = \psi^n_i - \Delta t \nabla V\left(\psi^n_i\right) ] where \(\psi^n_i\) is the i-th image on the string at the n-th iteration.
- Type: float
- Default: 0.01
trust_radius
-
The maximum allowed atom displacement each iteration.
- Type: LengthQuantity
- Default: "0.053 angstrom"
StringPathResult
- Class for describing results from the String Path workflow
Fields
All the fields in StringPathInput and the following:
computation_history
-
- Type: List[List[GradientResult]]
- Default: []
converged
-
- Type: bool
- Default: False
energy_history
-
- Type: List[Array]
- Default: []
final_energies
-
- Type: List[float]
- Default: []
final_string
-
- Type: List[Molecule]
- Default: []
Functions
StringPathResult.visualize
visualize() -> None
:
The results of a string path calculation can be displayed by using this function. CAVEAT: This function can only be used inside a jupyter notebook.
Returns
None