/usr/share/python-ase/doc/ase/constraints.rst is in python-ase-doc 3.9.1.4567-3.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 | .. module:: ase.constraints
:synopsis: Constraining some degrees of freedom
===========
Constraints
===========
When performing minimizations or dynamics one may wish to keep some
degrees of freedom in the system fixed. One way of doing this is by
attaching constraint object(s) directly to the atoms object.
Important: setting constraints will freeze the corresponding atom positions.
Changing such atom positions can be achieved:
- by directly setting the :attr:`~ase.atoms.Atoms.positions` attribute
(see example of setting :ref:`atoms_special_attributes`),
- alternatively, by removing the constraints first::
del atoms.constraints
or::
atoms.set_constraint()
and using the :meth:`~ase.atoms.Atoms.set_positions` method.
The FixAtoms class
==================
This class is used for fixing some of the atoms.
.. class:: FixAtoms(indices=None, mask=None)
You must supply either the indices of the atoms that should be fixed
or a mask. The mask is a list of booleans, one for each atom, being true
if the atoms should be kept fixed.
For example, to fix the positions of all the Cu atoms in a simulation
with the indices keyword:
>>> c = FixAtoms(indices=[atom.index for atom in atoms if atom.symbol == 'Cu'])
>>> atoms.set_constraint(c)
or with the mask keyword:
>>> c = FixAtoms(mask=[atom.symbol == 'Cu' for atom in atoms])
>>> atoms.set_constraint(c)
The FixBondLength class
=======================
This class is used to fix the distance between two atoms specified by
their indices (*a1* and *a2*)
.. class:: FixBondLength(a1, a2)
Example of use::
>>> c = FixBondLength(0, 1)
>>> atoms.set_constraint(c)
In this example the distance between the atoms
with indices 0 and 1 will be fixed in all following dynamics and/or
minimizations performed on the *atoms* object.
This constraint is useful for finding minimum energy barriers for
reactions where the path can be described well by a single bond
length (see the :ref:`mep2` tutorial).
Important: If fixing multiple bond lengths, use the FixBondLengths class
below, particularly if the same atom is fixed to multiple partners.
The FixBondLengths class
========================
More than one bond length can be fixed by using this class. Especially
for cases in which more than one bond length constraint is applied on
the same atom. It is done by specifying the indices of the two atoms
forming the bond in pairs.
.. class:: FixBondLengths(pairs)
Example of use::
>>> c = FixBondLengths([[0, 1], [0, 2]])
>>> atoms.set_constraint(c)
Here the distances between atoms with indices 0 and 1 and atoms with
indices 0 and 2 will be fixed. The constraint is for the same purpose
as the FixBondLength class.
The FixedLine class
===================
.. autoclass:: FixedLine
The FixedPlane class
====================
.. autoclass:: FixedPlane
Example of use: :ref:`constraints_diffusion_tutorial`.
The FixedMode class
===================
.. autoclass:: FixedMode
A mode is a list of vectors specifying a direction for each atom. It often
comes from :meth:`ase.vibrations.Vibrations.get_mode`.
The Hookean class
=================
This class of constraints, based on Hooke's Law, is generally used to
conserve molecular identity in optimization schemes and can be used in three
different ways. In the first, it applies a Hookean restorative force between
two atoms if the distance between them exceeds a threshold. This is useful to
maintain the identity of molecules in quenched molecular dynamics, without
changing the degrees of freedom or violating conservation of energy. When the
distance between the two atoms is less than the threshold length, this
constraint is completely inactive.
The below example tethers atoms at indices 3 and 4 together::
>>> c = Hookean(a1=3, a2=4, rt=1.79, k=5.)
>>> atoms.set_constraint(c)
Alternatively, this constraint can tether a single atom to a point in space,
for example to prevent the top layer of a slab from subliming during a
high-temperature MD simulation. An example of tethering atom at index 3 to its
original position:
>>> c = Hookean(a1=3, a2=atoms[3].position, rt=0.94, k=2.)
>>> atoms.set_constraint(c)
Reasonable values of the threshold (rt) and spring constant (k) for some
common bonds are below.
.. list-table::
* - Bond
- rt (Angstroms)
- k (eV Angstrom^-2)
* - O-H
- 1.40
- 5
* - C-O
- 1.79
- 5
* - C-H
- 1.59
- 7
* - C=O
- 1.58
- 10
* - Pt sublimation
- 0.94
- 2
* - Cu sublimation
- 0.97
- 2
A third way this constraint can be applied is to apply a restorative force if an atom crosses a plane in space. For example::
>>> c = Hookean(a1=3, a2=(0, 0, 1, -7), k=10.)
>>> atoms.set_constraint(c)
This will apply a restorative force on atom 3 in the downward direction of magnitude k * (atom.z - 7) if the atom's vertical position exceeds 7 Angstroms. In other words, if the atom crosses to the (positive) normal side of the plane, the force is applied and directed towards the plane. (The same plane with the normal direction pointing in the -z direction would be given by (0, 0, -1, 7).)
For an example of use, see the :ref:`mhtutorial` tutorial.
.. note::
In previous versions of ASE, this was known as the BondSpring constraint.
The FixInternals class
======================
This class allows to fix an arbitrary number of bond lengths, angles
and dihedral angles. The defined constraints are satisfied self
consistently. To define the constraints one needs to specify the
atoms object on which the constraint works (needed for atomic
masses), a list of bond, angle and dihedral constraints.
Those constraint definitions are always list objects containing
the value to be set and a list of atomic indices. The epsilon value
specifies the accuracy to which the constraints are fulfilled.
.. class:: FixInternals(bonds=[bond1, bond2],
angles=[angle1], dihedrals=[dihedral1, dihedral2], epsilon=1.e-7)
Example of use::
>>> bond1 = [1.20, [1, 2]]
>>> angle_indices1 = [2, 3, 4]
>>> dihedral_indices1 = [2, 3, 4, 5]
>>> angle1 = [atoms.get_angle(angle_indices1), angle_indices1]
>>> dihedral1 = [atoms.get_dihedral(dihedral_indices1),
... dihedral_indices1]
>>> c = FixInternals(bonds=[bonds1], angles=[angles1],
... dihedrals=[dihedral1])
>>> atoms.set_constraint(c)
This example defines a bond, an angle and a dihedral angle constraint
to be fixed at the same time.
Combining constraints
=====================
It is possible to supply several constraints on an atoms object. For
example one may wish to keep the distance between two nitrogen atoms
fixed while relaxing it on a fixed ruthenium surface::
>>> pos = [[0.00000, 0.00000, 9.17625],
... [0.00000, 0.00000, 10.27625],
... [1.37715, 0.79510, 5.00000],
... [0.00000, 3.18039, 5.00000],
... [0.00000, 0.00000, 7.17625],
... [1.37715, 2.38529, 7.17625]]
>>> unitcell = [5.5086, 4.7706, 15.27625]
>>> atoms = Atoms(positions=pos,
... symbols='N2Ru4',
... cell=unitcell,
... pbc=[True,True,False])
>>> fa = FixAtoms(mask=[a.symbol == 'Ru' for a in atoms])
>>> fb = FixBondLength(0, 1)
>>> atoms.set_constraint([fa, fb])
When applying more than one constraint they are passed as a list in
the :meth:`~ase.atoms.Atoms.set_constraint` method, and they will be applied
one after the other.
Important: If wanting to fix the length of more than one bond in the
simulation, do not supply a list of :class:`FixBondLength`
instances; instead, use a single instance of
:class:`FixBondLengths`.
Making your own constraint class
================================
A constraint class must have these two methods:
.. method:: adjust_positions(oldpositions, newpositions)
Adjust the *newpositions* array inplace.
.. method:: adjust_forces(positions, forces)
Adjust the *forces* array inplace.
A simple example::
import numpy as np
class MyConstraint:
"""Constrain an atom to move along a given direction only."""
def __init__(self, a, direction):
self.a = a
self.dir = direction / sqrt(np.dot(direction, direction))
def adjust_positions(self, atoms, newpositions):
step = newpositions[self.a] - atoms.positions[self.a]
step = np.dot(step, self.dir)
newpositions[self.a] = atoms.positions[self.a] + step * self.dir
def adjust_forces(self, atoms, forces):
forces[self.a] = self.dir * np.dot(forces[self.a], self.dir)
A constraint can optionally have two additional methods, which
will be ignored if missing:
.. method:: adjust_momenta(atoms, momenta)
Adjust the *momenta* array inplace.
.. method:: adjust_potential_energy(atoms, energy)
Provide the difference in the *potential energy* due to the constraint.
(Note that inplace adjustment is not possible for energy, which is a
float.)
The Filter class
================
Constraints can also be applied via filters, which acts as a wrapper
around an atoms object. A typical use case will look like this::
------- -------- ----------
| | | | | |
| Atoms |<----| Filter |<----| Dynamics |
| | | | | |
------- -------- ----------
and in Python this would be::
>>> atoms = Atoms(...)
>>> filter = Filter(atoms, ...)
>>> dyn = Dynamics(filter, ...)
This class hides some of the atoms in an Atoms object.
.. class:: Filter(atoms, indices=None, mask=None)
You must supply either the indices of the atoms that should be kept
visible or a mask. The mask is a list of booleans, one for each atom,
being true if the atom should be kept visible.
Example of use::
>>> from ase import Atoms, Filter
>>> atoms=Atoms(positions=[[ 0 , 0 , 0],
... [ 0.773, 0.600, 0],
... [-0.773, 0.600, 0]],
... symbols='OH2')
>>> f1 = Filter(atoms, indices=[1, 2])
>>> f2 = Filter(atoms, mask=[0, 1, 1])
>>> f3 = Filter(atoms, mask=[a.Z == 1 for a in atoms])
>>> f1.get_positions()
[[ 0.773 0.6 0. ]
[-0.773 0.6 0. ]]
In all three filters only the hydrogen atoms are made
visible. When asking for the positions only the positions of the
hydrogen atoms are returned.
The UnitCellFilter class
========================
.. autoclass:: UnitCellFilter
The StrainFilter class
======================
.. autoclass:: StrainFilter
|