# 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.83881241]
[ 0.          0.         -1.29228756]]
"""
#> Image 3 geometry:
"""
[[ 0.          0.32186687  2.61230172]
[ 0.         -0.44414901  0.87550358]
[ 0.          0.12228212 -1.18780532]]
"""
#> Image 4 geometry:
"""
[[ 0.          0.56509899  2.3375639 ]
[ 0.         -0.82405571  0.93343731]
[ 0.          0.25895671 -0.97100122]]
"""
#> Image 5 geometry:
"""
[[ 0.          0.76609392  2.06966878]
[ 0.         -1.18002147  0.91048689]
[ 0.          0.41392755 -0.68015565]]
"""
#> Image 6 geometry:
"""
[[ 0.          0.99679701  1.87166117]
[ 0.         -1.50195635  0.76048017]
[ 0.          0.50515933 -0.33214136]]
"""
#> Image 7 geometry:
"""
[[ 0.          1.28505342  1.73364462]
[ 0.         -1.74491801  0.53346003]
[ 0.          0.45986462  0.03289536]]
"""
#> Image 8 geometry:
"""
[[ 0.          1.61124901  1.5901584 ]
[ 0.         -1.89487198  0.32486506]
[ 0.          0.28362299  0.38497649]]
"""
print(image.geometry)
"""
[[ 0.          1.83570772  1.32879426]
[ 0.         -1.94876089  0.16992009]
[ 0.          0.1130532   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.

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.

optimization_method

The method with which to optimize the string.

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
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 [since Sierra 1.4.1]

The size of the time step for each iteration.

• Type: float
• Default: "0.01"
time_step

Deprecated in favour of step_size.

• Deprecated: use step_size [Sierra 1.4.1]
• Type: float
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 of the fields in StringPathInput and the following:

computation_history

A full history of all gradients evaluated during the String Path. Each computation is organized first by iteration and then by image in the string; therefore computation_history[-1][2] would be the third image of the last string.

converged

A flag marking if the workflow converged or not.

• Type: bool
• Default: False
final_energies

The energy of the final images in the string.

• Type: List[float]
• Default: []
final_string

The optimized list of Molecule in the string.