diff --git a/doc4.2.2/_images/ccmake-example.png b/doc4.2.2/_images/ccmake-example.png new file mode 100644 index 0000000000..4731a606a4 Binary files /dev/null and b/doc4.2.2/_images/ccmake-example.png differ diff --git a/doc4.2.2/_images/conical_frustum.png b/doc4.2.2/_images/conical_frustum.png new file mode 100644 index 0000000000..83d6275152 Binary files /dev/null and b/doc4.2.2/_images/conical_frustum.png differ diff --git a/doc4.2.2/_images/constraint-distance.png b/doc4.2.2/_images/constraint-distance.png new file mode 100644 index 0000000000..397f56e636 Binary files /dev/null and b/doc4.2.2/_images/constraint-distance.png differ diff --git a/doc4.2.2/_images/constraint-force.png b/doc4.2.2/_images/constraint-force.png new file mode 100644 index 0000000000..37998fd956 Binary files /dev/null and b/doc4.2.2/_images/constraint-force.png differ diff --git a/doc4.2.2/_images/constraint-force_only_positive.png b/doc4.2.2/_images/constraint-force_only_positive.png new file mode 100644 index 0000000000..b1f2e0482e Binary files /dev/null and b/doc4.2.2/_images/constraint-force_only_positive.png differ diff --git a/doc4.2.2/_images/correlator_scheme.png b/doc4.2.2/_images/correlator_scheme.png new file mode 100644 index 0000000000..4387e540cb Binary files /dev/null and b/doc4.2.2/_images/correlator_scheme.png differ diff --git a/doc4.2.2/_images/diamond.png b/doc4.2.2/_images/diamond.png new file mode 100644 index 0000000000..52a015580d Binary files /dev/null and b/doc4.2.2/_images/diamond.png differ diff --git a/doc4.2.2/_images/dihedral-angle.pdf b/doc4.2.2/_images/dihedral-angle.pdf new file mode 100644 index 0000000000..df09a3eb45 Binary files /dev/null and b/doc4.2.2/_images/dihedral-angle.pdf differ diff --git a/doc4.2.2/_images/elc-errordist.pdf b/doc4.2.2/_images/elc-errordist.pdf new file mode 100644 index 0000000000..dab65c3699 Binary files /dev/null and b/doc4.2.2/_images/elc-errordist.pdf differ diff --git a/doc4.2.2/_images/inter_angle.png b/doc4.2.2/_images/inter_angle.png new file mode 100644 index 0000000000..95d9da06e2 Binary files /dev/null and b/doc4.2.2/_images/inter_angle.png differ diff --git a/doc4.2.2/_images/oif-arealocal.png b/doc4.2.2/_images/oif-arealocal.png new file mode 100644 index 0000000000..f17e8ad0de Binary files /dev/null and b/doc4.2.2/_images/oif-arealocal.png differ diff --git a/doc4.2.2/_images/oif-bending.png b/doc4.2.2/_images/oif-bending.png new file mode 100644 index 0000000000..b558afefa1 Binary files /dev/null and b/doc4.2.2/_images/oif-bending.png differ diff --git a/doc4.2.2/_images/oif-stretching.png b/doc4.2.2/_images/oif-stretching.png new file mode 100644 index 0000000000..cab0d18c02 Binary files /dev/null and b/doc4.2.2/_images/oif-stretching.png differ diff --git a/doc4.2.2/_images/oif-volcons.png b/doc4.2.2/_images/oif-volcons.png new file mode 100644 index 0000000000..0198462b11 Binary files /dev/null and b/doc4.2.2/_images/oif-volcons.png differ diff --git a/doc4.2.2/_images/oif.png b/doc4.2.2/_images/oif.png new file mode 100644 index 0000000000..a698f735ed Binary files /dev/null and b/doc4.2.2/_images/oif.png differ diff --git a/doc4.2.2/_images/oif1.png b/doc4.2.2/_images/oif1.png new file mode 100644 index 0000000000..7f89cb4db8 Binary files /dev/null and b/doc4.2.2/_images/oif1.png differ diff --git a/doc4.2.2/_images/oif2.png b/doc4.2.2/_images/oif2.png new file mode 100644 index 0000000000..edf1298cc4 Binary files /dev/null and b/doc4.2.2/_images/oif2.png differ diff --git a/doc4.2.2/_images/oif3.png b/doc4.2.2/_images/oif3.png new file mode 100644 index 0000000000..cf445ca4d6 Binary files /dev/null and b/doc4.2.2/_images/oif3.png differ diff --git a/doc4.2.2/_images/oifchannel.png b/doc4.2.2/_images/oifchannel.png new file mode 100644 index 0000000000..c20cf824a4 Binary files /dev/null and b/doc4.2.2/_images/oifchannel.png differ diff --git a/doc4.2.2/_images/oifcolored-triangles.png b/doc4.2.2/_images/oifcolored-triangles.png new file mode 100644 index 0000000000..875193e19b Binary files /dev/null and b/doc4.2.2/_images/oifcolored-triangles.png differ diff --git a/doc4.2.2/_images/oifcylinder.png b/doc4.2.2/_images/oifcylinder.png new file mode 100644 index 0000000000..4c228f904a Binary files /dev/null and b/doc4.2.2/_images/oifcylinder.png differ diff --git a/doc4.2.2/_images/oifrhomboid.png b/doc4.2.2/_images/oifrhomboid.png new file mode 100644 index 0000000000..99bbc768f7 Binary files /dev/null and b/doc4.2.2/_images/oifrhomboid.png differ diff --git a/doc4.2.2/_images/oifstretched-sphere.png b/doc4.2.2/_images/oifstretched-sphere.png new file mode 100644 index 0000000000..ef520cfab7 Binary files /dev/null and b/doc4.2.2/_images/oifstretched-sphere.png differ diff --git a/doc4.2.2/_images/oifvectordata.png b/doc4.2.2/_images/oifvectordata.png new file mode 100644 index 0000000000..6f07a3dd39 Binary files /dev/null and b/doc4.2.2/_images/oifvectordata.png differ diff --git a/doc4.2.2/_images/shape-conical_frustum.png b/doc4.2.2/_images/shape-conical_frustum.png new file mode 100644 index 0000000000..d92631980f Binary files /dev/null and b/doc4.2.2/_images/shape-conical_frustum.png differ diff --git a/doc4.2.2/_images/shape-cylinder.png b/doc4.2.2/_images/shape-cylinder.png new file mode 100644 index 0000000000..04770f1fdb Binary files /dev/null and b/doc4.2.2/_images/shape-cylinder.png differ diff --git a/doc4.2.2/_images/shape-ellipsoid.png b/doc4.2.2/_images/shape-ellipsoid.png new file mode 100644 index 0000000000..539c2e517d Binary files /dev/null and b/doc4.2.2/_images/shape-ellipsoid.png differ diff --git a/doc4.2.2/_images/shape-hollowconicalfrustum_central_angle.png b/doc4.2.2/_images/shape-hollowconicalfrustum_central_angle.png new file mode 100644 index 0000000000..7e2f5ac714 Binary files /dev/null and b/doc4.2.2/_images/shape-hollowconicalfrustum_central_angle.png differ diff --git a/doc4.2.2/_images/shape-simplepore.png b/doc4.2.2/_images/shape-simplepore.png new file mode 100644 index 0000000000..7dd370374e Binary files /dev/null and b/doc4.2.2/_images/shape-simplepore.png differ diff --git a/doc4.2.2/_images/shape-slitpore.png b/doc4.2.2/_images/shape-slitpore.png new file mode 100644 index 0000000000..83f0b39ea7 Binary files /dev/null and b/doc4.2.2/_images/shape-slitpore.png differ diff --git a/doc4.2.2/_images/shape-sphere.png b/doc4.2.2/_images/shape-sphere.png new file mode 100644 index 0000000000..ba69d4e498 Binary files /dev/null and b/doc4.2.2/_images/shape-sphere.png differ diff --git a/doc4.2.2/_images/shape-spherocylinder.png b/doc4.2.2/_images/shape-spherocylinder.png new file mode 100644 index 0000000000..fa302355d7 Binary files /dev/null and b/doc4.2.2/_images/shape-spherocylinder.png differ diff --git a/doc4.2.2/_images/shape-torus.png b/doc4.2.2/_images/shape-torus.png new file mode 100644 index 0000000000..b407615030 Binary files /dev/null and b/doc4.2.2/_images/shape-torus.png differ diff --git a/doc4.2.2/_images/shape-wall.png b/doc4.2.2/_images/shape-wall.png new file mode 100644 index 0000000000..2ddbf1e3a0 Binary files /dev/null and b/doc4.2.2/_images/shape-wall.png differ diff --git a/doc4.2.2/_images/slitpore.png b/doc4.2.2/_images/slitpore.png new file mode 100644 index 0000000000..2b156ac84f Binary files /dev/null and b/doc4.2.2/_images/slitpore.png differ diff --git a/doc4.2.2/_images/vs-code-settings.png b/doc4.2.2/_images/vs-code-settings.png new file mode 100644 index 0000000000..39ba0640dd Binary files /dev/null and b/doc4.2.2/_images/vs-code-settings.png differ diff --git a/doc4.2.2/_modules/espressomd.html b/doc4.2.2/_modules/espressomd.html new file mode 100644 index 0000000000..afbcc7e2f6 --- /dev/null +++ b/doc4.2.2/_modules/espressomd.html @@ -0,0 +1,149 @@ + + + + + + + + espressomd — ESPResSo 4.2.2 documentation + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Source code for espressomd

+# Copyright (C) 2016-2022 The ESPResSo project
+# Copyright (C) 2014 Olaf Lenz
+#
+# This file is part of ESPResSo.
+#
+# ESPResSo is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# ESPResSo is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+# Initialize MPI, start the main loop on the worker nodes
+from . import _init
+
+from .system import System
+from .code_info import features, all_features
+from .cuda_init import gpu_available
+from . import code_info
+from . import utils
+
+
+
[docs]class FeaturesError(Exception): + + def __init__(self, missing_features): + super().__init__(f"Missing features {', '.join(missing_features)}")
+ + +
[docs]def has_features(*args): + """ + Check whether a list of features is a subset of the compiled-in features. + """ + + lvl = utils.nesting_level(args) + assert lvl in [1, 2], "has_features() takes strings as argument" + if lvl == 2: + check_set = set(args[0]) + else: + check_set = set(args) + + if not check_set <= code_info.all_features(): + unknown_features = check_set - code_info.all_features() + raise RuntimeError(f"unknown features {','.join(unknown_features)}") + + return check_set <= set(code_info.features())
+ + +
[docs]def missing_features(*args): + """ + Return a list of the missing features in the arguments. + """ + + lvl = utils.nesting_level(args) + assert lvl in [1, 2], "missing_features() takes strings as argument" + if lvl == 2: + features = set(args[0]) + else: + features = set(args) + + return sorted(features - set(code_info.features()))
+ + +
[docs]def assert_features(*args): + """ + Raise an exception when a list of features is not a subset of the + compiled-in features. + """ + + if not has_features(*args): + raise FeaturesError(missing_features(*args))
+
+ +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/doc4.2.2/_modules/espressomd/MDA_ESP.html b/doc4.2.2/_modules/espressomd/MDA_ESP.html new file mode 100644 index 0000000000..84b7c4eeaf --- /dev/null +++ b/doc4.2.2/_modules/espressomd/MDA_ESP.html @@ -0,0 +1,331 @@ + + + + + + + + espressomd.MDA_ESP — ESPResSo 4.2.2 documentation + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Source code for espressomd.MDA_ESP

+# Copyright (C) 2010-2022 The ESPResSo project
+#
+# This file is part of ESPResSo.
+#
+# ESPResSo is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# ESPResSo is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+"""
+This modules exposes ESPResSo's coordinates and particle attributes
+to MDAnalysis without the need to save any information to files.
+
+The main class is :class:`Stream`, which is used to initialize the stream of
+data to MDAnalysis' readers. These are the topology reader :class:`ESPParser`
+and the coordinates reader :class:`ESPReader`.
+
+A minimal working example is the following:
+
+>>> import espressomd
+>>> import espressomd.MDA_ESP
+>>> import MDAnalysis as mda
+>>> # system setup
+>>> system = espressomd.System(box_l=[10., 10., 10.])
+>>> system.time_step = 1.
+>>> system.cell_system.skin = 1.
+>>> system.part.add(pos=[1., 2., 3.])
+>>> # set up the stream
+>>> eos = espressomd.MDA_ESP.Stream(system)
+>>> # feed Universe with a topology and coordinates
+>>> u = mda.Universe(eos.topology, eos.trajectory)
+>>> print(u)
+<Universe with 1 atoms>
+
+"""
+
+try:
+    import cStringIO as StringIO
+    StringIO = StringIO.StringIO
+except ImportError:
+    from io import StringIO
+
+import numpy as np
+import MDAnalysis
+
+import setuptools
+assert setuptools.version.pkg_resources.packaging.specifiers.SpecifierSet('>=1.0.0,<2.0.0').contains(MDAnalysis.__version__), \
+    f'MDAnalysis version {MDAnalysis.__version__} is not supported'
+
+from MDAnalysis.lib import util
+from MDAnalysis.coordinates.core import triclinic_box
+from MDAnalysis.coordinates.core import triclinic_vectors
+from MDAnalysis.lib.util import NamedStream
+from MDAnalysis.topology.base import TopologyReaderBase
+from MDAnalysis.coordinates import base
+from MDAnalysis.coordinates.base import SingleFrameReaderBase
+from MDAnalysis.core.topology import Topology
+
+from MDAnalysis.core.topologyattrs import (
+    Atomnames, Atomids, Atomtypes, Masses,
+    Resids, Resnums, Segids, Resnames, AltLocs,
+    ICodes, Occupancies, Tempfactors, Charges, Bonds, Angles, Dihedrals
+)
+
+
+
[docs]class Stream: + + """ + Create an object that provides a MDAnalysis topology and a coordinate reader + + >>> eos = espressomd.MDA_ESP.Stream(system) + >>> u = mda.Universe(eos.topology, eos.trajectory) + + Parameters + ---------- + + system : :obj:`espressomd.system.System` + """ + + def __init__(self, system): + self.topology = ESPParser(None, espresso=system).parse() + self.system = system + + @property + def trajectory(self): + """ + Particles' coordinates at the current time + + Returns + ------- + + stream : :class:`MDAnalysis.lib.util.NamedStream` + A stream in the format that can be parsed by :class:`ESPReader` + + """ + # time + _xyz = str(self.system.time) + '\n' + # number of particles + _xyz += str(len(self.system.part)) + '\n' + # box edges + _xyz += str(self.system.box_l) + '\n' + # configuration + for _p in self.system.part: + _xyz += str(_p.pos) + '\n' + for _p in self.system.part: + _xyz += str(_p.v) + '\n' + for _p in self.system.part: + _xyz += str(_p.f) + '\n' + return NamedStream(StringIO(_xyz), "__.ESP")
+ + +
[docs]class ESPParser(TopologyReaderBase): + + """ + An MDAnalysis reader of ESPResSo's topology. + + """ + format = 'ESP' + + def __init__(self, filename, **kwargs): # pylint: disable=unused-argument + self.kwargs = kwargs + +
[docs] def parse(self): + """ + Access ESPResSo data and return the topology object. + + Returns + ------- + + top : :class:`MDAnalysis.core.topology.Topology` + a topology object + + """ + espresso = self.kwargs['espresso'] + + names = [] + atomtypes = [] + masses = [] + charges = [] + bonds = [] + angles = [] + dihedrals = [] + + for p in espresso.part: + names.append("A" + repr(p.type)) + atomtypes.append("T" + repr(p.type)) + masses.append(p.mass) + charges.append(p.q) + for bond in p.bonds: + partner_ids = bond[1:] + n_partner = len(partner_ids) + if n_partner == 1: + bonds.append((p.id, partner_ids[0])) + elif n_partner == 2: + angles.append((partner_ids[0], p.id, partner_ids[1])) + elif n_partner == 3: + dihedrals.append( + (partner_ids[0], p.id, partner_ids[1], partner_ids[2])) + else: + continue + natoms = len(espresso.part) + attrs = [Atomnames(np.array(names, dtype=object)), + Atomids(np.arange(natoms) + 1), + Atomtypes(np.array(atomtypes, dtype=object)), + Masses(masses), + Resids(np.array([1])), + Resnums(np.array([1])), + Segids(np.array(['System'], dtype=object)), + AltLocs(np.array([' '] * natoms, dtype=object)), + Resnames(np.array(['R'], dtype=object)), + Occupancies(np.zeros(natoms)), + Tempfactors(np.zeros(natoms)), + ICodes(np.array([' '], dtype=object)), + Charges(np.array(charges)), + Bonds(bonds), + Angles(angles), + Dihedrals(dihedrals) + ] + + top = Topology(natoms, 1, 1, attrs=attrs) + + return top
+ + +
[docs]class Timestep(base.Timestep): + _ts_order_x = [0, 3, 4] + _ts_order_y = [5, 1, 6] + _ts_order_z = [7, 8, 2] + + def _init_unitcell(self): + return np.zeros(9, dtype=np.float32) + + @property + def dimensions(self): + # This information now stored as _ts_order_x/y/z to keep DRY + x = self._unitcell[self._ts_order_x] + y = self._unitcell[self._ts_order_y] + z = self._unitcell[self._ts_order_z] + # this ordering is correct! (checked it, OB) + return triclinic_box(x, y, z) + + @dimensions.setter + def dimensions(self, box): + x, y, _ = triclinic_vectors(box) + np.put(self._unitcell, self._ts_order_x, x) + np.put(self._unitcell, self._ts_order_y, y)
+ + +
[docs]class ESPReader(SingleFrameReaderBase): + + """ + An MDAnalysis single frame reader for the stream provided by :class:`Stream`. + + """ + format = 'ESP' + units = {'time': None, 'length': 'nm', 'velocity': 'nm/ps'} + _Timestep = Timestep + + def _read_first_frame(self): + with util.openany(self.filename, 'rt') as espfile: + n_atoms = 1 + for pos, line in enumerate(espfile, start=-3): + if pos == -3: + time = float(line[1:-1]) + elif pos == -2: + n_atoms = int(line) + self.n_atoms = n_atoms + positions = np.zeros( + self.n_atoms * 3, dtype=np.float32).reshape(self.n_atoms, 3) + velocities = np.zeros( + self.n_atoms * 3, dtype=np.float32).reshape(self.n_atoms, 3) + forces = np.zeros( + self.n_atoms * 3, dtype=np.float32).reshape(self.n_atoms, 3) + self.ts = ts = self._Timestep( + self.n_atoms, **self._ts_kwargs) + self.ts.time = time + elif pos == -1: + self.ts._unitcell[:3] = np.array( + list(map(float, line[1:-2].split()))) + elif pos < n_atoms: + positions[pos] = np.array( + list(map(float, line[1:-2].split()))) + elif pos < 2 * n_atoms: + velocities[pos - n_atoms] = np.array( + list(map(float, line[1:-2].split()))) + else: + forces[pos - 2 * n_atoms] = np.array( + list(map(float, line[1:-2].split()))) + + ts.positions = np.copy(positions) + ts.velocities = np.copy(velocities) + ts.forces = np.copy(forces)
+
+ +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/doc4.2.2/_modules/espressomd/accumulators.html b/doc4.2.2/_modules/espressomd/accumulators.html new file mode 100644 index 0000000000..fc980652ee --- /dev/null +++ b/doc4.2.2/_modules/espressomd/accumulators.html @@ -0,0 +1,402 @@ + + + + + + + + espressomd.accumulators — ESPResSo 4.2.2 documentation + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Source code for espressomd.accumulators

+# Copyright (C) 2010-2022 The ESPResSo project
+#
+# This file is part of ESPResSo.
+#
+# ESPResSo is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# ESPResSo is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+from .script_interface import ScriptObjectList, ScriptInterfaceHelper, script_interface_register
+import numpy as np
+
+
+
[docs]@script_interface_register +class MeanVarianceCalculator(ScriptInterfaceHelper): + + """ + Accumulates results from observables. + + Parameters + ---------- + obs : :class:`espressomd.observables.Observable` + delta_N : :obj:`int` + Number of timesteps between subsequent samples for the auto update mechanism. + + Methods + ------- + update() + Update the accumulator (get the current values from the observable). + + """ + _so_name = "Accumulators::MeanVarianceCalculator" + _so_bind_methods = ( + "update", + "shape", + ) + _so_creation_policy = "LOCAL" + +
[docs] def mean(self): + """ + Returns the samples mean values of the respective observable with + which the accumulator was initialized. + """ + return np.array(self.call_method("mean")).reshape(self.shape())
+ +
[docs] def variance(self): + """ + Returns the samples variance for the observable. + """ + return np.array(self.call_method("variance")).reshape(self.shape())
+ +
[docs] def std_error(self): + """ + Returns the standard error calculated from the samples variance for the observable by + assuming uncorrelated samples. + """ + return np.array(self.call_method("std_error")).reshape(self.shape())
+ + +
[docs]@script_interface_register +class TimeSeries(ScriptInterfaceHelper): + + """ + Records results from observables. + + Parameters + ---------- + obs : :class:`espressomd.observables.Observable` + delta_N : :obj:`int` + Number of timesteps between subsequent samples for the auto update mechanism. + + Methods + ------- + update() + Update the accumulator (get the current values from the observable). + clear() + Clear the data + + """ + _so_name = "Accumulators::TimeSeries" + _so_bind_methods = ( + "update", + "shape", + "clear" + ) + _so_creation_policy = "LOCAL" + +
[docs] def time_series(self): + """ + Returns the recorded values of the observable. + """ + return np.array(self.call_method("time_series")).reshape(self.shape())
+ + +
[docs]@script_interface_register +class Correlator(ScriptInterfaceHelper): + + """ + Calculates the correlation of two observables :math:`A` and :math:`B`, + or of one observable against itself (i.e. :math:`B = A`). + The correlation can be compressed using the :ref:`multiple tau correlation + algorithm <Details of the multiple tau correlation algorithm>`. + + The operation that is performed on :math:`A(t)` and :math:`B(t+\\tau)` + to obtain :math:`C(\\tau)` depends on the ``corr_operation`` argument: + + * ``"scalar_product"``: Scalar product of :math:`A` and + :math:`B`, i.e., :math:`C=\\sum\\limits_{i} A_i B_i` + + * ``"componentwise_product"``: Componentwise product of + :math:`A` and :math:`B`, i.e., :math:`C_i = A_i B_i` + + * ``"square_distance_componentwise"``: Each component of + the correlation vector is the square of the difference + between the corresponding components of the observables, i.e., + :math:`C_i = (A_i-B_i)^2`. Example: when :math:`A` is + :class:`espressomd.observables.ParticlePositions`, it produces the + mean square displacement (for each component separately). + + * ``"tensor_product"``: Tensor product of :math:`A` and + :math:`B`, i.e., :math:`C_{i \\cdot l_B + j} = A_i B_j` + with :math:`l_B` the length of :math:`B`. + + * ``"fcs_acf"``: Fluorescence Correlation Spectroscopy (FCS) + autocorrelation function, i.e., + + .. math:: + + G_i(\\tau) = + \\frac{1}{N} \\left< \\exp \\left( + - \\frac{\\Delta x_i^2(\\tau)}{w_x^2} + - \\frac{\\Delta y_i^2(\\tau)}{w_y^2} + - \\frac{\\Delta z_i^2(\\tau)}{w_z^2} + \\right) \\right> + + where :math:`N` is the average number of fluorophores in the + illumination area, + + .. math:: + + \\Delta x_i^2(\\tau) = \\left( x_i(0) - x_i(\\tau) \\right)^2 + + is the square displacement of particle + :math:`i` in the :math:`x` direction, and :math:`w_x` + is the beam waist of the intensity profile of the + exciting laser beam, + + .. math:: + + W(x,y,z) = I_0 \\exp + \\left( - \\frac{2x^2}{w_x^2} - \\frac{2y^2}{w_y^2} - + \\frac{2z^2}{w_z^2} \\right). + + The values of :math:`w_x`, :math:`w_y`, and :math:`w_z` + are passed to the correlator as ``args``. The correlator calculates + + .. math:: + + C_i(\\tau) = + \\exp \\left( + - \\frac{\\Delta x_i^2(\\tau)}{w_x^2} + - \\frac{\\Delta y_i^2(\\tau)}{w_y^2} + - \\frac{\\Delta z_i^2(\\tau)}{w_z^2} + \\right) + + Per each 3 dimensions of the observable, one dimension of the correlation + output is produced. If ``"fcs_acf"`` is used with other observables than + :class:`espressomd.observables.ParticlePositions`, the physical meaning + of the result is unclear. + + The above equations are a generalization of the formula presented by + Höfling et al. :cite:`hofling11a`. For more information, see references + therein. + + Parameters + ---------- + obs1 : :class:`espressomd.observables.Observable` + The observable :math:`A` to be correlated with :math:`B` (``obs2``). + If ``obs2`` is omitted, autocorrelation of ``obs1`` is calculated by + default. + + obs2 : :class:`espressomd.observables.Observable`, optional + The observable :math:`B` to be correlated with :math:`A` (``obs1``). + + corr_operation : :obj:`str` + The operation that is performed on :math:`A(t)` and :math:`B(t+\\tau)`. + + delta_N : :obj:`int` + Number of timesteps between subsequent samples for the auto update mechanism. + + tau_max : :obj:`float` + This is the maximum value of :math:`\\tau` for which the + correlation should be computed. Warning: Unless you are using + the multiple tau correlator, choosing ``tau_max`` of more than + ``100 * dt`` will result in a huge computational overhead. In a + multiple tau correlator with reasonable parameters, ``tau_max`` + can span the entire simulation without too much additional cpu time. + + tau_lin : :obj:`int` + The number of data-points for which the results are linearly spaced + in ``tau``. This is a parameter of the multiple tau correlator. If you + want to use it, make sure that you know how it works. ``tau_lin`` must + be divisible by 2. By setting ``tau_lin`` such that + ``tau_max >= dt * delta_N * tau_lin``, the + multiple tau correlator is used, otherwise the trivial linear + correlator is used. By setting ``tau_lin = 1``, the value will be + overridden by ``tau_lin = ceil(tau_max / (dt * delta_N))``, which + will result in either the multiple or linear tau correlator. + In many cases, ``tau_lin=16`` is a + good choice but this may strongly depend on the observables you are + correlating. For more information, we recommend to read + ref. :cite:`ramirez10a` or to perform your own tests. + + compress1 : :obj:`str` + These functions are used to compress the data when + going to the next level of the multiple tau + correlator. This is done by producing one value out of two. + The following compression functions are available: + + * ``"discard2"``: (default value) discard the second value from the time series, use the first value as the result + + * ``"discard1"``: discard the first value from the time series, use the second value as the result + + * ``"linear"``: make a linear combination (average) of the two values + + If only ``compress1`` is specified, then + the same compression function is used for both + observables. If both ``compress1`` and ``compress2`` are specified, + then ``compress1`` is used for ``obs1`` and ``compress2`` for ``obs2``. + + Both ``discard1`` and ``discard2`` are safe for all + observables but produce poor statistics in the + tail. For some observables, ``"linear"`` compression + can be used which makes an average of two + neighboring values but produces systematic + errors. Depending on the observable, the + systematic error using the ``"linear"`` compression + can be anything between harmless and disastrous. + For more information, we recommend to read ref. + :cite:`ramirez10a` or to perform your own tests. + + compress2 : :obj:`str`, optional + See ``compress1``. + + args: :obj:`float` of length 3 + Three floats which are passed as arguments to the correlation + function. Currently it is only used by ``"fcs_acf"``, which + will square these values in the core; if you later decide to + update these weights with ``obs.args = [...]``, you'll have to + provide already squared values! Other correlation operations + will ignore these values. + """ + + _so_name = "Accumulators::Correlator" + _so_bind_methods = ( + "update", + "shape", + "finalize") + _so_creation_policy = "LOCAL" + +
[docs] def result(self): + """ + Get correlation. + + Returns + ------- + :obj:`ndarray` of :obj:`float` + The result of the correlation function. The shape of the array + is determined by the shape of the input observable(s) and the + correlation operation. + """ + return np.array(self.call_method( + "get_correlation")).reshape(self.shape())
+ +
[docs] def lag_times(self): + """ + Returns + ------- + :obj:`ndarray` of :obj:`float` + Lag times of the correlation. + """ + return np.array(self.call_method("get_lag_times"))
+ +
[docs] def sample_sizes(self): + """ + Returns + ------- + :obj:`ndarray` of :obj:`int` + Samples sizes for each lag time. + """ + return np.array(self.call_method("get_samples_sizes"), dtype=int)
+ + +
[docs]@script_interface_register +class AutoUpdateAccumulators(ScriptObjectList): + + """ + Class for handling the auto-update of accumulators used by + :class:`espressomd.system.System`. + + """ + _so_name = "Accumulators::AutoUpdateAccumulators" + _so_creation_policy = "LOCAL" + +
[docs] def add(self, accumulator): + """ + Adds an accumulator instance to the auto-update list. + + """ + self.call_method("add", object=accumulator)
+ +
[docs] def remove(self, accumulator): + """ + Removes an accumulator from the auto-update list. + + """ + self.call_method("remove", object=accumulator)
+ +
[docs] def clear(self): + """ + Removes all accumulators from the auto-update list. + """ + self.call_method("clear")
+
+ +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/doc4.2.2/_modules/espressomd/actors.html b/doc4.2.2/_modules/espressomd/actors.html new file mode 100644 index 0000000000..ae6b837eaf --- /dev/null +++ b/doc4.2.2/_modules/espressomd/actors.html @@ -0,0 +1,171 @@ + + + + + + + + espressomd.actors — ESPResSo 4.2.2 documentation + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Source code for espressomd.actors

+# Copyright (C) 2010-2022 The ESPResSo project
+#
+# This file is part of ESPResSo.
+#
+# ESPResSo is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# ESPResSo is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+from . import highlander
+from . import script_interface
+
+
+
[docs]class Actors: + + """ + Container for actor objects. + """ + + active_actors = [] + + def __del__(self): + self.clear() + + def __getstate__(self): + return self.active_actors + + def __setstate__(self, active_actors): + self.active_actors[:] = [] + for actor in active_actors: + self.active_actors.append(actor) + actor._activate() + +
[docs] def add(self, actor): + """ + Parameters + ---------- + actor : + Actor to add to this container. + + """ + if actor in Actors.active_actors: + raise highlander.ThereCanOnlyBeOne(actor) + + if isinstance(actor, script_interface.ScriptInterfaceHelper): + actor._activate() + + self.active_actors.append(actor) + + if not isinstance(actor, script_interface.ScriptInterfaceHelper): + actor._activate()
+ +
[docs] def remove(self, actor): + """ + Parameters + ---------- + actor : + Actor to remove from this container. + + """ + if actor not in self.active_actors: + raise Exception("Actor is not active") + actor._deactivate() + self.active_actors.remove(actor)
+ +
[docs] def clear(self): + """Remove all actors.""" + # The order in which actors are removed matters. Some actors set up + # global bitfields that activate sanity checks on the MD cellsystem, + # and reset these bitfields when removed. Actors need to be removed + # in the reverse order they were inserted to guarantee pre-conditions + # and post-conditions are always met. + while len(self.active_actors): + self.remove(self.active_actors[-1])
+ + def __str__(self): + return str(self.active_actors) + + def __getitem__(self, key): + return self.active_actors[key] + + def __len__(self): + return len(self.active_actors) + + def __iter__(self): + for actor in self.active_actors: + yield actor + + def __delitem__(self, idx): + actor = self[idx] + self.remove(actor)
+
+ +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/doc4.2.2/_modules/espressomd/bond_breakage.html b/doc4.2.2/_modules/espressomd/bond_breakage.html new file mode 100644 index 0000000000..bb3dd58738 --- /dev/null +++ b/doc4.2.2/_modules/espressomd/bond_breakage.html @@ -0,0 +1,129 @@ + + + + + + + + espressomd.bond_breakage — ESPResSo 4.2.2 documentation + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Source code for espressomd.bond_breakage

+#
+# Copyright (C) 2022 The ESPResSo project
+#
+# This file is part of ESPResSo.
+#
+# ESPResSo is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# ESPResSo is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+from .script_interface import script_interface_register, ScriptObjectMap, ScriptInterfaceHelper
+from . import interactions
+
+
+
[docs]@script_interface_register +class BreakageSpec(ScriptInterfaceHelper): + """ + Specifications for bond breakage. + See :ref:`Deleting bonds when particles are pulled apart` for more details. + + Parameters + ---------- + breakage_length: :obj:`float` + Maximal bond extension until the bond breaks. + action_type: :obj:`str`, {'delete_bond', 'revert_bind_at_point_of_collision', 'none'} + Action triggered when the bond reaches its maximal extension. + + """ + + _so_name = "BondBreakage::BreakageSpec"
+ + +
[docs]@script_interface_register +class BreakageSpecs(ScriptObjectMap): + _so_name = "BondBreakage::BreakageSpecs" + + def _get_key(self, key): + """Convert a bond object to a bond id.""" + if isinstance(key, interactions.BondedInteraction): + key = key._bond_id + if key == -1: + raise ValueError("Bond needs to be added to the system first") + return key + + def __getitem__(self, key): + return super().__getitem__(self._get_key(key)) + + def __setitem__(self, key, value): + return super().__setitem__(self._get_key(key), value)
+
+ +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/doc4.2.2/_modules/espressomd/cell_system.html b/doc4.2.2/_modules/espressomd/cell_system.html new file mode 100644 index 0000000000..43f10d5e65 --- /dev/null +++ b/doc4.2.2/_modules/espressomd/cell_system.html @@ -0,0 +1,291 @@ + + + + + + + + espressomd.cell_system — ESPResSo 4.2.2 documentation + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Source code for espressomd.cell_system

+#
+# Copyright (C) 2013-2022 The ESPResSo project
+#
+# This file is part of ESPResSo.
+#
+# ESPResSo is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# ESPResSo is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+from . import utils
+from . import particle_data
+from .script_interface import ScriptInterfaceHelper, script_interface_register
+
+
+
[docs]@script_interface_register +class CellSystem(ScriptInterfaceHelper): + """ + This class controls the particle decomposition. + + Attributes + ---------- + decomposition_type : :obj:`str` + Name of the currently active particle decomposition. + use_verlet_lists : :obj:`bool` + Whether to use Verlet lists. + skin : :obj:`float` + Verlet list skin. + node_grid : (3,) array_like of :obj:`int` + MPI repartition for the regular decomposition cell system. + max_cut_bonded : :obj:`float` + Maximal range from bonded interactions. + max_cut_nonbonded : :obj:`float` + Maximal range from non-bonded interactions. + interaction_range : :obj:`float` + Maximal interaction range from all interactions, + or -1 when no interactions are active (or their + cutoff has no impact when only 1 MPI rank is used). + + Methods + ------- + resort() + Resort the particles in the cell system. + + Parameters + ---------- + global_flag : :obj:`bool`, optional + If true (default), a global resorting is done, otherwise particles + are only exchanged between neighboring nodes. + + Returns + ------- + (N,) array_like of :obj:`int` + The number of particles per node. + + tune_skin() + Tune the skin by measuring the integration time and bisecting over the + given range of skins. The best skin is set in the simulation core. + + Parameters + ----------- + min_skin : :obj:`float` + Minimum skin to test. + max_skin : :obj:`float` + Maximum skin. + tol : :obj:`float` + Accuracy in skin to tune to. + int_steps : :obj:`int` + Integration steps to time. + adjust_max_skin : :obj:`bool`, optional + If ``True``, the value of ``max_skin`` is reduced + to the maximum permissible skin (in case the passed + value is too large). Defaults to ``False``. + + Returns + ------- + :obj:`float` : + The :attr:`skin` + + get_state() + Get the current state of the cell system. + + Returns + ------- + :obj:`dict` : + The cell system state. + + """ + _so_name = "CellSystem::CellSystem" + _so_creation_policy = "GLOBAL" + _so_bind_methods = ("get_state", "tune_skin", "resort") + + def __reduce__(self): + so_callback, so_callback_args = super().__reduce__() + return (CellSystem._restore_object, (so_callback, so_callback_args)) + + @classmethod + def _restore_object(cls, so_callback, so_callback_args): + return so_callback(*so_callback_args) + +
[docs] def set_regular_decomposition(self, **kwargs): + """ + Activate the regular decomposition cell system. + + Parameters + ---------- + use_verlet_lists : :obj:`bool`, optional + Activates or deactivates the usage of Verlet lists. + Defaults to ``True``. + + """ + self.call_method("initialize", name="regular_decomposition", **kwargs)
+ +
[docs] def set_n_square(self, **kwargs): + """ + Activate the N-square cell system. + + Parameters + ---------- + use_verlet_lists : :obj:`bool`, optional + Activates or deactivates the usage of Verlet lists. + Defaults to ``True``. + + """ + self.call_method("initialize", name="n_square", **kwargs)
+ +
[docs] def set_hybrid_decomposition(self, **kwargs): + """ + Activate the hybrid domain decomposition. + + Parameters + ---------- + cutoff_regular : :obj:`float` + Maximum cutoff to consider in regular decomposition. + Should be as low as the system permits. + n_square_types : list of :obj:`int`, optional + Particles types that should be handled in the N-square cell system. + Defaults to an empty list. + use_verlet_lists : :obj:`bool`, optional + Activates or deactivates the usage of Verlet lists. + Defaults to ``True``. + + """ + self.call_method("initialize", name="hybrid_decomposition", **kwargs)
+ +
[docs] def get_pairs(self, distance, types='all'): + """ + Get pairs of particles closer than threshold value. + + Parameters + ---------- + distance : :obj:`float` + Pairs of particles closer than ``distance`` are found. + types : list of :obj:`int` or ``'all'``, optional + Restrict the pair search to the specified types. + Defaults to ``'all'``, in which case all particles are considered. + + Returns + ------- + list of tuples of :obj:`int` + The particle pairs identified by their index + + Raises + ------ + Exception + If the pair search distance is greater than the cell size + """ + pairs = self.call_method("get_pairs", distance=distance, types=types) + return [tuple(pair) for pair in pairs]
+ +
[docs] def get_neighbors(self, particle, distance): + """ + Get neighbors of a given particle up to a certain distance. + + The choice of :ref:`cell systems <Cell systems>` has an impact on + how far the algorithm can detect particle pairs: + + * N-square: no restriction on the search distance, no double counting + if search distance is larger than the box size + * regular decomposition: the search distance is bounded by half + the local cell geometry + * hybrid decomposition: not supported + + Parameters + ---------- + particle : :class:`~espressomd.particle_data.ParticleHandle` + distance : :obj:`float` + Pairs of particles closer than ``distance`` are found. + + Returns + ------- + (N,) array_like of :obj:`int` + The list of neighbor particles surrounding the particle + + """ + utils.check_type_or_throw_except( + particle, 1, particle_data.ParticleHandle, "Parameter 'particle' must be a particle") + utils.check_type_or_throw_except( + distance, 1, float, "Parameter 'distance' must be a float") + return self.call_method( + "get_neighbors", distance=distance, pid=particle.id)
+ +
[docs] def non_bonded_loop_trace(self): + pairs = self.call_method("non_bonded_loop_trace") + res = [] + for id1, id2, pos1, pos2, vec21, node in pairs: + pos1 = utils.array_locked(pos1) + pos2 = utils.array_locked(pos2) + vec21 = utils.array_locked(vec21) + res.append((id1, id2, pos1, pos2, vec21, node)) + return res
+
+ +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/doc4.2.2/_modules/espressomd/checkpointing.html b/doc4.2.2/_modules/espressomd/checkpointing.html new file mode 100644 index 0000000000..84245abad3 --- /dev/null +++ b/doc4.2.2/_modules/espressomd/checkpointing.html @@ -0,0 +1,369 @@ + + + + + + + + espressomd.checkpointing — ESPResSo 4.2.2 documentation + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Source code for espressomd.checkpointing

+#
+# Copyright (C) 2013-2022 The ESPResSo project
+#
+# This file is part of ESPResSo.
+#
+# ESPResSo is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# ESPResSo is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+import collections
+import inspect
+import os
+import re
+import signal
+from . import utils
+
+try:
+    import cPickle as pickle
+except ImportError:
+    import pickle
+
+
+# Convenient Checkpointing for ESPResSo
+
[docs]class Checkpoint: + + """Checkpoint handling (reading and writing). + + Parameters + ---------- + checkpoint_id : :obj:`str` + A string identifying a specific checkpoint. + checkpoint_path : :obj:`str`, optional + Path for reading and writing the checkpoint. + If not given, the current working directory is used. + + """ + + def __init__(self, checkpoint_id=None, checkpoint_path="."): + # check if checkpoint_id is valid (only allow a-z A-Z 0-9 _ -) + if not isinstance(checkpoint_id, str) or bool( + re.compile(r"[^a-zA-Z0-9_\-]").search(checkpoint_id)): + raise ValueError("Invalid checkpoint id.") + + if not isinstance(checkpoint_path, str): + raise ValueError("Invalid checkpoint path.") + + self.checkpoint_objects = [] + self.checkpoint_signals = [] + frm = inspect.stack()[1] + self.calling_module = inspect.getmodule(frm[0]) + + checkpoint_path = os.path.join(checkpoint_path, checkpoint_id) + self.checkpoint_dir = os.path.realpath(checkpoint_path) + + if not os.path.isdir(self.checkpoint_dir): + os.makedirs(self.checkpoint_dir) + + # update checkpoint counter + self.counter = 0 + while os.path.isfile(os.path.join( + self.checkpoint_dir, f"{self.counter}.checkpoint")): + self.counter += 1 + + # init signals + for signum in self.read_signals(): + self.register_signal(signum) + + def __getattr_submodule(self, obj, name, default): + """ + Generalization of ``getattr()``. + ``__getattr_submodule(object, "name1.sub1.sub2", None)`` will return + attribute ``sub2`` if available otherwise ``None``. + + """ + names = name.split('.') + + for i in range(len(names) - 1): + obj = getattr(obj, names[i], default) + + return getattr(obj, names[-1], default) + + def __setattr_submodule(self, obj, name, value): + """ + Generalization of ``setattr()``. + ``__setattr_submodule(object, "name1.sub1.sub2", value)`` will set + attribute ``sub2`` to ``value``. Will raise exception if parent + modules do not exist. + + """ + names = name.split('.') + for i in range(len(names) - 1): + obj = getattr(obj, names[i], None) + + if obj is None: + raise Exception( + f"Cannot set attribute of non existing submodules: {name}\n" + f"Check the order you registered objects for checkpointing.") + setattr(obj, names[-1], value) + + def __hasattr_submodule(self, obj, name): + """ + Generalization of ``hasattr()``. + ``__hasattr_submodule(object, "name1.sub1.sub2")`` will return + ``True`` if submodule ``sub1`` has the attribute ``sub2``. + + """ + names = name.split('.') + for i in range(len(names) - 1): + obj = getattr(obj, names[i], None) + + return hasattr(obj, names[-1]) + +
[docs] def register(self, *args): + """Register python objects for checkpointing. + + Parameters + ---------- + args : list of :obj:`str` + Names of python objects to be registered for checkpointing. + + """ + for a in args: + if not isinstance(a, str): + raise ValueError( + "The object that should be checkpointed is identified with its name given as a string.") + + # if not a in dir(self.calling_module): + if not self.__hasattr_submodule(self.calling_module, a): + raise KeyError( + f"The given object '{a}' was not found in the current scope.") + + if a in self.checkpoint_objects: + raise KeyError( + f"The given object '{a}' is already registered for checkpointing.") + + self.checkpoint_objects.append(a)
+ +
[docs] def unregister(self, *args): + """Unregister python objects for checkpointing. + + Parameters + ---------- + args : list of :obj:`str` + Names of python objects to be unregistered for checkpointing. + + """ + for a in args: + if not isinstance(a, str) or a not in self.checkpoint_objects: + raise KeyError( + f"The given object '{a}' was not registered for checkpointing yet.") + + self.checkpoint_objects.remove(a)
+ +
[docs] def get_registered_objects(self): + """ + Returns a list of all object names that are registered for + checkpointing. + + """ + return self.checkpoint_objects
+ +
[docs] def has_checkpoints(self): + """Check for checkpoints. + + Returns + ------- + :obj:`bool` + ``True`` if any checkpoints exist that match ``checkpoint_id`` and + ``checkpoint_path`` otherwise ``False``. + + """ + return self.counter > 0
+ +
[docs] def get_last_checkpoint_index(self): + """ + Returns the last index of the given checkpoint id. Will raise exception + if no checkpoints are found. + + """ + if not self.has_checkpoints(): + raise Exception( + "No checkpoints found. Cannot return index for last checkpoint.") + return self.counter - 1
+ +
[docs] def save(self, checkpoint_index=None): + """ + Saves all registered python objects in the given checkpoint directory + using cPickle. + + """ + # get attributes of registered objects + checkpoint_data = collections.OrderedDict() + for obj_name in self.checkpoint_objects: + checkpoint_data[obj_name] = self.__getattr_submodule( + self.calling_module, obj_name, None) + + if checkpoint_index is None: + checkpoint_index = self.counter + filename = os.path.join( + self.checkpoint_dir, f"{checkpoint_index}.checkpoint") + + tmpname = filename + ".__tmp__" + with open(tmpname, "wb") as checkpoint_file: + pickle.dump(checkpoint_data, checkpoint_file, -1) + os.rename(tmpname, filename)
+ +
[docs] def load(self, checkpoint_index=None): + """ + Loads the python objects using (c)Pickle and sets them in the calling + module. + + Parameters + ---------- + checkpoint_index : :obj:`int`, optional + If not given, the last ``checkpoint_index`` will be used. + + """ + if checkpoint_index is None: + checkpoint_index = self.get_last_checkpoint_index() + + filename = os.path.join( + self.checkpoint_dir, f"{checkpoint_index}.checkpoint") + with open(filename, "rb") as f: + checkpoint_data = pickle.load(f) + + for key in checkpoint_data: + self.__setattr_submodule( + self.calling_module, key, checkpoint_data[key]) + self.checkpoint_objects.append(key)
+ + def __signal_handler(self, signum, frame): # pylint: disable=unused-argument + """ + Will be called when a registered signal was sent. + + """ + self.save() + exit(signum) + +
[docs] def read_signals(self): + """ + Reads all registered signals from the signal file and returns a list of + integers. + + """ + if not os.path.isfile(os.path.join(self.checkpoint_dir, "signals")): + return [] + + with open(os.path.join(self.checkpoint_dir, "signals"), "r") as signal_file: + signals = signal_file.readline().strip().split() + signals = [int(i) + for i in signals] # will raise exception if signal file contains invalid entries + return signals
+ + def __write_signal(self, signum=None): + """Writes the given signal integer signum to the signal file. + + """ + signum = int(signum) + if not utils.is_valid_type(signum, int): + raise ValueError("Signal must be an integer number.") + + signals = self.read_signals() + + if signum not in signals: + signals.append(signum) + signals = " ".join(str(i) for i in signals) + with open(os.path.join(self.checkpoint_dir, "signals"), "w") as signal_file: + signal_file.write(signals) + +
[docs] def register_signal(self, signum=None): + """Register a signal that will trigger the signal handler. + + Parameters + ---------- + signum : :obj:`int` + Signal to be registered. + + """ + if not utils.is_valid_type(signum, int): + raise ValueError("Signal must be an integer number.") + + if signum in self.checkpoint_signals: + raise KeyError( + f"The signal {signum} is already registered for checkpointing.") + + signal.signal(signum, self.__signal_handler) + self.checkpoint_signals.append(signum) + self.__write_signal(signum)
+
+ +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/doc4.2.2/_modules/espressomd/cluster_analysis.html b/doc4.2.2/_modules/espressomd/cluster_analysis.html new file mode 100644 index 0000000000..0ba7d0a198 --- /dev/null +++ b/doc4.2.2/_modules/espressomd/cluster_analysis.html @@ -0,0 +1,249 @@ + + + + + + + + espressomd.cluster_analysis — ESPResSo 4.2.2 documentation + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Source code for espressomd.cluster_analysis

+# Copyright (C) 2010-2022 The ESPResSo project
+#
+# This file is part of ESPResSo.
+#
+# ESPResSo is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# ESPResSo is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+from .script_interface import ScriptInterfaceHelper, script_interface_register
+from .particle_data import ParticleHandle, ParticleSlice
+
+
+
[docs]@script_interface_register +class Cluster(ScriptInterfaceHelper): + + """Class representing a cluster of particles. + + Methods + ------- + particle_ids() + Returns list of particle ids in the cluster + + size() + Returns the number of particles in the cluster + + center_of_mass() + Center of mass of the cluster (folded coordinates) + + longest_distance() + Longest distance between any combination of two particles in the cluster + + fractal_dimension(dr=None) + Estimates the cluster's fractal dimension by fitting the number of + particles :math:`n` in spheres of growing radius around the center of mass + to :math:`c*r_g^d`, where :math:`r_g` is the radius of gyration of the + particles within the sphere, and :math:`d` is the fractal dimension. + + .. note:: + + Requires ``GSL`` external feature, enabled with ``-DWITH_GSL=ON``. + + Parameters + ---------- + dr: :obj:`float` + Minimum increment for the radius of the spheres. + + Returns + ------- + :obj:`tuple`: + Fractal dimension and mean square residual. + + """ + _so_name = "ClusterAnalysis::Cluster" + _so_bind_methods = ("particle_ids", "size", "longest_distance", + "radius_of_gyration", "fractal_dimension", "center_of_mass") + + _so_creation_policy = "LOCAL" + +
[docs] def particles(self): + """ + Get particles in the cluster. + + Returns + ------- + :class:`espressomd.particle_data.ParticleSlice` + + """ + return ParticleSlice(self.particle_ids())
+ + +
[docs]@script_interface_register +class ClusterStructure(ScriptInterfaceHelper): + + """Cluster structure of a simulation system, and access to cluster analysis + + Parameters + ---------- + pair_criterion: :class:`espressomd.pair_criteria._PairCriterion` + Criterion to decide whether two particles are neighbors. + + """ + _so_name = "ClusterAnalysis::ClusterStructure" + _so_creation_policy = "LOCAL" + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self._clusters = Clusters(self) + +
[docs] def run_for_all_pairs(self): + """ + Runs the cluster analysis, considering all pairs of particles in the system + + """ + return self.call_method("run_for_all_pairs")
+ +
[docs] def run_for_bonded_particles(self): + """ + Runs the cluster analysis, considering only pairs of particles connected by a pair-bond. + + """ + return self.call_method("run_for_bonded_particles")
+ +
[docs] def clear(self): + """ + Clears the cluster structure. + + """ + return self.call_method("clear")
+ +
[docs] def cluster_ids(self): + """ + Returns a list of all cluster ids of the clusters in the structure. + + """ + return self.call_method("cluster_ids")
+ +
[docs] def cid_for_particle(self, p): + """Returns cluster id for the particle. + + Parameters + ---------- + p : :obj:`espressomd.particle_data.ParticleHandle` or :obj:`int` containing the particle id + Particle. + + """ + if isinstance(p, ParticleHandle): + return self.call_method("cid_for_particle", pid=p.id) + if isinstance(p, int): + return self.call_method("cid_for_particle", pid=p) + raise TypeError( + "The particle has to be passed as instance of ParticleHandle or as an integer particle id")
+ + @property + def clusters(self): + """Gives access to the clusters in the cluster structure via an + instance of :class:`Clusters`.""" + return self._clusters
+ + +
[docs]class Clusters: + + """Access to the clusters in the cluster structure. + + Access is as follows: + + * number of clusters: ``len(clusters)`` + * access a cluster via its id: ``clusters[id]`` + * iterate over clusters (yields ``(id, cluster)`` tuples) + + Example:: + + >>> for cluster_id, cluster in clusters: + ... print(f"{cluster_id=} CoM={cluster.center_of_mass()}") + cluster_id=1 CoM=[1.71834061 1.54988961 1.54734631] + + """ + + def __init__(self, cluster_structure): + self.cluster_structure = cluster_structure + + def __getitem__(self, cluster_id): + return self.cluster_structure.call_method("get_cluster", id=cluster_id) + + def __iter__(self): + for cid in self.cluster_structure.cluster_ids(): + yield (cid, self.cluster_structure.call_method("get_cluster", id=cid)) + + def __len__(self): + return self.cluster_structure.call_method("n_clusters")
+
+ +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/doc4.2.2/_modules/espressomd/collision_detection.html b/doc4.2.2/_modules/espressomd/collision_detection.html new file mode 100644 index 0000000000..b99374cc1a --- /dev/null +++ b/doc4.2.2/_modules/espressomd/collision_detection.html @@ -0,0 +1,215 @@ + + + + + + + + espressomd.collision_detection — ESPResSo 4.2.2 documentation + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Source code for espressomd.collision_detection

+# Copyright (C) 2010-2022 The ESPResSo project
+#
+# This file is part of ESPResSo.
+#
+# ESPResSo is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# ESPResSo is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+from .script_interface import ScriptInterfaceHelper, script_interface_register
+from .interactions import BondedInteraction, BondedInteractions
+from .__init__ import assert_features
+
+
+
[docs]@script_interface_register +class CollisionDetection(ScriptInterfaceHelper): + + """ + Interface to the collision detection / dynamic binding. + + See :ref:`Creating bonds when particles collide` for detailed instructions. + + This class should not be instantiated by the user. Instead, use + the :attr:`~espressomd.system.System.collision_detection` attribute + of the system class to access the collision detection. + + Use method :meth:`~espressomd.collision_detection.CollisionDetection.set_params` + to change the parameters of the collision detection. + + """ + + _so_name = "CollisionDetection::CollisionDetection" + + def __init__(self, **kwargs): + assert_features("COLLISION_DETECTION") + if "sip" in kwargs: + super().__init__(**kwargs) + return + super().__init__() + self.set_params(**kwargs) + + # Do not allow setting of individual attributes + def __setattr__(self, *args, **kwargs): + raise Exception( + "Please set all parameters at once via collision_detection.set_params()") + +
[docs] def set_params(self, **kwargs): + """ + Set the parameters for the collision detection + + See :ref:`Creating bonds when particles collide` for detailed instructions. + + + Parameters + ---------- + mode : :obj:`str`, {"off", "bind_centers", "bind_at_point_of_collision", "bind_three_particles", "glue_to_surface"} + Collision detection mode + + distance : :obj:`float` + Distance below which a pair of particles is considered in the + collision detection + + bond_centers : :obj:`espressomd.interactions.BondedInteraction` + Bond to add between the colliding particles + + bond_vs : :obj:`espressomd.interactions.BondedInteraction` + Bond to add between virtual sites (for modes using virtual sites) + + part_type_vs : :obj:`int` + Particle type of the virtual sites being created on collision + (virtual sites based modes) + + part_type_to_be_glued : :obj:`int` + particle type for ``"glue_to_surface"`` mode. See user guide. + + part_type_to_attach_vs_to : :obj:`int` + particle type for ``"glue_to_surface"`` mode. See user guide. + + part_type_after_glueing : :obj:`int` + particle type for ``"glue_to_surface"`` mode. See user guide. + + distance_glued_particle_to_vs : :obj:`float` + Distance for ``"glue_to_surface"`` mode. See user guide. + + bond_three_particles : :obj:`espressomd.interactions.BondedInteraction` + First angular bond for the ``"bind_three_particles"`` mode. See + user guide + + three_particle_binding_angle_resolution : :obj:`int` + Resolution for the angular bonds (mode ``"bind_three_particles"``). + Resolution+1 bonds are needed to accommodate the case of 180 degrees + angles + + """ + + if "mode" not in kwargs: + raise ValueError( + "Collision mode must be specified via the 'mode' argument") + # Convert bonds to bond ids + for name in ["bond_centers", "bond_vs", "bond_three_particle_binding"]: + if name in kwargs: + if isinstance(kwargs[name], BondedInteraction): + kwargs[name] = kwargs[name]._bond_id + self.call_method('instantiate', **kwargs)
+ +
[docs] def get_parameter(self, name): + """Gets a single parameter from the collision detection.""" + + value = super().get_parameter(name) + if name in ["bond_centers", "bond_vs", "bond_three_particle_binding"]: + if value == -1: # Not defined + value = None + else: + value = BondedInteractions()[value] + return value
+ +
[docs] def get_params(self): + """Returns the parameters of the collision detection as dict. + + """ + params = {} + mode = super().get_parameter("mode") + for name in self.call_method("params_for_mode", mode=mode): + params[name] = self.get_parameter(name) + return params
+ + def __reduce__(self): + so_callback, so_callback_args = super().__reduce__() + return (CollisionDetection._restore_object, + (so_callback, so_callback_args, self.get_params())) + + @classmethod + def _restore_object(cls, so_callback, so_callback_args, state): + so = so_callback(*so_callback_args) + so.set_params(**state) + return so
+
+ +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/doc4.2.2/_modules/espressomd/comfixed.html b/doc4.2.2/_modules/espressomd/comfixed.html new file mode 100644 index 0000000000..edd2119079 --- /dev/null +++ b/doc4.2.2/_modules/espressomd/comfixed.html @@ -0,0 +1,110 @@ + + + + + + + + espressomd.comfixed — ESPResSo 4.2.2 documentation + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Source code for espressomd.comfixed

+# Copyright (C) 2010-2022 The ESPResSo project
+#
+# This file is part of ESPResSo.
+#
+# ESPResSo is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# ESPResSo is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+from .script_interface import ScriptInterfaceHelper, script_interface_register
+
+
+
[docs]@script_interface_register +class ComFixed(ScriptInterfaceHelper): + + """Fix the center of mass of specific types. + + Subtracts mass-weighted fraction of the total + force action on all particles of the type from + the particles after each force calculation. This + keeps the center of mass of the type fixed iff + the total momentum of the type is zero. + + Parameters + ---------- + types : array_like + List of types for which the center of mass should be fixed. + """ + + _so_name = "ComFixed" + _so_creation_policy = "GLOBAL"
+
+ +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/doc4.2.2/_modules/espressomd/constraints.html b/doc4.2.2/_modules/espressomd/constraints.html new file mode 100644 index 0000000000..f526421842 --- /dev/null +++ b/doc4.2.2/_modules/espressomd/constraints.html @@ -0,0 +1,692 @@ + + + + + + + + espressomd.constraints — ESPResSo 4.2.2 documentation + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Source code for espressomd.constraints

+# Copyright (C) 2010-2022 The ESPResSo project
+#
+# This file is part of ESPResSo.
+#
+# ESPResSo is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# ESPResSo is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+from .script_interface import ScriptObjectList, ScriptInterfaceHelper, script_interface_register
+import numpy as np
+import itertools
+
+
+
[docs]@script_interface_register +class Constraints(ScriptObjectList): + + """ + List of active constraints. Add a :class:`espressomd.constraints.Constraint` + to make it active in the system, or remove it to make it inactive. + + """ + + _so_name = "Constraints::Constraints" + +
[docs] def add(self, *args, **kwargs): + """ + Add a constraint to the list. + + Parameters + ---------- + constraint: :class:`espressomd.constraints.Constraint` + Either a constraint object... + **kwargs + ... or parameters to construct an + :class:`espressomd.constraints.ShapeBasedConstraint` + + Returns + ---------- + constraint : :class:`espressomd.constraints.Constraint` + The added constraint + + """ + + if len(args) == 1: + if isinstance(args[0], Constraint): + constraint = args[0] + else: + raise TypeError( + "Either a Constraint object or key-value pairs for the parameters of a ShapeBasedConstraint object need to be passed.") + else: + constraint = ShapeBasedConstraint(**kwargs) + self.call_method("add", object=constraint) + return constraint
+ +
[docs] def remove(self, constraint): + """ + Remove a constraint from the list. + + Parameters + ---------- + constraint : :obj:`espressomd.constraints.Constraint` + + """ + + self.call_method("remove", object=constraint)
+ +
[docs] def clear(self): + """ + Remove all constraints. + + """ + self.call_method("clear")
+ + +
[docs]class Constraint(ScriptInterfaceHelper): + + """ + Base class for constraints. A constraint provides a force and + an energy contribution for a single particle. + + """ + + _so_name = "Constraints::Constraint"
+ + +
[docs]@script_interface_register +class ShapeBasedConstraint(Constraint): + + """ + + Attributes + ---------- + only_positive : :obj:`bool` + Act only in the direction of positive normal, + only useful if penetrable is ``True``. + particle_type : :obj:`int` + Interaction type of the constraint. + particle_velocity : array_like of :obj:`float` + Interaction velocity of the boundary + penetrable : :obj:`bool` + Whether particles are allowed to penetrate the constraint. + shape : :class:`espressomd.shapes.Shape` + One of the shapes from :mod:`espressomd.shapes` + + See Also + ---------- + espressomd.shapes : shape module that defines mathematical surfaces + + Examples + ---------- + >>> import espressomd + >>> import espressomd.shapes + >>> system = espressomd.System(box_l=3 * [10.]) + >>> + >>> # create first a shape-object to define the constraint surface + >>> spherical_cavity = espressomd.shapes.Sphere(center=system.box_l / 2, radius=2.0, direction=-1.0) + >>> + >>> # now create an un-penetrable shape-based constraint of type 0 + >>> spherical_constraint = system.constraints.add(particle_type=0, penetrable=False, shape=spherical_cavity) + >>> + >>> # place a trapped particle inside this sphere + >>> system.part.add(pos=0.51 * system.box_l, type=1) + + """ + + _so_name = "Constraints::ShapeBasedConstraint" + +
[docs] def min_dist(self): + """ + Calculates the minimum distance to all interacting particles. + + Returns + ---------- + :obj:`float` : + The minimum distance + """ + return self.call_method("min_dist", object=self)
+ +
[docs] def total_force(self): + """ + Get total force acting on this constraint. + + Examples + ---------- + >>> import espressomd + >>> import espressomd.shapes + >>> system = espressomd.System(box_l=[50., 50., 50.]) + >>> system.time_step = 0.01 + >>> system.thermostat.set_langevin(kT=0.0, gamma=1.0) + >>> system.cell_system.set_n_square(use_verlet_lists=False) + >>> system.non_bonded_inter[0, 0].lennard_jones.set_params( + ... epsilon=1, sigma=1, cutoff=2**(1. / 6), shift="auto") + >>> + >>> floor = system.constraints.add( + ... shape=espressomd.shapes.Wall(normal=[0, 0, 1], dist=0.0), + ... particle_type=0, penetrable=False, only_positive=False) + >>> + >>> p = system.part.add(pos=[0,0,1.5], type=0, ext_force=[0, 0, -.1]) + >>> # print the particle position as it falls + >>> # and print the force it applies on the floor + >>> for t in range(10): + ... system.integrator.run(100) + ... print(p.pos, floor.total_force()) + + """ + return self.call_method("total_force", constraint=self)
+ +
[docs] def total_normal_force(self): + """ + Get the total summed normal force acting on this constraint. + + """ + return self.call_method("total_normal_force", constraint=self)
+ + +
[docs]@script_interface_register +class HomogeneousMagneticField(Constraint): + """ + Homogeneous magnetic field :math:`\\vec{H}`. + The resulting force :math:`\\vec{F}`, torque :math:`\\vec{\\tau}` + and energy `U` on the particles are then + + :math:`\\vec{F} = \\vec{0}` + + :math:`\\vec{\\tau} = \\vec{\\mu} \\times \\vec{H}` + + :math:`U = -\\vec{\\mu} \\cdot \\vec{H}` + + where :math:`\\vec{\\mu}` is the particle dipole moment. + + Attributes + ---------- + H : (3,) array_like of :obj:`float` + Magnetic field vector. Describes both field direction and + strength of the magnetic field (via length of the vector). + + """ + + _so_name = "Constraints::HomogeneousMagneticField"
+ + +class _Interpolated(Constraint): + + """ + Tabulated field data. + The actual field value is calculated by linear + interpolation (force fields) or gradient linear + interpolation. + + The data has to have one point of halo in each direction, + and is shifted by half a grid spacing in the +xyz direction, + so that the element (0,0,0) has coordinates -0.5 * grid_spacing. + The number of points has to be such that the data spans the whole + box, e.g. the most up right back point has to be at least at + box + 0.5 * grid_spacing. There are convenience functions on this + class that can calculate the required grid dimensions and the coordinates. + + Arguments + ---------- + field : (M, N, O, P) array_like of :obj:`float` + The actual field on a grid of size (M, N, O) with dimension P. + grid_spacing : (3,) array_like of :obj:`float` + Spacing of the grid points. + + Attributes + ---------- + + field : (M, N, O, P) array_like of :obj:`float` + The actual field on a grid of size (M, N, O) with dimension P. + Please be aware that depending on the interpolation + order additional points are used on the boundaries. + + grid_spacing : array_like of :obj:`float` + Spacing of the grid points. + + origin : (3,) array_like of :obj:`float` + Coordinates of the grid origin. + + """ + + def __init__(self, **kwargs): + if "sip" not in kwargs: + field = kwargs.pop("field") + shape, codim = self._unpack_dims(field) + super().__init__(_field_shape=shape, _field_codim=codim, + _field_data=field.flatten(), **kwargs) + else: + super().__init__(**kwargs) + + @classmethod + def required_dims(cls, box_size, grid_spacing): + """ + Calculate the grid size and origin needed for specified box size and + grid spacing. Returns the shape and origin (coordinates of [0][0][0]) + needed. + + Arguments + --------- + box_size : (3,) array_like of obj:`float` + The box the field should be used. + + grid_spacing : array_like obj:`float` + The desired grid spacing. + + """ + + shape = np.array(np.ceil(box_size / grid_spacing), dtype=int) + 2 + origin = -0.5 * grid_spacing + return shape, origin + + @classmethod + def field_from_fn(cls, box_size, grid_spacing, f, codim=None): + """Generate field data for a desired box size and grid spacing + by evaluating a function at the coordinates. + + Arguments + --------- + box_size : (3,) array_like of obj:`float` + The box the field should be used. + + grid_spacing : array_like obj:`float` + The desired grid spacing. + + f : callable + A function that is called with the coordinates of every + grid point to populate the grid. + + """ + + shape, origin = cls.required_dims(box_size, grid_spacing) + + if not codim: + codim = cls._codim + + field = np.zeros((shape[0], shape[1], shape[2], codim)) + + for i in itertools.product(*map(range, shape)): + x = origin + np.array(i) * grid_spacing + field[i] = f(x) + + return field + + @classmethod + def field_coordinates(cls, box_size, grid_spacing): + """Returns an array of the coordinates of the grid points required. + + Arguments + --------- + box_size : (3,) array_like of obj:`float` + The box the field should be used. + + grid_spacing : array_like obj:`float` + The desired grid spacing. + """ + + return cls.field_from_fn(box_size, grid_spacing, lambda x: x, 3) + + def _unpack_dims(self, a): + s = a.shape + shape = s[:3] + codim = s[3] + + return (shape, codim) + + @property + def field(self): + shape = self._field_shape + return np.reshape(self._field_data, + (shape[0], shape[1], shape[2], self._field_codim)) + + +
[docs]@script_interface_register +class ForceField(_Interpolated): + + """ + A generic tabulated force field that applies a per-particle scaling factor. + + Arguments + ---------- + field : (M, N, O, 3) array_like of :obj:`float` + Forcefield amplitude on a grid of size (M, N, O). + grid_spacing : (3,) array_like of :obj:`float` + Spacing of the grid points. + default_scale : :obj:`float` + Scaling factor for particles that have no individual scaling factor. + particle_scales : :obj:`dict` + A dictionary mapping particle ids to scaling factors. + For these particles, the interaction is scaled with + their individual scaling factor. Other particles are + scaled with the default scaling factor. + + """ + + def __init__(self, **kwargs): + super().__init__(**kwargs) + + _codim = 3 + _so_name = "Constraints::ForceField"
+ + +
[docs]@script_interface_register +class PotentialField(_Interpolated): + + """ + A generic tabulated force field that applies a per-particle + scaling factor. The forces are calculated numerically from + the data by finite differences. The potential is interpolated + from the provided data. + + Arguments + ---------- + field : (M, N, O, 1) array_like of :obj:`float` + Potential on a grid of size (M, N, O). + grid_spacing : (3,) array_like of :obj:`float` + Spacing of the grid points. + default_scale : :obj:`float` + Scaling factor for particles that have no individual scaling factor. + particle_scales : :obj:`dict` + A dictionary mapping particle ids to scaling factors. + For these particles, the interaction is scaled with + their individual scaling factor. Other particles are + scaled with the default scaling factor. + + """ + + def __init__(self, **kwargs): + super().__init__(**kwargs) + + _codim = 1 + _so_name = "Constraints::PotentialField"
+ + +
[docs]@script_interface_register +class Gravity(Constraint): + + """ + Gravity force + + :math:`\\vec{F} = m \\cdot \\vec{g}` + + Arguments + ---------- + g : (3,) array_like of :obj:`float` + The gravitational constant. + + """ + + def __init__(self, **kwargs): + if "sip" not in kwargs: + kwargs["value"] = kwargs.pop("g") + super().__init__(**kwargs) + + @property + def g(self): + return self.value + + _so_name = "Constraints::Gravity"
+ + +
[docs]@script_interface_register +class LinearElectricPotential(Constraint): + + """ + Electric potential of the form + + :math:`\\phi = -\\vec{E} \\cdot \\vec{x} + \\phi_0`, + + resulting in the electric field :math:`\\vec{E}` everywhere. + The resulting force on the particles are then + + :math:`\\vec{F} = q \\cdot \\vec{E}` + + where :math:`q` and :math:`\\vec{x}` are the particle charge and position + in folded coordinates. + This can be used to model a plate capacitor. + + Arguments + ---------- + E : array_like of :obj:`float` + The electric field. + phi0 : :obj:`float` + The potential at the origin + + """ + + def __init__(self, phi0=0, **kwargs): + if "sip" not in kwargs: + kwargs["A"] = -np.array(kwargs.pop("E")) + kwargs["b"] = phi0 + super().__init__(**kwargs) + + @property + def E(self): + return -np.array(self.A) + + @property + def phi0(self): + return np.array(self.b) + + _so_name = "Constraints::LinearElectricPotential"
+ + +
[docs]@script_interface_register +class ElectricPlaneWave(Constraint): + + """ + Electric field of the form + + :math:`\\vec{E} = \\vec{E_0} \\cdot \\sin(\\vec{k} \\cdot \\vec{x} + \\omega \\cdot t + \\phi)` + + The resulting force on the particles are then + + :math:`\\vec{F} = q \\cdot \\vec{E}` + + where :math:`q` and :math:`\\vec{x}` are the particle charge and position + in folded coordinates. + This can be used to generate a homogeneous AC + field by setting :math:`\\vec{k}` to the null vector. + For periodic systems, :math:`\\vec{k}` must be an integer multiple + of :math:`2\\pi \\vec{L}^{-1}` with :math:`\\vec{L}` the box length. + + Arguments + ---------- + E0 : array_like of :obj:`float` + Amplitude of the electric field. + k : array_like of :obj:`float` + Wave vector of the wave + omega : :obj:`float` + Frequency of the wave + phi : :obj:`float`, optional + Phase + + """ + + _so_name = "Constraints::ElectricPlaneWave" + + def __init__(self, phi=0, **kwargs): + if "sip" not in kwargs: + kwargs["amplitude"] = kwargs.pop("E0") + kwargs["wave_vector"] = kwargs.pop("k") + kwargs["frequency"] = kwargs.pop("omega") + kwargs["phase"] = phi + super().__init__(**kwargs) + + @property + def E0(self): + return np.array(self.amplitude) + + @property + def k(self): + return np.array(self.wave_vector) + + @property + def omega(self): + return self.frequency + + @property + def phi(self): + return self.phase
+ + +
[docs]@script_interface_register +class FlowField(_Interpolated): + + """ + Viscous coupling to a flow field that is + interpolated from tabulated data like + + :math:`\\vec{F} = -\\gamma \\cdot \\left( \\vec{u}(\\vec{x}) - \\vec{v} \\right)` + + where :math:`\\vec{v}` and :math:`\\vec{x}` are the particle velocity and position + in folded coordinates, and :math:`\\vec{u}(\\vec{x})` is a 3D flow field on a grid. + + Arguments + ---------- + field : (M, N, O, 3) array_like of :obj:`float` + Field velocity on a grid of size (M, N, O) + grid_spacing : (3,) array_like of :obj:`float` + Spacing of the grid points. + gamma : :obj:`float` + Coupling constant + + """ + + def __init__(self, **kwargs): + super().__init__(**kwargs) + + _codim = 3 + _so_name = "Constraints::FlowField"
+ + +
[docs]@script_interface_register +class HomogeneousFlowField(Constraint): + + """ + Viscous coupling to a flow field that is + constant in space with the force + + :math:`\\vec{F} = -\\gamma \\cdot (\\vec{u} - \\vec{v})` + + where :math:`\\vec{v}` is the velocity of the particle + and :math:`\\vec{u}` is the constant flow field. + + Attributes + ---------- + gamma : :obj:`float` + Coupling constant + + """ + + def __init__(self, **kwargs): + if "sip" not in kwargs: + kwargs["value"] = kwargs.pop("u") + super().__init__(**kwargs) + + @property + def u(self): + """ + Field velocity ((3,) array_like of :obj:`float`). + """ + return self.value + + _so_name = "Constraints::HomogeneousFlowField"
+ + +
[docs]@script_interface_register +class ElectricPotential(_Interpolated): + + """ + Electric potential interpolated from + provided data. The electric field :math:`\\vec{E}` is + calculated numerically from the potential, + and the resulting force on the particles are + + :math:`\\vec{F} = q \\cdot \\vec{E}` + + where :math:`q` is the charge of the particle. + + Arguments + ---------- + field : (M, N, O, 1) array_like of :obj:`float` + Potential on a grid of size (M, N, O) + grid_spacing : (3,) array_like of :obj:`float` + Spacing of the grid points. + + """ + + def __init__(self, **kwargs): + super().__init__(**kwargs) + + _codim = 1 + _so_name = "Constraints::ElectricPotential"
+
+ +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/doc4.2.2/_modules/espressomd/drude_helpers.html b/doc4.2.2/_modules/espressomd/drude_helpers.html new file mode 100644 index 0000000000..76d2b78f4c --- /dev/null +++ b/doc4.2.2/_modules/espressomd/drude_helpers.html @@ -0,0 +1,389 @@ + + + + + + + + espressomd.drude_helpers — ESPResSo 4.2.2 documentation + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Source code for espressomd.drude_helpers

+# Copyright (C) 2010-2022 The ESPResSo project
+#
+# This file is part of ESPResSo.
+#
+# ESPResSo is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# ESPResSo is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+from . import interactions
+from .__init__ import has_features
+
+
+
[docs]class DrudeHelpers: + """ + Provides helper functions to assist in the creation of Drude particles. + + """ + + def __init__(self): + # Dict with Drude type information + self.drude_dict = {} + # Lists with unique Drude and core types + self.core_type_list = [] + self.drude_type_list = [] + # Get core id from Drude id + self.core_id_from_drude_id = {} + # Drude IDs + self.drude_id_list = [] + +
[docs] def add_drude_particle_to_core(self, system, harmonic_bond, + thermalized_bond, p_core, type_drude, alpha, + mass_drude, coulomb_prefactor, + thole_damping=2.6, verbose=False): + """ + Adds a Drude particle with specified type and mass to the system and + returns its `espressomd.particle_data.ParticleHandle`. + Checks if different Drude particles have different types. + Collects types/charges/polarizations/Thole factors for intramolecular + core-Drude short-range exclusion and Thole interaction. + + Parameters + ---------- + + system : :class:`espressomd.system.System` + harmonic_bond: :class:`espressomd.interactions.HarmonicBond` + Add this harmonic bond to between Drude particle and core + thermalized_bond: :class:`espressomd.interactions.ThermalizedBond` + Add this thermalized_bond to between Drude particle and core + p_core: :class:`espressomd.particle_data.ParticleHandle` + The existing core particle + type_drude: :obj:`int` + The type of the newly created Drude particle + alpha : :obj:`float` + The polarizability in units of inverse volume. Related to the charge + of the Drude particle. + mass_drude : :obj:`float` + The mass of the newly created Drude particle + coulomb_prefactor : :obj:`float` + Required to calculate the charge of the Drude particle. + thole_damping : :obj:`float` + Thole damping factor of the Drude pair. Comes to effect if + :meth:`add_all_thole()` method is used. + verbose : :obj:`bool` + Turns on verbosity. + + Returns + ------- + :class:`espressomd.particle_data.ParticleHandle` + The created Drude Particle. + + """ + + k = harmonic_bond.params["k"] + q_drude = -1.0 * pow(k * alpha / coulomb_prefactor, 0.5) + + if has_features("THERMOSTAT_PER_PARTICLE"): + if has_features("PARTICLE_ANISOTROPY"): + gamma_off = [0.0, 0.0, 0.0] + else: + gamma_off = 0.0 + + drude_part = system.part.add(pos=p_core.pos, type=type_drude, + q=q_drude, mass=mass_drude) + if has_features("THERMOSTAT_PER_PARTICLE"): + drude_part.gamma = gamma_off + id_drude = drude_part.id + + if verbose: + print( + f"Adding to core {p_core.id} pol {alpha} core charge {p_core.q} -> {p_core.q - q_drude} drude charge {q_drude}") + + p_core.q -= q_drude + p_core.mass -= mass_drude + p_core.add_bond((harmonic_bond, id_drude)) + p_core.add_bond((thermalized_bond, id_drude)) + if has_features("THERMOSTAT_PER_PARTICLE"): + p_core.gamma = gamma_off + + if type_drude in self.drude_dict and not ( + self.drude_dict[type_drude]["q"] == q_drude and + self.drude_dict[type_drude]["thole_damping"] == thole_damping): + raise Exception( + "Drude particles with different drude charges have to have different types for THOLE") + + self.core_id_from_drude_id[id_drude] = p_core.id + + # Add new Thole non-bonded interaction for D-D, D-C, C-C for all existing + # Drude types if this type is seen for the first time + if type_drude not in self.drude_dict: + + # Bookkeeping of q, alphas and damping parameter + self.drude_dict[type_drude] = {} + self.drude_dict[type_drude]["q"] = q_drude + self.drude_dict[type_drude]["qc"] = p_core.q + self.drude_dict[type_drude]["alpha"] = alpha + self.drude_dict[type_drude]["thole_damping"] = thole_damping + self.drude_dict[type_drude]["core_type"] = p_core.type + # Save same information to get access to the parameters via core + # types + self.drude_dict[p_core.type] = {} + self.drude_dict[p_core.type]["q"] = -q_drude + self.drude_dict[p_core.type]["qc"] = p_core.q + self.drude_dict[p_core.type]["alpha"] = alpha + self.drude_dict[p_core.type]["thole_damping"] = thole_damping + self.drude_dict[p_core.type]["drude_type"] = type_drude + + # Collect unique Drude types + if type_drude not in self.drude_type_list: + self.drude_type_list.append(type_drude) + + # Collect unique core types + if p_core.type not in self.core_type_list: + self.core_type_list.append(p_core.type) + + # Collect unique Drude ids + if id_drude not in self.drude_id_list: + self.drude_id_list.append(id_drude) + + return drude_part
+ +
[docs] def add_thole_pair_damping(self, system, t1, t2, verbose=False): + """ + Calculates mixed Thole factors depending on Thole damping and polarization. + Adds non-bonded Thole interactions to the system. + + Parameters + ---------- + + system : :class:`espressomd.system.System` + t1 : :obj:`int` + Type 1 + t2 : :obj:`int` + Type 2 + verbose : :obj:`bool` + Turns on verbosity. + + """ + + qq = self.drude_dict[t1]["q"] * self.drude_dict[t2]["q"] + s = 0.5 * (self.drude_dict[t1]["thole_damping"] + self.drude_dict[t2]["thole_damping"] + ) / (self.drude_dict[t1]["alpha"] * self.drude_dict[t2]["alpha"])**(1.0 / 6.0) + + system.non_bonded_inter[t1, t2].thole.set_params( + scaling_coeff=s, q1q2=qq) + + if verbose: + print( + f"Added THOLE non-bonded interaction for types {t1} <-> {t2} S {s} q1q2 {qq}")
+ +
[docs] def add_all_thole(self, system, verbose=False): + """ + Calls :meth:`add_thole_pair_damping()` for all necessary combinations to + create the interactions. + + Parameters + ---------- + + system : :class:`espressomd.system.System` + verbose : :obj:`bool` + Turns on verbosity. + + """ + + # Drude <-> Drude + for i in range(len(self.drude_type_list)): + for j in range(i, len(self.drude_type_list)): + self.add_thole_pair_damping( + system, self.drude_type_list[i], self.drude_type_list[j], verbose) + # core <-> core + for i in range(len(self.core_type_list)): + for j in range(i, len(self.core_type_list)): + self.add_thole_pair_damping( + system, self.core_type_list[i], self.core_type_list[j], verbose) + # Drude <-> core + for i in self.drude_type_list: + for j in self.core_type_list: + self.add_thole_pair_damping(system, i, j, verbose)
+ +
[docs] def setup_and_add_drude_exclusion_bonds(self, system, verbose=False): + """ + Creates electrostatic short-range exclusion bonds for global exclusion + between Drude particles and core charges and adds the bonds to the cores. + Has to be called once after all Drude particles have been created. + + Parameters + ---------- + + system : :class:`espressomd.system.System` + verbose: :obj:`bool` + Turns on verbosity. + + """ + + # All Drude types need... + for td in self.drude_type_list: + + # ...exclusions with core + qd = self.drude_dict[td]["q"] # Drude charge + qc = self.drude_dict[td]["qc"] # Core charge + subtr_sr_bond = interactions.BondedCoulombSRBond( + q1q2=-qd * qc) + system.bonded_inter.add(subtr_sr_bond) + self.drude_dict[td]["subtr_sr_bonds_drude-core"] = subtr_sr_bond + if verbose: + print( + f"Added drude-core SR exclusion bond {subtr_sr_bond} for drude {qd} <-> core {qc} to system") + + for drude_id in self.drude_id_list: + core_id = self.core_id_from_drude_id[drude_id] + pd = system.part.by_id(drude_id) + pc = system.part.by_id(core_id) + bond = self.drude_dict[pd.type]["subtr_sr_bonds_drude-core"] + pc.add_bond((bond, drude_id)) + if verbose: + print( + f"Added drude-core SR bond {bond} between ids {drude_id} and {core_id}")
+ +
[docs] def setup_intramol_exclusion_bonds(self, system, mol_drude_types, mol_core_types, + mol_core_partial_charges, verbose=False): + """ + Creates electrostatic short-range exclusion bonds for intramolecular exclusion + between Drude particles and partial charges of the cores. Has to be called once + after all Drude particles have been created. + + Parameters + ---------- + + system : :class:`espressomd.system.System` + mol_drude_types : + List of types of Drude particles within the molecule + mol_core_types : + List of types of core particles within the molecule + mol_core_partial_charges : + List of partial charges of core particles within the molecule + verbose : :obj:`bool` + Turns on verbosity. + + """ + + # All Drude types need... + for td in mol_drude_types: + self.drude_dict[td]["subtr_sr_bonds_intramol"] = {} + + # ... sr exclusion bond with other partial core charges... + for tc, qp in zip(mol_core_types, mol_core_partial_charges): + # ...excluding the Drude core partner + if self.drude_dict[td]["core_type"] != tc: + qd = self.drude_dict[td]["q"] # Drude charge + subtr_sr_bond = interactions.BondedCoulombSRBond( + q1q2=-qd * qp) + system.bonded_inter.add(subtr_sr_bond) + self.drude_dict[td]["subtr_sr_bonds_intramol"][ + tc] = subtr_sr_bond + if verbose: + print( + f"Added intramolecular exclusion {subtr_sr_bond} for drude {qd} <-> core {qp} to system")
+ +
[docs] def add_intramol_exclusion_bonds( + self, drude_parts, core_parts, verbose=False): + """ + Applies electrostatic short-range exclusion bonds for the given ids. + Has to be applied for all molecules. + + Parameters + ---------- + + system : :class:`espressomd.system.System` + drude_parts : + List of Drude particles within a molecule. + core_parts : + List of core particles within a molecule. + verbose : :obj:`bool` + Turns on verbosity. + + """ + + for drude_part in drude_parts: + drude_id = drude_part.id + for core_part in core_parts: + core_id = core_part.id + if self.core_id_from_drude_id[drude_id] != core_id: + pd = drude_part + pc = core_part + bond = self.drude_dict[pd.type][ + "subtr_sr_bonds_intramol"][pc.type] + pd.add_bond((bond, core_id)) + if verbose: + print( + f"Added subtr_sr bond {bond} between ids {drude_id} and {core_id}")
+
+ +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/doc4.2.2/_modules/espressomd/ekboundaries.html b/doc4.2.2/_modules/espressomd/ekboundaries.html new file mode 100644 index 0000000000..021dfb6106 --- /dev/null +++ b/doc4.2.2/_modules/espressomd/ekboundaries.html @@ -0,0 +1,111 @@ + + + + + + + + espressomd.ekboundaries — ESPResSo 4.2.2 documentation + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Source code for espressomd.ekboundaries

+# Copyright (C) 2010-2022 The ESPResSo project
+#
+# This file is part of ESPResSo.
+#
+# ESPResSo is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# ESPResSo is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+from .script_interface import script_interface_register
+from .__init__ import has_features
+import espressomd.lbboundaries
+
+
+if any(has_features(i) for i in ["LB_BOUNDARIES", "LB_BOUNDARIES_GPU"]):
+
[docs] @script_interface_register + class EKBoundaries(espressomd.lbboundaries.LBBoundaries): + + """ + Creates a set of electrokinetics boundaries. + + """ + pass
+ +
[docs] @script_interface_register + class EKBoundary(espressomd.lbboundaries.LBBoundary): + + """ + Creates a EK boundary. + + """ + pass
+
+ +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/doc4.2.2/_modules/espressomd/electrostatic_extensions.html b/doc4.2.2/_modules/espressomd/electrostatic_extensions.html new file mode 100644 index 0000000000..f3e3d7851b --- /dev/null +++ b/doc4.2.2/_modules/espressomd/electrostatic_extensions.html @@ -0,0 +1,242 @@ + + + + + + + + espressomd.electrostatic_extensions — ESPResSo 4.2.2 documentation + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Source code for espressomd.electrostatic_extensions

+#
+# Copyright (C) 2013-2022 The ESPResSo project
+#
+# This file is part of ESPResSo.
+#
+# ESPResSo is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# ESPResSo is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+from . import utils
+from .script_interface import ScriptInterfaceHelper, script_interface_register
+from .__init__ import has_features
+import numpy as np
+
+
+
[docs]class ElectrostaticExtensions(ScriptInterfaceHelper): + + _so_creation_policy = "GLOBAL" + + def __init__(self, **kwargs): + self._check_required_features() + + if 'sip' not in kwargs: + params = self.default_params() + params.update(kwargs) + self.validate_params(params) + super().__init__(**params) + else: + super().__init__(**kwargs) + + def _check_required_features(self): + if not has_features("ELECTROSTATICS"): + raise NotImplementedError("Feature ELECTROSTATICS not compiled in") + +
[docs] def validate_params(self, params): + raise NotImplementedError("Derived classes must implement this method")
+ +
[docs] def default_params(self): + raise NotImplementedError("Derived classes must implement this method")
+ +
[docs] def valid_keys(self): + raise NotImplementedError("Derived classes must implement this method")
+ +
[docs] def required_keys(self): + raise NotImplementedError("Derived classes must implement this method")
+ + def _activate(self): + self.call_method("check_charge_neutrality") + self.call_method("activate") + utils.handle_errors("Coulomb extension activation failed") + + def _deactivate(self): + self.call_method("deactivate") + utils.handle_errors("Coulomb extension deactivation failed")
+ + +
[docs]@script_interface_register +class ICC(ElectrostaticExtensions): + """ + Interface to the induced charge calculation scheme for dielectric + interfaces. See :ref:`Dielectric interfaces with the ICC algorithm` + for more details. + + Parameters + ---------- + n_icc : :obj:`int` + Total number of ICC Particles. + first_id : :obj:`int`, optional + ID of the first ICC Particle. + convergence : :obj:`float`, optional + Abort criteria of the iteration. It corresponds to the maximum relative + change of any of the interface particle's charge. + relaxation : :obj:`float`, optional + SOR relaxation parameter. + ext_field : :obj:`float`, optional + Homogeneous electric field added to the calculation of dielectric boundary forces. + max_iterations : :obj:`int`, optional + Maximal number of iterations. + eps_out : :obj:`float`, optional + Relative permittivity of the outer region (where the particles are). + normals : (``n_icc``, 3) array_like :obj:`float` + Normal vectors pointing into the outer region. + areas : (``n_icc``, ) array_like :obj:`float` + Areas of the discretized surface. + sigmas : (``n_icc``, ) array_like :obj:`float`, optional + Additional surface charge density in the absence of any charge + induction. + epsilons : (``n_icc``, ) array_like :obj:`float` + Dielectric constant associated to the areas. + + """ + _so_name = "Coulomb::ICCStar" + _so_creation_policy = "GLOBAL" + +
[docs] def validate_params(self, params): + utils.check_type_or_throw_except( + params["n_icc"], 1, int, "Invalid parameter 'n_icc'") + utils.check_type_or_throw_except( + params["first_id"], 1, int, "Invalid parameter 'first_id'") + utils.check_type_or_throw_except( + params["convergence"], 1, float, "Invalid parameter 'convergence'") + utils.check_type_or_throw_except( + params["relaxation"], 1, float, "Invalid parameter 'relaxation'") + utils.check_type_or_throw_except( + params["ext_field"], 3, float, "Invalid parameter 'ext_field'") + utils.check_type_or_throw_except( + params["max_iterations"], 1, int, "Invalid parameter 'max_iterations'") + utils.check_type_or_throw_except( + params["eps_out"], 1, float, "Invalid parameter 'eps_out'") + + n_icc = params["n_icc"] + if n_icc <= 0: + raise ValueError("Parameter 'n_icc' must be >= 1") + + if n_icc: + if np.shape(params["normals"]) != (n_icc, 3): + raise ValueError("Parameter 'normals' has incorrect shape") + utils.check_array_type_or_throw_except( + np.reshape(params["normals"], (-1,)), 3 * n_icc, float, + "Parameter 'normals' has incorrect type") + + if "sigmas" not in params: + params["sigmas"] = np.zeros(n_icc) + + for key in ("areas", "sigmas", "epsilons"): + if np.shape(params[key]) != (n_icc,): + raise ValueError(f"Parameter '{key}' has incorrect shape") + utils.check_array_type_or_throw_except( + np.reshape(params[key], (-1,)), n_icc, float, + f"Parameter '{key}' has incorrect type")
+ +
[docs] def valid_keys(self): + return {"n_icc", "convergence", "relaxation", "ext_field", + "max_iterations", "first_id", "eps_out", "normals", + "areas", "sigmas", "epsilons", "check_neutrality"}
+ +
[docs] def required_keys(self): + return {"n_icc", "normals", "areas", "epsilons"}
+ +
[docs] def default_params(self): + return {"convergence": 1e-3, + "relaxation": 0.7, + "ext_field": [0., 0., 0.], + "max_iterations": 100, + "first_id": 0, + "eps_out": 1, + "check_neutrality": True}
+ +
[docs] def last_iterations(self): + """ + Number of iterations needed in last relaxation to + reach the convergence criterion. + + Returns + ------- + iterations : :obj:`int` + Number of iterations + + """ + return self.citeration
+
+ +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/doc4.2.2/_modules/espressomd/electrostatics.html b/doc4.2.2/_modules/espressomd/electrostatics.html new file mode 100644 index 0000000000..322671a830 --- /dev/null +++ b/doc4.2.2/_modules/espressomd/electrostatics.html @@ -0,0 +1,626 @@ + + + + + + + + espressomd.electrostatics — ESPResSo 4.2.2 documentation + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Source code for espressomd.electrostatics

+#
+# Copyright (C) 2013-2022 The ESPResSo project
+#
+# This file is part of ESPResSo.
+#
+# ESPResSo is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# ESPResSo is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+from . import utils
+from .script_interface import ScriptInterfaceHelper, script_interface_register
+from .__init__ import has_features
+
+
+
[docs]class ElectrostaticInteraction(ScriptInterfaceHelper): + """ + Common interface for electrostatics solvers. + + Parameters + ---------- + prefactor : :obj:`float` + Electrostatics prefactor :math:`\\frac{1}{4\\pi\\varepsilon_0\\varepsilon_r}` + + """ + _so_creation_policy = "GLOBAL" + + def __init__(self, **kwargs): + self._check_required_features() + + if 'sip' not in kwargs: + params = self.default_params() + params.update(kwargs) + self.validate_params(params) + super().__init__(**params) + else: + super().__init__(**kwargs) + + def _check_required_features(self): + if not has_features("ELECTROSTATICS"): + raise NotImplementedError("Feature ELECTROSTATICS not compiled in") + +
[docs] def validate_params(self, params): + """Check validity of given parameters. + """ + utils.check_type_or_throw_except( + params["prefactor"], 1, float, "prefactor should be a double")
+ +
[docs] def default_params(self): + raise NotImplementedError("Derived classes must implement this method")
+ +
[docs] def valid_keys(self): + raise NotImplementedError("Derived classes must implement this method")
+ +
[docs] def required_keys(self): + raise NotImplementedError("Derived classes must implement this method")
+ + def _activate(self): + self.call_method("check_charge_neutrality") + self.call_method("activate") + utils.handle_errors("Coulomb actor activation failed") + + def _deactivate(self): + self.call_method("deactivate") + utils.handle_errors("Coulomb actor deactivation failed")
+ + +
[docs]@script_interface_register +class DH(ElectrostaticInteraction): + """ + Electrostatics solver based on the Debye-Hueckel framework. + See :ref:`Debye-Hückel potential` for more details. + + Parameters + ---------- + prefactor : :obj:`float` + Electrostatics prefactor (see :eq:`coulomb_prefactor`). + kappa : :obj:`float` + Inverse Debye screening length. + r_cut : :obj:`float` + Cutoff radius for this interaction. + + """ + _so_name = "Coulomb::DebyeHueckel" + _so_creation_policy = "GLOBAL" + +
[docs] def valid_keys(self): + return {"prefactor", "kappa", "r_cut", "check_neutrality"}
+ +
[docs] def required_keys(self): + return {"prefactor", "kappa", "r_cut"}
+ +
[docs] def default_params(self): + return {"check_neutrality": True}
+ + +
[docs]@script_interface_register +class ReactionField(ElectrostaticInteraction): + """ + Electrostatics solver based on the Reaction Field framework. + See :ref:`Reaction Field method` for more details. + + Parameters + ---------- + prefactor : :obj:`float` + Electrostatics prefactor (see :eq:`coulomb_prefactor`). + kappa : :obj:`float` + Inverse Debye screening length. + epsilon1 : :obj:`float` + interior dielectric constant + epsilon2 : :obj:`float` + exterior dielectric constant + r_cut : :obj:`float` + Cutoff radius for this interaction. + + """ + _so_name = "Coulomb::ReactionField" + _so_creation_policy = "GLOBAL" + +
[docs] def valid_keys(self): + return {"prefactor", "kappa", "epsilon1", "epsilon2", "r_cut", + "check_neutrality"}
+ +
[docs] def required_keys(self): + return {"prefactor", "kappa", "epsilon1", "epsilon2", "r_cut"}
+ +
[docs] def default_params(self): + return {"check_neutrality": True}
+ + +class _P3MBase(ElectrostaticInteraction): + def valid_keys(self): + return {"mesh", "cao", "accuracy", "epsilon", "alpha", "r_cut", + "prefactor", "tune", "check_neutrality", "timings", + "verbose", "mesh_off"} + + def required_keys(self): + return {"prefactor", "accuracy"} + + def default_params(self): + return {"cao": -1, + "r_cut": -1., + "alpha": -1., + "mesh": [-1, -1, -1], + "epsilon": 0., + "mesh_off": [-1., -1., -1.], + "prefactor": 0., + "check_neutrality": True, + "tune": True, + "timings": 10, + "verbose": True} + + def validate_params(self, params): + super().validate_params(params) + + if utils.is_valid_type(params["mesh"], int): + params["mesh"] = 3 * [params["mesh"]] + utils.check_type_or_throw_except(params["mesh"], 3, int, + "P3M mesh has to be an integer or integer list of length 3") + if (params["mesh"][0] % 2 != 0 and params["mesh"][0] != -1) or \ + (params["mesh"][1] % 2 != 0 and params["mesh"][1] != -1) or \ + (params["mesh"][2] % 2 != 0 and params["mesh"][2] != -1): + raise ValueError( + "P3M requires an even number of mesh points in all directions") + + if params["epsilon"] == "metallic": + params["epsilon"] = 0.0 + + utils.check_type_or_throw_except( + params["epsilon"], 1, float, + "epsilon should be a double or 'metallic'") + + utils.check_type_or_throw_except( + params["mesh_off"], 3, float, + "mesh_off should be a (3,) array_like of values between 0 and 1") + + if not utils.is_valid_type(params["timings"], int): + raise TypeError("P3M timings has to be an integer") + if params["timings"] <= 0: + raise ValueError("P3M timings must be > 0") + if not utils.is_valid_type(params["tune"], bool): + raise TypeError("P3M tune has to be a boolean") + + +
[docs]@script_interface_register +class P3M(_P3MBase): + """ + P3M electrostatics solver. + + Particle--Particle--Particle--Mesh (P3M) is a Fourier-based Ewald + summation method to calculate potentials in N-body simulation. + See :ref:`Coulomb P3M` for more details. + + Parameters + ---------- + prefactor : :obj:`float` + Electrostatics prefactor (see :eq:`coulomb_prefactor`). + accuracy : :obj:`float` + P3M tunes its parameters to provide this target accuracy. + alpha : :obj:`float`, optional + The Ewald parameter. + cao : :obj:`float`, optional + The charge-assignment order, an integer between 1 and 7. + epsilon : :obj:`float` or :obj:`str`, optional + A positive number for the dielectric constant of the + surrounding medium. Use ``'metallic'`` to set the dielectric + constant of the surrounding medium to infinity (default). + mesh : :obj:`int` or (3,) array_like of :obj:`int`, optional + The number of mesh points in x, y and z direction. Use a single + value for cubic boxes. + mesh_off : (3,) array_like of :obj:`float`, optional + Mesh offset. + r_cut : :obj:`float`, optional + The real space cutoff. + tune : :obj:`bool`, optional + Used to activate/deactivate the tuning method on activation. + Defaults to ``True``. + timings : :obj:`int` + Number of force calculations during tuning. + verbose : :obj:`bool`, optional + If ``False``, disable log output during tuning. + check_neutrality : :obj:`bool`, optional + Raise a warning if the system is not electrically neutral when + set to ``True`` (default). + + """ + _so_name = "Coulomb::CoulombP3M" + _so_creation_policy = "GLOBAL" + + def _check_required_features(self): + if not has_features("P3M"): + raise NotImplementedError("Feature P3M not compiled in")
+ + +
[docs]@script_interface_register +class P3MGPU(_P3MBase): + """ + P3M electrostatics solver with GPU support. + + Particle--Particle--Particle--Mesh (P3M) is a Fourier-based Ewald + summation method to calculate potentials in N-body simulation. + See :ref:`Coulomb P3M on GPU` for more details. + + Parameters + ---------- + prefactor : :obj:`float` + Electrostatics prefactor (see :eq:`coulomb_prefactor`). + accuracy : :obj:`float` + P3M tunes its parameters to provide this target accuracy. + alpha : :obj:`float`, optional + The Ewald parameter. + cao : :obj:`float`, optional + The charge-assignment order, an integer between 0 and 7. + epsilon : :obj:`float` or :obj:`str`, optional + A positive number for the dielectric constant of the + surrounding medium. Use ``'metallic'`` to set the dielectric + constant of the surrounding medium to infinity (default). + mesh : :obj:`int` or (3,) array_like of :obj:`int`, optional + The number of mesh points in x, y and z direction. Use a single + value for cubic boxes. + mesh_off : (3,) array_like of :obj:`float`, optional + Mesh offset. + r_cut : :obj:`float`, optional + The real space cutoff + tune : :obj:`bool`, optional + Used to activate/deactivate the tuning method on activation. + Defaults to ``True``. + timings : :obj:`int` + Number of force calculations during tuning. + verbose : :obj:`bool`, optional + If ``False``, disable log output during tuning. + check_neutrality : :obj:`bool`, optional + Raise a warning if the system is not electrically neutral when + set to ``True`` (default). + + """ + _so_name = "Coulomb::CoulombP3MGPU" + _so_creation_policy = "GLOBAL" + + def _check_required_features(self): + if not has_features("P3M"): + raise NotImplementedError("Feature P3M not compiled in") + if not has_features("CUDA"): + raise NotImplementedError("Feature CUDA not compiled in")
+ + +
[docs]@script_interface_register +class ELC(ElectrostaticInteraction): + """ + Electrostatics solver for systems with two periodic dimensions. + See :ref:`Electrostatic Layer Correction (ELC)` for more details. + + Parameters + ---------- + actor : :obj:`P3M`, required + Base P3M actor. + gap_size : :obj:`float`, required + The gap size gives the height :math:`h` of the empty region between + the system box and the neighboring artificial images. |es| checks + that the gap is empty and will throw an error if it isn't. Therefore + you should really make sure that the gap region is empty (e.g. + with wall constraints). + maxPWerror : :obj:`float`, required + The maximal pairwise error sets the least upper bound (LUB) error + of the force between any two charges without prefactors (see the + papers). The algorithm tries to find parameters to meet this LUB + requirements or will throw an error if there are none. + delta_mid_top : :obj:`float`, optional + Dielectric contrast :math:`\\Delta_t` between the upper boundary + and the simulation box. Value between -1 and +1 (inclusive). + delta_mid_bottom : :obj:`float`, optional + Dielectric contrast :math:`\\Delta_b` between the lower boundary + and the simulation box. Value between -1 and +1 (inclusive). + const_pot : :obj:`bool`, optional + Activate a constant electric potential between the top and bottom + of the simulation box. + pot_diff : :obj:`float`, optional + If ``const_pot`` is enabled, this parameter controls the applied + voltage between the boundaries of the simulation box in the + *z*-direction (at :math:`z = 0` and :math:`z = L_z - h`). + neutralize : :obj:`bool`, optional + By default, *ELC* just as P3M adds a homogeneous neutralizing + background to the system in case of a net charge. However, unlike + in three dimensions, this background adds a parabolic potential + across the slab :cite:`ballenegger09a`. Therefore, under normal + circumstances, you will probably want to disable the neutralization + for non-neutral systems. This corresponds then to a formal + regularization of the forces and energies :cite:`ballenegger09a`. + Also, if you add neutralizing walls explicitly as constraints, you + have to disable the neutralization. When using a dielectric + contrast or full metallic walls (``delta_mid_top != 0`` or + ``delta_mid_bot != 0`` or ``const_pot=True``), ``neutralize`` is + overwritten and switched off internally. Note that the special + case of non-neutral systems with a *non-metallic* dielectric jump + (e.g. ``delta_mid_top`` or ``delta_mid_bot`` in ``]-1,1[``) is not + covered by the algorithm and will throw an error. + far_cut : :obj:`float`, optional + Cutoff radius, use with care, intended for testing purposes. When + setting the cutoff directly, the maximal pairwise error is ignored. + """ + _so_name = "Coulomb::ElectrostaticLayerCorrection" + _so_creation_policy = "GLOBAL" + + def _check_required_features(self): + if not has_features("P3M"): + raise NotImplementedError("Feature P3M not compiled in") + +
[docs] def validate_params(self, params): + utils.check_type_or_throw_except( + params["maxPWerror"], 1, float, "maxPWerror has to be a float") + utils.check_type_or_throw_except( + params["gap_size"], 1, float, "gap_size has to be a float") + utils.check_type_or_throw_except( + params["far_cut"], 1, float, "far_cut has to be a float") + utils.check_type_or_throw_except( + params["neutralize"], 1, bool, "neutralize has to be a bool")
+ +
[docs] def valid_keys(self): + return {"actor", "maxPWerror", "gap_size", "far_cut", + "neutralize", "delta_mid_top", "delta_mid_bot", + "const_pot", "pot_diff", "check_neutrality"}
+ +
[docs] def required_keys(self): + return {"actor", "maxPWerror", "gap_size"}
+ +
[docs] def default_params(self): + return {"far_cut": -1., + "delta_mid_top": 0., + "delta_mid_bot": 0., + "const_pot": False, + "pot_diff": 0., + "neutralize": True, + "check_neutrality": True}
+ + +
[docs]@script_interface_register +class MMM1D(ElectrostaticInteraction): + """ + Electrostatics solver for systems with one periodic direction. + See :ref:`MMM1D` for more details. + + Parameters + ---------- + prefactor : :obj:`float` + Electrostatics prefactor (see :eq:`coulomb_prefactor`). + maxWPerror : :obj:`float` + Maximal pairwise error. + far_switch_radius : :obj:`float`, optional + Radius where near-field and far-field calculation are switched. + verbose : :obj:`bool`, optional + If ``False``, disable log output during tuning. + timings : :obj:`int`, optional + Number of force calculations during tuning. + check_neutrality : :obj:`bool`, optional + Raise a warning if the system is not electrically neutral when + set to ``True`` (default). + + """ + _so_name = "Coulomb::CoulombMMM1D" + _so_creation_policy = "GLOBAL" + +
[docs] def validate_params(self, params): + default_params = self.default_params() + if params["prefactor"] <= 0: + raise ValueError("prefactor should be a positive float") + if params["maxPWerror"] < 0 and params["maxPWerror"] != default_params["maxPWerror"]: + raise ValueError("maxPWerror should be a positive double") + if params["far_switch_radius"] < 0 and params["far_switch_radius"] != default_params["far_switch_radius"]: + raise ValueError("switch radius should be a positive double")
+ +
[docs] def default_params(self): + return {"far_switch_radius": -1., + "verbose": True, + "timings": 15, + "tune": True, + "check_neutrality": True}
+ +
[docs] def valid_keys(self): + return {"prefactor", "maxPWerror", "far_switch_radius", + "verbose", "timings", "tune", "check_neutrality"}
+ +
[docs] def required_keys(self): + return {"prefactor", "maxPWerror"}
+ + +
[docs]@script_interface_register +class MMM1DGPU(ElectrostaticInteraction): + """ + Electrostatics solver with GPU support for systems with one periodic + direction. See :ref:`MMM1D on GPU` for more details. + + Parameters + ---------- + prefactor : :obj:`float` + Electrostatics prefactor (see :eq:`coulomb_prefactor`). + maxWPerror : :obj:`float` + Maximal pairwise error. + far_switch_radius : :obj:`float`, optional + Radius where near-field and far-field calculation are switched + bessel_cutoff : :obj:`int`, optional + timings : :obj:`int`, optional + Number of force calculations during tuning. + check_neutrality : :obj:`bool`, optional + Raise a warning if the system is not electrically neutral when + set to ``True`` (default). + """ + _so_name = "Coulomb::CoulombMMM1DGpu" + _so_creation_policy = "GLOBAL" + + def _check_required_features(self): + if not has_features("MMM1D_GPU"): + raise NotImplementedError("Feature MMM1D_GPU not compiled in") + +
[docs] def validate_params(self, params): + default_params = self.default_params() + if params["prefactor"] <= 0: + raise ValueError("prefactor should be a positive float") + if params["maxPWerror"] < 0 and params["maxPWerror"] != default_params["maxPWerror"]: + raise ValueError("maxPWerror should be a positive double") + if params["far_switch_radius"] < 0 and params["far_switch_radius"] != default_params["far_switch_radius"]: + raise ValueError("switch radius should be a positive double") + if params["bessel_cutoff"] < 0 and params["bessel_cutoff"] != default_params["bessel_cutoff"]: + raise ValueError("bessel_cutoff should be a positive integer")
+ +
[docs] def default_params(self): + return {"far_switch_radius": -1., + "bessel_cutoff": -1, + "tune": True, + "check_neutrality": True}
+ +
[docs] def valid_keys(self): + return {"prefactor", "maxPWerror", "far_switch_radius", + "bessel_cutoff", "tune", "check_neutrality"}
+ +
[docs] def required_keys(self): + return {"prefactor", "maxPWerror"}
+ + +
[docs]@script_interface_register +class Scafacos(ElectrostaticInteraction): + + """ + Calculate the Coulomb interaction using the ScaFaCoS library. + See :ref:`ScaFaCoS electrostatics` for more details. + + Parameters + ---------- + prefactor : :obj:`float` + Coulomb prefactor as defined in :eq:`coulomb_prefactor`. + method_name : :obj:`str` + Name of the ScaFaCoS method to use. + method_params : :obj:`dict` + Dictionary containing the method-specific parameters. + + Methods + ------- + get_available_methods() + List long-range methods available in the ScaFaCoS library. + + set_near_field_delegation() + Choose whether to delegate short-range calculation to ESPResSo + (this is the default when the method supports it) or ScaFaCos. + + Parameters + ---------- + delegate : :obj:`bool` + Delegate to ESPResSo if ``True`` and the method supports it. + + get_near_field_delegation() + Find whether the short-range calculation is delegated to ESPResSo + (this is the default when the method supports it) or ScaFaCos. + + Returns + ------- + delegate : :obj:`bool` + Delegate to ESPResSo if ``True`` and the method supports it, + ``False`` if delegated to ScaFaCoS or the method doesn't have a + short-range kernel. + + """ + _so_name = "Coulomb::CoulombScafacos" + _so_creation_policy = "GLOBAL" + _so_bind_methods = ElectrostaticInteraction._so_bind_methods + \ + ("get_available_methods", + "get_near_field_delegation", + "set_near_field_delegation") + + def _check_required_features(self): + if not has_features("ELECTROSTATICS"): + raise NotImplementedError("Feature ELECTROSTATICS not compiled in") + if not has_features("SCAFACOS"): + raise NotImplementedError("Feature SCAFACOS not compiled in") + +
[docs] def validate_params(self, params): + pass
+ +
[docs] def default_params(self): + return {"check_neutrality": True}
+ +
[docs] def valid_keys(self): + return {"method_name", "method_params", + "prefactor", "check_neutrality"}
+ +
[docs] def required_keys(self): + return {"method_name", "method_params", "prefactor"}
+
+ +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/doc4.2.2/_modules/espressomd/highlander.html b/doc4.2.2/_modules/espressomd/highlander.html new file mode 100644 index 0000000000..e90df77813 --- /dev/null +++ b/doc4.2.2/_modules/espressomd/highlander.html @@ -0,0 +1,143 @@ + + + + + + + + espressomd.highlander — ESPResSo 4.2.2 documentation + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Source code for espressomd.highlander

+#
+# Copyright (C) 2013-2022 The ESPResSo project
+#
+# This file is part of ESPResSo.
+#
+# ESPResSo is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# ESPResSo is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+import functools
+
+
+
[docs]class ThereCanOnlyBeOne(BaseException): + + def __init__(self, cls): + self._cls = cls + + def __str__(self): + return f"There can only be one instance of '{self._cls}' at any time."
+ + +
[docs]def highlander(klass): + klass.highlander_created = False + + def cls_init(self, *args, **kwargs): # pylint: disable=unused-argument + "__init__ method by the highlander decorator." + if self.__class__.highlander_created: + raise ThereCanOnlyBeOne(self.__class__) + self.__class__.highlander_created = True + + def cls_init_call_orig(self, *args, **kwargs): + if self.__class__.highlander_created: + raise ThereCanOnlyBeOne(self.__class__) + self.__class__.highlander_created = True + self.__class__.__init_orig__(self, *args, **kwargs) + + # override the __init__ method of the class to store the bool + # "highlander_created" + if hasattr(klass, '__init__'): + klass.__init_orig__ = klass.__init__ + klass.__init__ = cls_init_call_orig + functools.update_wrapper(cls_init_call_orig, klass.__init_orig__) + else: + klass.__init__ = cls_init + + # override the __del__ method of the class + def cls_del(self): + "__del__ method by the highlander decorator." + self.__class__.highlander_created = False + + def cls_del_call_orig(self): + cls_del(self) + self.__class__.__del_orig__(self) + + if hasattr(klass, '__del__'): + klass.__del_orig__ = klass.__del__ + klass.__del__ = cls_del_call_orig + functools.update_wrapper(cls_del_call_orig, klass.__del_orig__) + else: + klass.__del__ = cls_del + + return klass
+
+ +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/doc4.2.2/_modules/espressomd/io/mpiio.html b/doc4.2.2/_modules/espressomd/io/mpiio.html new file mode 100644 index 0000000000..5816ff6d46 --- /dev/null +++ b/doc4.2.2/_modules/espressomd/io/mpiio.html @@ -0,0 +1,168 @@ + + + + + + + + espressomd.io.mpiio — ESPResSo 4.2.2 documentation + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Source code for espressomd.io.mpiio

+# Copyright (C) 2010-2022 The ESPResSo project
+#
+# This file is part of ESPResSo.
+#
+# ESPResSo is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# ESPResSo is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+from ..script_interface import ScriptInterfaceHelper, script_interface_register
+
+
+
[docs]@script_interface_register +class Mpiio(ScriptInterfaceHelper): + + """MPI-IO object. + + Used to output particle data using MPI-IO to binary files. + """ + _so_name = "ScriptInterface::MPIIO::MPIIOScript" + _so_creation_policy = "GLOBAL" + +
[docs] def write(self, prefix=None, positions=False, velocities=False, + types=False, bonds=False): + """MPI-IO write. + + Outputs binary data using MPI-IO to several files starting with prefix. + Suffixes are: + + - head: Information about fields that are dumped, + - pref: Information about processes: 1 int per process, + - id: Particle ids: 1 int per particle, + - pos: Position information (if dumped): 3 doubles per particle, + - vel: Velocity information (if dumped): 3 doubles per particle, + - typ: Type information (if dumped): 1 int per particle, + - bond: Bond information (if dumped): variable amount of data, + - boff: Bond offset information (if bonds are dumped): 1 int per particle. + + .. note:: + Do not read the files on a machine with a different architecture! + + Parameters + ---------- + prefix : :obj:`str` + Common prefix for the filenames. + positions : :obj:`bool`, optional + Indicates if positions should be dumped. + velocities : :obj:`bool`, optional + Indicates if velocities should be dumped. + types : :obj:`bool`, optional + Indicates if types should be dumped. + bonds : :obj:`bool`, optional + Indicates if bonds should be dumped. + + Raises + ------ + ValueError + If no prefix was given or none of the output fields are chosen. + """ + + if prefix is None: + raise ValueError( + "Need to supply output prefix via the 'prefix' argument.") + if not positions and not velocities and not types and not bonds: + raise ValueError("No output fields chosen.") + + self.call_method( + "write", prefix=prefix, pos=positions, vel=velocities, typ=types, bond=bonds)
+ +
[docs] def read(self, prefix=None, positions=False, velocities=False, + types=False, bonds=False): + """MPI-IO read. + + This function reads data dumped by :meth`write`. See the :meth`write` + documentation for details. + + .. note:: + The files must be read on the same number of processes that wrote + the data. The data must be read on a machine with the same + architecture (otherwise, this might silently fail). + """ + if prefix is None: + raise ValueError( + "Need to supply output prefix via the 'prefix' argument.") + if not positions and not velocities and not types and not bonds: + raise ValueError("No output fields chosen.") + + self.call_method( + "read", prefix=prefix, pos=positions, vel=velocities, typ=types, bond=bonds)
+
+ +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/doc4.2.2/_modules/espressomd/io/writer/h5md.html b/doc4.2.2/_modules/espressomd/io/writer/h5md.html new file mode 100644 index 0000000000..240cf7eedd --- /dev/null +++ b/doc4.2.2/_modules/espressomd/io/writer/h5md.html @@ -0,0 +1,235 @@ + + + + + + + + espressomd.io.writer.h5md — ESPResSo 4.2.2 documentation + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Source code for espressomd.io.writer.h5md

+# Copyright (C) 2010-2022 The ESPResSo project
+#
+# This file is part of ESPResSo.
+#
+# ESPResSo is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# ESPResSo is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+import sys
+import pathlib
+
+from ...script_interface import script_interface_register, ScriptInterfaceHelper  # pylint: disable=import
+from ...__init__ import assert_features
+from ... import utils
+
+
+
[docs]class UnitSystem: + """ + Data class for writing H5MD trajectories with + `physical units <https://nongnu.org/h5md/modules/units.html>`__. + There are four settable units: 'mass', 'length', 'time', 'charge'. + Units should be written as strings following the specifications defined + `here <https://nongnu.org/h5md/modules/units.html#unit-string>`__, + e.g. ``UnitSystem(time='ps', mass='u', length='nm', charge='e')``. + """ + + def __init__(self, **kwargs): + self.mass = '' + self.time = '' + self.length = '' + self.charge = '' + for key, value in kwargs.items(): + assert hasattr(self, key), f'unknown dimension {key}' + setattr(self, key, value or '') + + if self.length and self.mass and self.time: + self.force = f'{self.length} {self.mass} {self.time}-2' + else: + self.force = '' + if self.length and self.time: + self.velocity = f'{self.length} {self.time}-1' + else: + self.velocity = ''
+ + +
[docs]@script_interface_register +class H5md(ScriptInterfaceHelper): + + """ + H5md file object. + + .. note:: + Bonds will be written to the file if they exist. + The pypresso script will be written in the metadata. + + Parameters + ---------- + file_path : :obj:`str` + Path to the trajectory file, or an existing file to append data to + (it must have the same specifications). + unit_system : :obj:`UnitSystem`, optional + Physical units for the data. + fields : :obj:`set` or :obj:`str`, optional + List of fields to write to the trajectory file. Defaults to ``'all'``. + See :meth:`~espressomd.io.writer.h5md.H5md.valid_fields()` for the + list of valid fields. This list defines the H5MD specifications. + If the file in ``file_path`` already exists but has different + specifications, an exception is raised. + + Methods + ------- + get_params() + Get the parameters from the script interface. + + valid_fields() + Get the list of valid fields. + + write() + Call the H5md write method. + + flush() + Call the H5md flush method. + + close() + Close the H5md file. + + Attributes + ---------- + file_path: :obj:`str` + Path to the trajectory file. + script_path: :obj:`str` + Path to the pypresso script, or empty string for interactive sessions. + fields: :obj:`list` + List of fields to write to the trajectory file. + mass_unit: :obj:`str` + length_unit: :obj:`str` + time_unit: :obj:`str` + force_unit: :obj:`str` + velocity_unit: :obj:`str` + charge_unit: :obj:`str` + + """ + _so_name = "ScriptInterface::Writer::H5md" + _so_creation_policy = "GLOBAL" + _so_bind_methods = ("valid_fields", "write", "flush", "close") + + def __init__(self, **kwargs): + assert_features("H5MD") + + if "sip" in kwargs: + super().__init__(**kwargs) + return + + params = self.default_params() + params.update(kwargs) + unit_system = params["unit_system"] + fields = params["fields"] + fields = [fields] if isinstance(fields, str) else list(fields) + params["fields"] = fields + self.validate_params(params) + script_path = "" + if sys.argv and sys.argv[0]: + script_path = str(pathlib.Path(sys.argv[0]).resolve()) + file_path = str(pathlib.Path(params["file_path"]).resolve()) + super().__init__( + file_path=file_path, + script_path=script_path, + fields=fields, + mass_unit=unit_system.mass, + length_unit=unit_system.length, + time_unit=unit_system.time, + force_unit=unit_system.force, + velocity_unit=unit_system.velocity, + charge_unit=unit_system.charge + ) + +
[docs] def default_params(self): + return {"unit_system": UnitSystem(), "fields": "all"}
+ +
[docs] def required_keys(self): + return {"file_path"}
+ +
[docs] def valid_keys(self): + return {"file_path", "unit_system", "fields"}
+ +
[docs] def validate_params(self, params): + """Check validity of given parameters. + """ + utils.check_type_or_throw_except( + params["file_path"], 1, str, "'file_path' should be a string") + for item in params["fields"]: + utils.check_type_or_throw_except( + item, 1, str, "'fields' should be a string or a list of strings")
+
+ +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/doc4.2.2/_modules/espressomd/io/writer/vtf.html b/doc4.2.2/_modules/espressomd/io/writer/vtf.html new file mode 100644 index 0000000000..4b07a1c02f --- /dev/null +++ b/doc4.2.2/_modules/espressomd/io/writer/vtf.html @@ -0,0 +1,168 @@ + + + + + + + + espressomd.io.writer.vtf — ESPResSo 4.2.2 documentation + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Source code for espressomd.io.writer.vtf

+# Copyright (C) 2010-2022 The ESPResSo project
+#
+# This file is part of ESPResSo.
+#
+# ESPResSo is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# ESPResSo is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+
+
[docs]def vtf_pid_map(system, types='all'): + """ + Generates a VTF particle index map to ESPResSo ``id``. + This fills the gap for particle ID's as required by VMD. + + Parameters + ---------- + system: :obj:`espressomd.system.System` + types : :obj:`str` + Specifies the particle types. The id mapping depends on which + particles are going to be printed. This should be the same as + the one used in :func:`writevsf()` and :func:`writevcf()`. + Returns + ------- + dict: + A dictionary where the values are the VTF indices and the keys + are the ESPresSo particle ``id``. + """ + + if not hasattr(types, '__iter__'): + types = [types] + if types == "all": + types = [types] + id_to_write = [] + for p in system.part: + for t in types: + if t in (p.type, "all"): + id_to_write.append(p.id) + return dict(zip(id_to_write, range(len(id_to_write))))
+ + +
[docs]def writevsf(system, fp, types='all'): + """ + writes a VST (VTF Structure Format) to a file. + This can be used to write the header of a VTF file. + + Parameters + ---------- + system: :obj:`espressomd.system.System` + types : :obj:`str` + Specifies the particle types. The string 'all' will write all particles + fp : file + File pointer to write to. + + """ + + vtf_index = vtf_pid_map(system, types) + fp.write(f"unitcell {' '.join(map(str, system.box_l))}\n") + + for pid, vtf_id, in vtf_index.items(): + partcl = system.part.by_id(pid) + fp.write( + f"atom {vtf_id} radius 1 name {partcl.type} type {partcl.type} \n") + for pid, vtf_id, in vtf_index.items(): + for b in system.part.by_id(pid).bonds: + if system.part.by_id(b[1]).id in vtf_index: + fp.write( + f"bond {vtf_id}:{vtf_index[system.part.by_id(b[1]).id]}\n")
+ + +
[docs]def writevcf(system, fp, types='all'): + """ + writes a VCF (VTF Coordinate Format) to a file. + This can be used to write a timestep to a VTF file. + + Parameters + ---------- + system: :obj:`espressomd.system.System` + types : :obj:`str` + Specifies the particle types. The string 'all' will write all particles + fp : file + File pointer to write to. + + """ + vtf_index = vtf_pid_map(system, types) + fp.write("\ntimestep indexed\n") + for pid, vtf_id, in vtf_index.items(): + fp.write(f"{vtf_id} {' '.join(map(str, system.part.by_id(pid).pos))}\n")
+
+ +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/doc4.2.2/_modules/espressomd/lbboundaries.html b/doc4.2.2/_modules/espressomd/lbboundaries.html new file mode 100644 index 0000000000..984798593b --- /dev/null +++ b/doc4.2.2/_modules/espressomd/lbboundaries.html @@ -0,0 +1,176 @@ + + + + + + + + espressomd.lbboundaries — ESPResSo 4.2.2 documentation + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Source code for espressomd.lbboundaries

+# Copyright (C) 2010-2022 The ESPResSo project
+#
+# This file is part of ESPResSo.
+#
+# ESPResSo is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# ESPResSo is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+from .script_interface import ScriptObjectList, ScriptInterfaceHelper, script_interface_register
+from .__init__ import has_features
+
+
+if any(has_features(i) for i in ["LB_BOUNDARIES", "LB_BOUNDARIES_GPU"]):
+
[docs] @script_interface_register + class LBBoundaries(ScriptObjectList): + + """ + Creates a set of lattice-Boltzmann boundaries. + + Methods + ------- + size() + Get the number of active boundaries. + empty() + Return ``True`` if there are not active boundaries. + clear() + Clear the list of boundaries. + + """ + + _so_name = "LBBoundaries::LBBoundaries" + _so_bind_methods = ("size", "empty", "clear") + +
[docs] def add(self, *args, **kwargs): + """ + Adds a boundary to the set of boundaries. + Either pass a valid boundary as argument, + or a valid set of parameters to create a boundary. + + """ + + if len(args) == 1: + if isinstance(args[0], LBBoundary): + lbboundary = args[0] + else: + raise TypeError( + "Either a LBBoundary object or key-value pairs for the parameters of a LBBoundary object need to be passed.") + else: + lbboundary = LBBoundary(**kwargs) + self.call_method("add", object=lbboundary) + return lbboundary
+ +
[docs] def remove(self, lbboundary): + """ + Removes a boundary from the set. + + Parameters + ---------- + lbboundary : :obj:`LBBoundary` + The boundary to be removed from the set. + + """ + + self.call_method("remove", object=lbboundary)
+ +
[docs] @script_interface_register + class LBBoundary(ScriptInterfaceHelper): + + """ + Creates a LB boundary from a shape. + + The fluid velocity is limited to :math:`v_{\\mathrm{max}} = 0.20` + (see *quasi-incompressible limit* in :cite:`kruger17a`, + chapter 7, page 272), which corresponds to Mach 0.35. + + The relative error in the fluid density between a compressible fluid + and an incompressible fluid at Mach 0.30 is less than 5% (see + *constant density assumption* in :cite:`kundu01a` chapter 16, page + 663). Since the speed of sound is :math:`c_s = 1 / \\sqrt{3}` in LB + velocity units in a D3Q19 lattice, the velocity limit at Mach 0.30 + is :math:`v_{\\mathrm{max}} = 0.30 / \\sqrt{3} \\approx 0.17`. + At Mach 0.35 the relative error is around 6% and + :math:`v_{\\mathrm{max}} = 0.35 / \\sqrt{3} \\approx 0.20`. + + Parameters + ---------- + shape : :obj:`espressomd.shapes.Shape` + The shape from which to build the boundary. + velocity : (3,) array_like of :obj:`float`, optional + The boundary slip velocity. By default, a velocity of zero is used + (no-slip boundary condition). + + """ + + _so_name = "LBBoundaries::LBBoundary" + _so_bind_methods = ("get_force",)
+
+ +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/doc4.2.2/_modules/espressomd/lees_edwards.html b/doc4.2.2/_modules/espressomd/lees_edwards.html new file mode 100644 index 0000000000..c3977df92b --- /dev/null +++ b/doc4.2.2/_modules/espressomd/lees_edwards.html @@ -0,0 +1,173 @@ + + + + + + + + espressomd.lees_edwards — ESPResSo 4.2.2 documentation + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Source code for espressomd.lees_edwards

+#
+# Copyright (C) 2021-2022 The ESPResSo project
+#
+# This file is part of ESPResSo.
+#
+# ESPResSo is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# ESPResSo is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+from .script_interface import ScriptInterfaceHelper, script_interface_register
+
+
+
[docs]@script_interface_register +class LeesEdwards(ScriptInterfaceHelper): + + """ + Interface to the :ref:`Lees-Edwards boundary conditions`. + When writing H5MD files, the shear direction and shear plane normals + are written as integers instead of characters, with 0 = *x*-axis, + 1 = *y*-axis, 2 = *z*-axis. + + Attributes + ---------- + protocol : :obj:`object` + Lees--Edwards protocol. + shear_velocity: :obj:`float` + Current shear velocity. + pos_offset : :obj:`float` + Current position offset + shear_direction : :obj:`str`, {'x', 'y', 'z'} + Shear direction. + shear_plane_normal : :obj:`str`, {'x', 'y', 'z'} + Shear plane normal. + + Methods + ------- + set_boundary_conditions() + Set a protocol, the shear direction and shear normal. + + Parameters + ---------- + protocol : :obj:`object` + shear_direction : :obj:`str`, {'x', 'y', 'z'} + shear_plane_normal : :obj:`str`, {'x', 'y', 'z'} + + """ + + _so_name = "LeesEdwards::LeesEdwards" + _so_bind_methods = ("set_boundary_conditions",)
+ + +
[docs]@script_interface_register +class Off(ScriptInterfaceHelper): + + """Lees--Edwards protocol resulting in un-shifted boundaries.""" + _so_name = "LeesEdwards::Off"
+ + +
[docs]@script_interface_register +class LinearShear(ScriptInterfaceHelper): + + """Lees--Edwards protocol for linear shear. + + Parameters + ---------- + initial_pos_offset : :obj:`float` + Positional offset at the Lees--Edwards boundary at t=0. + shear_velocity : :obj:`float` + Shear velocity (velocity jump) across the Lees--Edwards boundary. + + """ + _so_name = "LeesEdwards::LinearShear"
+ + +
[docs]@script_interface_register +class OscillatoryShear(ScriptInterfaceHelper): + + """Lees--Edwards protocol for oscillatory shear. + + Parameters + ---------- + initial_pos_offset : :obj:`float` + Positional offset at the Lees--Edwards boundary at t=0. + amplitude : :obj:`float` + Maximum amplitude of the positional offset at the Lees--Edwards boundary. + omega : :obj:`float` + Radian frequency of the oscillation. + time_0 : :obj:`float` + Time offset of the oscillation. + + """ + _so_name = "LeesEdwards::OscillatoryShear"
+
+ +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/doc4.2.2/_modules/espressomd/magnetostatics.html b/doc4.2.2/_modules/espressomd/magnetostatics.html new file mode 100644 index 0000000000..a01e6c1410 --- /dev/null +++ b/doc4.2.2/_modules/espressomd/magnetostatics.html @@ -0,0 +1,463 @@ + + + + + + + + espressomd.magnetostatics — ESPResSo 4.2.2 documentation + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Source code for espressomd.magnetostatics

+#
+# Copyright (C) 2013-2022 The ESPResSo project
+#
+# This file is part of ESPResSo.
+#
+# ESPResSo is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# ESPResSo is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+from . import utils
+from .script_interface import ScriptInterfaceHelper, script_interface_register
+from .__init__ import has_features
+
+
+
[docs]class MagnetostaticInteraction(ScriptInterfaceHelper): + """ + Common interface for magnetostatics solvers. + + Parameters + ---------- + prefactor : :obj:`float` + Magnetostatics prefactor :math:`\\frac{\\mu_0\\mu}{4\\pi}` + + """ + _so_creation_policy = "GLOBAL" + + def __init__(self, **kwargs): + self._check_required_features() + + if 'sip' not in kwargs: + params = self.default_params() + params.update(kwargs) + self.validate_params(params) + super().__init__(**params) + else: + super().__init__(**kwargs) + + def _check_required_features(self): + if not has_features("DIPOLES"): + raise NotImplementedError("Feature DIPOLES not compiled in") + +
[docs] def validate_params(self, params): + """Check validity of given parameters. + """ + utils.check_type_or_throw_except( + params["prefactor"], 1, float, "prefactor should be a double")
+ +
[docs] def default_params(self): + raise NotImplementedError("Derived classes must implement this method")
+ +
[docs] def valid_keys(self): + raise NotImplementedError("Derived classes must implement this method")
+ +
[docs] def required_keys(self): + raise NotImplementedError("Derived classes must implement this method")
+ + def _activate(self): + self.call_method("activate") + utils.handle_errors("Dipolar actor activation failed") + + def _deactivate(self): + self.call_method("deactivate") + utils.handle_errors("Dipolar actor deactivation failed") + +
[docs] def get_magnetostatics_prefactor(self): + """ + Get the magnetostatics prefactor + + """ + return self.prefactor
+ + +
[docs]@script_interface_register +class DipolarP3M(MagnetostaticInteraction): + """ + Calculate magnetostatic interactions using the dipolar P3M method. + See :ref:`Dipolar P3M` for more details. + + Parameters + ---------- + prefactor : :obj:`float` + Magnetostatics prefactor (:math:`\\mu_0/(4\\pi)`) + accuracy : :obj:`float` + P3M tunes its parameters to provide this target accuracy. + alpha : :obj:`float` + Ewald parameter. + cao : :obj:`int` + Charge-assignment order, an integer between 1 and 7. + mesh : :obj:`int` or (3,) array_like of :obj:`int` + The number of mesh points in x, y and z direction. Use a single + value for cubic boxes. + mesh_off : (3,) array_like of :obj:`float`, optional + Mesh offset. + r_cut : :obj:`float` + Real space cutoff. + tune : :obj:`bool`, optional + Activate/deactivate the tuning method on activation + (default is ``True``, i.e., activated). + timings : :obj:`int` + Number of force calculations during tuning. + + """ + _so_name = "Dipoles::DipolarP3M" + + def _check_required_features(self): + if not has_features("DP3M"): + raise NotImplementedError("Feature DP3M not compiled in") + +
[docs] def validate_params(self, params): + """Check validity of parameters. + + """ + super().validate_params(params) + + if utils.is_valid_type(params["mesh"], int): + params["mesh"] = 3 * [params["mesh"]] + else: + utils.check_type_or_throw_except(params["mesh"], 3, int, + "DipolarP3M mesh has to be an integer or integer list of length 3") + + if params["epsilon"] == "metallic": + params["epsilon"] = 0.0 + + utils.check_type_or_throw_except( + params["epsilon"], 1, float, + "epsilon should be a double or 'metallic'") + + utils.check_type_or_throw_except(params["mesh_off"], 3, float, + "mesh_off should be a (3,) array_like of values between 0.0 and 1.0") + + if not utils.is_valid_type(params["timings"], int): + raise TypeError("DipolarP3M timings has to be an integer") + if params["timings"] <= 0: + raise ValueError("DipolarP3M timings must be > 0") + if not utils.is_valid_type(params["tune"], bool): + raise TypeError("DipolarP3M tune has to be a boolean")
+ +
[docs] def valid_keys(self): + return {"prefactor", "alpha_L", "r_cut_iL", "mesh", "mesh_off", + "cao", "accuracy", "epsilon", "cao_cut", "a", "ai", + "alpha", "r_cut", "cao3", "tune", "timings", "verbose"}
+ +
[docs] def required_keys(self): + return {"accuracy"}
+ +
[docs] def default_params(self): + return {"cao": -1, + "r_cut": -1, + "alpha": -1, + "accuracy": -1, + "mesh": [-1, -1, -1], + "epsilon": 0.0, + "mesh_off": [0.5, 0.5, 0.5], + "prefactor": 0., + "tune": True, + "timings": 10, + "verbose": True}
+ + +
[docs]@script_interface_register +class DipolarDirectSumCpu(MagnetostaticInteraction): + """ + Calculate magnetostatic interactions by direct summation over all pairs. + See :ref:`Dipolar direct sum` for more details. + + If the system has periodic boundaries, the minimum image convention is + applied in the respective directions. + + Parameters + ---------- + prefactor : :obj:`float` + Magnetostatics prefactor (:math:`\\mu_0/(4\\pi)`) + + """ + _so_name = "Dipoles::DipolarDirectSum" + +
[docs] def default_params(self): + return {}
+ +
[docs] def required_keys(self): + return set()
+ +
[docs] def valid_keys(self): + return {"prefactor"}
+ + +
[docs]@script_interface_register +class DipolarDirectSumWithReplicaCpu(MagnetostaticInteraction): + """ + Calculate magnetostatic interactions by direct summation over all pairs. + See :ref:`Dipolar direct sum` for more details. + + If the system has periodic boundaries, ``n_replica`` copies of the system are + taken into account in the respective directions. Spherical cutoff is applied. + + Parameters + ---------- + prefactor : :obj:`float` + Magnetostatics prefactor (:math:`\\mu_0/(4\\pi)`) + n_replica : :obj:`int` + Number of replicas to be taken into account at periodic boundaries. + + """ + _so_name = "Dipoles::DipolarDirectSumWithReplica" + +
[docs] def default_params(self): + return {}
+ +
[docs] def required_keys(self): + return {"n_replica"}
+ +
[docs] def valid_keys(self): + return {"prefactor", "n_replica"}
+ + +
[docs]@script_interface_register +class Scafacos(MagnetostaticInteraction): + + """ + Calculate the dipolar interaction using dipoles-capable methods + from the ScaFaCoS library. See :ref:`ScaFaCoS magnetostatics` for + more details. + + Parameters + ---------- + prefactor : :obj:`float` + Magnetostatics prefactor (:math:`\\mu_0/(4\\pi)`). + method_name : :obj:`str` + Name of the ScaFaCoS method to use. + method_params : :obj:`dict` + Dictionary with the key-value pairs of the method parameters as + defined in ScaFaCoS. Note that the values are cast to strings + to match ScaFaCoS' interface. + + Methods + ------- + get_available_methods() + List long-range methods available in the ScaFaCoS library. + + """ + _so_name = "Dipoles::DipolarScafacos" + _so_creation_policy = "GLOBAL" + _so_bind_methods = MagnetostaticInteraction._so_bind_methods + \ + ("get_available_methods", ) + + def _check_required_features(self): + if not has_features("DIPOLES"): + raise NotImplementedError("Feature DIPOLES not compiled in") + if not has_features("SCAFACOS_DIPOLES"): + raise NotImplementedError( + "Feature SCAFACOS_DIPOLES not compiled in") + +
[docs] def validate_params(self, params): + pass
+ +
[docs] def default_params(self): + return {}
+ +
[docs] def valid_keys(self): + return {"method_name", "method_params", "prefactor"}
+ +
[docs] def required_keys(self): + return {"method_name", "method_params", "prefactor"}
+ + +
[docs]@script_interface_register +class DipolarDirectSumGpu(MagnetostaticInteraction): + """ + Calculate magnetostatic interactions by direct summation over all + pairs. See :ref:`Dipolar direct sum` for more details. + + If the system has periodic boundaries, the minimum image convention + is applied in the respective directions. + + This is the GPU version of :class:`espressomd.magnetostatics.DipolarDirectSumCpu` + but uses floating point precision. + + Requires feature ``DIPOLAR_DIRECT_SUM``, which depends on + ``DIPOLES`` and ``CUDA``. + + Parameters + ---------- + prefactor : :obj:`float` + Magnetostatics prefactor (:math:`\\mu_0/(4\\pi)`) + + """ + _so_name = "Dipoles::DipolarDirectSumGpu" + _so_creation_policy = "GLOBAL" + + def _check_required_features(self): + if not has_features("DIPOLAR_DIRECT_SUM"): + raise NotImplementedError( + "Features CUDA and DIPOLES not compiled in") + +
[docs] def default_params(self): + return {}
+ +
[docs] def required_keys(self): + return set()
+ +
[docs] def valid_keys(self): + return {"prefactor"}
+ + +
[docs]@script_interface_register +class DipolarBarnesHutGpu(MagnetostaticInteraction): + + """ + Calculates magnetostatic interactions by direct summation over all + pairs. See :ref:`Barnes-Hut octree sum on GPU` for more details. + + TODO: If the system has periodic boundaries, the minimum image + convention is applied. + + Requires feature ``DIPOLAR_BARNES_HUT``, which depends on + ``DIPOLES`` and ``CUDA``. + + """ + _so_name = "Dipoles::DipolarBarnesHutGpu" + _so_creation_policy = "GLOBAL" + + def _check_required_features(self): + if not has_features("DIPOLAR_BARNES_HUT"): + raise NotImplementedError( + "Features CUDA and DIPOLES not compiled in") + +
[docs] def default_params(self): + return {"epssq": 100.0, "itolsq": 4.0}
+ +
[docs] def required_keys(self): + return set()
+ +
[docs] def valid_keys(self): + return {"prefactor", "epssq", "itolsq"}
+ + +
[docs]@script_interface_register +class DLC(MagnetostaticInteraction): + + """ + Electrostatics solver for systems with two periodic dimensions. + See :ref:`Dipolar Layer Correction (DLC)` for more details. + + Notes + ----- + At present, the empty gap (volume without any particles), is assumed to be + along the z-axis. As a reference for the DLC method, see :cite:`brodka04a`. + + Parameters + ---------- + gap_size : :obj:`float` + The gap size gives the height :math:`h` of the empty region between + the system box and the neighboring artificial images. |es| checks + that the gap is empty and will throw an error if it isn't. Therefore + you should really make sure that the gap region is empty (e.g. + with wall constraints). + maxPWerror : :obj:`float` + Maximal pairwise error of the potential and force. + far_cut : :obj:`float`, optional + Cutoff of the exponential sum. + + """ + _so_name = "Dipoles::DipolarLayerCorrection" + _so_creation_policy = "GLOBAL" + +
[docs] def validate_params(self, params): + utils.check_type_or_throw_except( + params["maxPWerror"], 1, float, "maxPWerror has to be a float") + utils.check_type_or_throw_except( + params["gap_size"], 1, float, "gap_size has to be a float") + utils.check_type_or_throw_except( + params["far_cut"], 1, float, "far_cut has to be a float")
+ +
[docs] def default_params(self): + return {"far_cut": -1.}
+ +
[docs] def valid_keys(self): + return {"actor", "maxPWerror", "gap_size", "far_cut"}
+ +
[docs] def required_keys(self): + return {"actor", "maxPWerror", "gap_size"}
+
+ +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/doc4.2.2/_modules/espressomd/math.html b/doc4.2.2/_modules/espressomd/math.html new file mode 100644 index 0000000000..5b2e3ee411 --- /dev/null +++ b/doc4.2.2/_modules/espressomd/math.html @@ -0,0 +1,113 @@ + + + + + + + + espressomd.math — ESPResSo 4.2.2 documentation + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Source code for espressomd.math

+# Copyright (C) 2010-2022 The ESPResSo project
+#
+# This file is part of ESPResSo.
+#
+# ESPResSo is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# ESPResSo is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+from .script_interface import ScriptInterfaceHelper, script_interface_register
+
+
+
[docs]@script_interface_register +class CylindricalTransformationParameters(ScriptInterfaceHelper): + """ + Class to hold and validate the parameters needed for a cylindrical transformation. + The three parameters are available as attributes but are read-only. + + Parameters + ---------- + center : (3,) array_like of :obj:`float`, default = [0, 0, 0] + Position of the origin of the cylindrical coordinate system. + axis : (3,) array_like of :obj:`float`, default = [0, 0, 1] + Orientation vector of the ``z``-axis of the cylindrical coordinate system. + orientation: (3,) array_like of :obj:`float`, default = [1, 0, 0] + The axis on which ``phi = 0``. + + Notes + ----- + If you provide no arguments, the defaults above are set. + If you provide only a ``center`` and an ``axis``, an ``orientation`` will be automatically generated that is orthogonal to ``axis``. + """ + _so_name = "CylindricalTransformationParameters"
+
+ +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/doc4.2.2/_modules/espressomd/observables.html b/doc4.2.2/_modules/espressomd/observables.html new file mode 100644 index 0000000000..92f1986e45 --- /dev/null +++ b/doc4.2.2/_modules/espressomd/observables.html @@ -0,0 +1,1160 @@ + + + + + + + + espressomd.observables — ESPResSo 4.2.2 documentation + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Source code for espressomd.observables

+# Copyright (C) 2010-2022 The ESPResSo project
+#
+# This file is part of ESPResSo.
+#
+# ESPResSo is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# ESPResSo is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+import itertools
+import numpy as np
+from .script_interface import ScriptInterfaceHelper, script_interface_register
+from .math import CylindricalTransformationParameters
+
+
+
[docs]@script_interface_register +class Observable(ScriptInterfaceHelper): + """ + Base class for all observables. + + Methods + ------- + shape() + Get the shape of the numpy array returned by the observable. + """ + _so_name = "Observables::Observable" + _so_bind_methods = ("shape",) + _so_creation_policy = "LOCAL" + +
[docs] def calculate(self): + return np.array(self.call_method("calculate")).reshape(self.shape())
+ + +
[docs]class ProfileObservable(Observable): + """ + Base class for histogram-based observables. + """ + +
[docs] def bin_edges(self): + """ + Returns + ------- + :obj:`ndarray` of :obj:`float` + Positions between the bins. If the histogram has dimensions + ``(M,N,O)``, the bin edges have dimensions ``(M+1,N+1,O+1,3)``. + """ + edges = self.call_method("edges") + shape = list(map(len, edges)) + [len(edges)] + return np.array(list(itertools.product(*edges))).reshape(shape)
+ +
[docs] def bin_centers(self): + """ + Returns + ------- + :obj:`ndarray` of :obj:`float` + Positions of the bins centers. If the histogram has dimensions + ``(M,N,O)``, the bin centers have dimensions ``(M,N,O,3)``. + """ + edges = self.call_method("edges") + for i, edge in enumerate(edges): + edges[i] = np.array(edge[:-1]) + (edge[1] - edge[0]) / 2 + shape = list(map(len, edges)) + [len(edges)] + return np.array(list(itertools.product(*edges))).reshape(shape)
+ + +
[docs]class CylindricalProfileObservable(ProfileObservable): + """ + Base class for observables that work with cylinder coordinates + """ + + def __init__( + self, transform_params=CylindricalTransformationParameters(), **kwargs): + # Provide default transformation parameters if not user-provided + kwargs['transform_params'] = transform_params + super().__init__(**kwargs)
+ + +
[docs]@script_interface_register +class ComPosition(Observable): + + """Calculates the center of mass for particles with given ids. + + Note that virtual sites are not included since they do not have a meaningful mass. + + Output format: :math:`\\frac{1}{\\sum_i m_i} \\left( \\sum_i m_i r^x_i, \\sum_i m_i r^y_i, \\sum_i m_i r^z_i\\right)` + + Parameters + ---------- + ids : array_like of :obj:`int` + The ids of (existing) particles to take into account. + + Methods + ------- + calculate() + Run the observable. + + Returns + ------- + (3,) :obj:`ndarray` of :obj:`float` + + """ + _so_name = "Observables::ComPosition"
+ + +
[docs]@script_interface_register +class ComVelocity(Observable): + + """Calculates the center of mass velocity for particles with given ids. + + Note that virtual sites are not included since they do not have a meaningful mass. + + Output format: :math:`\\frac{1}{\\sum_i m_i} \\left( \\sum_i m_i v^x_i, \\sum_i m_i v^y_i, \\sum_i m_i v^z_i\\right)` + + Parameters + ---------- + ids : array_like of :obj:`int` + The ids of (existing) particles to take into account. + + Methods + ------- + calculate() + Run the observable. + + Returns + ------- + (3,) :obj:`ndarray` of :obj:`float` + + """ + _so_name = "Observables::ComVelocity"
+ + +
[docs]@script_interface_register +class DensityProfile(ProfileObservable): + + """Calculates the particle density profile for particles with given ids. + + Parameters + ---------- + ids : array_like of :obj:`int` + The ids of (existing) particles to take into account. + n_x_bins : :obj:`int` + Number of bins in ``x`` direction. + n_y_bins : :obj:`int` + Number of bins in ``y`` direction. + n_z_bins : :obj:`int` + Number of bins in ``z`` direction. + min_x : :obj:`float` + Minimum ``x`` to consider. + min_y : :obj:`float` + Minimum ``y`` to consider. + min_z : :obj:`float` + Minimum ``z`` to consider. + max_x : :obj:`float` + Maximum ``x`` to consider. + max_y : :obj:`float` + Maximum ``y`` to consider. + max_z : :obj:`float` + Maximum ``z`` to consider. + + Methods + ------- + calculate() + Run the observable. + + Returns + ------- + (``n_x_bins``, ``n_y_bins``, ``n_z_bins``) :obj:`ndarray` of :obj:`float` + + """ + _so_name = "Observables::DensityProfile"
+ + +
[docs]@script_interface_register +class DipoleMoment(Observable): + + """Calculates the electric dipole moment for particles with given ids. + + Output format: :math:`\\left(\\sum_i q_i r^x_i, \\sum_i q_i r^y_i, \\sum_i q_i r^z_i\\right)` + + Parameters + ---------- + ids : array_like of :obj:`int` + The ids of (existing) particles to take into account. + + Methods + ------- + calculate() + Run the observable. + + Returns + ------- + (3,) :obj:`ndarray` of :obj:`float` + + """ + _so_name = "Observables::DipoleMoment"
+ + +
[docs]@script_interface_register +class FluxDensityProfile(ProfileObservable): + + """Calculates the particle flux density for particles with given ids. + + Parameters + ---------- + ids : array_like of :obj:`int` + The ids of (existing) particles to take into account. + n_x_bins : :obj:`int` + Number of bins in ``x`` direction. + n_y_bins : :obj:`int` + Number of bins in ``y`` direction. + n_z_bins : :obj:`int` + Number of bins in ``z`` direction. + min_x : :obj:`float` + Minimum ``x`` to consider. + min_y : :obj:`float` + Minimum ``y`` to consider. + min_z : :obj:`float` + Minimum ``z`` to consider. + max_x : :obj:`float` + Maximum ``x`` to consider. + max_y : :obj:`float` + Maximum ``y`` to consider. + max_z : :obj:`float` + Maximum ``z`` to consider. + + Methods + ------- + calculate() + Run the observable. + + Returns + ------- + (``n_x_bins``, ``n_y_bins``, ``n_z_bins``, 3) :obj:`ndarray` of :obj:`float` + The fourth dimension of the array stores the histogram for the x, + y and z components of the flux density, respectively. + + """ + _so_name = "Observables::FluxDensityProfile"
+ + +
[docs]@script_interface_register +class ForceDensityProfile(ProfileObservable): + + """Calculates the force density profile for particles with given ids. + + Parameters + ---------- + ids : array_like of :obj:`int` + The ids of (existing) particles to take into account. + n_x_bins : :obj:`int` + Number of bins in ``x`` direction. + n_y_bins : :obj:`int` + Number of bins in ``y`` direction. + n_z_bins : :obj:`int` + Number of bins in ``z`` direction. + min_x : :obj:`float` + Minimum ``x`` to consider. + min_y : :obj:`float` + Minimum ``y`` to consider. + min_z : :obj:`float` + Minimum ``z`` to consider. + max_x : :obj:`float` + Maximum ``x`` to consider. + max_y : :obj:`float` + Maximum ``y`` to consider. + max_z : :obj:`float` + Maximum ``z`` to consider. + + Methods + ------- + calculate() + Run the observable. + + Returns + ------- + (``n_x_bins``, ``n_y_bins``, ``n_z_bins``, 3) :obj:`ndarray` of :obj:`float` + The fourth dimension of the array stores the histogram for the x, + y and z components of the force, respectively. + + """ + _so_name = "Observables::ForceDensityProfile"
+ + +
[docs]@script_interface_register +class LBVelocityProfile(ProfileObservable): + + """Calculates the LB fluid velocity profile. + + This observable samples the fluid in on a regular grid defined by the variables + ``sampling_*``. Note that a small delta leads to a large number of sample + points and carries a performance cost. + + Parameters + ---------- + n_x_bins : :obj:`int` + Number of bins in ``x`` direction. + n_y_bins : :obj:`int` + Number of bins in ``y`` direction. + n_z_bins : :obj:`int` + Number of bins in ``z`` direction. + min_x : :obj:`float` + Minimum ``x`` to consider. + min_y : :obj:`float` + Minimum ``y`` to consider. + min_z : :obj:`float` + Minimum ``z`` to consider. + max_x : :obj:`float` + Maximum ``x`` to consider. + max_y : :obj:`float` + Maximum ``y`` to consider. + max_z : :obj:`float` + Maximum ``z`` to consider. + sampling_delta_x : :obj:`float`, default=1.0 + Spacing for the sampling grid in ``x``-direction. + sampling_delta_y : :obj:`float`, default=1.0 + Spacing for the sampling grid in ``y``-direction. + sampling_delta_z : :obj:`float`, default=1.0 + Spacing for the sampling grid in ``z``-direction. + sampling_offset_x : :obj:`float`, default=0.0 + Offset for the sampling grid in ``x``-direction. + sampling_offset_y : :obj:`float`, default=0.0 + Offset for the sampling grid in ``y``-direction. + sampling_offset_z : :obj:`float`, default=0.0 + Offset for the sampling grid in ``z``-direction. + allow_empty_bins : :obj:`bool`, default=False + Whether or not to allow bins that will not be sampled at all. + + Methods + ------- + calculate() + Run the observable. + + Returns + ------- + (``n_x_bins``, ``n_y_bins``, ``n_z_bins``, 3) :obj:`ndarray` of :obj:`float` + The fourth dimension of the array stores the histogram for the x, + y and z components of the LB velocity, respectively. + + """ + _so_name = "Observables::LBVelocityProfile"
+ + +
[docs]@script_interface_register +class LBFluidPressureTensor(Observable): + + """Calculates the average pressure tensor of the LB fluid for all nodes. + + Parameters + ---------- + None + + Methods + ------- + calculate() + Run the observable. + + Returns + ------- + (3, 3) :obj:`ndarray` of :obj:`float` + + """ + _so_name = "Observables::LBFluidPressureTensor"
+ + +
[docs]@script_interface_register +class MagneticDipoleMoment(Observable): + + """Calculates the magnetic dipole moment for particles with given ids. + + Output format: :math:`\\left(\\sum_i \\mu^x_i, \\sum_i \\mu^y_i, \\sum_i \\mu^z_i\\right)` + + Parameters + ---------- + ids : array_like of :obj:`int` + The ids of (existing) particles to take into account. + + Methods + ------- + calculate() + Run the observable. + + Returns + ------- + (3,) :obj:`ndarray` of :obj:`float` + + """ + _so_name = "Observables::MagneticDipoleMoment"
+ + +
[docs]@script_interface_register +class ParticleAngularVelocities(Observable): + + """Calculates the angular velocity (omega) in the spaced-fixed frame of reference + + Output format: :math:`(\\omega^x_1,\\ \\omega^y_1,\\ \\omega^z_1),\\ (\\omega^x_2,\\ \\omega^y_2,\\ \\omega^z_2), \\dots,\\ (\\omega^x_n,\\ \\omega^y_n,\\ \\omega^z_n)`. + + The particles are ordered according to the list of ids passed to the observable. + + Parameters + ---------- + ids : array_like of :obj:`int` + The ids of (existing) particles to take into account. + + Methods + ------- + calculate() + Run the observable. + + Returns + ------- + (N, 3) :obj:`ndarray` of :obj:`float` + + """ + _so_name = "Observables::ParticleAngularVelocities"
+ + +
[docs]@script_interface_register +class ParticleBodyAngularVelocities(Observable): + + """Calculates the angular velocity (omega) in the particles' body-fixed frame of reference. + + For each particle, the body-fixed frame of reference is obtained from the particle's + orientation stored in the quaternions. + + Output format: :math:`(\\omega^x_1,\\ \\omega^y_1,\\ \\omega^z_1),\\ (\\omega^x_2,\\ \\omega^y_2,\\ \\omega^z_2), \\dots,\\ (\\omega^x_n,\\ \\omega^y_n,\\ \\omega^z_n)`. + + The particles are ordered according to the list of ids passed to the observable. + + Parameters + ---------- + ids : array_like of :obj:`int` + The ids of (existing) particles to take into account. + + Methods + ------- + calculate() + Run the observable. + + Returns + ------- + (N, 3) :obj:`ndarray` of :obj:`float` + + """ + _so_name = "Observables::ParticleBodyAngularVelocities"
+ + +
[docs]@script_interface_register +class ParticleBodyVelocities(Observable): + + """Calculates the particle velocity in the particles' body-fixed frame of reference. + + For each particle, the body-fixed frame of reference is obtained from the particle's + orientation stored in the quaternions. + + Output format: :math:`(v^x_1,\\ v^y_1,\\ v^z_1),\\ (v^x_2,\\ v^y_2,\\ v^z_2),\\ \\dots,\\ (v^x_n,\\ v^y_n,\\ v^z_n)`. + + The particles are ordered according to the list of ids passed to the observable. + + Parameters + ---------- + ids : array_like of :obj:`int` + The ids of (existing) particles to take into account. + + Methods + ------- + calculate() + Run the observable. + + Returns + ------- + (N, 3) :obj:`ndarray` of :obj:`float` + + """ + _so_name = "Observables::ParticleBodyVelocities"
+ + +
[docs]@script_interface_register +class ParticleForces(Observable): + + """Calculates the particle forces for particles with given ids. + + Output format: :math:`(f^x_1,\\ f^y_1,\\ f^z_1),\\ (f^x_2,\\ f^y_2,\\ f^z_2),\\ \\dots,\\ (f^x_n,\\ f^y_n,\\ f^z_n)`. + + The particles are ordered according to the list of ids passed to the observable. + + Parameters + ---------- + ids : array_like of :obj:`int` + The ids of (existing) particles to take into account. + + Methods + ------- + calculate() + Run the observable. + + Returns + ------- + (N, 3) :obj:`ndarray` of :obj:`float` + + """ + _so_name = "Observables::ParticleForces"
+ + +
[docs]@script_interface_register +class ParticlePositions(Observable): + + """Calculates the particle positions for particles with given ids. + + Output format: :math:`(x_1,\\ y_1,\\ z_1),\\ (x_2,\\ y_2,\\ z_2),\\ \\dots,\\ (x_n,\\ y_n,\\ z_n)`. + + The particles are ordered according to the list of ids passed to the observable. + + Parameters + ---------- + ids : array_like of :obj:`int` + The ids of (existing) particles to take into account. + + Methods + ------- + calculate() + Run the observable. + + Returns + ------- + (N, 3) :obj:`ndarray` of :obj:`float` + + """ + _so_name = "Observables::ParticlePositions"
+ + +
[docs]@script_interface_register +class ParticleVelocities(Observable): + + """Calculates the particle velocities for particles with given ids. + + Output format: :math:`(v^x_1,\\ v^y_1,\\ v^z_1),\\ (v^x_2,\\ v^y_2,\\ v^z_2),\\ \\dots,\\ (v^x_n,\\ v^y_n,\\ v^z_n)`. + + The particles are ordered according to the list of ids passed to the observable. + + Parameters + ---------- + ids : array_like of :obj:`int` + The ids of (existing) particles to take into account. + + Methods + ------- + calculate() + Run the observable. + + Returns + ------- + (N, 3) :obj:`ndarray` of :obj:`float` + + """ + _so_name = "Observables::ParticleVelocities"
+ + +
[docs]@script_interface_register +class ParticleDistances(Observable): + + """Calculates the distances between particles with given ids along a + polymer chain. + + Parameters + ---------- + ids : array_like of :obj:`int` + The ids of (existing) particles to take into account. + + Methods + ------- + calculate() + Run the observable. + + Returns + ------- + (N - 1,) :obj:`ndarray` of :obj:`float` + + """ + _so_name = "Observables::ParticleDistances"
+ + +
[docs]@script_interface_register +class TotalForce(Observable): + + """Calculates the total force on particles with given ids. + + Note that virtual sites are not included since forces on them do not enter the equation of motion directly. + + Output format: :math:`\\left(\\sum_i f^x_i, \\sum_i f^y_i, \\sum_i f^z_i\\right)` + + Parameters + ---------- + ids : array_like of :obj:`int` + The ids of (existing) particles to take into account. + + Methods + ------- + calculate() + Run the observable. + + Returns + ------- + (3,) :obj:`ndarray` of :obj:`float` + + """ + _so_name = "Observables::TotalForce"
+ + +
[docs]@script_interface_register +class BondAngles(Observable): + + """Calculates the angles between bonds of particles with given ids along a + polymer chain. + + Parameters + ---------- + ids : array_like of :obj:`int` + The ids of (existing) particles to take into account. + + Methods + ------- + calculate() + Run the observable. + + Returns + ------- + (N - 2,) :obj:`ndarray` of :obj:`float` + + """ + _so_name = "Observables::BondAngles"
+ + +
[docs]@script_interface_register +class CosPersistenceAngles(Observable): + + """Calculates the cosine of mutual bond angles for chained particles with given ids. + + The *i*-th value of the result contains the cosine of the angle between bonds that + are separated by *i* bonds. The values are averaged over the chain. + + Parameters + ---------- + ids : array_like of :obj:`int` + The ids of (existing) particles to take into account. + + Methods + ------- + calculate() + Run the observable. + + Returns + ------- + (N - 2,) :obj:`ndarray` of :obj:`float` + + """ + _so_name = "Observables::CosPersistenceAngles"
+ + +
[docs]@script_interface_register +class BondDihedrals(Observable): + + """Calculates the dihedrals between particles with given ids along a + polymer chain. + + Parameters + ---------- + ids : array_like of :obj:`int` + The ids of (existing) particles to take into account. + + Methods + ------- + calculate() + Run the observable. + + Returns + ------- + (N - 3,) :obj:`ndarray` of :obj:`float` + + """ + _so_name = "Observables::BondDihedrals"
+ + +
[docs]@script_interface_register +class Energy(Observable): + + """Calculates the total energy. + + Methods + ------- + calculate() + Run the observable. + + Returns + ------- + :obj:`float` + + """ + _so_name = "Observables::Energy"
+ + +
[docs]@script_interface_register +class Pressure(Observable): + + """Calculates the total scalar pressure. + + Methods + ------- + calculate() + Run the observable. + + Returns + ------- + :obj:`float` + + """ + _so_name = "Observables::Pressure"
+ + +
[docs]@script_interface_register +class PressureTensor(Observable): + + """Calculates the total pressure tensor. + + Methods + ------- + calculate() + Run the observable. + + Returns + ------- + (3, 3) :obj:`ndarray` of :obj:`float` + + """ + _so_name = "Observables::PressureTensor"
+ + +
[docs]@script_interface_register +class DPDStress(Observable): + + """Calculates the non-equilibrium contribution of the DPD interaction + to the stress tensor. + + Parameters + ---------- + None + + Methods + ------- + calculate() + Run the observable. + + Returns + ------- + (3, 3) :obj:`ndarray` of :obj:`float` + + """ + _so_name = "Observables::DPDStress"
+ + +
[docs]@script_interface_register +class CylindricalDensityProfile(CylindricalProfileObservable): + + """Calculates the particle density in cylindrical coordinates. + + Parameters + ---------- + ids : array_like of :obj:`int` + The ids of (existing) particles to take into account. + transform_params : :class:`espressomd.math.CylindricalTransformationParameters`, optional + Parameters of the cylinder transformation. Defaults to the default of :class:`espressomd.math.CylindricalTransformationParameters` + n_r_bins : :obj:`int`, default = 1 + Number of bins in radial direction. + n_phi_bins : :obj:`int`, default = 1 + Number of bins for the azimuthal direction. + n_z_bins : :obj:`int`, default = 1 + Number of bins in ``z`` direction. + min_r : :obj:`float`, default = 0 + Minimum ``r`` to consider. + min_phi : :obj:`float`, default = :math:`-\\pi` + Minimum ``phi`` to consider. Must be in :math:`[-\\pi,\\pi)`. + min_z : :obj:`float` + Minimum ``z`` to consider. + max_r : :obj:`float` + Maximum ``r`` to consider. + max_phi : :obj:`float`, default = :math:`\\pi` + Maximum ``phi`` to consider. Must be in :math:`(-\\pi,\\pi]`. + max_z : :obj:`float` + Maximum ``z`` to consider. + + Methods + ------- + calculate() + Run the observable. + + Returns + ------- + (``n_r_bins``, ``n_phi_bins``, ``n_z_bins``) :obj:`ndarray` of :obj:`float` + + """ + _so_name = "Observables::CylindricalDensityProfile"
+ + +
[docs]@script_interface_register +class CylindricalFluxDensityProfile(CylindricalProfileObservable): + + """Calculates the particle flux density in cylindrical coordinates. + + Parameters + ---------- + ids : array_like of :obj:`int` + The ids of (existing) particles to take into account. + transform_params : :class:`espressomd.math.CylindricalTransformationParameters`, optional + Parameters of the cylinder transformation. Defaults to the default of :class:`espressomd.math.CylindricalTransformationParameters` + n_r_bins : :obj:`int`, default = 1 + Number of bins in radial direction. + n_phi_bins : :obj:`int`, default = 1 + Number of bins for the azimuthal direction. + n_z_bins : :obj:`int`, default = 1 + Number of bins in ``z`` direction. + min_r : :obj:`float`, default = 0 + Minimum ``r`` to consider. + min_phi : :obj:`float`, default = :math:`-\\pi` + Minimum ``phi`` to consider. Must be in :math:`[-\\pi,\\pi)`. + min_z : :obj:`float` + Minimum ``z`` to consider. + max_r : :obj:`float` + Maximum ``r`` to consider. + max_phi : :obj:`float`, default = :math:`\\pi` + Maximum ``phi`` to consider. Must be in :math:`(-\\pi,\\pi]`. + max_z : :obj:`float` + Maximum ``z`` to consider. + + Methods + ------- + calculate() + Run the observable. + + Returns + ------- + (``n_r_bins``, ``n_phi_bins``, ``n_z_bins``, 3) :obj:`ndarray` of :obj:`float` + The fourth dimension of the array stores the histogram for the + radial distance, azimuth and axial coordinate of the particle + flux density field, respectively. + + """ + _so_name = "Observables::CylindricalFluxDensityProfile"
+ + +
[docs]@script_interface_register +class CylindricalLBFluxDensityProfileAtParticlePositions( + CylindricalProfileObservable): + + """Calculates the LB fluid flux density at the particle positions in + cylindrical coordinates. + + Parameters + ---------- + ids : array_like of :obj:`int` + The ids of (existing) particles to take into account. + transform_params : :class:`espressomd.math.CylindricalTransformationParameters`, optional + Parameters of the cylinder transformation. Defaults to the default of :class:`espressomd.math.CylindricalTransformationParameters` + n_r_bins : :obj:`int`, default = 1 + Number of bins in radial direction. + n_phi_bins : :obj:`int`, default = 1 + Number of bins for the azimuthal direction. + n_z_bins : :obj:`int`, default = 1 + Number of bins in ``z`` direction. + min_r : :obj:`float`, default = 0 + Minimum ``r`` to consider. + min_phi : :obj:`float`, default = :math:`-\\pi` + Minimum ``phi`` to consider. Must be in :math:`[-\\pi,\\pi)`. + min_z : :obj:`float` + Minimum ``z`` to consider. + max_r : :obj:`float` + Maximum ``r`` to consider. + max_phi : :obj:`float`, default = :math:`\\pi` + Maximum ``phi`` to consider. Must be in :math:`(-\\pi,\\pi]`. + max_z : :obj:`float` + Maximum ``z`` to consider. + + Methods + ------- + calculate() + Run the observable. + + Returns + ------- + (``n_r_bins``, ``n_phi_bins``, ``n_z_bins``, 3) :obj:`ndarray` of :obj:`float` + The fourth dimension of the array stores the histogram for the + radial distance, azimuth and axial coordinate of the LB flux + density field, respectively. + + """ + _so_name = "Observables::CylindricalLBFluxDensityProfileAtParticlePositions"
+ + +
[docs]@script_interface_register +class CylindricalLBVelocityProfileAtParticlePositions( + CylindricalProfileObservable): + + """Calculates the LB fluid velocity at the particle positions in + cylindrical coordinates. + + Parameters + ---------- + ids : array_like of :obj:`int` + The ids of (existing) particles to take into account. + transform_params : :class:`espressomd.math.CylindricalTransformationParameters`, optional + Parameters of the cylinder transformation. Defaults to the default of :class:`espressomd.math.CylindricalTransformationParameters` + n_r_bins : :obj:`int`, default = 1 + Number of bins in radial direction. + n_phi_bins : :obj:`int`, default = 1 + Number of bins for the azimuthal direction. + n_z_bins : :obj:`int`, default = 1 + Number of bins in ``z`` direction. + min_r : :obj:`float`, default = 0 + Minimum ``r`` to consider. + min_phi : :obj:`float`, default = :math:`-\\pi` + Minimum ``phi`` to consider. Must be in :math:`[-\\pi,\\pi)`. + min_z : :obj:`float` + Minimum ``z`` to consider. + max_r : :obj:`float` + Maximum ``r`` to consider. + max_phi : :obj:`float`, default = :math:`\\pi` + Maximum ``phi`` to consider. Must be in :math:`(-\\pi,\\pi]`. + max_z : :obj:`float` + Maximum ``z`` to consider. + + Methods + ------- + calculate() + Run the observable. + + Returns + ------- + (``n_r_bins``, ``n_phi_bins``, ``n_z_bins``, 3) :obj:`ndarray` of :obj:`float` + The fourth dimension of the array stores the histogram for the + radial distance, azimuth and axial coordinate of the LB velocity + field, respectively. + + """ + _so_name = "Observables::CylindricalLBVelocityProfileAtParticlePositions"
+ + +
[docs]@script_interface_register +class CylindricalVelocityProfile(CylindricalProfileObservable): + + """Calculates the particle velocity profile in cylindrical coordinates. + + Parameters + ---------- + ids : array_like of :obj:`int` + The ids of (existing) particles to take into account. + transform_params : :class:`espressomd.math.CylindricalTransformationParameters`, optional + Parameters of the cylinder transformation. Defaults to the default of :class:`espressomd.math.CylindricalTransformationParameters` + n_r_bins : :obj:`int`, default = 1 + Number of bins in radial direction. + n_phi_bins : :obj:`int`, default = 1 + Number of bins for the azimuthal direction. + n_z_bins : :obj:`int`, default = 1 + Number of bins in ``z`` direction. + min_r : :obj:`float`, default = 0 + Minimum ``r`` to consider. + min_phi : :obj:`float`, default = :math:`-\\pi` + Minimum ``phi`` to consider. Must be in :math:`[-\\pi,\\pi)`. + min_z : :obj:`float` + Minimum ``z`` to consider. + max_r : :obj:`float` + Maximum ``r`` to consider. + max_phi : :obj:`float`, default = :math:`\\pi` + Maximum ``phi`` to consider. Must be in :math:`(-\\pi,\\pi]`. + max_z : :obj:`float` + Maximum ``z`` to consider. + + Methods + ------- + calculate() + Run the observable. + + Returns + ------- + (``n_r_bins``, ``n_phi_bins``, ``n_z_bins``, 3) :obj:`ndarray` of :obj:`float` + The fourth dimension of the array stores the histogram for the + radial distance, azimuth and axial coordinate of the particle + velocity field, respectively. + + """ + _so_name = "Observables::CylindricalVelocityProfile"
+ + +
[docs]@script_interface_register +class CylindricalLBVelocityProfile(CylindricalProfileObservable): + + """Calculates the LB fluid velocity profile in cylindrical coordinates. + + This observable samples the fluid in on a regular grid defined by variable + ``sampling_density``. Note that a small delta leads to a large number of + sample points and carries a performance cost. + + Parameters + ---------- + transform_params : :class:`espressomd.math.CylindricalTransformationParameters`, optional + Parameters of the cylinder transformation. Defaults to the default of :class:`espressomd.math.CylindricalTransformationParameters` + n_r_bins : :obj:`int`, default = 1 + Number of bins in radial direction. + n_phi_bins : :obj:`int`, default = 1 + Number of bins for the azimuthal direction. + n_z_bins : :obj:`int`, default = 1 + Number of bins in ``z`` direction. + min_r : :obj:`float`, default = 0 + Minimum ``r`` to consider. + min_phi : :obj:`float`, default = :math:`-\\pi` + Minimum ``phi`` to consider. Must be in :math:`[-\\pi,\\pi)`. + min_z : :obj:`float` + Minimum ``z`` to consider. + max_r : :obj:`float` + Maximum ``r`` to consider. + max_phi : :obj:`float`, default = :math:`\\pi` + Maximum ``phi`` to consider. Must be in :math:`(-\\pi,\\pi]`. + max_z : :obj:`float` + Maximum ``z`` to consider. + sampling_density : :obj:`float` + Samples per unit volume for the LB velocity interpolation. + + Methods + ------- + calculate() + Run the observable. + + Returns + ------- + (``n_r_bins``, ``n_phi_bins``, ``n_z_bins``, 3) :obj:`ndarray` of :obj:`float` + The fourth dimension of the array stores the histogram for the + radial distance, azimuth and axial coordinate of the LB velocity + field, respectively. + + """ + _so_name = "Observables::CylindricalLBVelocityProfile"
+ + +
[docs]@script_interface_register +class RDF(Observable): + + """Calculates a radial distribution function. + The result is normalized by the bulk concentration. + + Parameters + ---------- + ids1 : array_like of :obj:`int` + The ids of (existing) particles to calculate the distance from. + ids2 : array_like of :obj:`int`, optional + The ids of (existing) particles to calculate the distance to. + If not provided, use ``ids1``. + n_r_bins : :obj:`int` + Number of bins in radial direction. + min_r : :obj:`float` + Minimum ``r`` to consider. + max_r : :obj:`float` + Maximum ``r`` to consider. + + Methods + ------- + calculate() + Run the observable. + + Returns + ------- + (``n_r_bins``,) :obj:`ndarray` of :obj:`float` + The RDF. + + """ + _so_name = "Observables::RDF" + + def __init__(self, **kwargs): + if "ids2" not in kwargs: + kwargs["ids2"] = [] + super().__init__(**kwargs) + +
[docs] def bin_centers(self): + bin_width = (self.max_r - self.min_r) / self.n_r_bins + return self.min_r + (np.arange(self.n_r_bins) + 0.5) * bin_width
+
+ +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/doc4.2.2/_modules/espressomd/pair_criteria.html b/doc4.2.2/_modules/espressomd/pair_criteria.html new file mode 100644 index 0000000000..d2f40321e5 --- /dev/null +++ b/doc4.2.2/_modules/espressomd/pair_criteria.html @@ -0,0 +1,170 @@ + + + + + + + + espressomd.pair_criteria — ESPResSo 4.2.2 documentation + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Source code for espressomd.pair_criteria

+# Copyright (C) 2010-2022 The ESPResSo project
+#
+# This file is part of ESPResSo.
+#
+# ESPResSo is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# ESPResSo is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+from .script_interface import ScriptInterfaceHelper, script_interface_register
+from .particle_data import ParticleHandle
+
+
+class _PairCriterion(ScriptInterfaceHelper):
+
+    def decide(self, p1, p2):
+        """Makes a decision based on the two particles specified.
+
+        Parameters
+        ----------
+        p1, p2 : :obj:`espressomd.particle_data.ParticleHandle` or :obj:`int` containing the particle id.
+            Particle pair.
+        """
+        id1 = None
+        id2 = None
+        if isinstance(p1, ParticleHandle) and isinstance(p2, ParticleHandle):
+            id1 = p1.id
+            id2 = p2.id
+        elif isinstance(p1, int) and isinstance(p2, int):
+            id1 = p1
+            id2 = p2
+        else:
+            raise ValueError(
+                "arguments must be instances of int or ParticleHandle")
+        return self.call_method("decide", id1=id1, id2=id2)
+
+
+
[docs]@script_interface_register +class DistanceCriterion(_PairCriterion): + + """Pair criterion returning true, if particles are closer than a cutoff. + Periodic boundaries are treated via minimum image convention. + + The following parameters can be passed to the constructor, changed via + ``set_params()`` and retrieved via ``get_params()``. + + Parameters + ---------- + cut_off : :obj:`float` + distance cutoff for the criterion + """ + _so_name = "PairCriteria::DistanceCriterion" + _so_creation_policy = "LOCAL"
+ + +
[docs]@script_interface_register +class EnergyCriterion(_PairCriterion): + + """Pair criterion returning true, if the short range energy between the + particles is superior or equal to the cutoff. + + Be aware that the short range energy contains the short range part of + dipolar and electrostatic interactions, but not the long range part. + + The following parameters can be passed to the constructor, changed via + ``set_params()`` and retrieved via ``get_params()``. + + Parameters + ---------- + cut_off : :obj:`float` + energy cutoff for the criterion + """ + _so_name = "PairCriteria::EnergyCriterion" + _so_creation_policy = "LOCAL"
+ + +
[docs]@script_interface_register +class BondCriterion(_PairCriterion): + + """Pair criterion returning true, if a pair bond of given type exists between them + + The following parameters can be passed to the constructor, changed via + ``set_params()`` and retrieved via ``get_params()``. + + Parameters + ---------- + bond_type : :obj:`int` + numeric type of the bond + """ + _so_name = "PairCriteria::BondCriterion" + _so_creation_policy = "LOCAL"
+
+ +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/doc4.2.2/_modules/espressomd/reaction_methods.html b/doc4.2.2/_modules/espressomd/reaction_methods.html new file mode 100644 index 0000000000..4b1fac71a1 --- /dev/null +++ b/doc4.2.2/_modules/espressomd/reaction_methods.html @@ -0,0 +1,643 @@ + + + + + + + + espressomd.reaction_methods — ESPResSo 4.2.2 documentation + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Source code for espressomd.reaction_methods

+# Copyright (C) 2010-2022 The ESPResSo project
+#
+# This file is part of ESPResSo.
+#
+# ESPResSo is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# ESPResSo is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+import numpy as np
+import warnings
+from .script_interface import ScriptInterfaceHelper, script_interface_register
+from . import utils
+
+
+
[docs]@script_interface_register +class SingleReaction(ScriptInterfaceHelper): + _so_name = "ReactionMethods::SingleReaction" + _so_creation_policy = "LOCAL" + + def __init__(self, **kwargs): + super().__init__(**kwargs) + if not 'sip' in kwargs: + utils.check_valid_keys(self.valid_keys(), kwargs.keys()) + +
[docs] def valid_keys(self): + return ("reactant_types", "reactant_coefficients", + "product_types", "product_coefficients", "gamma")
+ +
[docs] def required_keys(self): + return ("reactant_types", "reactant_coefficients", + "product_types", "product_coefficients", "gamma")
+ +
[docs] def make_backward_reaction(self): + return SingleReaction( + gamma=1. / self.gamma, reactant_types=self.product_types, + reactant_coefficients=self.product_coefficients, + product_types=self.reactant_types, + product_coefficients=self.reactant_coefficients)
+ + +
[docs]@script_interface_register +class ReactionAlgorithm(ScriptInterfaceHelper): + """ + + This class provides the base class for Reaction Algorithms like + the Reaction Ensemble algorithm and the constant pH method. + Initialize the reaction algorithm by setting the + standard pressure, temperature, and the exclusion range. + + Note: When creating particles the velocities of the new particles are set + according the Maxwell-Boltzmann distribution. In this step the mass of the + new particle is assumed to equal 1. + + + Parameters + ---------- + kT : :obj:`float` + Thermal energy of the system in simulation units + exclusion_range : :obj:`float` + Minimal distance from any particle, within which new particles will not + be inserted. + seed : :obj:`int` + Initial counter value (or seed) of the Mersenne Twister RNG. + exclusion_radius_per_type : :obj:`dict`, optional + Mapping of particle types to exclusion radii. + search_algorithm : :obj:`str` + Pair search algorithm. Default is ``"order_n"``, which evaluates the + distance between the inserted particle and all other particles in the + system, which scales with O(N). For MPI-parallel simulations, the + ``"parallel"`` method is faster. The ``"parallel"`` method is not + recommended for simulations on 1 MPI rank, since it comes with the + overhead of a ghost particle update. + + Methods + ------- + remove_constraint() + Remove any previously defined constraint. + Requires setting the volume using :meth:`set_volume`. + + set_cylindrical_constraint_in_z_direction() + Constrain the reaction moves within a cylinder aligned on the z-axis. + Requires setting the volume using :meth:`set_volume`. + + Parameters + ---------- + center_x : :obj:`float` + x coordinate of center of the cylinder. + center_y : :obj:`float` + y coordinate of center of the cylinder. + radius_of_cylinder : :obj:`float` + radius of the cylinder + + set_wall_constraints_in_z_direction() + Restrict the sampling area to a slab in z-direction. Requires setting + the volume using :meth:`set_volume`. This constraint is necessary when + working with :ref:`Electrostatic Layer Correction (ELC)`. + + Parameters + ---------- + slab_start_z : :obj:`float` + z coordinate of the bottom wall. + slab_end_z : :obj:`float` + z coordinate of the top wall. + + Examples + -------- + + >>> import espressomd + >>> import espressomd.shapes + >>> import espressomd.electrostatics + >>> import espressomd.reaction_methods + >>> import numpy as np + >>> # setup a charged system + >>> box_l = 20 + >>> elc_gap = 10 + >>> system = espressomd.System(box_l=[box_l, box_l, box_l + elc_gap]) + >>> system.time_step = 0.001 + >>> system.cell_system.skin = 0.4 + >>> types = {"HA": 0, "A-": 1, "H+": 2, "wall": 3} + >>> charges = {types["HA"]: 0, types["A-"]: -1, types["H+"]: +1} + >>> for i in range(10): + ... system.part.add(pos=np.random.random(3) * box_l, type=types["A-"], q=charges[types["A-"]]) + ... system.part.add(pos=np.random.random(3) * box_l, type=types["H+"], q=charges[types["H+"]]) + >>> for particle_type in charges.keys(): + ... system.non_bonded_inter[particle_type, types["wall"]].wca.set_params(epsilon=1.0, sigma=1.0) + >>> # add ELC actor + >>> p3m = espressomd.electrostatics.P3M(prefactor=1.0, accuracy=1e-2) + >>> elc = espressomd.electrostatics.ELC(actor=p3m, maxPWerror=1.0, gap_size=elc_gap) + >>> system.actors.add(elc) + >>> # add constant pH method + >>> RE = espressomd.reaction_methods.ConstantpHEnsemble(kT=1, exclusion_range=1, seed=77) + >>> RE.constant_pH = 2 + >>> RE.add_reaction(gamma=0.0088, reactant_types=[types["HA"]], + ... product_types=[types["A-"], types["H+"]], + ... default_charges=charges) + >>> # add walls for the ELC gap + >>> RE.set_wall_constraints_in_z_direction(0, box_l) + >>> RE.set_volume(box_l**3) + >>> system.constraints.add(shape=espressomd.shapes.Wall(dist=0, normal=[0, 0, 1]), + ... particle_type=types["wall"]) + >>> system.constraints.add(shape=espressomd.shapes.Wall(dist=-box_l, normal=[0, 0, -1]), + ... particle_type=types["wall"]) + + get_wall_constraints_in_z_direction() + Returns the restrictions of the sampling area in z-direction. + + set_volume() + Set the volume to be used in the acceptance probability of the reaction + ensemble. This can be useful when using constraints, if the relevant + volume is different from the box volume. If not used the default volume + which is used, is the box volume. + + Parameters + ---------- + volume : :obj:`float` + Volume of the system in simulation units + + get_volume() + Get the volume to be used in the acceptance probability of the reaction + ensemble. + + get_acceptance_rate_configurational_moves(): + Returns the acceptance rate for the configuration moves. + + get_acceptance_rate_reaction() + Returns the acceptance rate for the given reaction. + + Parameters + ---------- + reaction_id : :obj:`int` + Reaction id + + set_non_interacting_type() + Sets the particle type for non-interacting particles. + Default value: 100. + This is used to temporarily hide particles during a reaction trial + move, if they are to be deleted after the move is accepted. Please + change this value if you intend to use the type 100 for some other + particle types with interactions, or if you need improved performance, + as the default value of 100 causes some overhead. + Please also note that particles + in the current implementation of the Reaction Ensemble are only + hidden with respect to Lennard-Jones and Coulomb interactions. Hiding + of other interactions, for example a magnetic, needs to be implemented + in the code. + + Parameters + ---------- + type : :obj:`int` + Particle type for the hidden particles + + get_non_interacting_type() + Returns the type which is used for hiding particle + + reaction() + Performs randomly selected reactions. + + Parameters + ---------- + reaction_steps : :obj:`int`, optional + The number of reactions to be performed at once, defaults to 1. + + displacement_mc_move_for_particles_of_type() + Performs displacement Monte Carlo moves for particles of a given type. + New positions of the displaced particles are chosen from the whole box + with a uniform probability distribution and new velocities are + sampled from the Maxwell-Boltzmann distribution. + + The sequence of moves is only accepted if each individual move in + the sequence was accepted. Particles are sampled without replacement. + Therefore, calling this method once for 10 particles is not equivalent + to calling this method 10 times for 1 particle. + + Parameters + ---------- + type_mc : :obj:`int` + Particle type which should be moved + particle_number_to_be_changed : :obj:`int` + Number of particles to move, defaults to 1. + Particles are selected without replacement. + + Returns + ------- + :obj:`bool` + Whether all moves were accepted. + + delete_particle() + Deletes the particle of the given p_id and makes sure that the particle + range has no holes. This function has some restrictions, as e.g. bonds + are not deleted. Therefore only apply this function to simple ions. + + Parameters + ---------- + p_id : :obj:`int` + Id of the particle to be deleted. + + change_reaction_constant() + Changes the reaction constant of a given reaction + (for both the forward and backward reactions). + The ``reaction_id`` which is assigned to a reaction + depends on the order in which :meth:`add_reaction` was called. + The 0th reaction has ``reaction_id=0``, the next added + reaction needs to be addressed with ``reaction_id=1``, etc. + + Parameters + ---------- + reaction_id : :obj:`int` + Reaction id + gamma : :obj:`float` + New reaction constant + + delete_reaction() + Delete a reaction from the set of used reactions + (the forward and backward reaction). + The ``reaction_id`` which is assigned to a reaction + depends on the order in which :meth:`add_reaction` was called. + The 0th reaction has ``reaction_id=0``, the next added + reaction needs to be addressed with ``reaction_id=1``, etc. + After the deletion of a reaction subsequent reactions + take the ``reaction_id`` of the deleted reaction. + + Parameters + ---------- + reaction_id : :obj:`int` + Reaction id + + """ + + _so_name = "ReactionMethods::ReactionAlgorithm" + _so_creation_policy = "LOCAL" + _so_bind_methods = ("remove_constraint", + "get_wall_constraints_in_z_direction", + "set_wall_constraints_in_z_direction", + "set_cylindrical_constraint_in_z_direction", + "set_volume", + "get_volume", + "get_acceptance_rate_reaction", + "set_non_interacting_type", + "get_non_interacting_type", + "reaction", + "displacement_mc_move_for_particles_of_type", + "check_reaction_method", + "change_reaction_constant", + "delete_reaction", + "delete_particle", + ) + + def __init__(self, **kwargs): + if 'exclusion_radius' in kwargs: + raise KeyError( + 'the keyword `exclusion_radius` is obsolete. Currently, the equivalent keyword is `exclusion_range`') + super().__init__(**kwargs) + if not 'sip' in kwargs: + utils.check_valid_keys(self.valid_keys(), kwargs.keys()) + +
[docs] def valid_keys(self): + return {"kT", "exclusion_range", "seed", + "exclusion_radius_per_type", "search_algorithm"}
+ +
[docs] def required_keys(self): + return {"kT", "exclusion_range", "seed"}
+ +
[docs] def add_reaction(self, **kwargs): + """ + Sets up a reaction in the forward and backward direction. + + Parameters + ---------- + gamma : :obj:`float` + Equilibrium constant :math:`\\Gamma` of the reaction in simulation + units (see section :ref:`Reaction Ensemble` for its definition). + reactant_types : list of :obj:`int` + List of particle types of reactants in the reaction. + reactant_coefficients : list of :obj:`int` + List of stoichiometric coefficients of the reactants in the same + order as the list of their types. + product_types : list of :obj:`int` + List of particle types of products in the reaction. + product_coefficients : list of :obj:`int` + List of stoichiometric coefficients of products of the reaction in + the same order as the list of their types + default_charges : :obj:`dict` + A dictionary of default charges for types that occur + in the provided reaction. + check_for_electroneutrality : :obj:`bool` + Check for electroneutrality of the given reaction. + Default is ``True``. + + """ + default_charges = kwargs.pop("default_charges") + neutrality_check = kwargs.pop("check_for_electroneutrality", True) + forward_reaction = SingleReaction(**kwargs) + backward_reaction = forward_reaction.make_backward_reaction() + if neutrality_check: + self._check_charge_neutrality( + type2charge=default_charges, + reaction=forward_reaction) + + self.call_method("add_reaction", reaction=forward_reaction) + self.call_method("add_reaction", reaction=backward_reaction) + + for ptype, charge in default_charges.items(): + self.call_method("set_charge_of_type", type=ptype, charge=charge) + self.call_method("check_reaction_method")
+ + def _check_charge_neutrality(self, type2charge, reaction): + if not isinstance(type2charge, dict): + raise ValueError( + "No dictionary for relation between types and default charges provided.") + charges = np.array(list(type2charge.values())) + if np.count_nonzero(charges) == 0: + # all particles have zero charge + # no need to check electroneutrality + return + # calculate net change of electrical charge for the reaction + net_charge_change = 0.0 + for coef, ptype in zip( + reaction.reactant_coefficients, reaction.reactant_types): + net_charge_change -= coef * type2charge[ptype] + for coef, ptype in zip( + reaction.product_coefficients, reaction.product_types): + net_charge_change += coef * type2charge[ptype] + min_abs_nonzero_charge = np.min( + np.abs(charges[np.nonzero(charges)[0]])) + if abs(net_charge_change) / min_abs_nonzero_charge > 1e-10: + raise ValueError("Reaction system is not charge neutral") + +
[docs] def get_status(self): + """ + Returns the status of the reaction ensemble in a dictionary containing + the used reactions, the used kT and the used exclusion radius. + + """ + + self.call_method("check_reaction_method") + reactions_list = [] + + for core_reaction in self.reactions: + reaction = {"reactant_coefficients": core_reaction.reactant_coefficients, + "reactant_types": core_reaction.reactant_types, + "product_types": core_reaction.product_types, + "product_coefficients": core_reaction.product_coefficients, + "reactant_types": core_reaction.reactant_types, + "gamma": core_reaction.gamma} + reactions_list.append(reaction) + + return {"reactions": reactions_list, "kT": self.kT, + "exclusion_range": self.exclusion_range}
+ + +
[docs]@script_interface_register +class ReactionEnsemble(ReactionAlgorithm): + """ + This class implements the Reaction Ensemble. + """ + + _so_name = "ReactionMethods::ReactionEnsemble" + _so_creation_policy = "LOCAL"
+ + +
[docs]@script_interface_register +class ConstantpHEnsemble(ReactionAlgorithm): + """ + This class implements the constant pH Ensemble. + + When adding an acid-base reaction, the acid and base particle types + are always assumed to be at index 0 of the lists passed to arguments + ``reactant_types`` and ``product_types``. + + Attributes + ---------- + constant_pH : :obj:`float` + Constant pH value. + + """ + _so_name = "ReactionMethods::ConstantpHEnsemble" + _so_creation_policy = "LOCAL" + +
[docs] def valid_keys(self): + return {"kT", "exclusion_range", "seed", + "constant_pH", "exclusion_radius_per_type", "search_algorithm"}
+ +
[docs] def required_keys(self): + return {"kT", "exclusion_range", "seed", "constant_pH"}
+ +
[docs] def add_reaction(self, *args, **kwargs): + warn_msg = ( + "arguments 'reactant_coefficients' and 'product_coefficients' " + "are deprecated and are no longer necessary for the constant pH " + "ensemble. They are kept for backward compatibility but might " + "be deleted in future versions.") + err_msg = ("All product and reactant coefficients must equal one in " + "the constant pH method as implemented in ESPResSo.") + warn_user = False + + if "reactant_coefficients" in kwargs: + if kwargs["reactant_coefficients"][0] != 1: + raise ValueError(err_msg) + else: + warn_user = True + else: + kwargs["reactant_coefficients"] = [1] + + if "product_coefficients" in kwargs: + if kwargs["product_coefficients"][0] != 1 or kwargs["product_coefficients"][1] != 1: + raise ValueError(err_msg) + else: + warn_user = True + else: + kwargs["product_coefficients"] = [1, 1] + + if warn_user: + warnings.warn(warn_msg, FutureWarning) + + if(len(kwargs["product_types"]) != 2 or len(kwargs["reactant_types"]) != 1): + raise ValueError( + "The constant pH method is only implemented for reactions " + "with two product types and one adduct type.") + + super().add_reaction(*args, **kwargs)
+ + +
[docs]@script_interface_register +class WidomInsertion(ReactionAlgorithm): + """ + This class implements the Widom insertion method in the canonical ensemble + for homogeneous systems, where the excess chemical potential is not + depending on the location. + + """ + + _so_name = "ReactionMethods::WidomInsertion" + _so_creation_policy = "LOCAL" + +
[docs] def required_keys(self): + return {"kT", "seed"}
+ +
[docs] def valid_keys(self): + return {"kT", "seed"}
+ +
[docs] def add_reaction(self, **kwargs): + kwargs['gamma'] = 1. + super().add_reaction(**kwargs)
+ +
[docs] def calculate_particle_insertion_potential_energy(self, **kwargs): + """ + Measures the potential energy when particles are inserted in the + system following the reaction provided in ``reaction_id``. Please + define the insertion moves first by calling the method + :meth:`~ReactionAlgorithm.add_reaction` (with only product types + specified). + + Note that although this function does not provide directly + the chemical potential, it can be used to calculate it. + For an example of such an application please check + :file:`/samples/widom_insertion.py`. + + Parameters + ---------- + reaction_id : :obj:`int` + Reaction identifier. + """ + # make inverse widom scheme (deletion of particles) inaccessible. + # The deletion reactions are the odd reaction_ids + + return self.call_method( + "calculate_particle_insertion_potential_energy", **kwargs)
+ +
[docs] def calculate_excess_chemical_potential( + self, **kwargs): + """ + Given a set of samples of the particle insertion potential energy, + calculates the excess chemical potential and its statistical error. + + Parameters + ---------- + particle_insertion_potential_energy_samples : array_like of :obj:`float` + Samples of the particle insertion potential energy. + N_blocks : :obj:`int`, optional + Number of bins for binning analysis. + + Returns + ------- + mean : :obj:`float` + Mean excess chemical potential. + error : :obj:`float` + Standard error of the mean. + """ + + def do_block_analysis(samples, N_blocks): + """ + Performs a binning analysis of samples. + Divides the samples in ``N_blocks`` equispaced blocks + and returns the mean and its uncertainty + """ + size_block = int(len(samples) / N_blocks) + block_list = [] + for block in range(N_blocks): + block_list.append( + np.mean(samples[block * size_block:(block + 1) * size_block])) + + sample_mean = np.mean(block_list) + sample_std = np.std(block_list, ddof=1) + sample_uncertainty = sample_std / np.sqrt(N_blocks) + + return sample_mean, sample_uncertainty + + kT = self.kT + + gamma_samples = np.exp(-1.0 * np.array( + kwargs["particle_insertion_potential_energy_samples"]) / kT) + + gamma_mean, gamma_std = do_block_analysis( + samples=gamma_samples, N_blocks=kwargs.get("N_blocks", 16)) + + mu_ex_mean = -kT * np.log(gamma_mean) + + # full propagation of error + mu_ex_Delta = 0.5 * kT * abs(-np.log(gamma_mean + gamma_std) - + (-np.log(gamma_mean - gamma_std))) + + return mu_ex_mean, mu_ex_Delta
+
+ +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/doc4.2.2/_modules/espressomd/rotation.html b/doc4.2.2/_modules/espressomd/rotation.html new file mode 100644 index 0000000000..4090f1d39f --- /dev/null +++ b/doc4.2.2/_modules/espressomd/rotation.html @@ -0,0 +1,210 @@ + + + + + + + + espressomd.rotation — ESPResSo 4.2.2 documentation + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Source code for espressomd.rotation

+#
+# Copyright (C) 2020-2022 The ESPResSo project
+#
+# This file is part of ESPResSo.
+#
+# ESPResSo is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# ESPResSo is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+import math
+
+import numpy as np
+
+
+
[docs]def matrix_to_quat(m): + """ + Convert the (proper) rotation matrix to the corresponding quaternion representation based + on pyquaternion_. + + .. _pyquaternion: https://github.com/KieranWynn/pyquaternion + + Parameters + ---------- + m : (3,3) array_like of :obj:`float` + Rotation matrix. + + Returns + ------- + array_like of :obj:`float` + Quaternion representation of the rotation. + + Raises + ------ + ValueError + If the matrix does not a correspond to a proper rotation (det(m) != 1). + + """ + if not math.isclose(np.linalg.det(m), 1.0, abs_tol=1e-7): + raise ValueError("Only proper rotations are supported") + m = m.copy().conj().transpose() + if m[2, 2] < 0: + if m[0, 0] > m[1, 1]: + t = 1 + m[0, 0] - m[1, 1] - m[2, 2] + return 0.5 / \ + math.sqrt(t) * np.array([m[1, 2] - m[2, 1], + t, m[0, 1] + m[1, 0], m[2, 0] + m[0, 2]]) + else: + t = 1 - m[0, 0] + m[1, 1] - m[2, 2] + return 0.5 / \ + math.sqrt(t) * np.array([m[2, 0] - m[0, 2], + m[0, 1] + m[1, 0], t, m[1, 2] + m[2, 1]]) + else: + if m[0, 0] < -m[1, 1]: + t = 1 - m[0, 0] - m[1, 1] + m[2, 2] + return 0.5 / \ + math.sqrt(t) * np.array([m[0, 1] - m[1, 0], + m[2, 0] + m[0, 2], m[1, 2] + m[2, 1], t]) + else: + t = 1 + m[0, 0] + m[1, 1] + m[2, 2] + return 0.5 / \ + math.sqrt( + t) * np.array([t, m[1, 2] - m[2, 1], m[2, 0] - m[0, 2], m[0, 1] - m[1, 0]])
+ + +
[docs]def inertia_tensor(positions, masses): + """ + Calculate the inertia tensor for given point masses + at given positions. + + Parameters + ---------- + positions : (N,3) array_like of :obj:`float` + Point masses' positions. + masses : (N,) array_like of :obj:`float` + + Returns + ------- + (3,3) array_like of :obj:`float` + Moment of inertia tensor. + + Notes + ----- + See wikipedia_. + + .. _wikipedia: https://en.wikipedia.org/wiki/Moment_of_inertia#Inertia_tensor + + """ + inertia_tensor = np.zeros((3, 3)) + for ind, p in enumerate(positions): + inertia_tensor += masses[ind] * \ + (np.dot(p, p) * np.identity(3) + - np.outer(p, p)) + return inertia_tensor
+ + +
[docs]def diagonalized_inertia_tensor(positions, masses): + """ + Calculate the diagonalized inertia tensor + with respect to the center of mass + for given point masses at given positions. + + Parameters + ---------- + positions : (N,3) array_like of :obj:`float` + Positions of the masses. + masses : (N,) array_like of :obj:`float` + + Returns + ------- + (3,) array_like of :obj:`float` + Principal moments of inertia. + (3,3) array_like of :obj:`float` + Principal axes of inertia. + Note that the second axis is the coordinate axis (same as input). + + """ + assert np.array(masses).shape[0] == np.array(positions).shape[0] + + def center_of_mass(positions, masses): return np.average( + positions, axis=0, weights=masses) + positions = np.array(np.copy(positions)) - \ + center_of_mass(positions, masses) + inertia = inertia_tensor(positions, masses) + eig, eigv = np.linalg.eig(inertia) + eigv = np.transpose(eigv) + # check for right-handedness + if not np.allclose(np.cross(eigv[0], eigv[1]), eigv[2]): + eigv[[0, 1], :] = eigv[[1, 0], :] + return eig, eigv
+
+ +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/doc4.2.2/_modules/espressomd/shapes.html b/doc4.2.2/_modules/espressomd/shapes.html new file mode 100644 index 0000000000..9159367119 --- /dev/null +++ b/doc4.2.2/_modules/espressomd/shapes.html @@ -0,0 +1,389 @@ + + + + + + + + espressomd.shapes — ESPResSo 4.2.2 documentation + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Source code for espressomd.shapes

+# Copyright (C) 2010-2022 The ESPResSo project
+#
+# This file is part of ESPResSo.
+#
+# ESPResSo is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# ESPResSo is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+import collections.abc
+
+from .script_interface import ScriptInterfaceHelper, script_interface_register, ScriptObjectList
+
+
+
[docs]class Shape: + _so_bind_methods = ("calc_distance",)
+ + +
[docs]@script_interface_register +class Cylinder(Shape, ScriptInterfaceHelper): + """ + A cylinder shape. + + Attributes + ---------- + center : (3,) array_like of :obj:`float` + Coordinates of the center of the cylinder. + axis : (3,) array_like of :obj:`float` + Axis of the cylinder. + radius : :obj:`float` + Radius of the cylinder. + length : :obj:`float` + Length of the cylinder. + direction : :obj:`int` + Surface orientation, for +1 the normal points + out of the mantel, for -1 it points inward. + open : :obj:`bool` + cylinder is open or has caps. + + """ + _so_name = "Shapes::Cylinder"
+ + +
[docs]@script_interface_register +class Ellipsoid(Shape, ScriptInterfaceHelper): + """ + An ellipsoid. + + For now only ellipsoids of revolution are supported. + The symmetry axis is aligned parallel to the x-direction. + + Attributes + ---------- + center : (3,) array_like of :obj:`float` + Coordinates of the center of the ellipsoid. + a : :obj:`float` + Semiaxis along the axis of rotational symmetry. + b : :obj:`float` + Equatorial semiaxes. + direction : :obj:`int` + Surface orientation, for +1 the normal points + out of the mantel, for -1 it points inward. + """ + _so_name = "Shapes::Ellipsoid"
+ + +
[docs]@script_interface_register +class Rhomboid(Shape, ScriptInterfaceHelper): + """ + A parallelepiped. + + Attributes + ---------- + a : (3,) array_like of :obj:`float` + First base vector. + b : (3,) array_like of :obj:`float` + Second base vector. + c : (3,) array_like of :obj:`float` + Third base vector. + corner : (3,) array_like of :obj:`float` + Lower left corner of the rhomboid. + direction : :obj:`int` + Surface orientation, for +1 the normal points + out of the mantel, for -1 it points inward. + + """ + _so_name = "Shapes::Rhomboid"
+ + +
[docs]@script_interface_register +class Slitpore(Shape, ScriptInterfaceHelper): + """ + + .. figure:: figures/slitpore.png + :alt: Schematic for the Slitpore shape with labeled geometrical parameters. + :align: center + :height: 8.00000cm + + Attributes + ---------- + + channel_width : :obj:`float` + lower_smoothing_radius : :obj:`float` + pore_length : :obj:`float` + pore_mouth : :obj:`float` + pore_width : :obj:`float` + upper_smoothing_radius : :obj:`float` + dividing_plane : :obj:`float` + + """ + _so_name = "Shapes::Slitpore"
+ + +
[docs]@script_interface_register +class Sphere(Shape, ScriptInterfaceHelper): + """ + A sphere. + + Attributes + ---------- + center : (3,) array_like of :obj:`float` + Center of the sphere + radius : :obj:`float` + Radius of the sphere. + direction : :obj:`int` + Surface orientation, for +1 the normal points + out of the mantel, for -1 it points inward. + + """ + _so_name = "Shapes::Sphere"
+ + +
[docs]@script_interface_register +class SpheroCylinder(Shape, ScriptInterfaceHelper): + """ + A cylinder with hemispheres as caps. + + Attributes + ---------- + center : (3,) array_like of :obj:`float` + Coordinates of the center of the cylinder. + axis : (3,) array_like of :obj:`float` + Axis of the cylinder. + radius : :obj:`float` + Radius of the cylinder. + direction : :obj:`int` + Surface orientation, for +1 the normal points + out of the mantel, for -1 it points inward. + length : :obj:`float` + Length of the cylinder (not including the caps). + + """ + _so_name = "Shapes::SpheroCylinder"
+ + +
[docs]@script_interface_register +class Torus(Shape, ScriptInterfaceHelper): + """ + A torus shape. + + Attributes + ---------- + center : (3,) array_like of :obj:`float` + Coordinates of the center of the torus. + normal : (3,) array_like of :obj:`float` + Normal axis of the torus. + radius : :obj:`float` + Radius of the torus. + tube_radius : :obj:`float` + Radius of the tube. + direction : :obj:`int` + Surface orientation, for +1 the normal points + out of the mantel, for -1 it points inward. + + """ + _so_name = "Shapes::Torus"
+ + +
[docs]@script_interface_register +class Wall(Shape, ScriptInterfaceHelper): + """ + An infinite plane. + + Attributes + ---------- + dist : :obj:`float` + Distance from the origin. + normal : (3,) array_like of :obj:`int` + Normal vector of the plane (needs not to be length 1). + + """ + _so_name = "Shapes::Wall"
+ + +
[docs]@script_interface_register +class SimplePore(Shape, ScriptInterfaceHelper): + """ + Two parallel infinite planes, and a cylindrical channel connecting them. + The cylinder and the planes are connected by torus segments with an + adjustable radius. + + Attributes + ---------- + radius: :obj:`float` + The radius of the pore. + length: :obj:`float` + The distance between the planes. + smoothing_radius: :obj:`float` + Radius of the torus segments + axis: (3,) array_like of :obj:`float` + Axis of the cylinder and normal of the planes + center: (3,) array_like of :obj:`float` + Position of the center of the cylinder. + + """ + _so_name = "Shapes::SimplePore"
+ + +
[docs]@script_interface_register +class HollowConicalFrustum(Shape, ScriptInterfaceHelper): + """ + Hollow conical frustum shape. + + Attributes + ---------- + cyl_transform_params : :class:`espressomd.math.CylindricalTransformationParameters`, + Parameters of the spacial orientation of the frustum. Contained must be parameters for ``center`` and ``axis``. ``orientation`` has no effect, unless ``central_angle != 0`` + r1: :obj:`float` + Radius r1. + r2: :obj:`float` + Radius r2. + length: :obj:`float` + Length of the conical frustum along ``axis``. + thickness: float + The thickness of the frustum. Also determines the rounding radius of the edges + direction: :obj:`int`, optional + Surface orientation, for +1 the normal points + out of the mantel, for -1 it points inside of the shape. Defaults to 1 + central_angle: :obj:`float`, optional + A ``central_angle`` creates an opening in the frustum along the side, centered symmetrically around the ``direction`` of ``cyl_transform_params``. Must be between ``0`` and ``2 pi``. Defaults to 0. + + + .. image:: figures/conical_frustum.png + """ + _so_name = "Shapes::HollowConicalFrustum"
+ + +
[docs]@script_interface_register +class Union(Shape, ScriptObjectList): + """A union of shapes. + + This shape represents a union of shapes where the distance to the union + is defined by the smallest distance to any shape contained in the union. + + Methods + ------- + size() + Number of shapes contained in the union. + clear() + Remove all shapes from the union. + + """ + _so_name = "Shapes::Union" + _so_bind_methods = Shape._so_bind_methods + ("size", "empty", "clear") + +
[docs] def add(self, shape): + """ + Add a shape to the union. + + Parameters + ---------- + shape : array_like / instance of :class:`espressomd.shapes.Shape` + Shape instance(s) to be added to the union. + + """ + + def _add(self, shape): + if isinstance(shape, Shape): + self.call_method("add", object=shape) + else: + raise ValueError("Only shapes can be added.") + + if isinstance(shape, collections.abc.Iterable): + for s in shape: + _add(self, s) + else: + _add(self, shape)
+ +
[docs] def remove(self, shape): + """ + Remove a shape from the union. + + Parameters + ---------- + shape : array_like / instance of :class:`espressomd.shapes.Shape` + Shape instance(s) to be removed from the union. + + """ + + def _remove(self, shape): + if isinstance(shape, Shape): + self.call_method("remove", object=shape) + else: + raise ValueError("Only shapes can be removed.") + if isinstance(shape, collections.abc.Iterable): + for s in shape: + _remove(self, s) + else: + _remove(self, shape)
+
+ +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/doc4.2.2/_modules/espressomd/virtual_sites.html b/doc4.2.2/_modules/espressomd/virtual_sites.html new file mode 100644 index 0000000000..721e67e112 --- /dev/null +++ b/doc4.2.2/_modules/espressomd/virtual_sites.html @@ -0,0 +1,141 @@ + + + + + + + + espressomd.virtual_sites — ESPResSo 4.2.2 documentation + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Source code for espressomd.virtual_sites

+# Copyright (C) 2010-2022 The ESPResSo project
+#
+# This file is part of ESPResSo.
+#
+# ESPResSo is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# ESPResSo is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+from .__init__ import has_features
+from .script_interface import ScriptInterfaceHelper, script_interface_register
+
+if has_features("VIRTUAL_SITES"):
+
[docs] @script_interface_register + class ActiveVirtualSitesHandle(ScriptInterfaceHelper): + + """Handle for the virtual sites implementation active in the core + + This should not be used directly. + + Attributes + ---------- + have_quaternion : :obj:`bool` + Whether the virtual sites has a quaternion (only relevant for + :class:`~espressomd.virtual_sites.VirtualSitesRelative`). + override_cutoff_check : :obj:`bool` + Whether to disable the sanity check that triggers when attempting + to set up a virtual site too far away from the real particle in a + MPI-parallel simulation with more than 1 core. Disabling this + check is not recommended; it is only relevant in rare situations + when using the :ref:`Hybrid decomposition` cell system. + + """ + _so_name = "VirtualSites::ActiveVirtualSitesHandle"
+ +
[docs] @script_interface_register + class VirtualSitesOff(ScriptInterfaceHelper): + + """Virtual sites implementation which does nothing (default)""" + _so_name = "VirtualSites::VirtualSitesOff"
+ + +if has_features("VIRTUAL_SITES_INERTIALESS_TRACERS"): +
[docs] @script_interface_register + class VirtualSitesInertialessTracers(ScriptInterfaceHelper): + + """Virtual sites which are advected with an LB fluid without inertia. + Forces are on them are transferred to the fluid instantly. + + """ + _so_name = "VirtualSites::VirtualSitesInertialessTracers"
+ + +if has_features("VIRTUAL_SITES_RELATIVE"): +
[docs] @script_interface_register + class VirtualSitesRelative(ScriptInterfaceHelper): + + """Virtual sites implementation placing virtual sites relative to other + particles. See :ref:`Rigid arrangements of particles` for details. + + """ + _so_name = "VirtualSites::VirtualSitesRelative"
+
+ +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/doc4.2.2/_modules/espressomd/visualization.html b/doc4.2.2/_modules/espressomd/visualization.html new file mode 100644 index 0000000000..7b5c338a6b --- /dev/null +++ b/doc4.2.2/_modules/espressomd/visualization.html @@ -0,0 +1,2948 @@ + + + + + + + + espressomd.visualization — ESPResSo 4.2.2 documentation + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Source code for espressomd.visualization

+# Copyright (C) 2010-2022 The ESPResSo project
+#
+# This file is part of ESPResSo.
+#
+# ESPResSo is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# ESPResSo is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+import ctypes
+import math
+import os
+import sys
+import time
+import itertools
+import threading
+import numpy as np
+import matplotlib.pyplot
+
+import OpenGL.GL
+import OpenGL.GLE
+import OpenGL.GLU
+import OpenGL.GLUT
+
+import espressomd
+import espressomd.particle_data
+
+
+
[docs]class openGLLive(): + """ + This class provides live visualization using pyOpenGL. + Use the update method to push your current simulation state after + integrating. Modify the appearance with a list of keywords. + Timed callbacks can be registered via the :meth:`register_callback` method + and keyboard callbacks via :meth:`keyboard_manager.register_button() + <espressomd.visualization.KeyboardManager.register_button>`. + + Parameters + ---------- + + system : :class:`espressomd.system.System` + window_size : (2,) array_like of :obj:`int`, optional + Size of the visualizer window in pixels. + name : :obj:`str`, optional + The name of the visualizer window. + background_color : (3,) array_like of :obj:`float`, optional + RGB of the background. + periodic_images : (3,) array_like of :obj:`int`, optional + Periodic repetitions on both sides of the box in xyz-direction. + draw_box : :obj:`bool`, optional + Draw wireframe boundaries. + draw_axis : :obj:`bool`, optional + Draw xyz system axes. + draw_nodes : :obj:`bool`, optional + Draw node boxes. + draw_cells : :obj:`bool`, optional + Draw cell boxes. + quality_particles : :obj:`int`, optional + The number of subdivisions for particle spheres. + quality_bonds : :obj:`int`, optional + The number of subdivisions for cylindrical bonds. + quality_arrows : :obj:`int`, optional + The number of subdivisions for external force arrows. + quality_constraints : :obj:`int`, optional + The number of subdivisions for primitive constraints. + close_cut_distance : :obj:`float`, optional + The distance from the viewer to the near clipping plane. + far_cut_distance : :obj:`float`, optional + The distance from the viewer to the far clipping plane. + camera_position : :obj:`str` or (3,) array_like of :obj:`float`, optional + Initial camera position. Use ``'auto'`` (default) for shifted position in z-direction. + camera_target : :obj:`str` or (3,) array_like of :obj:`float`, optional + Initial camera target. Use ``'auto'`` (default) to look towards the system center. + camera_right : (3,) array_like of :obj:`float`, optional + Camera right vector in system coordinates. Default is ``[1, 0, 0]`` + particle_sizes : :obj:`str` or array_like of :obj:`float` or callable, optional + * ``'auto'`` (default): The Lennard-Jones sigma value of the + self-interaction is used for the particle diameter. + * callable: A lambda function with one argument. Internally, + the numerical particle type is passed to the lambda + function to determine the particle radius. + * list: A list of particle radii, indexed by the particle type. + particle_coloring : :obj:`str`, optional + * ``'auto'`` (default): Colors of charged particles are + specified by ``particle_charge_colors``, neutral particles + by ``particle_type_colors``. + * ``'charge'``: Minimum and maximum charge of all particles is determined by the + visualizer. All particles are colored by a linear + interpolation of the two colors given by + ``particle_charge_colors`` according to their charge. + * ``'type'``: Particle colors are specified by ``particle_type_colors``, + indexed by their numerical particle type. + * ``'node'``: Color according to the node the particle is on. + particle_type_colors : array_like of :obj:`float`, optional + Colors for particle types. + particle_type_materials : array_like of :obj:`str`, optional + Materials of the particle types. + particle_charge_colors : (2,) array_like of :obj:`float`, optional + Two colors for min/max charged particles. + draw_constraints : :obj:`bool`, optional + Enables constraint visualization. For simple constraints + (planes, spheres and cylinders), OpenGL primitives are + used. Otherwise, visualization by rasterization is used. + rasterize_pointsize : :obj:`float`, optional + Point size for the rasterization dots. + rasterize_resolution : :obj:`float`, optional + Accuracy of the rasterization. + quality_constraints : :obj:`int`, optional + The number of subdivisions for primitive constraints. + constraint_type_colors : array_like of :obj:`float`, optional + Colors of the constraints by type. + constraint_type_materials : array_like of :obj:`str`, optional + Materials of the constraints by type. + draw_bonds : :obj:`bool`, optional + Enables bond visualization. + bond_type_radius : array_like of :obj:`float`, optional + Radii of bonds by type. + bond_type_colors : array_like of :obj:`float`, optional + Color of bonds by type. + bond_type_materials : array_like of :obj:`str`, optional + Materials of bonds by type. + ext_force_arrows : :obj:`bool`, optional + Enables external force visualization. + ext_force_arrows_type_scale : array_like of :obj:`float`, optional + List of scale factors of external force arrows for different particle types. + ext_force_arrows_type_colors : array_like of :obj:`float`, optional + Colors of ext_force arrows for different particle types. + ext_force_arrows_type_materials : array_like of :obj:`str`, optional + Materials of ext_force arrows for different particle types. + ext_force_arrows_type_radii : array_like of :obj:`float`, optional + List of arrow radii for different particle types. + force_arrows : :obj:`bool`, optional + Enables particle force visualization. + force_arrows_type_scale : array_like of :obj:`float`, optional + List of scale factors of particle force arrows for different particle types. + force_arrows_type_colors : array_like of :obj:`float`, optional + Colors of particle force arrows for different particle types. + force_arrows_type_materials : array_like of :obj:`str`, optional + Materials of particle force arrows for different particle types. + force_arrows_type_radii : array_like of :obj:`float`, optional + List of arrow radii for different particle types. + velocity_arrows : :obj:`bool`, optional + Enables particle velocity visualization. + velocity_arrows_type_scale : array_like of :obj:`float`, optional + List of scale factors of particle velocity arrows for different particle types. + velocity_arrows_type_colors : array_like of :obj:`float`, optional + Colors of particle velocity arrows for different particle types. + velocity_arrows_type_materials : array_like of :obj:`str`, optional + Materials of particle velocity arrows for different particle types. + velocity_arrows_type_radii : array_like of :obj:`float`, optional + List of arrow radii for different particle types. + director_arrows : :obj:`bool`, optional + Enables particle director visualization. + director_arrows_type_scale : :obj:`float`, optional + Scale factor of particle director arrows for different particle types. + director_arrows_type_colors : array_like of :obj:`float`, optional + Colors of particle director arrows for different particle types. + director_arrows_type_materials : array_like of :obj:`str`, optional + Materials of particle director arrows for different particle types. + director_arrows_type_radii : array_like of :obj:`float`, optional + List of arrow radii for different particle types. + drag_enabled : :obj:`bool`, optional + Enables mouse-controlled particles dragging (Default: False) + drag_force : :obj:`bool`, optional + Factor for particle dragging + LB_draw_nodes : :obj:`bool`, optional + Draws a lattice representation of the LB nodes that are no boundaries. + LB_draw_node_boundaries : :obj:`bool`, optional + Draws a lattice representation of the LB nodes that are boundaries. + LB_draw_boundaries : :obj:`bool`, optional + Draws the LB shapes. + LB_draw_velocity_plane : :obj:`bool`, optional + Draws LB node velocity arrows in a plane perpendicular to the axis in + ``LB_plane_axis``, at a distance ``LB_plane_dist`` from the origin, + every ``LB_plane_ngrid`` grid points. + LB_plane_axis : :obj:`int`, optional + LB node velocity arrows are drawn in a plane perpendicular to the + x, y, or z axes, which are encoded by values 0, 1, or 2 respectively. + LB_plane_dist : :obj:`float`, optional + LB node velocity arrows are drawn in a plane perpendicular to the + x, y, or z axes, at a distance ``LB_plane_dist`` from the origin. + LB_plane_ngrid : :obj:`int`, optional + LB node velocity arrows are drawn in a plane perpendicular to the + x, y, or z axes, every ``LB_plane_ngrid`` grid points. + LB_vel_scale : :obj:`float`, optional + Rescale LB node velocity arrow length. + LB_vel_radius_scale : :obj:`float`, optional + Rescale LB node velocity arrow radii. + LB_arrow_color : (3,) array_like of :obj:`float`, optional + RGB of the LB velocity arrows. + LB_arrow_material : :obj:`str`, optional + Material of LB arrows. + quality_constraints : :obj:`int`, optional + The number of subdivisions for LB arrows. + light_pos : (3,) array_like of :obj:`float`, optional + If auto (default) is used, the light is placed dynamically in + the particle barycenter of the system. Otherwise, a fixed + coordinate can be set. + light_colors : array_like of :obj:`float`, optional + Three lists to specify ambient, diffuse and specular light colors. + light_brightness : :obj:`float`, optional + Brightness (inverse constant attenuation) of the light. + light_size : :obj:`float`, optional + Size (inverse linear attenuation) of the light. If auto + (default) is used, the light size will be set to a reasonable + value according to the box size at start. + spotlight_enabled : :obj:`bool`, optional + If set to True (default), it enables a spotlight on the + camera position pointing in look direction. + spotlight_colors : array_like of :obj:`float`, optional + Three lists to specify ambient, diffuse and specular spotlight colors. + spotlight_angle : :obj:`float`, optional + The spread angle of the spotlight in degrees (from 0 to 90). + spotlight_brightness : :obj:`float`, optional + Brightness (inverse constant attenuation) of the spotlight. + spotlight_focus : :obj:`float`, optional + Focus (spot exponent) for the spotlight from 0 (uniform) to 128. + + Notes + ----- + The visualization of some constraints is either improved by or even relies + on the presence of an installed OpenGL Extrusion library on your system. + + """ + + materials = { + 'bright': [0.9, 1.0, 0.8, 0.4, 1.0], + 'medium': [0.6, 0.8, 0.2, 0.4, 1.0], + 'dark': [0.4, 0.5, 0.1, 0.4, 1.0], + 'transparent1': [0.6, 0.8, 0.2, 0.5, 0.8], + 'transparent2': [0.6, 0.8, 0.2, 0.5, 0.4], + 'transparent3': [0.6, 0.8, 0.2, 0.5, 0.2], + 'rubber': [0, 0.4, 0.7, 0.078125, 1.0], + 'chrome': [0.25, 0.4, 0.774597, 0.6, 1.0], + 'plastic': [0, 0.55, 0.7, 0.25, 1.0], + 'steel': [0.25, 0.38, 0, 0.32, 1.0] + } + + def __init__(self, system, **kwargs): + # default properties + self.specs = { + 'window_size': [800, 800], + 'name': 'ESPResSo Visualization', + + 'background_color': [0, 0, 0], + + 'draw_fps': False, + 'draw_box': True, + 'draw_axis': True, + 'draw_nodes': False, + 'draw_cells': False, + + 'update_fps': 30, + + 'periodic_images': [0, 0, 0], + + 'quality_particles': 20, + 'quality_bonds': 16, + 'quality_arrows': 16, + 'quality_constraints': 32, + + 'close_cut_distance': 0.1, + 'far_cut_distance': 5, + + 'camera_position': 'auto', + 'camera_target': 'auto', + 'camera_right': [1.0, 0.0, 0.0], + + 'particle_coloring': 'auto', + 'particle_sizes': 'auto', + 'particle_type_colors': + [[1, 1, 0], [1, 0, 1], [0, 0, 1], [0, 1, 1], + [1, 1, 1], [1, 0.5, 0], [0.5, 0, 1]], + 'particle_type_materials': ['medium'], + 'particle_charge_colors': [[1, 0, 0], [0, 1, 0]], + + 'draw_constraints': True, + 'rasterize_pointsize': 10, + 'rasterize_resolution': 75.0, + 'constraint_type_colors': + [[0.5, 0.5, 0.5], [0, 0.5, 0.5], [0.5, 0, 0.5], + [0.5, 0.5, 0], [0, 0, 0.5], [0.5, 0, 0]], + 'constraint_type_materials': ['transparent1'], + + 'draw_bonds': True, + 'bond_type_radius': [0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5], + 'bond_type_colors': + [[1, 1, 1], [1, 0, 1], [0, 0, 1], [0, 1, 1], + [1, 1, 0], [1, 0.5, 0], [0.5, 0, 1]], + 'bond_type_materials': ['medium'], + + 'ext_force_arrows': False, + 'ext_force_arrows_type_scale': [1.0], + 'ext_force_arrows_type_colors': + [[1, 1, 1], [1, 0, 1], [0, 0, 1], [0, 1, 1], + [1, 1, 0], [1, 0.5, 0], [0.5, 0, 1]], + 'ext_force_arrows_type_materials': ['transparent2'], + 'ext_force_arrows_type_radii': [0.2], + + 'velocity_arrows': False, + 'velocity_arrows_type_scale': [1.0], + 'velocity_arrows_type_colors': + [[1, 1, 1], [1, 0, 1], [0, 0, 1], [0, 1, 1], + [1, 1, 0], [1, 0.5, 0], [0.5, 0, 1]], + 'velocity_arrows_type_materials': ['transparent2'], + 'velocity_arrows_type_radii': [0.2], + + 'force_arrows': False, + 'force_arrows_type_scale': [1.0], + 'force_arrows_type_colors': + [[1, 1, 1], [1, 0, 1], [0, 0, 1], [0, 1, 1], + [1, 1, 0], [1, 0.5, 0], [0.5, 0, 1]], + 'force_arrows_type_materials': ['transparent2'], + 'force_arrows_type_radii': [0.2], + + 'director_arrows': False, + 'director_arrows_type_scale': [1.0], + 'director_arrows_type_colors': + [[1, 1, 1], [1, 0, 1], [0, 0, 1], [0, 1, 1], + [1, 1, 0], [1, 0.5, 0], [0.5, 0, 1]], + 'director_arrows_type_materials': ['transparent2'], + 'director_arrows_type_radii': [0.2], + + 'LB_draw_nodes': False, + 'LB_draw_node_boundaries': False, + 'LB_draw_boundaries': False, + + 'LB_draw_velocity_plane': False, + 'LB_plane_axis': 2, + 'LB_plane_dist': 0, + 'LB_plane_ngrid': 5, + 'LB_vel_scale': 1.0, + 'LB_vel_radius_scale': 0.005, + 'LB_arrow_color': [1.0, 1.0, 1.0], + 'LB_arrow_material': 'transparent1', + 'LB_arrow_quality': 16, + + 'light_pos': 'auto', + 'light_colors': + [[0.1, 0.1, 0.2], [0.9, 0.9, 0.9], [1.0, 1.0, 1.0]], + 'light_brightness': 1.0, + 'light_size': 'auto', + + 'spotlight_enabled': False, + 'spotlight_colors': + [[0.2, 0.2, 0.3], [0.5, 0.5, 0.5], [1.0, 1.0, 1.0]], + 'spotlight_angle': 45, + 'spotlight_focus': 1, + 'spotlight_brightness': 0.6, + + 'drag_enabled': False, + 'drag_force': 3.0 + } + + # overwrite with user properties + for key in kwargs: + if key not in self.specs: + raise ValueError(f'{key} is no valid visualization property') + else: + self.specs[key] = kwargs[key] + + # dependencies + if not espressomd.has_features('EXTERNAL_FORCES'): + self.specs['drag_enabled'] = False + self.specs['ext_force_arrows'] = False + + if not espressomd.has_features('ROTATION'): + self.specs['director_arrows'] = False + + if not espressomd.has_features('LB_BOUNDARIES') and \ + not espressomd.has_features('LB_BOUNDARIES_GPU'): + self.specs['LB_draw_boundaries'] = False + self.specs['LB_draw_node_boundaries'] = False + + # ESPResSo-related inits that are known only when running the + # integration loop are called once in the update loop + # (constraints, node boxes, cell boxes, charge range, bonds) + + # ESPResSo-related inits that are known on instantiation go here: + + # content of particle data + self.has_particle_data = { + 'velocity': self.specs['velocity_arrows'], + 'force': self.specs['force_arrows'], + 'ext_force': self.specs['ext_force_arrows'] or + self.specs['drag_enabled']} + + if espressomd.has_features('ELECTROSTATICS'): + self.has_particle_data['charge'] = \ + self.specs['particle_coloring'] == 'auto' or \ + self.specs['particle_coloring'] == 'charge' + else: + self.has_particle_data['charge'] = False + self.has_particle_data['director'] = self.specs['director_arrows'] + self.has_particle_data['node'] = self.specs['particle_coloring'] == 'node' + + # particle info of highlighted particle: collect particle attributes + self.highlighted_particle = {} + self.particle_attributes = [] + for d in dir(espressomd.particle_data.ParticleHandle): + if isinstance(getattr(espressomd.particle_data.ParticleHandle, d), + type(espressomd.particle_data.ParticleHandle.pos)): + if d not in ["pos_folded"]: + self.particle_attributes.append(d) + self.max_len_attr = max([len(a) for a in self.particle_attributes]) + + # fixed colors from inverse background color for good contrast + self.inverse_bg_color = \ + np.array([1 - self.specs['background_color'][0], + 1 - self.specs['background_color'][1], + 1 - self.specs['background_color'][2], 1.0]) + + self.node_box_color = np.copy(self.inverse_bg_color) + self.node_box_color[0] += 0.5 * (0.5 - self.node_box_color[0]) + + self.cell_box_color = np.copy(self.inverse_bg_color) + self.cell_box_color[1] += 0.5 * (0.5 - self.cell_box_color[1]) + + self.lb_box_color = np.copy(self.inverse_bg_color) + self.lb_box_color[2] = 0.5 + + self.lb_box_color_boundary = np.copy(self.inverse_bg_color) + self.lb_box_color_boundary[1] = 0.5 + + self.text_color = np.copy(self.inverse_bg_color) + + # increase line thickness if node/cell box is enabled + self.line_width_fac = 1.0 + if self.specs['draw_nodes']: + self.line_width_fac += 0.5 + if self.specs['draw_cells']: + self.line_width_fac += 0.5 + + # has periodic images + self.has_images = any(i != 0 for i in self.specs['periodic_images']) + self.image_vectors = [ + list(range(-i, i + 1)) for i in self.specs['periodic_images']] + + # various inits + self.system = system + self.system_info = {} + + self.last_box_l = self.system.box_l + self.fps_last = 0 + self.fps = 0 + self.fps_count = 1 + + self.glut_main_loop_started = False + self.screenshot_initialized = False + self.hasParticleData = False + self.quit_safely = False + self.paused = False + self.take_screenshot = False + self.screenshot_captured = False + + self.keyboard_manager = KeyboardManager() + self.mouse_manager = MouseManager() + self.camera = self._init_camera() + + self.timers = [] + self.particles = {} + + # times of last call of update(), redraw_on_idle() + self.last_update = time.time() + self.last_draw = time.time() + + self.trigger_set_particle_drag = False + self.trigger_reset_particle_drag = False + self.drag_id = -1 + + # list of [(x, y), string] for user-defined text + self.user_texts = [] + +
[docs] def update_system_info(self): + """Update the information stored in dict self.system_info. + + The dictionary is used for showing system information, such as particle + or constraint information, in the visualizer window. + + """ + # collect system information + self.system_info = { + 'Actors': [], 'Non-bonded interactions': [], + 'Bonded interactions': [b for b in self.system.bonded_inter], + 'Constraints': [], 'Thermostat': self.system.thermostat.get_state() + } + + if len(self.system_info['Bonded interactions']) == 0: + self.system_info['Bonded interactions'].append('None') + + # collect all actors + for a in self.system.actors: + self.system_info['Actors'].append(str(a)) + if len(self.system_info['Actors']) == 0: + self.system_info['Actors'].append('None') + + # collect all types from particles and constraints + all_types = set(self.system.part.all().type) + constraint_types = [] + for c in self.system.constraints[:]: + constraint_types.append(c.get_parameter('particle_type')) + all_types.update(constraint_types) + + # collect all active non-bonded interactions + all_non_bonded_inters = [ + x for x in dir(self.system.non_bonded_inter[0, 0]) + if not x.startswith('__') and x != 'type1' and x != 'type2'] + for t1 in all_types: + for t2 in all_types: + for check_nb in all_non_bonded_inters: + nb = getattr( + self.system.non_bonded_inter[t1, t2], check_nb) + if nb is not None and nb.is_active(): + self.system_info['Non-bonded interactions'].append( + [t1, t2, nb.type_name(), nb.get_params()]) + if len(self.system_info['Non-bonded interactions']) == 0: + self.system_info['Non-bonded interactions'].append('None') + + # collect constraints + for c in self.system.constraints[:]: + co = c.get_params() + co_s = c.get_parameter('shape') + co['shape'] = [co_s.name(), co_s.get_params()] + self.system_info['Constraints'].append(co) + if len(self.system_info['Constraints']) == 0: + self.system_info['Constraints'].append('None')
+ +
[docs] def register_callback(self, cb, interval=1000): + """Register timed callbacks. + + """ + self.timers.append((int(interval), cb))
+ +
[docs] def screenshot(self, path): + """Renders the current state into an image file at ``path`` with + dimensions of ``specs['window_size']`` in PNG format. + + """ + # on first call: init and create buffers + if not self.screenshot_initialized: + self.screenshot_initialized = True + self._init_opengl() + + # create buffers that can be larger than the screen frame buffer + fbo = OpenGL.GL.glGenFramebuffers(1) + OpenGL.GL.glBindFramebuffer(OpenGL.GL.GL_FRAMEBUFFER, fbo) + # color buffer + rbo = OpenGL.GL.glGenRenderbuffers(1) + OpenGL.GL.glBindRenderbuffer(OpenGL.GL.GL_RENDERBUFFER, rbo) + OpenGL.GL.glRenderbufferStorage( + OpenGL.GL.GL_RENDERBUFFER, + OpenGL.GL.GL_RGB, + self.specs['window_size'][0], + self.specs['window_size'][1]) + OpenGL.GL.glFramebufferRenderbuffer( + OpenGL.GL.GL_FRAMEBUFFER, + OpenGL.GL.GL_COLOR_ATTACHMENT0, + OpenGL.GL.GL_RENDERBUFFER, + rbo) + # depth buffer + dbo = OpenGL.GL.glGenRenderbuffers(1) + OpenGL.GL.glBindRenderbuffer(OpenGL.GL.GL_RENDERBUFFER, dbo) + OpenGL.GL.glRenderbufferStorage( + OpenGL.GL.GL_RENDERBUFFER, OpenGL.GL.GL_DEPTH_COMPONENT, + self.specs['window_size'][0], self.specs['window_size'][1]) + OpenGL.GL.glFramebufferRenderbuffer( + OpenGL.GL.GL_FRAMEBUFFER, + OpenGL.GL.GL_DEPTH_ATTACHMENT, + OpenGL.GL.GL_RENDERBUFFER, + dbo) + + self._reshape_window( + self.specs['window_size'][0], self.specs['window_size'][1]) + OpenGL.GLUT.glutHideWindow() + + # initialize properties that depend on the ESPResSo system + self._init_espresso_visualization() + self._initial_espresso_updates() + + # draw the simulation box + OpenGL.GL.glClear( + OpenGL.GL.GL_COLOR_BUFFER_BIT | OpenGL.GL.GL_DEPTH_BUFFER_BIT) + OpenGL.GL.glLoadMatrixf(self.camera.modelview) + self._draw_system() + + # read the pixels + OpenGL.GL.glReadBuffer(OpenGL.GL.GL_COLOR_ATTACHMENT0) + + # save image + self._make_screenshot(path)
+ +
[docs] def run(self, integration_steps=1): + """Convenience method with a simple integration thread. + + """ + + def main(): + while True: + self.update() + if not self.paused: + try: + self.system.integrator.run(integration_steps) + except Exception as e: + print(e) + os._exit(1) + + # Necessary to regularly drop the Global Interpreter Lock (GIL) + # which prevents freezing of the visualizer under certain + # circumstances (see Issue #3764). + time.sleep(1e-12) + + t = threading.Thread(target=main) + t.daemon = True + t.start() + + self.start()
+ +
[docs] def start(self): + """The blocking start method. + + """ + self._init_opengl() + self._init_espresso_visualization() + self._init_controls() + self._init_OpenGL_callbacks() + self._init_timers() + + # start the blocking main loop + self.glut_main_loop_started = True + OpenGL.GLUT.glutMainLoop()
+ +
[docs] def update(self): + """Update method to be called after integration. + Changes of ESPResSo system can only happen here. + + """ + if self.glut_main_loop_started: + + # update on startup + if not self.hasParticleData: + self._initial_espresso_updates() + self.hasParticleData = True + + # updates + refresh_time = 1. / self.specs['update_fps'] + if (time.time() - self.last_update) > refresh_time: + # update particle/bond data after system propagation, + # or on pause to display particle info + self._update_particles_and_bonds() + + # LB update + if self.specs['LB_draw_velocity_plane']: + self._update_lb_velocity_plane() + + # box_l changed + if not (self.last_box_l == self.system.box_l).all(): + self.last_box_l = np.copy(self.system.box_l) + self._box_size_dependence() + + # keyboard callbacks may change ESPResSo system properties, + # only safe to change here + for c in self.keyboard_manager.userCallbackStack: + c() + self.keyboard_manager.userCallbackStack = [] + + self.last_update = time.time() + + # drag particles + if self.specs['drag_enabled']: + if self.trigger_set_particle_drag and self.drag_id != -1: + self.system.part.by_id( + self.drag_id).ext_force = self.dragExtForce + self.trigger_set_particle_drag = False + elif self.trigger_reset_particle_drag and self.drag_id != -1: + self.system.part.by_id( + self.drag_id).ext_force = self.extForceOld + self.trigger_reset_particle_drag = False + self.drag_id = -1 + + # <escape> key was pressed: wait for ESPResSo to complete current task, + # then call sys exit from main thread + if self.quit_safely: + os._exit(1)
+ + # fetch data on startup + def _initial_espresso_updates(self): + self._update_particles_and_bonds() + if self.has_particle_data['charge']: + self._update_charge_color_range() + if self.specs['draw_constraints']: + self._update_constraints() + if self.specs['draw_cells'] or self.specs['draw_nodes']: + self._update_nodes() + if self.specs['draw_cells']: + self._update_cells() + + def _update_particles_and_bonds(self): + """Fetch particle data from core and put it in the data dicts + used by the visualizer. + + """ + parts_from_core = self.system.part.all() + self._update_particles(parts_from_core) + self._update_bonds(parts_from_core) + + def _update_particles(self, particle_data): + """Updates particle data used for drawing particles. + Do not call directly but use _update_particles_and_bonds()! + + """ + self.particles['pos'] = particle_data.pos_folded + self.particles['type'] = particle_data.type + # particle ids can be discontiguous, therefore create a dict that maps + # particle ids to respective index in data arrays (used by + # _draw_bonds()) + self.index_from_id = { + id: ndx for ndx, id in enumerate( + particle_data.id)} + + if self.has_particle_data['velocity']: + self.particles['velocity'] = particle_data.v + + if self.has_particle_data['force']: + self.particles['force'] = particle_data.f + + if self.has_particle_data['ext_force']: + self.particles['ext_force'] = particle_data.ext_force + + if self.has_particle_data['charge']: + self.particles['charge'] = particle_data.q + + if self.has_particle_data['director']: + self.particles['director'] = particle_data.director + + if self.has_particle_data['node']: + self.particles['node'] = particle_data.node + + if self.info_id != -1: + # data array index of particle with id info_id + info_index = self.index_from_id[self.info_id] + for attr in self.particle_attributes: + self.highlighted_particle[attr] = \ + getattr(particle_data, attr)[info_index] + + def _update_lb_velocity_plane(self): + if self.lb_is_cpu: + self._update_lb_velocity_plane_cpu() + else: + self._update_lb_velocity_plane_gpu() + + def _update_lb_velocity_plane_cpu(self): + agrid = self.lb_params['agrid'] + self.lb_plane_vel = [] + ng = self.specs['LB_plane_ngrid'] + for xi in range(ng): + for xj in range(ng): + pp = np.copy((self.lb_plane_p + xi * 1.0 / ng * self.lb_plane_b1 + + xj * 1.0 / ng * self.lb_plane_b2) % self.system.box_l) + i, j, k = (int(ppp / agrid) for ppp in pp) + lb_vel = np.copy(self.lb[i, j, k].velocity) + self.lb_plane_vel.append([pp, lb_vel]) + + def _update_lb_velocity_plane_gpu(self): + ng = self.specs['LB_plane_ngrid'] + col_pos = [] + for xi in range(ng): + for xj in range(ng): + p = np.array((self.lb_plane_p + xi * 1.0 / ng * self.lb_plane_b1 + + xj * 1.0 / ng * self.lb_plane_b2) % self.system.box_l) + col_pos.append(p) + + lb_vels = self.lb.get_interpolated_fluid_velocity_at_positions( + np.array(col_pos)) + self.lb_plane_vel = [] + for p, v in zip(col_pos, lb_vels): + self.lb_plane_vel.append([p, v]) + + def _update_cells(self): + self.cell_box_origins = [] + cell_system_state = self.system.cell_system.get_state() + # Not all particle decompositions have a cell grid, if + # it does not exist in the cell system state, we just + # ignore it + try: + self.cell_size = cell_system_state['cell_size'] + for i in range(cell_system_state['cell_grid'][0]): + for j in range(cell_system_state['cell_grid'][1]): + for k in range(cell_system_state['cell_grid'][2]): + self.cell_box_origins.append( + np.array([i, j, k]) * self.cell_size) + except KeyError: + pass + + def _update_nodes(self): + self.node_box_origins = [] + self.local_box_l = np.array([0, 0, 0]) + for i in range(self.system.cell_system.node_grid[0]): + for j in range(self.system.cell_system.node_grid[1]): + for k in range(self.system.cell_system.node_grid[2]): + self.node_box_origins.append( + np.array([i, j, k]) * self.local_box_l) + + def _update_constraints(self): + """Collect shapes and interaction type (for coloring) from constraints + and update the list self.shapes with instances of the respective Shape + (or child) classes. + + """ + self.shapes = [] + + # helper functions and shape dictionary + def unpack_shapes(shapes_list): + """Return a list of shapes, where all unions have been unpacked. + + """ + shapes = [] + try: + # recursively unpack unions + for shape in shapes_list: + shapes.extend(unpack_shapes(shape)) + except TypeError: + # otherwise just append the shape + shapes.append(shapes_list) + return shapes + + def shape_arguments(shape, part_type): + """Helper function returning argument list for initialization of + Shape class (or respective child classes). + + """ + arguments = [ + shape, part_type, + self._modulo_indexing(self.specs['constraint_type_colors'], + part_type), + self.materials[self._modulo_indexing( + self.specs['constraint_type_materials'], part_type)], + self.specs['quality_constraints'], self.system.box_l, + self.specs['rasterize_resolution'], + self.specs['rasterize_pointsize'] + ] + return arguments + + shape_mapping = { + 'Shapes::Cylinder': Cylinder, + 'Shapes::Ellipsoid': Ellipsoid, + 'Shapes::HollowConicalFrustum': HollowConicalFrustum, + 'Shapes::SimplePore': SimplePore, + 'Shapes::Slitpore': Slitpore, + 'Shapes::Sphere': Sphere, + 'Shapes::SpheroCylinder': Spherocylinder, + 'Shapes::Wall': Wall + } + + # collect shapes using the helper functions + for constraint in self.system.constraints: + if isinstance(constraint, + espressomd.constraints.ShapeBasedConstraint): + part_type = constraint.get_parameter('particle_type') + shape = constraint.get_parameter('shape') + for sub_shape in unpack_shapes(shape): + arguments = shape_arguments(sub_shape, part_type) + try: + self.shapes.append( + shape_mapping[sub_shape.name()](*arguments)) + except KeyError: + self.shapes.append(Shape(*arguments)) + + if self.specs['LB_draw_boundaries']: + ni = 0 + for constraint in self.system.lbboundaries: + if isinstance(constraint, espressomd.lbboundaries.LBBoundary): + part_type = ni + ni += 1 + shape = constraint.get_parameter('shape') + for sub_shape in unpack_shapes(shape): + arguments = shape_arguments(sub_shape, part_type) + try: + self.shapes.append( + shape_mapping[sub_shape.name()](*arguments)) + except KeyError: + self.shapes.append(Shape(*arguments)) + + def _update_bonds(self, particle_data): + """Update bond data used for drawing bonds. + Do not call directly but use + :meth:`~espressomd.visualization_opengl.openGLLive._update_particles_and_bonds`! + + Updates data array ``self.bonds[]``; structure of elements is: + ``[<id of first bond partner>, <id of second bond partner>, <bond type>]`` + + """ + if self.specs['draw_bonds']: + self.bonds = [] + for particle in particle_data: + for bond in particle.bonds: + # input data: + # bond[0]: bond type, bond[1:] bond partners + bond_type = bond[0].type_number() + if len(bond) == 4: + self.bonds.append([particle.id, bond[1], bond_type]) + self.bonds.append([particle.id, bond[2], bond_type]) + self.bonds.append([bond[2], bond[3], bond_type]) + else: + for bond_partner in bond[1:]: + self.bonds.append( + [particle.id, bond_partner, bond_type]) + + def _draw_text(self, x, y, text, color, + font=OpenGL.GLUT.GLUT_BITMAP_9_BY_15): + OpenGL.GL.glColor(color) + OpenGL.GL.glWindowPos2f(x, y) + for ch in text: + OpenGL.GLUT.glutBitmapCharacter(font, ctypes.c_int(ord(ch))) + + # draw called automatically from GLUT display function + def _draw_system(self): + if self.specs['LB_draw_velocity_plane']: + self._draw_lb_vel() + + if self.specs['draw_axis']: + axis_fac = 0.2 + axis_r = np.min(self.system.box_l) / 50.0 + draw_arrow([0, 0, 0], [self.system.box_l[0] * axis_fac, 0, 0], axis_r, + [1, 0, 0, 1], self.materials['chrome'], self.specs['quality_arrows']) + draw_arrow([0, 0, 0], [0, self.system.box_l[2] * axis_fac, 0], axis_r, + [0, 1, 0, 1], self.materials['chrome'], self.specs['quality_arrows']) + draw_arrow([0, 0, 0], [0, 0, self.system.box_l[2] * axis_fac], axis_r, + [0, 0, 1, 1], self.materials['chrome'], self.specs['quality_arrows']) + + if self.specs['draw_bonds']: + self._draw_bonds() + self._draw_system_particles() + + if self.specs['draw_constraints']: + self._draw_constraints() + + if self.specs['draw_box']: + self._draw_system_box() + if self.specs['draw_nodes']: + self._draw_nodes() + if self.specs['draw_cells']: + self._draw_cells() + if self.specs['LB_draw_nodes'] or self.specs['LB_draw_node_boundaries']: + self._draw_lb_grid() + + def _draw_system_box(self): + draw_box([0, 0, 0], self.system.box_l, self.inverse_bg_color, + self.materials['medium'], 2.0 * self.line_width_fac) + + def _draw_nodes(self): + for n in self.node_box_origins: + draw_box(n, self.local_box_l, self.node_box_color, + self.materials['transparent1'], 1.5 * self.line_width_fac) + + def _draw_cells(self): + for n in self.node_box_origins: + for c in self.cell_box_origins: + draw_box( + c + n, self.cell_size, self.cell_box_color, + self.materials['transparent1'], 0.75 * self.line_width_fac) + + def _draw_lb_grid(self): + a = self.lb_params['agrid'] + cell_size = np.array([a] * 3) + dims = np.rint(np.array(self.system.box_l) / a) + for i in range(int(dims[0])): + for j in range(int(dims[1])): + for k in range(int(dims[2])): + n = np.array([i, j, k]) * cell_size + if self.specs['LB_draw_node_boundaries'] \ + and self.lb[i, j, k].boundary: + draw_box(n, cell_size, self.lb_box_color_boundary, + self.materials['transparent2'], 5.0) + if self.specs['LB_draw_nodes'] \ + and not self.lb[i, j, k].boundary: + draw_box(n, cell_size, self.lb_box_color, + self.materials['transparent2'], 1.5) + + def _draw_constraints(self): + + # clip borders of simulation box + for i in range(6): + OpenGL.GL.glEnable(OpenGL.GL.GL_CLIP_PLANE0 + i) + OpenGL.GL.glClipPlane(OpenGL.GL.GL_CLIP_PLANE0 + i, + self.box_eqn[i, :]) + + for shape in self.shapes: + shape.draw() + + for i in range(6): + OpenGL.GL.glDisable(OpenGL.GL.GL_CLIP_PLANE0 + i) + + def _determine_radius(self, part_type): + def radius_by_lj(part_type): + ia = self.system.non_bonded_inter[part_type, part_type] + radius = 0.0 + if hasattr(ia, "lennard_jones"): + radius = ia.lennard_jones.get_params()["sigma"] * 0.5 + if radius == 0.0 and hasattr(ia, "wca"): + radius = ia.wca.get_params()["sigma"] * 0.5 + if radius == 0.0: + radius = 0.5 + return radius + + if self.specs['particle_sizes'] == 'auto': + radius = radius_by_lj(part_type) + elif callable(self.specs['particle_sizes']): + radius = self.specs['particle_sizes'](part_type) + else: + try: + radius = self._modulo_indexing( + self.specs['particle_sizes'], part_type) + except RuntimeError: + radius = self.radius_by_lj(part_type) + return radius + + def _draw_system_particles(self, color_by_id=False): + part_type = -1 + reset_material = False + + for part_id, index in self.index_from_id.items(): + part_type_last = part_type + part_type = int(self.particles['type'][index]) + + # Only change material if type/charge has changed, color_by_id or + # material was reset by arrows + if reset_material or color_by_id or part_type != part_type_last or \ + part_id == self.drag_id or part_id == self.info_id or \ + self.specs['particle_coloring'] == 'node': + reset_material = False + + radius = self._determine_radius(part_type) + + m = self._modulo_indexing( + self.specs['particle_type_materials'], part_type) + material = self.materials[m] + + if color_by_id: + color = self._id_to_fcolor(part_id) + OpenGL.GL.glColor(color) + else: + if self.specs['particle_coloring'] == 'auto': + # Color auto: Charge then Type + if self.has_particle_data['charge'] and self.particles['charge'][index] != 0: + color = self._color_by_charge( + self.particles['charge'][index]) + reset_material = True + else: + color = self._modulo_indexing( + self.specs['particle_type_colors'], part_type) + elif self.specs['particle_coloring'] == 'charge': + color = self._color_by_charge( + self.particles['charge'][index]) + reset_material = True + elif self.specs['particle_coloring'] == 'type': + color = self._modulo_indexing( + self.specs['particle_type_colors'], part_type) + elif self.specs['particle_coloring'] == 'node': + color = self._modulo_indexing( + self.specs['particle_type_colors'], self.particles['node'][index]) + else: + raise ValueError( + f"Cannot process particle_coloring={self.specs['particle_coloring']}") + + # Invert color of highlighted particle + if part_id == self.drag_id or part_id == self.info_id: + reset_material = True + color = [1. - color[0], 1. - color[1], 1. - color[2]] + + set_solid_material(color, material) + + # Create a new display list, used until next material/color + # change + OpenGL.GL.glNewList(self.dl_sphere, OpenGL.GL.GL_COMPILE) + OpenGL.GLUT.glutSolidSphere( + radius, self.specs['quality_particles'], self.specs['quality_particles']) + OpenGL.GL.glEndList() + + self._redraw_sphere(self.particles['pos'][index]) + + if self.has_images: + for imx, imy, imz in itertools.product(*self.image_vectors): + if imx != 0 or imy != 0 or imz != 0: + offset = [imx, imy, imz] * self.system.box_l + self._redraw_sphere( + self.particles['pos'][index] + offset) + + if espressomd.has_features('EXTERNAL_FORCES'): + if self.specs['ext_force_arrows'] or part_id == self.drag_id: + if any(v != 0 for v in self.particles['ext_force'][index]): + if part_id == self.drag_id: + sc = 1 + else: + sc = self._modulo_indexing( + self.specs['ext_force_arrows_type_scale'], part_type) + if sc > 0: + arrow_col = self._modulo_indexing( + self.specs['ext_force_arrows_type_colors'], part_type) + arrow_radius = self._modulo_indexing( + self.specs['ext_force_arrows_type_radii'], part_type) + draw_arrow(self.particles['pos'][index], np.array( + self.particles['ext_force'][index]) * sc, arrow_radius, arrow_col, + self.materials['chrome'], self.specs['quality_arrows']) + reset_material = True + + if self.specs['velocity_arrows']: + self._draw_arrow_property( + part_id, part_type, self.specs['velocity_arrows_type_scale'], + self.specs['velocity_arrows_type_colors'], + self.specs['velocity_arrows_type_materials'], + self.specs['velocity_arrows_type_radii'], 'velocity') + reset_material = True + + if self.specs['force_arrows']: + self._draw_arrow_property( + part_id, part_type, self.specs['force_arrows_type_scale'], + self.specs['force_arrows_type_colors'], + self.specs['force_arrows_type_materials'], + self.specs['force_arrows_type_radii'], 'force') + reset_material = True + + if self.specs['director_arrows']: + self._draw_arrow_property( + part_id, part_type, self.specs['director_arrows_type_scale'], + self.specs['director_arrows_type_colors'], + self.specs['director_arrows_type_materials'], + self.specs['director_arrows_type_radii'], 'director') + reset_material = True + + def _draw_arrow_property(self, part_id, part_type, type_scale, + type_colors, type_materials, type_radii, prop): + sc = self._modulo_indexing(type_scale, part_type) + if sc > 0: + v = self.particles[prop][self.index_from_id[part_id]] + col = self._modulo_indexing(type_colors, part_type) + radius = self._modulo_indexing(type_radii, part_type) + material = self._modulo_indexing(type_materials, part_type) + draw_arrow(self.particles['pos'][self.index_from_id[part_id]], + np.array(v, dtype=float) * sc, radius, col, + self.materials[material], self.specs['quality_arrows']) + + def _draw_bonds(self): + half_box_l = self.system.box_l / 2.0 + quality_bonds = self.specs['quality_bonds'] + for b in self.bonds: + col = self._modulo_indexing(self.specs['bond_type_colors'], b[2]) + mat = self.materials[self._modulo_indexing( + self.specs['bond_type_materials'], b[2])] + radius = self._modulo_indexing( + self.specs['bond_type_radius'], b[2]) + # if particles are deleted in the core, index_from_id might + # throw a KeyError -- e. g. when deleting a bond created by + # collision_detection (using virtual site particles) + try: + x_a = self.particles['pos'][self.index_from_id[b[0]]] + x_b = self.particles['pos'][self.index_from_id[b[1]]] + except Exception: + # skip this bond + continue + dx = x_b - x_a + + if np.all(np.abs(dx) < half_box_l): + # bond completely inside box + draw_cylinder(x_a, x_b, radius, col, mat, quality_bonds) + if self.has_images: + for imx, imy, imz in itertools.product( + *self.image_vectors): + if imx != 0 or imy != 0 or imz != 0: + offset = [imx, imy, imz] * self.system.box_l + draw_cylinder(x_a + offset, x_b + offset, radius, + col, mat, quality_bonds) + else: + # bond crosses the box boundaries + d = self._cut_bond(x_a, dx) + if d is np.inf: + continue + + s_a = x_a + d * dx + s_b = x_b - (1 - d) * dx + draw_cylinder(x_a, s_a, radius, col, mat, quality_bonds) + draw_cylinder(x_b, s_b, radius, col, mat, quality_bonds) + + if self.has_images: + for imx, imy, imz in itertools.product( + *self.image_vectors): + if imx != 0 or imy != 0 or imz != 0: + offset = [imx, imy, imz] * self.system.box_l + draw_cylinder(x_a + offset, s_a + offset, radius, + col, mat, quality_bonds) + draw_cylinder(x_b + offset, s_b + offset, radius, + col, mat, quality_bonds) + + def _redraw_sphere(self, pos): + OpenGL.GL.glPushMatrix() + OpenGL.GL.glTranslatef(pos[0], pos[1], pos[2]) + OpenGL.GL.glCallList(self.dl_sphere) + OpenGL.GL.glPopMatrix() + + # helper to draw periodic bonds + def _cut_bond(self, x_a, dx): + """ + Algorithm for the line-plane intersection problem. Given the unfolded + positions of two particles, determine: 1) the box image that minimizes + the folded bond length, 2) which side of the simulation box is crossed + by the bond, 3) how much of the bond is inside the unit cell starting + from the first particle. That scalar is returned by the function, and + can be used to calculate the coordinates of the line-plane + intersection point. The algorithm can be found at + https://en.wikipedia.org/w/index.php?title=Line%E2%80%93plane_intersection&oldid=940427752#Algebraic_form + """ + # corner case: the two particles occupy the same position + if np.dot(dx, dx) < 1e-9: + return np.inf + # find the box image that minimizes the unfolded bond length + shift = np.rint(dx / self.system.box_l) + # get the unfolded bond vector + dx -= shift * self.system.box_l + # find which side of the simulation box is crossed by the bond + best_d = np.inf + for i in range(3): + if dx[i] == 0: + continue # corner case: bond is parallel to a face + elif dx[i] > 0: + p0_i = self.system.box_l[i] + else: + p0_i = 0 + # calculate the length of the bond that is inside the box using + # an optimized version of `np.dot(p0 - x0, n) / np.dot(dx, n)` + # where the dot products decay to an array access, because `n` + # is always a unit vector in rectangular boxes and its sign + # is canceled out by the division + d = (p0_i - x_a[i]) / dx[i] + if d < best_d: + best_d = d + return best_d + + # arrows in a plane for LB velocities + def _draw_lb_vel(self): + + for lb_pos, lb_vel in self.lb_plane_vel: + draw_arrow( + lb_pos, + lb_vel * self.specs['LB_vel_scale'], + self.lb_arrow_radius, + self.specs['LB_arrow_color'], + self.materials[self.specs['LB_arrow_material']], + self.specs['LB_arrow_quality']) + + # use modulo if there are more particle types than type definitions for + # colors, materials etc. + @staticmethod + def _modulo_indexing(l, t): + return l[t % len(l)] + + # fade particle charge color from white (q=0) to plus_color (q=q_max) resp + # minus_color (q=q_min) + def _color_by_charge(self, q): + if q < 0.: + c = q / self.min_q + minus_color = self.specs['particle_charge_colors'][0] + return (1. - c) * np.ones(3) + c * np.array(minus_color) + else: + c = q / self.max_q + plus_color = self.specs['particle_charge_colors'][1] + return (1. - c) * np.ones(3) + c * np.array(plus_color) + + # on initialization, check q_max/q_min + def _update_charge_color_range(self): + if len(self.particles['charge'][:]) > 0: + self.min_q = min(self.particles['charge'][:]) + self.max_q = max(self.particles['charge'][:]) + + def _handle_screenshot(self): + if self.take_screenshot: + self.take_screenshot = False + script_name = os.path.splitext(sys.argv[0])[0] + + i = 0 + while os.path.exists(f"{script_name}_{i:04d}.png"): + i += 1 + file_name = f"{script_name}_{i:04d}.png" + + self._make_screenshot(file_name) + + self.screenshot_captured = True + self.screenshot_capture_time = time.time() + self.screenshot_capture_txt = f"Saved screenshot {file_name}" + + def _make_screenshot(self, filepath): + data = OpenGL.GL.glReadPixels(0, 0, self.specs['window_size'][0], + self.specs['window_size'][1], + OpenGL.GL.GL_RGB, OpenGL.GL.GL_FLOAT) + data = np.flipud(data.reshape((data.shape[1], data.shape[0], 3))) + matplotlib.pyplot.imsave(filepath, data) + + def _display_all(self): + + OpenGL.GL.glClear( + OpenGL.GL.GL_COLOR_BUFFER_BIT | OpenGL.GL.GL_DEPTH_BUFFER_BIT) + + OpenGL.GL.glLoadMatrixf(self.camera.modelview) + + self._set_camera_spotlight() + + self._draw_system() + self._draw_texts() + + OpenGL.GLUT.glutSwapBuffers() + + self._handle_screenshot() + + def _draw_texts(self): + + # draw user text + for (x, y), text in self.user_texts: + self._draw_text(x, y, text, self.text_color) + + # draw fps text + if self.specs['draw_fps']: + t = time.time() + if t - self.fps_last > 1.0: + self.fps_last = t + self.fps = self.fps_count + self.fps_count = 0 + + self._draw_text(10, 10, f"{self.fps} fps", self.text_color) + self._draw_text(10, 30, f"{1000.0 / self.fps} ms/frame", + self.text_color) + self.fps_count += 1 + + # draw particle info + if self.show_system_info: + self._draw_sysinfo_dict(self.system_info) + elif self.info_id != -1: + self._draw_particle_dict( + self.highlighted_particle, self.max_len_attr) + + # indicate screen capture + if self.screenshot_captured and not self.take_screenshot: + col = np.array(self.text_color) + ts = time.time() - self.screenshot_capture_time + fadetime = 2.0 + col[3] = 1.0 - ts / fadetime + if ts > fadetime: + self.screenshot_captured = False + else: + self._draw_text( + self.specs['window_size'][0] - len( + self.screenshot_capture_txt) * 9.0 - 15, + self.specs['window_size'][1] - 15, self.screenshot_capture_txt, col) + + def _draw_sysinfo_dict(self, sysinfo_dict): + y = 0 + for key, value_list in sysinfo_dict.items(): + # category title + self._draw_text(10, self.specs['window_size'][1] - 10 - 15 * y, + f"{key}:", self.text_color) + # item list + for item in value_list: + txt = str(item) + n_lines = int( + len(txt) * 9.0 / self.specs['window_size'][0]) + 1 + chars_per_line = int(self.specs['window_size'][0] / 9) - 4 + if chars_per_line < 20: + break + ls = 0 + for _ in range(n_lines): + y += 1 + line_txt = txt[ls:ls + chars_per_line] + self._draw_text( + 30, self.specs['window_size'][1] - 10 - 15 * y, + line_txt, self.text_color) + ls += chars_per_line + y += 1.5 + + def _draw_particle_dict(self, particle_dict, max_len): + y = 0 + for k, v in particle_dict.items(): + txt = f"{k} {(max_len - len(k)) * ' '} {v}" + self._draw_text(10, self.specs['window_size'][1] - 10 - 15 * y, + txt, self.text_color) + y += 1 + + # called on window position/size change + def _reshape_window(self, w, h): + OpenGL.GL.glViewport(0, 0, w, h) + OpenGL.GL.glMatrixMode(OpenGL.GL.GL_PROJECTION) + OpenGL.GL.glLoadIdentity() + box_diag = np.linalg.norm(self.system.box_l) + OpenGL.GLU.gluPerspective(40, 1.0 * w / h, + self.specs['close_cut_distance'], + self.specs['far_cut_distance'] * box_diag) + OpenGL.GL.glMatrixMode(OpenGL.GL.GL_MODELVIEW) + self.specs['window_size'][0] = w + self.specs['window_size'][1] = h + + # inits for GLUT functions + def _init_OpenGL_callbacks(self): + # OpenGL callbacks + def display(): + if self.hasParticleData and self.glut_main_loop_started: + self._display_all() + + # pylint: disable=unused-argument + def keyboard_up(button, x, y): + if isinstance(button, bytes): + button = button.decode("utf-8") + self.keyboard_manager.keyboard_up(button) + + # pylint: disable=unused-argument + def keyboard_down(button, x, y): + if isinstance(button, bytes): + button = button.decode("utf-8") + self.keyboard_manager.keyboard_down(button) + + def mouse(button, state, x, y): + self.mouse_manager.mouse_click(button, state, x, y) + + def motion(x, y): + self.mouse_manager.mouse_move(x, y) + + def redraw_on_idle(): + # don't repost faster than 60 fps + if (time.time() - self.last_draw) > 1.0 / 60.0: + OpenGL.GLUT.glutPostRedisplay() + self.last_draw = time.time() + + def reshape_callback(w, h): + self._reshape_window(w, h) + + def close_window(): + os._exit(1) + + OpenGL.GLUT.glutDisplayFunc(display) + OpenGL.GLUT.glutMouseFunc(mouse) + OpenGL.GLUT.glutKeyboardFunc(keyboard_down) + OpenGL.GLUT.glutKeyboardUpFunc(keyboard_up) + OpenGL.GLUT.glutSpecialFunc(keyboard_down) + OpenGL.GLUT.glutSpecialUpFunc(keyboard_up) + OpenGL.GLUT.glutReshapeFunc(reshape_callback) + OpenGL.GLUT.glutMotionFunc(motion) + OpenGL.GLUT.glutWMCloseFunc(close_window) + OpenGL.GLUT.glutIdleFunc(redraw_on_idle) + + def _init_timers(self): + """ + Starts infinite loops of timed function callbacks. + + Using `OpenGL.GLUT.glutTimerFunc()` a timed function callback is + registered that after (at least) the specified time calls a + specific function, which re-registers a timed callback to itself + plus does some other stuff. + Per callback registered in `self.timers`, one such infinite + callback loop is started. + In addition, potential keyboard input is handled every (at least) + 17 ms, corresponding to a rate of ~60 1/s. + + """ + + # timers for register_callback + def dummy_timer(index): + self.timers[index][1]() + OpenGL.GLUT.glutTimerFunc( + self.timers[index][0], dummy_timer, index) + + for index, timer in enumerate(self.timers): + OpenGL.GLUT.glutTimerFunc(timer[0], dummy_timer, index) + + # handle input with 60 fps + # pylint: disable=unused-argument + def timed_handle_input(data): + self.keyboard_manager.handle_input() + OpenGL.GLUT.glutTimerFunc(17, timed_handle_input, -1) + + OpenGL.GLUT.glutTimerFunc(17, timed_handle_input, -1) + + # click on particle: drag; click on background: change camera angle. + def _mouse_motion(self, mouse_pos, mouse_pos_old, mouse_button_state): + + if self.specs['drag_enabled'] and self.drag_id != -1: + part_pos = self.particles['pos'][self.drag_id] + viewport = OpenGL.GL.glGetIntegerv(OpenGL.GL.GL_VIEWPORT) + mouse_world = OpenGL.GLU.gluUnProject( + mouse_pos[0], viewport[3] - mouse_pos[1], self.depth) + + self.dragExtForce = self.specs['drag_force'] * \ + (np.asarray(mouse_world) - np.array(part_pos)) + self.trigger_set_particle_drag = True + else: + self.camera.rotate_camera(mouse_pos, mouse_pos_old, + mouse_button_state) + + # re-draw scene without light to identify particle id by pixel color + def _get_particle_id(self, pos): + + OpenGL.GL.glClearColor(0.0, 0.0, 0.0, 1.0) + OpenGL.GL.glClear( + OpenGL.GL.GL_COLOR_BUFFER_BIT | OpenGL.GL.GL_DEPTH_BUFFER_BIT) + + OpenGL.GL.glLoadMatrixf(self.camera.modelview) + + OpenGL.GL.glDisable(OpenGL.GL.GL_LIGHTING) + OpenGL.GL.glDisable(OpenGL.GL.GL_LIGHT0) + if self.specs['spotlight_enabled']: + OpenGL.GL.glDisable(OpenGL.GL.GL_LIGHT1) + self._draw_system_particles(color_by_id=True) + viewport = OpenGL.GL.glGetIntegerv(OpenGL.GL.GL_VIEWPORT) + + read_pixel = OpenGL.GL.glReadPixelsui( + pos[0], viewport[3] - pos[1], 1, 1, + OpenGL.GL.GL_RGB, OpenGL.GL.GL_FLOAT)[0][0] + depth = OpenGL.GL.glReadPixelsf( + pos[0], viewport[3] - pos[1], 1, 1, + OpenGL.GL.GL_DEPTH_COMPONENT, OpenGL.GL.GL_FLOAT)[0][0] + + part_id = self._fcolor_to_id(read_pixel) + + OpenGL.GL.glEnable(OpenGL.GL.GL_LIGHTING) + OpenGL.GL.glEnable(OpenGL.GL.GL_LIGHT0) + if self.specs['spotlight_enabled']: + OpenGL.GL.glEnable(OpenGL.GL.GL_LIGHT1) + OpenGL.GL.glClearColor(self.specs['background_color'][0], + self.specs['background_color'][1], + self.specs['background_color'][2], 1.) + + return part_id, depth + + @staticmethod + def _id_to_fcolor(part_id): + part_id += 1 + return [int(part_id / 256 ** 2) / 255.0, + int((part_id % 256 ** 2) / 256) / 255.0, + (part_id % 256) / 255.0, 1.0] + + @staticmethod + def _fcolor_to_id(fcolor): + if (fcolor == [0, 0, 0]).all(): + return -1 + return int(fcolor[0] * 255) * 256 ** 2 + \ + int(fcolor[1] * 255) * 256 + \ + int(fcolor[2] * 255) - 1 + + # pylint: disable=unused-argument + def _set_particle_drag(self, pos, pos_old): + part_id, depth = self._get_particle_id(pos) + self.drag_id = part_id + + if part_id != -1: + self.dragPosInitial = self.particles['pos'][self.drag_id] + self.extForceOld = self.particles['ext_force'][self.drag_id][:] + self.depth = depth + + # pylint: disable=unused-argument + def _reset_particle_drag(self, pos, pos_old): + if self.drag_id != -1: + self.trigger_reset_particle_drag = True + + def _get_particle_info(self, pos, pos_old): + part_id, _ = self._get_particle_id(pos) + if self.show_system_info: + self.show_system_info = False + elif part_id == -1 and self.info_id == -1: + self.show_system_info = True + self.update_system_info() + self.info_id = part_id + + def _next_particle_info(self): + self.info_id = (self.info_id + 1) % len(self.particles['pos']) + + def _previous_particle_info(self): + self.info_id = (self.info_id - 1) % len(self.particles['pos']) + + def _init_espresso_visualization(self): + # initialize properties that depend on the ESPResSo system + self.max_q = 0. + self.min_q = 0. + + self.drag_id = -1 + self.info_id = -1 + self.show_system_info = False + self.dragPosInitial = [] + self.extForceOld = [] + self.dragExtForceOld = [] + self.trigger_reset_particle_drag = False + self.trigger_set_particle_drag = False + + self.depth = 0 + + # LOOK FOR LB ACTOR + lb_types = [espressomd.lb.LBFluid] + if espressomd.has_features('CUDA'): + lb_types.append(espressomd.lb.LBFluidGPU) + for actor in self.system.actors: + if isinstance(actor, tuple(lb_types)): + self.lb_params = actor.get_params() + self.lb = actor + self.lb_is_cpu = isinstance(actor, espressomd.lb.LBFluid) + break + + if self.specs['LB_draw_velocity_plane']: + if self.specs['LB_plane_axis'] == 0: + pn = [1.0, 0.0, 0.0] + self.lb_plane_b1 = [0.0, 1.0, 0.0] + self.lb_plane_b2 = [0.0, 0.0, 1.0] + elif self.specs['LB_plane_axis'] == 1: + pn = [0.0, 1.0, 0.0] + self.lb_plane_b1 = [1.0, 0.0, 0.0] + self.lb_plane_b2 = [0.0, 0.0, 1.0] + else: + pn = [0.0, 0.0, 1.0] + self.lb_plane_b1 = [1.0, 0.0, 0.0] + self.lb_plane_b2 = [0.0, 1.0, 0.0] + + self.lb_plane_b1 *= self.system.box_l + self.lb_plane_b2 *= self.system.box_l + self.lb_plane_p = np.array(pn) * self.specs['LB_plane_dist'] + + self.lb_arrow_radius = self.system.box_l[ + self.specs['LB_plane_axis']] * self.specs['LB_vel_radius_scale'] + + self.lb_min_vel = np.array([-1e-6] * 3) + self.lb_max_vel = np.array([1e-6] * 3) + self.lb_vel_range = self.lb_max_vel - self.lb_min_vel + self.lb_min_dens = np.array([0] * 3) + self.lb_max_dens = np.array([0] * 3) + + self._update_lb_velocity_plane() + + self._box_size_dependence() + + def _box_size_dependence(self): + # initialize properties that depend on the box geometry + + if self.specs['draw_cells'] or self.specs['draw_nodes']: + self._update_nodes() + if self.specs['draw_cells']: + self._update_cells() + + self.box_eqn = np.full((6, 4), np.nan) + # set face normals of box + self.box_eqn[:3, :3] = np.identity(3) + self.box_eqn[3:, :3] = -np.identity(3) + # set face parameters of box + self.box_eqn[:3, 3] = 0.001 * self.system.box_l + self.box_eqn[3:, 3] = 1.001 * self.system.box_l + + self.camera.center = np.array(self.system.box_l) * 0.5 + self.camera.update_modelview() + + def _init_controls(self): + # initialize mouse/keyboard event listeners + + # mouse look/rotate/drag + self.mouse_manager.register_button(MouseButtonEvent( + None, MouseFireEvent.FreeMotion, self._mouse_motion)) + + self.mouse_manager.register_button(MouseButtonEvent( + 3, MouseFireEvent.ButtonPressed, self.camera.move_backward)) + + self.mouse_manager.register_button(MouseButtonEvent( + 4, MouseFireEvent.ButtonPressed, self.camera.move_forward)) + + # left mouse button to start/stop drag + if self.specs['drag_enabled']: + self.mouse_manager.register_button(MouseButtonEvent( + OpenGL.GLUT.GLUT_LEFT_BUTTON, MouseFireEvent.ButtonPressed, self._set_particle_drag, True)) + self.mouse_manager.register_button(MouseButtonEvent( + OpenGL.GLUT.GLUT_LEFT_BUTTON, MouseFireEvent.ButtonReleased, self._reset_particle_drag, True)) + + # left mouse button for particle information + self.mouse_manager.register_button(MouseButtonEvent( + OpenGL.GLUT.GLUT_LEFT_BUTTON, MouseFireEvent.DoubleClick, self._get_particle_info, True)) + + # left/right arrows to cycle through particles + self.keyboard_manager.register_button(KeyboardButtonEvent( + OpenGL.GLUT.GLUT_KEY_LEFT, KeyboardFireEvent.Pressed, self._previous_particle_info)) + self.keyboard_manager.register_button(KeyboardButtonEvent( + OpenGL.GLUT.GLUT_KEY_RIGHT, KeyboardFireEvent.Pressed, self._next_particle_info)) + + # <space> key to pause integration thread + self.keyboard_manager.register_button(KeyboardButtonEvent( + ' ', KeyboardFireEvent.Pressed, self._pause, True)) + + # <return> key to take screenshot + self.keyboard_manager.register_button(KeyboardButtonEvent( + '\x0d', KeyboardFireEvent.Pressed, self._trigger_screenshot, True)) + + # <escape> key to quit + self.keyboard_manager.register_button(KeyboardButtonEvent( + '\x1b', KeyboardFireEvent.Pressed, self._quit, True)) + + # camera control via keyboard + self.keyboard_manager.register_button(KeyboardButtonEvent( + 'w', KeyboardFireEvent.Hold, self.camera.move_up, True)) + self.keyboard_manager.register_button(KeyboardButtonEvent( + 's', KeyboardFireEvent.Hold, self.camera.move_down, True)) + self.keyboard_manager.register_button(KeyboardButtonEvent( + 'a', KeyboardFireEvent.Hold, self.camera.move_left, True)) + self.keyboard_manager.register_button(KeyboardButtonEvent( + 'd', KeyboardFireEvent.Hold, self.camera.move_right, True)) + self.keyboard_manager.register_button(KeyboardButtonEvent( + 'e', KeyboardFireEvent.Hold, self.camera.rotate_system_XR, True)) + self.keyboard_manager.register_button(KeyboardButtonEvent( + 'q', KeyboardFireEvent.Hold, self.camera.rotate_system_XL, True)) + self.keyboard_manager.register_button(KeyboardButtonEvent( + 'c', KeyboardFireEvent.Hold, self.camera.rotate_system_YR, True)) + self.keyboard_manager.register_button(KeyboardButtonEvent( + 'z', KeyboardFireEvent.Hold, self.camera.rotate_system_YL, True)) + self.keyboard_manager.register_button(KeyboardButtonEvent( + 'r', KeyboardFireEvent.Hold, self.camera.rotate_system_ZR, True)) + self.keyboard_manager.register_button(KeyboardButtonEvent( + 'f', KeyboardFireEvent.Hold, self.camera.rotate_system_ZL, True)) + self.keyboard_manager.register_button(KeyboardButtonEvent( + 't', KeyboardFireEvent.Hold, self.camera.move_forward, True)) + self.keyboard_manager.register_button(KeyboardButtonEvent( + 'g', KeyboardFireEvent.Hold, self.camera.move_backward, True)) + + def _quit(self): + self.quit_safely = True + + def _pause(self): + self.paused = not self.paused + + def _trigger_screenshot(self): + self.take_screenshot = True + + # asynchronous parallel calls to glLight() causes segfaults, so only change + # light at central display() method and trigger changes + def _set_camera_spotlight(self): + if self.specs['spotlight_enabled']: + p = self.camera.cam_pos + fp = [p[0], p[1], p[2], 1] + OpenGL.GL.glLightfv(OpenGL.GL.GL_LIGHT1, OpenGL.GL.GL_POSITION, fp) + OpenGL.GL.glLightfv( + OpenGL.GL.GL_LIGHT1, + OpenGL.GL.GL_SPOT_DIRECTION, + self.camera.state_target) + + def _init_camera(self): + b = np.array(self.system.box_l) + box_diag = np.linalg.norm(b) + box_center = b * 0.5 + if self.specs['camera_position'] == 'auto': + cp = [box_center[0], box_center[1], b[2] * 3] + else: + cp = self.specs['camera_position'] + + if self.specs['camera_target'] == 'auto': + ct = box_center + else: + ct = self.specs['camera_target'] + + cr = np.array(self.specs['camera_right']) + + self._set_camera_spotlight() + + return Camera(cam_pos=np.array(cp), cam_target=ct, cam_right=cr, + move_speed=0.5 * box_diag / 17.0, center=box_center) + + def _init_opengl(self): + OpenGL.GLUT.glutInit(self.specs['name']) + OpenGL.GLUT.glutInitDisplayMode( + OpenGL.GLUT.GLUT_DOUBLE | OpenGL.GLUT.GLUT_RGB | OpenGL.GLUT.GLUT_DEPTH) + + OpenGL.GLUT.glutInitWindowSize(self.specs['window_size'][0], + self.specs['window_size'][1]) + + OpenGL.GLUT.glutCreateWindow(b"ESPResSo visualization") + + OpenGL.GL.glClearColor(self.specs['background_color'][0], + self.specs['background_color'][1], + self.specs['background_color'][2], 1.) + + OpenGL.GL.glEnable(OpenGL.GL.GL_BLEND) + OpenGL.GL.glBlendFunc( + OpenGL.GL.GL_SRC_ALPHA, + OpenGL.GL.GL_ONE_MINUS_SRC_ALPHA) + + OpenGL.GL.glEnable(OpenGL.GL.GL_POINT_SMOOTH) + OpenGL.GL.glEnable(OpenGL.GL.GL_LINE_SMOOTH) + OpenGL.GL.glHint(OpenGL.GL.GL_LINE_SMOOTH_HINT, OpenGL.GL.GL_NICEST) + + # bad for transparent particles + # OpenGL.GL.glEnable(OpenGL.GL.GL_CULL_FACE) + # OpenGL.GL.glCullFace(OpenGL.GL.GL_BACK) + + OpenGL.GL.glLineWidth(2.0) + OpenGL.GLUT.glutIgnoreKeyRepeat(1) + + # setup lighting + if self.specs['light_size'] == 'auto': + box_diag = np.linalg.norm(self.system.box_l) + self.specs['light_size'] = box_diag * 2.0 + + OpenGL.GL.glEnable(OpenGL.GL.GL_DEPTH_TEST) + OpenGL.GL.glEnable(OpenGL.GL.GL_LIGHTING) + + # LIGHT0 + if self.specs['light_pos'] != 'auto': + OpenGL.GL.glLightfv(OpenGL.GL.GL_LIGHT0, OpenGL.GL.GL_POSITION, + np.array(self.specs['light_pos']).tolist()) + else: + OpenGL.GL.glLightfv(OpenGL.GL.GL_LIGHT0, OpenGL.GL.GL_POSITION, + (np.array(self.system.box_l) * 1.1).tolist()) + + OpenGL.GL.glLightfv( + OpenGL.GL.GL_LIGHT0, + OpenGL.GL.GL_AMBIENT, + self.specs['light_colors'][0]) + OpenGL.GL.glLightfv( + OpenGL.GL.GL_LIGHT0, + OpenGL.GL.GL_DIFFUSE, + self.specs['light_colors'][1]) + OpenGL.GL.glLightfv( + OpenGL.GL.GL_LIGHT0, + OpenGL.GL.GL_SPECULAR, + self.specs['light_colors'][2]) + + OpenGL.GL.glLightf( + OpenGL.GL.GL_LIGHT0, OpenGL.GL.GL_CONSTANT_ATTENUATION, + 1.0 / self.specs['light_brightness']) + OpenGL.GL.glLightf( + OpenGL.GL.GL_LIGHT0, OpenGL.GL.GL_LINEAR_ATTENUATION, + 1.0 / self.specs['light_size']) + OpenGL.GL.glEnable(OpenGL.GL.GL_LIGHT0) + + # LIGHT1: spotlight on camera in look direction + if self.specs['spotlight_enabled']: + OpenGL.GL.glLightfv( + OpenGL.GL.GL_LIGHT1, + OpenGL.GL.GL_POSITION, + [0, 0, 0, 1]) + + OpenGL.GL.glLightfv( + OpenGL.GL.GL_LIGHT1, + OpenGL.GL.GL_AMBIENT, + self.specs['spotlight_colors'][0]) + OpenGL.GL.glLightfv( + OpenGL.GL.GL_LIGHT1, + OpenGL.GL.GL_DIFFUSE, + self.specs['spotlight_colors'][1]) + OpenGL.GL.glLightfv(OpenGL.GL.GL_LIGHT1, OpenGL.GL.GL_SPECULAR, + self.specs['spotlight_colors'][2]) + + OpenGL.GL.glLightf( + OpenGL.GL.GL_LIGHT1, + OpenGL.GL.GL_SPOT_CUTOFF, + self.specs['spotlight_angle']) + OpenGL.GL.glLightfv( + OpenGL.GL.GL_LIGHT1, + OpenGL.GL.GL_SPOT_DIRECTION, + [1.0, 1.0, 1.0]) + OpenGL.GL.glLightf(OpenGL.GL.GL_LIGHT1, OpenGL.GL.GL_SPOT_EXPONENT, + self.specs['spotlight_focus']) + + OpenGL.GL.glLightf( + OpenGL.GL.GL_LIGHT1, OpenGL.GL.GL_CONSTANT_ATTENUATION, + 1.0 / self.specs['spotlight_brightness']) + OpenGL.GL.glLightf( + OpenGL.GL.GL_LIGHT1, + OpenGL.GL.GL_LINEAR_ATTENUATION, + 0.0) + OpenGL.GL.glLightf( + OpenGL.GL.GL_LIGHT1, + OpenGL.GL.GL_QUADRATIC_ATTENUATION, + 0.0) + OpenGL.GL.glEnable(OpenGL.GL.GL_LIGHT1) + + self.dl_sphere = OpenGL.GL.glGenLists(1)
+ + +# END OF MAIN CLASS + +
[docs]class Shape(): + """ + Shape base class in the visualizer context. + + """ + + def __init__(self, shape, particle_type, color, material, + quality, box_l, rasterize_resolution, rasterize_pointsize): + self.shape = shape + self.particle_type = particle_type + self.color = color + self.material = material + self.quality = quality + self.box_l = box_l + self.rasterize_resolution = rasterize_resolution + self.pointsize = rasterize_pointsize + self.rasterized_surface_points = None + +
[docs] def draw(self): + """ + Draw shape via rasterization. Used as a default draw method. + Can and should be overwritten in child classes to implement a better + draw method. + + """ + # get and store points of rasterized surface if not already present + if self.rasterized_surface_points is None: + self.rasterized_surface_points = self._rasterize_shape() + + set_solid_material(self.color, self.material) + OpenGL.GL.glPointSize(self.pointsize) + OpenGL.GL.glBegin(OpenGL.GL.GL_POINTS) + for point in self.rasterized_surface_points: + OpenGL.GL.glVertex3f(point[0], point[1], point[2]) + OpenGL.GL.glEnd()
+ + def _rasterize_shape(self): + # rasterize brute force + spacing = max(self.box_l) / self.rasterize_resolution + resolution = np.array(self.box_l) / spacing + + points = [] + for i in range(int(resolution[0])): + for j in range(int(resolution[1])): + for k in range(int(resolution[2])): + # some shapes may not have a well-defined distance function + # in the whole domain and may throw a ValueError + try: + p = np.array([i, j, k]) * spacing + dist, vec = self.shape.call_method( + "calc_distance", position=p.tolist()) + if not (np.isnan(vec).any() or np.isnan(dist)) \ + and abs(dist) < spacing: + points.append((p - vec).tolist()) + except ValueError: + continue + return points + + def _has_gle_features(self, feature_names): + for feature_name in feature_names: + if not bool(getattr(OpenGL.GLE, feature_name)): + return False + return True
+ + +
[docs]class Cylinder(Shape): + """ + Drawable Shape Cylinder. + + """ + + def __init__(self, shape, particle_type, color, material, + quality, box_l, rasterize_resolution, rasterize_pointsize): + super().__init__(shape, particle_type, color, material, + quality, box_l, rasterize_resolution, rasterize_pointsize) + self.center = np.array(self.shape.get_parameter('center')) + self.axis = np.array(self.shape.get_parameter('axis')) + self.length = self.shape.get_parameter('length') + self.radius = self.shape.get_parameter('radius') + self.open = self.shape.get_parameter('open') + self.cap_center_1 = self.center - self.axis / \ + np.linalg.norm(self.axis) * 0.5 * self.length + self.cap_center_2 = self.center + self.axis / \ + np.linalg.norm(self.axis) * 0.5 * self.length + +
[docs] def draw(self): + draw_cylinder(self.cap_center_1, self.cap_center_2, + self.radius, self.color, self.material, + self.quality, draw_caps=not self.open)
+ + +
[docs]class Ellipsoid(Shape): + """ + Drawable Shape Ellipsoid. + + """ + + def __init__(self, shape, particle_type, color, material, + quality, box_l, rasterize_resolution, rasterize_pointsize): + super().__init__(shape, particle_type, color, material, + quality, box_l, rasterize_resolution, rasterize_pointsize) + self.center = np.array(self.shape.get_parameter('center')) + self.semiaxis_a = np.array(self.shape.get_parameter('a')) + self.semiaxis_b = np.array(self.shape.get_parameter('b')) + self.semiaxis_c = np.array(self.shape.get_parameter('b')) + +
[docs] def draw(self): + set_solid_material(self.color, self.material) + OpenGL.GL.glPushMatrix() + OpenGL.GL.glTranslatef(self.center[0], self.center[1], self.center[2]) + OpenGL.GL.glScalef(self.semiaxis_a, self.semiaxis_b, self.semiaxis_c) + OpenGL.GLUT.glutSolidSphere(1, self.quality, self.quality) + OpenGL.GL.glPopMatrix()
+ + +
[docs]class HollowConicalFrustum(Shape): + """ + Drawable Shape HollowConicalFrustum. + + """ + + def __init__(self, shape, particle_type, color, material, + quality, box_l, rasterize_resolution, rasterize_pointsize): + super().__init__(shape, particle_type, color, material, + quality, box_l, rasterize_resolution, rasterize_pointsize) + ctp = self.shape.get_parameter('cyl_transform_params') + self.center = np.array(ctp.center) + self.axis = np.array(ctp.axis) + self.orientation = np.array(ctp.orientation) + self.radius_1 = self.shape.get_parameter('r1') + self.radius_2 = self.shape.get_parameter('r2') + self.length = self.shape.get_parameter('length') + self.thickness = self.shape.get_parameter('thickness') + self.central_angle = self.shape.get_parameter('central_angle') + self.use_gle = self._has_gle_features( + ["gleSpiral", "gleSetNumSides", "gleSetJoinStyle"]) + +
[docs] def draw(self): + """ + Draw using OpenGL Extrusion library, if available. + Use rasterization of base class, otherwise. + + """ + if self.use_gle and self.central_angle == 0.: + self._draw_using_gle() + else: + super().draw()
+ + # if available, use the GL Extrusion library + def _draw_using_gle(self): + set_solid_material(self.color, self.material) + OpenGL.GL.glPushMatrix() + # basic position and orientation + OpenGL.GL.glTranslate(self.center[0], self.center[1], self.center[2]) + ax, rx, ry = rotation_helper(self.axis) + OpenGL.GL.glRotatef(ax, rx, ry, 0.0) + + n = max(20, self.quality) + rotation_angle = np.arctan( + (self.radius_1 - self.radius_2) / self.length) + l = self.length / np.cos(rotation_angle) + + contour = [] + for theta in np.linspace(-0.5 * np.pi, 0.5 * np.pi, n): + contour.append([np.sin(theta) * 0.5 * self.thickness, + np.cos(theta) * 0.5 * self.thickness + 0.5 * l]) + for theta in np.linspace(0.5 * np.pi, -0.5 * np.pi, n): + contour.append([np.sin(theta) * 0.5 * self.thickness, + -np.cos(theta) * 0.5 * self.thickness - 0.5 * l]) + contour = np.matmul(np.array(contour), + np.array([[np.cos(rotation_angle), -np.sin(rotation_angle)], + [np.sin(rotation_angle), np.cos(rotation_angle)]])) + + normals = np.diff(np.array(contour), axis=0) + normals /= np.linalg.norm(normals, ord=2, axis=1, keepdims=True) + normals = np.roll(normals, 1, axis=1) + + OpenGL.GLE.gleSetJoinStyle(OpenGL.GLE.TUBE_JN_ANGLE) + OpenGL.GLE.gleSetNumSides(max(90, 3 * self.quality)) + OpenGL.GLE.gleSpiral(contour, normals, [0, 0, 1], 0.5 * (self.radius_1 + self.radius_2), 0., 0., 0., + [[1, 0, 0], [0, 1, 0]], [[0, 0, 0], [0, 0, 0]], 0., 360) + + OpenGL.GL.glPopMatrix()
+ + +
[docs]class SimplePore(Shape): + """ + Drawable Shape SimplePore. + + """ + + def __init__(self, shape, particle_type, color, material, + quality, box_l, rasterize_resolution, rasterize_pointsize): + super().__init__(shape, particle_type, color, material, + quality, box_l, rasterize_resolution, rasterize_pointsize) + self.center = np.array(self.shape.get_parameter('center')) + self.axis = np.array(self.shape.get_parameter('axis')) + self.length = np.array(self.shape.get_parameter('length')) + self.radius = np.array(self.shape.get_parameter('radius')) + self.smoothing_radius = np.array( + self.shape.get_parameter('smoothing_radius')) + self.max_box_l = max(box_l) + self.use_gle = self._has_gle_features( + ["gleSpiral", "gleSetNumSides", "gleSetJoinStyle"]) + +
[docs] def draw(self): + """ + Draw using OpenGL Extrusion library, if available. + Use OpenGL primitives + clip planes, otherwise. + + """ + set_solid_material(self.color, self.material) + OpenGL.GL.glPushMatrix() + # basic position and orientation + OpenGL.GL.glTranslate(self.center[0], self.center[1], self.center[2]) + ax, rx, ry = rotation_helper(self.axis) + OpenGL.GL.glRotatef(ax, rx, ry, 0.0) + + if self.use_gle: + self._draw_using_gle() + else: + self._draw_using_primitives() + + OpenGL.GL.glPopMatrix()
+ + def _draw_using_gle(self): + n = max(10, self.quality // 3) + contour = [[0.5 * self.max_box_l, -0.5 * self.length]] + for theta in np.linspace(0, 0.5 * np.pi, n): + contour.append([(1. - np.sin(theta)) * self.smoothing_radius, + -0.5 * self.length + (1. - np.cos(theta)) * self.smoothing_radius]) + for theta in np.linspace(0.5 * np.pi, np.pi, n): + contour.append([(1. - np.sin(theta)) * self.smoothing_radius, + 0.5 * self.length - (1. + np.cos(theta)) * self.smoothing_radius]) + contour.append([0.5 * self.max_box_l, 0.5 * self.length]) + + normals = np.diff(np.array(contour), axis=0) + normals /= np.linalg.norm(normals, ord=2, axis=1, keepdims=True) + normals = np.roll(normals, 1, axis=1) + normals[:, 0] *= -1 + + OpenGL.GLE.gleSetJoinStyle(OpenGL.GLE.TUBE_JN_ANGLE) + OpenGL.GLE.gleSetNumSides(max(90, 3 * self.quality)) + OpenGL.GLE.gleSpiral(contour, normals, [0, 0, 1], self.radius, 0., 0., 0., + [[1, 0, 0], [0, 1, 0]], [[0, 0, 0], [0, 0, 0]], 0., 360) + + def _draw_using_primitives(self): + clip_plane = get_extra_clip_plane() + # cylinder + OpenGL.GL.glTranslate(0, 0, -0.5 * self.length + self.smoothing_radius) + quadric = OpenGL.GLU.gluNewQuadric() + OpenGL.GLU.gluCylinder(quadric, self.radius, self.radius, self.length - 2 * + self.smoothing_radius, self.quality, self.quality) + # torus segment + OpenGL.GL.glEnable(clip_plane) + OpenGL.GL.glClipPlane(clip_plane, (0, 0, -1, 0)) + OpenGL.GLUT.glutSolidTorus( + self.smoothing_radius, + self.radius + self.smoothing_radius, + self.quality, + self.quality) + OpenGL.GL.glDisable(clip_plane) + # wall + OpenGL.GL.glTranslate(0, 0, -self.smoothing_radius) + OpenGL.GLU.gluPartialDisk(quadric, self.radius + self.smoothing_radius, + 2.0 * self.max_box_l, self.quality, 1, 0, 360) + # torus segment + OpenGL.GL.glTranslate(0, 0, self.length - self.smoothing_radius) + OpenGL.GL.glEnable(clip_plane) + OpenGL.GL.glClipPlane(clip_plane, (0, 0, 1, 0)) + OpenGL.GLUT.glutSolidTorus( + self.smoothing_radius, + self.radius + self.smoothing_radius, + self.quality, + self.quality) + OpenGL.GL.glDisable(clip_plane) + # wall + OpenGL.GL.glTranslate(0, 0, self.smoothing_radius) + OpenGL.GLU.gluPartialDisk(quadric, self.radius + self.smoothing_radius, + 2.0 * self.max_box_l, self.quality, 1, 0, 360) + + OpenGL.GLU.gluDeleteQuadric(quadric)
+ + +
[docs]class Slitpore(Shape): + """ + Drawable Shape Slitpore. + + """ + + def __init__(self, shape, particle_type, color, material, + quality, box_l, rasterize_resolution, rasterize_pointsize): + super().__init__(shape, particle_type, color, material, + quality, box_l, rasterize_resolution, rasterize_pointsize) + self.channel_width = np.array( + self.shape.get_parameter('channel_width')) + self.lower_smoothing_radius = np.array( + self.shape.get_parameter('lower_smoothing_radius')) + self.upper_smoothing_radius = np.array( + self.shape.get_parameter('upper_smoothing_radius')) + self.pore_length = np.array(self.shape.get_parameter('pore_length')) + self.pore_mouth = np.array(self.shape.get_parameter('pore_mouth')) + self.pore_width = np.array(self.shape.get_parameter('pore_width')) + self.dividing_plane = np.array( + self.shape.get_parameter('dividing_plane')) + self.max_box_l = max(self.box_l) + +
[docs] def draw(self): + set_solid_material(self.color, self.material) + # If pore is large, an additional wall is necessary + if self.pore_width > 2. * self.lower_smoothing_radius: + wall_0 = [ + [self.dividing_plane - 0.5 * self.pore_width + self.lower_smoothing_radius, + 0., self.pore_mouth - self.pore_length], + [self.dividing_plane + 0.5 * self.pore_width - self.lower_smoothing_radius, + 0., self.pore_mouth - self.pore_length], + [self.dividing_plane + 0.5 * self.pore_width - self.lower_smoothing_radius, + self.max_box_l, self.pore_mouth - self.pore_length], + [self.dividing_plane - 0.5 * self.pore_width + self.lower_smoothing_radius, + self.max_box_l, self.pore_mouth - self.pore_length]] + draw_plane(wall_0, self.color, self.material) + + # Add the remaining walls + wall_1 = [ + [0., 0., self.channel_width + self.pore_mouth], + [self.max_box_l, 0., self.channel_width + self.pore_mouth], + [self.max_box_l, self.max_box_l, self.channel_width + self.pore_mouth], + [0., self.max_box_l, self.channel_width + self.pore_mouth]] + + wall_2 = [ + [0., 0., self.pore_mouth], + [self.dividing_plane - 0.5 * self.pore_width - + self.upper_smoothing_radius, 0., self.pore_mouth], + [self.dividing_plane - 0.5 * self.pore_width - + self.upper_smoothing_radius, self.max_box_l, self.pore_mouth], + [0., self.max_box_l, self.pore_mouth]] + + wall_3 = [ + [self.dividing_plane + 0.5 * self.pore_width + + self.upper_smoothing_radius, 0., self.pore_mouth], + [self.max_box_l, 0., self.pore_mouth], + [self.max_box_l, self.max_box_l, self.pore_mouth], + [self.dividing_plane + 0.5 * self.pore_width + + self.upper_smoothing_radius, self.max_box_l, self.pore_mouth]] + + wall_4 = [ + [self.dividing_plane - 0.5 * self.pore_width, 0., + self.pore_mouth - self.upper_smoothing_radius], + [self.dividing_plane - 0.5 * self.pore_width, self.max_box_l, + self.pore_mouth - self.upper_smoothing_radius], + [self.dividing_plane - 0.5 * self.pore_width, self.max_box_l, + self.pore_mouth - self.pore_length + self.lower_smoothing_radius], + [self.dividing_plane - 0.5 * self.pore_width, 0., + self.pore_mouth - self.pore_length + self.lower_smoothing_radius]] + + wall_5 = [ + [self.dividing_plane + 0.5 * self.pore_width, 0., + self.pore_mouth - self.upper_smoothing_radius], + [self.dividing_plane + 0.5 * self.pore_width, self.max_box_l, + self.pore_mouth - self.upper_smoothing_radius], + [self.dividing_plane + 0.5 * self.pore_width, self.max_box_l, + self.pore_mouth - self.pore_length + self.lower_smoothing_radius], + [self.dividing_plane + 0.5 * self.pore_width, 0., + self.pore_mouth - self.pore_length + self.lower_smoothing_radius]] + + draw_plane(wall_1, self.color, self.material) + draw_plane(wall_2, self.color, self.material) + draw_plane(wall_3, self.color, self.material) + draw_plane(wall_4, self.color, self.material) + draw_plane(wall_5, self.color, self.material) + + # Add smooth edges via clipped cylinders + ax, rx, ry = rotation_helper([0., 1., 0.]) + + OpenGL.GL.glPushMatrix() + quadric = OpenGL.GLU.gluNewQuadric() + OpenGL.GL.glTranslate(self.dividing_plane - self.upper_smoothing_radius - + 0.5 * self.pore_width, 0, self.pore_mouth - self.upper_smoothing_radius) + OpenGL.GL.glRotatef(ax, rx, ry, 0.) + + # Upper edges + clip_plane = get_extra_clip_plane() + OpenGL.GL.glEnable(clip_plane) + OpenGL.GL.glClipPlane(clip_plane, + (1, -1, 0, -self.upper_smoothing_radius)) + OpenGL.GLU.gluCylinder(quadric, self.upper_smoothing_radius, + self.upper_smoothing_radius, self.max_box_l, self.quality, self.quality) + + OpenGL.GL.glTranslate(self.pore_width + 2. * self.upper_smoothing_radius, + 0, 0) + OpenGL.GL.glClipPlane(clip_plane, + (-1, -1, 0, -self.upper_smoothing_radius)) + OpenGL.GLU.gluCylinder(quadric, self.upper_smoothing_radius, + self.upper_smoothing_radius, self.max_box_l, self.quality, self.quality) + + # Lower edges + OpenGL.GL.glTranslate(- self.upper_smoothing_radius - self.lower_smoothing_radius, + self.pore_length - self.upper_smoothing_radius - self.lower_smoothing_radius, 0) + OpenGL.GL.glClipPlane(clip_plane, + (1, 1, 0, -self.lower_smoothing_radius)) + OpenGL.GLU.gluCylinder(quadric, self.lower_smoothing_radius, + self.lower_smoothing_radius, self.max_box_l, self.quality, self.quality) + + OpenGL.GL.glTranslate(-self.pore_width + 2. * + self.lower_smoothing_radius, 0, 0) + OpenGL.GL.glClipPlane(clip_plane, + (-1, 1, 0, -self.lower_smoothing_radius)) + OpenGL.GLU.gluCylinder(quadric, self.lower_smoothing_radius, + self.lower_smoothing_radius, self.max_box_l, self.quality, self.quality) + + OpenGL.GL.glDisable(clip_plane) + OpenGL.GLU.gluDeleteQuadric(quadric) + OpenGL.GL.glPopMatrix()
+ + +
[docs]class Sphere(Shape): + """ + Drawable Shape Sphere. + + """ + + def __init__(self, shape, particle_type, color, material, + quality, box_l, rasterize_resolution, rasterize_pointsize): + super().__init__(shape, particle_type, color, material, + quality, box_l, rasterize_resolution, rasterize_pointsize) + self.center = self.shape.get_parameter('center') + self.radius = self.shape.get_parameter('radius') + +
[docs] def draw(self): + OpenGL.GL.glPushMatrix() + OpenGL.GL.glTranslatef(self.center[0], self.center[1], self.center[2]) + set_solid_material(self.color, self.material) + OpenGL.GLUT.glutSolidSphere(self.radius, self.quality, self.quality) + OpenGL.GL.glPopMatrix()
+ + +
[docs]class Spherocylinder(Shape): + """ + Drawable Shape Spherocylinder. + + """ + + def __init__(self, shape, particle_type, color, material, + quality, box_l, rasterize_resolution, rasterize_pointsize): + super().__init__(shape, particle_type, color, material, + quality, box_l, rasterize_resolution, rasterize_pointsize) + self.center = np.array(self.shape.get_parameter('center')) + self.axis = np.array(self.shape.get_parameter('axis')) + self.length = self.shape.get_parameter('length') + self.radius = self.shape.get_parameter('radius') + self.cap_center_1 = self.center - self.axis / \ + np.linalg.norm(self.axis) * 0.5 * self.length + self.cap_center_2 = self.center + self.axis / \ + np.linalg.norm(self.axis) * 0.5 * self.length + +
[docs] def draw(self): + set_solid_material(self.color, self.material) + OpenGL.GL.glPushMatrix() + quadric = OpenGL.GLU.gluNewQuadric() + + d = self.cap_center_2 - self.cap_center_1 + if d[2] == 0.0: + d[2] = 0.0001 + + v = np.linalg.norm(d) + if v == 0: + ax = 57.2957795 + else: + ax = 57.2957795 * math.acos(d[2] / v) + + if d[2] < 0.0: + ax = -ax + rx = -d[1] * d[2] + ry = d[0] * d[2] + length = np.linalg.norm(d) + OpenGL.GL.glTranslatef( + self.cap_center_1[0], + self.cap_center_1[1], + self.cap_center_1[2]) + OpenGL.GL.glRotatef(ax, rx, ry, 0.0) + + # First hemispherical cap + clip_plane = get_extra_clip_plane() + OpenGL.GL.glEnable(clip_plane) + OpenGL.GL.glClipPlane(clip_plane, (0, 0, -1, 0)) + OpenGL.GLU.gluSphere(quadric, self.radius, self.quality, self.quality) + OpenGL.GL.glDisable(clip_plane) + # Cylinder + OpenGL.GLU.gluCylinder(quadric, self.radius, self.radius, + length, self.quality, self.quality) + # Second hemispherical cap + OpenGL.GL.glTranslatef(0, 0, v) + OpenGL.GL.glEnable(clip_plane) + OpenGL.GL.glClipPlane(clip_plane, (0, 0, 1, 0)) + OpenGL.GLU.gluSphere(quadric, self.radius, self.quality, self.quality) + OpenGL.GL.glDisable(clip_plane) + + OpenGL.GLU.gluDeleteQuadric(quadric) + OpenGL.GL.glPopMatrix()
+ + +
[docs]class Wall(Shape): + """ + Drawable Shape Wall. + + """ + + def __init__(self, shape, particle_type, color, material, + quality, box_l, rasterize_resolution, rasterize_pointsize): + super().__init__(shape, particle_type, color, material, + quality, box_l, rasterize_resolution, rasterize_pointsize) + self.distance = self.shape.get_parameter('dist') + self.normal = self.shape.get_parameter('normal') + self.box_diag = np.linalg.norm(self.box_l) + self.edges = self._edges_from_pn(self.distance * np.array(self.normal), + self.normal, 2 * self.box_diag) + + @staticmethod + def _get_tangents(n): + n = np.array(n) + v1 = np.random.randn(3) + v1 -= v1.dot(n) * n / np.linalg.norm(n)**2 + v2 = np.cross(n, v1) + v1 /= np.linalg.norm(v1) + v2 /= np.linalg.norm(v2) + return v1, v2 + + def _edges_from_pn(self, p, n, diag): + v1, v2 = self._get_tangents(n) + edges = [p + diag * v1, p + diag * v2, p - diag * v1, p - diag * v2] + return edges + +
[docs] def draw(self): + draw_plane(self.edges, self.color, self.material)
+ + +# OPENGL DRAW WRAPPERS + +
[docs]def set_solid_material(color, material=(0.6, 1.0, 0.1, 0.4, 1.0)): + OpenGL.GL.glMaterialfv(OpenGL.GL.GL_FRONT_AND_BACK, OpenGL.GL.GL_AMBIENT, [ + color[0] * material[0], color[1] * material[0], color[2] * material[0], material[4]]) + OpenGL.GL.glMaterialfv(OpenGL.GL.GL_FRONT_AND_BACK, OpenGL.GL.GL_DIFFUSE, [ + color[0] * material[1], color[1] * material[1], color[2] * material[1], material[4]]) + OpenGL.GL.glMaterialfv(OpenGL.GL.GL_FRONT_AND_BACK, OpenGL.GL.GL_SPECULAR, [ + color[0] * material[2], color[1] * material[2], color[2] * material[2], material[4]]) + OpenGL.GL.glMaterialf( + OpenGL.GL.GL_FRONT_AND_BACK, + OpenGL.GL.GL_SHININESS, + int(material[3] * 128))
+ + +
[docs]def draw_box(p0, s, color, material, width): + OpenGL.GL.glLineWidth(width) + set_solid_material(color, material) + OpenGL.GL.glPushMatrix() + OpenGL.GL.glTranslatef(p0[0], p0[1], p0[2]) + OpenGL.GL.glBegin(OpenGL.GL.GL_LINE_LOOP) + OpenGL.GL.glVertex3f(0.0, 0.0, 0.0) + OpenGL.GL.glVertex3f(s[0], 0.0, 0.0) + OpenGL.GL.glVertex3f(s[0], s[1], 0.0) + OpenGL.GL.glVertex3f(0, s[1], 0.0) + OpenGL.GL.glEnd() + OpenGL.GL.glBegin(OpenGL.GL.GL_LINE_LOOP) + OpenGL.GL.glVertex3f(0.0, 0.0, s[2]) + OpenGL.GL.glVertex3f(s[0], 0.0, s[2]) + OpenGL.GL.glVertex3f(s[0], s[1], s[2]) + OpenGL.GL.glVertex3f(0, s[1], s[2]) + OpenGL.GL.glEnd() + OpenGL.GL.glBegin(OpenGL.GL.GL_LINES) + OpenGL.GL.glVertex3f(0.0, 0.0, 0.0) + OpenGL.GL.glVertex3f(0.0, 0.0, s[2]) + OpenGL.GL.glVertex3f(s[0], 0.0, 0.0) + OpenGL.GL.glVertex3f(s[0], 0.0, s[2]) + OpenGL.GL.glVertex3f(s[0], s[1], 0.0) + OpenGL.GL.glVertex3f(s[0], s[1], s[2]) + OpenGL.GL.glVertex3f(0.0, s[1], 0.0) + OpenGL.GL.glVertex3f(0.0, s[1], s[2]) + OpenGL.GL.glEnd() + + OpenGL.GL.glPopMatrix()
+ + +
[docs]def draw_plane(corners, color, material): + + set_solid_material(color, material) + + OpenGL.GL.glBegin(OpenGL.GL.GL_QUADS) + for c in corners: + OpenGL.GL.glVertex3f(c[0], c[1], c[2]) + OpenGL.GL.glEnd()
+ + +
[docs]def draw_cylinder(posA, posB, radius, color, material, quality, + draw_caps=False): + set_solid_material(color, material) + OpenGL.GL.glPushMatrix() + quadric = OpenGL.GLU.gluNewQuadric() + + d = posB - posA + + length = np.linalg.norm(d) + OpenGL.GL.glTranslatef(posA[0], posA[1], posA[2]) + + ax, rx, ry = rotation_helper(d) + OpenGL.GL.glRotatef(ax, rx, ry, 0.0) + OpenGL.GLU.gluCylinder(quadric, radius, radius, length, quality, quality) + + if draw_caps: + OpenGL.GLU.gluDisk(quadric, 0, radius, quality, quality) + OpenGL.GL.glTranslatef(0, 0, length) + OpenGL.GLU.gluDisk(quadric, 0, radius, quality, quality) + + OpenGL.GLU.gluDeleteQuadric(quadric) + OpenGL.GL.glPopMatrix()
+ + +
[docs]def rotation_helper(d): + # the rotation axis is the cross product between z and d + vz = np.cross([0.0, 0.0, 1.0], d) + # get the angle using a dot product + norm = np.linalg.norm(d) + angle = np.nan + if norm != 0.: + angle = 180.0 / np.pi * math.acos(d[2] / norm) + + return angle, vz[0], vz[1]
+ + +
[docs]def get_extra_clip_plane(): + + # ON SOME HARDWARE (e.g. MAC) only 6 CLIP PLANES ARE ALLOWED, + # SO CAPPING OF BOX BOUNDARIES AND ADDITIONAL SHAPE CLIP PLANES + # ARE NOT POSSIBLE. THIS WILL CAUSE THE SHAPES THAT NEED ADDITIONAL + # CLIP PLANES TO NOT BE CLIPPED ON ONE FACE OF THE BOX + + if sys.platform == "darwin": + return OpenGL.GL.GL_CLIP_PLANE0 + else: + return OpenGL.GL.GL_CLIP_PLANE0 + 6
+ + +
[docs]def draw_arrow(pos, d, radius, color, material, quality): + pos2 = np.array(pos) + np.array(d) + + draw_cylinder(pos, pos2, radius, color, material, quality) + + ax, rx, ry = rotation_helper(d) + if math.isnan(ax): + return + + OpenGL.GL.glPushMatrix() + OpenGL.GL.glTranslatef(pos2[0], pos2[1], pos2[2]) + OpenGL.GL.glRotatef(ax, rx, ry, 0.0) + OpenGL.GLUT.glutSolidCone(radius * 3, radius * 3, quality, quality) + OpenGL.GL.glPopMatrix()
+ + +# MOUSE EVENT MANAGER +
[docs]class MouseFireEvent: + """Event type of mouse button used for mouse callbacks. + + """ + + ButtonPressed = 0 + FreeMotion = 1 + ButtonMotion = 2 + ButtonReleased = 3 + DoubleClick = 4
+ + +
[docs]class MouseButtonEvent: + """Mouse event used for mouse callbacks. Stores button and callback. + + """ + + def __init__(self, button, fireEvent, callback, positional=False): + self.button = button + self.fireEvent = fireEvent + self.callback = callback + self.positional = positional
+ + +
[docs]class MouseManager: + """Handles mouse callbacks. + + """ + + def __init__(self): + self.mousePos = np.array([0, 0]) + self.mousePosOld = np.array([0, 0]) + self.mouseEventsPressed = [] + self.mouseEventsFreeMotion = [] + self.mouseEventsButtonMotion = [] + self.mouseEventsReleased = [] + self.mouseEventsDoubleClick = [] + self.mouseState = {OpenGL.GLUT.GLUT_LEFT_BUTTON: OpenGL.GLUT.GLUT_UP, + OpenGL.GLUT.GLUT_MIDDLE_BUTTON: OpenGL.GLUT.GLUT_UP, + OpenGL.GLUT.GLUT_RIGHT_BUTTON: OpenGL.GLUT.GLUT_UP, + '3': OpenGL.GLUT.GLUT_UP, '4': OpenGL.GLUT.GLUT_UP} + self.pressedTime = {OpenGL.GLUT.GLUT_LEFT_BUTTON: 0, + OpenGL.GLUT.GLUT_MIDDLE_BUTTON: 0, + OpenGL.GLUT.GLUT_RIGHT_BUTTON: 0, + 3: 0, 4: 0} + self.pressedTimeOld = {OpenGL.GLUT.GLUT_LEFT_BUTTON: 0, + OpenGL.GLUT.GLUT_MIDDLE_BUTTON: 0, + OpenGL.GLUT.GLUT_RIGHT_BUTTON: 0, 3: 0, 4: 0} + +
[docs] def register_button(self, mouseEvent): + """Register mouse input callbacks. + + """ + if mouseEvent.fireEvent == MouseFireEvent.ButtonPressed: + self.mouseEventsPressed.append(mouseEvent) + elif mouseEvent.fireEvent == MouseFireEvent.ButtonReleased: + self.mouseEventsReleased.append(mouseEvent) + elif mouseEvent.fireEvent == MouseFireEvent.FreeMotion: + self.mouseEventsFreeMotion.append(mouseEvent) + elif mouseEvent.fireEvent == MouseFireEvent.ButtonMotion: + self.mouseEventsButtonMotion.append(mouseEvent) + elif mouseEvent.fireEvent == MouseFireEvent.DoubleClick: + self.mouseEventsDoubleClick.append(mouseEvent)
+ +
[docs] def mouse_click(self, button, state, x, y): + self.mousePosOld = self.mousePos + self.mousePos = np.array([x, y]) + + self.mouseState[button] = state + + for me in self.mouseEventsPressed: + if me.button == button and state == OpenGL.GLUT.GLUT_DOWN: + if me.positional: + me.callback(self.mousePos, self.mousePosOld) + else: + me.callback() + for me in self.mouseEventsReleased: + if me.button == button and state == OpenGL.GLUT.GLUT_UP: + if me.positional: + me.callback(self.mousePos, self.mousePosOld) + else: + me.callback() + + if state == OpenGL.GLUT.GLUT_DOWN: + self.pressedTimeOld[button] = self.pressedTime[button] + self.pressedTime[button] = time.time() + + for me in self.mouseEventsDoubleClick: + if me.button == button and state == OpenGL.GLUT.GLUT_DOWN and self.pressedTime[ + button] - self.pressedTimeOld[button] < 0.25: + if me.positional: + me.callback(self.mousePos, self.mousePosOld) + else: + me.callback()
+ +
[docs] def mouse_move(self, x, y): + self.mousePosOld = self.mousePos + self.mousePos = np.array([x, y]) + + for me in self.mouseEventsFreeMotion: + me.callback(self.mousePos, self.mousePosOld, self.mouseState)
+ + +# KEYBOARD EVENT MANAGER + +
[docs]class KeyboardFireEvent: + """Event type of button used for keyboard callbacks. + + """ + + Pressed = 0 + Hold = 1 + Released = 2
+ + +
[docs]class KeyboardButtonEvent: + """Keyboard event used for keyboard callbacks. Stores button, event type and callback. + + """ + + def __init__(self, button, fireEvent, callback, internal=False): + self.button = button + self.fireEvent = fireEvent + self.callback = callback + self.internal = internal
+ + +
[docs]class KeyboardManager: + """Handles keyboard callbacks. + + """ + + def __init__(self): + self.pressedKeys = set([]) + self.keyStateOld = {} + self.keyState = {} + self.buttonEventsPressed = [] + self.buttonEventsHold = [] + self.buttonEventsReleased = [] + self.userCallbackStack = [] + +
[docs] def register_button(self, buttonEvent): + """Register keyboard input callbacks. + + """ + if buttonEvent.fireEvent == KeyboardFireEvent.Pressed: + self.buttonEventsPressed.append(buttonEvent) + elif buttonEvent.fireEvent == KeyboardFireEvent.Hold: + self.buttonEventsHold.append(buttonEvent) + elif buttonEvent.fireEvent == KeyboardFireEvent.Released: + self.buttonEventsReleased.append(buttonEvent)
+ +
[docs] def callback_on_button(self, be, b): + if be.button == b: + if be.internal: + be.callback() + else: + self.userCallbackStack.append(be.callback)
+ +
[docs] def handle_input(self): + removeKeys = set([]) + for b in self.pressedKeys: + if self.keyStateOld[b] == 0 and self.keyState[b] == 1: + for be in self.buttonEventsPressed: + self.callback_on_button(be, b) + for be in self.buttonEventsHold: + self.callback_on_button(be, b) + + elif self.keyStateOld[b] == 1 and self.keyState[b] == 1: + for be in self.buttonEventsHold: + self.callback_on_button(be, b) + + elif self.keyStateOld[b] == 1 and self.keyState[b] == 0: + for be in self.buttonEventsReleased: + self.callback_on_button(be, b) + removeKeys.add(b) + + self.keyStateOld[b] = self.keyState[b] + + self.pressedKeys = self.pressedKeys.difference(removeKeys)
+ +
[docs] def keyboard_up(self, button): + self.keyState[button] = 0 # Key up
+ +
[docs] def keyboard_down(self, button): + self.pressedKeys.add(button) + self.keyState[button] = 1 # Key down + if button not in self.keyStateOld.keys(): + self.keyStateOld[button] = 0
+ + +# CAMERA + +
[docs]class Camera: + + def __init__(self, cam_pos=np.array([0, 0, 1]), cam_target=np.array([0, 0, 0]), + cam_right=np.array([1.0, 0.0, 0.0]), move_speed=0.5, + global_rot_speed=3.0, center=np.array([0, 0, 0])): + self.cam_pos = cam_pos + self.move_speed = move_speed + self.global_rot_speed = global_rot_speed + self.center = center + + self.modelview = np.identity(4, np.float32) + + t = cam_pos - cam_target + r = np.linalg.norm(t) + + self.state_target = -t / r + self.state_right = cam_right / np.linalg.norm(cam_right) + self.state_up = np.cross(self.state_right, self.state_target) + self.state_pos = np.array([0, 0, r]) + + self.update_modelview() + +
[docs] def move_forward(self): + self.state_pos[2] += self.move_speed + self.update_modelview()
+ +
[docs] def move_backward(self): + self.state_pos[2] -= self.move_speed + self.update_modelview()
+ +
[docs] def move_up(self): + self.state_pos[1] += self.move_speed + self.update_modelview()
+ +
[docs] def move_down(self): + self.state_pos[1] -= self.move_speed + self.update_modelview()
+ +
[docs] def move_left(self): + self.state_pos[0] -= self.move_speed + self.update_modelview()
+ +
[docs] def move_right(self): + self.state_pos[0] += self.move_speed + self.update_modelview()
+ +
[docs] def rotate_system_XL(self): + self.rotate_system_y(0.01 * self.global_rot_speed)
+ +
[docs] def rotate_system_XR(self): + self.rotate_system_y(-0.01 * self.global_rot_speed)
+ +
[docs] def rotate_system_YL(self): + self.rotate_system_z(0.01 * self.global_rot_speed)
+ +
[docs] def rotate_system_YR(self): + self.rotate_system_z(-0.01 * self.global_rot_speed)
+ +
[docs] def rotate_system_ZL(self): + self.rotate_system_x(0.01 * self.global_rot_speed)
+ +
[docs] def rotate_system_ZR(self): + self.rotate_system_x(-0.01 * self.global_rot_speed)
+ +
[docs] def rotate_camera(self, mouse_pos, mouse_pos_old, mouse_button_state): + dm = mouse_pos - mouse_pos_old + + if mouse_button_state[OpenGL.GLUT.GLUT_LEFT_BUTTON] == OpenGL.GLUT.GLUT_DOWN: + if dm[0] != 0: + self.rotate_system_y(-0.001 * dm[0] * self.global_rot_speed) + if dm[1] != 0: + self.rotate_system_x(-0.001 * dm[1] * self.global_rot_speed) + elif mouse_button_state[OpenGL.GLUT.GLUT_RIGHT_BUTTON] == OpenGL.GLUT.GLUT_DOWN: + self.state_pos[0] -= 0.05 * dm[0] * self.move_speed + self.state_pos[1] += 0.05 * dm[1] * self.move_speed + self.update_modelview() + elif mouse_button_state[OpenGL.GLUT.GLUT_MIDDLE_BUTTON] == OpenGL.GLUT.GLUT_DOWN: + self.state_pos[2] += 0.05 * dm[1] * self.move_speed + self.rotate_system_z(dm[0] * 0.001 * self.global_rot_speed)
+ +
[docs] def get_camera_rotation_matrix(self, target_vec, up_vec): + normalized_target_vec = target_vec / np.linalg.norm(target_vec) + normalized_up_vec = up_vec / np.linalg.norm(up_vec) + perpendicular_normal = np.cross(normalized_up_vec, target_vec) + + rotation_matrix = np.identity(4, np.float32) + rotation_matrix[:3, :3] = np.array( + [perpendicular_normal, + np.cross(normalized_target_vec, perpendicular_normal), + normalized_target_vec]).T + + return rotation_matrix
+ +
[docs] def rotate_vector(self, vector, phi, axis): + """ + Rotate vector around (unit vector) axis by angle phi. + Uses Rodrigues' rotation formula. + + """ + rotated = vector * np.cos(phi) + np.cross(axis, vector) * np.sin(phi) \ + + axis * np.dot(axis, vector) * (1 - np.cos(phi)) + return rotated
+ +
[docs] def rotate_system_x(self, angle): + self.state_target = self.rotate_vector(self.state_target, + angle, self.state_right) + self.state_up = np.cross(self.state_right, self.state_target) + self.update_modelview()
+ +
[docs] def rotate_system_y(self, angle): + self.state_target = self.rotate_vector(self.state_target, + angle, self.state_up) + self.state_right = np.cross(self.state_target, self.state_up) + self.update_modelview()
+ +
[docs] def rotate_system_z(self, angle): + self.state_right = self.rotate_vector(self.state_right, + angle, self.state_target) + self.state_up = self.rotate_vector(self.state_up, + angle, self.state_target) + self.update_modelview()
+ +
[docs] def update_modelview(self): + + self.state_up /= np.linalg.norm(self.state_up) + self.state_right /= np.linalg.norm(self.state_right) + self.state_target /= np.linalg.norm(self.state_target) + + # Center Box + trans = np.identity(4, np.float32) + trans[3, :3] -= self.center + + # Camera rotation + rotate_cam = self.get_camera_rotation_matrix( + -self.state_target, self.state_up) + + # System translation + trans_cam = np.identity(4, np.float32) + trans_cam[3, :3] -= self.state_pos + + self.modelview = trans.dot(rotate_cam.dot(trans_cam)) + + c_xyz = -1 * np.mat(self.modelview[:3, :3]) * \ + np.mat(self.modelview[3, :3]).T + self.cam_pos = np.array([c_xyz[0, 0], c_xyz[1, 0], c_xyz[2, 0]])
+
+ +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/doc4.2.2/_modules/index.html b/doc4.2.2/_modules/index.html new file mode 100644 index 0000000000..2ff8f0877c --- /dev/null +++ b/doc4.2.2/_modules/index.html @@ -0,0 +1,117 @@ + + + + + + + + Overview: module code — ESPResSo 4.2.2 documentation + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/doc4.2.2/_sources/advanced_methods.rst.txt b/doc4.2.2/_sources/advanced_methods.rst.txt new file mode 100644 index 0000000000..340a69bddd --- /dev/null +++ b/doc4.2.2/_sources/advanced_methods.rst.txt @@ -0,0 +1,1413 @@ +.. _Advanced methods: + +Advanced methods +================ + +This page documents advanced features of |es|. Be sure to read the relevant +literature before using them. + + +.. _Creating bonds when particles collide: + +Creating bonds when particles collide +------------------------------------- + +Please cite :cite:`arnold13a` when using dynamic binding. + +With the help of this feature, bonds between particles can be created +automatically during the simulation, every time two particles collide. +This is useful for simulations of chemical reactions and irreversible +adhesion processes. Both, sliding and non-sliding contacts can be created. + +The collision detection is controlled via the system +:attr:`~espressomd.system.System.collision_detection` attribute, +which is an instance of the class +:class:`~espressomd.collision_detection.CollisionDetection`. + +Several modes are available for different types of binding. + +* ``"bind_centers"``: adds a pair-bond between two particles at their first collision. + By making the bonded interaction *stiff* enough, the particles can be held together + after the collision. Note that the particles can still slide on each others' surface, + as the pair bond is not directional. This mode is set up as follows:: + + import espressomd + import espressomd.interactions + + system = espressomd.System(box_l=[1, 1, 1]) + bond_centers = espressomd.interactions.HarmonicBond(k=1000, r_0=1.5) + system.bonded_inter.add(bond_centers) + system.collision_detection.set_params(mode="bind_centers", distance=1.5, + bond_centers=bond_centers) + + The parameters are as follows: + + * ``distance`` is the distance between two particles at which the binding is triggered. + This cutoff distance, ``1.5`` in the example above, is typically chosen slightly larger + than the particle diameter. It is also a good choice for the equilibrium length of the bond. + * ``bond_centers`` is the bonded interaction to be created between the particles + (an instance of :class:`~espressomd.interactions.HarmonicBond` in the example above). + No guarantees are made regarding which of the two colliding particles gets the bond. + Once there is a bond of this type on any of the colliding particles, + no further binding occurs for this pair of particles. + +* ``"bind_at_point_of_collision"``: this mode prevents sliding of the colliding particles at the contact. + This is achieved by creating two virtual sites at the point of collision. + They are rigidly connected to each of the colliding particles. + A bond is then created between the virtual sites, or an angular bond between + the two colliding particles and the virtual particles. In the latter case, + the virtual particles are the centers of the angle potentials + (particle 2 in the description of the angle potential, see :ref:`Bond-angle interactions`). + Due to the rigid connection between each of the + particles in the collision and its respective virtual site, a sliding + at the contact point is no longer possible. See the documentation on + :ref:`Rigid arrangements of particles` for details. In addition to the bond between the virtual + sites, the bond between the colliding particles is also created, i.e., + the ``"bind_at_point_of_collision"`` mode implicitly includes the ``"bind_centers"`` mode. + You can either use a real bonded interaction to prevent wobbling around + the point of contact or you can use :class:`espressomd.interactions.Virtual` which acts as a marker, only. + The method is setup as follows:: + + system.virtual_sites = espressomd.virtual_sites.VirtualSitesRelative() + system.collision_detection.set_params( + mode="bind_at_point_of_collision", + distance=0.1, + bond_centers=harmonic_bond1, + bond_vs=harmonic_bond2, + part_type_vs=1, + vs_placement=0) + + The parameters ``distance`` and ``bond_centers`` have the same meaning + as in the ``"bind_centers"`` mode. The remaining parameters are as follows: + + * ``bond_vs`` is the bond to be added between the two virtual sites created on collision. + This is either a pair-bond with an equilibrium length matching the distance between + the virtual sites, or an angle bond fully stretched in its equilibrium configuration. + * ``part_type_vs`` is the particle type assigned to the virtual sites created on collision. + In nearly all cases, no non-bonded interactions should be defined for this particle type. + * ``vs_placement`` controls, where on the line connecting the centers of the colliding + particles, the virtual sites are placed. A value of 0 means that the virtual sites are + placed at the same position as the colliding particles on which they are based. + A value of 0.5 will result in the virtual sites being placed at the mid-point between + the two colliding particles. A value of 1 will result the virtual site associated + to the first colliding particle to be placed at the position of the second colliding + particle. In most cases, 0.5, is a good choice. Then, the bond connecting the virtual + sites should have an equilibrium length of zero. + +* ``"glue_to_surface"``: This mode is used to irreversibly attach small particles + to the surface of a big particle. It is asymmetric in that several small particles + can be bound to a big particle but not vice versa. The small particles can change type + after collision to make them *inert*. On collision, a single virtual site is placed + and related to the big particle. Then, a bond (``bond_centers``) connects the big + and the small particle. A second bond (``bond_vs``) connects the virtual site and + the small particle. Further required parameters are: + + * ``part_type_to_attach_vs_to``: Type of the particle to which the virtual site is attached, i.e., the *big* particle. + * ``part_type_to_be_glued``: Type of the particle bound to the virtual site (the *small* particle). + * ``part_type_after_glueing``: The type assigned to the particle bound to the virtual site (*small* particle) after the collision. + * ``part_type_vs``: Particle type assigned to the virtual site created during the collision. + * ``distance_glued_particle_to_vs``: Distance of the virtual site to the particle being bound to it (*small* particle). + + Note: When the type of a particle is changed on collision, this makes the + particle inert with regards to further collision. Should a particle of + type ``part_type_to_be_glued`` collide with two particles in a single + time step, no guarantees are made with regards to which partner is selected. + In particular, there is no guarantee that the choice is unbiased. + + The method is used as follows:: + + system.virtual_sites = espressomd.virtual_sites.VirtualSitesRelative() + system.collision_detection.set_params( + mode="glue_to_surface", + distance=0.1, + distance_glued_particle_to_vs=0.02, + bond_centers=harmonic_bond1, + bond_vs=harmonic_bond2, + part_type_vs=1, + part_type_to_attach_vs_to=2, + part_type_to_be_glued=3, + part_type_after_glueing=4) + +* ``"bind_three_particles"`` allows for the creation of agglomerates which maintain + their shape similarly to those create by the mode ``"bind_at_point_of_collision"``. + The present approach works without virtual sites. Instead, for each two-particle + collision, the surrounding is searched for a third particle. If one is found, + angular bonds are placed to maintain the local shape. + If all three particles are within the cutoff distance, an angle bond is added + on each of the three particles in addition + to the distance based bonds between the particle centers. + If two particles are within the cutoff of a central particle (e.g., chain of three particles) + an angle bond is placed on the central particle. + The angular bonds being added are determined from the angle between the particles. + This method does not depend on the particles' rotational + degrees of freedom being integrated. Virtual sites are not required. + The method, along with the corresponding bonds are setup as follows:: + + n_angle_bonds = 181 # 0 to 180 degrees in one degree steps + for i in range(0, n_angle_bonds, 1): + system.bonded_inter[i] = espressomd.interactions.AngleHarmonic( + bend=1., phi0=float(i) / float(n_angle_bonds - 1) * np.pi) + + bond_centers = espressomd.interactions.HarmonicBond(k=1., r_0=0.1, r_cut=0.5) + system.bonded_inter.add(bond_centers) + + system.collision_detection.set_params( + mode="bind_three_particles", + bond_centers=bond_centers, + bond_three_particles=0, + three_particle_binding_angle_resolution=n_angle_bonds, + distance=0.1) + + Important: The bonds for the angles are mapped via their numerical bond ids. + In this example, ids from 0 to 180 are used. All other bonds required for + the simulation need to be added to the system after those bonds. In particular, + this applies to the bonded interaction passed via ``bond_centers`` + + +The following limitations currently apply for the collision detection: + +* No distinction is currently made between different particle types for the ``"bind_centers"`` method. + +* The ``"bind_at_point_of_collision"`` and ``"glue_to_surface"`` approaches require + the feature ``VIRTUAL_SITES_RELATIVE`` to be activated in :file:`myconfig.hpp`. + +* The ``"bind_at_point_of_collision"`` approach cannot handle collisions + between virtual sites + +.. _Deleting bonds when particles are pulled apart: + +Deleting bonds when particles are pulled apart +---------------------------------------------- + +With this feature, bonds between particles can be deleted automatically +when the bond length exceeds a critical distance. This is used to model +breakable bonds. + +The bond breakage action is specified for individual bonds via the system +:attr:`~espressomd.system.System.bond_breakage` attribute. + +Several modes are available: + +* ``"delete_bond"``: delete a bond from the first particle +* ``"revert_bind_at_point_of_collision"``: delete a bond between the virtual site +* ``"none"``: cancel an existing bond breakage specification + +Example:: + + import espressomd + import espressomd.interactions + import espressomd.bond_breakage + import numpy as np + + system = espressomd.System(box_l=[10] * 3) + system.cell_system.skin = 0.4 + system.time_step = 0.1 + system.min_global_cut = 2. + + h1 = espressomd.interactions.HarmonicBond(k=0.01, r_0=0.4) + h2 = espressomd.interactions.HarmonicBond(k=0.01, r_0=0.5) + system.bonded_inter.add(h1) + system.bonded_inter.add(h2) + system.bond_breakage[h1] = espressomd.bond_breakage.BreakageSpec( + breakage_length=0.5, action_type="delete_bond") + + p1 = system.part.add(id=1, pos=[0.00, 0.0, 0.0], v=[0.0, 0.0, 0.0]) + p2 = system.part.add(id=2, pos=[0.46, 0.0, 0.0], v=[0.1, 0.0, 0.0]) + p1.add_bond((h1, p2)) + p1.add_bond((h2, p2)) + for i in range(3): + system.integrator.run(2) + bond_length = np.linalg.norm(system.distance_vec(p1, p2)) + print(f"length = {bond_length:.2f}, bonds = {p1.bonds}") + +Output: + +.. code-block:: none + + length = 0.48, bonds = ((, 2), (, 2)) + length = 0.50, bonds = ((, 2), (, 2)) + length = 0.52, bonds = ((, 2),) + +Please note there is no special treatment for the energy released or consumed +by bond removal. This can lead to physical inconsistencies. + + +.. _Modeling reversible bonds: + +Modeling reversible bonds +------------------------- + +The :ref:`collision detection` +and :ref:`bond breakage` +features can be combined to model reversible bonds. + +Two combinations are possible: + +* ``"delete_bond"`` mode for breakable bonds together with + ``"bind_centers"`` mode for collision detection: + used to create or delete a bond between two real particles +* ``"revert_bind_at_point_of_collision"`` mode for breakable bonds together + with ``"bind_at_point_of_collision"`` mode for collision detection: + used to create or delete virtual sites (the implicitly created + bond between the real particles isn't affected) + +Please note that virtual sites are not automatically removed from the +simulation, therefore the particle number will increase. If you want to +remove virtual sites, you need to do so manually, either by tracking which +virtual sites were introduced by collision detection, or by periodically +looping over the particle list and removing virtual sites which have no +corresponding bond. + + +.. _Immersed Boundary Method for soft elastic objects: + +Immersed Boundary Method for soft elastic objects +------------------------------------------------- + +Please contact the Biofluid Simulation and Modeling Group at the +University of Bayreuth if you plan to use this feature. + +With the Immersed Boundary Method (IBM), soft particles are considered as an infinitely +thin shell filled with liquid (see e.g. :cite:`peskin02a,crowl10a,kruger11a`). When the +shell is deformed by an external flow, it responds with elastic restoring +forces which are transmitted into the fluid. In the present case, the +inner and outer liquid are of the same type and are simulated using +lattice-Boltzmann. + +Numerically, the shell is discretized by a set of marker points +connected by triangles. The marker points are advected with *exactly* +the local fluid velocity, i.e., they do not possess a mass nor a +friction coefficient (this is different from the Object-in-Fluid method +below). We implement these marker points as virtual tracer +particles which are not integrated using the usual velocity-Verlet +scheme, but instead are propagated using a simple Euler algorithm with +the local fluid velocity. + +The immersed boundary method consists of two components, which can be used independently: + +* :ref:`Inertialess lattice-Boltzmann tracers` implemented as virtual sites + +* Interactions providing the elastic forces for the particles forming the surface. + These are described in :ref:`Immersed Boundary Method interactions`. + +For a more detailed description, see e.g. :cite:`guckenberger17a` or contact us. +This feature probably does not work with advanced LB features such as electrokinetics. + +A sample script is provided in the :file:`/samples/immersed_boundary/` directory. + + +.. _Object-in-fluid: + +Object-in-fluid +--------------- +If you plan to use this feature, please contact the Cell-in-fluid Research Group at the +University of Zilina: ivan.cimrak@fri.uniza.sk or iveta.jancigova@fri.uniza.sk. + +When using this module, please cite :cite:`cimrak14a` (BibTeX key +``cimrak14a`` in :file:`doc/bibliography.bib`) and :cite:`cimrak12a` +(BibTeX key ``cimrak12a`` in :file:`doc/bibliography.bib`) + +This documentation introduces the features of module Object-in-fluid (OIF). +Even though |es| was not primarily intended to work with closed +objects, it is a flexible package and appears very suitable when one +wants to model closed objects with elastic properties, especially if +they are immersed in a moving fluid. Here we describe the module +itself and offer some additional information to get you started with. +Additionally, we provide a step by step tutorial that will show you how +to use this module. + +The OIF module was developed for simulations of red blood cells +flowing through microfluidic devices and therefore the elasticity +features were designed with this application in mind. However, they +are completely tunable and can be modified easily to allow the user to +model any elastic object moving in fluid flow. + + +|image1| |image2| |image3| + +.. |image1| image:: figures/oif1.png + :width: 30% +.. |image2| image:: figures/oif2.png + :width: 30% +.. |image3| image:: figures/oif3.png + :width: 30% + + +Triangulations of elastic objects +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +To create an elastic object, we need a triangulation of the surface of +this object. Sample triangulations are provided at +`http://cell-in-fluid.fri.uniza.sk/en/content/oif-espresso +`_. +Users can create their own meshes, for example in gmsh, salome or any other +meshing software. Two files are needed, one for the node positions and one +for the connectivity of triangles: + +* :file:`oif_nodes.dat` should contain triplets of floats (one + triplet per line), where each triplet represents the :math:`x, y` and + :math:`z` coordinates of one node of the surface triangulation. No + additional information should be written in this file, so this means + that the number of lines is equals to the number of surface nodes. The + coordinates of the nodes should be specified in such a way that the + approximate center of mass of the object corresponds to the origin + (0,0,0). This is for convenience when placing the objects at desired + locations later. +* :file:`oif_triangles.dat` should contain triplets of numbers, + this time integers. These integers refer to the IDs of the nodes in + the :file:`oif_nodes.dat` file and specify which three nodes form a + triangle. Please note that the nodes' IDs start at 0, i.e. + the node written in the first line of :file:`oif_nodes.dat` has ID 0, the + node in the second line, has ID 1, etc. + +.. figure:: figures/oif.png + :width: 5.00000cm + + +Description of sample script +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. note:: + + The following features are required: + ``LB_BOUNDARIES``, + ``EXTERNAL_FORCES``, + ``MASS``, ``SOFT_SPHERE`` + +The script described in this section is available in :file:`samples/object-in-fluid/motivation.py` and also at +`http://cell-in-fluid.fri.uniza.sk/en/content/oif-espresso +`_. + +In the first few lines, the script includes several imports related to +the red blood cell model, fluid, boundaries and interactions. Then we +have:: + + system = espressomd.System(box_l=(22, 14, 15)) + system.time_step = 0.1 + system.cell_system.skin = 0.2 + +Here we set up a system and its most important parameters. The ``skin`` +depth tunes the system's performance. The one important thing a user needs to know +about it is that it has to be strictly less than half the grid size. + +``box_l`` sets up the dimensions of the 3D simulation box. You might +wonder what the units are. For now, you can think of them as +micrometers, we will return to them later. + +``time_step`` is the time step that will be used in the simulation, for +the purposes here, in microseconds. It allows separate specification of +time step for the particles and for the fluid. This is useful when one +takes into account also thermal fluctuations relevant on molecular +level, however, for us, both of these time steps will mostly be +identical. + + +Specification of immersed objects +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +:: + + cell_type = OifCellType(nodesfile="input/rbc374nodes.dat", + trianglesfile="input/rbc374triangles.dat", system=system, + ks=0.02, kb=0.016, kal=0.02, kag=0.9, kv=0.5, resize=[2.0, 2.0, 2.0]) + +We do not create elastic objects directly but rather each one has to +correspond to a template, ``cell_type``, that has been created first. +The advantage of this approach is clear when creating many objects of +the same type that only differ by e.g. position or rotation, because in +such case it significantly speeds up the creation of objects that are +just copies of the same template. + +The three mandatory arguments are ``nodes-file`` and ``triangles-file`` +that specify input data files with desired triangulation and ``system`` +that specifies the |es| system. The relaxed mesh triangles should be +as close to equilateral as possible with average edge length +approximately equal to the space discretisation step :math:`\Delta x`. +While these lengths vary during the simulation, the connectivity of the +mesh nodes never changes. Basic meshes can be downloaded from our +website. This script assumes that the two necessary files are located +inside an ``input`` directory that resides in the same folder as the +simulation script. + +All other arguments are optional. ``resize`` defines resizing in the +:math:`x, y, z` directions with respect to unit size of the object, so +in this case, the cell radius will be 2. ``ks``, ``kb``, ``kal``, +``kag``, ``kv`` specify the elastic properties: stretching, bending, +local area conservation, global area conservation and volume +conservation respectively. These properties are described in +:ref:`Object-in-fluid interactions`. + +:: + + cell = OifCell(cellType=cell_type, partType=0, origin=[5.0, 5.0, 3.0]) + +Next, an actual object is created and its initial position is saved to a +*.vtk* file (the directory ``output/sim1`` needs to exist before the +script is executed). Each object has to have a unique ID, specified using the +keyword ``partType``. The IDs have to start at 0 and increase +consecutively. The other two mandatory arguments are ``cellType`` and +``origin``. ``cellType`` specifies which previously defined cell type +will be used for this object. ``origin`` gives placement of object's +center in the simulation box. + + + +Specification of fluid and movement +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +:: + + lbf = espressomd.lb.LBFluid(agrid=1, dens=1.0, visc=1.5, fric=1.5, + tau=time_step, ext_force_density=[0.002, 0.0, 0.0]) + system.actors.add(lbf) + +This part of the script specifies the fluid that will get the system +moving. Here ``agrid`` :math:`=\Delta x` is the spatial discretisation +step, ``tau`` is the time step that will be the same as the time step +for particles, viscosity ``visc`` and density ``dens`` of the fluid are +physical parameters scaled to lattice units. ``fric`` is a +(non-physical) friction parameter that enters the fluid-object +interaction and has to be set carefully. Finally, ``ext_force_density`` sets the +force-per-unit-volume vector that drives the fluid. Another option to +add momentum to fluid is by specifying the velocity on the boundaries. + + +Here we achieved the movement of the fluid by applying external force. +Another alternative is to set up a wall/rhomboid with velocity. This +does not mean that the physical boundary is moving, but rather that it +transfers specified momentum onto the fluid. + + + +Specification of boundaries +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +To set up the geometry of the channels, we mostly use rhomboids and +cylinders, but there are also other shape types available in |es|. +Their usage is described elsewhere. + + +|image4| |image5| |image6| + +.. |image4| image:: figures/oifcylinder.png + :width: 3.60000cm +.. |image5| image:: figures/oifrhomboid.png + :width: 7.80000cm +.. |image6| image:: figures/oifchannel.png + :width: 5.50000cm + +Each wall and obstacle has to be specified separately as a fluid +boundary and as a particle constraint. The former enters the simulation +as a boundary condition for the fluid, the latter serves for +particle-boundary interactions. Sample cylinder and rhomboid can then be +defined as follows. First we define the two shapes: + +:: + + boundary1 = shapes.Rhomboid(corner=[0.0, 0.0, 0.0], + a=[boxX, 0.0, 0.0], + b=[0.0, boxY, 0.0], + c=[0.0, 0.0, 1.0], + direction=1) + boundary2 = shapes.Cylinder(center=[11.0, 2.0, 7.0], + axis=[0.0, 0.0, 1.0], + length=7.0, + radius=2.0, + direction=1) + +The ``direction=1`` determines that the fluid is on the *outside*. Next +we create boundaries for the fluid: + +:: + + system.lbboundaries.add(lbboundaries.LBBoundary(shape=boundary1)) + system.lbboundaries.add(lbboundaries.LBBoundary(shape=boundary2)) + +Followed by creating the constraints for cells: + +:: + + system.constraints.add(shape=boundary1, particle_type=10) + system.constraints.add(shape=boundary2, particle_type=10) + +The ``particle_type=10`` will be important for specifying cell-wall +interactions later. And finally, we output the boundaries for +visualisation: + +:: + + output_vtk_rhomboid(corner=[0.0, 0.0, 0.0], + a=[boxX, 0.0, 0.0], + b=[0.0, boxY, 0.0], + c=[0.0, 0.0, 1.0], + out_file="output/sim1/wallBack.vtk") + output_vtk_cylinder(center=[11.0, 2.0, 7.0], + axis=[0.0, 0.0, 1.0], + length=7.0, + radius=2.0, + n=20, + out_file="output/sim1/obstacle.vtk") + +Note that the method for cylinder output also has an argument ``n``. +This specifies number of rectangular faces on the side. + +It is a good idea to output and visualize the boundaries and objects +just prior to running the actual simulation, to make sure that the +geometry is correct and no objects intersect with any boundaries. + + + +Specification of interactions +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +We can define an interaction with the boundaries: + +:: + + system.non_bonded_inter[0, 10].soft_sphere.set_params( + soft_a=0.0001, soft_n=1.2, soft_cut=0.1, soft_offset=0.0) + +These interactions are also *pointwise*, e.g. each particle of type 0 +(that means all mesh points of cell) will have a repulsive soft-sphere +interaction with all boundaries of type 10 (here all boundaries) once it +gets closer than ``soft_cut``. The parameters ``soft_a`` and ``soft_n`` +adjust how strong the interaction is and ``soft_offset`` is a distance +offset, which will always be zero for our purposes. + + + +System integration +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +And finally, the heart of this script is the integration loop at the +end: + +:: + + for i in range(1, 101): + system.integrator.run(steps=500) + cell.output_vtk_pos_folded(filename=f"output/sim1/cell_{i}.vtk") + print(f"time: {i * time_step}") + print("Simulation completed.") + +This simulation runs for 100 cycles. In each cycle, 500 integration +steps are performed and output is saved into files +:file:`output/sim1/cell_*.vtk`. Note that they differ only by the number +before the *.vtk* extension (this variable changes due to the ``for`` +loop) and this will allow us to animate them in the visualisation +software. ``str`` changes the type of ``i`` from integer to string, so +that it can be used in the filename. The strings can be joined together +by the + sign. Also, in each pass of the loop, the simulation time is +printed in the terminal window and when the integration is complete, we +should get a message about it. + + +To sum up, the proper order of setting up individual simulation +parts is as follows: + +- cell types +- cells +- fluid +- fluid boundaries +- interactions + +If cell types and cells are specified after the fluid, the simulation +is slower. Also, interactions can only be defined once the objects +and boundaries both exist. Technically, the fluid boundaries can be +specified before fluid, but it is really not recommended. + + + +Running the simulation +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The script can be executed in the terminal with + +.. code-block:: bash + + ../pypresso script.py + +Here :file:`script.py` is the name of the script we just went over and +:file:`../pypresso` should be replaced with the path to your executable. +This command assumes that we are currently in the same directory as the +script. Once the command is executed, messages should appear on the +terminal about the creation of cell type, cell and the integration +steps. + +Writing out data +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +In the script, we have used the commands such as + +:: + + cell.output_vtk_pos_folded(filename=f"output/sim1/cell_{i}.vtk") + +to output the information about cell in every pass of the simulation +loop. These files can then be used for inspection in ParaView and +creation of animations. It is also possible to save a .vtk file for the +fluid. And obviously, one can save various types of other data into text +or data files for further processing and analysis. + + + +Visualization in ParaView +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +For visualization we suggest the free software ParaView [5]_. All .vtk +files (boundaries, fluid, objects at all time steps) can be loaded at +the same time. The loading is a two step process, because only after +pressing the Apply button, are the files actually imported. Using the +eye icon to the left of file names, one can turn on and off the +individual objects and/or boundaries. + +Fluid can be visualized using Filters/Alphabetical/Glyph (or other +options from this menu. Please, refer to the ParaView user's guide for +more details). + +Note, that ParaView does not automatically reload the data if they +have been changed in the input folder, but a useful thing to know is +that the created filters can be "recycled". Once you delete the old +data, load the new data and right-click on the existing filters, you +can re-attach them to the new data. + +It is a good idea to output and visualize the boundaries and objects +just prior to running the actual simulation, to make sure that the +geometry is correct and no objects intersect with any boundaries. This +would cause "particle out of range" error and crash the simulation. + +File format +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +ParaView (download at https://www.paraview.org) accepts .vtk files. For +our cells we use the following format: + +.. code-block:: none + + # vtk DataFile Version 3.0 + Data + ASCII + DATASET POLYDATA + POINTS 393 float + p0x p0y p0z + p1x p1y p1z + ... + p391x p391y p391z + p392x p392y p392z + TRIANGLE_STRIPS num_triang 4*num_triang + 3 p1 p2 p3 + 3 p1 p3 p5 + ... + 3 p390 p391 p392 + +where the cell has 393 surface nodes (particles). After initial +specification, the list of points is present, with x, y, z coordinates for +each. Then we write the triangulation, since that is how our +surface is specified. We need to know the number of triangles +(``num_triang``) and the each line/triangle is specified by 4 numbers +(so we are telling ParaView to expect 4 * ``num_triang``  numbers in +the following lines. Each line begins with 3 (which stands for a +triangle) and three point IDs that tell us which three points (from +the order above) form this specific triangle. + + + +Color coding of scalar data by surface points +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +It is possible to save (and visualize) data corresponding to individual +surface points. These data can be scalar or vector values associated +with all surface points. At the end of the .vtk file above, add the +following lines: + +.. code-block:: none + + POINT_DATA 393 + SCALARS sample_scalars float 1 + LOOKUP_TABLE default + value-at-p0 + value-at-p1 + ... + value-at-p392 + +This says that data for each of 393 points are coming. Next line says +that the data are scalar in this case, one float for each point. To +color code the values in the visualization, a default (red-to-blue) +table will be used. It is also possible to specify your own lookup +table. As an example, we might want to see a force magnitude in each +surface node + + +.. figure:: figures/oifstretched-sphere.png + :width: 4.00000cm + + Stretched sphere after some relaxation, showing magnitude + of total stretching force in each node. + + + +Color coding of scalar data by triangles +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +It is also possible to save (and visualize) data corresponding to +individual triangles + +.. figure:: figures/oifcolored-triangles.png + :width: 4.00000cm + + Red blood cell showing which triangles (local surface areas) are under + most strain in shear flow. + +In such case, the keyword ``POINT_DATA`` is changed to ``CELL_DATA`` and the number of +triangles is given instead of number of mesh points. + +.. code-block:: none + + # vtk DataFile Version 3.0 + Data + ASCII + DATASET POLYDATA + POINTS 4 float + 1 1 1 + 3 1 1 + 1 3 1 + 1 1 3 + TRIANGLE_STRIPS 3 12 + 3 0 1 2 + 3 0 2 3 + 3 0 1 3 + CELL_DATA 3 + SCALARS sample_scalars float 1 + LOOKUP_TABLE default + 0.0 + 0.5 + 1.0 + +Note - it is also possible to save (and visualize) data corresponding to edges. + + + +Multiple scalar data in one .vtk file +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +If one wants to switch between several types of scalar values +corresponding to mesh nodes, these are specifies consecutively in the +.vtk file, as follows. Their names (*scalars1* and *scalars2* in the +following example) appear in a drop-down menu in ParaView. + +.. code-block:: none + + POINT_DATA 393 + SCALARS scalars1 float 1 + LOOKUP_TABLE default + value1-at-p0 + value1-at-p1 + ... + value1-at-p392 + SCALARS scalars2 float 1 + LOOKUP_TABLE default + value2-at-p0 + value2-at-p1 + ... + value2-at-p392 + + + +Vector data for objects .vtk file +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +| If we want to observe some vector data (e.g. outward normal, + fig. [fig:vectordata]) at points of the saved objects, we can use the + following structure of the .vtk file, where the vector at one point is + [v1, v2, v3]: + +.. code-block:: none + + POINT_DATA 393 + VECTORS vector_field float + v1-at-p0 v2-at-p0 v3-at-p0 + v1-at-p1 v2-at-p1 v3-at-p1 + ... + v1-at-p391 v2-at-p391 v3-at-p392 + +.. figure:: figures/oifvectordata.png + :width: 6.00000cm + + Example of vector data stored in points of the object + +| More info on .vtk files and possible options: +| https://vtk.org/wp-content/uploads/2015/04/file-formats.pdf + + + +Automatic loading +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +| Sometimes it is frustrating to reload data in ParaView: manually open + all the files, click all the properties etc. This however, can be done + automatically. +| Scenario: +| Load file *data.vtk* with the fluid velocity field. +| Add filter called *slice* to visualize the flow field on the + cross-section. +| To do it automatically, ParaView has a feature for tracking steps. To + record the steps that create the scenario above, first choose + Tools/Start Trace. From that moment, all the steps done in ParaView + will be recorded. Then you Tools/Stop Trace. Afterwards, a window + appears with a python code with recorded steps. It needs to be saved + as, e.g. *loading-script.py.* +| Next time you open ParaView with command + ``paraview --script=loading-script.py`` and all the steps for creating + that scenario will be executed and you end up with the velocity field + visualized. + + +Available Object-in-fluid (OIF) classes +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +| Here we describe the currently available OIF classes and commands. + Note that there are more still being added. We would be pleased to + hear from you about any suggestions on further functionality. + +| Notation: ``keywords``, *parameter values*, **vectors** +| The keywords do not have to be in a specific order. + +class OifCellType +^^^^^^^^^^^^^^^^^ + +For those familiar with earlier version of object-in-fluid framework, +this class corresponds to the oif_emplate in tcl. It contains a "recipe" +for creating cells of the same type. These cells can then be placed at +different locations with different orientation, but their elasticity and +size is determined by the CellType. There are no actual particles +created at this stage. Also, while the interactions are defined, no +bonds are created here. + +:: + + OifCellType.print_info() + OifCellType.mesh.output_mesh_triangles(filename) + +| ``nodesfile=``\ *nodes.dat* - input file. Each line contains three + real numbers. These are the *x, y, z* coordinates of individual + surface mesh nodes of the objects centered at [0,0,0] and normalized + so that the "radius" of the object is 1. + +| ``trianglesfile=``\ *triangles.dat* - input file. Each line contains + three integers. These are the ID numbers of the mesh nodes as they + appear in *nodes.dat*. Note that the first node has ID 0. + +| ``system=``\ *system* Particles of cells created using this + template will be added to this system. Note that there can be only one + system per simulation. + +| ``ks=``\ *value* - elastic modulus for stretching forces. + +| ``kslin=`` *value* - elastic modulus for linear stretching forces. + +| ``kb=`` *value* - elastic modulus for bending forces. + +| ``kal=`` *value* - elastic modulus for local area forces. + +| The switches ``ks``, ``kb`` and ``kal`` set elastic parameters for + local interactions: ``ks`` for edge stiffness, ``kb`` for angle + preservation stiffness and ``kal`` for triangle area preservation + stiffness. Currently, the stiffness is implemented to be uniform over + the whole object, but with some tweaking, it is possible to have + non-uniform local interactions. + +| Note, the difference between stretching (``ks``) and linear stretching + (``kslin``) - these two options cannot be used simultaneously: + +| Linear stretching behaves like linear spring, where the stretching + force is calculated as :math:`\mathbf{F}_s=k_s*\Delta L`, where + :math:`\Delta L` is the prolongation of the given edge. By default, + the stretching is non-linear (neo-Hookian). + +| ``kvisc=``\ *value* - elastic modulus for viscosity of the membrane. + Viscosity slows down the reaction of the membrane. + +| ``kag=``\ *value* - elastic modulus for global area forces + +| ``kv=``\ *value* - elastic modulus for volume forces + +| Note: At least one of the elastic moduli should be set. + +| ``resize=``\ (*x, y, z*) - coefficients, by which the coordinates + stored in *nodesfile* will be stretched in the *x, y, z* + direction. The default value is (1.0, 1.0, 1.0). + +| ``mirror=``\ (*x, y, z*) - whether the respective coordinates should + be flipped around 0. Arguments *x, y, z* must be either 0 or 1. + The reflection of only one coordinate is allowed so at most one + argument is set to 1, others are 0. For example ``mirror=``\ (0, 1, 0) + results in flipping the coordinates (*x, y, z*) to (*x, -y, z*). The + default value is (0, 0, 0). + +| ``normal`` - by default set to *False*, however without this + option enabled, the membrane collision (and thus cell-cell + interactions) will not work. + +| ``check_orientation`` - by default set to *True*. This options + performs a check, whether the supplied *trianglesfile* contains + triangles with correct orientation. If not, it corrects the + orientation and created cells with corrected triangles. It is useful + for new or unknown meshes, but not necessary for meshes that have + already been tried out. Since it can take a few minutes for larger + meshes (with thousands of nodes), it can be set to *False*. In + that case, the check is skipped when creating the ``CellType`` and a + warning is displayed. + +| The order of indices in *triangles.dat* is important. Normally, each + triangle ABC should be oriented in such a way, that the normal vector + computed as vector product ABxAC must point inside the object. For + example, a sphere (or any other sufficiently convex object) contains + such triangles that the normals of these triangles point towards the + center of the sphere (almost). + +| The check runs over all triangles, makes sure that they have the + correct orientation and then calculates the volume of the object. If + the result is negative, it flips the orientation of all triangles. + +| Note, this method tells the user about the correction it makes. If + there is any, it might be useful to save the corrected triangulation + for future simulations using the method + ``CellType.mesh.OutputMeshTriangles``\ (*filename*), so that the + check does not have to be used repeatedly. + +| ``CellType.mesh.output_mesh_triangles``\ (*filename*) - this is + useful after checking orientation, if any of the triangles where + corrected. This method saves the current triangles into a file that + can be used as input in the next simulations. + +| ``CellType.print_info()`` - prints the information about the template. + + +class OifCell +^^^^^^^^^^^^^^^ +:: + + OifCell.set_origin([x, y, z]) + OifCell.get_origin() + OifCell.get_origin_folded() + OifCell.get_approx_origin() + OifCell.get_velocity() + OifCell.set_velocity([x, y, z]) + OifCell.pos_bounds() + OifCell.surface() + OifCell.volume() + OifCell.diameter() + OifCell.get_n_nodes() + OifCell.set_force([x, y, z]) + OifCell.kill_motion() + OifCell.unkill_motion() + OifCell.output_vtk_pos(filename.vtk) + OifCell.output_vtk_pos_folded(filename.vtk) + OifCell.append_point_data_to_vtk(filename.vtk, dataname, data, firstAppend) + OifCell.output_raw_data(filename, rawdata) + OifCell.output_mesh_points(filename) + OifCell.set_mesh_points(filename) + OifCell.elastic_forces(elasticforces, fmetric, vtkfile, rawdatafile) + OifCell.print_info() + +| ``cell_type`` - object will be created using nodes, triangle + incidences, elasticity parameters and initial stretching saved in this + cellType. + +| ``part_type``\ =\ *type* - must start at 0 for the first cell and + increase consecutively for different cells. Volume calculation of + individual objects and interactions between objects are set up using + these types. + +| ``origin``\ =(\ *x, y, z*) - center of the object will be at this + point. + +| ``rotate``\ =(\ *x, y, z*) - angles in radians, by which the object + will be rotated about the *x, y, z* axis. Default value is (0.0, + 0.0, 0.0). Value (:math:`\pi/2, 0.0, 0.0`) means that the object will + be rotated by :math:`\pi/2` radians clockwise around the *x* + axis when looking in the positive direction of the axis. + +| ``mass``\ =\ *m* - mass of one particle. Default value is 1.0. + +| ``OifCell.set_origin``\ (**o**) - moves the object such that the origin + has coordinates **o**\ =(\ *x, y, z*). + +| ``OifCell.get_origin()`` - outputs the location of the center of the + object. + +| ``OifCell.get_origin_folded()`` - outputs the location of the center of + the object. For periodical movements the coordinates are folded + (always within the computational box). + +| ``OifCell.get_approx_origin()`` - outputs the approximate location of + the center of the object. It is computed as average of 6 mesh points + that have extremal *x, y* and *z* coordinates at the time + of object loading. + +| ``OifCell.get_velocity()`` - outputs the average velocity of the + object. Runs over all mesh points and outputs their average velocity. + +| ``OifCell.set_velocity``\ (**v**) - sets the velocities of all mesh + points to **v**\ =(\ :math:`v_x`, :math:`v_y`, :math:`v_z`). + +| ``OifCell.pos_bounds()`` - computes six extremal coordinates of the + object. More precisely, runs through the all mesh points and returns + the minimal and maximal :math:`x`-coordinate, :math:`y`-coordinate and + :math:`z`-coordinate in the order (:math:`x_{max}`, :math:`x_{min}`, + :math:`y_{max}`, :math:`y_{min}`, :math:`z_{max}`, :math:`z_{min}`). + +| ``OifCell.surface()`` - outputs the surface of the object. + +| ``OifCell.volume()`` - outputs the volume of the object. + +| ``OifCell.diameter()`` - outputs the largest diameter of the object. + +| ``OifCell.get_n_nodes()`` - returns the number of mesh nodes. + +| ``OifCell.set_force``\ (**f**) - sets the external force vector + **f**\ =(\ :math:`f_x`, :math:`f_y`, :math:`f_z`) to all mesh nodes of + the object. Setting is done using command ``p.set_force``\ (**f**). + Note, that this command sets the external force in each integration + step. So if you want to use the external force only in one iteration, + you need to set zero external force in the following integration step. + +| ``OifCell.kill_motion()`` - stops all the particles in the object + (analogue to the command ``p.kill_motion()``). + +| ``OifCell.unkill_motion()`` - enables the movement of all the particles + in the object (analogue to the command ``p.unkill_motion()``). + +| ``OifCell.output_vtk_pos``\ (*filename.vtk*) - outputs the mesh of the + object to the desired *filename.vtk*. ParaView can directly visualize + this file. + +| ``OifCell.output_vtk_pos_folded``\ (*filename.vtk*) - outputs the mesh of + the object to the desired *filename.vtk*. ParaView can directly + visualize this file. For periodical movements the coordinates are + folded (always within the computational box). + +| ``OifCell.append_point_data_to_vtk``\ (*filename.vtk*, *dataname*, + **data**, *firstAppend*) - outputs the specified scalar **data** to an + existing *filename.vtk*. This is useful for ParaView + visualisation of local velocity magnitudes, magnitudes of forces, etc. + in the meshnodes and can be shown in ParaView by selecting the + *dataname* in the *Properties* toolbar. It is possible to + consecutively write multiple datasets into one *filename.vtk*. + For the first one, the *firstAppend* parameter is set to + *True*, for the following datasets, it needs to be set to + *False*. This is to ensure the proper structure of the output + file. + +| ``OifCell.output_raw_data``\ (*filename*, **rawdata**) - outputs the + vector **rawdata** about the object into the *filename*. + +| ``OifCell.output_mesh_points``\ (*filename*) - outputs the positions of + the mesh nodes to *filename*. In fact, this command creates a new + *nodes.dat* file that can be used by the method + ``OifCell.set_mesh_points``\ (*nodes.dat*). The center of the object is + located at point (0.0, 0.0, 0.0). This command is aimed to store the + deformed shape in order to be loaded later. + +| ``OifCell.set_mesh_points``\ (*filename*) - deforms the object in such a + way that its origin stays unchanged, however the relative positions of + the mesh points are taken from file *filename*. The *filename* should + contain the coordinates of the mesh points with the origin location at + (0.0, 0.0, 0.0). The procedure also checks whether number of lines in + the *filename* is the same as the corresponding value from + ``OifCell.get_n_nodes()``. + +| ``OifCell.elastic_forces``\ (**elasticforces**, **fmetric**, *vtkfile*, + *rawdatafile*) - this method can be used in two different ways. One is + to compute the elastic forces locally for each mesh node and the other + is to compute the f-metric, which is an approximation of elastic + energy. + +| To compute the elastic forces, use the vector + **elasticforces**. It is a sextuple of zeros and ones, + e.g. **elasticforces** = (1,0,0,1,0,0), where the ones + denote the elastic forces to be computed. The order is (stretching, + bending, local area, global area, volume, total). The output can be + saved in two different ways: either by setting + *vtkfile = filename.vtk*, which saves a .vtk file that can be + visualized using ParaView. If more than one elastic force was + selected, they can be chosen in the Properties window in ParaView. The + other type of output is *rawdatafile=filename.dat*, which will + save a datafile with the selected type of elastic force - one force + per row, where each row corresponds to a single mesh node. Note that + only one type of elastic force can be written this way at a time. + Thus, if you need output for several elastic forces, this method + should be called several times. + +| To compute the f-metric, use the vector **fmetric**. It + is again a sextuple of zeros and ones, e.g. + **fmetric** = (1,1,0,0,0,0), where the ones denote the + elastic forces to be computed. The order is (stretching, bending, + local area, global area, volume, total). The output is again a vector + with six elements, each corresponding to the requested f-metric/“naive + energy” computed as a sum of magnitudes of respective elastic forces + over all nodes of the object. + +| ``OifCell.print_info()`` - prints the information about the elastic + object. + + +Short utility procedures +^^^^^^^^^^^^^^^^^^^^^^^^ + +| ``get_n_triangle``\ (**a, b, c**) - returns the normal **n** + to the triangle given by points (**a, b, c**). + +| ``norm``\ (**v**) - returns the norm of the vector **v**. + +| ``distance``\ (**a, b**) - returns the distance between + points **a** and **b**. + +| ``area_triangle``\ (**a, b, c**) - returns the area of the + given triangle (**a, b, c**). + +| ``angle_btw_triangles``\ (:math:`\mathbf{p}_1`, :math:`\mathbf{p}_2`, + :math:`\mathbf{p}_3`, :math:`\mathbf{p}_4` - returns the angle + :math:`\phi` between two triangles: (:math:`\mathbf{p}_1`, + :math:`\mathbf{p}_2`, :math:`\mathbf{p}_3`) and (:math:`\mathbf{p}_3`, + :math:`\mathbf{p}_2`, :math:`\mathbf{p}_4`) that have a common edge + (:math:`\mathbf{p}_2`, :math:`\mathbf{p}_3`). + +| ``discard_epsilon``\ (*x*) - needed for rotation; discards very + small numbers *x*. + +| ``oif_neo_hookean_nonlin``\ (:math:`\lambda`) - nonlinearity for neo-Hookean stretching + +| ``calc_stretching_force``\ (:math:`k_s,\ \mathbf{p}_A,\ \mathbf{p}_B`, *dist0*, *dist*) + - computes the nonlinear stretching force with given :math:`k_s` for + points :math:`\mathbf{p}_A` and :math:`\mathbf{p}_B` given by their + coordinates, whose initial distance was *dist0* and current distance + is *dist*. + +| ``calc_linear_stretching_force``\ (:math:`k_s,\ \mathbf{p}_A,\ \mathbf{p}_B`, *dist0*, *dist*) + - computes the linear stretching force with given :math:`k_s` for + points :math:`\mathbf{p}_A` and :math:`\mathbf{p}_B` given by their + coordinates, whose initial distance was *dist0* and current distance + is *dist*. + +| ``calc_bending_force``\ (:math:`k_b,\ \mathbf{p}_A,\ \mathbf{p}_B,\ \mathbf{p}_C,\ \mathbf{p}_D,\ \phi_0,\ \phi`) + - computes the bending force with given :math:`k_b` for points + :math:`\mathbf{p}_A`, :math:`\mathbf{p}_B`, :math:`\mathbf{p}_C` and + :math:`\mathbf{p}_D` (:math:`\triangle_1`\ =BAC; + :math:`\triangle_2`\ =BCD) given by their coordinates; the initial + angle for these two triangles was :math:`\phi_0`, the current angle is + :math:`\phi`. + +| ``calc_local_area_force``\ (:math:`k_{al},\ \mathbf{p}_A,\ \mathbf{p}_B,\ \mathbf{p}_C,\ A_0,\ A`) + - computes the local area force with given :math:`k_{al}` for points + :math:`\mathbf{p}_A`, :math:`\mathbf{p}_B` and :math:`\mathbf{p}_C` + given by their coordinates; the initial area of triangle ABC was + :math:`A_0`, the current area is :math:`A`. + +| ``calc_global_area_force``\ (:math:`k_{ag},\ \mathbf{p}_A,\ \mathbf{p}_B,\ \mathbf{p}_C,\ A_{g0},\ A_g`) + - computes the global area force with given :math:`k_{ag}` for points + :math:`\mathbf{p}_A`, :math:`\mathbf{p}_B` and :math:`\mathbf{p}_C` + given by their coordinates; the initial surface area of the object was + :math:`A_{g0}`, the current surface area of the object is :math:`A_g`. + +| ``calc_volume_force``\ (:math:`k_v,\ \mathbf{p}_A,\ \mathbf{p}_B,\ \mathbf{p}_C,\ V_0,\ V`) + - computes the volume force with given :math:`k_v` for points + :math:`\mathbf{p}_A`, :math:`\mathbf{p}_B` and :math:`\mathbf{p}_C` + given by their coordinates; the initial volume of the object was + :math:`V_0`, the current volume of the object is :math:`V`. + +| ``output_vtk_rhomboid``\ (**corner**, **a**, **b**, **c**, *outFile.vtk*) + - outputs rhomboid boundary for later visualisation in ParaView. + +| ``output_vtk_cylinder``\ (**center**, **normal**, *L*, *r*, *n*, *outFile.vtk*) + - outputs cylinder boundary for later visualisation in ParaView. + +| ``output_vtk_lines``\ (*lines*, *outFile.vtk*) - outputs a set of + line segments for later visualisation in ParaView. + + +Description of helper classes +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Awareness of these classes is not necessary for a user of OIF module, +but is essential for developers who wish to modify it because it shows +how the object data are stored. + +classes ``FixedPoint`` and ``PartPoint`` + + +Class PartPoint represents a particle. These particles are then used as +building blocks for edges, angles, triangles and ultimately the whole +object mesh. Since we use a two-step process to create the objects, it +is necessary to distinguish between a FixedPoint and PartPoint. +FixedPoint is a point used by template and does not correspond to +particle. The FixedPoints of one OifCellType form a mesh that is +centered around origin. Only after it is stretched and shifted to the +object origin are the PartPoints of the given object created. + +classes ``Edge``, ``Angle``, ``Triangle``, ``ThreeNeighbors`` + + +These classes represent the building blocks of a mesh. They are used to +compute the elastic interactions: Edge is for stretching, Angle for +bending, Triangle for local and global area and volume and ThreeNeigbors +for calculation of outward normal vector needed for cell-cell +interaction. + +class ``Mesh`` + + +This class holds all the information about the geometry of the object, +including nodes, edges, angles, triangles and neighboring points. The +mesh of OifCellType is copied every time a new object (i.e. OifCell) of +this type is created. This saves computational time, since the data for +elastic interactions of the given object do not need to be recalculated +every time. + +.. [5] + https://www.paraview.org/ + +.. _Particle polarizability with thermalized cold Drude oscillators: + +Particle polarizability with thermalized cold Drude oscillators +--------------------------------------------------------------- + +.. note:: + + Requires features ``THOLE``, ``P3M``, ``THERMOSTAT_PER_PARTICLE``. + +.. note:: + + Drude is only available for the P3M electrostatics solver and the Langevin thermostat. + +**Thermalized cold Drude oscillators** can be used to simulate +polarizable particles. The basic idea is to add a 'charge-on-a-spring' (Drude +charge) to a particle (Drude core) that mimics an electron cloud which can be +elongated to create a dynamically inducible dipole. The energetic minimum of +the Drude charge can be obtained self-consistently, which requires several +iterations of the system's electrostatics and is usually considered +computationally expensive. However, with thermalized cold Drude oscillators, the +distance between Drude charge and core is coupled to a thermostat so that it +fluctuates around the SCF solution. This thermostat is kept at a low +temperature compared to the global temperature to minimize the heat flow into +the system. A second thermostat is applied on the centre of mass of the Drude +charge + core system to maintain the global temperature. The downside of this +approach is that usually a smaller time step has to be used to resolve the high +frequency oscillations of the spring to get a stable system. + +In |es|, the basic ingredients to simulate such a system are split into three bonds: + +1. A :ref:`Harmonic Bond` to account for the spring. +2. A :ref:`Thermalized distance bond` with a cold thermostat on the Drude-Core distance. +3. A :ref:`Subtract P3M short-range bond` to cancel the electrostatic interaction between Drude and core particles. + +The system-wide thermostat has to be applied to the centre of mass and not to +the core particle directly. Therefore, the particles have to be excluded from +global thermostatting. With ``THERMOSTAT_PER_PARTICLE`` enabled, we set the +friction coefficient of the Drude complex to zero, which allows +to still use a global Langevin thermostat for non-polarizable particles. + +As the Drude charge should not alter the *charge* or *mass* of the Drude +complex, both properties have to be subtracted from the core when adding the +Drude particle. In the following convention, we assume that the Drude charge is +**always negative**. It is calculated via the spring constant :math:`k` and +polarizability :math:`\alpha` (in units of inverse volume) with :math:`q_d = +-\sqrt{k \cdot \alpha}`. + +The following helper method takes into account all the preceding considerations +and can be used to conveniently add a Drude particle to a given core particle. +It returns an `espressomd.particle_data.ParticleHandle` to the created Drude +particle. Note that as the function also adds the first two bonds between Drude +and core, these bonds have to be already available.:: + + import espressomd.drude_helpers + dh = espressomd.drude_helpers.DrudeHelpers() + drude_part = dh.add_drude_particle_to_core(, , + , , , , + , , , ) + +The arguments of the helper function are: + * ````: The :class:`espressomd.System() `. + * ````: The harmonic bond of the charge-on-a-spring. This is + added between core and newly generated Drude particle + * ````: The thermalized distance bond for the cold and hot + thermostats. + * ````: The core particle on which the Drude particle is added. + * ````: The user-defined type of the Drude particle. + Each Drude particle of each complex should have an + individual type (e.g. in an ionic system with Anions (type 0) and Cations + (type 1), two new, individual Drude types have to be assigned). + * ````: The polarizability volume. + * ````: The Coulomb prefactor of the system. Used to + calculate the Drude charge from the polarizability and the spring constant + of the Drude bond. + * ````: (optional) An individual Thole damping parameter for the + core-Drude pair. Only relevant if Thole damping is used (defaults to 2.6). + * ````: (bool, optional) Prints out information about the added Drude + particles (default: False) + +What is still missing is the short-range exclusion bond between all Drude-core pairs. +One bond type of this kind is needed per Drude type. The above helper function also +tracks particle types, ids and charges of Drude and core particles, so a simple call of +another helper function:: + + dh.setup_and_add_drude_exclusion_bonds(system) + +will use this data to create a :ref:`Subtract P3M short-range bond` per Drude type +and set it up it between all Drude and core particles collected in calls of +:meth:`~espressomd.drude_helpers.DrudeHelpers.add_drude_particle_to_core`. + +.. _Canceling intramolecular electrostatics: + +Canceling intramolecular electrostatics +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Note that for polarizable **molecules** (i.e. connected particles, coarse grained +models etc.) with partial charges on the molecule sites, the Drude charges will +have electrostatic interaction with other cores of the molecule. Often, this +is unwanted, as it might be already part of the force-field (via. partial +charges or parametrization of the covalent bonds). Without any further +measures, the elongation of the Drude particles will be greatly affected be the +close-by partial charges of the molecule. To prevent this, one has to cancel +the interaction of the Drude charge with the partial charges of the cores +within the molecule. This can be done with special bonds that subtracts the P3M +short-range interaction of the charge portion :math:`q_d q_{partial}`. This ensures +that only the *dipolar interaction* inside the molecule remains. It should be +considered that the error of this approximation increases with the share of the +long-range part of the electrostatic interaction. Two helper methods assist +with setting up this exclusion. If used, they have to be called +after all Drude particles are added to the system:: + + espressomd.drude_helpers.setup_intramol_exclusion_bonds(, , + , , ) + +This function creates the required number of bonds which are later added to the +particles. It has to be called only once. In a molecule with :math:`N` polarizable +sites, :math:`N \cdot (N-1)` bond types are needed to cover all the combinations. +Parameters are: + +* ````: The :class:`espressomd.System() `. +* ````: List of the Drude types within the molecule. +* ````: List of the core types within the molecule that have partial charges. +* ````: List of the partial charges on the cores. +* ````: (bool, optional) Prints out information about the created bonds (default: False) + +After setting up the bonds, one has to add them to each molecule with the +following method:: + + espressomd.drude_helpers.add_intramol_exclusion_bonds(, , , ) + +This method has to be called for all molecules and needs the following parameters: + +* ````: The :class:`espressomd.System() `. +* ````: The ids of the Drude particles within one molecule. +* ````: The ids of the core particles within one molecule. +* ````: (bool, optional) Prints out information about the added bonds (default: ``False``) + +Internally, this is done with the bond described in :ref:`Subtract P3M short-range bond`, that +simply adds the p3m shortrange pair-force of scale :math:`- q_{\textrm{d}} q_{\textrm{partial}}` the to +bonded particles. + +.. seealso:: + + Often used in conjunction with Drude oscillators is the :ref:`Thole correction` + to damp dipole-dipole interactions on short distances. It is available in |es| + as a non-bonded interaction. diff --git a/doc4.2.2/_sources/analysis.rst.txt b/doc4.2.2/_sources/analysis.rst.txt new file mode 100644 index 0000000000..b3fd6df853 --- /dev/null +++ b/doc4.2.2/_sources/analysis.rst.txt @@ -0,0 +1,789 @@ +.. _Analysis: + +Analysis +======== + +|es| provides two concepts of system analysis: + +- :ref:`Direct analysis routines`: The :mod:`espressomd.analyze` module provides + online-calculation of specialized local and global observables with + calculation and data accumulation performed in the core. +- :ref:`Observables framework`: This provides a more flexible concept of + in-core analysis, where a certain observable (:ref:`Available observables`), + a rule for data accumulation (:ref:`Accumulators`) and/or correlation (:ref:`Correlations`) can be defined. + + +.. _Direct analysis routines: + +Direct analysis routines +------------------------ + +The direct analysis commands only take into account the current configuration of the system. +Available commands are: + +- :ref:`Energies` +- :ref:`Pressure` +- :ref:`Pressure Tensor` +- :ref:`Momentum of the System` +- :ref:`Minimal distances between particles` +- :ref:`Particles in the neighborhood` +- :ref:`Particle distribution` +- :ref:`Structure factor` +- :ref:`Center of mass` +- :ref:`Moment of inertia matrix` +- :ref:`Gyration tensor` + +.. _Energies: + +Energies +~~~~~~~~ +:meth:`espressomd.analyze.Analysis.energy` + +Returns the energies of the system. +The different energetic contributions to the total energy can also be obtained (kinetic, bonded, non-bonded, Coulomb). + +For example, :: + + >>> energy = system.analysis.energy() + >>> print(energy["total"]) + >>> print(energy["kinetic"]) + >>> print(energy["bonded"]) + >>> print(energy["non_bonded"]) + + +.. _Momentum of the system: + +Momentum of the System +~~~~~~~~~~~~~~~~~~~~~~ +:meth:`espressomd.analyze.Analysis.linear_momentum` + +This command returns the total linear momentum of the particles and the +lattice-Boltzmann (LB) fluid, if one exists. Giving the optional +parameters either causes the command to ignore the contribution of LB or +of the particles. + +.. _Minimal distances between particles: + +Minimal distances between particles +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +:meth:`espressomd.analyze.Analysis.min_dist` +Returns the minimal distance between all particles in the system. + +When used with type-lists as arguments, then the minimal distance between particles of only those types is determined. + + +For example, :: + + >>> import espressomd + >>> system = espressomd.System(box_l=[100, 100, 100]) + >>> for i in range(10): + ... system.part.add(pos=[1.0, 1.0, i**2], type=0) + >>> system.analysis.min_dist() + 1.0 + + +.. _Particles in the neighborhood: + +Particles in the neighborhood +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +:meth:`espressomd.analyze.Analysis.nbhood` + +Returns a list of the ids of particles that fall within a given radius of a target position. +For example, :: + + ids = system.analysis.nbhood(pos=system.box_l * 0.5, r_catch=5.0) + +.. _Particle distribution: + +Particle distribution +~~~~~~~~~~~~~~~~~~~~~ +:meth:`espressomd.analyze.Analysis.distribution` + +Returns the distance distribution of particles +(probability of finding a particle of a certain type at a specified distance around +a particle of another specified type, disregarding the fact that a spherical shell of a +larger radius covers a larger volume). +The distance is defined as the *minimal* distance between a particle of one group to any of the other +group. + +Two arrays are returned corresponding to the normalized distribution and the bins midpoints, for example :: + + >>> system = espressomd.System(box_l=[10, 10, 10]) + >>> for i in range(5): + ... system.part.add(pos=i * system.box_l, type=0) + >>> bins, count = system.analysis.distribution(type_list_a=[0], type_list_b=[0], + ... r_min=0.0, r_max=10.0, r_bins=10) + >>> print(bins) + [ 0.5 1.5 2.5 3.5 4.5 5.5 6.5 7.5 8.5 9.5] + >>> print(count) + [ 1. 0. 0. 0. 0. 0. 0. 0. 0. 0.] + + +.. _Structure factor: + +Structure factor +~~~~~~~~~~~~~~~~ +:meth:`espressomd.analyze.Analysis.structure_factor` + +Calculate the structure factor for given types. + +Returns the spherically averaged structure factor :math:`S(q)` of +particles specified in ``sf_types``. :math:`S(q)` is calculated for all possible +wave vectors :math:`\frac{2\pi}{L} \leq q \leq \frac{2\pi}{L}` up to ``sf_order``. + + +.. _Center of mass: + +Center of mass +~~~~~~~~~~~~~~ +:meth:`espressomd.analyze.Analysis.center_of_mass` + +Returns the center of mass of particles of the given type given by ``part_type``. + + +.. _Moment of inertia matrix: + +Moment of inertia matrix +~~~~~~~~~~~~~~~~~~~~~~~~ +:meth:`espressomd.analyze.Analysis.moment_of_inertia_matrix` + +Returns the 3x3 moment of inertia matrix for particles of a given type. + + +.. _Gyration tensor: + +Gyration tensor +~~~~~~~~~~~~~~~ +:meth:`espressomd.analyze.Analysis.gyration_tensor` + +Analyze the gyration tensor of particles of a given type, or of all particles in the system if no type is given. Returns a dictionary containing the squared radius of gyration, three shape descriptors (asphericity, acylindricity, and relative shape anisotropy), eigenvalues of the gyration tensor and their corresponding eigenvectors. The eigenvalues are sorted in descending order. + + +.. _Pressure: + +Pressure +~~~~~~~~ + +:meth:`espressomd.analyze.Analysis.pressure` + +Computes the instantaneous virial pressure for an isotropic and homogeneous system. It +returns all the contributions to the total pressure as well as the total pressure (see :meth:`espressomd.analyze.Analysis.pressure`). + +The instantaneous pressure is calculated (if there are no electrostatic interactions) +by the volume averaged, direction averaged instantaneous virial pressure + +.. math:: + p = \frac{2E_{\text{kinetic}}}{Vf} + \frac{\sum_{j>i} {F_{ij}r_{ij}}}{3V} + :label: eqptens + +where :math:`f=3` is the number of translational degrees of freedom of +each particle, :math:`V` is the volume of the system, +:math:`E_{\text{kinetic}}` is the kinetic energy, :math:`F_{ij}` the force +between particles i and j, and :math:`r_{ij}` is the distance between +them. The kinetic energy divided by the degrees of freedom is + +.. math:: \frac{2E_{\text{kinetic}}}{f} = \frac{1}{3}\sum_{i} {m_{i}v_{i}^{2}}. + +Note that Equation :eq:`eqptens` can only be applied to pair potentials and +central forces. Description of how contributions from other interactions +are calculated is beyond the scope of this manual. Three body potentials +are implemented following the procedure in +Ref. :cite:`thompson09a`. A different formula is used to +calculate contribution from electrostatic interactions. For +electrostatic interactions in P3M, the :math:`k`-space contribution is implemented according to :cite:`essmann95a`. +The implementation of the Coulomb P3M pressure is tested against LAMMPS. + +Four-body dihedral potentials are not included. Except of +``VIRTUAL_SITES_RELATIVE`` constraints all other +constraints of any kind are not currently accounted for in the pressure +calculations. The pressure is no longer correct, e.g., when particles +are confined to a plane. + +Note: The different contributions which are returned are the summands that arise from force splitting :math:`\vec{F}_{i,j}={\vec{F}_{i,j}}_\text{bonded}+{\vec{F}_{i,j}}_\text{nonbonded}+...` in the virial pressure formula. Later when the user calculates the ensemble average via e.g. :math:`\langle p \rangle \approx 1/N \sum_{i=1}^N p_i` however the ensemble average with all interactions present is performed. That means the contributions are not easy to interpret! Those are the contributions to the pressure in a system where all interactions are present and therefore in a coupled system. + +.. _Pressure Tensor: + +Pressure Tensor +~~~~~~~~~~~~~~~ +:meth:`espressomd.analyze.Analysis.pressure_tensor` + +Computes the volume averaged instantaneous pressure tensor of the system with options which are +described by in :meth:`espressomd.analyze.Analysis.pressure_tensor`. +In general do only use it for (on average) homogeneous systems. For inhomogeneous systems you need to use the local pressure tensor. + +The instantaneous virial pressure tensor is calculated by + +.. math:: p_{(k,l)} = \frac{\sum_{i} {m_{i}v_{i}^{(k)}v_{i}^{(l)}}}{V} + \frac{\sum_{j>i}{F_{ij}^{(k)}r_{ij}^{(l)}}}{V} + +where the notation is the same as for the pressure. The superscripts :math:`k` +and :math:`l` correspond to the components in the tensors and vectors. + +If electrostatic interactions are present then also the coulombic parts of the pressure tensor need to be calculated. If P3M is present, then the instantaneous pressure tensor is added to the above equation in accordance with :cite:`essmann95a` : + +.. math :: p^\text{Coulomb, P3M}_{(k,l)} =p^\text{Coulomb, P3M, dir}_{(k,l)} + p^\text{Coulomb, P3M, rec}_{(k,l)}, + +where the first summand is the short ranged part and the second summand is the long ranged part. + +The short ranged part is given by: + +.. math :: p^\text{Coulomb, P3M, dir}_{(k,l)}= \frac{1}{4\pi \varepsilon_0 \varepsilon_r} \frac{1}{2V} \sum_{\vec{n}}^* \sum_{i,j=1}^N q_i q_j \left( \frac{ \mathrm{erfc}(\beta |\vec{r}_j-\vec{r}_i+\vec{n}|)}{|\vec{r}_j-\vec{r}_i+\vec{n}|^3} + \\ \frac{2\beta \pi^{-1/2} \exp(-(\beta |\vec{r}_j-\vec{r}_i+\vec{n}|)^2)}{|\vec{r}_j-\vec{r}_i+\vec{n}|^2} \right) (\vec{r}_j-\vec{r}_i+\vec{n})_k (\vec{r}_j-\vec{r}_i+\vec{n})_l, + +where :math:`\beta` is the P3M splitting parameter, :math:`\vec{n}` identifies the periodic images, the asterisk denotes that terms with :math:`\vec{n}=\vec{0}` and i=j are omitted. +The long ranged (k-space) part is given by: + +.. math :: p^\text{Coulomb, P3M, rec}_{(k,l)}= \frac{1}{4\pi \varepsilon_0 \varepsilon_r} \frac{1}{2 \pi V^2} \sum_{\vec{k} \neq \vec{0}} \frac{\exp(-\pi^2 \vec{k}^2/\beta^2)}{\vec{k}^2} |S(\vec{k})|^2 \cdot (\delta_{k,l}-2\frac{1+\pi^2\vec{k}^2/\beta^2}{\vec{k}^2} \vec{k}_k \vec{k}_l), + +where :math:`S(\vec{k})` is the Fourier transformed charge density. Compared to Essmann we do not have the contribution :math:`p^\text{corr}_{k,l}` since we want to calculate the pressure that arises from all particles in the system. + +Note: The different contributions which are returned are the summands that arise from force splitting :math:`\vec{F}_{i,j}={\vec{F}_{i,j}}_\text{bonded}+{\vec{F}_{i,j}}_\text{nonbonded}+...` in the virial pressure tensor formula. +Later when the user calculates the pressure tensor via :math:`\langle p_{(k,l)}\rangle \approx 1/N \sum_{i=1}^N p_{k,l}` however the ensemble average with all interactions present is performed. +That means the contributions are not easy to interpret! Those are the contributions to the pressure in a system where all interactions are present and therefore in a coupled system. + +Note that the angular velocities of the particles are not included in +the calculation of the pressure tensor. + +.. _Chains: + +Chains +~~~~~~ + +All analysis functions in this section require the topology of the chains to be set correctly. +A chain needs to be set up with a contiguous range of particle IDs, and the +head resp. tail particle must be have the first resp. last id in the range. +For chain observables that rely on connectivity information, the chain topology +must be linear, i.e. particle :math:`n` is connected to :math:`n+1` and so on. +Each chain is a set of consecutively numbered particles and all chains are +supposed to consist of the same number of particles. + +The particles :attr:`~espressomd.particle_data.ParticleHandle.image_box` +values must also be consistent, since these observables are calculated using +*unfolded coordinates*. For example, if all particles were to be inserted in +the central box except for the tail particle, which would be e.g. inserted in +the fourth periodic image, the end-to-end distance and radius of gyration +would be quite large, even if the tail particle is in close proximity to the +penultimate particle in *folded coordinates*, because the last inter-particle +distance would be evaluated as being 4 times the box length plus the bond +length. Particles *can* have different ``image_box`` values, for example +in a chain with equilibrium bond length 2, if the penultimate particle is at +``[box_l - 1, 0, 0]`` and the tail particle at ``[box_l + 1, 0, 0]``, their +inter-particle distance would be evaluated as 2 and the observables would +be correctly calculated. This can lead to counter-intuitive behavior when +chains are longer than half the box size in a fully periodic system. As an +example, consider the end-to-end distance of a linear polymer growing on +the x-axis. While :meth:`espressomd.system.System.distance()` would feature +a triangle wave with a period equal to the box length in the x-direction, +:meth:`espressomd.analyze.Analysis.calc_re` would be monotonically increasing, +assuming the ``image_box`` values were properly set up. This is important to +consider when setting up systems where the polymers are much longer than the +box length, which is common when simulating polymer melts. + +.. _Available chain analysis functions: + +Available chain analysis functions +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* :meth:`espressomd.analyze.Analysis.calc_re`: average end-to-end-distance + +* :meth:`espressomd.analyze.Analysis.calc_rg`: average radius of gyration + +* :meth:`espressomd.analyze.Analysis.calc_rh`: average hydrodynamic radius + + +.. _Observables framework: + +Observables framework +--------------------- + +Observables extract properties of the particles and the LB fluid and +return either the raw data or a statistic derived from them. +Correlators and accumulators provide functionality to collect and +process the output of observables automatically throughout the course +of the simulation. + +The Observables framework is progressively replacing the Analysis framework. +This is motivated by the fact, that sometimes it is desirable that the +analysis functions do more than just return a value to the scripting +interface. For some observables it is desirable to be sampled every few +integration steps. In addition, it should be possible to pass the +observable values to other functions which compute history-dependent +quantities, such as correlation functions. All this should be done +without the need to interrupt the integration by passing the control to +the script level and back, which produces a significant overhead when +performed too often. + +Some observables in the core have their corresponding counterparts in +the :mod:`espressomd.analyze` module. However, only the core-observables +can be used on the fly with the toolbox of accumulators and correlators. + +The first step of the core analysis is to create an observable. +An observable in the sense of the core analysis can be considered as a +rule how to compute a certain set of numbers from a given state of the +system or a rule how to collect data from other observables. Any +observable is represented as a single array of double values in the core. +Any more complex shape (tensor, complex number, …) must be compatible to this +prerequisite. Every observable however documents the storage order and returns +a reshaped numpy array. + +The observables can be used in parallel simulations. However, +not all observables carry out their calculations in parallel. +Instead, the entire particle configuration is collected on the head node, +and the calculations are carried out there. +This is only performance-relevant if the number of processor cores is large +and/or interactions are calculated very frequently. + +.. _Using observables: + +Using observables +~~~~~~~~~~~~~~~~~ + +The observables are represented as Python classes derived from +:class:`espressomd.observables.Observable`. They are contained in +the ``espressomd.observables`` module. An observable is instantiated as +follows + +:: + + import espressomd.observables + part_pos = espressomd.observables.ParticlePositions(ids=(1, 2, 3, 4, 5)) + +Here, the keyword argument ``ids`` specifies the ids of the particles, +which the observable should take into account. + +The current value of an observable can be obtained using its +:meth:`~espressomd.observables.Observable.calculate` method:: + + print(part_pos.calculate()) + +Profile observables have additional methods +:meth:`~espressomd.observables.ProfileObservable.bin_centers` and +:meth:`~espressomd.observables.ProfileObservable.bin_edges` to facilitate +plotting of histogram slices with functions that require either bin centers +or bin edges for the axes. Example:: + + import matplotlib.pyplot as plt + import numpy as np + import espressomd + import espressomd.observables + + system = espressomd.System(box_l=[10.0, 10.0, 10.0]) + p1 = system.part.add(pos=[4.0, 3.0, 6.0]) + p2 = system.part.add(pos=[7.0, 3.0, 6.0]) + + # histogram in Cartesian coordinates + density_profile = espressomd.observables.DensityProfile( + ids=[p1.id, p2.id], + n_x_bins=8, min_x=1.0, max_x=9.0, + n_y_bins=8, min_y=1.0, max_y=9.0, + n_z_bins=4, min_z=4.0, max_z=8.0) + obs_data = density_profile.calculate() + obs_bins = density_profile.bin_centers() + + # 1D slice: requires bin centers + plt.plot(obs_bins[:, 2, 2, 0], obs_data[:, 2, 2]) + plt.show() + + # 2D slice: requires extent + plt.imshow(obs_data[:, :, 2].T, origin='lower', + extent=[density_profile.min_x, density_profile.max_x, + density_profile.min_y, density_profile.max_y]) + plt.show() + +Observables based on cylindrical coordinates are also available. +They require special parameters if the cylindrical coordinate system is non-standard, +e.g. if you want the origin of the cylindrical coordinates to be at a special location +of the box or if you want to make use of symmetries along an axis that is not parallel to the z-axis. +For this purpose, use :class:`espressomd.math.CylindricalTransformationParameters` +to create a consistent set of the parameters needed. Example:: + + import espressomd.math + + # shifted and rotated cylindrical coordinates + cyl_transform_params = espressomd.math.CylindricalTransformationParameters( + center=[5.0, 0.0, 5.0], axis=[0, 1, 0], orientation=[0, 0, 1]) + + # histogram in cylindrical coordinates + density_profile = espressomd.observables.CylindricalDensityProfile( + ids=[p1.id, p2.id], + transform_params = cyl_transform_params, + n_r_bins=8, min_r=1.0, max_r=4.0, + n_phi_bins=16, min_phi=-np.pi, max_phi=np.pi, + n_z_bins=4, min_z=0.0, max_z=8.0) + obs_data = density_profile.calculate() + obs_bins = density_profile.bin_edges() + + # 2D slice: requires bin edges + fig = plt.figure() + ax = fig.add_subplot(111, polar='True') + r = obs_bins[:, 0, 0, 0] + phi = obs_bins[0, :, 0, 1] + ax.pcolormesh(phi, r, obs_data[:, :, 1]) + plt.show() + + +.. _Available observables: + +Available observables +~~~~~~~~~~~~~~~~~~~~~ + +The following list contains some of the available observables. You can find +documentation for all available observables in :mod:`espressomd.observables`. + +- Observables working on a given set of particles: + - :class:`~espressomd.observables.ParticlePositions`: Positions of the particles + + - :class:`~espressomd.observables.ParticleVelocities`: Velocities of the particles + + - :class:`~espressomd.observables.ParticleForces`: Forces on the particles + + - :class:`~espressomd.observables.ParticleBodyVelocities`: The particles' velocities in their respective body-fixed frames (as per their orientation in space stored in their quaternions). + + - :class:`~espressomd.observables.ParticleAngularVelocities`: The particles' angular velocities in the space-fixed frame + + - :class:`~espressomd.observables.ParticleBodyAngularVelocities`: As above, but in the particles' body-fixed frame. + +- Observables working on a given set of particles and returning reduced quantities: + - :class:`~espressomd.observables.DipoleMoment`: Total electric dipole moment of the system obtained based on unfolded positions + + - :class:`~espressomd.observables.MagneticDipoleMoment`: Total magnetic dipole moment of the system based on the :attr:`~espressomd.particle_data.ParticleHandle.dip` property. + + - :class:`~espressomd.observables.ComPosition`: The system's center of mass based on unfolded coordinates + + - :class:`~espressomd.observables.ComVelocity`: Velocity of the center of mass + + - :class:`~espressomd.observables.ParticleDistances`: Distances between particles on a polymer chain. + + - :class:`~espressomd.observables.TotalForce`: Sum of the forces on the particles + + - :class:`~espressomd.observables.BondAngles`: Angles between bonds on a polymer chain. + + - :class:`~espressomd.observables.BondDihedrals`: Dihedral angles between bond triples on a polymer chain. + + - :class:`~espressomd.observables.CosPersistenceAngles`: Cosine of angles between bonds. The ``i``-th value in the result vector corresponds to the cosine of the angle between + bonds that are separated by ``i`` bonds. This observable might be useful for measuring the persistence length of a polymer. + + - :class:`~espressomd.observables.RDF`: Radial distribution function. Can be used on two different sets of particles. + +- Profile observables sampling the spatial profile of various quantities: + - :class:`~espressomd.observables.DensityProfile` + + - :class:`~espressomd.observables.FluxDensityProfile` + + - :class:`~espressomd.observables.ForceDensityProfile` + + - :class:`~espressomd.observables.LBVelocityProfile` + +- Observables sampling the cylindrical profile of various quantities: + - :class:`~espressomd.observables.CylindricalDensityProfile` + + - :class:`~espressomd.observables.CylindricalFluxDensityProfile` + + - :class:`~espressomd.observables.CylindricalVelocityProfile` + + - :class:`~espressomd.observables.CylindricalLBVelocityProfile` + + - :class:`~espressomd.observables.CylindricalLBFluxDensityProfileAtParticlePositions` + + - :class:`~espressomd.observables.CylindricalLBVelocityProfileAtParticlePositions` + +- System-wide observables + - :class:`~espressomd.observables.Energy`: Total energy (see :ref:`Energies`) + + - :class:`~espressomd.observables.Pressure`: Total scalar pressure (see :ref:`Pressure`) + + - :class:`~espressomd.observables.PressureTensor`: Total pressure tensor (see :ref:`Pressure Tensor`) + + - :class:`~espressomd.observables.DPDStress` + + +.. _Accumulators: + +Accumulators +~~~~~~~~~~~~ + +.. _Time series: + +Time series +^^^^^^^^^^^ + +In order to take snapshots of an observable, +:class:`espressomd.accumulators.TimeSeries` can be used:: + + import espressomd + import espressomd.observables + import espressomd.accumulators + + system = espressomd.System(box_l=[10.0, 10.0, 10.0]) + system.cell_system.skin = 0.4 + system.time_step = 0.01 + p1 = system.part.add(pos=[5.0, 5.0, 5.0], v=[0, 2, 0]) + position_observable = espressomd.observables.ParticlePositions(ids=[p1.id]) + accumulator = espressomd.accumulators.TimeSeries( + obs=position_observable, delta_N=2) + system.auto_update_accumulators.add(accumulator) + system.integrator.run(10) + print(accumulator.time_series()) + +In the example above the automatic update of the accumulator is used. However, +it's also possible to manually update the accumulator by calling +:meth:`espressomd.accumulators.TimeSeries.update`. + +.. _Mean-variance calculator: + +Mean-variance calculator +^^^^^^^^^^^^^^^^^^^^^^^^ + +In order to calculate the running mean and variance of an observable, +:class:`espressomd.accumulators.MeanVarianceCalculator` can be used:: + + import espressomd + import espressomd.observables + import espressomd.accumulators + + system = espressomd.System(box_l=[10.0, 10.0, 10.0]) + system.cell_system.skin = 0.4 + system.time_step = 0.01 + p1 = system.part.add(pos=[5.0, 5.0, 5.0], v=[0, 2, 0]) + position_observable = espressomd.observables.ParticlePositions(ids=[p1.id]) + accumulator = espressomd.accumulators.MeanVarianceCalculator( + obs=position_observable, delta_N=2) + system.auto_update_accumulators.add(accumulator) + system.integrator.run(10) + print(accumulator.mean()) + print(accumulator.variance()) + +In the example above the automatic update of the accumulator is used. However, +it's also possible to manually update the accumulator by calling +:meth:`espressomd.accumulators.MeanVarianceCalculator.update`. + + +.. _Correlations: + +Correlations +~~~~~~~~~~~~ + +Time correlation functions are ubiquitous in statistical mechanics and +molecular simulations when dynamical properties of many-body systems are +concerned. A prominent example is the velocity autocorrelation function, +:math:`\left< \mathbf{v}(t) \cdot \mathbf{v}(t+\tau) \right>` which is +used in the Green-Kubo relations. In general, time correlation functions +are of the form + +.. math:: + + C(\tau) = \left + + +where :math:`t` is time, :math:`\tau` is the lag time (time difference) +between the measurements of (vector) observables :math:`A` and +:math:`B`, and :math:`\otimes` is an operator which produces the vector +quantity :math:`C` from :math:`A` and :math:`B`. The ensemble average +:math:`\left< \cdot \right>` is taken over all time origins \ :math:`t`. +Correlation functions describing dynamics of large and complex molecules +such as polymers span many orders of magnitude, ranging from MD time +step up to the total simulation time. + +A correlator takes one or two observables, obtains values from them during the simulation and +finally uses a fast correlation algorithm which enables efficient computation +of correlation functions spanning many orders of magnitude in the lag time. + +The implementation for computing averages and error estimates of a time series +of observables relies on estimates of autocorrelation functions and the +respective autocorrelation times. The correlator provides the same +functionality as a by-product of computing the correlation function. + +An example of the usage of observables and correlations is provided in +the script :file:`samples/observables_correlators.py`. + +.. _Creating a correlation: + +Creating a correlation +^^^^^^^^^^^^^^^^^^^^^^ + +Each correlator is represented by an instance of the :class:`espressomd.accumulators.Correlator`. +Please see its documentation for an explanation of the arguments that have to be passed to the constructor. + +Correlators can be registered for automatic updating during the +integration by adding them to :attr:`espressomd.system.System.auto_update_accumulators`. + +:: + + system.auto_update_accumulators.add(corr) + +Alternatively, an update can triggered by calling the ``update()`` method of the correlator instance. +In that case, one has to make sure to call the update in the correct time intervals. + + +The current on-the-fly correlation result can of a correlator can be obtained using its ``result()`` method. +The final result (including the latest data in the buffers) is obtained using the ``finalize()`` method. +After this, no further update of the correlator is possible. + +.. _Example\: Calculating a particle's diffusion coefficient: + +Example: Calculating a particle's diffusion coefficient +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +For setting up an observable and correlator to obtain the mean square displacement of particle 0, use:: + + pos_obs = ParticlePositions(ids=[p1.id]) + c_pos = Correlator(obs1=pos_obs, tau_lin=16, tau_max=100., delta_N=10, + corr_operation="square_distance_componentwise", compress1="discard1") + +To obtain the velocity auto-correlation function of particle 0, use:: + + obs = ParticleVelocities(ids=[p1.id]) + c_vel = Correlator(obs1=vel_obs, tau_lin=16, tau_max=20., delta_N=1, + corr_operation="scalar_product", compress1="discard1") + +The full example can be found in :file:`samples/diffusion_coefficient.py`. +Note that in this example, the operation :literal:`square_distance_componentwise` +is used, which is not a correlation function in the mathematical sense. Other +available operations include actual correlation functions, as described +in the source documentation of :class:`espressomd.accumulators.Correlator`. + + +.. _Details of the multiple tau correlation algorithm: + +Details of the multiple tau correlation algorithm +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Here we briefly describe the multiple tau correlator which is +implemented in |es|. For a more detailed description and discussion of its +behavior with respect to statistical and systematic errors, please read +the cited literature. This type of correlator has been in use for years +in the analysis of dynamic light +scattering :cite:`schatzel88a`. About a decade later it +found its way to the Fluorescence Correlation Spectroscopy +(FCS) :cite:`magatti01a`. The book of Frenkel and +Smit :cite:`frenkel02b` describes its application for the +special case of the velocity autocorrelation function. + +.. _fig_correlator_scheme: + +.. figure:: figures/correlator_scheme.png + :scale: 50 % + :alt: Schematic representation of buffers in the correlator. + + Schematic representation of buffers in the correlator. + +Let us consider a set of :math:`N` observable values as schematically +shown in the figure above, where a value of index :math:`i` was +measured at times :math:`i\delta t`. We are interested in computing the +correlation function for a range +of lag times :math:`\tau = (i-j)\delta t` between the measurements +:math:`i` and :math:`j`. To simplify the notation, we drop +:math:`\delta t` when referring to observables and lag times. + +The trivial implementation takes all possible pairs of values +corresponding to lag times +:math:`\tau \in [{\tau_{\mathrm{min}}}:{\tau_{\mathrm{max}}}]`. Without +loss of generality, we consider +:math:`{\tau_{\mathrm{min}}}=0`. The computational effort for such an +algorithm scales as +:math:`{\cal O} \bigl({\tau_{\mathrm{max}}}^2\bigr)`. As a rule of +thumb, this is feasible if :math:`{\tau_{\mathrm{max}}}< 10^3`. The +multiple tau correlator provides a solution to compute the correlation +functions for arbitrary range of the lag times by coarse-graining the +high :math:`\tau` values. It applies the naive algorithm to a relatively +small range of lag times :math:`\tau \in [0:p-1]` +(:math:`p` corresponds to parameter ``tau_lin``). +This we refer to as compression level 0. +To compute the correlations for lag times +:math:`\tau \in [p:2(p-1)]`, the original data are first coarse-grained, +so that :math:`m` values of the original data are compressed to produce +a single data point in the higher compression level. Thus the lag time +between the neighboring values in the higher compression level +increases by a factor of :math:`m`, while the number of stored values +decreases by the same factor and the number of correlation operations at +this level reduces by a factor of :math:`m^2`. Correlations for lag +times :math:`\tau \in [2p:4(p-1)]` are computed at compression level 2, +which is created in an analogous manner from level 1. This can continue +hierarchically up to an arbitrary level for which enough data is +available. Due to the hierarchical reduction of the data, the algorithm +scales as +:math:`{\cal O} \bigl( p^2 \log({\tau_{\mathrm{max}}}) \bigr)`. Thus an +additional order of magnitude in :math:`{\tau_{\mathrm{max}}}` costs +just a constant extra effort. + +The speedup is gained at the expense of statistical accuracy. The loss +of accuracy occurs at the compression step. In principle one can use any +value of :math:`m` and :math:`p` to tune the algorithm performance. +However, it turns out that using a high :math:`m` dilutes the data at +high :math:`\tau`. Therefore :math:`m=2` is hard-coded in the correlator +and cannot be modified by user. The value of :math:`p` remains an +adjustable parameter which can be modified by user by setting when +defining a correlation. In general, one should choose :math:`p \gg m` to +avoid loss of statistical accuracy. Choosing :math:`p=16` seems to be +safe but it may depend on the properties of the analyzed correlation +functions. A detailed analysis has been performed in +Ref. :cite:`ramirez10a`. + +The choice of the compression function also influences the statistical +accuracy and can even lead to systematic errors. The default compression +function discards the second value and +pushes the first one to the higher level. This is robust and can be +applied universally to any combination of observables and correlation +operation. On the other hand, it reduces the statistical accuracy as the +compression level increases. In many cases, the compression operation +can be applied, which averages the two neighboring values and the +average then enters the higher level, preserving almost the full +statistical accuracy of the original data. In general, if averaging can +be safely used or not, depends on the properties of the difference + +.. math:: + + \frac{1}{2} (A_i \otimes B_{i+p} + A_{i+1} \otimes B_{i+p+1} ) - + \frac{1}{2} (A_i + A_{i+1} ) \otimes \frac{1}{2} (B_{i+p} + B_{i+p+1}) + \label{eq:difference} + +For example in the case of velocity autocorrelation function, the +above-mentioned difference has a small value and a random sign,   +different contributions cancel each other. On the other hand, in the of +the case of mean square displacement the difference is always positive, +resulting in a non-negligible systematic error. A more general +discussion is presented in Ref. :cite:`ramirez10a`. + +Cluster analysis +---------------- + +|es| provides support for online cluster analysis. Here, a cluster +is a group of particles, such that you can get from any particle +to any second particle by at least one path of neighboring particles. +I.e., if particle B is a neighbor of particle A, particle C is a neighbor +of A and particle D is a neighbor of particle B, all four particles are +part of the same cluster. The cluster analysis is available in parallel +simulations, but the analysis is carried out on the head node, only. + + +Whether or not two particles are neighbors is defined by a pair criterion. +The available criteria can be found in :mod:`espressomd.pair_criteria`. +For example, a distance criterion which will consider particles as neighbors +if they are closer than 0.11 is created as follows:: + + import espressomd.pair_criteria + dc = espressomd.pair_criteria.DistanceCriterion(cut_off=0.11) + +To obtain the cluster structure of a system, an instance of +:class:`espressomd.cluster_analysis.ClusterStructure` has to be created. +To to create a cluster structure with above criterion:: + + import espressomd.cluster_analysis + cs = espressomd.cluster_analysis.ClusterStructure(distance_criterion=dc) + +In most cases, the cluster analysis is carried out by calling the +:any:`espressomd.cluster_analysis.ClusterStructure.run_for_all_pairs` method. +When the pair criterion is purely based on bonds, +:any:`espressomd.cluster_analysis.ClusterStructure.run_for_bonded_particles` can be used. + +The results can be accessed via ClusterStructure.clusters, which is an instance of +:any:`espressomd.cluster_analysis.Clusters`. + +Individual clusters are represented by instances of +:any:`espressomd.cluster_analysis.Cluster`, which provides access to the +particles contained in a cluster as well as per-cluster analysis routines +such as radius of gyration, center of mass and longest distance. +Note that the cluster objects do not contain copies of the particles, +but refer to the particles in the simulation. Hence, the objects become +outdated if the simulation system changes. On the other hand, it is possible +to directly manipulate the particles contained in a cluster. diff --git a/doc4.2.2/_sources/appendix.rst.txt b/doc4.2.2/_sources/appendix.rst.txt new file mode 100644 index 0000000000..e3f17d0560 --- /dev/null +++ b/doc4.2.2/_sources/appendix.rst.txt @@ -0,0 +1,492 @@ +.. _Appendix: + +Appendix +======== + +.. _The MMM family of algorithms: + +The MMM family of algorithms +---------------------------- + +.. _MMM_Introduction: + +Introduction +~~~~~~~~~~~~ + +In the MMM family of algorithms for the electrostatic interaction, a +convergence factor approach to tackle the conditionally convergent +Coulomb sum is used (even the authors of the original MMM method have no +idea what this acronym stands for). Instead of defining the summation +order, one multiplies each summand by a continuous factor +:math:`c(\beta,r_{ij},n_{klm})` such that the sum is absolutely +convergent for :math:`\beta>0`, but :math:`c(0,.,.)=1`. The energy is +then defined as the limit :math:`\beta\rightarrow 0` of the sum, i.e. +:math:`\beta` is an artificial convergence parameter. For a convergence +factor of :math:`e^{-\beta n_{klm}^2}` the limit is the same as the spherical +limit, and one can derive the classical Ewald method quite conveniently through +this approach :cite:`smith81a`. To derive the formulas for MMM, +one has to use a different convergence factor, namely +:math:`e^{-\beta|r_{ij}+n_{klm}|}`, which defines the alternative energy + +.. math:: + + \tilde{E}=\,\frac{1}{2}\lim_{\beta\rightarrow + 0}\sum_{k,l,m}{\sum_{i,j=1}^N}' \frac{q_i q_je^{-\beta|p_{ij} + + n_{klm}|}} {|p_{ij} + n_{klm}|} + =:\,\frac{1}{2}\lim_{\beta\rightarrow 0}\sum_{i,j=1}^N + q_iq_j\phi_\beta(x_{ij}, y_{ij},z_{ij}). + +:math:`\phi_\beta` is given by +:math:`\phi_\beta(x,y,z)=\,\tilde\phi_\beta(x,y,z) ++ \frac{e^{-\beta r}}{r}` for :math:`(x,y,z)\neq 0` and +:math:`\phi_\beta(0,0,0)=\,\tilde\phi_\beta(0,0,0)`, where + +.. math:: + + \tilde\phi_\beta(x,y,z)=\,\sum_{(k,l,m)\neq 0} \frac{e^{-\beta + r_{klm}}}{r_{klm}}. + +The limit :math:`\tilde{E}` exists, but differs for three-dimensionally +periodic systems by some multiple of the square of the dipole moment +from the spherical limit as obtained by the Ewald +summation :cite:`smith81a`. From the physical point of view +the Coulomb interaction is replaced by a screened Coulomb interaction +with screening length :math:`1/\beta`. :math:`\tilde{E}` is then the +energy in the limit of infinite screening length. But because of the +conditional convergence of the electrostatic sum, this is not +necessarily the same as the energy of an unscreened system. Since the +difference to the Ewald methods only depends on the dipole moment of the +system, the correction can be calculated easily in linear time and can +be ignored with respect to accuracy as well as to computation time. + +For one- or two-dimensionally systems, however, :math:`\tilde{E}=E`, the +convergence factor approach equals the spherical summation limit of the +Ewald sum, and MMM1D and MMM2D do not require a dipole correction. + +Starting from this convergence factor approach, Strebel constructed a +method of computational order :math:`O(N\log N)`, which is called MMM +:cite:`strebel99a`. The favorable scaling is obtained, +very much like in the Ewald case, by technical tricks in the calculation +of the far formula. The far formula has a product decomposition and can +be evaluated hierarchically similarly to the fast multipole methods. + +For particles sufficiently separated in the z-axis one can Fourier +transform the potential along both x and y. We obtain the far formula as + +.. math:: + + \phi(x,y,z) =\, u_x u_y\sum_{p,q\neq 0} \frac{e^{2\pi f_{pq}z} + + e^{2\pi f_{pq}(\lambda_z-z)}}{f_{pq} \left(e^{2\pi f_{pq}\lambda_z} + - 1\right)} e^{2\pi i u_y q y}e^{2\pi i u_x p x} + 2\pi u_x + u_y\left(u_z z^2 - z + \frac{\lambda_z}{6}\right). + +where :math:`\lambda_{x,y,z}` are the box dimensions, :math:`f_{pq} =\, +\sqrt{(u_x p)^2 + (u_y q)^2},\quad f_p =\, u_x p,\quad f_q =\, u_x q`, +:math:`\omega_p=2\pi u_x p` and :math:`\omega_q=2\pi u_y q`. The +advantage of this formula is that it allows for a product decomposition +into components of the particles. For example + +.. math:: + + e^{2\pi f_{pq}z}=e^{2\pi f_{pq}(z_i-z_j)}=e^{2\pi + f_{pq}z_i}e^{-2\pi f_{pq}z_j} + +etc. Therefore one just has to calculate the sum over all these +exponentials on the left side and on the right side and multiply them +together, which can be done in :math:`O(N)` computation time. As can be +seen easily, the convergence of the series is excellent as long as z is +sufficiently large. By symmetry one can choose the coordinate with the +largest distance as z to optimize the convergence. Similar to the Lekner +sum, we need a different formula if all coordinates are small, i.e. for +particles close to each other. For sufficiently small :math:`u_y\rho` +and :math:`u_xx` we obtain the near formula as + +.. math:: + + \begin{array}{rl} \tilde\phi(x,y,z)=\, & 2 u_x + u_y\sum\limits_{p,q>0} \frac{\cosh(2\pi f_{pq}z)}{f_{pq} + \left(e^{2\pi f_{pq}\lambda_z} - 1\right)} e^{2\pi i u_y q + y}e^{2\pi i u_x p x} +\\ & 4u_x\sum\limits_{l,p>0}\left(K_0(2\pi + u_x p\rho_l) + K_N(2\pi u_x p\rho_{-l})\right)cos(2\pi u_x p x) + -\\ & 2u_x\sum\limits_{n\ge 1}\frac{b_{2n}}{2n(2n)!}\Re\bigl((2\pi + u_y (z+iy))^{2n}\bigr) +\\ & u_x\sum\limits_{n\ge + 0}\left(\begin{array}{c}-\frac{1}{2}\\ + n\end{array}\right)\frac{\left( \psi^{(2n)}(1 + u_x x) + + \psi^{(2n)}(1 - u_x x)\right)}{(2n)!}\rho^{2n} -\\ & + 2\log(4\pi). \end{array} + +Note that this time we calculate :math:`\tilde{\phi}` instead of +:math:`\phi`, i.e. we omit the contribution of the primary simulation +box. This is very convenient as it includes the case of self energy and +makes :math:`\tilde{\phi}` a smooth function. To obtain :math:`\phi` one +has to add the :math:`1/r` contribution of the primary box. The self +energy is given by + +.. math:: + + \tilde\phi(0,0,0)=\, 2 u_x u_y\sum\limits_{p,q>0} \frac{1}{f_{pq} + \left(e^{2\pi f_{pq}\lambda_z} - 1\right)}+ + 8u_x\sum\limits_{l,p>0}K_N(2\pi u_x\lambda_y p l) + 2 u_x\psi^{(0)}(1) + - 2\log(4\pi). + +Both the near and far formula are derived using the same convergence +factor approach, and consequently the same singularity in :math:`\beta` +is obtained. This is important since otherwise the charge neutrality +argument does not hold. + +To obtain the :math:`O(N\log N)` scaling, some algorithm tricks are +needed, which are not used in MMM1D, MMM2D or ELC and are therefore not +discussed here. For details, see :cite:`strebel99a`. + +.. _MMM2D theory: + +MMM2D theory +~~~~~~~~~~~~ + +In the case of periodicity only in the x and y directions, the far +formula looks like + +.. math:: + + \begin{array}{rl} \phi(x,y,z) = \, & 4 u_x u_y\sum_{p,q>0} + \frac{e^{-2\pi f_{pq}|z|}} {f_{pq}} \cos(\omega_p x)\cos(\omega_q y) + +\\ & 2 u_x u_y\left(\sum_{q>0} \frac{e^{-2\pi f_q|z|}}{f_q} + \cos(\omega_q y) + \sum_{p>0} \frac{e^{-2\pi f_p|z|}}{f_p} + \cos(\omega_p x)\right) -\\ & 2\pi u_x u_y |z|, \end{array} + +and the near formula is + +.. math:: + + \begin{array}{rl} \tilde\phi(x,y,z)=\, & + 4u_x\sum_{l,p>0}\left(K_0(\omega_p\rho_l) + + K_0(\omega_p\rho_{-l})\right)\cos(\omega_p x) -\\ & 2u_x\sum_{n\ge + 1}\frac{b_{2n}}{2n(2n)!} \Re\bigl((2\pi u_y + (z+iy))^{2n}\bigr)\,+\, \sum_{k=1}^{N_\psi-1}\left(\frac{1}{r_{k}} + + \frac{1}{r_{-k}}\right) -\\ & u_x\sum_{n\ge + 0}\left(\begin{array}{c}-\frac{1}{2}\\n\end{array}\right)\frac{\left( + \psi^{(2n)}(N_\psi + u_x x) + \psi^{(2n)}(N_\psi - u_x + x)\right)}{(2n)!}(u_x\rho)^{2n} -\\ & + 2u_x\log\left(4\pi\frac{u_y}{u_x}\right). \end{array} + +As said before, the energy obtained from these potentials is equal to +the electrostatic energy obtained by the spherical summation limit. The +deeper reason for this is that in some sense the electrostatic sum is +absolutely convergent :cite:`arnold02a`. + +The near formula is used for particles with a small distance along the z +axis, for all other particles the far formula is used. Below is shown, +that the far formula can be evaluated much more efficiently, however, +its convergence breaks down for small z distance. To efficiently +implement MMM2D, the layered cell system is required, which splits up +the system in equally sized gaps along the z axis. The interaction of +all particles in a layer S with all particles in the layers S-1,S,S+1 is +calculated using the near formula, for the particles in layers +:math:`1,\dots,S-2`, and in layers :math:`S+2,\dots,N`, the far formula +is used. + +The implementation of the near formula is relatively straight forward +and can be treated as any short ranged force is treated using the link +cell algorithm, here in the layered variant. The special functions in +the formula are somewhat demanding, but for the polygamma functions +Taylor series can be achieved, which are implemented in :file:`mmm-common.hpp`. +The Bessel functions are calculated using a Chebychev series. + +The treatment of the far formula is algorithmically more complicated. +For a particle i in layer :math:`S_i`, the formula can product +decomposed, as in + +.. math:: + + \begin{array}{rl} \sum_{j\in I_S, S < S_i - 1} q_iq_j\frac{e^{-2\pi + f_{pq}|z_i-z_j|}}{f_{pq}} \cos(\omega_p (x_i - + x_j))\cos(\omega_q (y_i - y_j)) = \\ + q_i\frac{e^{-2\pi f_{pq}z_i}}{f_{pq}} \cos(\omega_p + x_i)\cos(\omega_q y_i) \sum_{j\in I_S, S < S_i - 1}q_je^{2\pi + f_{pq}z_j} \cos(\omega_p x_j)\cos(\omega_q y_j) + \\ + q_i\frac{e^{-2\pi f_{pq}z_i}}{f_{pq}} \cos(\omega_p + x_i)\sin(\omega_q y_i) \sum_{j\in I_S, S < S_i - 1}q_je^{2\pi + f_{pq}z_j} \cos(\omega_p x_j)\sin(\omega_q y_j) + \\ + q_i\frac{e^{-2\pi f_{pq}z_i}}{f_{pq}} \sin(\omega_p + x_i)\cos(\omega_q y_i) \sum_{j\in I_S, S < S_i - 1}q_je^{2\pi + f_{pq}z_j} \sin(\omega_p x_j)\cos(\omega_q y_j) + \\ + q_i\frac{e^{-2\pi f_{pq}z_i}}{f_{pq}} \sin(\omega_p + x_i)\sin(\omega_q y_i) \sum_{j\in I_S, S < S_i - 1}q_je^{2\pi + f_{pq}z_j} \sin(\omega_p x_j)\sin(\omega_q y_j). \end{array} + +This representation has the advantage, that the contributions of the two +particles are decoupled. For all particles j only the eight terms + +.. math:: + + \xi^{(\pm,s/c,s/c)}_j= q_je^{\pm 2\pi f_{pq}z_j} \sin/\cos(\omega_p + x_j)\sin/\cos(\omega_q y_j) + +are needed. The upper index describes the sign of the exponential term +and whether sine or cosine is used for :math:`x_j` and :math:`y_j` in +the obvious way. These terms can be used for all expressions on the +right hand side of the product decomposition. Moreover it is easy to see +from the addition theorem for the sine function that these terms also +can be used to calculate the force information up to simple prefactors +that depend only on p and q. + +Every processor starts with the calculation of the terms +:math:`\xi^{(\pm,s/c,s/c)}_j` and adds them up in each layer, so that +one obtains + +.. math:: \Xi^{(\pm,s/c,s/c)}_s= \sum_{j\in S_s}\xi^{(\pm,s/c,s/c)}_j. + +Now we calculate + +.. math:: \Xi^{(l,s/c,s/c)}_s=\sum_{t < s - 1}\Xi^{(+,s/c,s/c)}_t + +and + +.. math:: \Xi^{(h,s/c,s/c)}_s=\sum_{t > s + 1}\Xi^{(-,s/c,s/c)}_t, + +which are needed for the evaluation of the product decomposition. While +the bottom processor can calculate :math:`\Xi^{(l,s/c,s/c)}_s` directly, +the other processors are dependent on its results. Therefore the bottom +processor starts with the calculation of its :math:`\Xi^{(l,s/c,s/c)}_s` +and sends up :math:`\Xi^{(l,s/c,s/c)}_s` and :math:`\Xi^{(+,s/c,s/c)}_s` +of its top layer s to the next processor dealing with the layers above. +Simultaneously the top processor starts with the calculation of the +:math:`\Xi^{(h,s/c,s/c)}_s` and sends them down. After the communicated +has been completed, every processor can use the +:math:`\Xi^{(l/h,s/c,s/c)}_j` and the :math:`\xi^{(\pm,s/c,s/c)}_j` to +calculate the force rsp. energy contributions for its particles. + +In pseudo code, the far formula algorithm looks like: + +#. for each layer :math:`s=1,\ldots,S` + + #. :math:`\Xi^{(\pm,s/c,s/c)}_s=0` + + #. for each particle :math:`j` in layer :math:`s` + + #. calculate :math:`\xi^{(\pm,s/c,s/c)}_j` + + #. :math:`\Xi^{(\pm,s/c,s/c)}_s += \xi^{(\pm,s/c,s/c)}_j` + +#. :math:`\Xi^{(l,s/c,s/c)}_3=\Xi^{(+,s/c,s/c)}_1` + +#. for each layer :math:`s=4,\ldots,S` + + #. .. math:: + \Xi^{(l,s/c,s/c)}_s=\Xi^{(l,s/c,s/c)}_{s-1} +\ + \Xi^{(+,s/c,s/c)}_{s-2} + +#. :math:`\Xi^{(l,s/c,s/c)}_{S-2}=\Xi^{(-,s/c,s/c)}_S` + +#. for each layer :math:`s=(S-3),...,1` + + #. .. math:: + \Xi^{(l,s/c,s/c)}_s=\Xi^{(l,s/c,s/c)}_{s+1} +\ + \Xi^{(-,s/c,s/c)}_{s+2} + +#. for each layer :math:`s=1,...,S` + + #. for each particle :math:`j` in layer :math:`s` + + #. calculate particle interaction from + :math:`\xi^{(+,s/c,s/c)}_j\Xi^{(l,s/c,s/c)}_s` and + :math:`\xi^{(-,s/c,s/c)}_j\Xi^{(h,s/c,s/c)}_s` + +For further details, see :cite:`arnold02a,arnold02b,arnold02c,arnold02d`. + +.. _Dielectric contrast: + +Dielectric contrast +^^^^^^^^^^^^^^^^^^^ + +A dielectric contrast at the lower and/or upper simulation box boundary +can be included comparatively easy by using image charges. Apart from +the images of the lowest and topmost layer, the image charges are far +enough to be treated by the far formula, and can be included as starting +points in the calculation of the :math:`\Xi` terms. The remaining +particles from the lowest and topmost layer are treated by direct +summation of the near formula. + +This means, that in addition to the algorithm above, one has to only a +few things: during the calculation of the particle and cell blocks +:math:`\xi` and :math:`\Xi`, one additionally calculates the +contributions of the image charges and puts them either in a separate +array or, for the boundary layers, into two extra :math:`\xi` cell +blocks outside the simulation box. The entries in the separate array are +then added up over all processors and stored in the :math:`\Xi`-terms of +the lowest/topmost layer. This are all modifications necessary for the +far formula part. In addition to the far formula part, there is an +additional loop over the particles at the boundary to directly calculate +their interactions with their images. For details, refer to +:cite:`tyagi07a`. + +.. _MMM1D theory: + +MMM1D theory +~~~~~~~~~~~~ + +In one-dimensionally periodic systems with z being the periodic +coordinate, the far formula looks like + +.. math:: + + \begin{array}{rl} \phi(\rho,z) &=\, 4 u_z\sum_{p\neq 0} + K_0(\omega\rho)\cos(\omega z) - 2u_z\log(\frac{\rho}{2\lambda_z}) - + 2u_z\gamma\\ F_\rho(\rho,z) &=\, 8\pi u_z^2\sum_{p\neq 0} p + K_1(\omega\rho)\cos(\omega z) + \frac{2 u_z}{\rho}\\ F_z(\rho,z) + &=\, 8\pi u_z^2 \sum_{p\neq 0} pK_0(\omega\rho)\sin(\omega z), + \end{array} + +the near formula is + +.. math:: + + \begin{array}{rl} \tilde{\phi}(\rho,z) &=\, -u_z\sum_{n\ge 0} + \left(\begin{array}{c}-\frac{1}{2}\\n\end{array}\right) + \frac{\left(\psi^{(2n)}(N_\psi + u_z z) + \psi^{(2n)}(N_\psi - u_z + z)\right)}{(2n)!}(u_z\rho)^{2n} - 2u_z\gamma + \\ + &\phantom{=\,++} + \sum_{k=1}^{N_\psi-1}\left(\frac{1}{r_k}+\frac{1}{r_{-k}}\right)\\ + \tilde{F}_\rho(\rho,z) &=\, -u_z^3 \sum_{n\ge 0} + \left(\begin{array}{c}-\frac{1}{2}\\n\end{array}\right) + \frac{\left(\psi^{(2n)}(N_\psi + u_z z) + \psi^{(2n)}(N_\psi - u_z + z)\right)}{(2n)!}(u_z\rho)^{2n-1} + \\ &\phantom{=\,++} + \sum_{k=1}^{N_\psi-1}\left(\frac{\rho}{r_k^3}+\frac{\rho}{r_{-k}^3}\right) + \\ \tilde{F}_z(\rho,z) &=\, -u_z^2 \sum_{n\ge 0} + \left(\begin{array}{c}-\frac{1}{2}\\n\end{array}\right) + \frac{\left(\psi^{(2n + 1)}(N_\psi + u_z z) + \psi^{(2n + 1)}(N_\psi + - u_z z)\right)}{(2n)!}(u_z\rho)^{2n} + \\ &\phantom{=\,++} + \sum_{k=1}^{N_\psi-1}\left(\frac{z+k\lambda_z}{r_k^3}+\frac{z-k\lambda_z}{r_{-k}^3}\right), + \end{array} + +where :math:`\rho` denotes the xy-distance of the particles. As for the +two-dimensional periodic case, the obtained energy is equal to the +one-dimensional Ewald sum. Algorithmically, MMM1D is uninteresting, since +neither the near nor far formula allow a product decomposition or +similar tricks. MMM1D has to be implemented as a simple NxN loop. +However, the formulas can be evaluated efficiently, so that MMM1D can +still be used reasonably for up to 400 particles on a single processor +:cite:`arnold05a`. + +.. _ELC theory: + +ELC theory +~~~~~~~~~~ + +The ELC method differs from the other MMM algorithms in that it is not +an algorithm for the calculation of the electrostatic interaction, but +rather represents a correction term which allows to use any method for +three-dimensionally periodic systems with spherical summation order for +two-dimensional periodicity. The basic idea is to expand the +two-dimensional slab system of height h in the non-periodic z-coordinate to +a system with periodicity in all three dimensions, with a period of +:math:`\lambda_z > h`, which leaves an empty gap of height +:math:`\delta = \lambda_z - h` above the particles in the simulation box. + +Since the electrostatic potential is only finite if the total system is +charge neutral, the additional image layers (those layers above or below +the original slab system) are charge neutral, too. Now let us consider +the n-th image layer which has an offset of :math:`n\lambda_z` to the +original layer. If :math:`n\lambda_z` is large enough, each particle of +charge :math:`q_j` at position :math:`(x_j,y_j,z_j+n\lambda_z)` and its +replicas in the xy-plane can be viewed as constituting a homogeneous +charged sheet of charge density +:math:`\sigma_j = \frac{q_j}{\lambda_x\lambda_y}`. The potential of such +a charged sheet at distance :math:`z` is :math:`2\pi \sigma_j |z|`. +Now we consider the contribution from a pair of image layers +located at :math:`\pm n\lambda_z`, n>0 to the energy of a charge :math:`q_i` at +position :math:`(x_i,y_i,z_i)` in the central layer. Since +:math:`|z_j - z_i| < n\lambda_z`, we have +:math:`|z_j - z_i + n\lambda_z| = n\lambda_z + z_j - z_i` +and :math:`|z_j - z_i - n\lambda_z|= n\lambda_z - z_j + z_i`, and +hence the interaction energy from those two image layers with the charge +:math:`q_i` vanishes by charge neutrality: + +.. math:: + + 2\pi q_i \sum_{j=1}^N \sigma_j(|z_j - z_i + n\lambda_z| + |z_j - + z_i - n\lambda_z|) = 4\pi q_i n\lambda_z \sum_{j=1}^N \sigma_j = 0. + +The only errors occurring are those coming from the approximation of +assuming homogeneously charged, infinite sheets instead of discrete +charges. This assumption should become better when increasing the +distance :math:`n\lambda_z` from the central layer. + +However, in a naive implementation, even large gap sizes will result in +large errors. This is due to the order of summation for the standard +Ewald sum, which is spherical, while the above approach orders the cells +in layers, called slab-wise summation. Smith has shown that by adding to +the Ewald energy the term + +.. math:: E_c=2\pi M_z^2 - \frac{2\pi M^2}{3}, + +where M is the total dipole moment, one obtains the result of a +slab-wise summation instead of the spherical limit +:cite:`smith81a`. Although this is a major change in the +summation order, the difference is a very simple term. In fact, Smith +shows that changes of the summation order always result in a difference +that depends only on the total dipole moment. + +Using the far formula of MMM2D, one can calculate the contributions of +the additional layers up to arbitrarily precision, even for small gap +sizes. This method is called electrostatic layer correction, ELC. The +advantage of this approach is that for the image layers, z is +necessarily large enough, so that all interactions can be represented +using the product decomposition. This allows for an order N evaluation +of the ELC term. + +The electrostatic layer correction term is given by + +.. math:: E_{lc}=\sum_{i,j=1}^Nq_iq_j\psi(p_i-p_j), + +where + +.. math:: + + \begin{array}{rl} \psi(x,y,z)=&4u_xu_y\sum_{p,q>0}\frac{\cosh(2\pi + f_{pq}z)}{f_{pq}(e^{2\pi f_{pq}\lambda_z} - 1)} \cos(\omega_p + x)\cos(\omega_q y) + \\ &2u_xu_y\sum_{p>0}\frac{\cosh(2\pi f_p + z)}{f_p(e^{2\pi f_p\lambda_z} - 1)}\cos(\omega_p x)+\\ + &2u_xu_y\sum_{q>0}\frac{\cosh(2\pi f_q z)}{f_q(e^{2\pi f_q\lambda_z} + - 1)}\cos(\omega_q y). \end{array} + +The implementation is very similar to MMM2D, except that the separation +between slices close by, and above and below is not necessary. + +.. _Errors: + +Errors +~~~~~~ + +Common to all algorithms of the MMM family is that accuracy is cheap +with respect to computation time. More precisely, the maximal pairwise +error, i.e. the maximal error of the :math:`\psi` expression decreases +exponentially with the cutoffs. In turn, the computation time grows +logarithmically with the accuracy. This is quite in contrast to the +Ewald methods, for which decreasing the error bound can lead to +excessive computation time. For example, P3M cannot reach a precision +beyond :math:`10^{-5}` in general. The precise form of the error +estimates is of little importance here, for details see +:cite:`arnold02c,arnold02d`. + +One important aspect is that the error estimates are also exponential in +the non-periodic coordinate. Since the number of close by and far away +particles is different for particles near the border and in the center +of the system, the error distribution is highly non-homogeneous. This is +unproblematic as long as the maximal error is really much smaller than +the thermal energy. However, one cannot interpret the error simply as an +additional error source. + +.. figure:: figures/elc-errordist.pdf + :alt: Error distribution of the ELC method. + :align: center + :height: 6.00000cm + + Error distribution of the ELC method. + +The figure shows the error distribution of the ELC method +for a gap size of :math:`10\%` of the total system height. For MMM2D and +MMM1D the error distribution is less homogeneous, however, also here it +is always better to have some extra precision, especially since it is +computationally cheap. + diff --git a/doc4.2.2/_sources/bibliography.rst.txt b/doc4.2.2/_sources/bibliography.rst.txt new file mode 100644 index 0000000000..5619f484ff --- /dev/null +++ b/doc4.2.2/_sources/bibliography.rst.txt @@ -0,0 +1,6 @@ +.. _Bibliography: + +Bibliography +============ + +.. bibliography:: bibliography.bib diff --git a/doc4.2.2/_sources/community.rst.txt b/doc4.2.2/_sources/community.rst.txt new file mode 100644 index 0000000000..de3a395c38 --- /dev/null +++ b/doc4.2.2/_sources/community.rst.txt @@ -0,0 +1,51 @@ +.. _Community: + +Community +========= + +.. _Community support: + +Community support +----------------- + +If you have any questions concerning |es| which you cannot resolve by +yourself, you may search for an answer on: + +- `GitHub issue tracker `__ +- `GitHub discussions `__ +- `espressomd-users mailing list archive `__ +- `Installation FAQ `__ + +If you still didn't find a solution, you may consider either opening a new +issue or discussion on GitHub, or sending an email on the mailing list. +Instructions on how to register to the mailing lists and post messages can be +found in `Mailing Lists +`__. +It is recommended to use these communication channels rather than to contact +individual developers, for several reasons: + +- All users get your message and you have a higher + probability that it is answered soon. +- Your question and the answers are archived and the archives can be + searched by others. +- The answer may be useful also to other users. +- There may not be a unique answer to your problem and it may be useful + to get suggestions from different people. + +Please remember that this is a community mailing list and a community GitHub +forum. It is other users and developers who are answering your questions. +They do it in their free time and are not paid for doing it. + +.. _Summer Schools: + +Summer Schools +-------------- + +Every year in October, a 5-day workshop is organized at University of Stuttgart, Germany. +Registration is free of charge and is managed by `CECAM `__. +Past events are archived on the |es| official website, under `Summer Schools +`__. +The teaching material can be found in the online documentation, section +`Tutorials `__. The lectures +can be found on the `ESPResSo Simulation Package +`__ YouTube channel. diff --git a/doc4.2.2/_sources/constraints.rst.txt b/doc4.2.2/_sources/constraints.rst.txt new file mode 100644 index 0000000000..b46a75f5bb --- /dev/null +++ b/doc4.2.2/_sources/constraints.rst.txt @@ -0,0 +1,596 @@ +.. _Single particle forces (constraints): + +Single particle forces (constraints) +==================================== + +:class:`espressomd.constraints.Constraint` + +A Constraint is an immobile surface which can interact with particles via a +non-bonded potential, where the distance between the two particles is +replaced by the distance of the center of the particle to the surface. + +The constraints are identified like a particle via its type ``particle_type`` for the +non-bonded interaction. After a type is defined for each constraint one +has to define the interaction of all different particle types with the +constraint using the :class:`espressomd.interactions.NonBondedInteractions` class. + +.. _Shaped-based constraints: + +Shaped-based constraints +------------------------ + +In order to use shapes you first have to import the :mod:`espressomd.shapes` +module. This module provides classes for the different available shapes:: + + import espressomd.shapes + +Shapes define geometries which can be used in |es| either as +constraints in particle interactions or as a boundary for a +lattice-Boltzmann fluid. + +To avoid unexpected behavior, make sure all parts of your shape are +within the central box since the distance to the shape is calculated only +within the central box. If parts of the shape are placed outside of the +central box, these parts are truncated by the box boundaries. This may +be desired as for example in the case of a cylinder shape whose end caps +could extend outside the box boundaries to create an infinite rod. + +In addition, particles will not interact with periodic images of shapes, +therefore make sure the shapes are not too close to any of the six sides +of the box. If the distance between the shape and the nearest box boundary +is less than the interaction cutoff, the potential will be discontinuous +when the particle crosses that periodic boundary. + +A shape is instantiated by calling its constructor. If you wanted to +create a wall shape you could do:: + + wall = espressomd.shapes.Wall() + +Available shapes are listed below. + +- :class:`espressomd.shapes.Wall` +- :class:`espressomd.shapes.Cylinder` +- :class:`espressomd.shapes.Ellipsoid` +- :class:`espressomd.shapes.Rhomboid` +- :class:`espressomd.shapes.SimplePore` +- :class:`espressomd.shapes.Slitpore` +- :class:`espressomd.shapes.Sphere` +- :class:`espressomd.shapes.SpheroCylinder` +- :class:`espressomd.shapes.Torus` +- :class:`espressomd.shapes.HollowConicalFrustum` +- :class:`espressomd.shapes.Union` + + +.. _Adding shape-based constraints to the system: + +Adding shape-based constraints to the system +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Usually you want to use constraints based on a shape. +The module :mod:`espressomd.constraints` provides the class +:class:`espressomd.constraints.ShapeBasedConstraint`:: + + shape_constraint = espressomd.constraints.ShapeBasedConstraint(shape=my_shape) + +In order to add the constraint to the system +invoke the :meth:`~espressomd.constraints.Constraints.add` method:: + + system.constraints.add(shape_constraint) + +All previously listed shapes can be added to the system constraints +by passing an initialized shape object to :meth:`~espressomd.constraints.Constraints.add`, returning a constraint object :: + + misshaped = Wall(dist=20, normal=[0.1, 0.0, 1]) + myConstraint = system.constraints.add(shape=myShape, particle_type=p_type) + +The extra argument ``particle_type`` specifies the non-bonded interaction to be used with +that constraint. + +There are two additional optional parameters +to fine-tune the behavior of the constraint. If ``penetrable`` is set to +``True`` then particles can move through the constraint. In this case the +other option ``only_positive`` controls where the particle is subjected to the +interaction potential (see :ref:`Available options`). +If the ``penetrable`` option is ignored or is set to ``False``, the +constraint cannot be violated, i.e. no +particle can go through the constraint surface (|es| will exit if any does). +If we wanted to add a non-penetrable pore constraint to our simulation, +we could do the following:: + + pore = espressomd.shapes.SimplePore( + axis=[1, 0, 0], length=2, pos=[15, 15, 15], radius=1, smoothing_radius=0.5) + pore_constraint = espressomd.constraints.ShapeBasedConstraint( + shape=pore, penetrable=False, particle_type=1) + system.constraints.add(pore_constraint) + +Interactions between the pore and other particles are then defined +as usual (:ref:`Non-bonded interactions`) to prevent particles from crossing +the shape surface. + +.. _Deleting a constraint: + +Deleting a constraint +^^^^^^^^^^^^^^^^^^^^^ + +Constraints can be removed in a similar fashion using :meth:`espressomd.constraints.Constraints.remove` :: + + system.constraints.remove(myConstraint) + +This command will delete the specified constraint. + + +.. _Getting the currently defined constraints: + +Getting the currently defined constraints +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +One can iterate through constraints, for example :: + + >>> for c in system.constraints: + ... print(c.shape) + +will print the shape information for all defined constraints. + + +.. _Getting the force on a constraint: + +Getting the force on a constraint +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +:meth:`espressomd.constraints.ShapeBasedConstraint.total_force` + +Returns the force acting on the constraint. Note, however, that this is +only due to forces from interactions with particles, not with other +constraints. Also, these forces still do not mean that the constraints +move, they are just the negative of the sum of forces acting on all +particles due to this constraint. Similarly, the total energy does not +contain constraint-constraint contributions. + +For example the pressure from wall :: + + >>> p = system.constraints[0].total_force() + >>> print(p) + +.. _Getting the minimal distance to a constraint: + +Getting the minimal distance to a constraint +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +:meth:`espressomd.constraints.ShapeBasedConstraint.min_dist` + +Calculates the smallest distance to all interacting +constraints that can be repulsive (wall, cylinder, sphere, rhomboid, +pore, slitpore). Negative distances mean that the position is +within the area that particles should not access. Helpful to find +initial configurations. + +.. _Available shapes: + +Available shapes +^^^^^^^^^^^^^^^^ + +:class:`espressomd.shapes` + +Python syntax:: + + import espressomd.shapes + shape = espressomd.shapes. + +```` can be any of the available shapes. + +The surface's geometry is defined via a few available shapes. +The following shapes can be used as constraints. + +.. warning:: + When using shapes with concave edges and corners, the fact that a particle + only interacts with the closest point on the constraint surface leads to discontinuous + force fields acting on the particles. This breaks energy conservation in otherwise + symplectic integrators. Often, the total energy of the system increases exponentially. + + +Wall +"""" + +:class:`espressomd.shapes.Wall` + +An infinite plane defined by the normal vector ``normal`` +and the distance ``dist`` from the origin (in the direction of the normal vector). +The force acts in the direction of the normal. +Note that ``dist`` describes the distance from the origin in units of the normal +vector so that the product of ``dist`` and ``normal`` is a point on the surface. +Therefore negative distances are quite common! + +.. figure:: figures/shape-wall.png + :alt: Visualization of a constraint with a Wall shape. + :align: center + :height: 6.00000cm + +Pictured is an example constraint with a ``Wall`` shape created with :: + + wall = Wall(dist=20, normal=[0.1, 0.0, 1]) + system.constraints.add(shape=wall, particle_type=0) + +For penetrable walls, if the ``only_positive`` flag is set to ``True``, interactions +are only calculated if the particle is on the side of the wall in which the +normal vector is pointing. + + +Sphere +"""""" + +:class:`espressomd.shapes.Sphere` + +A sphere with center ``center`` and radius ``radius``. +The direction ``direction`` determines the force direction, ``-1`` for inward +and ``+1`` for outward. + +.. _shape-sphere: + +.. figure:: figures/shape-sphere.png + :alt: Visualization of a constraint with a Sphere shape. + :align: center + :height: 6.00000cm + +Pictured is an example constraint with a ``Sphere`` shape created with :: + + sphere = Sphere(center=[25, 25, 25], radius=15, direction=1) + system.constraints.add(shape=sphere, particle_type=0) + + +Ellipsoid +""""""""" + +:class:`espressomd.shapes.Ellipsoid` + +An ellipsoid with center ``center``, semiaxis ``a`` along the symmetry axis and +equatorial semiaxes ``b``. The symmetry axis is aligned parallel to the x-axis. +The direction ``direction`` determines the force direction, ``-1`` for inward and ``+1`` for outward. +The distance to the surface is determined iteratively via Newton's method. + +.. _shape-ellipsoid: + +.. figure:: figures/shape-ellipsoid.png + :alt: Visualization of a constraint with an Ellipsoid shape. + :align: center + :height: 6.00000cm + +Pictured is an example constraint with an ``Ellipsoid`` shape created with :: + + ellipsoid = Ellipsoid(center=[25, 25, 25], a=25, b=15) + system.constraints.add(shape=ellipsoid, particle_type=0) + + +Cylinder +"""""""" + +:class:`espressomd.shapes.Cylinder` + +A cylinder with center ``center``, radius ``radius`` and length ``length``. +The ``axis`` parameter is a vector along the cylinder axis, which is normalized in the program. +The direction ``direction`` determines the force direction, ``-1`` for inward and ``+1`` for outward. + + +.. figure:: figures/shape-cylinder.png + :alt: Visualization of a constraint with a Cylinder shape. + :align: center + :height: 6.00000cm + +Pictured is an example constraint with a ``Cylinder`` shape created with :: + + cylinder = Cylinder(center=[25, 25, 25], + axis=[1, 0, 0], + direction=1, + radius=10, + length=30) + system.constraints.add(shape=cylinder, particle_type=0) + + +Rhomboid +"""""""" + +:class:`espressomd.shapes.Rhomboid` + +A rhomboid or parallelepiped, defined by one corner located at ``corner`` +and three adjacent edges, defined by the three vectors connecting the +corner ``corner`` with its three neighboring corners: ``a``, ``b`` and ``c``. +The direction ``direction`` determines the force direction, ``-1`` for inward and ``+1`` for outward. + +:: + + rhomboid = Rhomboid(corner=[5.0, 5.0, 5.0], + a=[1.0, 1.0, 0.0], + b=[0.0, 0.0, 1.0], + c=[0.0, 1.0, 0.0], + direction=1) + system.constraints.add(shape=rhomboid, particle_type=0, penetrable=True) + +creates a rhomboid defined by one corner located at ``[5.0, 5.0, 5.0]`` and three +adjacent edges, defined by the three vectors connecting the corner with its three neighboring corners, ``(1,1,0)`` , ``(0,0,1)`` and ``(0,1,0)``. + + +SimplePore +"""""""""" + +:class:`espressomd.shapes.SimplePore` + +Two parallel infinite planes, connected by a cylindrical orifice. The cylinder +is connected to the planes by torus segments with an adjustable radius. + +Length and radius of the cylindrical pore can be set via the corresponding parameters +``length`` and ``radius``. The parameter ``center`` defines the central point of the pore. +The orientation of the pore is given by the vector ``axis``, which points along the cylinder's symmetry axis. +The pore openings are smoothed with radius ``smoothing_radius``. + +.. figure:: figures/shape-simplepore.png + :alt: Visualization of a constraint with a SimplePore shape. + :align: center + :height: 6.00000cm + +Pictured is an example constraint with a ``SimplePore`` shape created with :: + + pore = SimplePore(axis=[1, 0, 0], + length=15, + radius=12.5, + smoothing_radius=2, + center=[25, 25, 25]) + system.constraints.add(shape=pore, particle_type=0, penetrable=True) + +Note: in the OpenGL visualizer, if the OpenGL Extrusion library is not available, +the smooth pore openings will be rendered using a sliced torus. You can safely +ignore this visual artifact, it has no impact on the force/energy calculation. + + +Slitpore +"""""""" + +:class:`espressomd.shapes.Slitpore` + +A T-shaped channel that extends in the *z*-direction. +The cross sectional geometry is depicted in Fig. :ref:`schematic `. +It is translationally invariant in y direction. + +The region is described as a pore (lower vertical part of the "T"-shape) and a channel (upper horizontal part of the "T"-shape). + +.. _figure-slitpore: + +.. figure:: figures/slitpore.png + :alt: Schematic for the Slitpore shape with labeled geometrical parameters. + :align: center + :height: 10.00000cm + +The parameter ``channel_width`` specifies the distance between the top and the plateau edge. +The parameter ``pore_length`` specifies the distance between the bottom and the plateau edge. +The parameter ``pore_width`` specifies the distance between the two plateau edges, it is the space between the left and right walls of the pore region. +The parameters ``pore_mouth`` and ``dividing_plane`` specify the location in the z-coordinate resp. x-coordinate of the pore opening. + +All the edges are smoothed via the parameters ``upper_smoothing_radius`` (for the concave corner at the edge of the plateau region) and ``lower_smoothing_radius`` (for the convex corner at the bottom of the pore region). +The meaning of the geometrical parameters can be inferred from the schematic in Fig. :ref:`slitpore `. + + +.. figure:: figures/shape-slitpore.png + :alt: Visualization of a constraint with a Slitpore shape. + :align: center + :height: 6.00000cm + + +Pictured is an example constraint with a ``Slitpore`` shape created with :: + + + slitpore = Slitpore(channel_width=15, + lower_smoothing_radius=1.5, + upper_smoothing_radius=2, + pore_length=20, + pore_mouth=30, + pore_width=5, + dividing_plane=25) + + system.constraints.add(shape=slitpore, particle_type=0, penetrable=True) + + +SpheroCylinder +"""""""""""""" + +:class:`espressomd.shapes.SpheroCylinder` + +A cylinder capped by hemispheres on both ends. Generates a capsule, pill, or spherocylinder depending on the choice of parameters. +Similar to :class:`espressomd.shapes.Cylinder`, it is positioned at ``center`` and has a radius ``radius``. +The ``length`` parameter is the cylinder length, and does not include the contribution from the hemispherical ends. +The ``axis`` parameter is a vector along the cylinder axis, which is normalized in the program. +The direction ``direction`` determines the force direction, ``-1`` for inward and ``+1`` for outward. + + +.. figure:: figures/shape-spherocylinder.png + :alt: Visualization of a constraint with a SpheroCylinder shape. + :align: center + :height: 6.00000cm + +Pictured is an example constraint with a ``SpheroCylinder`` shape created with :: + + spherocylinder = SpheroCylinder(center=[25, 25, 25], + axis=[1, 0, 0], + direction=1, + radius=10, + length=30) + system.constraints.add(shape=spherocylinder, particle_type=0) + + +Torus +""""" + +:class:`espressomd.shapes.Torus` + +It is positioned at ``center`` and has a radius ``radius`` with tube radius ``tube_radius``. +The ``normal`` parameter is the torus rotation axis, which is normalized in the program. +The direction ``direction`` determines the force direction, ``-1`` for inward and ``+1`` for outward. + +.. figure:: figures/shape-torus.png + :alt: Visualization of a constraint with a Torus shape. + :align: center + :height: 6.00000cm + +Pictured is an example constraint with a ``Torus`` shape created with :: + + torus = Torus(center=[25, 25, 25], normal=[1, 1, 1], + direction=1, radius=15, tube_radius=6) + system.constraints.add(shape=torus, particle_type=0) + + +HollowConicalFrustum +"""""""""""""""""""" + +:class:`espressomd.shapes.HollowConicalFrustum` + +A hollow cone with round corners. +Can include an opening in the side (see figures below). The specific parameters +are described in the shape's class :class:`espressomd.shapes.HollowConicalFrustum`. + +.. figure:: figures/shape-conical_frustum.png + :alt: Visualization of a constraint with a HollowConicalFrustum shape. + :align: center + :height: 6.00000cm + +.. figure:: figures/shape-hollowconicalfrustum_central_angle.png + :alt: Visualization a HollowConicalFrustum shape with central angle + :align: center + :height: 6.00000cm + +.. figure:: figures/conical_frustum.png + :alt: Schematic for the HollowConicalFrustum shape with labeled geometrical parameters. + :align: center + :height: 6.00000cm + +Note: in the OpenGL visualizer, if the OpenGL Extrusion library is not available, +the shape surface will be rendered with dots. + + +Union +""""" + +:class:`espressomd.shapes.Union` + +A meta-shape which is the union of given shapes. Note that only the regions where +all shapes have a "positive distance" (see :ref:`Available options`) can be used for the +union. The distance to the union is defined as the minimum distance to any contained shape. +This shape cannot be checkpointed when multiple MPI ranks are used. + + +.. _Available options: + +Available options +^^^^^^^^^^^^^^^^^ + +There are some options to help control the behavior of shaped-based +constraints. Some of the options, like ``direction`` need to be specified for +the shape :class:`espressomd.shapes`, and some options are specified for the +constraint :class:`espressomd.constraints.ShapeBasedConstraint`. We will +discuss them together in this section in the context of a specific example. + +The ``direction`` option typically specifies which volumes are inside versus +outside the shape. Consider a constraint based on the sphere shape. If one +wishes to place particles inside the sphere, one would usually use +``direction=-1``, if one wishes to place particles outside, one would use +``direction=1``. In this example, we place a sphere centre at position +(25,0,0). A particle is continuously displaced on the x-axis in order to probe +the effect of different options. For this, we need to first define a repulsive +interaction between the probe and the constraint. + +The plot below demonstrates how the distance between the probe and the +constraint surface is calculated when the ``distance`` option is toggled +between ``direction=1`` and ``direction=-1``. In the plot, a schematic of a +circle centered at x=25 is used to represent the spherical constraint. + +.. figure:: figures/constraint-distance.png + :alt: Distance measure from an example spherical constraint. + :align: center + :height: 8.00000cm + +When the option ``direction=1`` is used for the sphere shape, positive +distances are measured whenever the particle is outside the sphere and negative +distances are measured whenever the particle is inside the sphere. Conversely, +when the option ``direction=-1`` is used for the sphere shape, negative +distances are measured whenever the particle is outside the sphere and positive +distances are measured whenever the particle is inside the sphere. In other +words, this option helps defines the sign of the normal surface vector. + +For now, this may not sound useful but it can be practical when used with +together with constraint options such as ``penetrable`` or ``only_positive``. +In the former case, using non-penetrable surfaces with ``penetrable=False`` will +cause |es| to throw an error is any distances between interacting particles and +constraints are found to be negative. This can be used to stop a simulation if +for one reason or another particles end up in an unwanted location. + +The ``only_positive`` constraint option is used to define if a force should be +applied to a particle that has a negative distance. For example, consider the +same probe particle as in the previous case. The plot below shows the particle +force with ``only_positive=True``. Notice that when the distance is negative, +forces are not applied at all to the particle. Thus the constraint surface is +either purely radially outwards (when ``direction=1``) or radially inwards +(when ``direction=-1``). Note that in both cases the constraint was set to be +penetrable with ``penetrable=True`` or else the simulation would crash whenever +the particle was found in any location that yields a negative distance. + +.. figure:: figures/constraint-force.png + :alt: Force measure from an example spherical constraint. + :align: center + :height: 8.00000cm + +The next figure shows what happens if we turn off the ``only_positive`` flag by +setting ``only_positive=False``. In this case the particle is pushed radially +inward if it is inside the sphere and radially outward if it is outside. As +with the previous example, the constraint was set to be penetrable for this to +make sense. + +.. figure:: figures/constraint-force_only_positive.png + :alt: Force measure from an example spherical constraint. + :align: center + :height: 8.00000cm + +Most shapes have a clear interpretation of what is inside versus outside with +the exception of a planar wall. For this, there is no ``direction`` option, but +the ``normal`` vector of the wall points in the direction that is considered to +yield positive distances. Outside their use in constraints, shapes can also be +used as a way to define LB boundary nodes. In this case, negative distances +define nodes which are part of a boundary (please refer to :ref:`Using shapes +as lattice-Boltzmann boundary`). + + +.. _External Fields: + +External Fields +--------------- + +There is a variety of external fields, which differ by how their +values are obtained and how they couple to particles. + +Constant fields +^^^^^^^^^^^^^^^ + +These are fields that are constant in space or simple linear functions +of the position. The available fields are: + +* :class:`espressomd.constraints.HomogeneousMagneticField` +* :class:`espressomd.constraints.ElectricPlaneWave` +* :class:`espressomd.constraints.LinearElectricPotential` +* :class:`espressomd.constraints.HomogeneousFlowField` +* :class:`espressomd.constraints.Gravity` + +A detailed description can be found in the class documentation. + +Please be aware of the fact that a constant per-particle force can be +set via the ``ext_force`` property of the particles and is not provided +here. + + +Interpolated Force and Potential fields +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The values of these fields are obtained by interpolating table data, +which has to be provided by the user. The fields differ by how +they couple to particles, for a detailed description see their respective +class documentation. + +* :class:`espressomd.constraints.ForceField` +* :class:`espressomd.constraints.PotentialField` +* :class:`espressomd.constraints.ElectricPotential` +* :class:`espressomd.constraints.FlowField` + diff --git a/doc4.2.2/_sources/contributing.rst.txt b/doc4.2.2/_sources/contributing.rst.txt new file mode 100644 index 0000000000..b4a124265d --- /dev/null +++ b/doc4.2.2/_sources/contributing.rst.txt @@ -0,0 +1,94 @@ +.. _Contributing: + +Contributing +============ + +Up to date information about the development of |es| can be found in the +`ESPResSo wiki `__: + +- proceedings of the ESPResSo meetings +- list of planned releases +- developer's guide + +The official website at https://espressomd.org provides additional information: + +- Latest stable release of |es| and older releases +- Obtaining development version of |es| +- Archives of both developers' and users' mailing lists +- Registering to mailing lists + +.. _Contributing your own code: + +Contributing your own code +-------------------------- + +If you are planning to make an extension to or already have a piece of +your own code which could be useful to others, you are very welcome to +contribute it to the community. Before you start making any changes to +the code, you should fork the `espressomd/espresso +`__ repository and work in a new branch. + +It is also generally a good idea to contact the developers on the mailing lists +before you start major coding projects. It might be that someone else is already +working on the problem or has a solution at hand. + +You will find more detailed information on our development processes in +`Contributing to ESPResSo +`__. +Please also refer to our developer's guide in the +`ESPResSo wiki `__. + +.. _Required Development Tools: + +Required Development Tools +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +- First of all, please install the dependencies for compiling |es|. + See the section :ref:`Installation`. + +- To be able to access the development version of |es|, you will need the + distributed versioning control system git_ and a GitHub account to fork the + `espressomd/espresso `__ repository + +- To build the user documentation, you will need Sphinx_. + +- To build the tutorials, you will need Jupyter_. + +- To build the core documentation, you will need Doxygen_. + +All of these tools should be easy to install on most Unix operating systems. + +You can find all Python dependencies of |es| in :file:`requirements.txt` in the +top-level source directory. Several optional packages for graphics, external +devices and continuous integration (CI) are not strictly essential and can be +safely removed if you're planning on installing dependencies via ``pip``: + +.. code-block:: bash + + pip3 install --upgrade --user -r requirements.txt + +Note that some distributions now use ``pip3`` for Python3 and ``pip2`` for +Python2. + + +.. _Building the User's guide: + +Building the User's guide +------------------------- + +If, while reading this documentation, you notice any mistakes or +undocumented features, you are very welcome to +contribute to the guide and have others benefit from your knowledge. + +For this, you should clone the development version at `espressomd/espresso +`__. Next build the software as shown +in :ref:`Installation` and then the documentation with ``make sphinx``. + + +.. _git: https://git-scm.com/ + +.. _Doxygen: https://www.doxygen.nl/manual/index.html + +.. _Sphinx: https://www.sphinx-doc.org/en/master/ + +.. _Jupyter: https://jupyter.org diff --git a/doc4.2.2/_sources/ek.rst.txt b/doc4.2.2/_sources/ek.rst.txt new file mode 100644 index 0000000000..2a586c3a75 --- /dev/null +++ b/doc4.2.2/_sources/ek.rst.txt @@ -0,0 +1,333 @@ +.. _Electrokinetics: + +Electrokinetics +=============== + +The electrokinetics setup in |es| allows for the description of +electro-hydrodynamic systems on the level of ion density distributions +coupled to a lattice-Boltzmann (LB) fluid. The ion density distributions +may also interact with explicit charged particles, which are +interpolated on the LB grid. In the following paragraph we briefly +explain the electrokinetic model implemented in |es|, before we come to the +description of the interface. + +.. _Electrokinetic equations: + +Electrokinetic equations +------------------------ + +In the electrokinetics code we solve the following system of coupled +continuity, diffusion-advection, Poisson, and Navier-Stokes equations: + +.. math:: + + \begin{aligned} + \label{eq:ek-model-continuity} \frac{\partial n_k}{\partial t} & = & -\, \nabla \cdot \vec{j}_k \vphantom{\left(\frac{\partial}{\partial}\right)} ; \\ + \label{eq:ek-model-fluxes} \vec{j}_{k} & = & -D_k \nabla n_k - \nu_k \, q_k n_k\, \nabla \Phi + n_k \vec{v}_{\mathrm{fl}} \vphantom{\left(\frac{\partial}{\partial}\right)} + \sqrt{n_k}\vec{\mathcal{W}}_k; \\ + \label{eq:ek-model-poisson} \Delta \Phi & = & -4 \pi \, {l_\mathrm{B}}\, {k_\mathrm{B}T}\sum_k q_k n_k \vphantom{\left(\frac{\partial}{\partial}\right)}; \\ + \nonumber \left(\frac{\partial \vec{v}_{\mathrm{fl}}}{\partial t} + \vec{v}_{\mathrm{fl}} \cdot \nabla \vec{v}_{\mathrm{fl}} \right) \rho_\mathrm{fl} & = & -{k_\mathrm{B}T}\, \nabla \rho_\mathrm{fl} - q_k n_k \nabla \Phi \\ + \label{eq:ek-model-velocity} & & +\, \eta \Delta \vec{v}_{\mathrm{fl}} + (\eta / 3 + \eta_{\text{b}}) \nabla (\nabla \cdot \vec{v}_{\mathrm{fl}}) \vphantom{\left(\frac{\partial}{\partial}\right)} ; \\ + \label{eq:ek-model-continuity-fl} \frac{\partial \rho_\mathrm{fl}}{\partial t} & = & -\,\nabla\cdot\left( \rho_\mathrm{fl} \vec{v}_{\mathrm{fl}} \right) \vphantom{\left(\frac{\partial}{\partial}\right)} , \end{aligned} + +which define relations between the following observables + +:math:`n_k` + the number density of the particles of species :math:`k`, + +:math:`\vec{j}_k` + the number density flux of the particles of species :math:`k`, + +:math:`\Phi` + the electrostatic potential, + +:math:`\rho_{\mathrm{fl}}` + the mass density of the fluid, + +:math:`\vec{v}_{\mathrm{fl}}` + the advective velocity of the fluid, + +and input parameters + +:math:`D_k` + the diffusion constant of species :math:`k`, + +:math:`\nu_k` + the mobility of species :math:`k`, + +:math:`\vec{\mathcal{W}}_k` + the white-noise term for the fluctuations of species :math:`k`, + +:math:`q_k` + the charge of a single particle of species :math:`k`, + +:math:`{l_\mathrm{B}}` + the Bjerrum length, + +:math:`{k_\mathrm{B}T}` + | the thermal energy given by the product of Boltzmann's constant + :math:`k_\text{B}` + | and the temperature :math:`T`, + +:math:`\eta` + the dynamic viscosity of the fluid, + +:math:`\eta_{\text{b}}` + the bulk viscosity of the fluid. + +The temperature :math:`T`, and diffusion constants :math:`D_k` and +mobilities :math:`\nu_k` of individual species are linked through the +Einstein-Smoluchowski relation :math:`D_k / +\nu_k = {k_\mathrm{B}T}`. This system of equations +combining diffusion-advection, electrostatics, and hydrodynamics is +conventionally referred to as the *Electrokinetic Equations*. + +The electrokinetic equations have the following properties: + +- On the coarse time and length scale of the model, the dynamics of the + particle species can be described in terms of smooth density + distributions and potentials as opposed to the microscale where + highly localized densities cause singularities in the potential. + + In most situations, this restricts the application of the model to + species of monovalent ions, since ions of higher valency typically + show strong condensation and correlation effects – the localization + of individual ions in local potential minima and the subsequent + correlated motion with the charges causing this minima. + +- Only the entropy of an ideal gas and electrostatic interactions are + accounted for. In particular, there is no excluded volume. + + This restricts the application of the model to monovalent ions and + moderate charge densities. At higher valencies or densities, + overcharging and layering effects can occur, which lead to + non-monotonic charge densities and potentials, that can not be + covered by a mean-field model such as Poisson--Boltzmann or this one. + + Even in salt free systems containing only counter ions, the + counter-ion densities close to highly charged objects can be + overestimated when neglecting excluded volume effects. Decades of the + application of Poisson--Boltzmann theory to systems of electrolytic + solutions, however, show that those conditions are fulfilled for + monovalent salt ions (such as sodium chloride or potassium chloride) + at experimentally realizable concentrations. + +- Electrodynamic and magnetic effects play no role. Electrolytic + solutions fulfill those conditions as long as they don't contain + magnetic particles. + +- The diffusion coefficient is a scalar, which means there can not be + any cross-diffusion. Additionally, the diffusive behavior has been + deduced using a formalism relying on the notion of a local + equilibrium. The resulting diffusion equation, however, is known to + be valid also far from equilibrium. + +- The temperature is constant throughout the system. + +- The density fluxes instantaneously relax to their local equilibrium + values. Obviously one can not extract information about processes on + length and time scales not covered by the model, such as dielectric + spectra at frequencies, high enough that they correspond to times + faster than the diffusive time scales of the charged species. + +.. _Setup: + +Setup +----- + +.. _Initialization: + +Initialization +~~~~~~~~~~~~~~ + +:class:`~espressomd.electrokinetics.Electrokinetics` is used to initialize +the LB fluid of the EK method:: + + import espressomd + import espressomd.electrokinetics + system = espressomd.System(box_l=[10.0, 10.0, 10.0]) + system.time_step = 0.0 + system.cell_system.skin = 0.4 + ek = espressomd.electrokinetics.Electrokinetics(agrid=1.0, lb_density=1.0, + viscosity=1.0, ext_force_density = [1,0,0], friction=1.0, T=1.0, prefactor=1.0, + stencil='linkcentered', advection=True, fluid_coupling='friction') + system.actors.add(ek) + +.. note:: Features ``ELECTROKINETICS`` and ``CUDA`` required + +It is very similar to the lattice-Boltzmann command in set-up. +We therefore refer the reader to chapter :ref:`Lattice-Boltzmann` +for details on the implementation of LB in |es| and describe only +the major differences here. + +The first major difference with the LB implementation is that the +electrokinetics set-up is a GPU-only implementation. A CPU version +will become available in the 4.3 line of |es|. To use the electrokinetics +features it is therefore imperative that your computer contains +a CUDA-capable GPU. + +To set up a proper LB fluid using this command, one has to specify at +least the following options: ``agrid``, ``lb_density``, ``viscosity``, +``friction``, ``T``, and ``prefactor``. The other options can be +used to modify the behavior of the LB fluid. Note that the command does +not allow the user to set the time step parameter as is the case for the +lattice-Boltzmann command, this parameter is instead taken directly from +the value set for :attr:`~espressomd.system.System.time_step`. +The LB *mass density* is set independently from the +electrokinetic *number densities*, since the LB fluid serves only as a +medium through which hydrodynamic interactions are propagated, as will +be explained further in the next paragraph. If no ``lb_density`` is specified, then our +algorithm assumes ``lb_density= 1.0``. The two 'new' parameters are the temperature ``T`` at +which the diffusive species are simulated and the ``prefactor`` +associated with the electrostatic properties of the medium. See the +above description of the electrokinetic equations for an explanation of +the introduction of a temperature, which does not come in directly via a +thermostat that produces thermal fluctuations. + +``advection`` can be set to ``True`` or ``False``. It controls whether there should be an +advective contribution to the diffusive species' fluxes. Default is +``True``. + +``fluid_coupling`` can be set to ``"friction"`` or ``"estatics"``. +This option determines the force term acting on the fluid. +The former specifies the force term to be the +sum of the species fluxes divided by their respective mobilities while +the latter simply uses the electrostatic force density acting on all +species. Note that this switching is only possible for the ``"linkcentered"`` +stencil. For all other stencils, this choice is hardcoded. The default +is ``"friction"``. + +``es_coupling`` enables the action of the electrostatic potential due to the +electrokinetics species and charged boundaries on the MD particles. The +forces on the particles are calculated by interpolation from the +electric field which is in turn calculated from the potential via finite +differences. This only includes interactions between the species and +boundaries and MD particles, not between MD particles and MD particles. +To get complete electrostatic interactions a particles Coulomb method +like Ewald or P3M has to be activated too. + +The fluctuation of the EK species can be turned on by the flag ``fluctuations``. +This adds a white-noise term to the fluxes. The amplitude of this noise term +can be controlled by ``fluctuation_amplitude``. To circumvent that these fluctuations +lead to negative densities, they are modified by a smoothed Heaviside function, +which decreases the magnitude of the fluctuation for densities close to 0. +By default the fluctuations are turned off. + +Another difference with LB is that EK parameters are immutables, +and the EK object cannot be checkpointed. + +.. _Diffusive species: + +Diffusive species +~~~~~~~~~~~~~~~~~ +:: + + species = espressomd.electrokinetics.Species(density=density, D=D, valency=valency, + ext_force_density=ext_force) + +:class:`~espressomd.electrokinetics.Species` is used to initialize a diffusive species. Here the +options specify: the number density ``density``, the diffusion coefficient ``D``, the +valency of the particles of that species ``valency``, and an optional external +(electric) force which is applied to the diffusive species. As mentioned +before, the LB density is completely decoupled from the electrokinetic +densities. This has the advantage that greater freedom can be achieved +in matching the internal parameters to an experimental system. Moreover, +it is possible to choose parameters for which the LB is more stable. +The species can be added to a LB fluid:: + + ek.add_species(species) + +One can also add the species during the initialization step of the +:class:`~espressomd.electrokinetics.Electrokinetics` class by defining +the list variable ``species``:: + + ek = espressomd.electrokinetics.Electrokinetics(species=[species], ...) + +The variables ``density``, ``D``, and +``valency`` must be set to properly initialize the diffusive species; the +``ext_force_density`` is optional. + +.. _EK boundaries: + +EK boundaries +~~~~~~~~~~~~~ + +:class:`~espressomd.ekboundaries.EKBoundary` is used to set up +internal (or external) boundaries for the electrokinetics algorithm in much +the same way as the :class:`~espressomd.lbboundaries.LBBoundary` class is +used for the LB fluid:: + + ek_boundary = espressomd.ekboundaries.EKBoundary(charge_density=1.0, shape=my_shape) + system.ekboundaries.add(ek_boundary) + +.. note:: Feature ``EK_BOUNDARIES`` required + +The major difference with the LB class is the option ``charge_density``, +with which a boundary can be endowed with a volume charge density. +To create a surface charge density, a combination of two +oppositely charged boundaries, one inside the other, can be used. However, +care should be taken to maintain the surface charge density when the value of ``agrid`` +is changed. Examples for possible shapes are wall, sphere, ellipsoid, cylinder, +rhomboid and hollow conical frustum. We refer to the documentation of the +:class:`espressomd.shapes` module for more possible shapes and information on +the options associated to these shapes. In order to properly set up the +boundaries, the ``charge_density`` and ``shape`` must be specified. + +.. _Output: + +Output +~~~~~~ + +.. _Fields: + +Fields +"""""" + +:: + + ek.write_vtk_boundary(path) + ek.write_vtk_density(path) + ek.write_vtk_velocity(path) + ek.write_vtk_potential(path) + +A property of the fluid field can be exported into a file in one go. +Currently supported fields are: density, velocity, potential and boundary, +which give the LB fluid density, the LB fluid velocity, +the electrostatic potential, and the location and type of the +boundaries, respectively. The boundaries can only be printed when the +``EK_BOUNDARIES`` is compiled in. The output is a vtk-file, which is readable by +visualization software such as ParaView [5]_ and Mayavi2 [6]_. + +:: + + species.write_vtk_flux(path) + species.write_vtk_density(path) + +These commands are similar to the above. They enable the +export of diffusive species properties, namely: ``density`` and ``flux``, which specify the +number density and flux of species ``species``, respectively. + +.. _Local quantities: + +Local quantities +"""""""""""""""" + +Local quantities like velocity or fluid density for single nodes can be accessed in the same way +as for an LB fluid, see :ref:`Lattice-Boltzmann`. The only EK-specific quantity is the potential. + +:: + + ek[0, 0, 0].potential + ek[0, 0, 0].velocity + ek[0, 0, 0].boundary + +The local ``density`` and ``flux`` of a species can be obtained in the same fashion: + +:: + + species[0, 0, 0].density + species[0, 0, 0].flux + +.. [5] + https://www.paraview.org/ +.. [6] + http://code.enthought.com/projects/mayavi/ diff --git a/doc4.2.2/_sources/electrostatics.rst.txt b/doc4.2.2/_sources/electrostatics.rst.txt new file mode 100644 index 0000000000..a9ca49258f --- /dev/null +++ b/doc4.2.2/_sources/electrostatics.rst.txt @@ -0,0 +1,426 @@ +.. _Electrostatics: + +Electrostatics +============== + +The Coulomb (or electrostatic) interaction is defined as +follows. For a pair of particles at distance :math:`r` with charges +:math:`q_1` and :math:`q_2`, the interaction is given by + +.. math:: U_C(r)=C \cdot \frac{q_1 q_2}{r} + +where + +.. math:: + C=\frac{1}{4\pi \varepsilon_0 \varepsilon_r} + :label: coulomb_prefactor + +is a prefactor which can be set by the user. The commonly used Bjerrum length +:math:`l_B = e^2 / (4 \pi \varepsilon_0 \varepsilon_r k_B T)` is the length at +which the Coulomb energy between two unit charges is equal to the thermal +energy :math:`k_B T`. +Based on this length, the prefactor is given by :math:`C=l_B k_B T / e^2`. + +Computing electrostatic interactions is computationally very expensive. +|es| features some state-of-the-art algorithms to deal with these +interactions as efficiently as possible, but almost all of them require +some knowledge to use them properly. Uneducated use can result in +completely unphysical simulations. + +Coulomb interactions have to be added to the list of active actors of the system object to become +active. This is done by calling the add-method of :attr:`espressomd.system.System.actors`. +Only one electrostatics method can be active at any time. + +Note that using the electrostatic interaction also requires assigning charges to +the particles via the particle property +:py:attr:`~espressomd.particle_data.ParticleHandle.q`. + +All solvers need a prefactor and a set of other required parameters. +This example shows the general usage of the electrostatic method ``P3M``. +An instance of the solver is created and added to the actors list, at which +point it will be automatically activated. This activation will internally +call a tuning function to achieve the requested accuracy:: + + import espressomd + import espressomd.electrostatics + + system = espressomd.System(box_l=[10, 10, 10]) + system.time_step = 0.01 + system.part.add(pos=[[0, 0, 0], [1, 1, 1]], q=[-1, 1]) + solver = espressomd.electrostatics.P3M(prefactor=2., accuracy=1e-3) + system.actors.add(solver) + +where the prefactor is defined as :math:`C` in Eqn. :eq:`coulomb_prefactor`. + +The list of actors can be cleared with +:meth:`system.actors.clear() ` and +:meth:`system.actors.remove(actor) `. + + +.. _Coulomb P3M: + +Coulomb P3M +----------- + +:class:`espressomd.electrostatics.P3M` + +For this feature to work, you need to have the ``fftw3`` library +installed on your system. In |es|, you can check if it is compiled in by +checking for the feature ``FFTW`` with ``espressomd.features``. +P3M requires full periodicity (1 1 1). When using a non-metallic dielectric +constant (``epsilon != 0.0``), the box must be cubic. +Make sure that you know the relevance of the P3M parameters before using P3M! +If you are not sure, read the following references: +:cite:`ewald21a,hockney88a,kolafa92a,deserno98a,deserno98b,deserno00e,deserno00b,cerda08d`. + +.. _Tuning Coulomb P3M: + +Tuning Coulomb P3M +~~~~~~~~~~~~~~~~~~ + +It is not easy to calculate the various parameters of the P3M method +such that the method provides the desired accuracy at maximum speed. To +simplify this, it provides a function to automatically tune the algorithm. +Note that for this function to work properly, your system should already +contain an initial configuration of charges and the correct initial box size. +The tuning method is called when the handle of the Coulomb P3M is added to +the actor list. Some parameters can be fixed (``r_cut``, ``cao``, ``mesh``) +to speed up the tuning if the parameters are already known. + +Please note that the provided tuning algorithms works very well on +homogeneous charge distributions, but might not achieve the requested +precision for highly inhomogeneous or symmetric systems. For example, +because of the nature of the P3M algorithm, systems are problematic +where most charges are placed in one plane, one small region, or on a +regular grid. + +The function employs the analytical expression of the error estimate for +the P3M method :cite:`hockney88a` and its real space error :cite:`kolafa92a` to +obtain sets of parameters that yield the desired accuracy, then it measures how +long it takes to compute the Coulomb interaction using these parameter sets and +chooses the set with the shortest run time. + +During tuning, the algorithm reports the tested parameter sets, +the corresponding k-space and real-space errors and the timings needed +for force calculations. In the output, the timings are given in units of +milliseconds, length scales are in units of inverse box lengths. + +.. _Coulomb P3M on GPU: + +Coulomb P3M on GPU +~~~~~~~~~~~~~~~~~~ + +:class:`espressomd.electrostatics.P3MGPU` + +The GPU implementation of P3M calculates the far field contribution to the +forces on the GPU. The near-field contribution to the forces, as well as the +near- and far-field contributions to the energies are calculated on the CPU. +It uses the same parameters +and interface functionality as the CPU version of the solver. +It should be noted that this does not always provide significant +increase in performance. Furthermore it computes the far field interactions +with only single precision which limits the maximum precision. +The algorithm does not work in combination with the electrostatic extension +:ref:`Dielectric interfaces with the ICC* algorithm `. + +The algorithm doesn't have kernels to compute energies, and will therefore +contribute 0 to the long-range potential energy of the system. This can be +an issue for other algorithms, such as :ref:`reaction methods ` +and :ref:`energy-based steepest descent `. + +.. _Debye-Hückel potential: + +Debye-Hückel potential +---------------------- + +:class:`espressomd.electrostatics.DH` + +The Debye-Hückel electrostatic potential is defined by + +.. math:: U^{C-DH} = C \cdot \frac{q_1 q_2 \exp(-\kappa r)}{r}\quad \mathrm{for}\quad r r_{\textrm{cut}}` it is +set to zero which introduces a step in energy. Therefore, it introduces +fluctuations in energy. + +For :math:`\kappa = 0`, this corresponds to the plain Coulomb potential. + +.. _Reaction Field method: + +Reaction Field method +--------------------- + +:class:`espressomd.electrostatics.ReactionField` + +The Reaction Field electrostatic potential is defined by + +.. math:: U^{C-RF} = C \cdot q_1 q_2 \left[\frac{1}{r} - \frac{B r^2}{2r_{\mathrm{cut}}^3} - \frac{1 - B/2}{r_{\mathrm{cut}}}\right] \quad \mathrm{for}\quad r`_ +* `GitHub discussions `_ +* `ESPResSo wiki `_ +* `Online documentation `_ +* `Official website `_ + +Python modules +-------------- + +.. toctree:: + :maxdepth: 1 + + modules.rst + +Indices and tables +------------------ + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` diff --git a/doc4.2.2/_sources/installation.rst.txt b/doc4.2.2/_sources/installation.rst.txt new file mode 100644 index 0000000000..a7e3bc84b6 --- /dev/null +++ b/doc4.2.2/_sources/installation.rst.txt @@ -0,0 +1,1008 @@ +.. _Installation: + +Installation +============ + +This chapter will describe how to get, compile and run the software. + +|es| releases are available as source code packages from the homepage [1]_. +This is where new users should get the code. The code within release packages +is tested and known to run on a number of platforms. +Alternatively, people who want to use the newest features of |es| or +start contributing to the software can instead obtain the +current development code via the version control system software [2]_ +from |es|'s project page at GitHub [3]_. This code might be not as well +tested and documented as the release code; it is recommended to use this +code only if you have already gained some experience in using |es|. + +Unlike most other software, no binary distributions of |es| are available, +and the software is usually not installed globally for all users. +Instead, users of |es| should compile the software themselves. The reason for +this is that it is possible to activate and deactivate various features +before compiling the code. Some of these features are not compatible +with each other, and some of the features have a profound impact on the +performance of the code. Therefore it is not possible to build a single +binary that can satisfy all needs. For performance reasons a user +should always activate only those features that are actually needed. +This means, however, that learning how to compile is a necessary evil. +The build system of |es| uses CMake to compile +software easily on a wide range of platforms. + +.. _Requirements: + +Requirements +------------ + +The following tools and libraries, including their header files, +are required to be able to compile and use |es|: + +.. glossary:: + + CMake + The build system is based on CMake version 3 or later [4]_. + + C++ compiler + The C++ core of |es| needs to be built by a C++14-capable compiler. + + Boost + A number of advanced C++ features used by |es| are provided by Boost. + We strongly recommend to use at least Boost 1.71. + + FFTW + For some algorithms like P\ :math:`^3`\ M, |es| needs the FFTW library + version 3 or later [5]_ for Fourier transforms, including header files. + + CUDA + For some algorithms like P\ :math:`^3`\ M, + |es| provides GPU-accelerated implementations for NVIDIA GPUs. + We strongly recommend CUDA 12.0 or later [6]_. + + MPI + An MPI library that implements the MPI standard version 1.2 is required + to run simulations in parallel. |es| is currently tested against + `Open MPI `__ and + `MPICH `__, with and without + `UCX `__ enabled. + Other MPI implementations like Intel MPI should also work, although + they are not actively tested in |es| continuous integration. + + Open MPI version 4.x is known to not properly support the MCA binding + policy "numa" in singleton mode on a few NUMA architectures. + On affected systems, e.g. AMD Ryzen or AMD EPYC, Open MPI halts with + a fatal error when setting the processor affinity in ``MPI_Init``. + This issue can be resolved by setting the environment variable + ``OMPI_MCA_hwloc_base_binding_policy`` to a value other than "numa", + such as "l3cache" to bind to a NUMA shared memory block, or to + "none" to disable binding (can cause performance loss). + + Python + |es|'s main user interface relies on Python 3. + + We strongly recommend using Python environments to isolate + packages required by |es| from packages installed system-wide. + This can be achieved using venv [7]_, conda [8]_, or any similar tool. + Inside an environment, commands of the form + ``sudo apt install python3-numpy python3-scipy`` + can be rewritten as ``python3 -m pip install numpy scipy``, + and thus do not require root privileges. + + Depending on your needs, you may choose to install all |es| + dependencies inside the environment, or only the subset of + dependencies not already satisfied by your workstation or cluster. + For the exact syntax to create and configure an environment, + please refer to the tool documentation. + + Cython + Cython is used for connecting the C++ core to Python. + + Python environment tools may allow you to install a Python executable + that is more recent than the system-wide Python executable. + Be aware this might lead to compatibility issues if Cython + accidentally picks up the system-wide :file:`Python.h` header file. + In that scenario, you will have to manually adapt the C++ compiler + include paths to find the correct :file:`Python.h` header file. + + +.. _Installing requirements on Ubuntu Linux: + +Installing requirements on Ubuntu Linux +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +To compile |es| on Ubuntu 22.04 LTS, install the following dependencies: + +.. code-block:: bash + + sudo apt install build-essential cmake cython3 python3-dev openmpi-bin \ + libboost-all-dev fftw3-dev libfftw3-mpi-dev libhdf5-dev libhdf5-openmpi-dev \ + python3-pip python3-numpy python3-scipy python3-opengl libgsl-dev freeglut3 + +Optionally the ccmake utility can be installed for easier configuration: + +.. code-block:: bash + + sudo apt install cmake-curses-gui + +.. _Nvidia GPU acceleration: + +Nvidia GPU acceleration +""""""""""""""""""""""" + +If your computer has an Nvidia graphics card, you should also download and install the +CUDA SDK to make use of GPU computation: + +.. code-block:: bash + + sudo apt install nvidia-cuda-toolkit + +Later in the installation instructions, you will see CMake commands of the +form ``cmake ..`` with optional arguments, such as ``cmake .. -D WITH_CUDA=ON`` +to activate CUDA. These commands may need to be adapted depending on which +operating system and CUDA version you are using. + +On Ubuntu 22.04, the default GCC compiler is too recent for nvcc and will fail +to compile sources that rely on ``std::function``. You can either use GCC 10: + +.. code-block:: bash + + CC=gcc-10 CXX=g++-10 cmake .. -D WITH_CUDA=ON + +or alternatively install Clang 12 as a replacement for nvcc and GCC: + +.. code-block:: bash + + CC=clang-12 CXX=clang++-12 cmake .. -D WITH_CUDA=ON -D WITH_CUDA_COMPILER=clang + +On Ubuntu 20.04, the default GCC compiler is also too recent for nvcc and will +generate compiler errors. You can either install an older version of GCC and +select it with environment variables ``CC`` and ``CXX`` when building |es|, +or edit the system header files as shown in the following +`patch for Ubuntu 20.04 `__. + +.. _Requirements for building the documentation: + +Requirements for building the documentation +""""""""""""""""""""""""""""""""""""""""""" + +To generate the Sphinx documentation, install the following packages: + +.. code-block:: bash + + pip3 install --user -c requirements.txt \ + sphinx sphinxcontrib-bibtex sphinx-toggleprompt + +To generate the Doxygen documentation, install the following packages: + +.. code-block:: bash + + sudo apt install doxygen graphviz + +.. _Setting up a Jupyter environment: + +Setting up a Jupyter environment +"""""""""""""""""""""""""""""""" + +To run the samples and tutorials, start by installing the following packages: + +.. code-block:: bash + + sudo apt install python3-matplotlib python3-pint python3-tqdm ffmpeg + pip3 install --user 'MDAnalysis>=1.0.0,<2.0.0' + +The tutorials are written in the +`Notebook Format `__ +version <= 4.4 and can be executed by any of these tools: + +* `Jupyter Notebook `__ +* `JupyterLab `__ +* `IPython `__ (not recommended) +* `VS Code Jupyter `__ + +To check whether one of them is installed, run these commands: + +.. code-block:: bash + + jupyter notebook --version + jupyter lab --version + ipython --version + code --version + +If you don't have any of these tools installed and aren't sure which one +to use, we recommend installing the historic Jupyter Notebook, since the +|es| tutorials have been designed with the ``exercise2`` plugin in mind. + +To use Jupyter Notebook, install the following packages: + +.. code-block:: bash + + pip3 install --user 'nbformat==5.1.3' 'nbconvert==6.4.5' 'notebook==6.4.8' 'jupyter_contrib_nbextensions==0.5.1' + jupyter contrib nbextension install --user + jupyter nbextension enable rubberband/main + jupyter nbextension enable exercise2/main + +Alternatively, to use JupyterLab, install the following packages: + +.. code-block:: bash + + pip3 install --user nbformat notebook jupyterlab + +Alternatively, to use VS Code Jupyter, install the following extensions: + +.. code-block:: bash + + code --install-extension ms-python.python + code --install-extension ms-toolsai.jupyter + code --install-extension ms-toolsai.jupyter-keymap + code --install-extension ms-toolsai.jupyter-renderers + +.. _Installing requirements on other Linux distributions: + +Installing requirements on other Linux distributions +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Please refer to the following Dockerfiles to find the minimum set of packages +required to compile |es| on other Linux distributions: + +* `Fedora `__ +* `Debian `__ + +.. _Installing requirements on Windows via WSL: + +Installing requirements on Windows via WSL +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +To run |es| on Windows, use the Linux subsystem. For that you need to + +* follow `these instructions `__ to install Ubuntu +* start Ubuntu (or open an Ubuntu tab in `Windows Terminal `__) +* execute ``sudo apt update`` to prepare the installation of dependencies +* optional step: If you have a NVIDIA graphics card available and want to make + use of |es|'s GPU acceleration, follow `these instructions `__ + to set up CUDA. +* follow the instructions for :ref:`Installing requirements on Ubuntu Linux` + +.. _Installing requirements on macOS: + +Installing requirements on macOS +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +To build |es| on macOS 10.15 or higher, you need to install its dependencies. +There are two possibilities for this, MacPorts and Homebrew. We strongly +recommend Homebrew, but if you already have MacPorts installed, you can use +that too, although we do not provide MacPorts installation instructions. + +To check whether you already have one or the other installed, run the +following commands: + +.. code-block:: bash + + test -e /opt/local/bin/port && echo "MacPorts is installed" + test -e /usr/local/bin/brew && echo "Homebrew is installed" + +If Homebrew is already installed, you should resolve any problems reported by +the command + +.. code-block:: bash + + brew doctor + +If you want to install Homebrew, follow the installation instructions at +https://docs.brew.sh/Installation, but bear in mind that MacPorts and Homebrew +may conflict with one another. + +If Anaconda Python or the Python from www.python.org are installed, you +will likely not be able to run |es|. Therefore, please uninstall them +using the following commands: + +.. code-block:: bash + + sudo rm -r ~/anaconda[23] + sudo rm -r /Library/Python + +Installing packages using Homebrew +"""""""""""""""""""""""""""""""""" + +Run the following commands: + +.. code-block:: bash + + brew install cmake python cython boost boost-mpi fftw \ + doxygen gsl numpy scipy ipython jupyter freeglut + brew install hdf5-mpi + brew link --force cython + pip install -c requirements.txt PyOpenGL matplotlib + +.. _Quick installation: + +Quick installation +------------------ + +If you have installed the requirements (see section :ref:`Requirements`) in +standard locations, compiling |es| is usually only a matter of creating a build +directory and calling ``cmake`` and ``make`` in it. See for example the command +lines below (optional steps which modify the build process are commented out): + +.. code-block:: bash + + mkdir build + cd build + cmake .. + #ccmake . // in order to add/remove features like ScaFaCoS or CUDA + make -j + +This will build |es| with a default feature set, namely +:file:`src/config/myconfig-default.hpp`. This file is a C++ header file, +which defines the features that should be compiled in. +You may want to adjust the feature set to your needs. This can be easily +done by copying the :file:`myconfig-sample.hpp` which has been created in +the :file:`build` directory to :file:`myconfig.hpp` and only uncomment +the features you want to use in your simulation. + +The ``cmake`` command looks for libraries and tools needed by |es|. +So |es| can only be built if ``cmake`` reports no errors. + +The command ``make`` will compile the source code. Depending on the +options passed to the program, ``make`` can also be used for a number of +other things: + +* It can install and uninstall the program to some other directories. + However, normally it is not necessary to actually *install* to run + it: ``make install`` + +* It can invoke code checks: ``make check`` + +* It can build this documentation: ``make sphinx`` + +When these steps have successfully completed, |es| can be started with the +command: + +.. code-block:: bash + + ./pypresso script.py + +where ``script.py`` is a Python script which has to be written by the user. +You can find some examples in the :file:`samples` folder of the source code +directory. If you want to run in parallel, you should have compiled with an +MPI library, and need to tell MPI to run in parallel. +The actual invocation is implementation-dependent, but in many cases, such as +*Open MPI* and *MPICH*, you can use + +.. code-block:: bash + + mpirun -n 4 ./pypresso script.py + +where ``4`` is the number of processors to be used. + + +.. _Features: + +Features +-------- + +This chapter describes the features that can be activated in |es|. Even if +possible, it is not recommended to activate all features, because this +will negatively affect |es|'s performance. + +Features can be activated in the configuration header :file:`myconfig.hpp` +(see section :ref:`myconfig.hpp\: Activating and deactivating features`). +To activate ``FEATURE``, add the following line to the header file: + +.. code-block:: c++ + + #define FEATURE + + +.. _General features: + +General features +~~~~~~~~~~~~~~~~ + +- ``ELECTROSTATICS`` This enables the use of the various electrostatics algorithms, such as P3M. + + .. seealso:: :ref:`Electrostatics` + +- ``MMM1D_GPU``: This enables MMM1D on GPU. It is faster than the CPU version + by several orders of magnitude, but has float precision instead of double + precision. + +- ``MMM1D_MACHINE_PREC``: This enables high-precision Bessel functions + for MMM1D on CPU. Comes with a 60% slow-down penalty. The low-precision + functions are enabled by default and are precise enough for most applications. + +- ``DIPOLES`` This activates the dipole-moment property of particles and switches + on various magnetostatics algorithms + + .. seealso:: :ref:`Magnetostatics` + +- ``SCAFACOS_DIPOLES`` This activates magnetostatics methods of ScaFaCoS. + +- ``DIPOLAR_DIRECT_SUM`` This activates the GPU implementation of the dipolar direct sum. + +- ``ROTATION`` Switch on rotational degrees of freedom for the particles, as well as + the corresponding quaternion integrator. + + .. seealso:: :ref:`Setting up particles` + + .. note:: + When this feature is activated, every particle has three + additional degrees of freedom, which for example means that the + kinetic energy changes at constant temperature is twice as large. + +- ``THERMOSTAT_PER_PARTICLE`` Allows setting a per-particle friction + coefficient for the Langevin and Brownian thermostats. + +- ``ROTATIONAL_INERTIA`` Allows particles to have individual rotational inertia matrix eigenvalues. + When not built in, all eigenvalues are unity in simulation units. + +- ``EXTERNAL_FORCES`` Allows to define an arbitrary constant force for each particle + individually. Also allows to fix individual coordinates of particles, + keep them at a fixed position or within a plane. + +- ``MASS`` Allows particles to have individual masses. + When not built in, all masses are unity in simulation units. + + .. seealso:: :attr:`espressomd.particle_data.ParticleHandle.mass` + +- ``EXCLUSIONS`` Allows to exclude specific short ranged interactions within + molecules. + + .. seealso:: :meth:`espressomd.particle_data.ParticleHandle.add_exclusion` + +- ``BOND_CONSTRAINT`` Turns on the RATTLE integrator which allows for fixed lengths bonds + between particles. + +- ``VIRTUAL_SITES_RELATIVE`` Virtual sites are particles, the position and velocity of which is + not obtained by integrating equations of motion. Rather, they are + placed using the position (and orientation) of other particles. The + feature allows for rigid arrangements of particles. + + .. seealso:: :ref:`Virtual sites` + +- ``COLLISION_DETECTION`` Allows particles to be bound on collision. + +In addition, there are switches that enable additional features in the +integrator or thermostat: + +- ``NPT`` Enables an on-the-fly NpT integration scheme. + + .. seealso:: :ref:`Isotropic NpT thermostat` + +- ``ENGINE`` + +- ``PARTICLE_ANISOTROPY`` + + +.. _Fluid dynamics and fluid structure interaction: + +Fluid dynamics and fluid structure interaction +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +- ``DPD`` Enables the dissipative particle dynamics thermostat and interaction. + + .. seealso:: :ref:`DPD interaction` + +- ``LB_BOUNDARIES`` + +- ``LB_BOUNDARIES_GPU`` + +- ``LB_ELECTROHYDRODYNAMICS`` Enables the implicit calculation of electro-hydrodynamics for charged + particles and salt ions in an electric field. + +- ``ELECTROKINETICS`` + +- ``EK_BOUNDARIES`` + +- ``EK_DEBUG`` + + +.. _Interaction features: + +Interaction features +~~~~~~~~~~~~~~~~~~~~ + +The following switches turn on various short ranged interactions (see +section :ref:`Isotropic non-bonded interactions`): + +- ``TABULATED`` Enable support for user-defined non-bonded interaction potentials. + +- ``LENNARD_JONES`` Enable the Lennard-Jones potential. + +- ``LENNARD_JONES_GENERIC`` Enable the generic Lennard-Jones potential with configurable + exponents and individual prefactors for the two terms. + +- ``LJCOS`` Enable the Lennard-Jones potential with a cosine-tail. + +- ``LJCOS2`` Same as ``LJCOS``, but using a slightly different way of smoothing the + connection to 0. + +- ``WCA`` Enable the Weeks--Chandler--Andersen potential. + +- ``GAY_BERNE`` Enable the Gay--Berne potential. + +- ``HERTZIAN`` Enable the Hertzian potential. + +- ``MORSE`` Enable the Morse potential. + +- ``BUCKINGHAM`` Enable the Buckingham potential. + +- ``SOFT_SPHERE`` Enable the soft sphere potential. + +- ``SMOOTH_STEP`` Enable the smooth step potential, a step potential with + two length scales. + +- ``BMHTF_NACL`` Enable the Born--Meyer--Huggins--Tosi--Fumi potential, + which can be used to model salt melts. + +- ``GAUSSIAN`` Enable the Gaussian potential. + +- ``HAT`` Enable the Hat potential. + +Some of the short-range interactions have additional features: + +- ``LJGEN_SOFTCORE`` This modifies the generic Lennard-Jones potential + (``LENNARD_JONES_GENERIC``) with tunable parameters. + +- ``THOLE`` See :ref:`Thole correction` + + +.. _Debug messages: + +Debug messages +~~~~~~~~~~~~~~ + +Finally, there is a flag for debugging: + +- ``ADDITIONAL_CHECKS`` Enables numerous additional checks which can detect + inconsistencies especially in the cell systems. These checks are however + too slow to be enabled in production runs. + + .. note:: + Because of a bug in OpenMPI versions 2.0-2.1, 3.0.0-3.0.2 and 3.1.0-3.1.2 + that causes a segmentation fault when running the |es| OpenGL visualizer + with feature ``ADDITIONAL_CHECKS`` enabled together with either + ``ELECTROSTATICS`` or ``DIPOLES``, the subset of additional checks for + those two features are disabled if an unpatched version of OpenMPI is + detected during compilation. + + +.. _External features: + +External features +~~~~~~~~~~~~~~~~~ + +External features cannot be added to the :file:`myconfig.hpp` file by the user. +They are added by CMake if the corresponding dependency was found on the +system. Some of these external features are optional and must be activated +using a CMake flag (see :ref:`Options and Variables`). + +- ``CUDA`` Enables GPU-specific features. + +- ``FFTW`` Enables features relying on the fast Fourier transforms, e.g. P3M. + +- ``H5MD`` Write data to H5MD-formatted hdf5 files (see :ref:`Writing H5MD-files`) + +- ``SCAFACOS`` Enables features relying on the ScaFaCoS library (see + :ref:`ScaFaCoS electrostatics`, :ref:`ScaFaCoS magnetostatics`). + +- ``GSL`` Enables features relying on the GNU Scientific Library, e.g. + :meth:`espressomd.cluster_analysis.Cluster.fractal_dimension`. + +- ``STOKESIAN_DYNAMICS`` Enables the Stokesian Dynamics feature + (see :ref:`Stokesian Dynamics`). Requires BLAS and LAPACK. + + + +.. _Configuring: + +Configuring +----------- + +.. _myconfig.hpp\: Activating and deactivating features: + +:file:`myconfig.hpp`: Activating and deactivating features +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +|es| has a large number of features that can be compiled into the binary. +However, it is not recommended to actually compile in all possible +features, as this will slow down |es| significantly. Instead, compile in only +the features that are actually required. A strong gain in speed can be +achieved by disabling all non-bonded interactions except for a single +one, e.g. ``LENNARD_JONES``. For developers, it is also possible to turn on or off a +number of debugging messages. The features and debug messages can be +controlled via a configuration header file that contains C-preprocessor +declarations. Subsection :ref:`Features` describes all available features. If a +file named :file:`myconfig.hpp` is present in the build directory when ``cmake`` +is run, all features defined in it will be compiled in. If no such file exists, +the configuration file :file:`src/config/myconfig-default.hpp` will be used +instead, which turns on the default features. + +When you distinguish between the build and the source directory, the +configuration header can be put in either of these. Note, however, that +when a configuration header is found in both directories, the one in the +build directory will be used. + +By default, the configuration header is called :file:`myconfig.hpp`. +The configuration header can be used to compile different binary +versions of with a different set of features from the same source +directory. Suppose that you have a source directory :file:`$srcdir` and two +build directories :file:`$builddir1` and :file:`$builddir2` that contain +different configuration headers: + +* :file:`$builddir1/myconfig.hpp`: + + .. code-block:: c++ + + #define ELECTROSTATICS + #define LENNARD_JONES + +* :file:`$builddir2/myconfig.hpp`: + + .. code-block:: c++ + + #define LJCOS + +Then you can simply compile two different versions of |es| via: + +.. code-block:: bash + + cd $builddir1 + cmake .. + make + + cd $builddir2 + cmake .. + make + +To see what features were activated in :file:`myconfig.hpp`, run: + +.. code-block:: bash + + ./pypresso + +and then in the Python interpreter: + +.. code-block:: python + + import espressomd + print(espressomd.features()) + + +.. _cmake: + +``cmake`` +~~~~~~~~~ + +In order to build the first step is to create a build directory in which +cmake can be executed. In cmake, the *source directory* (that contains +all the source files) is completely separated from the *build directory* +(where the files created by the build process are put). ``cmake`` is +designed to *not* be executed in the source directory. ``cmake`` will +determine how to use and where to find the compiler, as well as the +different libraries and tools required by the compilation process. By +having multiple build directories you can build several variants of |es|, +each variant having different activated features, and for as many +platforms as you want. + +Once you've run ``ccmake``, you can list the configured variables with +``cmake -LAH -N . | less`` (uses a pager) or with ``ccmake ..`` and pressing +key ``t`` to toggle the advanced mode on (uses the ``curses`` interface). + +**Example:** + +When the source directory is :file:`srcdir` (the files where unpacked to this +directory), then the user can create a build directory :file:`build` below that +path by calling ``mkdir srcdir/build``. In the build directory ``cmake`` is to be +executed, followed by a call to ``make``. None of the files in the source directory +are ever modified by the build process. + +.. code-block:: bash + + cd build + cmake .. + make -j + +Afterwards |es| can be run by calling ``./pypresso`` from the command line. + + +.. _ccmake: + +``ccmake`` +~~~~~~~~~~ + +Optionally and for easier use, the curses interface to cmake can be used +to configure |es| interactively. + +**Example:** + +Alternatively to the previous example, instead of cmake, the ccmake executable +is called in the build directory to configure |es|, followed by a call to make: + +.. code-block:: bash + + cd build + ccmake .. + make + +Fig. :ref:`ccmake-figure` shows the interactive ccmake UI. + +.. _ccmake-figure: + +.. figure:: figures/ccmake-example.png + :alt: ccmake interface + :width: 70.0% + :align: center + + ccmake interface + + +.. _Options and Variables: + +Options and Variables +~~~~~~~~~~~~~~~~~~~~~ + +The behavior of |es| can be controlled by means of options and variables +in the :file:`CMakeLists.txt` file. Most options are boolean values +(``ON`` or ``OFF``). A few options are strings or semicolon-delimited lists. + +The following options control features from external libraries: + +* ``WITH_CUDA``: Build with GPU support. +* ``WITH_HDF5``: Build with HDF5 support. +* ``WITH_SCAFACOS``: Build with ScaFaCoS support. +* ``WITH_GSL``: Build with GSL support. +* ``WITH_STOKESIAN_DYNAMICS`` Build with Stokesian Dynamics support. +* ``WITH_PYTHON`` Build with Stokesian Dynamics support. + +The following options control code instrumentation: + +* ``WITH_VALGRIND_INSTRUMENTATION``: Build with valgrind instrumentation markers +* ``WITH_PROFILER``: Build with Caliper profiler annotations +* ``WITH_MSAN``: Compile C++ code with memory sanitizer +* ``WITH_ASAN``: Compile C++ code with address sanitizer +* ``WITH_UBSAN``: Compile C++ code with undefined behavior sanitizer +* ``WITH_COVERAGE``: Generate C++ code coverage reports when running |es| +* ``WITH_COVERAGE_PYTHON``: Generate Python code coverage reports when running |es| + +The following options control how the project is built and tested: + +* ``WITH_CLANG_TIDY``: Run Clang-Tidy during compilation. +* ``WITH_CPPCHECK``: Run Cppcheck during compilation. +* ``WITH_CCACHE``: Enable compiler cache for faster rebuilds. +* ``WITH_TESTS``: Enable C++ and Python tests. +* ``WITH_BENCHMARKS``: Enable benchmarks. +* ``WITH_CUDA_COMPILER`` (string): Select the CUDA compiler. +* ``CTEST_ARGS`` (string): Arguments passed to the ``ctest`` command. +* ``TEST_TIMEOUT``: Test timeout. +* ``ESPRESSO_ADD_OMPI_SINGLETON_WARNING``: Add a runtime warning in the + pypresso and ipypresso scripts that is triggered in singleton mode + with Open MPI version 4.x on unsupported NUMA environments + (see :term:`MPI installation requirements ` for details). +* ``MYCONFIG_NAME`` (string): Filename of the user-provided config file +* ``MPIEXEC_PREFLAGS``, ``MPIEXEC_POSTFLAGS`` (strings): Flags passed to the + ``mpiexec`` command in MPI-parallel tests and benchmarks. +* ``CMAKE_CXX_FLAGS`` (string): Flags passed to the compilers. +* ``CMAKE_BUILD_TYPE`` (string): Build type. Default is ``Release``. +* ``CUDA_TOOLKIT_ROOT_DIR`` (string): Path to the CUDA toolkit directory. + +Most of these options are opt-in, meaning their default value is set to +``OFF`` in the :file:`CMakeLists.txt` file. These options can be modified +by calling ``cmake`` with the command line argument ``-D``: + +.. code-block:: bash + + cmake -D WITH_HDF5=OFF .. + +When an option is enabled, additional options may become available. +For example with ``-D WITH_CUDA=ON``, one can choose the CUDA compiler with +``-D WITH_CUDA_COMPILER=``, where ```` can be +``nvcc`` (default) or ``clang``. + +Environment variables can be passed to CMake. For example, to select Clang, use +``CC=clang CXX=clang++ cmake .. -DWITH_CUDA=ON -DWITH_CUDA_COMPILER=clang``. +If you have multiple versions of the CUDA library installed, you can select the +correct one with ``CUDA_BIN_PATH=/usr/local/cuda-10.0 cmake .. -DWITH_CUDA=ON`` +(with Clang as the CUDA compiler, you also need to override its default CUDA +path with ``-DCMAKE_CXX_FLAGS=--cuda-path=/usr/local/cuda-10.0``). + +.. _Build types and compiler flags: + +Build types and compiler flags +"""""""""""""""""""""""""""""" + +The build type is controlled by ``-D CMAKE_BUILD_TYPE=`` where +```` can take one of the following values: + +* ``Release``: for production use: disables assertions and debug information, + enables ``-O3`` optimization (this is the default) +* ``RelWithAssert``: for debugging purposes: enables assertions and + ``-O3`` optimization (use this to track the source of a fatal error) +* ``Debug``: for debugging in GDB +* ``Coverage``: for code coverage + +Cluster users and HPC developers may be interested in manually editing the +``Espresso_cpp_flags`` target in the top-level ``CMakeLists.txt`` file for +finer control over compiler flags. The variable declaration is followed +by a series of conditionals to enable or disable compiler-specific flags. +Compiler flags passed to CMake via the ``-DCMAKE_CXX_FLAGS`` option +(such as ``cmake . -DCMAKE_CXX_FLAGS="-ffast-math -fno-finite-math-only"``) +will appear in the compiler command before the flags in ``Espresso_cpp_flags``, +and will therefore have lower precedence. + +Be aware that fast-math mode can break |es|. It is incompatible with the +``ADDITIONAL_CHECKS`` feature due to the loss of precision in the LB code +on CPU. The Clang 10 compiler breaks field couplings with ``-ffast-math``. +The Intel compiler enables the ``-fp-model fast=1`` flag by default; +it can be disabled by adding the ``-fp-model=strict`` flag. + +|es| currently doesn't fully support link-time optimization (LTO). + + +.. _Configuring without a network connection: + +Configuring without a network connection +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Several :ref:`external features ` in |es| rely on +external libraries that are downloaded automatically by CMake. When a +network connection cannot be established due to firewall restrictions, +the CMake logic needs editing: + +* ``WITH_HDF5``: when cloning |es|, the :file:`libs/h5xx` folder will be + a git submodule containing a :file:`.git` subfolder. To prevent CMake from + updating this submodule with git, delete the corresponding command with: + + .. code-block:: bash + + sed -i '/execute_process(COMMAND ${GIT_EXECUTABLE} submodule update -- libs\/h5xx/,+1 d' CMakeLists.txt + + When installing a release version of |es|, no network communication + is needed for HDF5. + +* ``WITH_STOKESIAN_DYNAMICS``: this library is installed using `FetchContent + `__. + The repository URL can be found in the ``GIT_REPOSITORY`` field of the + corresponding ``FetchContent_Declare()`` command. The ``GIT_TAG`` field + provides the commit. Clone this repository locally next to the |es| + folder and edit the |es| build system such that ``GIT_REPOSITORY`` points + to the absolute path of the Stokesian Dynamics clone, for example with: + + .. code-block:: bash + + sed -ri 's|GIT_REPOSITORY +.+stokesian-dynamics.git|GIT_REPOSITORY /work/username/stokesian_dynamics|' CMakeLists.txt + + +Compiling, testing and installing +--------------------------------- + +The command ``make`` is mainly used to compile the source code, but it +can do a number of other things. The generic syntax of the ``make`` +command is: + +.. code-block:: bash + + make [options] [target] [variable=value] + +When no target is given, the target ``all`` is used. The following +targets are available: + +``all`` + Compiles the complete source code. The variable can be used to + specify the name of the configuration header to be used. + +``check`` + Runs the testsuite. By default, all available tests will be run on + 1, 2, 3, 4, 6, or 8 processors. + +``test`` + Do not use this target, it is a broken feature + (see `issue #4370 `__). + Use ``make check`` instead. + +``clean`` + Deletes all files that were created during the compilation. + +``install`` + Install |es| in the path specified by the CMake variable + ``CMAKE_INSTALL_PREFIX``. The path can be changed by calling CMake + with ``cmake .. -DCMAKE_INSTALL_PREFIX=/path/to/espresso``. Do not use + ``make DESTDIR=/path/to/espresso install`` to install to a specific path, + this will cause issues with the runtime path (RPATH) and will conflict + with the CMake variable ``CMAKE_INSTALL_PREFIX`` if it has been set. + +``doxygen`` + Creates the Doxygen code documentation in the :file:`doc/doxygen` + subdirectory. + +``sphinx`` + Creates the ``sphinx`` code documentation in the :file:`doc/sphinx` + subdirectory. + +``tutorials`` + Creates the tutorials in the :file:`doc/tutorials` subdirectory. + +``doc`` + Creates all documentation in the :file:`doc` subdirectory (only when + using the development sources). + +A number of options are available when calling ``make``. The most +interesting option is probably ``-j num_jobs``, which can be used for +parallel compilation. ``num_jobs`` specifies the maximal number of +concurrent jobs that will be run. Setting ``num_jobs`` to the number +of available processors speeds up the compilation process significantly. + +.. _Troubleshooting: + +Troubleshooting +--------------- + +If you encounter issues when building |es| or running it for the first time, +please have a look at the `Installation FAQ `__ +on the wiki. If you still didn't find an answer, see :ref:`Community support`. + +Many algorithms require parameters that must be provided within valid ranges. +Range checks are implemented to catch invalid input values and generate +meaningful error messages, however these checks cannot always catch errors +arising from an invalid combination of two or more features. If you encounter +issues with a script, you can activate extra runtime checks by enabling C++ +assertions. This is achieved by updating the CMake project and rebuilding +|es| with: + +.. code-block:: bash + + cmake . -DCMAKE_BUILD_TYPE=RelWithAssert + make -j + +The resulting build will run slightly slower, but will produce an error +message for common issues, such as divisions by zero, array access out +of bounds, or square roots of negative numbers. + +If this still doesn't help, you can activate debug symbols to help with +instrumentation: + +.. code-block:: bash + + cmake . -DCMAKE_BUILD_TYPE=Debug + make -j + +The resulting build will be quite slow but will allow many debugging tools +to be used. For details, please refer to chapter :ref:`Debugging es`. + +If you are dealing with a segmentation fault or undefined behavior, and GDB +doesn't help or is too cumbersome to use (e.g. in MPI-parallel simulations), +you can as a last resort activate sanitizers: + +.. code-block:: bash + + cmake . -DWITH_ASAN=ON -DWITH_UBSAN=ON -DCMAKE_BUILD_TYPE=Release + make -j + +The resulting build will be around 5 times slower that a debug build, +but it will generate valuable reports when detecting fatal exceptions. +For more details, please consult the online documentation of +`UBSAN `__ and +`ASAN `__. + +____ + +.. [1] + https://espressomd.org + +.. [2] + https://git-scm.com/ + +.. [3] + https://github.com/espressomd/espresso + +.. [4] + https://cmake.org/ + +.. [5] + https://www.fftw.org/ + +.. [6] + https://docs.nvidia.com/cuda/ + +.. [7] + https://docs.python.org/3/library/venv.html + +.. [8] + https://conda.io/projects/conda/en/latest/user-guide/tasks/manage-environments.html diff --git a/doc4.2.2/_sources/integration.rst.txt b/doc4.2.2/_sources/integration.rst.txt new file mode 100644 index 0000000000..5517bb01ab --- /dev/null +++ b/doc4.2.2/_sources/integration.rst.txt @@ -0,0 +1,700 @@ +.. _Integrators and thermostats: + +Integrators and thermostats +=========================== + +.. _Particle integration and propagation: + +Particle integration and propagation +------------------------------------ + +The main integration scheme of |es| is the velocity Verlet algorithm. +A steepest descent algorithm is used to minimize the system. + +Additional integration schemes are available, which can be coupled to +thermostats to enable Langevin dynamics, Brownian dynamics, Stokesian dynamics, +dissipative particle dynamics, and simulations in the NpT ensemble. + +.. _Integrators: + +Integrators +----------- + +To run the integrator call the method +:meth:`system.integrate.run() `:: + + system.integrator.run(number_of_steps, recalc_forces=False, reuse_forces=False) + +where ``number_of_steps`` is the number of time steps the integrator should perform. + +.. _Velocity Verlet Algorithm: + +Velocity Verlet algorithm +^^^^^^^^^^^^^^^^^^^^^^^^^ + +:meth:`espressomd.integrate.IntegratorHandle.set_vv` + +The equations of motion for the trajectory of point-like particles read + +.. math:: \dot v_i(t) = F_i(\{x_j\},v_i,t)/m_i \\ \dot x_i(t) = v_i(t), + +where :math:`x_i`, :math:`v_i`, :math:`m_i` are position, velocity and mass of +particle :math:`i` and :math:`F_i(\{x_j\},v_i,t)` the forces acting on it. +These forces comprise all interactions with other particles and external fields +as well as non-deterministic contributions described in :ref:`Thermostats`. + +For numerical integration, this equation is discretized to the following steps (:cite:`rapaport04a` eqs. 3.5.8 - 3.5.10): + +1. Calculate the velocity at the half step + + .. math:: v(t+dt/2) = v(t) + \frac{F(x(t),v(t-dt/2),t)}{m} dt/2 + +2. Calculate the new position + + .. math:: x(t+dt) = x(t) + v(t+dt/2) dt + +3. Calculate the force based on the new position + + .. math:: F = F(x(t+dt), v(t+dt/2), t+dt) + +4. Calculate the new velocity + + .. math:: v(t+dt) = v(t+dt/2) + \frac{F(x(t+dt),t+dt)}{m} dt/2 + +Note that this implementation of the velocity Verlet algorithm reuses +forces in step 1. That is, they are computed once in step 3, +but used twice, in step 4 and in step 1 of the next iteration. In the first time +step after setting up, there are no forces present yet. Therefore, |es| has +to compute them before the first time step. That has two consequences: +first, random forces are redrawn, resulting in a narrower distribution +of the random forces, which we compensate by stretching. Second, +coupling forces of e.g. the lattice-Boltzmann fluid cannot be computed +and are therefore lacking in the first half time step. In order to +minimize these effects, |es| has a quite conservative heuristics to decide +whether a change makes it necessary to recompute forces before the first +time step. Therefore, calling 100 times +:meth:`espressomd.integrate.Integrator.run` with ``steps=1`` does the +same as with ``steps=100``, apart from some small calling overhead. + +However, for checkpointing, there is no way for |es| to tell that the forces +that you read back in actually match the parameters that are set. +Therefore, |es| would recompute the forces before the first time step, which +makes it essentially impossible to checkpoint LB simulations, where it +is vital to keep the coupling forces. To work around this, there is +an additional parameter ``reuse_forces``, which tells integrate to not recalculate +the forces for the first time step, but use that the values still stored +with the particles. Use this only if you are absolutely sure that the +forces stored match your current setup! + +The opposite problem occurs when timing interactions: In this case, one +would like to recompute the forces, despite the fact that they are +already correctly calculated. To this aim, the option ``recalc_forces`` can be used to +enforce force recalculation. + +.. _Isotropic NpT integrator: + +Isotropic NpT integrator +^^^^^^^^^^^^^^^^^^^^^^^^ + +:meth:`espressomd.integrate.IntegratorHandle.set_isotropic_npt` + +As the NpT thermostat alters the way the equations of motion are integrated, it is +discussed here and only a brief summary is given in :ref:`Thermostats`. + +To activate the NpT integrator, use :meth:`~espressomd.integrate.IntegratorHandle.set_isotropic_npt` +with parameters: + +* ``ext_pressure``: The external pressure +* ``piston``: The mass of the applied piston +* ``direction``: Flags to enable/disable box dimensions to be subject to fluctuations. By default, all directions are enabled. + +Additionally, a NpT thermostat has to be set by :meth:`~espressomd.thermostat.Thermostat.set_npt()` +with parameters: + +* ``kT``: Thermal energy of the heat bath +* ``gamma0``: Friction coefficient of the bath +* ``gammav``: Artificial friction coefficient for the volume fluctuations. + +A code snippet would look like:: + + import espressomd + + system = espressomd.System(box_l=[1, 1, 1]) + system.thermostat.set_npt(kT=1.0, gamma0=1.0, gammav=1.0, seed=42) + system.integrator.set_isotropic_npt(ext_pressure=1.0, piston=1.0) + +The physical meaning of these parameters is described below: + +The relaxation towards a desired pressure :math:`P` (parameter ``ext_pressure``) +is enabled by treating the box +volume :math:`V` as a degree of freedom with corresponding momentum :math:`\Pi = Q\dot{V}`, +where :math:`Q` (parameter ``piston``) is an artificial piston mass. +Which box dimensions are affected to change the volume can be controlled by a list of +boolean flags for parameter ``direction``. +An additional energy :math:`H_V = 1/(2Q)\Pi + PV` +associated with the volume is postulated. This results in a "force" on the box such that + +.. math:: \dot{\Pi} = \mathcal{P} - P + +where + +.. math:: \mathcal{P} = \frac{1}{Vd} \sum_{i,j} f_{ij}x_{ij} + \frac{1}{Vd} \sum_i m_i v_i^2 + +Here :math:`\mathcal{P}` is the instantaneous pressure, :math:`d` the dimension +of the system (number of flags set by ``direction``), :math:`f_{ij}` the +short range interaction force between particles :math:`i` and :math:`j` and +:math:`x_{ij}= x_j - x_i`. + +In addition to this deterministic force, a friction :math:`-\frac{\gamma^V}{Q}\Pi(t)` +and noise :math:`\sqrt{k_B T \gamma^V} \eta(t)` are added for the box +volume dynamics and the particle dynamics. This introduces three new parameters: +The friction coefficient for the box :math:`\gamma^V` (parameter ``gammav``), +the friction coefficient of the particles :math:`\gamma^0` (parameter ``gamma0``) +and the thermal energy :math:`k_BT` (parameter ``kT``). +For a discussion of these terms and their discretisation, see :ref:`Langevin thermostat`, +which uses the same approach, but only for particles. +As a result of box geometry changes, the particle positions and velocities have to be rescaled +during integration. + +The discretisation consists of the following steps (see :cite:`kolb99a` for a full derivation of the algorithm): + +1. Calculate the particle velocities at the half step + + .. math:: v'(t+dt/2) = v(t) + \frac{F(x(t),v(t-dt/2),t)}{m} dt/2 + +2. Calculate the instantaneous pressure and "volume momentum" + + .. math:: \mathcal{P} = \mathcal{P}(x(t),V(t),f(x(t)), v'(t+dt/2)) + .. math:: \Pi(t+dt/2) = \Pi(t) + (\mathcal{P}-P) dt/2 -\frac{\gamma^V}{Q}\Pi(t) dt/2 + \sqrt{k_B T \gamma^V dt} \overline{\eta} + +3. Calculate box volume and scaling parameter :math:`L` at half step and full step, scale the simulation box accordingly + + .. math:: V(t+dt/2) = V(t) + \frac{\Pi(t+dt/2)}{Q} dt/2 + .. math:: L(t+dt/2) = V(t+dt/2)^{1/d} + .. math:: V(t+dt) = V(t+dt/2) + \frac{\Pi(t+dt/2)}{Q} dt/2 + .. math:: L(t+dt) = V(t+dt)^{1/d} + +4. Update particle positions and scale velocities + + .. math:: x(t+dt) = \frac{L(t+dt)}{L(t)} \left[ x(t) + \frac{L^2(t)}{L^2(t+dt/2)} v(t+dt/2) dt \right] + .. math:: v(t+dt/2) = \frac{L(t)}{L(t+dt)} v'(t+dt/2) + +5. Calculate forces, instantaneous pressure and "volume momentum" + + .. math:: F = F(x(t+dt),v(t+dt/2),t) + .. math:: \mathcal{P} = \mathcal{P}(x(t+dt),V(t+dt),f(x(t+dt)), v(t+dt/2)) + .. math:: \Pi(t+dt) = \Pi(t+dt/2) + (\mathcal{P}-P) dt/2 -\frac{\gamma^V}{Q}\Pi(t+dt/2) dt/2 + \sqrt{k_B T \gamma^V dt} \overline{\eta} + + with uncorrelated numbers :math:`\overline{\eta}` drawn from a random uniform process :math:`\eta(t)` + +6. Update the velocities + + .. math:: v(t+dt) = v(t+dt/2) + \frac{F(t+dt)}{m} dt/2 + +Notes: + +* The NpT algorithm is only tested for all 3 directions enabled for scaling. Usage of ``direction`` is considered an experimental feature. +* In step 4, only those coordinates are scaled for which ``direction`` is set. +* For the instantaneous pressure, the same limitations of applicability hold as described in :ref:`Pressure`. +* The particle forces :math:`F` include interactions as well as a friction (:math:`\gamma^0`) and noise term (:math:`\sqrt{k_B T \gamma^0 dt} \overline{\eta}`) analogous to the terms in the :ref:`Langevin thermostat`. +* The particle forces are only calculated in step 5 and then reused in step 1 of the next iteration. See :ref:`Velocity Verlet Algorithm` for the implications of that. +* The NpT algorithm doesn't support :ref:`Lees-Edwards boundary conditions`. +* The NpT algorithm doesn't support propagation of angular velocities. + +.. _Steepest descent: + +Steepest descent +^^^^^^^^^^^^^^^^ + +:meth:`espressomd.integrate.IntegratorHandle.set_steepest_descent` + +This feature is used to propagate each particle by a small distance parallel to the force acting on it. +When only conservative forces for which a potential exists are in use, this is equivalent to a steepest descent energy minimization. +A common application is removing overlap between randomly placed particles. + +Please note that the behavior is undefined if a thermostat is activated, +in which case the integrator will generate an error. The integrator runs +the following steepest descent algorithm: + +.. math:: \vec{r}_{i+1} = \vec{r}_i + \min(\gamma \vec{F}_i, \vec{r}_{\text{max_displacement}}), + +while the maximal force/torque is bigger than ``f_max`` or for at most ``steps`` times. The energy +is relaxed by ``gamma``, while the change per coordinate per step is limited to ``max_displacement``. +The combination of ``gamma`` and ``max_displacement`` can be used to get a poor man's adaptive update. +Rotational degrees of freedom are treated similarly: each particle is +rotated around an axis parallel to the torque acting on the particle, +with ``max_displacement`` interpreted as the maximal rotation angle. +Please be aware of the fact that this needs not to converge to a local +minimum in periodic boundary conditions. Translational and rotational +coordinates that are fixed using the ``fix`` and ``rotation`` attribute of particles are not altered. + +Usage example:: + + system.integrator.set_steepest_descent( + f_max=0, gamma=0.1, max_displacement=0.1) + system.integrator.run(20) # maximal number of steps + system.integrator.set_vv() # to switch back to velocity Verlet + +.. _Using a custom convergence criterion: + +Using a custom convergence criterion +"""""""""""""""""""""""""""""""""""" + +The ``f_max`` parameter can be set to zero to prevent the integrator from +halting when a specific force/torque is reached. The integration can then +be carried out in a loop with a custom convergence criterion:: + + min_sigma = 1 # size of the smallest particle + max_sigma = 5 # size of the largest particle + min_dist = 0.0 + system.integrator.set_steepest_descent(f_max=0, gamma=10, + max_displacement=min_sigma * 0.01) + # gradient descent until particles are separated by at least max_sigma + while min_dist < max_sigma: + min_dist = system.analysis.min_dist() + system.integrator.run(10) + system.integrator.set_vv() + +When writing a custom convergence criterion based on forces or torques, keep +in mind that particles whose motion and rotation are fixed in space along +some or all axes with ``fix`` or ``rotation`` need to be filtered from the +force/torque observable used in the custom convergence criterion. Since these +two properties can be cast to boolean values, they can be used as masks to +remove forces/torques that are ignored by the integrator:: + + particles = system.part.all() + max_force = np.max(np.linalg.norm(particles.f * np.logical_not(particles.fix), axis=1)) + max_torque = np.max(np.linalg.norm(particles.torque_lab * np.logical_not(particles.rotation), axis=1)) + +Virtual sites can also be an issue since the force on the virtual site is +transferred to the target particle at the beginning of the integration loop. +The correct forces need to be re-calculated after running the integration:: + + def convergence_criterion(forces): + '''Function that decides when the gradient descent has converged''' + return ... + p1 = system.part.add(pos=[0, 0, 0], type=1) + p2 = system.part.add(pos=[0, 0, 0.1], type=1) + p2.vs_auto_relate_to(p1) + system.integrator.set_steepest_descent(f_max=800, gamma=1.0, max_displacement=0.01) + while convergence_criterion(system.part.all().f): + system.integrator.run(10) + system.integrator.run(0, recalc_forces=True) # re-calculate forces from virtual sites + system.integrator.set_vv() + +The algorithm can also be used for energy minimization:: + + # minimize until energy difference < 5% or energy < 1e-3 + system.integrator.set_steepest_descent(f_max=0, gamma=1.0, max_displacement=0.01) + relative_energy_change = float('inf') + relative_energy_change_threshold = 0.05 + energy_threshold = 1e-3 + energy_old = system.analysis.energy()['total'] + print(f'Energy: {energy_old:.2e}') + for i in range(20): + system.integrator.run(50) + energy = system.analysis.energy()['total'] + print(f'Energy: {energy:.2e}') + relative_energy_change = (energy_old - energy) / energy_old + if relative_energy_change < relative_energy_change_threshold or energy < energy_threshold: + break + energy_old = energy + else: + print(f'Energy minimization did not converge in {i + 1} cycles') + system.integrator.set_vv() + +Please note that not all features support energy calculation. +For example :ref:`IBM ` +and :ref:`OIF ` do not implement energy calculation for +mesh surface deformation. + +.. _Brownian Dynamics: + +Brownian Dynamics +^^^^^^^^^^^^^^^^^ + +Brownian Dynamics integrator :cite:`schlick10a`. +See details in :ref:`Brownian thermostat`. + +.. _Stokesian Dynamics: + +Stokesian Dynamics +^^^^^^^^^^^^^^^^^^ + +.. note:: + + Requires ``STOKESIAN_DYNAMICS`` external feature, enabled with + ``-DWITH_STOKESIAN_DYNAMICS=ON``. + +:meth:`espressomd.integrate.IntegratorHandle.set_stokesian_dynamics` + +The Stokesian Dynamics method is used to model the behavior of spherical +particles in a viscous fluid. It is targeted at systems with very low Reynolds +numbers. In such systems, particles come to a rest almost immediately as soon as +any force on them is removed. In other words, motion has no memory of the past. + +The integration scheme is relatively simple. Only the particles' positions, +radii and forces (including torques) are needed to compute the momentary +velocities (including angular velocities). The particle positions are +integrated by the simple Euler scheme. + +The computation of the velocities is an approximation with good results +in the far field. +The Stokesian Dynamics method is only available for open systems, +i.e. no periodic boundary conditions are supported. The box size has +no effect either. + +The Stokesian Dynamics method is outlined in :cite:`durlofsky87a`. + +The following minimal example illustrates how to use the SDM in |es|:: + + import espressomd + system = espressomd.System(box_l=[1.0, 1.0, 1.0]) + system.periodicity = [False, False, False] + system.time_step = 0.01 + system.cell_system.skin = 0.4 + system.part.add(pos=[0, 0, 0], rotation=[1, 0, 0]) + system.integrator.set_stokesian_dynamics(viscosity=1.0, radii={0: 1.0}) + system.integrator.run(100) + +Because there is no force on the particle yet, nothing will move. You will need +to add your own actors to the system. The parameter ``radii`` is a dictionary +that maps particle types to different radii. ``viscosity`` is the dynamic +viscosity of the ambient infinite fluid. There are additional optional +parameters for ``set_stokesian_dynamics()``. For more information, see +:py:meth:`espressomd.integrate.IntegratorHandle.set_stokesian_dynamics()`. + +Note that this setup represents a system at zero temperature. In order to +thermalize the system, the SD thermostat needs to be activated (see +:ref:`Stokesian thermostat`). + +.. _Important_SD: + +Important +""""""""" + +The particles must be prevented from overlapping. It is mathematically allowed +for the particles to overlap to a certain degree. However, once the distance +of the sphere centers is less than 2/3 of the sphere diameter, the mobility +matrix is no longer positive definite and the Stokesian Dynamics integrator +will fail. Therefore, the particle centers must be kept apart from each +other by a strongly repulsive potential, for example the WCA potential +that is set to the appropriate particle radius (for more information about +the available interaction types see :ref:`Non-bonded interactions`). + +The current implementation of SD only includes the far field approximation. +The near field (so-called lubrication) correction is planned. For now, +Stokesian Dynamics provides a good approximation of the hydrodynamics +in dilute systems where the average distance between particles is several +sphere diameters. + + +.. _Thermostats: + +Thermostats +----------- + +To add a thermostat, call the appropriate setter:: + + system.thermostat.set_langevin(kT=1.0, gamma=1.0, seed=41) + +The different thermostats available in |es| will be described in the following +subsections. + +You may combine different thermostats at your own risk by turning them on +one by one. The list of active thermostats can be cleared at any time with +:py:meth:`system.thermostat.turn_off() `. +Not all combinations of thermostats are allowed, though (see +:py:func:`espressomd.thermostat.AssertThermostatType` for details). +Some integrators only work with a specific thermostat and throw an +error otherwise. Note that there is only one temperature for all +thermostats, although for some thermostats like the Langevin thermostat, +particles can be assigned individual temperatures. + +Since |es| does not enforce a particular unit system, it cannot know about +the current value of the Boltzmann constant. Therefore, when specifying +the temperature of a thermostat, you actually do not define the +temperature, but the value of the thermal energy :math:`k_B T` in the +current unit system (see the discussion on units, Section :ref:`On units`). + +All thermostats have a ``seed`` argument that controls the state of the random +number generator (Philox Counter-based RNG). This seed is required on first +activation of a thermostat, unless stated otherwise. It can be omitted in +subsequent calls of the method that activates the same thermostat. The random +sequence also depends on the thermostats counters that are +incremented after each integration step. + +.. _Langevin thermostat: + +Langevin thermostat +^^^^^^^^^^^^^^^^^^^ + +In order to activate the Langevin thermostat the member function +:py:meth:`~espressomd.thermostat.Thermostat.set_langevin` of the thermostat +class :class:`espressomd.thermostat.Thermostat` has to be invoked. +Best explained in an example:: + + import espressomd + system = espressomd.System(box_l=[1, 1, 1]) + system.thermostat.set_langevin(kT=1.0, gamma=1.0, seed=41) + +As explained before the temperature is set as thermal energy :math:`k_\mathrm{B} T`. + +The Langevin thermostat is based on an extension of Newton's equation of motion to + +.. math:: m_i \dot{v}_i(t) = f_i(\{x_j\},v_i,t) - \gamma v_i(t) + \sqrt{2\gamma k_B T} \eta_i(t). + +Here, :math:`f_i` are all deterministic forces from interactions, +:math:`\gamma` the bare friction coefficient and :math:`\eta` a random, "thermal" force. +The friction term accounts for dissipation in a surrounding fluid whereas +the random force mimics collisions of the particle with solvent molecules +at temperature :math:`T` and satisfies + +.. math:: <\eta(t)> = 0 , <\eta^\alpha_i(t)\eta^\beta_j(t')> = \delta_{\alpha\beta} \delta_{ij}\delta(t-t') + +(:math:`<\cdot>` denotes the ensemble average and :math:`\alpha,\beta` are spatial coordinates). + +In the |es| implementation of the Langevin thermostat, +the additional terms only enter in the force calculation. +This reduces the accuracy of the velocity Verlet integrator +by one order in :math:`dt` because forces are now velocity-dependent. + +The random process :math:`\eta(t)` is discretized by drawing an uncorrelated random number +:math:`\overline{\eta}` for each component of all the particle forces. +The distribution of :math:`\overline{\eta}` is uniform and satisfies + +.. math:: <\overline{\eta}> = 0 , <\overline{\eta}\overline{\eta}> = 1/dt + +If the feature ``ROTATION`` is compiled in, the rotational degrees of freedom are +also coupled to the thermostat. If only the first two arguments are +specified then the friction coefficient for the rotation is set to the +same value as that for the translation. +A separate rotational friction coefficient can be set by inputting +``gamma_rotate``. The two options allow one to switch the translational and rotational +thermalization on or off separately, maintaining the frictional behavior. This +can be useful, for instance, in high Péclet number active matter systems, where +one wants to thermalize only the rotational degrees of freedom while +translational degrees of freedom are affected by the self-propulsion. + +The keywords ``gamma`` and ``gamma_rotate`` can be specified as a scalar, +or, with feature ``PARTICLE_ANISOTROPY`` compiled in, as the three eigenvalues +of the respective friction coefficient tensor. This is enables the simulation of +the anisotropic diffusion of anisotropic colloids (rods, etc.). + +Using the Langevin thermostat, it is possible to set a temperature and a +friction coefficient for every particle individually via the feature +``THERMOSTAT_PER_PARTICLE``. Consult the reference of the ``part`` command +(chapter :ref:`Setting up particles`) for information on how to achieve this. + +.. _Brownian thermostat: + +Brownian thermostat +^^^^^^^^^^^^^^^^^^^ + +Brownian thermostat is a formal name of a thermostat enabling the +Brownian Dynamics feature (see :cite:`schlick10a`) which implies +a propagation scheme involving systematic and thermal parts of the +classical Ermak-McCammom's (see :cite:`ermak78a`) +Brownian Dynamics. Currently it is implemented without +hydrodynamic interactions, i.e. +with a diagonal diffusion tensor. +The hydrodynamic interactions feature will be available later +as a part of the present Brownian Dynamics or +implemented separately within the Stokesian Dynamics. + +In order to activate the Brownian thermostat, the member function +:py:attr:`~espressomd.thermostat.Thermostat.set_brownian` of the thermostat +class :class:`espressomd.thermostat.Thermostat` has to be invoked. +The system integrator should be also changed. +Best explained in an example:: + + import espressomd + system = espressomd.System(box_l=[1, 1, 1]) + system.thermostat.set_brownian(kT=1.0, gamma=1.0, seed=41) + system.integrator.set_brownian_dynamics() + +where ``gamma`` (hereinafter :math:`\gamma`) is a viscous friction coefficient. +In terms of the Python interface and setup, the Brownian thermostat is very +similar to the :ref:`Langevin thermostat`. The feature +``THERMOSTAT_PER_PARTICLE`` is used to control the per-particle +temperature and the friction coefficient setup. The major differences are +its internal integrator implementation and other temporal constraints. +The integrator is still a symplectic velocity Verlet-like one. +It is implemented via a viscous drag part and a random walk of both the position and +velocity. Due to a nature of the Brownian Dynamics method, its time step :math:`\Delta t` +should be large enough compared to the relaxation time +:math:`m/\gamma` where :math:`m` is the particle mass. +This requirement is just a conceptual one +without specific implementation technical restrictions. +Note that with all similarities of +Langevin and Brownian Dynamics, the Langevin thermostat temporal constraint +is opposite. A velocity is restarting from zero at every step. +Formally, the previous step velocity at the beginning of the the :math:`\Delta t` interval +is dissipated further +and does not contribute to the end one as well as to the positional random walk. +Another temporal constraint +which is valid for both Langevin and Brownian Dynamics: conservative forces +should not change significantly over the :math:`\Delta t` interval. + +The viscous terminal velocity :math:`\Delta v` and corresponding positional +step :math:`\Delta r` are fully driven by conservative forces :math:`F`: + +.. math:: \Delta r = \frac{F \cdot \Delta t}{\gamma} + +.. math:: \Delta v = \frac{F}{\gamma} + +A positional random walk variance of each coordinate :math:`\sigma_p^2` +corresponds to a diffusion within the Wiener process: + +.. math:: \sigma_p^2 = 2 \frac{kT}{\gamma} \cdot \Delta t + +Each velocity component random walk variance :math:`\sigma_v^2` is defined by the heat +component: + +.. math:: \sigma_v^2 = \frac{kT}{m} + +Note: the velocity random walk is propagated from zero at each step. + +A rotational motion is implemented similarly. +Note: the rotational Brownian dynamics implementation is compatible with particles which have +the isotropic moment of inertia tensor only. Otherwise, the viscous terminal angular velocity +is not defined, i.e. it has no constant direction over the time. + +.. _Isotropic NpT thermostat: + +Isotropic NpT thermostat +^^^^^^^^^^^^^^^^^^^^^^^^ + +This feature allows to simulate an (on average) homogeneous and isotropic system in the NpT ensemble. +In order to use this feature, ``NPT`` has to be defined in the :file:`myconfig.hpp`. +Activate the NpT thermostat with the command :py:meth:`~espressomd.thermostat.Thermostat.set_npt` +and setup the integrator for the NpT ensemble with :py:meth:`~espressomd.integrate.IntegratorHandle.set_isotropic_npt`. + +For example:: + + import espressomd + + system = espressomd.System(box_l=[1, 1, 1]) + system.thermostat.set_npt(kT=1.0, gamma0=1.0, gammav=1.0, seed=41) + system.integrator.set_isotropic_npt(ext_pressure=1.0, piston=1.0) + +For an explanation of the algorithm involved, see :ref:`Isotropic NpT integrator`. + +Be aware that this feature is neither properly examined for all systems +nor is it maintained regularly. If you use it and notice strange +behavior, please contribute to solving the problem. + +.. _Dissipative Particle Dynamics (DPD): + +Dissipative Particle Dynamics (DPD) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The DPD thermostat adds friction and noise to the particle +dynamics like the :ref:`Langevin thermostat`, but these +are not applied to every particle individually but instead +encoded in a dissipative interaction between particles :cite:`soddemann03a`. + +To realize a complete DPD fluid model in |es|, three parts are needed: +the DPD thermostat, which controls the temperate, a dissipative interaction +between the particles that make up the fluid, see :ref:`DPD interaction`, +and a repulsive conservative force, see :ref:`Hat interaction`. + +The temperature is set via +:py:meth:`espressomd.thermostat.Thermostat.set_dpd` +which takes ``kT`` and ``seed`` as arguments. + +The friction coefficients and cutoff are controlled via the +:ref:`DPD interaction` on a per type-pair basis. + +The friction (dissipative) and noise (random) term are coupled via the +fluctuation-dissipation theorem. The friction term is a function of the +relative velocity of particle pairs. The DPD thermostat is better for +dynamics than the Langevin thermostat, since it mimics hydrodynamics in +the system. + +As a conservative force any interaction potential can be used, +see :ref:`Isotropic non-bonded interactions`. A common choice is +a force ramp which is implemented as :ref:`Hat interaction`. + +A complete example of setting up a DPD fluid and running it +to sample the equation of state can be found in :file:`/samples/dpd.py`. + +When using a Lennard-Jones interaction, :math:`{r_\mathrm{cut}} = +2^{\frac{1}{6}} \sigma` is a good value to choose, so that the +thermostat acts on the relative velocities between nearest neighbor +particles. Larger cutoffs including next nearest neighbors or even more +are unphysical. + +Boundary conditions for DPD can be introduced by adding the boundary +as a particle constraint, and setting a velocity and a type on it, see +:class:`espressomd.constraints.Constraint`. Then a +:ref:`DPD interaction` with the type can be defined, which acts as a +boundary condition. + +.. _LB thermostat: + +Lattice-Boltzmann thermostat +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The :ref:`Lattice-Boltzmann` thermostat acts similar to the :ref:`Langevin thermostat` in that the governing equation for particles is + +.. math:: m_i \dot{v}_i(t) = f_i(\{x_j\},v_i,t) - \gamma (v_i(t)-u(x_i(t),t)) + \sqrt{2\gamma k_B T} \eta_i(t). + +where :math:`u(x,t)` is the fluid velocity at position :math:`x` and time :math:`t`. +To preserve momentum, an equal and opposite friction force and random force act on the fluid. + +Numerically the fluid velocity is determined from the lattice-Boltzmann node velocities +by interpolating as described in :ref:`Interpolating velocities`. +The backcoupling of friction forces and noise to the fluid is also done by distributing those forces amongst the nearest LB nodes. +Details for both the interpolation and the force distribution can be found in :cite:`ahlrichs99a` and :cite:`dunweg09a`. + +The LB fluid can be used to thermalize particles, while also including their hydrodynamic interactions. +The LB thermostat expects an instance of either :class:`espressomd.lb.LBFluid` or :class:`espressomd.lb.LBFluidGPU`. +Temperature is set via the ``kT`` argument of the LB fluid. + +The magnitude of the frictional coupling can be adjusted by the +parameter ``gamma``. To enable the LB thermostat, use:: + + import espressomd + import espressomd.lb + system = espressomd.System(box_l=[1, 1, 1]) + lbf = espressomd.lb.LBFluid(agrid=1, dens=1, visc=1, tau=0.01) + system.actors.add(lbf) + system.thermostat.set_lb(LB_fluid=lbf, seed=123, gamma=1.5) + +No other thermostatting mechanism is necessary +then. Please switch off any other thermostat before starting the LB +thermostatting mechanism. + +The LBM implementation provides a fully thermalized LB fluid, all +nonconserved modes, including the pressure tensor, fluctuate correctly +according to the given temperature and the relaxation parameters. All +fluctuations can be switched off by setting the temperature to 0. + +.. note:: Coupling between LB and MD only happens if the LB thermostat is set with a :math:`\gamma \ge 0.0`. + +.. _Stokesian thermostat: + +Stokesian thermostat +^^^^^^^^^^^^^^^^^^^^ + +.. note:: + + Requires ``STOKESIAN_DYNAMICS`` external feature, enabled with + ``-DWITH_STOKESIAN_DYNAMICS=ON``. + +In order to thermalize a Stokesian Dynamics simulation, the SD thermostat +needs to be activated via:: + + import espressomd + system = espressomd.System(box_l=[1.0, 1.0, 1.0]) + system.periodicity = [False, False, False] + system.time_step = 0.01 + system.cell_system.skin = 0.4 + system.part.add(pos=[0, 0, 0], rotation=[1, 0, 0], ext_force=[0, 0, -1]) + system.thermostat.set_stokesian(kT=1.0, seed=43) + system.integrator.set_stokesian_dynamics(viscosity=1.0, radii={0: 1.0}) + system.integrator.run(100) + +where ``kT`` denotes the desired temperature of the system, and ``seed`` the +seed for the random number generator. diff --git a/doc4.2.2/_sources/inter_bonded.rst.txt b/doc4.2.2/_sources/inter_bonded.rst.txt new file mode 100644 index 0000000000..9daa2d51cb --- /dev/null +++ b/doc4.2.2/_sources/inter_bonded.rst.txt @@ -0,0 +1,729 @@ +.. _Bonded interactions: + +Bonded interactions +=================== + +Bonded interactions are configured by the +:class:`espressomd.interactions.BondedInteractions` class, which is +a member of :class:`espressomd.system.System`. Generally, one may use +the following syntax to activate and assign a bonded interaction:: + + system.bonded_inter.add(bond) + p1.add_bond((bond, p2, ...)) + +In general, one instantiates an interaction object ``bond`` and subsequently passes it +to :meth:`espressomd.interactions.BondedInteractions.add`. This will enable the +bonded interaction and allows the user to assign bonds between particles ``p1`` +and ``p2``. +Bonded interactions are identified by either their *bondid* or their appropriate object. + +Defining a bond between two particles always involves three steps: +defining the interaction, adding it to the system and applying it to the particles. +To illustrate this, assume that two particles ``p1`` and ``p2`` already exist. +One could for example create a FENE bond (more information about the FENE bond +is provided in subsection :ref:`FENE bond`) between them using:: + + fene = FeneBond(k=1, d_r_max=1) + system.bonded_inter.add(fene) + p1.add_bond((fene, p2)) + +Note that the ``fene`` object specifies the type of bond and its parameters, +while the information of the bond between ``p1`` and its bonded partners +is stored on ``p1``. This means that to remove a bond, one has to remember +on which particle the bond was added. You can find more +information regarding particle properties in :ref:`Setting up particles`. + +To delete the FENE bond between particles ``p1`` and ``p2``:: + + p1.delete_bond((fene, p2)) + +Note that alternatively to particle handles, the particle's ids can be +used to setup bonded interactions. For example, to create a bond between the +particles with the ids 12 and 43:: + + system.part.by_id(12).add_bond((fene, 43)) + +.. _Distance-dependent bonds: + +Distance-dependent bonds +------------------------ + +.. _FENE bond: + +FENE bond +~~~~~~~~~ + +A FENE (finite extension nonlinear elastic) bond can be instantiated via +:class:`espressomd.interactions.FeneBond`:: + + import espressomd.interactions + fene = espressomd.interactions.FeneBond(k=, d_r_max=, r_0=) + +This command creates a bond type identifier with a FENE +interaction. The FENE potential + +.. math:: + + V(r) = -\frac{1}{2} K \Delta r_\mathrm{max}^2\ln \left[ 1 - \left( + \frac{r-r_0}{\Delta r_\mathrm{max}} \right)^2 \right] + +models a rubber-band-like, symmetric interaction between two particles with magnitude +:math:`K`, maximal stretching length :math:`\Delta r_0` and equilibrium bond length +:math:`r_0`. The bond potential diverges at a particle distance +:math:`r=r_0-\Delta r_\mathrm{max}` and :math:`r=r_0+\Delta r_\mathrm{max}`. + +.. _Harmonic bond: + +Harmonic bond +~~~~~~~~~~~~~ + +A harmonic bond can be instantiated via +:class:`espressomd.interactions.HarmonicBond`:: + + import espressomd.interactions + hb = espressomd.interactions.HarmonicBond(k=, r_0=, r_cut=) + + +This creates a bond type identifier with a classical harmonic +potential. It is a symmetric interaction between two particles. With the +equilibrium length :math:`r_0` and the magnitude :math:`k`. It is given by + +.. math:: V(r) = \frac{1}{2} k \left( r - r_0 \right)^2 + +The third, optional parameter defines a cutoff radius. Whenever a +harmonic bond gets longer than :math:`r_\mathrm{cut}`, the bond will be reported as broken, +and a background error will be raised. + +.. _Quartic bond: + +Quartic bond +~~~~~~~~~~~~ + +A quartic bond can be instantiated via +:class:`espressomd.interactions.QuarticBond`. + +The potential is minimal at particle distance :math:`r=R`. It is given by + +.. math:: V(r) = \frac{1}{2} K_0 \left( r - R \right)^2 + \frac{1}{4} K_1 \left( r - R \right)^4 + +The fourth, optional, parameter defines a cutoff radius. Whenever a +quartic bond gets longer than ``r_cut``, the bond will be reported as broken, and +a background error will be raised. + +.. _Bonded Coulomb: + +Bonded Coulomb +~~~~~~~~~~~~~~ + +.. note:: + + Requires ``ELECTROSTATICS`` feature. + +A pairwise Coulomb interaction can be instantiated via +:class:`espressomd.interactions.BondedCoulomb`:: + + import espressomd.interactions + bonded_coulomb = espressomd.interactions.BondedCoulomb(prefactor=1.0) + system.bonded_inter.add(bonded_coulomb) + p1.add_bond((bonded_coulomb, p2)) + +This creates a bond with a Coulomb pair potential between particles ``p1`` and ``p2``. +It is given by + +.. math:: V(r) = \alpha \frac{q_1 q_2}{r}, + +where :math:`q_1` and :math:`q_2` are the charges of the bound particles and :math:`\alpha` is the +Coulomb prefactor. This interaction has no cutoff and acts independently of other +Coulomb interactions. + +.. _Subtract P3M short-range bond: + +Subtract P3M short-range bond +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. note:: + + Requires the ``P3M`` feature. + +This bond can be instantiated via +:class:`espressomd.interactions.BondedCoulombSRBond`:: + + import espressomd.interactions + subtr_p3m_sr = espressomd.interactions.BondedCoulombSRBond(q1q2=) + +The parameter ``q1q2`` sets the charge factor of the short-range P3M interaction. +It can differ from the actual particle charges. This specialized bond can be +used to cancel or add **only the short-range** electrostatic part +of the P3M solver. A use case is described in :ref:`Particle polarizability with +thermalized cold Drude oscillators`. + +.. _Rigid bonds: + +Rigid bonds +~~~~~~~~~~~ + +.. note:: + + Requires ``BOND_CONSTRAINT`` feature. + + +A rigid bond can be instantiated via +:class:`espressomd.interactions.RigidBond`:: + + import espressomd.interactions + rig = espressomd.interactions.RigidBond(r=, ptol=, vtol= ) + +To simulate rigid bonds, |es| uses the Rattle Shake algorithm which satisfies +internal constraints for molecular models with internal constraints, +using Lagrange multipliers.\ :cite:`andersen83a` The constrained bond distance +is named ``r``, the positional tolerance is named ``ptol`` and the velocity tolerance +is named ``vtol``. + +.. _Thermalized distance bond: + +Thermalized distance bond +~~~~~~~~~~~~~~~~~~~~~~~~~ + +A thermalized bond can be instantiated via +:class:`espressomd.interactions.ThermalizedBond`:: + + import espressomd.interactions + thermalized_bond = espressomd.interactions.ThermalizedBond( + temp_com=, gamma_com=, + temp_distance=, gamma_distance=, + r_cut=, seed=) + system.bonded_inter.add(thermalized_bond) + +This bond can be used to apply Langevin thermalization on the centre of mass +and the distance of a particle pair. Each thermostat can have its own +temperature and friction coefficient. + +The bond is closely related to simulating :ref:`Particle polarizability with +thermalized cold Drude oscillators`. + +.. _Tabulated distance: + +Tabulated distance +~~~~~~~~~~~~~~~~~~ + +A tabulated bond length can be instantiated via +:class:`espressomd.interactions.TabulatedDistance`:: + + import espressomd.interactions + tab_dist = espressomd.interactions.TabulatedDistance( + min=, max=, energy=, force=) + system.bonded_inter.add(tab_dist) + p1.add_bond((tab_dist, p2)) + +This creates a bond type identifier with a tabulated potential. The force acts +in the direction of the connecting vector between the particles. The bond breaks +above the tabulated range, but for distances smaller than the tabulated range, +a linear extrapolation based on the first two tabulated force values is used. +For details of the interpolation, see :ref:`Tabulated interaction`. + + +.. _Virtual bonds: + +Virtual bonds +~~~~~~~~~~~~~ + +A virtual bond can be instantiated via +:class:`espressomd.interactions.Virtual`:: + + import espressomd.interactions + vb = espressomd.interactions.Virtual() + + +This creates a virtual bond type identifier for a pair bond +without associated potential or force. It can be used to specify topologies +and for some analysis that rely on bonds, or for bonds that should be +displayed in the visualizer. + + + +.. _Bond-angle interactions: + +Bond-angle interactions +----------------------- + +Bond-angle interactions involve three particles forming the angle :math:`\phi`, as shown in the schematic below. + +.. _inter_angle: +.. figure:: figures/inter_angle.png + :alt: Bond-angle interactions + :align: center + :height: 12.00cm + +This allows for a bond type having an angle-dependent potential. This potential +is defined between three particles and depends on the angle :math:`\phi` +between the vectors from the central particle to the two other particles. + +Similar to other bonded interactions, these are defined for every particle triplet and must be added to a particle (see property :attr:`~espressomd.particle_data.ParticleHandle.bonds`), in this case the central one. +For example, for the schematic with particles ``p0``, ``p1`` (central particle) and ``p2`` the bond was defined using :: + + p1.add_bond((bond_angle, p0, p2)) + +The parameter ``bond_angle`` is an instance of one of four possible bond-angle +classes, described below. + + +Harmonic angle potential +~~~~~~~~~~~~~~~~~~~~~~~~ + +:class:`espressomd.interactions.AngleHarmonic` + +Equation: + +.. math:: V(\phi) = \frac{K}{2} \left(\phi - \phi_0\right)^2. + +:math:`K` is the bending constant and :math:`\phi_0` is the equilibrium bond +angle in radians ranging from 0 to :math:`\pi`. + +Example:: + + import espressomd.interactions + angle_harmonic = espressomd.interactions.AngleHarmonic(bend=1.0, phi0=2 * np.pi / 3) + system.bonded_inter.add(angle_harmonic) + p1.add_bond((angle_harmonic, p0, p2)) + + +Cosine angle potential +~~~~~~~~~~~~~~~~~~~~~~ + +:class:`espressomd.interactions.AngleCosine` + +Equation: + +.. math:: V(\phi) = K \left[1 - \cos(\phi - \phi_0)\right] + +:math:`K` is the bending constant and :math:`\phi_0` is the equilibrium bond +angle in radians ranging from 0 to :math:`\pi`. + +Around :math:`\phi_0`, this potential is close to a harmonic one +(both are :math:`1/2(\phi-\phi_0)^2` in leading order), but it is +periodic and smooth for all angles :math:`\phi`. + +Example:: + + import espressomd.interactions + angle_cosine = espressomd.interactions.AngleCosine(bend=1.0, phi0=2 * np.pi / 3) + system.bonded_inter.add(angle_cosine) + p1.add_bond((angle_cosine, p0, p2)) + + +Harmonic cosine potential +~~~~~~~~~~~~~~~~~~~~~~~~~ + +:class:`espressomd.interactions.AngleCossquare` + +Equation: + +.. math:: V(\phi) = \frac{K}{2} \left[\cos(\phi) - \cos(\phi_0)\right]^2 + +:math:`K` is the bending constant and :math:`\phi_0` is the equilibrium bond +angle in radians ranging from 0 to :math:`\pi`. + +This form is used for example in the GROMOS96 force field. The +potential is :math:`1/8(\phi-\phi_0)^4` around :math:`\phi_0`, and +therefore much flatter than the two aforementioned potentials. + +Example:: + + import espressomd.interactions + angle_cossquare = espressomd.interactions.AngleCossquare(bend=1.0, phi0=2 * np.pi / 3) + system.bonded_inter.add(angle_cossquare) + p1.add_bond((angle_cossquare, p0, p2)) + + +Tabulated angle potential +~~~~~~~~~~~~~~~~~~~~~~~~~ + +A tabulated bond angle can be instantiated via +:class:`espressomd.interactions.TabulatedAngle`:: + + import espressomd.interactions + theta = np.linspace(0, np.pi, num=91, endpoint=True) + angle_tab = espressomd.interactions.TabulatedAngle( + energy=10 * (theta - 2 * np.pi / 3)**2, + force=10 * (theta - 2 * np.pi / 3) / 2) + system.bonded_inter.add(angle_tab) + p1.add_bond((angle_tab, p0, p2)) + +The energy and force tables must be sampled from :math:`0` to :math:`\pi`, +where :math:`\pi` corresponds to a flat angle. The forces are scaled with the +inverse length of the connecting vectors. The force on the extremities acts +perpendicular to the connecting vector between the corresponding particle and +the center particle, in the plane defined by the three particles. The force on +the center particle balances the other two forces. +For details of the interpolation, see :ref:`Tabulated interaction`. + + +.. _Dihedral interactions: + +Dihedral interactions +--------------------- + +Dihedral potential with phase shift +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Dihedral interactions are available through the :class:`espressomd.interactions.Dihedral` class:: + + import espressomd.interactions + dihedral = espressomd.interactions.Dihedral(bend=, mult=, phase=) + system.bonded_inter.add(dihedral) + p2.add_bond((dihedral, p1, p3, p4)) + +This creates a bond type identifier with a dihedral potential, a +four-body-potential. In the following, let the particle for which the +bond is created be particle :math:`p_2`, and the other bond partners +:math:`p_1`, :math:`p_3`, :math:`p_4`, in this order. Then, the +dihedral potential is given by + +.. math:: V(\phi) = K\left[1 - \cos(n\phi - \phi_0)\right], + +where :math:`n` is the multiplicity of the potential (number of minima) and can +take any integer value (typically from 1 to 6), :math:`\phi_0` is a phase +parameter and :math:`K` is the bending constant of the potential. :math:`\phi` is +the dihedral angle between the particles defined by the particle +quadruple :math:`p_1`, :math:`p_2`, :math:`p_3` and :math:`p_4`, the +angle between the planes defined by the particle triples :math:`p_1`, +:math:`p_2` and :math:`p_3` and :math:`p_2`, :math:`p_3` and +:math:`p_4`: + +.. _inter_dihedral: +.. figure:: figures/dihedral-angle.pdf + :alt: Dihedral interaction + :align: center + :height: 12.00cm + +Together with appropriate Lennard-Jones interactions, this potential can +mimic a large number of atomic torsion potentials. + +Note that there is a singularity in the forces, but not in the energy, when +:math:`\phi = 0` and :math:`\phi = \pi`. + + +Tabulated dihedral potential +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +A tabulated dihedral interaction can be instantiated via +:class:`espressomd.interactions.TabulatedDihedral`:: + + import espressomd.interactions + dihedral_tab = espressomd.interactions.TabulatedDihedral(energy=, force=) + system.bonded_inter.add(dihedral_tab) + p2.add_bond((dihedral_tab, p1, p3, p4)) + +The energy and force tables must be sampled from :math:`0` to :math:`2\pi`. +For details of the interpolation, see :ref:`Tabulated interaction`. + +Note that there is a singularity in the forces, but not in the energy, when +:math:`\phi = 0` and :math:`\phi = \pi`. + +.. _Immersed Boundary Method interactions: + +Immersed Boundary Method interactions +------------------------------------- + +Elastic forces for the Immersed Boundary Method (IBM). With the IBM, soft +particles are modelled as a triangulated surface. Each vertex has an +associated particle, and neighboring particles have bonded interactions. +When the surface is deformed by external forces, elastic forces restore +the original geometry :cite:`kruger12a`. + +.. _IBM local forces: + +IBM local forces +~~~~~~~~~~~~~~~~ + +.. _IBM Shear: + +Shear +^^^^^ + +:class:`espressomd.interactions.IBM_Triel` + +Compute elastic shear forces. To setup an interaction, use:: + + tri1 = IBM_Triel(ind1=0, ind2=1, ind3=2, elasticLaw="Skalak", k1=0.1, k2=0, maxDist=2.4) + +where ``ind1``, ``ind2`` and ``ind3`` represent the indices of the three +marker points making up the triangle. The parameter ``maxDist`` specifies +the maximum stretch above which the bond is considered broken. The parameter +``elasticLaw`` can be either ``"NeoHookean"`` or ``"Skalak"``. +The parameters ``k1`` and ``k2`` are the elastic moduli. + +.. _IBM Bending: + +Bending +^^^^^^^ + +:class:`espressomd.interactions.IBM_Tribend` + +Compute out-of-plane bending forces. To setup an interaction, use:: + + tribend = IBM_Tribend(ind1=0, ind2=1, ind3=2, ind4=3, kb=1, refShape="Initial") + +where ``ind1``, ``ind2``, ``ind3`` and ``ind4`` are four marker points +corresponding to two neighboring triangles. The indices ``ind1`` and ``ind3`` +contain the shared edge. Note that the marker points within a triangle must +be labelled such that the normal vector +:math:`\vec{n} = (\vec{r}_\text{ind2} - \vec{r}_\text{ind1}) \times (\vec{r}_\text{ind3} - \vec{r}_\text{ind1})` +points outward of the elastic object. The reference (zero energy) shape +can be either ``"Flat"`` or the initial curvature ``"Initial"``. +The bending modulus is ``kb``. + +.. _IBM global forces: + +IBM global forces +~~~~~~~~~~~~~~~~~ + +.. _IBM Volume conservation: + +Volume conservation +^^^^^^^^^^^^^^^^^^^ + +:class:`espressomd.interactions.IBM_VolCons` + +Compute the volume-conservation force. Without this correction, the volume +of the soft object tends to shrink over time due to numerical inaccuracies. +Therefore, this implements an artificial force intended to keep the volume +constant. If volume conservation is to be used for a given soft particle, +the interaction must be added to every marker point belonging to that object:: + + volCons = IBM_VolCons(softID=1, kappaV=kV) + +where ``softID`` identifies the soft particle and ``kappaV`` is a volumetric +spring constant. Note that this ``volCons`` bond does not have a bond partner. +It is added to a particle as follows:: + + system.part.by_id(0).add_bond((volCons,)) + +The comma is needed to create a tuple containing a single item. + + +.. _Object-in-fluid interactions: + +Object-in-fluid interactions +---------------------------- + +Please cite :cite:`cimrak14a` when using the interactions in this section in +order to simulate extended objects embedded in a LB fluid. For more details +please consult the dedicated OIF documentation available at +`http://cell-in-fluid.fri.uniza.sk/en/content/oif-espresso +`_. + +The following interactions are implemented in order to mimic the +mechanics of elastic or rigid objects immersed in the LB fluid flow. +Their mathematical formulations were inspired by +:cite:`dupin07a`. Details on how the bonds can be used for +modeling objects are described in section :ref:`Object-in-fluid`. + +.. _OIF local forces: + +OIF local forces +~~~~~~~~~~~~~~~~ + +OIF local forces are available through the :class:`espressomd.interactions.OifLocalForces` class. + +This type of interaction is available for closed 3D immersed objects flowing in the LB flow. + +This interaction comprises three different concepts. The local +elasticity of biological membranes can be captured by three different +elastic moduli. Stretching of the membrane, bending of the membrane and +local preservation of the surface area. Parameters +:math:`{L^0_{AB}},\ {k_s},\ {k_{s,\mathrm{lin}}}` define the stretching, +parameters :math:`\phi,\ k_b` define the bending, and +:math:`A_1,\ A_2,\ k_{al}` define the preservation of local area. The +stretching force is applied first, followed by the bending force and +finally the local area force. They can be used all together, or, by setting +any of :math:`k_s, k_{s,\mathrm{lin}}, k_b, k_{al}` to zero, the corresponding modulus +can be turned off. + +OIF local forces are asymmetric. After creating the interaction + +:: + + local_inter = OifLocalForces(r0=1.0, ks=0.5, kslin=0.0, phi0=1.7, kb=0.6, + A01=0.2, A02=0.3, kal=1.1, kvisc=0.7) + +it is important how the bond is created. Particles need to be mentioned +in the correct order. Command + +:: + + p1.add_bond((local_inter, p0.part_id, p2.part_id, p3.part_id)) + +creates a bond related to the triangles 012 and 123. The particle 0 +corresponds to point A1, particle 1 to C, particle 2 to B and particle 3 +to A2. There are two rules that need to be fulfilled: + +- there has to be an edge between particles 1 and 2 + +- orientation of the triangle 012, that is the normal vector defined as + a vector product :math:`01 \times 02` must point to the inside of + the immersed object. + +Then the stretching force is applied to particles 1 and 2, with the +relaxed length being 1.0. The bending force is applied to preserve the +angle between triangles 012 and 123 with relaxed angle 1.7 and finally, +local area force is applied to both triangles 012 and 123 with relaxed +area of triangle 012 being 0.2 and relaxed area of triangle 123 being +0.3. + + +.. _OIF Stretching: + +Stretching +^^^^^^^^^^ + +For each edge of the mesh, :math:`L_{AB}` is the current distance between point :math:`A` and +point :math:`B`. :math:`L^0_{AB}` is the distance between these points in the relaxed state, that +is if the current edge has this length exactly, then no forces are +added. :math:`\Delta L_{AB}` is the deviation from the relaxed +state, that is :math:`\Delta L_{AB} = L_{AB} - L_{AB}^0`. The +stretching force between :math:`A` and :math:`B` is calculated using + +.. math:: F_s(A,B) = (k_s\kappa(\lambda_{AB}) + k_{s,\mathrm{lin}})\Delta L_{AB}n_{AB}. + +Here, :math:`n_{AB}` is the unit vector pointing from :math:`A` to :math:`B`, :math:`k_s` is the +constant for nonlinear stretching, :math:`k_{s,\mathrm{lin}}` is the constant for +linear stretching, :math:`\lambda_{AB} = L_{AB}/L_{AB}^0`, and :math:`\kappa` +is a nonlinear function that resembles neo-Hookean behavior + +.. math:: + + \kappa(\lambda_{AB}) = \frac{\lambda_{AB}^{0.5} + \lambda_{AB}^{-2.5}} + {\lambda_{AB} + \lambda_{AB}^{-3}}. + +Typically, one wants either nonlinear or linear behavior and therefore one of +:math:`k_s, k_{s,\mathrm{lin}}` is zero. Nonetheless the interaction will work +if both constants are non-zero. + +.. figure:: figures/oif-stretching.png + :height: 4.00000cm + + +.. _OIF Bending: + +Bending +^^^^^^^ + +The tendency of an elastic object to maintain the resting shape is +achieved by prescribing the preferred angles between neighboring +triangles of the mesh. + +Denote the angle between two triangles in the resting shape by +:math:`\theta^0`. For closed immersed objects, one always has to set the +inner angle. The deviation of this angle +:math:`\Delta \theta = \theta - \theta^0` defines two bending forces for +two triangles :math:`A_1BC` and :math:`A_2BC` + +.. math:: F_{bi}(A_iBC) = k_b \Delta \theta n_{A_iBC} + +Here, :math:`n_{A_iBC}` is the unit normal vector to the triangle :math:`A_iBC`. +The force :math:`F_{bi}(A_iBC)` is assigned +to the vertex not belonging to the common edge. The opposite force +divided by two is assigned to the two vertices lying on the common edge. +This procedure is done twice, for :math:`i=1` and for :math:`i=2`. + +Notice that concave objects can be created with :math:`\theta^0 > \pi`. + +.. figure:: figures/oif-bending.png + :height: 5.00000cm + + +.. _Local area conservation: + +Local area conservation +^^^^^^^^^^^^^^^^^^^^^^^ + +This interaction conserves the area of the triangles in the triangulation. +The area constraint assigns the following shrinking/expanding force to +vertex :math:`A`: + +.. math:: F_{AT} = k_{al} \vec{AT}\frac{\Delta S_\triangle}{t_a^2 + t_b^2 + t_c^2} + +where :math:`\Delta S_\triangle` is the difference between current :math:`S_\triangle` +and area :math:`S^0` of the triangle in relaxed state, :math:`T` is the centroid of +the triangle, and :math:`t_a, t_b, t_c` are the lengths of segments :math:`AT, BT, CT`, +respectively. Similarly the analogue forces are assigned to :math:`B` and :math:`C`. + +.. figure:: figures/oif-arealocal.png + :height: 5.00000cm + + +.. _OIF global forces: + +OIF global forces +~~~~~~~~~~~~~~~~~ + +OIF global forces are available through the +:class:`espressomd.interactions.OifGlobalForces` class. + +This type of interaction is available solely for closed 3D immersed objects. + +It comprises two concepts: preservation of global surface +and of volume of the object. The parameters :math:`S^0, k_{ag}` +define preservation of the surface while parameters +:math:`V^0, k_{v}` define volume preservation. They can be +used together, or, by setting either :math:`k_{ag}` or :math:`k_{v}` to +zero, the corresponding modulus can be turned off. + +These interactions are symmetric. After the definition of the interaction by + +:: + + global_force_interaction = OifGlobalForces(A0_g=65.3, ka_g=3.0, V0=57.0, kv=2.0) + +the order of vertices is crucial. By the following command the bonds are +defined + +:: + + p0.add_bond((global_force_interaction, p1.part_id, p2.part_id)) + +Triangle 012 must have correct orientation, that is the normal vector +defined by a vector product :math:`01\times02` must point to the inside of +the immersed object. + + +.. _OIF Global area conservation: + +Global area conservation +^^^^^^^^^^^^^^^^^^^^^^^^ + +The global area conservation force is defined as + + +.. math:: F_{ag}(A) = k_{ag} \frac{S^{c} - S^{c}_0}{S^{c}_0} \cdot S_{ABC} \cdot \frac{t_{a}}{|t_a|^2 + |t_b|^2 + |t_c|^2}, + +where :math:`S^c` denotes the current surface of the immersed object, :math:`S^c_0` the surface in +the relaxed state, :math:`S_{ABC}` is the surface of the triangle, :math:`T` is the centroid of the triangle, and :math:`t_a, t_b, t_c` are the lengths of segments :math:`AT, BT, CT`, respectively. + + +.. _OIF Volume conservation: + +Volume conservation +^^^^^^^^^^^^^^^^^^^ + +The deviation of the objects volume :math:`V` is computed from the volume +in the resting shape :math:`\Delta V = V - V^0`. For each triangle, the +following force is computed: + +.. math:: F_v(ABC) = -k_v\frac{\Delta V}{V^0} S_{ABC} n_{ABC} + +where :math:`S_{ABC}` is the area of triangle :math:`ABC`, :math:`n_{ABC}` is +the normal unit vector of the plane spanned by :math:`ABC`, and :math:`k_v` +is the volume constraint coefficient. The volume of one immersed object +is computed from + +.. math:: V = \sum_{ABC}S_{ABC}\ n_{ABC}\cdot h_{ABC}, + +where the sum is computed over all triangles of the mesh and :math:`h_{ABC}` is the +normal vector from the centroid of triangle :math:`ABC` to any plane which does not +cross the cell. The force :math:`F_v(ABC)` is equally distributed to all three vertices +:math:`A, B, C.` + +.. figure:: figures/oif-volcons.png + :height: 4.00000cm diff --git a/doc4.2.2/_sources/inter_non-bonded.rst.txt b/doc4.2.2/_sources/inter_non-bonded.rst.txt new file mode 100644 index 0000000000..4b4e07ff2f --- /dev/null +++ b/doc4.2.2/_sources/inter_non-bonded.rst.txt @@ -0,0 +1,735 @@ +.. _Non-bonded interactions: + +Non-bonded interactions +======================= + +In |es|, interactions are set up and investigated by the :mod:`espressomd.interactions` module. There are +mainly two types of interactions: non-bonded and bonded interactions. + +Non-bonded interactions only depend on the *type* of the two particles +involved. This also applies to the electrostatic interaction; however, +due to its long-ranged nature, it requires special care and |es| handles it +separately with a number of state-of-the-art algorithms. To specify particle +type and charge see :ref:`Setting up particles`. + +A bonded interaction defines an interaction between a number of specific +particles; it only applies to the set of particles for which it has been +explicitly set. A bonded interaction between a set of particles has to +be specified explicitly by the command, while the command is used to +define the interaction parameters. + +.. _Isotropic non-bonded interactions: + +Isotropic non-bonded interactions +--------------------------------- + +Non-bonded interaction are configured via the :class:`espressomd.interactions.NonBondedInteraction` class, which is a member of :class:`espressomd.system.System`:: + + system.non_bonded_inter[type1, type2] + +This command defines an interaction between all particles of type ``type1`` and +``type2``. Possible interaction types and their parameters are +listed below. + +For many non-bonded interactions, it is possible to artificially cap the +forces, which often allows to equilibrate the system much faster. See +the subsection :ref:`Capping the force during warmup` for more details. + +.. _Tabulated interaction: + +Tabulated interaction +~~~~~~~~~~~~~~~~~~~~~ + +.. note:: + + Feature ``TABULATED`` required. + +The interface for tabulated interactions are implemented in the +:class:`~espressomd.interactions.TabulatedNonBonded` class. They can be configured +via the following syntax:: + + system.non_bonded_inter[type1, type2].tabulated.set_params( + min='min', max='max', energy='energy', force='force') + +This defines an interaction between particles of the types ``type1`` and +``type2`` according to an arbitrary tabulated pair potential by linear interpolation. +``force`` specifies the tabulated forces and ``energy`` the energies as a function of the +separation distance. ``force`` and ``energy`` have to have the same length :math:`N_\mathrm{points}`. +Take care when choosing the number of points, since a copy of each lookup +table is kept on each node and must be referenced very frequently. +The maximal tabulated separation distance also acts as the effective cutoff +value for the potential. + +The values of :math:`r` are assumed to be equally distributed between +:math:`r_\mathrm{min}` and :math:`r_\mathrm{max}` with a fixed distance +of :math:`(r_\mathrm{max}-r_\mathrm{min})/(N_\mathrm{points}-1)`. + +.. _Lennard-Jones interaction: + +Lennard-Jones interaction +~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. note:: + Feature ``LENNARD_JONES`` required. + +The interface for the Lennard-Jones interaction is implemented in +:class:`~espressomd.interactions.LennardJonesInteraction`. The Lennard-Jones parameters +can be set via:: + + system.non_bonded_inter[type1, type2].lennard_jones.set_params(**kwargs) + +This command defines the traditional (12-6)-Lennard-Jones interaction +between particles of the types ``type1`` and ``type2``. For a description of the input arguments +see :class:`~espressomd.interactions.LennardJonesInteraction`. The potential is defined by + +.. math:: + + \label{eq:lj} + V_\mathrm{LJ}(r) = + \begin{cases} + 4 \epsilon \left[ \left(\frac{\sigma}{r-r_\mathrm{off}}\right)^{12} + - \left(\frac{\sigma}{r-r_\mathrm{off}}\right)^6+c_\mathrm{shift}\right] + & \mathrm{if~} r_\mathrm{min}+r_\mathrm{off} < r < r_\mathrm{cut}+r_\mathrm{off}\\ + 0 + & \mathrm{otherwise} + \end{cases}. + +The traditional Lennard-Jones potential is the "work-horse" potential of +particle--particle interactions in coarse-grained simulations. It is a +simple model for the van-der-Waals interaction, and is attractive at +large distance, but strongly repulsive at short distances. +:math:`r_\mathrm{off} + \sigma` corresponds to the sum of +the radii of the interaction particles. At this distance, the potential is +:math:`V_\mathrm{LJ}(r_\mathrm{off} + \sigma) = 4 \epsilon c_\mathrm{shift}`. +The minimum of the potential is at +:math:`V_\mathrm{LJ}(r_\mathrm{off} + +2^\frac{1}{6}\sigma) = +-\epsilon + 4 \epsilon c_\mathrm{shift}`. Beyond this value the interaction is attractive. +Beyond the distance :math:`r_\mathrm{cut}` the potential is cut off and the interaction force is zero. + +If :math:`c_\mathrm{shift}` is set to the string ``'auto'``, the shift will be +automatically computed such that the potential is continuous at the +cutoff radius. + +The net force on a particle can be capped by using force capping, see +section :ref:`Capping the force during warmup` + +An optional additional parameter can be used to restrict the interaction +from a *minimal* distance :math:`r_\mathrm{min}`. This is an +optional parameter, set to :math:`0` by default. + +A special case of the Lennard-Jones potential is the +Weeks--Chandler--Andersen (WCA) potential, which one obtains by putting +the cutoff into the minimum and shifting the potential to be continuous, choosing +:math:`r_\mathrm{cut}=2^\frac{1}{6}\sigma` and :math:`c_\mathrm{shift}=` ``'auto'``. The WCA +potential is purely repulsive, and is often used to mimic hard sphere repulsion. + +.. _Generic Lennard-Jones interaction: + +Generic Lennard-Jones interaction +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. note:: + Feature ``LENNARD_JONES_GENERIC`` required. + + +The interface for the generic Lennard-Jones interactions is implemented in +:class:`espressomd.interactions.GenericLennardJonesInteraction`. They +are configured via the syntax:: + + system.non_bonded_inter[type1, type2].generic_lennard_jones.set_params(**kwargs) + +This command defines a generalized version of the Lennard-Jones +interaction (see :ref:`Lennard-Jones interaction`) between particles of the +types ``type1`` and ``type2``. The potential is defined by + +.. math:: + + \label{eq:lj-generic} + V_\mathrm{LJ}(r) = + \begin{cases} + \epsilon\left[b_1\left(\frac{\sigma}{r-r_\mathrm{off}}\right)^{e_1} + -b_2\left(\frac{\sigma}{r-r_\mathrm{off}}\right)^{e_2}+c_\mathrm{shift}\right] + & \mathrm{if~} r_\mathrm{min}+r_\mathrm{off} < r < r_\mathrm{cut}+r_\mathrm{off}\\ + 0 + & \mathrm{otherwise} + \end{cases}\ . + +Note that the prefactor 4 of the standard LJ potential is missing, so +the normal LJ potential is recovered for :math:`b_1=b_2=4`, +:math:`e_1=12` and :math:`e_2=6`. + +The optional ``LJGEN_SOFTCORE`` feature activates a softcore version of +the potential, where the following transformations apply: +:math:`\epsilon \rightarrow \lambda \epsilon` and +:math:`r-r_\mathrm{off} \rightarrow \sqrt{(r-r_\mathrm{off})^2 + +(1-\lambda) \delta \sigma^2}`. :math:`\lambda` allows to tune the strength of the +interaction, while :math:`\delta` varies how smoothly the potential goes to zero as +:math:`\lambda\rightarrow 0`. Such a feature allows one to perform +alchemical transformations, where a group of atoms can be slowly turned +on/off during a simulation. + +.. _Weeks-Chandler-Andersen interaction: + +Weeks--Chandler--Andersen interaction +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. note:: + Feature ``WCA`` required. + +The interface for the Weeks--Chandler--Andersen interactions is implemented in +:class:`espressomd.interactions.WCAInteraction`. They +are configured via the syntax:: + + system.non_bonded_inter[type1, type2].wca.set_params(**kwargs) + +This command defines a Weeks-Chandler-Andersen interaction between particles of the +types ``type1`` and ``type2``. The potential is defined by + +.. math:: + + \label{eq:wca} + V_\mathrm{WCA}(r) = + \begin{cases} + 4 \epsilon \left[ \left(\frac{\sigma}{r}\right)^{12} + - \left(\frac{\sigma}{r}\right)^6 + \frac{1}{4} \right] + & \mathrm{if~} r < \sigma 2^{\frac{1}{6}}\\ + 0 + & \mathrm{otherwise} + \end{cases}. + +.. _Lennard-Jones cosine interaction: + +Lennard-Jones cosine interaction +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. note:: + + Feature ``LJCOS`` and/or ``LJCOS2`` required. + +:class:`espressomd.interactions.LennardJonesCosInteraction` and +:class:`espressomd.interactions.LennardJonesCos2Interaction` specify +a Lennard-Jones interaction with cosine tail :cite:`soddemann01a` +between particles of the types ``type1`` and ``type2``. They +are configured via the syntax:: + + system.non_bonded_inter[type1, type2].lennard_jones_cos.set_params(**kwargs) + system.non_bonded_inter[type1, type2].lennard_jones_cos2.set_params(**kwargs) + +The first variant behaves as follows: until the minimum of the Lennard-Jones +potential at :math:`r_\mathrm{min} = r_\mathrm{off} + 2^{\frac{1}{6}}\sigma`, it +behaves identical to the unshifted Lennard-Jones potential +(:math:`c_\mathrm{shift}=0`). Between :math:`r_\mathrm{min}` and :math:`r_\mathrm{cut}`, a cosine is used to +smoothly connect the potential to 0, i.e., + +.. math:: + + V(r)=\frac{1}{2}\epsilon\left(\cos\left[\alpha(r - r_\mathrm{off})^2 + \beta\right]-1\right), + +where :math:`\alpha = \pi\left[(r_\mathrm{cut} - +r_\mathrm{off})^2-(r_\mathrm{min} - r_\mathrm{off})^2\right]^{-1}` and +:math:`\beta = \pi - \left(r_\mathrm{min} - +r_\mathrm{off}\right)^2\alpha`. + +In the second variant, the cutoff radius is +:math:`r_\mathrm{cut}=r_\mathrm{min} + \omega`, where +:math:`r_\mathrm{min} = r_\mathrm{off} + 2^{\frac{1}{6}}\sigma` as in +the first variant. The potential between :math:`r_\mathrm{min}` and +:math:`r_\mathrm{cut}` is given by + +.. math:: + + V(r)=-\epsilon\cos^2\left[\frac{\pi}{2\omega}(r - r_\mathrm{min})\right]. + +For :math:`r < r_\mathrm{min}`, :math:`V(r)` is implemented as normal +:ref:`Lennard-Jones interaction` with :math:`c_\mathrm{shift} = 0`. + +The net force on a particle can be capped by using force capping, see +section :ref:`Capping the force during warmup` + +.. _Smooth step interaction: + +Smooth step interaction +~~~~~~~~~~~~~~~~~~~~~~~ + +.. note:: + Feature ``SMOOTH_STEP`` required. + +The interface for the smooth-step interaction is implemented in +:class:`espressomd.interactions.SmoothStepInteraction`. The smooth-step parameters +can be set via:: + + system.non_bonded_inter[type1, type2].smooth_step.set_params(**kwargs) + +This defines a smooth step interaction between particles of the types ``type1`` +and ``type2``, for which the potential is + +.. math:: V(r)= \left(d/r\right)^n + \epsilon/(1 + \exp\left[2k_0 (r - \sigma)\right]) + +for :math:`rr^\text{cut}_\parallel` (parameter ``r_cut``). + +In case the ``weight_function`` 1 is selected the parameter ``k`` can be chosen. :math:`k = 1` is the +default and recovers the linear ramp. :math:`k > 1` enhances the dissipative nature of the interaction +and thus yields higher Schmidt numbers :cite:`yaghoubi15a`. + +The random force has the properties + +.. math:: <\eta_{ij}(t)> = 0 , <\eta_{ij}^\alpha(t)\eta_{kl}^\beta(t')> = \delta_{\alpha\beta} \delta_{ik}\delta_{jl}\delta(t-t') + +and is numerically discretized to a random number :math:`\overline{\eta}` for each spatial +component for each particle pair drawn from a uniform distribution +with properties + +.. math:: <\overline{\eta}> = 0 , <\overline{\eta}\overline{\eta}> = 1/dt + +For the perpendicular part, the dissipative and random force are calculated analogously + +.. math:: \vec{F}_{ij}^{D} = -\gamma_\bot w^D (r_{ij}) (I-\hat{r}_{ij}\otimes\hat{r}_{ij}) \cdot \vec{v}_{ij} +.. math:: \vec{F}_{ij}^R = \sqrt{2 k_B T \gamma_\bot w_\bot (r_{ij})} (I-\hat{r}_{ij}\otimes\hat{r}_{ij}) \cdot \vec{\eta}_{ij} + +and introduce the second set of parameters prefixed with ``trans_``. +For :math:`w_\bot (r_{ij})` (parameter ``trans_weight_function``) +the same options are available as for :math:`w_\parallel (r_{ij})`. + +Note: This interaction does *not* conserve angular momentum. + +A more detailed description of the interaction can be found in :cite:`soddemann03a`. + +.. _Thole correction: + +Thole correction +~~~~~~~~~~~~~~~~ + +.. note:: + + Requires features ``THOLE`` and ``ELECTROSTATICS``. + +.. note:: + + ``THOLE`` is only implemented for the P3M electrostatics solver. + +The Thole correction is closely related to simulations involving +:ref:`Particle polarizability with thermalized cold Drude oscillators`. +In this context, it is used to correct for overestimation of +induced dipoles at short distances. Ultimately, it alters the short-range +electrostatics of P3M to result in a damped Coulomb interaction potential +:math:`V(r) = \frac{q_1 q_2}{r} \cdot (1- e^{-s r} (1 + \frac{s r}{2}) )`. The +Thole scaling coefficient :math:`s` is related to the polarizabilities +:math:`\alpha` and Thole damping parameters :math:`a` of the interacting +species via :math:`s = \frac{ (a_i + a_j) / 2 }{ (\alpha_i \alpha_j)^{1/6} }`. +Note that for the Drude oscillators, the Thole correction should be applied +only for the dipole part :math:`\pm q_d` added by the Drude charge and not on +the total core charge, which can be different for polarizable ions. Also note +that the Thole correction acts between all dipoles, intra- and intermolecular. +Again, the accuracy is related to the P3M accuracy and the split between +short-range and long-range electrostatics interaction. It is configured by:: + + system = espressomd.System(box_l=[1, 1, 1]) + system.non_bonded_inter[type_1,type_2].thole.set_params(scaling_coeff=, q1q2=) + +with parameters: + * ``scaling_coeff``: The scaling coefficient :math:`s`. + * ``q1q2``: The charge factor of the involved charges. + +Because the scaling coefficient depends on the *mixed* polarizabilities and the +nonbonded interaction is controlled by particle types, each Drude charge with a +unique polarizability has to have a unique type. Each Drude charge type has +a Thole correction interaction with all other Drude charges and all Drude +cores, except the one it's connected to. This exception is handled internally +by disabling Thole interaction between particles connected via Drude bonds. +Also, each Drude core has a Thole correction interaction with all other Drude +cores and Drude charges. To assist with the bookkeeping of mixed scaling +coefficients, the helper method :meth:`~espressomd.drude_helpers.DrudeHelpers.add_drude_particle_to_core` (see +:ref:`Particle polarizability with thermalized cold Drude oscillators`) +collects all core types, Drude types and relevant parameters when a Drude +particle is created. The user already provided all the information when +setting up the Drude particles, so the simple call:: + + add_all_thole(, ) + +given the :class:`espressomd.System() ` object, uses this information to create all +necessary Thole interactions. The method calculates the mixed scaling +coefficient ``s`` and creates the non-bonded Thole interactions between the +collected types to cover all the Drude-Drude, Drude-core and core-core +combinations. No further calls of :meth:`~espressomd.drude_helpers.DrudeHelpers.add_drude_particle_to_core` should +follow. Set ``verbose`` to ``True`` to print out the coefficients, charge factors +and involved types. + +The samples folder contains the script :file:`/samples/drude_bmimpf6.py` with a +fully polarizable, coarse grained ionic liquid where this approach is applied. + +.. _Anisotropic non-bonded interactions: + +Anisotropic non-bonded interactions +----------------------------------- + +.. _Gay-Berne interaction: + +Gay--Berne interaction +~~~~~~~~~~~~~~~~~~~~~~ + +.. note:: + Feature ``GAY_BERNE`` required. + +The interface for a Gay--Berne interaction is provided by the +:class:`espressomd.interactions.GayBerneInteraction` class. Interaction +parameters can be set via:: + + system.non_bonded_inter[type1, type2].gay_berne.set_params(**kwargs) + +This defines a Gay--Berne potential for prolate and oblate particles +between particles types ``type1`` and ``type2``. The Gay--Berne potential is an +anisotropic version of the classic Lennard-Jones potential, with +orientational dependence of the range :math:`\sigma_0` and the well-depth +:math:`\varepsilon_0`. + +Assume two particles with orientations given by the unit vectors +:math:`\mathbf{\hat{u}}_i` and :math:`\mathbf{\hat{u}}_j` and +intermolecular vector :math:`\mathbf{r} = r\mathbf{\hat{r}}`. If +:math:`r` a +broad range of interaction potentials which opens up possibilities for +performing simulations using models with different levels of coarse-graining. +It also includes modern and efficient algorithms for treatment of +:ref:`electrostatics` (P3M, MMM-type algorithms, constant potential +simulations, dielectric interfaces, …), hydrodynamic interactions +(:ref:`DPD`, :ref:`Lattice-Boltzmann`), +and :ref:`magnetic interactions`, only +to name a few. It is designed to exploit the capabilities of parallel +computational environments. The program is being continuously extended to keep +the pace with current developments both in the algorithms and software. + +The kernel of |es| is written in C++ with computational efficiency in mind. +Interaction between the user and the simulation engine is provided via a +*Python scripting interface*. This enables setup of arbitrarily complex +systems, with simulation parameters that can be modified at runtime. + +.. _Guiding principles: + +Guiding principles +------------------ + +|es| is a tool for performing computer simulation and this user guide describes +how to use this tool. However, it should be borne in mind that being able to +operate a tool is not sufficient to obtain physically meaningful results. It is +always the responsibility of the user to understand the principles behind the +model, simulation and analysis methods he or she is using. + +It is expected that the users of |es| and readers of this user guide have a +thorough understanding of simulation methods and algorithms they are planning +to use. They should have passed a basic course on molecular simulations or read +one of the renown textbooks, e.g. :cite:`frenkel02b`. It is not necessary to +understand everything that is contained in |es|, but it is inevitable to +understand all methods that you want to use. Using the program as a black box +without proper understanding of the background will most probably result in +wasted user and computer time with no useful output. + +To enable future extensions, the functionality of the program is kept as +general as possible. It is modularized, so that extensions to some parts +of the program (e.g. implementing a new potential) can be done by modifying +or adding only a few files, leaving most of the code untouched. + +Much emphasis is put on readability of the code. To cite a few examples, +hard-coded C-style for loops are generally avoided in favor of modern C++ +range-based for loops or STL accumulators and algorithms, and output +parameters are often avoided by returning a ``std::tuple``. In addition, +vector algebra can be expressed in few lines of code thanks to the +``Utils::Vector`` class that provides overloads for elementary operations, +the dot product, the cross product and operations with matrices. + +Hand-in-hand with the extensibility and readability of the code comes the +flexibility of the whole program. On the one hand, it is provided by the +generalized functionality of its parts, avoiding highly specialized functions. +An example can be the implementation of the Generic Lennard-Jones potential +described in section :ref:`Generic Lennard-Jones interaction` where the user +can change all available parameters. Where possible, default values are +avoided, providing the user with the possibility of choice. |es| cannot be +aware whether your particles are representing atoms or billiard balls, so it +cannot check if the chosen parameters make sense and it is the user's +responsibility to make sure they do. In fact, |es| can be used to play +billiard (see sample script :file:`samples/billiard.py`)! + +On the other hand, flexibility of |es| stems from the employment of a scripting +language at the steering level. Apart from the ability to modify the simulation +and system parameters at runtime, many simple tasks which are not +computationally critical can be implemented at this level, without even +touching the C++ kernel. For example, simple problem-specific analysis routines +can be implemented in this way and made to interact with the simulation core. +Another example of the program's flexibility is the possibility to integrate +system setup, simulation and analysis in one single control script. |es| +provides commands to create particles and set up interactions between them. +Capping of forces helps prevent system blow-up when initially some particles +are placed on top of each other. Using the Python interface, one can simulate +the randomly set-up system with capped forces, interactively check whether it +is safe to remove the cap and switch on the full interactions and then perform +the actual productive simulation. + +.. _Basic program structure: + +Basic program structure +----------------------- + +As already mentioned, |es| consists of two components. The simulation engine is +written in C++ for the sake of computational efficiency. The steering or +control level is interfaced to the kernel via an interpreter of Python +scripting languages. + +The kernel performs all computationally demanding tasks. Before all, +integration of Newton's equations of motion, including calculation of energies +and forces. It also takes care of internal organization of data, storing the +data about particles, communication between different processors or cells of +the cell-system. The kernel is modularized so that basic functions are accessed +via a set of well-defined lean interfaces, hiding the details of the complex +numerical algorithms. + +The scripting interface (Python) is used to setup the system (particles, +boundary conditions, interactions, ...), control the simulation, run analysis, +and store and load results. The user has at hand the full readability and +functionality of the scripting language. For instance, it is possible to use +the SciPy package for analysis and PyPlot for plotting. With a certain overhead +in efficiency, it can also be used to reject/accept new configurations in +combined MD/MC schemes. In principle, any parameter which is accessible from +the scripting level can be changed at any moment of runtime. In this way +methods like thermodynamic integration become readily accessible. + +The focus of the user guide is documenting the scripting interface, its +behavior and use in the simulation. It only describes certain technical details +of implementation which are necessary for understanding how the script +interface works. Technical documentation of the code and program structure is +contained in the `online wiki `_. + +.. _Basic python simulation script: + +Basic python simulation script +------------------------------ + +In this section, a brief overview is given over the most important components +of the Python interface. Their usage is illustrated by short examples, which +can be put together to a demo script. + +.. rubric:: Imports + +As usual, the Python script starts by importing the necessary modules. The +|es| interface is contained in the :mod:`espressomd` Python module, which needs to be +imported, before anything related can be done. :: + + import espressomd + +This should be followed by further necessary imports of the example at hand: :: + + import espressomd.interactions + import espressomd.electrostatics + +.. rubric:: espressomd.System + +Access to the simulation system is provided via the :class:`~espressomd.system.System` class. As a +first step, an instance of this class needs to be created. :: + + system = espressomd.System(box_l=[10, 10, 10]) + +Note that only one instance of the System class can be created due to +limitations in the simulation core. :ref:`Properties of the System +class` are used to access the parameters +concerning the simulation system such as box geometry, time step or +:ref:`cell-system`: :: + + print(f"The box dimensions are {system.box_l}") + system.time_step = 0.01 + system.cell_system.skin = 0.4 + +.. rubric:: Particles + +The particles in the simulation are accessed via ``system.part``, an instance of the +:class:`~espressomd.particle_data.ParticleList` class. Use the ``add`` method to +:ref:`create new particles`: :: + + part1 = system.part.add(pos=[1.0, 1.0, 1.0], type=0) + part2 = system.part.add(pos=[1.0, 1.0, 2.0], type=0) + +The individual particles are represented by instances of :class:`~espressomd.particle_data.ParticleHandle` which, as +demonstrated in the example above, can be stored as Python variables (``part1`` and ``part2``). +The properties of the particle are implemented as Python properties and can be accessed and/or modified using +the respective :class:`~espressomd.particle_data.ParticleHandle`: :: + + >>> print(part2.pos) + [1.0, 1.0, 2.0] + >>> part2.pos = [0.2, 2.0, 0.0] + >>> print(part2.pos) + [0.2, 2.0, 0.0] + +It is also possible to :ref:`loop` over all particles:: + + for p in system.part: + print(f"Particle pos {p.pos}, type {p.type}") + +Internally, each particle is automatically assigned a unique numerical id by |es|. +Note that in principle it is possible to explicitly set this particle id (if not in use already) on particle creation. +Using the id, the respective particle can be accessed from the particle list:: + + >>> system.part.add(id=3, pos=[2.1, 1.2, 3.3], type=0) + >>> system.part.by_id(3).pos = [1.0, 1.0, 2.0] + >>> print(system.part.by_id(3).pos) + [1.0, 1.0, 2.0] + +For larger simulation setups, explicit handling of numerical ids can quickly +become confusing and is thus error-prone. We therefore highly recommend using +:class:`~espressomd.particle_data.ParticleHandle` instead wherever possible. + +:ref:`Properties of all particles` +can be accessed via: :: + + positions = system.part.all().pos + +.. rubric:: Interactions + +In |es|, interactions between particles usually fall in three categories: + +- :ref:`Non-bonded interactions` are short-ranged interactions between *all* + pairs of particles of specified types. An example is the + Lennard-Jones interaction mimicking overlap repulsion and van-der-Waals attraction. + +- :ref:`Bonded interactions` act only between two specific particles. An + example is the harmonic bond between adjacent particles in a polymer + chain. + +- Long-range interactions act between all particles with specific + properties in the entire system. An example is the :ref:`Coulomb + interaction`. + +.. rubric:: Non-bonded interaction + +Non-bonded interactions are represented as subclasses of +:class:`~espressomd.interactions.NonBondedInteraction`, e.g. +:class:`~espressomd.interactions.LennardJonesInteraction`. +Instances of these classes for a given pair of particle types are accessed via +the non_bonded_inter attribute of the System class. This sets up a Lennard-Jones +interaction between all particles of type 0 with the given parameters: :: + + system.non_bonded_inter[0, 0].lennard_jones.set_params( + epsilon=1, sigma=1, cutoff=5.0, shift="auto") + +.. rubric:: Bonded interaction + +Next, we add a pair of particles with a different type to later add +a :ref:`harmonic bond` between them: :: + + part1 = system.part.add(pos=[7.0, 7.0, 7.0], type=1) + part2 = system.part.add(pos=[7.0, 7.0, 8.0], type=1) + +To set up a bonded interaction, first an instance of the appropriate +class is created with the desired parameters: :: + + harmonic = espressomd.interactions.HarmonicBond(k=1.0, r_0=0.5) + +Then, the bonded interaction is registered in the simulation core +by adding the instance to :attr:`~espressomd.system.System.bonded_inter`: :: + + system.bonded_inter.add(harmonic) + +Finally, the bond can be added to particles using the :meth:`~espressomd.particle_data.ParticleHandle.add_bond()` +method of :class:`~espressomd.particle_data.ParticleHandle` with the instance of the bond class and the +instance of the partner particle: :: + + part1.add_bond((harmonic, part2)) + +.. rubric:: Charges + +Now we demonstrate how to setup a pair of charged particles treated by the P3M +electrostatics solver. We start by adding the particles: :: + + cation = system.part.add(pos=[4.0, 1.0, 1.0], type=2, q=1.0) + anion = system.part.add(pos=[6.0, 1.0, 1.0], type=2, q=-1.0) + +Long-range interactions and other methods that might be mutually exclusive +are treated as so-called *actors*. They are used by first creating an instance +of the desired actor:: + + p3m = espressomd.electrostatics.P3M(accuracy=1e-3, prefactor=1.0) + +and then adding it to the system: :: + + print("Tuning p3m ...") + system.actors.add(p3m) + +.. rubric:: Integration + +So far we just *added* particles and interactions, but did not propagate the +system. This is done by the *integrator*. It uses by default the velocity +Verlet algorithm and is already created by the system class. To perform an +integration step, just execute:: + + system.integrator.run(1) + +Usually, the system is propagated for a number of steps in a loop alongside +with some analysis. In this last snippet, the different energy contributions +of the system are printed: :: + + num_configs = 10 + num_steps = 1000 + + for i in range(num_configs): + system.integrator.run(num_steps) + energy = system.analysis.energy() + print(f"System time: {system.time}") + print(f"Energy of the LJ interaction: {energy['non_bonded']}") + print(f"Energy of the harmonic bond: {energy['bonded']}") + print(f"Energy of the Coulomb interaction: {energy['coulomb']}") + +.. _Tutorials: + +Tutorials +--------- + +There are a number of tutorials that introduce the use of |es| for different +physical systems. You can also find the tutorials and related scripts in the +directory :file:`/doc/tutorials`. +They are executed with the ``ipypresso`` script. + +The following tutorials are available: + +* :file:`lennard_jones`: Modelling of a single-component and a two-component Lennard-Jones liquid. +* :file:`visualization`: Using the online visualizers of |es|. +* :file:`error_analysis`: Statistical analysis of simulation results. +* :file:`charged_system`: Modelling of ion condensation around a charged rod. +* :file:`ferrofluid`: Modelling a colloidal suspension of magnetic particles. +* :file:`lattice_boltzmann`: Simulations including hydrodynamic interactions using the lattice-Boltzmann method. +* :file:`raspberry_electrophoresis`: Extended objects in a lattice-Boltzmann fluid, raspberry particles. +* :file:`active_matter`: Modelling of self-propelling particles. +* :file:`electrokinetics`: Modelling electrokinetics together with hydrodynamic interactions. +* :file:`constant_pH`: Modelling the titration of a weak acid using the constant pH method + +The executed notebooks with solutions and plots are periodically deployed +online to the `GitHub Pages `__. + +.. _Sample scripts: + +Sample scripts +-------------- + +Several scripts that can serve as usage examples can be found in the +directory :file:`/samples`. +They are executed with the ``pypresso`` script. + +The following samples are available: + +.. include:: samples.rst + + +.. _On units: + +On units +-------- + +What is probably one of the most confusing subjects for beginners of |es| is, +that |es| does not predefine any units. While most MD programs specify a set +of units, like, for example, that all lengths are measured in Ångström +or nanometers, times are measured in nano- or picoseconds and energies +are measured in :math:`\mathrm{kJ/mol}`, |es| does not do so. + +Instead, the length-, time- and energy scales can be freely chosen by +the user. Once these three scales are fixed, all remaining units are +derived from these three basic choices. + +The probably most important choice is the length scale. A length of +:math:`1.0` can mean a nanometer, an Ångström, or a kilometer - +depending on the physical system, that the user has in mind when he +writes his |es|-script. When creating particles that are intended to +represent a specific type of atoms, one will probably use a length scale +of Ångström. This would mean, that the parameter :math:`\sigma` of the +Lennard-Jones interaction between two atoms would be set to twice the +van-der-Waals radius of the atom in Ångström. Alternatively, one could +set :math:`\sigma` to :math:`2.0` and measure all lengths in multiples +of the van-der-Waals radius. When simulation colloidal particles, which +are usually of micrometer size, one will choose their diameter (or +radius) as basic length scale, which is much larger than the Ångström +scale used in atomistic simulations. + +The second choice to be made is the energy scale. One can for example +choose to set the Lennard-Jones parameter :math:`\epsilon` to the energy +in :math:`\mathrm{kJ/mol}`. Then all energies will be measured in that +unit. Alternatively, one can choose to set it to :math:`1.0` and measure +everything in multiples of the van-der-Waals binding energy of the +respective particles. + +The final choice is the time (or mass) scale. By default, |es| uses a reduced +mass of 1 for all particles, so that the mass unit is simply the mass of one particle. +Combined with the energy and length scale, this is sufficient to derive +the resulting time scale: + +.. math:: + + [\mathrm{time}] = [\mathrm{length}]\sqrt{\frac{[\mathrm{mass}]}{[\mathrm{energy}]}} + +This means, that if you measure lengths in Ångström, energies in +:math:`k_B T` at 300K and masses in 39.95u, then your time scale is +:math:`\mathring{A} \sqrt{39.95u / k_B T} = 0.40\,\mathrm{ps}`. + +On the other hand, if you want a particular time scale, then the mass +scale can be derived from the time, energy and length scales as + +.. math:: + + [\mathrm{mass}] = [\mathrm{energy}]\frac{[\mathrm{time}]^2}{[\mathrm{length}]^2}. + +By activating the feature ``MASS``, you can specify particle masses in +the chosen unit system. + +A special note is due regarding the temperature, which is coupled to the +energy scale by Boltzmann's constant. However, since |es| does not enforce a +particular unit system, we also don't know the numerical value of the +Boltzmann constant in the current unit system. Therefore, when +specifying the temperature of a thermostat, you actually do not define +the temperature, but the value of the thermal energy :math:`k_B T` in +the current unit system. For example, if you measure energy in units of +:math:`\mathrm{kJ/mol}` and your real temperature should be 300K, then +you need to set the thermostat's effective temperature to +:math:`k_B 300\, K \mathrm{mol / kJ} = 2.494`. + +As long as one remains within the same unit system throughout the whole +|es|-script, there should be no problems. + +.. _Available simulation methods: + +Available simulation methods +---------------------------- + +|es| provides a number of useful methods. The following table shows the +various methods as well as their status. The table distinguishes between +the state of the development of a certain feature and the state of its +use. We distinguish between five levels: + +**Core** + means that the method is part of the core of |es|, and that it is + extensively developed and used by many people. + +**Good** + means that the method is developed and used by independent people + from different groups. + +**Group** + means that the method is developed and used in one group. + +**Single** + means that the method is developed and used by one person only. + +**None** + means that the method is developed and used by nobody. + +**Experimental** + means that the method might have side effects. + +In the "Tested" column, we note whether there is an integration test for the method. + +If you believe that the status of a certain method is wrong, please +report so to the developers using the instructions in :ref:`Contributing`. + +.. tabularcolumns:: |l|c|c|c| + ++--------------------------------+------------------------+------------------+------------+ +| **Feature** | **Development Status** | **Usage Status** | **Tested** | ++================================+========================+==================+============+ +| **Integrators**, **Thermostats**, **Barostats** | ++--------------------------------+------------------------+------------------+------------+ +| Velocity-Verlet Integrator | Core | Core | Yes | ++--------------------------------+------------------------+------------------+------------+ +| Langevin Thermostat | Core | Core | Yes | ++--------------------------------+------------------------+------------------+------------+ +| Isotropic NpT | Experimental | None | Yes | ++--------------------------------+------------------------+------------------+------------+ +| Quaternion Integrator | Core | Good | Yes | ++--------------------------------+------------------------+------------------+------------+ +| Stokesian Dynamics | Single | None | Yes | ++--------------------------------+------------------------+------------------+------------+ +| **Interactions** | ++--------------------------------+------------------------+------------------+------------+ +| Short-range Interactions | Core | Core | Yes | ++--------------------------------+------------------------+------------------+------------+ +| Constraints | Core | Core | Yes | ++--------------------------------+------------------------+------------------+------------+ +| Relative Virtual Sites | Good | Good | Yes | ++--------------------------------+------------------------+------------------+------------+ +| RATTLE Rigid Bonds | Single | Group | Yes | ++--------------------------------+------------------------+------------------+------------+ +| Gay--Berne Interaction | Experimental | Experimental | Yes | ++--------------------------------+------------------------+------------------+------------+ +| **Coulomb Interaction** | ++--------------------------------+------------------------+------------------+------------+ +| P3M | Core | Core | Yes | ++--------------------------------+------------------------+------------------+------------+ +| P3M on GPU | Single | Single | Yes | ++--------------------------------+------------------------+------------------+------------+ +| Dipolar P3M | Group | Good | Yes | ++--------------------------------+------------------------+------------------+------------+ +| MMM1D | Single | Good | No | ++--------------------------------+------------------------+------------------+------------+ +| MMM1D on GPU | Single | Single | No | ++--------------------------------+------------------------+------------------+------------+ +| ELC | Good | Good | Yes | ++--------------------------------+------------------------+------------------+------------+ +| ICC* | Group | Group | Yes | ++--------------------------------+------------------------+------------------+------------+ +| **Hydrodynamic Interaction** | ++--------------------------------+------------------------+------------------+------------+ +| Lattice-Boltzmann | Core | Core | Yes | ++--------------------------------+------------------------+------------------+------------+ +| Lattice-Boltzmann on GPU | Group | Core | Yes | ++--------------------------------+------------------------+------------------+------------+ +| **Input/Output** | ++--------------------------------+------------------------+------------------+------------+ +| VTF output | Core | Core | Yes | ++--------------------------------+------------------------+------------------+------------+ +| VTK output | Group | Group | No | ++--------------------------------+------------------------+------------------+------------+ +| Checkpointing | Experimental | Experimental | Yes | ++--------------------------------+------------------------+------------------+------------+ +| **Visualization** | ++--------------------------------+------------------------+------------------+------------+ +| OpenGL visualizer | Good | Good | No | ++--------------------------------+------------------------+------------------+------------+ +| **Miscellaneous** | ++--------------------------------+------------------------+------------------+------------+ +| Electrokinetics | Group | Group | Yes | ++--------------------------------+------------------------+------------------+------------+ +| Collision Detection | Group | Group | Yes | ++--------------------------------+------------------------+------------------+------------+ +| Reaction Ensemble | Group | Group | Yes | ++--------------------------------+------------------------+------------------+------------+ +| Constant pH Method | Group | Group | Yes | ++--------------------------------+------------------------+------------------+------------+ +| Object-in-fluid | Group | Group | Yes | ++--------------------------------+------------------------+------------------+------------+ +| Immersed boundary method | Group | Group | Yes | ++--------------------------------+------------------------+------------------+------------+ +| DPD | Single | Good | Yes | ++--------------------------------+------------------------+------------------+------------+ +| DPD Thermostat | Single | Good | Yes | ++--------------------------------+------------------------+------------------+------------+ + + + +.. _Software releases: + +Software releases +----------------- + +|es| releases use the following versioning scheme: ``major.minor.patch_level``. +New features are introduced in major and minor releases, while bugfix releases +only patch bugs without adding or removing features. Since the ``patch_level`` +doesn't affect the capabilities of the software, it's common to refer to +releases simply as ``major.minor``. + +New users should always choose the latest release. When opting for an +older release, we recommend using the latest bugfix release from that +line (for example 4.0.2 instead of 4.0), unless you need to capture the +behavior of bugs for reproducibility reasons. When filing bug reports +or citing |es|, the version should always be mentioned. See +our policies on :ref:`bug reports ` and +:ref:`citing the software ` for more details. + +Releases from 4.0 onward can be found on +`GitHub `_. +Older releases from 2.1 to 3.3 can be found in +`GNU Savannah `_. +See our policy on :ref:`API backward compatibility +` +if you need more details. + +.. _Release workflow: + +Release workflow +^^^^^^^^^^^^^^^^ + +Major and minor releases are branched from the development branch ``python``. +When a version ``X.Y.0`` is released, the ``python`` branch is copied +to a new branch named ``X.Y``, at which point the ``python`` branch is ready +to accept contributions for the ``X.Y+1.0`` release. The ``X.Y`` branch +still gets bugfix releases ``X.Y.1``, ``X.Y.2``, ..., for several months. + +`GitHub milestones `_ +track the progress of each release. They can give you an idea of the changes +in future releases, although it's more convenient to follow the live release +notes in the `wiki `_ (listed +under "Planned releases" in the side bar). These notes are updated monthly. +Most users will only be interested in the live release notes of the +planned bugfix release for the version of |es| they're using. + +If you're actively developing code for |es|, you might also be interested in +the summaries of the `ESPResSo meetings +`_, +where the core team discusses plans for future releases and feature freezes. + +.. _Intended interface compatibility between ESPResSo versions: + +Intended interface compatibility between |es| versions +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +With regards to the stability of the Python interface, we have the following +guidelines: + +* ``patch_level``: The Python interface will not change if only the + ``patch_level`` number is different. Example: 4.0.0 :math:`\to` 4.0.1. + +* ``minor``: There will be no silent interface changes between two versions + with different minor numbers, i.e. a simulation script will not silently + produce different results with the new version. The interface can, however, + be extended. In important cases, the interface can change in such a way + that using the old interface produces a clear error message and the + simulation is terminated. Example: 4.0.2 :math:`\to` 4.1.0. + +* ``major``: No guarantees are made for a transition between major versions. + Example: 4.1.2 :math:`\to` 5.0. + +* No guarantees are made with regards to the development branch on GitHub. + +* No guarantees are made with respect to the C++ bindings in the simulation core. + +.. _How to cite ESPResSo: + +How to cite |es| +^^^^^^^^^^^^^^^^ + +Please cite :cite:t:`weik19a` (BibTeX key ``weik19a`` in :file:`doc/bibliography.bib`) +for |es| 4.0 and later, or both :cite:t:`arnold13a` and :cite:t:`limbach06a` +(BibTeX keys ``arnold13a`` and ``limbach06a`` in :file:`doc/bibliography.bib`) +for |es| 2.0 to 3.3. To find the version number, use the following command: + +.. code-block:: bash + + ./pypresso -c "import espressomd.version;print(espressomd.version.friendly())" + +A number of algorithms in |es| are fairly advanced and unique to |es|. +The authors of these contributions kindly ask you to cite the relevant +publications, using the BibTeX entries indicated in this user guide. + +A complete citation would look like this: + + Simulations were carried out with ESPResSo 4.2[24] using the ICC\* + algorithm[25]. + + | ____________ + + | [24] F. Weik, R. Weeber, K. Szuttor *et al.* ESPResSo 4.0 -- an + extensible software package for simulating soft matter systems. + *Eur. Phys. J. Spec. Top.* **227**, 1789--1816 (2019). + doi:\ `10.1140/epjst/e2019-800186-9 `_. + | [25] C. Tyagi, M. Süzen, M. Sega *et al.* An iterative, fast, + linear-scaling method for computing induced charges on arbitrary + dielectric boundaries. *J. Chem. Phys.* **132**, 154112 (2010). + doi:\ `10.1063/1.3376011 `_. + +You may also provide the patch level, when relevant. If you developed code +for |es| and made it available in a publicly accessible repository, you +should consider providing the corresponding URL, for example in a footnote: + + The method was implemented for ESPResSo 4.2.2[24] and the source code is + available online\ :superscript:`note 1`. + + | ____________ + + | :superscript:`note 1` https://github.com/username/espresso/tree/implemented-algorithm + + | [24] F. Weik, R. Weeber, K. Szuttor *et al.* ESPResSo 4.0 -- an + extensible software package for simulating soft matter systems. + *Eur. Phys. J. Spec. Top.* **227**, 1789--1816 (2019). + doi:\ `10.1140/epjst/e2019-800186-9 `_. + diff --git a/doc4.2.2/_sources/io.rst.txt b/doc4.2.2/_sources/io.rst.txt new file mode 100644 index 0000000000..a05fc2c780 --- /dev/null +++ b/doc4.2.2/_sources/io.rst.txt @@ -0,0 +1,545 @@ +.. _Input and Output: + +Input and Output +================ + +.. _No generic checkpointing: + +Checkpointing and restoring a simulation +---------------------------------------- + +One of the most asked-for feature that seems to be missing is +*checkpointing*, a simple way to store and restore the current +state of the simulation, and to be able to write this state to or read +it from a file. This would be most useful to be able to restart a +simulation from a specific point in time. + +Unfortunately, it is impossible to provide a simple command +(``checkpoint``), out of two reasons. The main reason is that it has no +way to determine what information constitutes the actual state of the +simulation. Scripts sometimes use variables that +contain essential information about a simulation: the stored values of +an observable that was computed in previous time steps, counters, etc. +These would have to be contained in a checkpoint. However, not all +variables are of interest. + +Another problem with a generic checkpoint would be the control flow of +the script. In principle, the checkpoint would have to store where in +the script the checkpointing function was called to be able to return +there. All this is even further complicated by the fact that |es| is +running in parallel. + +Having said that, |es| does provide functionality which aims to store the state of the simulation engine. +In addition, variables declared in the simulation script can be added to the checkpoint. +The checkpoint data can then later be restored by calling one +load function that will automatically process the checkpoint data by +setting the user variables and restore the components of the simulation. +Furthermore, the checkpointing can be triggered by system signals that +are invoked for example when the simulation is aborted by the user or by +a timeout. + +The checkpointing functionality is difficult to test for all possible simulation setups. Therefore, it is to be used with care. +It is strongly recommended to keep track of the times in the simulation run where a checkpoint was written and restored and manually verify that the observables of interest do not jump or drift after restoring the checkpoint. +Moreover, please carefully read the limitations mentioned below. + +Checkpointing is implemented by the :class:`espressomd.checkpointing.Checkpoint` class. It is instanced as follows:: + + import espressomd + import espressomd.checkpointing + checkpoint = espressomd.checkpointing.Checkpoint(checkpoint_id="mycheckpoint", checkpoint_path=".") + +Here, ``checkpoint_id`` denotes the identifier for a checkpoint. Legal characters for an id +are "0-9", "a-zA-Z", "-", "_". +The parameter ``checkpoint_path``, specifies the relative or absolute path where the checkpoints are +stored. The current working directory is assumed, when this parameter is skipped. + +After the simulation system and user variables are set up, they can be +registered for checkpointing. +Name the string of the object or user variable that should be registered for +checkpointing. + +To give an example:: + + my_var = "some variable value" + system = espressomd.System(box_l=[100.0, 100.0, 100.0]) + # ... set system properties like time_step here ... + checkpoint.register("system") + checkpoint.register("my_var") + # ... + +will register the user variable ``my_var`` and the instance of the simulation system. The checkpoint can be saved via:: + + + checkpoint.save() + +To trigger the checkpoint when Ctrl+C is pressed during a running simulation, the corresponding signal has to be registered:: + + + import signal + # signal.SIGINT: signal 2, is sent when ctrl+c is pressed + checkpoint.register_signal(signal.SIGINT) + +In the above example checkpointing is triggered, when the user interrupts by +pressing Ctrl+C. In this case a new checkpoint is written and the simulation +quits. + +An existing checkpoint can be loaded with:: + + import espressomd + import espressomd.checkpointing + import signal + + checkpoint = espressomd.checkpointing.Checkpoint(checkpoint_id="mycheckpoint") + checkpoint.load() + +This will restore the state of the objects registered for checkpointing. +The checkpointing instance itself will also be restored. I.e., the same +variables will be registered for the next checkpoint and the same system +signals will be caught as in the initial setup of the checkpointing. + +Be aware of the following limitations: + +* Checkpointing makes use of the ``pickle`` python package. Objects will only + be restored as far as they support pickling. This is the case for Python's + basic data types, ``numpy`` arrays and many other objects. Still, pickling + support cannot be taken for granted. + +* Pickling of the :class:`espressomd.system.System` instance and + contained objects such as bonded and non-bonded interactions and + electrostatics methods is covered by basic tests. However, not all + combinations of algorithms can be tested. If you encounter an issue + for a specific combination of features, please share your findings + with the |es| community. + +* The active actors, i.e., the content of ``system.actors``, are checkpointed. + For lattice-Boltzmann fluids, this only includes the parameters such as the + lattice constant (``agrid``). The actual flow field has to be saved + separately with the lattice-Boltzmann specific methods + :meth:`espressomd.lb.HydrodynamicInteraction.save_checkpoint` + and loaded via :meth:`espressomd.lb.HydrodynamicInteraction.load_checkpoint` + after restoring the checkpoint. See :ref:`LB checkpointing ` + for more details. + +* References between Python objects are not maintained during checkpointing. + For example, if an instance of a shape and an instance of a constraint + containing the shape are checkpointed, these two objects are equal before + checkpointing but independent copies which have the same parameters after + restoring the checkpoint. Changing one will no longer affect the other. + +* The state of the cell system as well as the MPI node grid are checkpointed. + Therefore, checkpoints can only be loaded, when the script runs on the same + number of MPI ranks. + +* Checkpoints are not compatible between different |es| versions. + +* Checkpoints may depend on the presence of other Python modules at specific + versions. It may therefore not be possible to load a checkpoint in a + different environment than where it was written. + +* To be fully deterministic when loading from a checkpoint with an active + thermostat, the first step of the integration should be called with the flag + ``reuse_forces=True``, e.g. ``system.integrator.run(2, reuse_forces=True)``. + This is because loading a checkpoint reinitializes the system and enforces + a recalculation of the forces. However, this computes the forces from the + velocities at the current time step and not at the previous half time step. + Please note that long-range actors can make trajectories non-reproducible. + For example, lattice-Boltzmann introduces errors of the order of 1e-15 with + binary checkpoint files, or 1e-7 with ASCII checkpoint files. In addition, + several electrostatic and magnetostatic actors automatically introduce + a deviation of the order of 1e-7, either due to floating-point rounding + errors (:class:`~espressomd.electrostatics.P3MGPU`), or due to re-tuning + using the most recent system state (:class:`~espressomd.electrostatics.MMM1D`, + :class:`~espressomd.electrostatics.MMM1DGPU`). + When in doubt, you can easily verify the absence of a "force jump" when + loading from a checkpoint by replacing the electrostatics actor with your + combination of features in files :file:`samples/save_checkpoint.py` and + :file:`samples/load_checkpoint.py` and running them sequentially. + +For additional methods of the checkpointing class, see +:class:`espressomd.checkpointing.Checkpoint`. + +.. _Writing H5MD-files: + +Writing H5MD-files +------------------ + +.. note:: + + Requires ``H5MD`` external feature, enabled with ``-DWITH_HDF5=ON``. Also + requires a parallel version of HDF5. On Ubuntu, this can be installed via + either ``libhdf5-openmpi-dev`` for OpenMPI or ``libhdf5-mpich-dev`` for + MPICH, but not ``libhdf5-dev`` which is the serial version. + +For long simulations, it's a good idea to store data in the hdf5 file format +(see https://www.hdfgroup.org for details, H5MD is based on hdf5). +Currently |es| supports some basic functions for writing simulation +data to H5MD files. The implementation is MPI-parallelized and is capable +of dealing with a varying number of particles. + +To write data in a hdf5-file according to the H5MD proposal +(https://nongnu.org/h5md), first an object of the class +:class:`espressomd.io.writer.h5md.H5md` has to be created and linked to the +respective hdf5-file. This may, for example, look like: + +.. code-block:: python + + import espressomd.io.writer.h5md + system = espressomd.System(box_l=[100.0, 100.0, 100.0]) + # ... add particles here + h5 = espressomd.io.writer.h5md.H5md(file_path="trajectory.h5") + +An optional argument to the constructor of :class:`espressomd.io.writer.h5md.H5md` is +an instance of :class:`espressomd.io.writer.h5md.UnitSystem` which encapsulates +physical units for time, mass, length and electrical charge. + +If a file at the given filepath exists and has a valid H5MD structure, +it will be backed up to a file with suffix ".bak" and loaded into +a new file. Therefore H5MD can be used together with checkpointing. +The backup file will be deleted when the new file is closed at the end of the +simulation with :meth:`~espressomd.io.writer.h5md.H5md.close()`. The backup +file is not be erased if the simulation terminates unexpectedly. + +To write data to the HDF5 file, simply call the method +:meth:`~espressomd.io.writer.h5md.H5md.write` without any arguments. +After the last write, call :meth:`~espressomd.io.writer.h5md.H5md.flush()` +and then :meth:`~espressomd.io.writer.h5md.H5md.close()` +to close the datasets and remove the backup file. + +The current implementation writes the following properties by default: folded +positions, periodic image count, velocities, forces, species (|es| types), +charges and masses of the particles. While folded positions are written +to disk, the unfolded coordinates can be reconstructed from the image count. +The time-dependent box size and Lees-Edwards parameters are also stored. +Some of these properties can be opted out by specifying in argument +``fields`` the subset of fields to write to the trajectory file; +call method :meth:`~espressomd.io.writer.h5md.H5md.valid_fields()` +to find out which string corresponds to which field. + +In simulations with a varying number of particles (Monte-Carlo reactions), the +size of the dataset will be adapted if the maximum number of particles +increases but will not be decreased. Instead a negative fill value will +be written to the trajectory for the id. + +If you have a parallel +simulation, please keep in mind that the sequence of particles in general +changes from timestep to timestep. Therefore you have to always use the +dataset for the ids to track which position/velocity/force/type/mass +entry belongs to which particle. + +For an example involving physical units, see :file:`/samples/h5md.py`. + +.. _Reading H5MD-files: + +Reading H5MD-files +------------------ + +H5MD files can be read and sometimes modified by many tools. If the data was +stored with `physical units `__, +they can be accessed by reading the group attributes. Since the data is +written in parallel, the particles are unsorted; if particles were created +with increasing particle id and no particle deletion occurred during the +simulation, the coordinates can be sorted with a simply numpy operation. + +To read with the python module ``h5py`` (documentation: +`HDF5 for Python `__):: + + import h5py + with h5py.File("sample.h5", mode='r') as h5file: + positions = h5file['particles/atoms/position/value'] + positions.attrs['unit'] + forces = h5file['particles/atoms/force/value'] + forces_unit = forces.attrs['unit'] + sim_time = h5file['particles/atoms/id/time'] + print(f"last frame: {sim_time[-2]:.3f} {sim_time.attrs['unit'].decode('utf8')}") + +To read with the python module ``pandas`` (documentation: `HDFStore: PyTables +`_):: + + import pandas + with pandas.HDFStore("sample.h5", mode='r') as h5file: + positions = h5file.root.particles.atoms.position.value + positions.attrs['unit'] + forces = h5file.root.particles.atoms.force.value + forces_unit = forces.attrs['unit'] + sim_time = h5file.root.particles.atoms.id.time + print(f"last frame: {sim_time[-2]:.3f} {sim_time.attrs['unit'].decode('utf8')}") + +To read from the command line with +`h5dump `__ +(Ubuntu package ``hdf5-tools``): + +.. code-block:: sh + + # show metadata only + h5dump --header sample.h5 | less + # show metadata + data + h5dump sample.h5 | less + +H5MD files can also be inspected with the GUI tool +`HDFView `__ (Ubuntu package +``hdfview``) or visually with the H5MD VMD plugin (GitHub project +`h5md/VMD-h5mdplugin `__). + +For an example involving ``h5py``, coordinates resorting and reconstruction +of the unfolded coordinates, see :file:`/samples/h5md_trajectory.py`. + +.. _Writing MPI-IO binary files: + +Writing MPI-IO binary files +--------------------------- + +This method outputs binary data in parallel and is, thus, also suitable for +large-scale simulations. Generally, H5MD is the preferred method because the +data is easily accessible. In contrast to H5MD, the MPI-IO functionality +outputs data in a *machine-dependent format*, but has write and read +capabilities. The usage is quite simple: + +.. code-block:: python + + import espressomd + import espressomd.io + system = espressomd.System(box_l=[1, 1, 1]) + # ... add particles here + mpiio = espressomd.io.mpiio.Mpiio() + mpiio.write("/tmp/mydata", positions=True, velocities=True, types=True, bonds=True) + +Here, :file:`/tmp/mydata` is the prefix used to generate several files. +The call will output particle positions, velocities, types and their bonds +to the following files in folder :file:`/tmp`: + +- :file:`mydata.head` +- :file:`mydata.id` +- :file:`mydata.pos` +- :file:`mydata.pref` +- :file:`mydata.type` +- :file:`mydata.vel` +- :file:`mydata.boff` +- :file:`mydata.bond` + +Depending on the chosen output, not all of these files might be created. +To read these in again, simply call :meth:`espressomd.io.mpiio.Mpiio.read`. +It has the same signature as :meth:`espressomd.io.mpiio.Mpiio.write`. +When writing files, make sure the prefix hasn't been used before +(e.g. by a different simulation script), otherwise the write operation +will fail to avoid accidentally overwriting pre-existing data. Likewise, +reading incomplete data (or complete data but with the wrong number of MPI +ranks) will throw an error. + +*WARNING*: Do not attempt to read these binary files on a machine +with a different architecture! This will read malformed data without +necessarily throwing an error. + +In case of read failure or write failure, the simulation will halt. +On 1 MPI rank, the simulation will halt with a python runtime error. +This exception can be recovered from; in case of a write operation, +any written file must be deleted before attempting to write again +(since the prefix argument must be unique). On more than 1 MPI rank, +the simulation will halt with a call to ``MPI_Abort`` and will send +the ``SIGABRT`` signal. + +.. _Writing VTF files: + +Writing VTF files +----------------- + +The formats VTF (**V**\ TF **T**\ rajectory **F**\ ormat), VSF +(**V**\ TF **S**\ tructure **F**\ ormat) and VCF (**V**\ TF +**C**\ oordinate **F**\ ormat) are formats for the visualization +software VMD: :cite:`humphrey96a`. They are intended to +be human-readable and easy to produce automatically and modify. + +The format distinguishes between *structure blocks* that contain the +topological information of the system (the system size, particle names, +types, radii and bonding information, amongst others), while *coordinate +blocks* (a.k.a. as *timestep blocks*) contain the coordinates for the +particles at a single timestep. For a visualization with VMD, one +structure block and at least one coordinate block is required. + +Files in the VSF format contain a single structure block, files in the +VCF format contain at least one coordinate block, while files in the VTF +format contain a single structure block (usually as a header) and an arbitrary number of +coordinate blocks (time frames) afterwards, thus allowing to store all information for +a whole simulation in a single file. For more details on the format, +refer to the VTF homepage (https://github.com/olenz/vtfplugin/wiki). + +Creating files in these formats from within is supported by the commands :meth:`espressomd.io.writer.vtf.writevsf` +and :meth:`espressomd.io.writer.vtf.writevcf`, that write a structure and coordinate block (respectively) to the +given file. To create a standalone VTF file, first use ``writevsf`` at the beginning of +the simulation to write the particle definitions as a header, and then ``writevcf`` +to generate a timeframe of the simulation state. For example: + +A standalone VTF file can simply be + +.. code-block:: python + + import espressomd + import espressomd.io.writer.vtf + system = espressomd.System(box_l=[100.0, 100.0, 100.0]) + fp = open('trajectory.vtf', mode='w+t') + + # ... add particles here + + # write structure block as header + espressomd.io.writer.vtf.writevsf(system, fp) + # write initial positions as coordinate block + espressomd.io.writer.vtf.writevcf(system, fp) + + # integrate and write the frame + for n in num_steps: + system.integrator.run(100) + espressomd.io.writer.vtf.writevcf(system, fp) + fp.close() + +The structure definitions in the VTF/VSF formats are incremental, the user +can easily add further structure lines to the VTF/VSF file after a +structure block has been written to specify further particle properties +for visualization. + +Note that the ``ids`` of the particles in |es| and VMD may differ. VMD requires +the particle ids to be enumerated continuously without any holes, while +this is not required in |es|. When using ``writevsf`` +and ``writevcf``, the particle ids are +automatically translated into VMD particle ids. The function allows the +user to get the VMD particle id for a given |es| particle id. + +One can specify the coordinates of which particles should be written using ``types``. +If ``types='all'`` is used, all coordinates will be written (in the ordered timestep format). +Otherwise, has to be a list specifying the pids of the particles. + +Also note, that these formats can not be used to write trajectories +where the number of particles or their types varies between the +timesteps. This is a restriction of VMD itself, not of the format. + +.. _writevsf\: Writing the topology: + +``writevsf``: Writing the topology +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +:meth:`espressomd.io.writer.vtf.writevsf` + +Writes a structure block describing the system's structure to the given channel, for example: + +.. code-block:: python + + import espressomd + import espressomd.io.writer.vtf + system = espressomd.System(box_l=[100.0, 100.0, 100.0]) + # ... add particles here + fp = open('trajectory.vsf', mode='w+t') + espressomd.io.writer.vtf.writevsf(system, fp, types='all') + +The output of this command can be +used for a standalone VSF file, or at the beginning of a VTF file that +contains a trajectory of a whole simulation. + +.. _writevcf\: Writing the coordinates: + +``writevcf``: Writing the coordinates +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +:meth:`espressomd.io.writer.vtf.writevcf` + +Writes a coordinate (or timestep) block that contains all coordinates of +the system's particles. + +.. code-block:: python + + import espressomd + import espressomd.io.writer.vtf + system = espressomd.System(box_l=[100.0, 100.0, 100.0]) + # ... add particles here + fp = open('trajectory.vcf', mode='w+t') + espressomd.io.writer.vtf.writevcf(system, fp, types='all') + +.. _vtf_pid_map\: Going back and forth between ESPResSo and VTF indexing: + +``vtf_pid_map``: Going back and forth between |es| and VTF indexing +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +:meth:`espressomd.io.writer.vtf.vtf_pid_map` + +Generates a dictionary which maps |es| particle ``id`` to VTF indices. +This is motivated by the fact that the list of |es| particle ``id`` is allowed to contain *holes* but VMD +requires increasing and continuous indexing. The |es| ``id`` can be used as *key* to obtain the VTF index as the *value*, for example: + +.. code-block:: python + + import espressomd + import espressomd.io.writer.vtf + system = espressomd.System(box_l=[100.0, 100.0, 100.0]) + system.part.add(id=5, pos=[0, 0, 0]) + system.part.add(id=3, pos=[0, 0, 0]) + vtf_index = espressomd.io.writer.vtf.vtf_pid_map(system) + vtf_index[3] + +Note that the |es| particles are ordered in increasing order, thus ``id=3`` corresponds to the zeroth VTF index. + +.. _Writing various formats using MDAnalysis: + +Writing various formats using MDAnalysis +---------------------------------------- + +If the MDAnalysis package (https://mdanalysis.org) is installed, it +is possible to use it to convert frames to any of the supported +configuration/trajectory formats, including PDB, GROMACS, GROMOS, +CHARMM/NAMD, AMBER, LAMMPS, ... + +To use MDAnalysis to write in any of these formats, one has first to prepare a stream from +the |es| particle data using the class :class:`espressomd.MDA_ESP`, and then read from it +using MDAnalysis. A simple example is the following: + +.. code:: python + + import espressomd + import MDAnalysis as mda + import espressomd.MDA_ESP + system = espressomd.System(box_l=[100.0, 100.0, 100.0]) + # ... add particles here + eos = espressomd.MDA_ESP.Stream(system) # create the stream + u = mda.Universe(eos.topology, eos.trajectory) # create the MDA universe + + # example: write a single frame to PDB + u.atoms.write("system.pdb") + + # example: save the trajectory to GROMACS format + from MDAnalysis.coordinates.TRR import TRRWriter + W = TRRWriter("traj.trr", n_atoms=len(system.part)) # open the trajectory file + for i in range(100): + system.integrator.run(1) + u.load_new(eos.trajectory) # load the frame to the MDA universe + W.write_next_timestep(u.trajectory.ts) # append it to the trajectory + +For other examples, see :file:`/samples/MDAnalysisIntegration.py` + +.. _Reading various formats using MDAnalysis: + +Reading various formats using MDAnalysis +---------------------------------------- + +MDAnalysis can read various formats, including MD topologies and trajectories. +To read a PDB file containing a single frame:: + + import MDAnalysis + import numpy as np + import espressomd + import espressomd.interactions + + # parse protein structure + universe = MDAnalysis.Universe("protein.pdb") + # extract only the C-alpha atoms of chain A + chainA = universe.select_atoms("name CA and segid A") + # use the unit cell as box + box_l = np.ceil(universe.dimensions[0:3]) + # setup system + system = espressomd.System(box_l=box_l) + system.time_step = 0.001 + system.cell_system.skin = 0.4 + # configure sphere size sigma and create a harmonic bond + system.non_bonded_inter[0, 0].lennard_jones.set_params( + epsilon=1, sigma=1.5, cutoff=2, shift="auto") + system.bonded_inter[0] = espressomd.interactions.HarmonicBond(k=0.5, r_0=1.5) + # create particles and add bonds between them + system.part.add(pos=np.array(chainA.positions, dtype=float)) + for i in range(0, len(chainA) - 1): + system.part.by_id(i).add_bond((system.bonded_inter[0], i + 1)) + # visualize protein in 3D + import espressomd.visualization + visualizer = espressomd.visualization.openGLLive(system, bond_type_radius=[0.2]) + visualizer.run(0) diff --git a/doc4.2.2/_sources/lb.rst.txt b/doc4.2.2/_sources/lb.rst.txt new file mode 100644 index 0000000000..72e78d4797 --- /dev/null +++ b/doc4.2.2/_sources/lb.rst.txt @@ -0,0 +1,445 @@ +.. _Lattice-Boltzmann: + +Lattice-Boltzmann +================= + +For an implicit treatment of a solvent, |es| can couple the molecular +dynamics simulation to a lattice-Boltzmann fluid. The lattice-Boltzmann +method (LBM) is a fast, lattice-based method that, in its "pure" form, +allows to calculate fluid flow in different boundary conditions of +arbitrarily complex geometries. Coupled to molecular dynamics, +it allows for the computationally efficient inclusion of hydrodynamic +interactions into the simulation. The focus of the |es| implementation +of the LBM is, of course, the coupling to MD and therefore available +geometries and boundary conditions are somewhat limited in comparison to +"pure" LB codes. + +Here we restrict the documentation to the interface. For a more detailed +description of the method, please refer to the literature. + +.. note:: + + Please cite :cite:`arnold13a` (BibTeX key ``arnold13a`` in + :file:`doc/bibliography.bib`) if you use the LB fluid and :cite:`rohm12a` + (BibTeX key ``rohm12a`` in :file:`doc/bibliography.bib`) if you use + the GPU implementation. + +.. _Setting up a LB fluid: + +Setting up a LB fluid +--------------------- + +The following minimal example illustrates how to use the LBM in |es|:: + + import espressomd + import espressomd.lb + system = espressomd.System(box_l=[10, 20, 30]) + system.time_step = 0.01 + system.cell_system.skin = 0.4 + lb = espressomd.lb.LBFluid(agrid=1.0, dens=1.0, visc=1.0, tau=0.01) + system.actors.add(lb) + system.integrator.run(100) + +To use the GPU-accelerated variant, replace line 6 in the example above by:: + + lb = espressomd.lb.LBFluidGPU(agrid=1.0, dens=1.0, visc=1.0, tau=0.01) + +.. note:: Feature ``CUDA`` required for the GPU-accelerated variant + +To use the (much faster) GPU implementation of the LBM, use +:class:`~espressomd.lb.LBFluidGPU` in place of :class:`~espressomd.lb.LBFluid`. +Please note that the GPU implementation uses single precision floating point operations. +This decreases the accuracy of calculations compared to the CPU implementation. +In particular, due to rounding errors, the fluid density decreases over time, +when external forces, coupling to particles, or thermalization is used. +The loss of density is on the order of :math:`10^{-12}` per time step. + +The command initializes the fluid with a given set of parameters. It is +also possible to change parameters on the fly, but this will only rarely +be done in practice. Before being able to use the LBM, it is necessary +to set up a box of a desired size. The parameter is used to set the +lattice constant of the fluid, so the size of the box in every direction +must be a multiple of ``agrid``. + +In the following, we discuss the parameters that can be supplied to the LBM in |es|. +The detailed interface definition is available at :class:`~espressomd.lb.LBFluid`. + +The LB scheme and the MD scheme are not synchronized: In one LB time +step typically several MD steps are performed. This allows to speed up +the simulations and is adjusted with the parameter ``tau``, the LB time step. +The parameters ``dens`` and ``visc`` set up the density and (kinematic) viscosity of the +LB fluid in (usual) MD units. Internally the LB implementation works +with a different set of units: all lengths are expressed in ``agrid``, all times +in ``tau`` and so on. +LB nodes are located at 0.5, 1.5, 2.5, etc. +(in terms of ``agrid``). This has important implications for the location of +hydrodynamic boundaries which are generally considered to be halfway +between two nodes for flat, axis-aligned walls. For more complex boundary geometries, +the hydrodynamic boundary location deviates from this midpoint and the deviation +decays to first order in ``agrid``. The LBM should +*not be used as a black box*, but only after a careful check of all +parameters that were applied. + +In the following, we describe a number of optional parameters. +Thermalization of the fluid (and particle coupling later on) can be activated by +providing a non-zero value for the parameter ``kT``. Then, a seed has to be provided for +the fluid thermalization:: + + lbfluid = espressomd.lb.LBFluid(kT=1.0, seed=134, ...) + +The parameter ``ext_force_density`` takes a three dimensional vector as an +array_like of :obj:`float`, representing a homogeneous external body force density in MD +units to be applied to the fluid. The parameter ``bulk_visc`` allows one to +tune the bulk viscosity of the fluid and is given in MD units. In the limit of +low Mach number, the flow does not compress the fluid and the resulting flow +field is therefore independent of the bulk viscosity. It is however known that +the value of the viscosity does affect the quality of the implemented +link-bounce-back method. ``gamma_even`` and ``gamma_odd`` are the relaxation +parameters for the kinetic modes. These fluid parameters do not correspond to +any macroscopic fluid properties, but do influence numerical properties of the +algorithm, such as the magnitude of the error at boundaries. Unless you are an +expert, leave their defaults unchanged. If you do change them, note that they +are to be given in LB units. + +Before running a simulation at least the following parameters must be +set up: ``agrid``, ``tau``, ``visc``, ``dens``. For the other parameters, +the following are taken: ``bulk_visc=0``, ``gamma_odd=0``, ``gamma_even=0``, +``ext_force_density=[0, 0, 0]``. + +.. _Checkpointing LB: + +Checkpointing +------------- + +:: + + lb.save_checkpoint(path, binary) + lb.load_checkpoint(path, binary) + +The first command saves all of the LB fluid nodes' populations to an ASCII +(``binary=False``) or binary (``binary=True``) format respectively. +The second command loads the LB fluid nodes' populations. +In both cases ``path`` specifies the location of the +checkpoint file. This is useful for restarting a simulation either on the same +machine or a different machine. Some care should be taken when using the binary +format as the format of doubles can depend on both the computer being used as +well as the compiler. One thing that one needs to be aware of is that loading +the checkpoint also requires the user to reuse the old forces. This is +necessary since the coupling force between the particles and the fluid has +already been applied to the fluid. Failing to reuse the old forces breaks +momentum conservation, which is in general a problem. It is particularly +problematic for bulk simulations as the system as a whole acquires a drift of +the center of mass, causing errors in the calculation of velocities and +diffusion coefficients. The correct way to restart an LB simulation is to first +load in the particles with the correct forces, and use:: + + system.integrator.run(steps=number_of_steps, reuse_forces=True) + +upon the first call ``integrator.run``. This causes the +old forces to be reused and thus conserves momentum. + +.. _Interpolating velocities: + +Interpolating velocities +------------------------ + +To get interpolated velocity values between lattice nodes, the function:: + + lb.get_interpolated_velocity(pos=[1.1, 1.2, 1.3]) + +with a single position ``pos`` as an argument can be used. +For the GPU fluid :class:`espressomd.lb.LBFluidGPU`, a method +:py:meth:`~espressomd.lb.LBFluidGPU.get_interpolated_fluid_velocity_at_positions()` +is also available, which expects a numpy array of positions as an argument. + +By default, the interpolation is done linearly between the nearest 8 LB nodes, +but for the GPU implementation also a quadratic scheme involving 27 nodes is implemented +(see eqs. 297 and 301 in :cite:`dunweg09a`). +You can choose by calling +one of:: + + lb.set_interpolation_order('linear') + lb.set_interpolation_order('quadratic') + +A note on boundaries: +both interpolation schemes don't take into account the physical location of the boundaries +(e.g. in the middle between two nodes for a planar wall) but will use the boundary node slip velocity +at the node position. This means that every interpolation involving at least one +boundary node will introduce an error. + +.. _Coupling LB to a MD simulation: + +Coupling LB to a MD simulation +------------------------------ + +MD particles can be coupled to a LB fluid through frictional coupling. The friction force + +.. math:: F_{i,\text{frict}} = - \gamma (v_i(t)-u(x_i(t),t)) + +depends on the particle velocity :math:`v` and the fluid velocity :math:`u`. It acts both +on the particle and the fluid (in opposite direction). Because the fluid is also affected, +multiple particles can interact via hydrodynamic interactions. As friction in molecular systems is +accompanied by fluctuations, the particle-fluid coupling has to be activated through +the :ref:`LB thermostat` (see more detailed description there). A short example is:: + + system.thermostat.set_lb(LB_fluid=lbf, seed=123, gamma=1.5) + +where ``lbf`` is an instance of either :class:`~espressomd.lb.LBFluid` or +:class:`~espressomd.lb.LBFluidGPU`, ``gamma`` the friction coefficient and +``seed`` the seed for the random number generator involved +in the thermalization. + + +.. _Reading and setting properties of single lattice nodes: + +Reading and setting properties of single lattice nodes +------------------------------------------------------ + +Appending three indices to the ``lb`` object returns an object that represents +the selected LB grid node and allows one to access all of its properties:: + + lb[x, y, z].density # fluid density (one scalar for LB and CUDA) + lb[x, y, z].velocity # fluid velocity (a numpy array of three floats) + lb[x, y, z].pressure_tensor # fluid pressure tensor (a symmetric 3x3 numpy array of floats) + lb[x, y, z].pressure_tensor_neq # nonequilibrium part of the pressure tensor (as above) + lb[x, y, z].boundary # flag indicating whether the node is fluid or boundary (fluid: boundary=0, boundary: boundary != 0) + lb[x, y, z].population # 19 LB populations (a numpy array of 19 floats, check order from the source code) + +All of these properties can be read and used in further calculations. +Only the property ``population`` can be modified. The indices ``x, y, z`` +are integers and enumerate the LB nodes in the three Cartesian directions, +starting at 0. To modify ``boundary``, refer to :ref:`Setting up boundary conditions`. + +Example:: + + print(lb[0, 0, 0].velocity) + lb[0, 0, 0].density = 1.2 + +The first line prints the fluid velocity at node (0 0 0) to the screen. +The second line sets this fluid node's density to the value ``1.2``. + +The nodes can be read and modified using slices. Example:: + + print(lb[0:4:2, 0:2, 0].velocity) + lb[0:4:2, 0:2, 0].density = [[[1.1], [1.2]], [[1.3], [1.4]]] + +The first line prints an array of shape (2, 2, 1, 3) with the velocities +of nodes (0 0 0), (0 1 0), (2 0 0), (2 1 0). The second line updates +these nodes with densities ranging from 1.1 to 1.4. You can set either +a value that matches the length of the slice (which sets each node +individually), or a single value that will be copied to every node +(e.g. a scalar for density, or an array of length 3 for the velocity). + +.. _Output for visualization: + +Output for visualization +------------------------ + +|es| implements a number of commands to output fluid field data of the whole fluid into a file at once. :: + + lb.write_vtk_velocity(path) + lb.write_vtk_boundary(path) + lb.write_velocity(path) + lb.write_boundary(path) + +Currently supported fluid properties are the velocity, and boundary flag in ASCII VTK as well as Gnuplot compatible ASCII output. + +The VTK format is readable by visualization software such as ParaView [1]_ +or Mayavi2 [2]_. If you plan to use ParaView for visualization, note that also the particle +positions can be exported using the VTK format (see :meth:`~espressomd.particle_data.ParticleList.writevtk`). + +The variant + +:: + + lb.write_vtk_velocity(path, bb1, bb2) + +allows you to only output part of the flow field by specifying an axis aligned +bounding box through the coordinates ``bb1`` and ``bb1`` (lists of three ints) of two of its corners. This +bounding box can be used to output a slice of the flow field. As an +example, executing + +:: + + lb.write_vtk_velocity(path, [0, 0, 5], [10, 10, 5]) + +will output the cross-section of the velocity field in a plane +perpendicular to the :math:`z`-axis at :math:`z = 5` (assuming the box +size is 10 in the :math:`x`- and :math:`y`-direction). + + +.. _Choosing between the GPU and CPU implementations: + +Choosing between the GPU and CPU implementations +------------------------------------------------ + +|es| contains an implementation of the LBM for NVIDIA +GPUs using the CUDA framework. On CUDA-supporting machines this can be +activated by compiling with the feature ``CUDA``. Within the +Python script, the :class:`~espressomd.lb.LBFluid` object can be substituted +with the :class:`~espressomd.lb.LBFluidGPU` object to switch from CPU based +to GPU based execution. For further +information on CUDA support see section :ref:`CUDA acceleration`. + +The following minimal example demonstrates how to use the GPU implementation +of the LBM in analogy to the example for the CPU given in section +:ref:`Setting up a LB fluid`:: + + import espressomd + system = espressomd.System(box_l=[10, 20, 30]) + system.time_step = 0.01 + system.cell_system.skin = 0.4 + lb = espressomd.lb.LBFluidGPU(agrid=1.0, dens=1.0, visc=1.0, tau=0.01) + system.actors.add(lb) + system.integrator.run(100) + +For boundary conditions analogous to the CPU +implementation, the feature ``LB_BOUNDARIES_GPU`` has to be activated. +:ref:`Lees-Edwards boundary conditions` are not supported by either +LB implementation. + +.. _Electrohydrodynamics: + +Electrohydrodynamics +-------------------- + +.. note:: + This needs the feature ``LB_ELECTROHYDRODYNAMICS``. + +If the feature is activated, the lattice-Boltzmann code can be +used to implicitly model surrounding salt ions in an external electric +field by having the charged particles create flow. + +For that to work, you need to set the electrophoretic mobility +(multiplied by the external :math:`E`-field) :math:`\mu E` on the +particles that should be subject to the field. This effectively acts +as a velocity offset between the particle and the LB fluid. + +For more information on this method and how it works, read the +publication :cite:`hickey10a`. + + +.. _Using shapes as lattice-Boltzmann boundary: + +Using shapes as lattice-Boltzmann boundary +------------------------------------------ + +.. note:: + Feature ``LB_BOUNDARIES`` required + +Lattice-Boltzmann boundaries are implemented in the module +:mod:`espressomd.lbboundaries`. You might want to take a look +at the classes :class:`~espressomd.lbboundaries.LBBoundary` +and :class:`~espressomd.lbboundaries.LBBoundaries` for more information. + +Adding a shape-based boundary is straightforward:: + + lbb = espressomd.lbboundaries.LBBoundary(shape=my_shape, velocity=[0, 0, 0]) + system.lbboundaries.add(lbb) + +or:: + + lbb = espressomd.lbboundaries.LBBoundary() + lbb.shape = my_shape + lbb.velocity = [0, 0, 0] + system.lbboundaries.add(lbb) + +.. _Minimal usage example: + +Minimal usage example +~~~~~~~~~~~~~~~~~~~~~ + +.. note:: Feature ``LB_BOUNDARIES`` or ``LB_BOUNDARIES_GPU`` required + +In order to add a wall as boundary for a lattice-Boltzmann fluid +you could do the following:: + + wall = espressomd.shapes.Wall(dist=5, normal=[1, 0, 0]) + lbb = espressomd.lbboundaries.LBBoundary(shape=wall, velocity=[0, 0, 0]) + system.lbboundaries.add(lbb) + +.. _Setting up boundary conditions: + +Setting up boundary conditions +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The following example sets up a system consisting of a spherical boundary +in the center of the simulation box acting as a no-slip boundary for the +LB fluid that is driven by 4 walls with a slip velocity:: + + import espressomd + import espressomd.lb + import espressomd.lbboundaries + import espressomd.shapes + + system = espressomd.System(box_l=[64, 64, 64]) + system.time_step = 0.01 + system.cell_system.skin = 0.4 + + lb = espressomd.lb.LBFluid(agrid=1.0, dens=1.0, visc=1.0, tau=0.01) + system.actors.add(lb) + + v = [0, 0, 0.01] # the boundary slip + walls = [None] * 4 + + wall_shape = espressomd.shapes.Wall(normal=[1, 0, 0], dist=1) + walls[0] = espressomd.lbboundaries.LBBoundary(shape=wall_shape, velocity=v) + + wall_shape = espressomd.shapes.Wall(normal=[-1, 0, 0], dist=-63) + walls[1] = espressomd.lbboundaries.LBBoundary(shape=wall_shape, velocity=v) + + wall_shape = espressomd.shapes.Wall(normal=[0, 1, 0], dist=1) + walls[2] = espressomd.lbboundaries.LBBoundary(shape=wall_shape, velocity=v) + + wall_shape = espressomd.shapes.Wall(normal=[0, -1, 0], dist=-63) + walls[3] = espressomd.lbboundaries.LBBoundary(shape=wall_shape, velocity=v) + + for wall in walls: + system.lbboundaries.add(wall) + + sphere_shape = espressomd.shapes.Sphere(radius=5.5, center=[33, 33, 33], direction=1) + sphere = espressomd.lbboundaries.LBBoundary(shape=sphere_shape) + system.lbboundaries.add(sphere) + + system.integrator.run(4000) + + print(sphere.get_force()) + +After integrating the system for a sufficient time to reach the steady state, +the hydrodynamic drag force exerted on the sphere is evaluated. + +The LB boundaries use the same :mod:`~espressomd.shapes` objects to specify +their geometry as :mod:`~espressomd.constraints` do for particles. +This allows the user to quickly set up a system with boundary conditions +that simultaneously act on the fluid and particles. For a complete +description of all available shapes, refer to :mod:`espressomd.shapes`. + +Intersecting boundaries are in principle possible but must be treated +with care. In the current implementation, all nodes that are +within at least one boundary are treated as boundary nodes. + +Currently, only the so-called "link-bounce-back" algorithm for wall +nodes is available. This creates a boundary that is located +approximately midway between the lattice nodes, so in the above example ``wall[0]`` +corresponds to a boundary at :math:`x=1.5`. Note that the +location of the boundary is unfortunately not entirely independent of +the viscosity. This can be seen when using the sample script with a high +viscosity. + +The bounce back boundary conditions permit it to set the velocity at the boundary +to a non-zero value via the ``v`` property of an ``LBBoundary`` object. +This allows to create shear flow and boundaries +moving relative to each other. The velocity boundary conditions are +implemented according to :cite:`succi01a` eq. 12.58. Using +this implementation as a blueprint for the boundary treatment, an +implementation of the Ladd-Coupling should be relatively +straightforward. The ``LBBoundary`` object furthermore possesses +a property ``force``, which keeps track of the hydrodynamic drag +force exerted onto the boundary by the moving fluid. + + +.. [1] + https://www.paraview.org/ + +.. [2] + http://code.enthought.com/projects/mayavi/ diff --git a/doc4.2.2/_sources/magnetostatics.rst.txt b/doc4.2.2/_sources/magnetostatics.rst.txt new file mode 100644 index 0000000000..3afc02ba3d --- /dev/null +++ b/doc4.2.2/_sources/magnetostatics.rst.txt @@ -0,0 +1,212 @@ +.. _Magnetostatics: + +Magnetostatics +============== + +.. _Dipolar interaction: + +Dipolar interaction +------------------- + +|es| contains methods to calculate the interactions between point dipoles + +.. math:: + + U^{Dip}(\vec{r}) = D \cdot \left( \frac{(\vec{\mu}_i \cdot \vec{\mu}_j)}{r^3} + - \frac{3 (\vec{\mu}_i \cdot \vec{r}) (\vec{\mu}_j \cdot \vec{r}) }{r^5} \right) + +where :math:`r=|\vec{r}|`. +The prefactor :math:`D` is can be set by the user and is given by + +.. math:: + D =\frac{\mu_0 \mu}{4\pi} + :label: dipolar_prefactor + +where :math:`\mu_0` and :math:`\mu` are the vacuum permittivity and the +relative permittivity of the background material, respectively. + +Magnetostatic interactions are activated via the actor framework:: + + import espressomd + import espressomd.magnetostatics + + system = espressomd.System(box_l=[10, 10, 10]) + system.time_step = 0.01 + system.part.add(pos=[[0, 0, 0], [1, 1, 1]], + rotation=2 * [(1, 1, 1)], dip=2 * [(1, 0, 0)]) + + actor = espressomd.magnetostatics.DipolarDirectSumCpu(prefactor=1.) + system.actors.add(actor) + +The list of actors can be cleared with +:meth:`system.actors.clear() ` and +:meth:`system.actors.remove(actor) `. + + +.. _Dipolar P3M: + +Dipolar P3M +~~~~~~~~~~~ + +:class:`espressomd.magnetostatics.DipolarP3M` + +This is the dipolar version of the P3M algorithm, described in :cite:`cerda08d`. + +Make sure that you know the relevance of the P3M parameters before using +P3M! If you are not sure, read the following references: +:cite:`ewald21a,hockney88a,kolafa92a,deserno98a,deserno98b,deserno00e,deserno00b,cerda08d`. + +Note that dipolar P3M does not work with non-cubic boxes. + + +The parameters of the dipolar P3M method can be tuned automatically, by +providing ``accuracy=`` to the method. It is also possible to +pass a subset of the method parameters such as ``mesh``. In that case, only +the omitted parameters are tuned:: + + import espressomd.magnetostatics as magnetostatics + p3m = magnetostatics.DipolarP3M(prefactor=1, mesh=32, accuracy=1E-4) + system.actors.add(p3m) + +It is important to note that the error estimates given in :cite:`cerda08d` +used in the tuning contain assumptions about the system. In particular, a +homogeneous system is assumed. If this is no longer the case during the +simulation, actual force and torque errors can be significantly larger. + + +.. _Dipolar Layer Correction (DLC): + +Dipolar Layer Correction (DLC) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +:class:`espressomd.magnetostatics.DLC` + +The dipolar layer correction (DLC) is used in conjunction with the dipolar P3M +method to calculate dipolar interactions in a 2D-periodic system. +It is based on :cite:`brodka04a` and the dipolar version of +:ref:`Electrostatic Layer Correction (ELC)`. + +Usage notes: + +* The non-periodic direction is always the **z-direction**. + +* The method relies on a slab of the simulation box perpendicular to the + z-direction not to contain particles. The size in z-direction of this slab + is controlled by the ``gap_size`` parameter. The user has to ensure that + no particles enter this region by means of constraints or by fixing the + particles' z-coordinate. When particles enter the slab of the specified + size, an error will be thrown. + +* The method can be tuned using the ``accuracy`` parameter. In contrast to + the electrostatic method, it refers to the energy. Furthermore, it is + assumed that all dipole moment are as large as the largest of the dipoles + in the system. + +* When the base solver is not a P3M method, metallic epsilon is assumed. + +The method is used as follows:: + + import espressomd.magnetostatics + dp3m = espressomd.magnetostatics.DipolarP3M(prefactor=1, accuracy=1E-4) + mdlc = espressomd.magnetostatics.DLC(actor=dp3m, maxPWerror=1E-5, gap_size=2.) + system.actors.add(mdlc) + + +.. _Dipolar direct sum: + +Dipolar direct sum +------------------ + +This interaction calculates energies and forces between dipoles by +explicitly summing over all pairs. For the directions in which the +system is periodic (as defined by ``system.periodicity``), it applies the +minimum image convention, i.e. the interaction is effectively cut off at +half a box length. + +The direct summation methods are mainly intended for non-periodic systems which cannot be solved using the dipolar P3M method. +Due to the long-range nature of dipolar interactions, Direct summation with minimum image convention does not yield good accuracy with periodic systems. + + +Two methods are available: + +* :class:`~espressomd.magnetostatics.DipolarDirectSumCpu` + performs the calculation in double precision on the Cpu. + +* :class:`~espressomd.magnetostatics.DipolarDirectSumGpu` + performs the calculations in single precision on a Cuda-capable graphics card. + The implementation is optimized for large systems of several thousand + particles. It makes use of one thread per particle. When there are fewer + particles than the number of threads the gpu can execute simultaneously, + the rest of the gpu remains idle. Hence, the method will perform poorly + for small systems. + +To use the methods, create an instance of either +:class:`~espressomd.magnetostatics.DipolarDirectSumCpu` or +:class:`~espressomd.magnetostatics.DipolarDirectSumGpu` and add it to the +system's list of active actors. The only required parameter is the Prefactor +:eq:`dipolar_prefactor`:: + + import espressomd.magnetostatics + dds = espressomd.magnetostatics.DipolarDirectSumGpu(prefactor=1) + system.actors.add(dds) + +For testing purposes, a variant of the dipolar direct sum is available which +adds periodic copies to the system in periodic directions: +:class:`~espressomd.magnetostatics.DipolarDirectSumWithReplicaCpu`. +As it is very slow, this method is not intended to do simulations, but +rather to check the results you get from more efficient methods like P3M. + +:class:`~espressomd.magnetostatics.DipolarDirectSumCpu` and +:class:`~espressomd.magnetostatics.DipolarDirectSumWithReplicaCpu` +do not support MPI parallelization. + + +.. _Barnes-Hut octree sum on GPU: + +Barnes-Hut octree sum on GPU +---------------------------- + +:class:`espressomd.magnetostatics.DipolarBarnesHutGpu` + +This interaction calculates energies and forces between dipoles by +summing over the spatial octree cells (aka ``leaves``). +Far enough cells are considered as a single dipole with a cumulative +vector in the cell center of mass. Parameters which determine that the +cell is far enough are :math:`I_{\mathrm{tol}}^2` and +:math:`\varepsilon^2` which define a fraction of the cell and +an additive distance respectively. For the detailed description of the +Barnes-Hut method application to the dipole-dipole interactions, please +refer to :cite:`polyakov13a`. + +To use the method, create an instance of :class:`~espressomd.magnetostatics.DipolarBarnesHutGpu` +and add it to the system's list of active actors:: + + import espressomd.magnetostatics + bh = espressomd.magnetostatics.DipolarBarnesHutGpu(prefactor=1., epssq=200.0, itolsq=8.0) + system.actors.add(bh) + + +.. _ScaFaCoS magnetostatics: + +ScaFaCoS magnetostatics +----------------------- + +:class:`espressomd.magnetostatics.Scafacos` + +|es| can use the methods from the ScaFaCoS *Scalable fast Coulomb solvers* +library for dipoles, if the methods support dipolar calculations. The feature +``SCAFACOS_DIPOLES`` has to be added to :file:`myconfig.hpp` to activate this +feature. Dipolar calculations are only included in the ``dipoles`` branch of +the ScaFaCoS code. The specific methods available can be queried with +:meth:`espressomd.electrostatics.Scafacos.get_available_methods`. + +To use ScaFaCoS, create an instance of :class:`~espressomd.magnetostatics.Scafacos` +and add it to the list of active actors. Three parameters have to be specified: +``prefactor``, ``method_name``, ``method_params``. The method-specific +parameters are described in the ScaFaCoS manual. In addition, methods +supporting tuning have a parameter ``tolerance_field`` which sets the desired +root mean square accuracy for the magnetic field. + +For details of the various methods and their parameters please refer to +the ScaFaCoS manual. To use this feature, ScaFaCoS has to be built as a +shared library. diff --git a/doc4.2.2/_sources/modules.rst.txt b/doc4.2.2/_sources/modules.rst.txt new file mode 100644 index 0000000000..9d3ea35dc3 --- /dev/null +++ b/doc4.2.2/_sources/modules.rst.txt @@ -0,0 +1,7 @@ +espressomd +========== + +.. toctree:: + :maxdepth: 4 + + espressomd diff --git a/doc4.2.2/_sources/particles.rst.txt b/doc4.2.2/_sources/particles.rst.txt new file mode 100644 index 0000000000..527e03454b --- /dev/null +++ b/doc4.2.2/_sources/particles.rst.txt @@ -0,0 +1,689 @@ +.. _Setting up particles: + +Setting up particles +==================== + +.. _Overview of the relevant Python classes: + +Overview of the relevant Python classes +--------------------------------------- +For understanding this chapter, it is helpful to be aware of the Python classes provided by |es| to interact with particles: + +* :class:`~espressomd.particle_data.ParticleHandle` provides access to a single particle in the simulation. +* :class:`~espressomd.particle_data.ParticleList` provides access to all particles in the simulation +* :class:`~espressomd.particle_data.ParticleSlice` provides access to a subset of particles in the simulation identified by a list of ids or an instance of :class:`slice` or :class:`range`. + +In almost no case have these classes to be instantiated explicitly by the user. +Rather, access is provided via the system :attr:`~espressomd.system.System.part` attribute. +The details are explained in the following sections. + +.. _Adding particles: + +Adding particles +---------------- +In order to add particles to the system, call +:meth:`ParticleList.add() `:: + + import espressomd + system = espressomd.System(box_l=[10., 10., 10.]) + p = system.part.add(pos=[1., 1., 1.], type=0) + +This command adds a single particle to the system with properties given +as arguments, and it returns an instance of +:class:`~espressomd.particle_data.ParticleHandle`, which will be used to access +properties of the newly created particle. The ``pos`` property is required, all +other properties are optional. +All available particle properties are members of :class:`~espressomd.particle_data.ParticleHandle`. + +Note that the instances of :class:`~espressomd.particle_data.ParticleHandle` returned by +:meth:`ParticleList.add() ` are handles for the live particles in the +simulation, rather than offline copies. Changing their properties will affect the simulation. + +It is also possible to add several particles at once:: + + import numpy as np + new_parts = system.part.add(pos=np.random.random((10, 3)) * box_length) + +If several particles are added at once, an instance of +:class:`~espressomd.particle_data.ParticleSlice` is returned. + +Particles are identified via their ``id`` property. A unique id is given to them +automatically. Alternatively, you can assign an id manually when adding them to the system:: + + system.part.add(pos=[1., 2., 3.], id=system.part.highest_particle_id + 1) + +The id provides an alternative way to access particles in the system. To +retrieve the handle of the particle with id ``5``, call:: + + p = system.part.by_id(5) + +.. _Accessing particle properties: + +Accessing particle properties +----------------------------- + +Particle properties can be accessed like any class member. + +For example, to print the particle's current position, call:: + + print(p.pos) + +.. _Modifying particle properties: + +Modifying particle properties +----------------------------- + +Similarly, the position can be set:: + + p.pos = [1., 2.5, 3.] + +Not all properties are writeable. For example, properties that are +automatically derived from other properties are read-only attributes. + +Please note that changing a particle property will not affect the ghost +particles until after the next integration loop. This can be an issue for +certain methods like :meth:`espressomd.system.System.distance` which use +the old ghost information, while other methods like particle-based analysis +tools and :meth:`espressomd.cell_system.CellSystem.get_neighbors` update the +ghost information before calculating the observable. + +.. _Vectorial properties: + +Vectorial properties +~~~~~~~~~~~~~~~~~~~~ + +For vectorial particle properties, component-wise manipulation like +``p.pos[0] = 1`` or in-place operators like ``+=`` or ``*=`` +are not allowed and raise an exception. +This behavior is inherited, so the same applies to ``pos`` after +``pos = p.pos``. If you want to use a vectorial property for further +calculations, you should explicitly make a copy e.g. via +``pos = numpy.copy(p.pos)``. + +.. _Deleting particles: + +Deleting particles +------------------ + +Particles can be easily deleted in Python using particle ids or ranges of particle ids. +For example, to delete all particles of type 1, run:: + + system.part.select(type=1).remove() + +To delete all particles, use:: + + system.part.clear() + +.. _Iterating over particles and pairs of particles: + +Iterating over particles and pairs of particles +----------------------------------------------- +You can iterate over all particles or over a subset of particles +(see :ref:`Interacting with groups of particles`) as follows:: + + for p in system.part: + print(p.pos) + + for p in system.part.select(type=1): + print(p.pos) + +You can iterate over all pairs of particles using:: + + for pair in system.part.pairs(): + print(pair[0].id, pair[1].id) + + +.. _Exclusions: + +Exclusions +---------- + +Particles can have an exclusion list of all other particles where non-bonded interactions are ignored. +This is typically used in atomistic simulations, +where nearest and next nearest neighbor interactions along a chain of bonded +particles have to be omitted since they are included in the bonding potentials. +Exclusions do not apply to the short range part of electrostatics and magnetostatics methods, e.g. to P3M. + +To create exclusions for particles pairs 0 and 1:: + + system.part.by_id(0).add_exclusion(1) + +To delete the exclusion:: + + system.part.by_id(0).delete_exclusion(1) + +The current list of exclusions is accessible in the +:attr:`~espressomd.particle_data.ParticleHandle.exclusions` property. + + +.. _Rotational degrees of freedom and particle anisotropy: + +Rotational degrees of freedom and particle anisotropy +----------------------------------------------------- + +When the feature ``ROTATION`` is compiled in, particles not only have a position, +but also an orientation that changes with an angular velocity. +A torque on a particle leads to a change in angular velocity depending on the +particles rotational inertia. +The property :attr:`~espressomd.particle_data.ParticleHandle.rinertia` has to +be specified as the three eigenvalues of the particles rotational inertia tensor. +Even if the particle rotational inertia is isotropic, the rotation state can be +important if, e.g., the particle carries a dipole or is an active particle. + +The rotational degrees of freedom are integrated using a velocity Verlet scheme. +The implementation is based on a quaternion representation of the particle +orientation and described in :cite:`omelyan98a` with quaternion components +indexing made according to the formalism +:math:`q = a + b\mathbf{i} + c\mathbf{j} + d\mathbf{k}` :cite:`allen17a`. + +When the Langevin thermostat is enabled, the rotational degrees of freedom are also thermalized. + +Whether or not rotational degrees of freedom are propagated, +is controlled on a per-particle and per-axis level, where the axes +are the Cartesian axes of the particle in its body-fixed frame. +It is important to note that starting from version 4.0 and unlike +in earlier versions of |es|, the particles' rotation is disabled by default. +In this way, just compiling in the ``ROTATION`` feature no longer changes the physics of the system. + +The rotation of a particle is controlled via the +:attr:`~espressomd.particle_data.ParticleHandle.rotation` property. +E.g., the following code adds a particle with rotation enabled around the x-axis of its body frame:: + + import espressomd + system = espressomd.System(box_l=[1, 1, 1]) + system.part.add(pos=(0, 0, 0), rotation=(True, False, False)) + +The rotational state of a particle is stored as a quaternion in the +:attr:`~espressomd.particle_data.ParticleHandle.quat` property. +For a value of (1,0,0,0), the body and space frames coincide. +When setting up a particle, its orientation state is by default aligned with the space frame of the box. +If your particles have a rotational symmetry, you can set up the particle direction +(the symmetry axis) using the :attr:`~espressomd.particle_data.ParticleHandle.director` property. +Note that then you have no control over the initial rotation angle around the symmetry axis. +If your particles are anisotropic in all three directions, you can either set +the :attr:`~espressomd.particle_data.ParticleHandle.quat` attribute directly, +or (recommended) set up all particle properties in the box frame and then use +:attr:`~espressomd.particle_data.ParticleHandle.rotate` to rotate the particle +to the desired state before starting the simulation. + +Notes: + +* The space-frame direction of the particle's z-axis in its body frame is accessible + through the :attr:`~espressomd.particle_data.ParticleHandle.director` property. +* Any other vector can be converted from body to space fixed frame using the + :meth:`ParticleHandle.convert_vector_body_to_space() + ` method. +* When ``DIPOLES`` are compiled in, the particles dipole moment is always + co-aligned with the z-axis in the body-fixed frame. +* Changing the particles dipole moment and director will re-orient the particle + such that its z-axis in space frame is aligned parallel to the given vector. + No guarantees are made for the other two axes after setting the director or the dipole moment. + + +The following particle properties are related to rotation: + +* :attr:`~espressomd.particle_data.ParticleHandle.dip` +* :attr:`~espressomd.particle_data.ParticleHandle.director` +* :attr:`~espressomd.particle_data.ParticleHandle.ext_torque` +* :attr:`~espressomd.particle_data.ParticleHandle.gamma_rot` +* :attr:`~espressomd.particle_data.ParticleHandle.gamma_rot` +* :attr:`~espressomd.particle_data.ParticleHandle.omega_body` +* :attr:`~espressomd.particle_data.ParticleHandle.omega_lab` +* :attr:`~espressomd.particle_data.ParticleHandle.quat` +* :attr:`~espressomd.particle_data.ParticleHandle.rinertia` +* :attr:`~espressomd.particle_data.ParticleHandle.rotation` +* :attr:`~espressomd.particle_data.ParticleHandle.torque_lab` + + +.. _Virtual sites: + +Virtual sites +------------- + +Virtual sites are particles, the positions and velocities of which are +not obtained by integrating an equation of motion. Rather, their +coordinates are obtained from the position (and orientation) of one or +more other particles. In this way, rigid arrangements of particles can +be constructed and a particle can be placed in the center of mass of a +set of other particles. Virtual sites can interact with other particles +in the system by means of interactions. Forces are added to them +according to their respective particle type. Before the next integration +step, the forces accumulated on a virtual site are distributed back to +those particles, from which the virtual site was derived. + + +There are different schemes for virtual sites, described in the +following sections. To switch the active scheme, the system +:attr:`~espressomd.system.System.virtual_sites` property can be used:: + + import espressomd + import espressomd.virtual_sites + + system = espressomd.System(box_l=[1, 1, 1]) + system.virtual_sites = espressomd.virtual_sites.VirtualSitesRelative(have_quaternion=False) + # or + system.virtual_sites = espressomd.virtual_sites.VirtualSitesOff() + +By default, :class:`espressomd.virtual_sites.VirtualSitesOff` is selected. +This means that virtual particles are not touched during integration. +The ``have_quaternion`` parameter determines whether the quaternion of +the virtual particle is updated (useful in combination with the +:attr:`~espressomd.particle_data.ParticleHandle.vs_quat` property of the +virtual particle which defines the orientation of the virtual particle +in the body fixed frame of the related real particle). + +.. _Rigid arrangements of particles: + +Rigid arrangements of particles +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The relative implementation of virtual sites allows for the simulation +of rigid arrangements of particles. It can be used, for extended +dipoles and raspberry-particles, but also for more complex +configurations. Position and velocity of a virtual site are obtained +from the position and orientation of exactly one non-virtual particle, +which has to be placed in the center of mass of the rigid body. Several +virtual sites can be related to one and the same non-virtual particle. +The position of the virtual site is given by + +.. math:: \vec{x_v} =\vec{x_n} +O_n (O_v \vec{E_z}) d, + +where :math:`\vec{x_n}` is the position of the non-virtual particle, +:math:`O_n` is the orientation of the non-virtual particle, :math:`O_v` +denotes the orientation of the vector :math:`\vec{x_v}-\vec{x_n}` with +respect to the non-virtual particles body fixed frame and :math:`d` the +distance between virtual and non-virtual particle. In words: The virtual +site is placed at a fixed distance from the non-virtual particle. When +the non-virtual particle rotates, the virtual sites rotates on an orbit +around the non-virtual particles center. + +To use this implementation of virtual sites, activate the feature +``VIRTUAL_SITES_RELATIVE``. Furthermore, an instance of +:class:`~espressomd.virtual_sites.VirtualSitesRelative` has to be set as the +active virtual sites scheme (see above). To set up a virtual site: + +#. Place the particle to which the virtual site should be related. + It needs to be in the center of mass of the rigid arrangement of + particles you create:: + + import espressomd + import espressomd.virtual_sites + + system = espressomd.System(box_l=[10., 10., 10.]) + system.virtual_sites = espressomd.virtual_sites.VirtualSitesRelative() + p1 = system.part.add(pos=[1., 2., 3.]) + +#. Place a particle at the desired relative position, make it virtual + and relate it to the first particle:: + + rel_offset = [1., 0., 0.] + p2 = system.part.add(pos=p1.pos + rel_offset) + p2.vs_auto_relate_to(p1) + + This will set the :attr:`~espressomd.particle_data.ParticleHandle.virtual` + attribute on particle ``p2`` to ``True``. + +#. Repeat the previous step with more virtual sites, if desired. + +#. To update the positions of all virtual sites, call:: + + system.integrator.run(0, recalc_forces=True) + +Please note: + +- The relative position of the virtual site is defined by its distance + from the non-virtual particle, the id of the non-virtual particle and + a quaternion which defines the vector from non-virtual particle to + virtual site in the non-virtual particles body-fixed frame. This + information is saved in the virtual site's + :attr:`~espressomd.particle_data.ParticleHandle.vs_relative` attribute. + Take care, not to overwrite it after using ``vs_auto_relate``. + +- Virtual sites can not be placed relative to other virtual sites, as + the order in which the positions of virtual sites are updated is not + guaranteed. Always relate a virtual site to a non-virtual particle + placed in the center of mass of the rigid arrangement of particles. + +- In case you know the correct quaternions, you can also setup a virtual + site using its :attr:`~espressomd.particle_data.ParticleHandle.vs_relative` + and :attr:`~espressomd.particle_data.ParticleHandle.virtual` attributes. + +- In a simulation on more than one CPU, the effective cell size needs + to be larger than the largest distance between a non-virtual particle + and its associated virtual sites. To this aim, when running on more than one core, + you need to set the system's :attr:`~espressomd.system.System.min_global_cut` + attribute to this largest distance. + An error is generated when this requirement is not met. + Under very specific circumstances it may be desirable to disable this check, + e.g. when using certain setups with the hybrid decomposition scheme. + You can do so by setting the virtual sites property ``override_cutoff_check = True``. + However, only consider this if you are absolutely sure of what you are doing. + +- If the virtual sites represent actual particles carrying a mass, the + inertia tensor of the non-virtual particle in the center of mass + needs to be adapted. + +- The presence of rigid bodies constructed by means of virtual sites + adds a contribution to the scalar pressure and pressure tensor. + +.. _Inertialess lattice-Boltzmann tracers: + +Inertialess lattice-Boltzmann tracers +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +:class:`espressomd.virtual_sites.VirtualSitesInertialessTracers` + +When this implementation is selected, the virtual sites follow the motion of a +lattice-Boltzmann fluid (both, CPU and GPU). This is achieved by integrating +their position using the fluid velocity at the virtual sites' position. +Forces acting on the virtual sites are directly transferred as force density +onto the lattice-Boltzmann fluid, making the coupling free of inertia. +The feature stems from the implementation of the +:ref:`Immersed Boundary Method for soft elastic objects`, but can be used independently. + +For correct results, the LB thermostat has to be deactivated for virtual sites:: + + system.thermostat.set_lb(kT=0, act_on_virtual=False) + +Please note that the velocity attribute of the virtual particles does not carry valid information for this virtual sites scheme. +With the LB GPU implementation, inertialess tracers only work on 1 MPI rank. + +.. _Interacting with groups of particles: + +Interacting with groups of particles +------------------------------------ + +Groups of particles are addressed using :class:`~espressomd.particle_data.ParticleSlice` objects. +Usually, these objects do not have to be instantiated by the user. There are several ways +to retrieve a particle slice: + +- By calling :meth:`ParticleList.add() ` + + When adding several particles at once, a particle slice is returned instead + of a particle handle. + +- By calling :meth:`ParticleList.by_ids() ` + + It is also possible to get a slice containing particles of specific ids, e.g.:: + + system.part.by_ids([1, 4, 3]) + + would contain the particles with ids 1, 4, and 3 in that specific order. + +- By calling :meth:`ParticleList.all() ` + + You can get a slice containing all particles using:: + + system.part.all() + +- By calling :meth:`ParticleList.select() ` + + This is useful to filter out particles with distinct properties, e.g.:: + + slice1 = system.part.select(type=0, q=1) + slice2 = system.part.select(lambda p: p.pos[0] < 0.5) + +Properties of particle slices can be accessed just like with single particles. +A list of all values is returned:: + + print(system.part.all().q) + +A particle slice can be iterated over, see :ref:`Iterating over particles and pairs of particles`. + +Setting properties of slices can be done by + +- supplying a *single value* that is assigned to each entry of the slice, e.g.:: + + system.part.by_ids(range(10)).ext_force = [1, 0, 0] + +- supplying an *array of values* that matches the length of the slice which sets each entry individually, e.g.:: + + system.part.by_ids(range(3)).ext_force = [[1, 0, 0], [2, 0, 0], [3, 0, 0]] + +For list properties that have no fixed length like ``exclusions`` or ``bonds``, some care has to be taken. +There, *single value* assignment also accepts lists/tuples just like setting the property of an individual particle. For example:: + + system.part.by_id(0).exclusions = [1, 2] + +would both exclude short-range interactions of the particle pairs ``0 <-> 1`` and ``0 <-> 2``. +Similarly, a list can also be assigned to each entry of the slice:: + + system.part.by_ids(range(2,4)).exclusions = [0, 1] + +This would exclude interactions between ``2 <-> 0``, ``2 <-> 1``, ``3 <-> 0`` and ``3 <-> 1``. +Now when it is desired to supply an *array of values* with individual values for each slice entry, the distinction can no longer be done +by the length of the input, as slice length and input length can be equal. Here, the nesting level of the input is the distinctive criterion:: + + system.part.by_ids(range(2,4)).exclusions = [[0, 1], [0, 1]] + +The above code snippet would lead to the same exclusions as the one before. +The same accounts for the ``bonds`` property by interchanging the integer entries of the exclusion list with +the tuple ``(bond, partners)``. + +You can select a subset of particles via using the select method. For example you can obtain a list of particles with charge -1 via using :: + + system.part.select(q=-1) + +For further information on how to use selections see :meth:`espressomd.particle_data.ParticleList.select()`. + +.. _Create particular particle configurations: + +Create particular particle configurations +----------------------------------------- + +.. _Setting up polymer chains: + +Setting up polymer chains +~~~~~~~~~~~~~~~~~~~~~~~~~ + +If you want to have polymers in your system, you can use the function +:func:`espressomd.polymer.linear_polymer_positions()` to determine suitable positions. + +Required arguments are the desired number of polymers ``n_polymers``, the +number of monomers per polymer chain ``beads_per_chain``, and the parameter +``bond_length``, which determines the distance between adjacent monomers +within the polymer chains. +Determining suitable particle positions pseudo-randomly requires the use of +a pseudo-random number generator, which has to be seeded. This ``seed`` +is therefore also a mandatory parameter. + +The function :func:`espressomd.polymer.linear_polymer_positions()` returns a +three-dimensional numpy array, namely a list of polymers containing the +positions of monomers (x, y, z). A quick example of how to set up polymers:: + + import espressomd + import espressomd.polymer + import espressomd.interactions + + system = espressomd.System([50, 50, 50]) + fene = espressomd.interactions.FeneBond(k=10, d_r_max=2) + system.bonded_inter.add(fene) + polymer_positions = espressomd.polymer.linear_polymer_positions( + n_polymers=10, beads_per_chain=25, bond_length=0.9, seed=23) + + for positions in polymer_positions: + monomers = system.part.add(pos=positions) + previous_part = None + for part in monomers: + if not previous_part is None: + part.add_bond((fene, previous_part)) + previous_part = part + +If there are constraints present in your system which you want to be taken +into account when creating the polymer positions, you can set the optional +boolean parameter ``respect_constraint=True``. +To simulate excluded volume while drawing the polymer positions, a minimum +distance between all particles can be set via ``min_distance``. This will +also respect already existing particles in the system. +Both when setting ``respect_constraints`` and choosing a ``min_distance`` +trial positions are pseudo-randomly chosen and only accepted if the +requested requirement is fulfilled. Otherwise, a new attempt will be made, +up to ``max_tries`` times per monomer and if this fails ``max_tries`` per +polymer. The default value is ``max_tries=1000``. Depending on the total +number of beads and constraints, this value may need to be adapted. If +determining suitable polymer positions within this limit fails, a runtime +error is thrown. + +Note that the distance between adjacent monomers +during the course of the simulation depends on the applied potentials. +For fixed bond length please refer to the Rattle Shake +algorithm\ :cite:`andersen83a`. The algorithm is based on +Verlet algorithm and satisfy internal constraints for molecular models +with internal constraints, using Lagrange multipliers. + + +.. _Setting up diamond polymer networks: + +Setting up diamond polymer networks +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +:func:`espressomd.polymer.setup_diamond_polymer()` creates a diamond-structured +polymer network with 8 tetra-functional nodes +connected by :math:`2 \times 8` polymer chains of length ``MPC`` with the system box as +the unit cell. The box therefore has to be cubic. +The diamond command creates ``16*MPC+8`` many particles +which are connected via the provided bond type (the term plus 8 stems from adding 8 nodes which are connecting the chains). +Chain monomers are placed at constant distance to each other +along the vector connecting network nodes. The distance between monomers is +``system.box_l[0]*(0.25 * sqrt(3))/(MPC + 1)``, which should be taken into account +when choosing the connecting bond. +The starting particle id, the charges of monomers, the frequency +of charged monomers in the chains as well as the types of the node particles, +the charged and the uncharged chain particles can be set via keyword arguments, see :func:`espressomd.polymer.setup_diamond_polymer()`. + +.. _diamond: +.. figure:: figures/diamond.png + :alt: Diamond-like polymer network with MPC=15. + :align: center + :height: 6.00000cm + + Diamond-like polymer network with ``MPC=15``. + +For simulating compressed or stretched gels, the function +:meth:`espressomd.system.System.change_volume_and_rescale_particles` may be used. + + +.. _Particle number counting feature: + +Particle number counting feature +-------------------------------- + +.. note:: + + Do not use these methods with the :mod:`espressomd.collision_detection` + module since the collision detection may create or delete particles + without the particle number counting feature being aware of this. + Therefore the :mod:`espressomd.reaction_methods` module may not + be used with the collision detection. + + +Knowing the number of particles of a certain type in simulations where +particle numbers can fluctuate is of interest. +Particle ids can be stored in a map for each individual type:: + + import espressomd + system = espressomd.System(box_l=[1, 1, 1]) + system.setup_type_map([_type]) + system.number_of_particles(_type) + +If you want to keep track of particle ids of a certain type you have to +initialize the method by calling :: + + system.setup_type_map([_type]) + +After that the system will keep track of particle ids of that type. Keeping +track of particles of a given type is not enabled by default since it requires +memory. The keyword ``number_of_particles`` as argument will return the number +of particles which have the given type. For counting the number of particles +of a given type you could also use +:meth:`ParticleList.select() ` :: + + import espressomd + system = espressomd.System(box_l=[1, 1, 1]) + system.part.add(pos=[1, 0, 0], type=0) + system.part.add(pos=[0, 1, 0], type=0) + system.part.add(pos=[0, 0, 1], type=2) + print(len(system.part.select(type=0))) + print(len(system.part.select(type=2))) + +However calling ``select(type=type)`` results in looping over all particles, +which is slow. In contrast, the system +:meth:`~espressomd.system.System.number_of_particles` method can return the +number of particles with that type. + +.. _Self-propelled swimmers: + +Self-propelled swimmers +----------------------- + +.. note:: + + If you are using this feature, please cite :cite:`degraaf16a`. + + +.. seealso:: + + :attr:`~espressomd.particle_data.ParticleHandle.swimming` + +.. _Langevin swimmers: + +Langevin swimmers +~~~~~~~~~~~~~~~~~ + +:: + + import espressomd + system = espressomd.System(box_l=[1, 1, 1]) + system.part.add(pos=[1, 0, 0], swimming={'f_swim': 0.03}) + +This enables the particle to be self-propelled in the direction determined by +its quaternion. For setting the particle's quaternion see +:attr:`~espressomd.particle_data.ParticleHandle.quat`. The self-propulsion +speed will relax to a constant velocity, that is specified by ``v_swim``. +Alternatively it is possible to achieve a constant velocity by imposing a +constant force term ``f_swim`` that is balanced by friction of a (Langevin) +thermostat. The way the velocity of the particle decays to the constant +terminal velocity in either of these methods is completely determined by the +friction coefficient. You may only set one of the possibilities ``v_swim`` *or* +``f_swim`` as you cannot relax to constant force *and* constant velocity at the +same time. Note that there is no real difference between ``v_swim`` and +``f_swim``, since the latter may always be chosen such that the same terminal +velocity is achieved for a given friction coefficient. + +.. _Lattice-Boltzmann swimmers: + +Lattice-Boltzmann swimmers +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +:: + + import espressomd + system = espressomd.System(box_l=[1, 1, 1]) + system.part.add(pos=[2, 0, 0], rotation=[1, 1, 1], swimming={ + 'f_swim': 0.01, 'mode': 'pusher', 'dipole_length': 2.0}) + +For an explanation of the parameters ``v_swim`` and ``f_swim`` see the previous +item. In lattice-Boltzmann self-propulsion is less trivial than for regular MD, +because the self-propulsion is achieved by a force-free mechanism, which has +strong implications for the far-field hydrodynamic flow field induced by the +self-propelled particle. In |es| only the dipolar component of the flow field +of an active particle is taken into account. This flow field can be generated +by a *pushing* or a *pulling* mechanism, leading to change in the sign of the +dipolar flow field with respect to the direction of motion. You can specify the +nature of the particle's flow field by using one of the modes: ``pusher`` or +``puller``. You will also need to specify a ``dipole_length`` which determines +the distance of the source of propulsion from the particle's center. Note that +you should not put this distance to zero; |es| (currently) does not support +mathematical dipole flow fields. + +You may ask: "Why are there two methods ``v_swim`` and ``f_swim`` for the +self-propulsion using the lattice-Boltzmann algorithm?" The answer is +straightforward. When a particle is accelerating, it has a monopolar flow-field +contribution which vanishes when it reaches its terminal velocity (for which +there will only be a dipolar flow field). The major difference between the +above two methods is that with ``v_swim`` the flow field *only* has a monopolar +moment and *only* while the particle is accelerating. As soon as the particle +reaches a constant speed (given by ``v_swim``) this monopolar moment is gone +and the flow field is zero! In contrast, ``f_swim`` always, i.e., while +accelerating *and* while swimming at constant force possesses a dipolar flow +field. diff --git a/doc4.2.2/_sources/reaction_methods.rst.txt b/doc4.2.2/_sources/reaction_methods.rst.txt new file mode 100644 index 0000000000..45e72fc277 --- /dev/null +++ b/doc4.2.2/_sources/reaction_methods.rst.txt @@ -0,0 +1,353 @@ +.. _Reaction methods: + +Reaction methods +================ + +This chapter describes methods for simulating chemical reaction equilibria +using reactive particles. Chemical species are referred to by an integer value +stored in the particle :attr:`~espressomd.particle_data.ParticleHandle.type` +property. Chemical reactions take place by changing the value in the +:attr:`~espressomd.particle_data.ParticleHandle.type` property via Monte Carlo +moves using the potential energy of the system before and after the reaction +:cite:`turner08a`. + +Please keep in mind the following remarks: + +* All reaction methods uses Monte Carlo moves which require potential energies. + Therefore reaction methods require support for energy calculations for all + active interactions in the simulation. Some algorithms do not support energy + calculation, e.g. :ref:`OIF ` and + :ref:`IBM `. + +* When modeling reactions that do not conserve the number of particles, the + method has to create or delete particles from the system. This process can + invalidate particle ids, in which case the particles are no longer numbered + contiguously. Particle slices returned by ``system.part`` are still iterable, + but the indices no longer match the particle ids. + +* Checkpointing is not supported, since the state of the Mersenne Twister + random number generator cannot be serialized. + +* For improved performance, you can set the type of invalidated particles with + :meth:`~espressomd.reaction_methods.ReactionAlgorithm.set_non_interacting_type` + in all reaction method classes. + +* Some of the functionality requires particle book-keeping. If your simulation + script raises runtime errors about "provided particle type X is currently not + tracked by the system", use :meth:`system.setup_type_map(type_list=[X]) + ` where ``X`` is the particle + type to track. + +Thermodynamic ensembles +----------------------- + +.. _Reaction ensemble: + +Reaction ensemble +~~~~~~~~~~~~~~~~~ + +The reaction ensemble :cite:`smith94c,johnson94a,turner08a` allows to simulate +chemical reactions which can be represented by the general equation: + +.. math:: + + \mathrm{\nu_1 S_1 +\ \dots\ \nu_l S_l\ \rightleftharpoons\ \nu_m S_m +\ \dots\ \nu_z S_z } + \label{general-eq} + +where :math:`\nu_i` is the stoichiometric coefficient of species +:math:`S_i`. By convention, stoichiometric coefficients of the +species on the left-hand side of the reaction (*reactants*) attain +negative values, and those on the right-hand side (*products*) attain +positive values, so that the reaction can be equivalently written as + +.. math:: + + \mathrm{\sum_i \nu_i S_i = 0} \,. + \label{general-eq-sum} + + +The equilibrium constant of the reaction is then given as + +.. math:: + + K = \exp(-\Delta_{\mathrm{r}}G^{\ominus} / k_B T) + \quad\text{with}\quad + \Delta_{\mathrm{r}}G^{\ominus} = \sum_i \nu_i \mu_i^{\ominus}\,. + \label{Keq} + + +Here :math:`k_B` is the Boltzmann constant, :math:`T` is temperature, +:math:`\Delta_{\mathrm{r}}G^{\ominus}` standard Gibbs free energy change +of the reaction, and :math:`\mu_i^{\ominus}` the standard chemical +potential (per particle) of species :math:`i`. Note that thermodynamic equilibrium is +independent of the direction in which we write the reaction. If it is +written with left and right-hand side swapped, +both :math:`\Delta_{\mathrm{r}}G^{\ominus}` and the stoichiometric +coefficients attain opposite signs, and the equilibrium constant attains the inverse value. +Further, note that the equilibrium constant :math:`K` is the +dimensionless *thermodynamic, concentration-based* equilibrium constant, +defined as + +.. math:: + + K(c^{\ominus}) = (c^{\ominus})^{-\bar\nu} \prod_i (c_i)^{\nu_i} + +where :math:`\bar\nu=\sum_i \nu_i`, and :math:`c^{\ominus}` is the reference concentration, +at which the standard chemical potential :math:`\Delta_{\mathrm{r}}G^{\ominus}` was determined. +In practice, this constant is often used with the dimension of :math:`(c^{\ominus})^{\bar\nu}` + +.. math:: + + K_c(c^{\ominus}) = K(c^{\ominus})\times (c^{\ominus})^{\bar\nu} + +A simulation in +the reaction ensemble consists of two types of moves: the *reaction move* +and the *configuration move*. The configuration move changes the configuration +of the system. +In the *forward* reaction, the appropriate number of reactants (given by +:math:`\nu_i`) is removed from the system, and the concomitant number of +products is inserted into the system. In the *backward* reaction, +reactants and products exchange their roles. The acceptance probability +:math:`P^{\xi}` for a move from state :math:`o` to :math:`n` in the reaction +ensemble is given by the criterion :cite:`smith94c` + +.. math:: + + P^{\xi} = \text{min}\biggl(1,V^{\bar\nu\xi}\Gamma^{\xi}e^{-\beta\Delta E}\prod_{i=1}\frac{N_i^0!}{(N_i^0+\nu_{i}\xi)!} + \label{eq:Pacc} + \biggr), + +where :math:`\Delta E=E_\mathrm{new}-E_\mathrm{old}` is the change in potential energy, +:math:`V` is the simulation box volume, +:math:`\beta=1/k_\mathrm{B}T` is the Boltzmann factor, and +:math:`\xi` is the extent of reaction, with :math:`\xi=1` for the forward and +:math:`\xi=-1` for the backward direction. + +:math:`\Gamma` is proportional to the reaction constant. It is defined as + +.. math:: + + \Gamma = \prod_i \Bigl(\frac{\left}{V} \Bigr)^{\bar\nu} = V^{-\bar\nu} \prod_i \left^{\nu_i} = K_c(c^{\ominus}=1/\sigma^3) + +where :math:`\left/V` is the average number density of particles of type :math:`i`. +Note that the dimension of :math:`\Gamma` is :math:`V^{\bar\nu}`, therefore its +units must be consistent with the units in which |es| measures the box volume, +i.e. :math:`\sigma^3`. + +It is often convenient, and in some cases even necessary, that some particles +representing reactants are not removed from or placed at randomly in the system +but their identity is changed to that of the products, or vice versa in the +backward direction. A typical example is the ionization reaction of weak +polyelectrolytes, where the ionizable groups on the polymer have to remain on +the polymer chain after the reaction. The replacement rule is that the identity of a given reactant type is +changed to the corresponding product type as long as the corresponding +coefficients allow for it. Corresponding means having the same position (index) in +the python lists of reactants and products which are used to set up the +reaction. + +Multiple reactions can be added to the same instance of the reaction ensemble. + +An example script can be found here: + +* `Reaction ensemble / constant pH ensemble `_ + +For a description of the available methods, see :class:`espressomd.reaction_methods.ReactionEnsemble`. + +.. _Grand canonical ensemble: + +Grand canonical ensemble +~~~~~~~~~~~~~~~~~~~~~~~~ + +As a special case, all stoichiometric coefficients on one side of the chemical +reaction can be set to zero. Such a reaction creates particles *ex nihilo*, and +is equivalent to exchanging particles with a reservoir. This type of simulation +in the reaction ensemble is equivalent to the grand canonical simulation. +Formally, this can be expressed by the reaction + +.. math:: + + \mathrm{\emptyset \rightleftharpoons\ \nu_A A } \,, + +where, if :math:`\nu_A=1`, the reaction constant :math:`\Gamma` defines the chemical potential of species A. +However, if :math:`\nu_A\neq 1`, the statistics of the reaction ensemble becomes +equivalent to the grand canonical only in the limit of large average number of species A in the box. +If the reaction contains more than one product, then the reaction constant +:math:`\Gamma` defines only the sum of their chemical potentials but not the +chemical potential of each product alone. + +Since the Reaction Ensemble acceptance transition probability can be +derived from the grand canonical acceptance transition probability, we +can use the reaction ensemble to implement grand canonical simulation +moves. This is done by adding reactions that only have reactants (for the +deletion of particles) or only have products (for the creation of +particles). There exists a one-to-one mapping of the expressions in the +grand canonical transition probabilities and the expressions in the +reaction ensemble transition probabilities. + +.. _Constant pH: + +Constant pH +~~~~~~~~~~~ + +As before in the reaction ensemble, one can define multiple reactions (e.g. for an ampholytic system which contains an acid and a base) in one :class:`~espressomd.reaction_methods.ConstantpHEnsemble` instance: + +.. code-block:: python + + cpH=reaction_methods.ConstantpHEnsemble( + temperature=1, exclusion_range=1, seed=77) + cpH.add_reaction(gamma=K_diss, reactant_types=[0], reactant_coefficients=[1], + product_types=[1, 2], product_coefficients=[1, 1], + default_charges={0: 0, 1: -1, 2: +1}) + cpH.add_reaction(gamma=1/(10**-14/K_diss), reactant_types=[3], reactant_coefficients=[1], product_types=[0, 2], product_coefficients=[1, 1], default_charges={0:0, 2:1, 3:1} ) + + +An example script can be found here: + +* `Reaction ensemble / constant pH ensemble `_ + +In the constant pH method due to Reed and Reed +:cite:`reed92a` it is possible to set the chemical potential +of :math:`H^{+}` ions, assuming that the simulated system is coupled to an +infinite reservoir. This value is the used to simulate dissociation +equilibrium of acids and bases. Under certain conditions, the constant +pH method can yield equivalent results as the reaction ensemble :cite:`landsgesell17b`. However, it +treats the chemical potential of :math:`H^{+}` ions and their actual +number in the simulation box as independent variables, which can lead to +serious artifacts. +The constant pH method can be used within the reaction ensemble module by +initializing the reactions with the standard commands of the reaction ensemble. + +The dissociation constant, which is the input of the constant pH method, is the equilibrium +constant :math:`K_c` for the following reaction: + +.. math:: + + \mathrm{HA \rightleftharpoons\ H^+ + A^- } \,, + +For a description of the available methods, see :class:`espressomd.reaction_methods.ConstantpHEnsemble`. + + +Widom Insertion (for homogeneous systems) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The Widom insertion method :cite:`widom63a` measures the change in excess free energy, i.e. the excess chemical potential due to the insertion of a new particle, or a group of particles: + +.. math:: + + \mu^\mathrm{ex}_B & :=\Delta F^\mathrm{ex} =F^\mathrm{ex}(N_B+1,V,T)-F^\mathrm{ex}(N_B,V,T)\\ + &=-kT \ln \left(\frac{1}{V} \int_V d^3r_{N_B+1} \langle \exp(-\beta \Delta E_\mathrm{pot}) \rangle_{N_B} \right) + +For this one has to provide the following reaction to the Widom method: + +.. code-block:: python + + type_B=1 + widom = reaction_methods.WidomInsertion( + temperature=temperature, seed=77) + widom.add_reaction(reactant_types=[], + reactant_coefficients=[], product_types=[type_B], + product_coefficients=[1], default_charges={1: 0}) + widom.calculate_particle_insertion_potential_energy(reaction_id=0) + + +The call of ``add_reaction`` define the insertion :math:`\mathrm{\emptyset \to type_B}` (which is the 0th defined reaction). +Multiple reactions for the insertions of different types can be added to the same ``WidomInsertion`` instance. +Measuring the excess chemical potential using the insertion method is done by +calling ``widom.calculate_particle_insertion_potential_energy(reaction_id=0)`` +multiple times and providing the accumulated sample to +``widom.calculate_excess_chemical_potential(particle_insertion_potential_energy_samples=samples)``. +If another particle insertion is defined, then the excess chemical potential +for this insertion can be measured in a similar fashion by sampling +``widom.calculate_particle_insertion_potential_energy(reaction_id=1)``. +Be aware that the implemented method only works for the canonical ensemble. If the numbers of particles fluctuate (i.e. in a semi grand canonical simulation) one has to adapt the formulas from which the excess chemical potential is calculated! This is not implemented. Also in a isobaric-isothermal simulation (NpT) the corresponding formulas for the excess chemical potentials need to be adapted. This is not implemented. + +The implementation can also deal with the simultaneous insertion of multiple particles and can therefore measure the change of excess free energy of multiple particles like e.g.: + +.. math:: + + \mu^\mathrm{ex, pair}&:=\Delta F^\mathrm{ex, pair}:= F^\mathrm{ex}(N_1+1, N_2+1,V,T)-F^\mathrm{ex}(N_1, N_2 ,V,T)\\ + &=-kT \ln \left(\frac{1}{V^2} \int_V \int_V d^3r_{N_1+1} d^3 r_{N_2+1} \langle \exp(-\beta \Delta E_\mathrm{pot}) \rangle_{N_1, N_2} \right) + +Note that the measurement involves three averages: the canonical ensemble average :math:`\langle \cdot \rangle_{N_1, N_2}` and the two averages over the position of particles :math:`N_1+1` and :math:`N_2+1`. +Since the averages over the position of the inserted particles are obtained via brute force sampling of the insertion positions it can be beneficial to have multiple insertion tries on the same configuration of the other particles. + +One can measure the change in excess free energy due to the simultaneous insertions of particles of type 1 and 2 and the simultaneous removal of a particle of type 3: + +.. math:: + + \mu^\mathrm{ex}:=\Delta F^\mathrm{ex, }:= F^\mathrm{ex}(N_1+1, N_2+1, N_3-1,V,T)-F^\mathrm{ex}(N_1, N_2, N_3 ,V,T) + +For this one has to provide the following reaction to the Widom method: + +.. code-block:: python + + widom.add_reaction(reactant_types=[type_3], + reactant_coefficients=[1], product_types=[type_1, type_2], + product_coefficients=[1,1], default_charges={1: 0}) + widom.calculate_particle_insertion_potential_energy(reaction_id=0) + +Be aware that in the current implementation, for MC moves which add +and remove particles, the insertion of the new particle always takes +place at the position where the last particle was removed. Be sure +that this is the behavior you want to have. Otherwise implement a new +function ``WidomInsertion::make_reaction_attempt`` in the core. + +An example script which demonstrates how to measure the pair excess +chemical potential for inserting an ion pair into a salt solution +can be found here: + +* `Widom Insertion `__ + +For a description of the available methods, see :class:`espressomd.reaction_methods.WidomInsertion`. + +Practical considerations +------------------------ + +.. _Converting tabulated reaction constants to internal units in ESPResSo: + +Converting tabulated reaction constants to internal units in |es| +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The implementation in |es| requires that the dimension of :math:`\Gamma` +is consistent with the internal unit of volume, :math:`\sigma^3`. The tabulated +values of equilibrium constants for reactions in solution, :math:`K_c`, typically use +:math:`c^{\ominus} = 1\,\mathrm{moldm^{-3}}` as the reference concentration, +and have the dimension of :math:`(c^{\ominus})^{\bar\nu}`. To be used with |es|, the +value of :math:`K_c` has to be converted as + +.. math:: + + \Gamma = K_c(c^{\ominus} = 1/\sigma^3) = K_c(c^{\ominus} = 1\,\mathrm{moldm^{-3}}) + \Bigl( N_{\mathrm{A}}\bigl(\frac{\sigma}{\mathrm{dm}}\bigr)^3\Bigr)^{\bar\nu} + +where :math:`N_{\mathrm{A}}` is the Avogadro number. For gas-phase reactions, +the pressure-based reaction constant, :math:`K_p` is often used, which can +be converted to :math:`K_c` as + +.. math:: + + K_p(p^{\ominus}=1\,\mathrm{atm}) = K_c(c^{\ominus} = 1\,\mathrm{moldm^{-3}}) \biggl(\frac{c^{\ominus}RT}{p^{\ominus}}\biggr)^{\bar\nu}, + +where :math:`p^{\ominus}=1\,\mathrm{atm}` is the standard pressure. +Consider using the python module pint for unit conversion. + +.. _Coupling reaction methods to molecular dynamics: + +Coupling reaction methods to molecular dynamics +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The Monte Carlo (MC) sampling of the reaction can be coupled with a configurational sampling using Molecular Dynamics (MD). +For non-interacting systems this coupling is not an issue, but for interacting systems the insertion of new particles +can lead to instabilities in the MD integration ultimately leading to a crash of the simulation. + +This integration instabilities can be avoided by defining a distance around the particles which already exist in the system +where new particles will not be inserted, which is defined by the required keyword ``exclusion_range``. +This prevents big overlaps with the newly inserted particles, avoiding too big forces between particles, which prevents the MD integration from crashing. +The value of the exclusion range does not affect the limiting result and it only affects the convergence and the stability of the integration. For interacting systems, +it is usually a good practice to choose the exclusion range such that it is comparable to the diameter of the particles. + +If particles with significantly different sizes are present, it is desired to define a different exclusion range for each pair of particle types. This can be done by +defining an exclusion radius per particle type by using the optional argument ``exclusion_radius_per_type``. Then, their exclusion range is calculated using +the Lorentz-Berthelot combination rule, *i.e.* ``exclusion_range = exclusion_radius_per_type[particle_type_1] + exclusion_radius_per_type[particle_type_2]``. +If the exclusion radius of one particle type is not defined, the value of the parameter provided in ``exclusion_range`` is used by default. +If the value in ``exclusion_radius_per_type`` is equal to 0, then the exclusion range of that particle type with any other particle is 0. diff --git a/doc4.2.2/_sources/running.rst.txt b/doc4.2.2/_sources/running.rst.txt new file mode 100644 index 0000000000..bc054e490f --- /dev/null +++ b/doc4.2.2/_sources/running.rst.txt @@ -0,0 +1,497 @@ +.. _Running a simulation: + +Running a simulation +==================== + +|es| is implemented as a Python module. This means that you need to write a +python script for any task you want to perform with |es|. In this chapter, +the basic structure of the interface will be explained. For a practical +introduction, see the tutorials, which are also part of the +distribution. + +.. _Running es: + +Running |es| +------------ + +Running a script +~~~~~~~~~~~~~~~~ + +To use |es|, you need to import the ``espressomd`` module in your +Python script. To this end, the folder containing the python module +needs to be in the Python search path. The module is located in the +:file:`src/python` folder under the build directory. + +A convenient way to run Python with the correct path is to use the +``pypresso`` script located in the build directory: + +.. code-block:: bash + + ./pypresso simulation.py + +The ``pypresso`` script is just a wrapper in order to expose the |es| python +module to the system's Python interpreter by modifying the ``$PYTHONPATH``. +If you have installed |es| from a Linux package manager that doesn't provide +the ``pypresso`` script, you will need to modify the ``$PYTHONPATH`` and +possibly the ``$LD_LIBRARY_PATH`` too, depending on which symbols are missing. + +The next chapter, :ref:`Setting up the system`, will explain in more details +how to write a simulation script for |es|. If you don't have any script, +simply call one of the files listed in section :ref:`Sample scripts`. + +Using the console +~~~~~~~~~~~~~~~~~ + +Since |es| can be manipulated like any other Python module, it is possible +to interact with it in a Python interpreter. Simply run the ``pypresso`` +script without arguments to start a Python session: + +.. code-block:: bash + + ./pypresso + +Likewise, a Jupyter console can be started with the ``ipypresso`` script, +which is also located in the build directory: + +.. code-block:: bash + + ./ipypresso console + +The name comes from the IPython interpreter, today known as Jupyter. + +Interactive notebooks +~~~~~~~~~~~~~~~~~~~~~ + +Tutorials are available as notebooks, i.e. they consist of a ``.ipynb`` +file which contains both the source code and the corresponding explanations. +They can be viewed, changed and run interactively. To generate the tutorials +in the build folder, do: + +.. code-block:: bash + + make tutorials + +The tutorials contain solutions hidden with the ``exercise2`` NB extension. +Since this extension is only available for Jupyter Notebook, JupyterLab +users need to convert the tutorials: + +.. code-block:: bash + + for f in doc/tutorials/*/*.ipynb; do + ./pypresso doc/tutorials/convert.py exercise2 --to-jupyterlab ${f} + done + +Likewise, VS Code Jupyter users need to convert the tutorials: + +.. code-block:: bash + + for f in doc/tutorials/*/*.ipynb; do + ./pypresso doc/tutorials/convert.py exercise2 --to-vscode-jupyter ${f} + done + +To interact with notebooks, move to the directory containing the tutorials +and call the ``ipypresso`` script to start a local Jupyter session. + +For Jupyter Notebook and IPython users: + +.. code-block:: bash + + cd doc/tutorials + ../../ipypresso notebook + +For JupyterLab users: + +.. code-block:: bash + + cd doc/tutorials + ../../ipypresso lab + +For VS Code Jupyter users, no action is needed if ``pypresso`` was set as +the interpreter path (see details in :ref:`Running inside an IDE`). + +You may then browse through the different tutorial folders. Files whose name +ends with extension ``.ipynb`` can be opened in the browser. Click on the Run +button to execute the current block, or use the keyboard shortcut Shift+Enter. +If the current block is a code block, the ``In [ ]`` label to the left will +change to ``In [*]`` while the code is being executed, and become ``In [1]`` +once the execution has completed. The number increments itself every time a +code cell is executed. This bookkeeping is extremely useful when modifying +previous code cells, as it shows which cells are out-of-date. It's also +possible to run all cells by clicking on the "Run" drop-down menu, then on +"Run All Below". This will change all labels to ``In [*]`` to show that the +first one is running, while the subsequent ones are awaiting execution. + +You'll also see that many cells generate an output. When the output becomes +very long, Jupyter will automatically put it in a box with a vertical scrollbar. +The output may also contain static plots, dynamic plots and videos. It is also +possible to start a 3D visualizer in a new window, however closing the window +will exit the Python interpreter and Jupyter will notify you that the current +Python kernel stopped. If a cell takes too long to execute, you may interrupt +it with the stop button. + +Solutions cells are created using the ``exercise2`` plugin from nbextensions. +To prevent solution code cells from running when clicking on "Run All", these +code cells need to be converted to Markdown cells and fenced with `````python`` +and ```````. + +To close the Jupyter session, go to the terminal where it was started and use +the keyboard shortcut Ctrl+C twice. + +When starting a Jupyter session, you may see the following warning in the +terminal: + +.. code-block:: none + + [TerminalIPythonApp] WARNING | Subcommand `ipython notebook` is deprecated and will be removed in future versions. + [TerminalIPythonApp] WARNING | You likely want to use `jupyter notebook` in the future + +This only means |es| was compiled with IPython instead of Jupyter. If Jupyter +is installed on your system, the notebook will automatically close IPython and +start Jupyter. To recompile |es| with Jupyter, provide ``cmake`` with the flag +``-DIPYTHON_EXECUTABLE=$(which jupyter)``. + +You can find the official Jupyter documentation at +https://jupyter.readthedocs.io/en/latest/running.html + +.. _Running inside an IDE: + +Running inside an IDE +~~~~~~~~~~~~~~~~~~~~~ + +You can use an integrated development environment (IDE) to develop and run |es| +scripts. Suitable IDEs are e.g. *Visual Studio Code* and *Spyder*. They can +provide a workflow superior to that of a standard text editor as they offer +useful features such as advanced code completion, debugging and analysis tools +etc. The following example shows how to setup |es| in *Visual Studio Code* on +Linux (tested with version 1.46.1). The process should be similar for every +Python IDE, namely the Python interpreter needs to be replaced. + +The ``pypresso`` executable can be set as a custom Python interpreter inside VS +Code. |es| scripts can then be executed just like any other python script. +Inside VS Code, the Python extension needs to be installed. Next, click the +gear at the bottom left and choose *Settings*. Search for +``Default Interpreter Path`` and change the setting to the path to your +``pypresso`` executable, e.g. + +.. code-block:: none + + ~/espresso/build/pypresso + +After that, you can open scripts and execute them with the keyboard shortcut +Ctrl+F5. + +Fig. :ref:`vs-code-figure` shows the VS Code interface with the interpreter +path set to ``pypresso``. + +.. note:: You may need to set the path relative to your home directory, i.e. ``~/path/to/pypresso``. + +.. _vs-code-figure: + +.. figure:: figures/vs-code-settings.png + :alt: Visual Studio Code interface with the default interpreter path set to the ``pypresso`` executable + :width: 55.0% + :align: center + + Visual Studio Code interface + + +.. _Debugging es: + +Debugging |es| +-------------- + +Exceptional situations occur in every program. If |es| crashes with a +segmentation fault, that means that there was a memory fault in the +simulation core which requires running the program in a debugger. The +``pypresso`` executable file is actually not a program but a script +which sets the Python path appropriately and starts the Python +interpreter with your arguments. Thus it is not possible to directly +run ``pypresso`` in a debugger. However, we provide some useful +command line options for the most common tools. + +.. code-block:: bash + + ./pypresso --tool + +where ``--tool`` can be any tool from the :ref:`table below `. +Only one tool can be used at a time. Some tools benefit from specific build +options, as outlined in the installation section :ref:`Troubleshooting`. +|es| can be debugged in MPI environments, as outlined in section +:ref:`Debugging parallel code`. + +.. _Debugging es with tools: + +.. table:: Tools for the Python wrapper to |es|. + + +---------------------+----------------------------------------------+ + | Tool | Effect | + +=====================+==============================================+ + | ``--gdb`` | ``gdb --args python `` | + +---------------------+----------------------------------------------+ + | ``--lldb`` | ``lldb -- python `` | + +---------------------+----------------------------------------------+ + | ``--valgrind`` | ``valgrind --leak-check=full python `` | + +---------------------+----------------------------------------------+ + | ``--cuda-gdb`` | ``cuda-gdb --args python `` | + +---------------------+----------------------------------------------+ + | ``--cuda-memcheck`` | ``cuda-memcheck python `` | + +---------------------+----------------------------------------------+ + + +.. _Parallel computing: + +Parallel computing +------------------ + +Many algorithms in |es| are designed to work with multiple MPI ranks. +However, not all algorithms benefit from MPI parallelization equally. +Several algorithms only use MPI rank 0 (e.g. :ref:`Reaction methods`). +|es| should work with most MPI implementations on the market; +see the :term:`MPI installation requirements ` for details. + +.. _General syntax: + +General syntax +~~~~~~~~~~~~~~ + +To run a simulation on several MPI ranks, for example 4, simply invoke +the ``pypresso`` script with the following syntax: + +.. code-block:: bash + + mpiexec -n 4 ./pypresso simulation.py + +The cell system is automatically split among the MPI ranks, and data +is automatically gathered on the main rank, which means a regular |es| +script can be executed in an MPI environment out-of-the-box. The number +of MPI ranks can be accessed via the system ``n_nodes`` state property. +The simulation box partition is controlled by the cell system +:attr:`~espressomd.cell_system.CellSystem.node_grid` property. +By default, MPI ranks are assigned in decreasing order, e.g. on 6 MPI ranks +``node_grid`` is ``[3, 2, 1]``. It is possible to re-assign the ranks by +changing the value of the ``node_grid`` property, however a few algorithms +(such as FFT-based electrostatic methods) only work for the default +partitioning scheme where values must be arranged in decreasing order. + +:: + + # get the number of ranks + print(system.cell_system.get_state()["n_nodes"]) + # re-assign the ranks + system.cell_system.node_grid = [2, 1, 3] + system.cell_system.node_grid = [6, 1, 1] + +There are alternative ways to invoke MPI on ``pypresso``, but they share +similar options. The number after the ``-n`` option is the number of ranks, +which needs to be inferior or equal to the number of *physical* cores on the +workstation. Command ``nproc`` displays the number of *logical* cores on the +workstation. For architectures that support hyperthreading, the number of +logical cores is an integer multiple of the number of physical cores, +usually 2. Therefore on a hyperthreaded workstation with 32 cores, +at most 16 cores can be used without major performance loss, unless +extra arguments are passed to the ``mpiexec`` program. + +On cluster computers, it might be necessary to load the MPI library with +``module load openmpi`` or similar. + +.. _Performance gain: + +Performance gain +~~~~~~~~~~~~~~~~ + +Simulations executed in parallel with run faster, however the runtime +won't decrease linearly with the number of MPI ranks. MPI-parallel +simulations introduce several sources of overhead and latency: + +* overhead of serializing, communicating and deserializing data structures +* extra calculations in the LB halo +* extra calculations in the ghost shell + (see section :ref:`Internal particle organization` for more details) +* latency due to blocking communication (i.e. a node remains idle + while waiting for a message from another node) +* latency due to blocking data collection for GPU + (only relevant for GPU methods) +* latency due to context switching +* latency due to memory bandwidth + +While good performance can be achieved up to 32 MPI ranks, allocating more +than 32 ranks to a simulation will not always lead to significantly improved +run times. The performance gain is highly sensitive to the algorithms used +by the simulation, for example GPU methods rarely benefit from more than +8 MPI ranks. Performance is also affected by the number of features enabled +at compile time, even when these features are not used by the simulation; +do not hesitate to remove all features not required by the +simulation script and rebuild |es| for optimal performance. + +Benchmarking is often the best way to determine the optimal number of MPI +ranks for a given simulation setup. Please refer to the wiki chapter on +`benchmarking `__ +for more details. + +Runtime speed-up is not the only appeal of MPI parallelization. Another +benefit is the possibility to distribute a calculation over multiple +compute nodes in clusters and high-performance environments, and therefore +split the data structures over multiple machines. This becomes necessary +when running simulations with millions of particles, as the memory +available on a single compute node would otherwise saturate. + +.. _Communication model: + +Communication model +~~~~~~~~~~~~~~~~~~~ + +|es| was originally designed for the "flat" model of communication: +each MPI rank binds to a logical CPU core. This communication model +doesn't fully leverage shared memory on recent CPUs, such as `NUMA +architectures `__, +and |es| currently doesn't support the hybrid +MPI+\ `OpenMP `__ programming model. + +The MPI+CUDA programming model is supported, although only one GPU can be +used for the entire simulation. As a result, a blocking *gather* operation +is carried out to collect data from all ranks to the main rank, and a +blocking *scatter* operation is carried out to transfer the result of the +GPU calculation from the main rank back to all ranks. This latency limits +GPU-acceleration to simulations running on fewer than 8 MPI ranks. +For more details, see section :ref:`GPU acceleration`. + +.. _The MPI callbacks framework: + +The MPI callbacks framework +""""""""""""""""""""""""""" + +When starting a simulation with :math:`n` MPI ranks, |es| will internally +use MPI rank :math:`0` as the head node (also referred to as the "main rank") +and MPI ranks :math:`1` to :math:`n-1` as worker nodes. The Python interface +interacts only with the head node, and the head node forwards the information +to the worker nodes. + +To put it another way, all worker nodes are idle until the user calls +a function that is designed to run in parallel, +in which case the head node calls the corresponding core function +and sends a request on the worker nodes to call the same core function. +The request can be a simple collective call, or a collective call with a +reduction if the function returns a value. The reduction can either: + +- combine the :math:`n` results via a mathematical operation + (usually a summation or a multiplication) +- discard the result of the :math:`n-1` worker nodes; this is done when + all ranks return the same value, or when the calculation can only be + carried out on the main rank but requires data from the other ranks +- return the result of one rank when the calculation can only be carried out + by a specific rank; this is achieved by returning an *optional*, which + contains a value on the rank that has access to the information necessary + to carry out the calculation, while the other :math:`n-1` ranks return + an empty optional + +For more details on this framework, please refer to the Doxygen documentation +of the the C++ core file :file:`MpiCallbacks.hpp`. + +.. _Debugging parallel code: + +Debugging parallel code +~~~~~~~~~~~~~~~~~~~~~~~ + +It is possible to debug an MPI-parallel simulation script with GDB. +Keep in mind that contrary to a textbook example MPI application, where +all ranks execute the ``main`` function, in |es| the worker nodes are idle +until the head node on MPI rank 0 delegates work to them. This means that +on MPI rank > 1, break points will only have an effect in code that can be +reached from a callback function whose pointer has been registered in the +:ref:`MPI callbacks framework `. + +The following command runs a script with 2 MPI ranks and binds a terminal +to each rank: + +.. code-block:: bash + + mpiexec -np 2 xterm -fa 'Monospace' -fs 12 -e ./pypresso --gdb simulation.py + +It can also be done via ssh with X-window forwarding: + +.. code-block:: bash + + ssh -X username@hostname + mpiexec -n 2 -x DISPLAY="${DISPLAY}" xterm -fa 'Monospace' -fs 12 \ + -e ./pypresso --gdb simulation.py + +The same syntax is used for C++ unit tests: + +.. code-block:: bash + + mpiexec -np 2 xterm -fa 'Monospace' -fs 12 \ + -e gdb src/core/unit_tests/EspressoSystemStandAlone_test + + +.. _GPU acceleration: + +GPU acceleration +---------------- + +.. _CUDA acceleration: + +CUDA acceleration +~~~~~~~~~~~~~~~~~ + +.. note:: + Feature ``CUDA`` required + +|es| is capable of delegating work to the GPU to speed up simulations. +Not every simulation method profits from GPU acceleration. +Refer to :ref:`Available simulation methods` +to check whether your desired method can be used on the GPU. +In order to use GPU acceleration you need a NVIDIA GPU +and it needs to have at least compute capability 2.0. +For more details, please refer to the installation section +:ref:`Nvidia GPU acceleration`. + +For more information please check :class:`espressomd.cuda_init.CudaInitHandle`. + +.. _List available devices: + +List available devices +"""""""""""""""""""""" + +To list available CUDA devices, call +:meth:`espressomd.cuda_init.CudaInitHandle.list_devices`:: + + >>> import espressomd + >>> system = espressomd.System(box_l=[1, 1, 1]) + >>> print(system.cuda_init_handle.list_devices()) + {0: 'GeForce RTX 2080', 1: 'GeForce GT 730'} + +This method returns a dictionary containing +the device id as key and the device name as its value. + +To get more details on the CUDA devices for each MPI node, call +:meth:`espressomd.cuda_init.CudaInitHandle.list_devices_properties`:: + + >>> import pprint + >>> import espressomd + >>> system = espressomd.System(box_l=[1, 1, 1]) + >>> pprint.pprint(system.cuda_init_handle.list_devices_properties()) + {'seraue': {0: {'name': 'GeForce RTX 2080', + 'compute_capability': (7, 5), + 'cores': 46, + 'total_memory': 8370061312}, + 1: {'name': 'GeForce GT 730', + 'compute_capability': (3, 5), + 'cores': 2, + 'total_memory': 1014104064}}} + +.. _Select a device: + +Select a device +""""""""""""""" + +When you start ``pypresso``, the first GPU should be selected. +If you wanted to use the second GPU, this can be done +by setting :attr:`espressomd.cuda_init.CudaInitHandle.device` as follows:: + + >>> import espressomd + >>> system = espressomd.System(box_l=[1, 1, 1]) + >>> system.cuda_init_handle.device = 1 + +Setting a device id outside the valid range or a device +which does not meet the minimum requirements will raise +an exception. diff --git a/doc4.2.2/_sources/system_manipulation.rst.txt b/doc4.2.2/_sources/system_manipulation.rst.txt new file mode 100644 index 0000000000..d399a59b2b --- /dev/null +++ b/doc4.2.2/_sources/system_manipulation.rst.txt @@ -0,0 +1,152 @@ +.. _System manipulation: + +System manipulation +=================== + +.. _Changing the box volume: + +Changing the box volume +----------------------- + +This is implemented in +:meth:`espressomd.system.System.change_volume_and_rescale_particles` +with the parameters ``d_new`` for the new length and ``dir`` for the +coordinates to work on and ``"xyz"`` for isotropic. + +Changes the volume of either a cubic simulation box to the new volume or +its given x-/y-/z-/xyz-extension to the new box-length, and +isotropically adjusts the particles coordinates as well. The function +returns the new volume of the deformed simulation box. + +.. _Stopping particles: + +Stopping particles +------------------ + +To stop particles you can use the functionality implemented in the +:mod:`espressomd.galilei` module. The corresponding class +:class:`espressomd.galilei.GalileiTransform` which is wrapped inside +the :class:`espressomd.system.System` instance as +:class:`espressomd.system.System.galilei` has two functions: + +- :meth:`espressomd.galilei.GalileiTransform.kill_particle_motion`: + halts all particles in the current simulation, setting their + velocities to zero, as well as their angular momentum if the + feature ``ROTATION`` has been compiled in. + +- :meth:`espressomd.galilei.GalileiTransform.kill_particle_forces`: + sets all forces on the particles to zero, as well as all torques if + the feature ``ROTATION`` has been compiled in. + +.. _Fixing the center of mass: + +Fixing the center of mass +------------------------- + +This interaction type applies a constraint on particles of the specified +types such that during the integration the center of mass of these particles is +fixed. This is accomplished as follows: The sum of all the forces acting +on particles of type are calculated. These include all the forces due to +other interaction types and also the thermostat. Next a force equal in +magnitude, but in the opposite direction is applied to all the +particles. This force is divided on the particles of type relative to +their respective mass. Under periodic boundary conditions, this fixes +the itinerant center of mass, that is, the one obtained from the +unfolded coordinates. + +Center of mass fixing can be activated via :class:`espressomd.system.System`:: + + system.comfixed.types = list_of_types_to_fix + +.. _Capping the force during warmup: + +Capping the force during warmup +------------------------------- + +Non-bonded interactions are often used to model the hard core repulsion +between particles. Most of the potentials in the section are therefore +singular at zero distance, and forces usually become very large for +distances below the particle size. This is not a problem during the +simulation, as particles will simply avoid overlapping. However, +creating an initial dense random configuration without overlap is often +difficult. By artificially capping the forces, it is possible to simulate a system +with overlaps. By gradually raising the cap value, possible overlaps +become unfavorable, and the system equilibrates to an overlap-free +configuration. + +Force capping can be activated via :class:`espressomd.system.System`:: + + system.force_cap = F_max + +This command will limit the magnitude of the force to :math:`r F_\mathrm{max}`. +Energies are not affected by the capping, so the energy can be used to +identify the remaining overlap. Torques are also not affected by the +capping. Force capping is switched off by setting :math:`F_\mathrm{max}=0`. + +For simple systems, it is often more convenient to use the +:ref:`Steepest descent` algorithm instead of writing a tailored warmup +loop in Python. The steepest descent algorithm will integrate the system +while capping both the maximum displacement and maximum rotation. + +.. _Galilei Transform and Particle Velocity Manipulation: + +Galilei Transform and Particle Velocity Manipulation +---------------------------------------------------- + +The following class :class:`espressomd.galilei.GalileiTransform` may be useful +in affecting the velocity of the system. :: + + system = espressomd.System(box_l=[1, 1, 1]) + gt = system.galilei + +* Particle motion and rotation + + :: + + gt.kill_particle_motion() + + This command halts all particles in the current simulation, setting + their velocities to zero, as well as their angular momentum if the + option ``rotation`` is specified and the feature ``ROTATION`` has been + compiled in. + +* Forces and torques acting on the particles + + :: + + gt.kill_particle_forces() + + This command sets all forces on the particles to zero, as well as all + torques if the option ``torque`` is specified and the feature ``ROTATION`` + has been compiled in. + +* The center of mass of the system + + :: + + gt.system_CMS() + + Returns the center of mass of the whole system. It currently does not + factor in the density fluctuations of the lattice-Boltzmann fluid. + +* The center-of-mass velocity + + :: + + gt.system_CMS_velocity() + + Returns the velocity of the center of mass of the whole system. + +* The Galilei transform + + :: + + gt.galilei_transform() + + Subtracts the velocity of the center of mass of the whole system from + every particle's velocity, thereby performing a Galilei transform into + the reference frame of the center of mass of the system. This + transformation is useful for example in combination with the DPD + thermostat, since there, a drift in the velocity of the whole system + leads to an offset in the reported temperature. + diff --git a/doc4.2.2/_sources/system_setup.rst.txt b/doc4.2.2/_sources/system_setup.rst.txt new file mode 100644 index 0000000000..a8ab3c23bf --- /dev/null +++ b/doc4.2.2/_sources/system_setup.rst.txt @@ -0,0 +1,410 @@ +.. _Setting up the system: + +Setting up the system +===================== + +.. _Setting global variables: + +Setting global variables +------------------------ + +The global system variables are controlled via the Python +:class:`espressomd.system.System` class:: + + import espressomd + system = espressomd.System(box_l=[10., 10., 10.]) + system.time_step = 0.01 + system.cell_system.skin = 0.4 + system.periodicity = [True, True, True] + +This code creates a system with a cubic unit cell of length 10 in simulation +units, and sets the skin to 0.4 simulation units and the time step to 0.01 +simulation units. + +Some variables belong to the ``System`` class and will be explained in the list +below, while other variables such as the skin belong to objects that are +attached to the class, and will be explain in subsequent sections and chapters. +Note that for many vectorial properties, e.g. ``box_l`` and ``periodicity``, +component-wise manipulation +like ``system.box_l[0] = 1`` or in-place operators like ``+=`` or ``*=`` are not +allowed and result in an error. This behavior is inherited, so the same applies +to ``a`` after ``a = system.box_l``. If you want to use a vectorial property +for further calculations, you should explicitly make a copy e.g. via +``a = numpy.copy(system.box_l)``. + +* :py:attr:`~espressomd.system.System.box_l` + + Simulation box lengths of the cuboid box used by |es|. + Note that if you change the box length during the simulation, the folded + particle coordinates will remain the same, i.e., the particle stay in + the same image box, but at the same relative position in their image + box. If you want to scale the positions, use the command + :py:meth:`~espressomd.system.System.change_volume_and_rescale_particles`. + +* :py:attr:`~espressomd.system.System.periodicity` + + Specifies periodicity for the three directions. |es| can be instructed + to treat some dimensions as non-periodic. By default |es| assumes periodicity in + all directions which equals setting this variable to ``[True, True, True]``. + A dimension is specified as non-periodic via setting the periodicity + variable for this dimension to ``False``. E.g. Periodicity only in z-direction + is obtained by ``[False, False, True]``. Caveat: Be aware of the fact that making a + dimension non-periodic does not hinder particles from leaving the box in + this direction; in this case, shape-based constraints can be used to keep + particles in the simulation box. For more details, see :ref:`Boundary conditions`. + +* :py:attr:`~espressomd.system.System.time_step` + + Time step for MD integration. + +* :py:attr:`~espressomd.system.System.time` + + The simulation time. + +* :py:attr:`~espressomd.system.System.min_global_cut` + + Minimal total cutoff for real space. Effectively, this plus the + :py:attr:`~espressomd.cell_system.CellSystem.skin` is the minimally possible + cell size. |es| typically determines this value automatically, but some + algorithms, virtual sites, require you to specify it manually. + +* :py:attr:`~espressomd.system.System.max_cut_bonded` + + *read-only* Maximal cutoff of bonded interactions. + +* :py:attr:`~espressomd.system.System.max_cut_nonbonded` + + *read-only* Maximal cutoff of non-bonded interactions. + +.. _Accessing module states: + +Accessing module states +~~~~~~~~~~~~~~~~~~~~~~~ + +Some variables like or are no longer directly available as attributes. +In these cases they can be easily derived from the corresponding Python +objects like:: + + n_part = len(system.part) + +or by calling the corresponding ``get_state()`` methods like:: + + temperature = system.thermostat.get_state()[0]['kT'] + gamma = system.thermostat.get_state()[0]['gamma'] + gamma_rot = system.thermostat.get_state()[0]['gamma_rotation'] + +.. _Simulation box: + +Simulation box +-------------- + +.. _Boundary conditions: + +Boundary conditions +~~~~~~~~~~~~~~~~~~~ + +.. _Periodic boundaries: + +Periodic boundaries +^^^^^^^^^^^^^^^^^^^ + +With periodic boundary conditions, particles interact with periodic +images of all particles in the system. This is the default behavior. +When particles cross a box boundary, their position are folded and +their image box counter are incremented. + +From the Python interface, the folded position is accessed with +:attr:`~espressomd.particle_data.ParticleHandle.pos_folded` and the image +box counter with :attr:`~espressomd.particle_data.ParticleHandle.image_box`. +Note that :attr:`~espressomd.particle_data.ParticleHandle.pos` gives the +unfolded particle position. + +Example:: + + import espressomd + system = espressomd.System(box_l=[5.0, 5.0, 5.0], periodicity=[True, True, True]) + system.time_step = 0.1 + system.cell_system.skin = 0.0 + p = system.part.add(pos=[4.9, 0.0, 0.0], v=[0.1, 0.0, 0.0]) + system.integrator.run(20) + print(f"pos = {p.pos}") + print(f"pos_folded = {p.pos_folded}") + print(f"image_box = {p.image_box}") + +Output: + +.. code-block:: none + + pos = [5.1 0. 0. ] + pos_folded = [0.1 0. 0. ] + image_box = [1 0 0] + +.. _Open boundaries: + +Open boundaries +^^^^^^^^^^^^^^^ + +With open boundaries, particles can leave the simulation box. +What happens in this case depends on which algorithm is used. +Some algorithms may require open boundaries, +such as :ref:`Stokesian Dynamics`. + +Example:: + + import espressomd + system = espressomd.System(box_l=[5.0, 5.0, 5.0], periodicity=[False, False, False]) + system.time_step = 0.1 + system.cell_system.skin = 0.0 + p = system.part.add(pos=[4.9, 0.0, 0.0], v=[0.1, 0.0, 0.0]) + system.integrator.run(20) + print(f"pos = {p.pos}") + print(f"pos_folded = {p.pos_folded}") + print(f"image_box = {p.image_box}") + +Output: + +.. code-block:: none + + pos = [5.1 0. 0. ] + pos_folded = [5.1 0. 0. ] + image_box = [0 0 0] + +.. _Lees-Edwards boundary conditions: + +Lees--Edwards boundary conditions +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Lees--Edwards boundary conditions (LEbc) are special periodic boundary +conditions to simulate systems under shear stress :cite:`lees72a`. +Periodic images of particles across the shear boundary appear with a +time-dependent position offset. When a particle crosses the shear boundary, +it appears to the opposite side of the simulation box with a position offset +and a shear velocity :cite:`bindgen21a`. + +LEbc require a fully periodic system and are configured with +:class:`~espressomd.lees_edwards.LinearShear` and +:class:`~espressomd.lees_edwards.OscillatoryShear`. +To temporarily disable LEbc, use :class:`~espressomd.lees_edwards.Off`. +To completely disable LEbc and reinitialize the box geometry, do +``system.lees_edwards.protocol = None``. + +Example:: + + import espressomd + import espressomd.lees_edwards + system = espressomd.System(box_l=[5.0, 5.0, 5.0]) + system.time_step = 0.1 + system.cell_system.skin = 0.0 + system.cell_system.set_n_square(use_verlet_lists=True) + le_protocol = espressomd.lees_edwards.LinearShear( + shear_velocity=-0.1, initial_pos_offset=0.0, time_0=-0.1) + system.lees_edwards.set_boundary_conditions( + shear_direction="y", # shear along y-axis + shear_plane_normal="x", # shift when crossing the x-boundary + protocol=le_protocol) + p = system.part.add(pos=[4.9, 0.0, 0.0], v=[0.1, 0.0, 0.0]) + system.integrator.run(20) + print(f"pos = {p.pos}") + print(f"pos_folded = {p.pos_folded}") + print(f"image_box = {p.image_box}") + print(f"velocity = {p.v}") + +Output: + +.. code-block:: none + + pos = [5.1 0.2 0. ] + pos_folded = [0.1 0.2 0. ] + image_box = [1 0 0] + velocity = [0.1 0.1 0. ] + +Particles inserted outside the box boundaries will be wrapped around +using the normal periodic boundary rules, i.e. they will not be sheared, +even though their :attr:`~espressomd.particle_data.ParticleHandle.image_box` +is *not* zero. + +Once a valid tuple ``(shear_direction, shear_plane_normal, protocol)`` has been +set via :meth:`~espressomd.lees_edwards.LeesEdwards.set_boundary_conditions`, +one can update the protocol via a simple assignment of the form +``system.lees_edwards.protocol = new_le_protocol``, in which case +the shear direction and shear normal are left unchanged. The method +:meth:`~espressomd.lees_edwards.LeesEdwards.set_boundary_conditions` +is the only way to modify the shear direction and shear normal. + + +.. _Cell systems: + +Cell systems +~~~~~~~~~~~~ + +This section deals with the flexible particle data organization of |es|. +|es| is able to change the organization of the particles in the computer +memory to accommodate for the needs of the algorithms being used. +For details on the internal organization, +refer to section :ref:`Internal particle organization`. + +.. _Global properties: + +Global properties +^^^^^^^^^^^^^^^^^ + +The properties of the cell system can be accessed via the system +:class:`~espressomd.system.System.cell_system` attribute: + +* :py:attr:`~espressomd.cell_system.CellSystem.node_grid` + + 3D node grid for real space domain decomposition (optional, if + unset an optimal partition is chosen automatically). The domain decomposition + can be visualized with :file:`samples/visualization_cellsystem.py`. + +* :py:attr:`~espressomd.cell_system.CellSystem.skin` + + Skin for the Verlet list. This value has to be set, otherwise the simulation will not start. + +Details about the cell system can be obtained by +:meth:`get_state() `: + +* ``cell_grid`` Dimension of the inner cell grid (only for regular decomposition). +* ``cell_size`` Box-length of a cell (only for regular decomposition). +* ``n_nodes`` Number of MPI nodes. +* ``node_grid`` MPI domain partition. +* ``type`` The current type of the cell system. +* ``skin`` Verlet list skin. +* ``verlet_reuse`` Average number of integration steps the Verlet list is re-used. + +.. _Regular decomposition: + +Regular decomposition +^^^^^^^^^^^^^^^^^^^^^ + +Invoking :py:meth:`~espressomd.cell_system.CellSystem.set_regular_decomposition` +selects the regular decomposition cell scheme, using Verlet lists for the +calculation of the interactions. If you specify ``use_verlet_lists=False``, +only the regular decomposition is used, but not the Verlet lists. :: + + import espressomd + system = espressomd.System(box_l=[1, 1, 1]) + system.cell_system.set_regular_decomposition(use_verlet_lists=True) + +The regular decomposition cellsystem is the default system and suits most +applications with short ranged interactions. The particles are divided +up spatially into small compartments, the cells, such that the cell size +is larger than the maximal interaction range. In this case interactions +only occur between particles in adjacent cells. Since the interaction +range should be much smaller than the total system size, leaving out all +interactions between non-adjacent cells can mean a tremendous speed-up. +Moreover, since for constant interaction range, the number of particles +in a cell depends only on the density. The number of interactions is +therefore of the order :math:`N` instead of order :math:`N^2` if one has to +calculate all pair interactions. + +With this scheme, there must be at least two cells per direction, +and at most 32 cells per direction for a cubic box geometry. +The number of cells per direction depends on the interaction range cutoff +:math:`l_{\mathrm{cut}}`, the Verlet list skin :math:`l_{\mathrm{skin}}` +and the box length :math:`l_{\mathrm{box}}`, and is determined automatically +by solving several equations. It can be useful to know how to estimate the +number of cells per direction, because it limits the number of MPI ranks +that can be allocated to an MPI-parallel simulation. As a rule of thumb, +for a cubic box geometry the number of cells per direction is often: + +.. math:: + + \left\lfloor \frac{l_{\mathrm{box}}}{l_{\mathrm{cut}} + l_{\mathrm{skin}}} \right\rfloor + +For example, in a system with box length 12, LJ cutoff 2.5 and Verlet +skin 0.4, the number of cells cannot be more than 4 in each direction. +A runtime error will be triggered during integration when running a +simulation with such a system and allocating more than 64 MPI ranks +in total, or more than 4 MPI ranks per direction. In this situation, +consider increasing the box size or decreasing the interaction cutoff +or Verlet list skin. + +.. _N-squared: + +N-squared +^^^^^^^^^ + +Invoking :py:meth:`~espressomd.cell_system.CellSystem.set_n_square` +selects the very primitive N-squared cellsystem, which calculates +the interactions for all particle pairs. Therefore it loops over all +particles, giving an unfavorable computation time scaling of +:math:`N^2`. However, algorithms like MMM1D or the plain Coulomb +interaction in the cell model require the calculation of all pair +interactions. :: + + import espressomd + system = espressomd.System(box_l=[1, 1, 1]) + system.cell_system.set_n_square() + +In a multiple processor environment, the N-squared cellsystem uses a +simple particle balancing scheme to have a nearly equal number of +particles per CPU, :math:`n` nodes have :math:`m` particles, and +:math:`p-n` nodes have :math:`m+1` particles, such that +:math:`n \cdot m + (p - n) \cdot (m + 1) = N`, the total number of particles. Therefore the +computational load should be balanced fairly equal among the nodes, with +one exception: This code always uses one CPU for the interaction between +two different nodes. For an odd number of nodes, this is fine, because +the total number of interactions to calculate is a multiple of the +number of nodes, but for an even number of nodes, for each of the +:math:`p-1` communication rounds, one processor is idle. + +E.g. for 2 processors, there are 3 interactions: 0-0, 1-1, 0-1. +Naturally, 0-0 and 1-1 are treated by processor 0 and 1, respectively. +But the 0-1 interaction is treated by node 1 alone, so the workload for +this node is twice as high. For 3 processors, the interactions are 0-0, +1-1, 2-2, 0-1, 1-2, 0-2. Of these interactions, node 0 treats 0-0 and +0-2, node 1 treats 1-1 and 0-1, and node 2 treats 2-2 and 1-2. + +Therefore it is highly recommended that you use N-squared only with an +odd number of nodes, if with multiple processors at all. + +.. _Hybrid decomposition: + +Hybrid decomposition +^^^^^^^^^^^^^^^^^^^^ + +If for a simulation setup the interaction range is much smaller than the +system size, use of a :ref:`Regular decomposition` leads to efficient +scaling behavior (order :math:`N` instead of order :math:`N^2`). +Consider a system with many small particles, e.g. a polymer solution. +There, already the addition of one single large particle increases the maximum +interaction range and thus the minimum cell size of the decomposition. +Due to this larger cell size, throughout the simulation box a large number +of non-interacting pairs of small particles is visited during the short +range calculation. This can considerably increase the computational cost of +the simulation. + +For such simulation setups, i.e. systems with a few large particles and much +more small particles, the hybrid decomposition can be used. This hybrid +decomposition is backed by two coupled particle decompositions which can +be used to efficiently deal with the differently sized particles. +Specifically that means putting the small particles into a +:ref:`Regular decomposition`. There, the minimum cell size is limited only +by the maximum interaction range of all particles within this decomposition. +The few large particles are put into a :ref:`N-squared` cellsystem. Particles +within this decomposition interact both, amongst each other and with all small +particles in the :ref:`Regular decomposition`. The hybrid decomposition can therefore +effectively recover the computational efficiency of the regular decomposition, +given that only a few large particles have been added. + +Invoking :py:meth:`~espressomd.cell_system.CellSystem.set_hybrid_decomposition` +selects the hybrid decomposition. :: + + system = espressomd.System(box_l=[10, 10, 10]) + system.cell_system.set_hybrid_decomposition(n_square_types={1, 3}, cutoff_regular=1.2) + +Here, ``n_square_types`` is a python set containing the types of particles to +put into the :ref:`N-squared` cellsystem, i.e. the particle types of the +large particles. Particles with other types will by default be put into the +:ref:`Regular decomposition`. Note that for now it is also necessary to manually set +the maximum cutoff to consider for interactions within the +:ref:`Regular decomposition`, i.e. the maximum interaction range among all +small particle types. Set this via the ``cutoff_regular`` parameter. + +.. note:: + + The hybrid particle decomposition has been added to |es| only recently and + for now should be considered an experimental feature. If you notice some unexpected + behavior please let us know via github or the mailing list. + diff --git a/doc4.2.2/_sources/under_the_hood.rst.txt b/doc4.2.2/_sources/under_the_hood.rst.txt new file mode 100644 index 0000000000..98e9760297 --- /dev/null +++ b/doc4.2.2/_sources/under_the_hood.rst.txt @@ -0,0 +1,110 @@ +.. _Under the hood: + +Under the hood +============== + +.. _Internal particle organization: + +Internal particle organization +------------------------------ + +Since basically all major parts of the main MD integration have to +access the particle data, efficient access to the particle data is +crucial for a fast MD code. Therefore the particle data needs some more +elaborate organization, which will be presented here. A particle itself +is represented by a structure (``Particle``) consisting of several +substructures (e.g. ``ParticlePosition``, ``ParticleForce`` or +``ParticleProperties``), which in turn represent basic physical properties +such as position, force or charge. The particles are organized in one or +more particle lists on each node, called ``CellPList``. The cells are +arranged by several possible systems, as described in :ref:`Cell systems`. +A cell system defines a way the particles are stored in |es|, i.e. +how they are distributed onto the processor nodes and how they are +organized on each of them. Moreover a cell system also defines +procedures to efficiently calculate the force, energy and pressure for +the short ranged interactions, since these can be heavily optimized +depending on the cell system. For example, the regular decomposition +cellsystem allows an order N interactions evaluation. + +Technically, a cell is organized as a dynamically growing array, not as +a list. This ensures that the data of all particles in a cell is stored +contiguously in the memory. The particle data is accessed transparently +through a set of methods common to all cell systems, which allocate the +cells, add new particles, retrieve particle information and are +responsible for communicating the particle data between the nodes. +Therefore most portions of the code can access the particle data safely +without direct knowledge of the currently used cell system. Only the +force, energy and pressure loops are implemented separately for each +cell model as explained above. + +The regular decomposition or link cell algorithm is implemented such +that the cells equal the cells, i.e. each cell is a separate particle +list. For an example let us assume that the simulation box has size +:math:`20\times 20\times 20` and that we assign 2 processors to the +simulation. Then each processor is responsible for the particles inside +a :math:`10\times 20\times 20` box. If the maximal interaction range is +1.2, the minimal possible cell size is 1.25 for 8 cells along the first +coordinate, allowing for a small skin of 0.05. If one chooses only 6 +boxes in the first coordinate, the skin depth increases to 0.467. In +this example we assume that the number of cells in the first coordinate +was chosen to be 6 and that the cells are cubic. One would then organize +the cells on each node in a :math:`6 \times 12 \times 12` cell grid +embedded at the center of a :math:`8 \times 14 \times 14` grid. +The additional cells around the cells containing the particles +represent the ghost shell in which the information of the ghost +particles from the neighboring nodes is stored. Therefore the particle +information stored on each node resides in 1568 particle lists of which +864 cells contain particles assigned to the node, the rest contain +information of particles from other nodes. + +Classically, the link cell algorithm is implemented differently. Instead +of having separate particle lists for each cell, there is only one +particle list per node, and the cells actually only contain pointers +to this particle list. This has the advantage that when particles are +moved from one cell to another on the same processor, only the pointers +have to be updated, which is much fewer data (4 rsp. 8 bytes) than the +full particle structure (around 192 bytes, depending on the features +compiled in). The data storage scheme of however requires to always move +the full particle data. Nevertheless, from our experience, the second +approach is 2-3 times faster than the classical one. + +To understand this, one has to know a little bit about the architecture +of modern computers. Most modern processors have a clock frequency above +1GHz and are able to execute nearly one instruction per clock tick. In +contrast, the memory runs at a clock speed around 200MHz. Modern +double data rate (DDR) RAM transfers up to 3.2GB/s at this clock speed +(at each edge of the clock signal 8 bytes are transferred). But in +addition to the data transfer speed, DDR RAM has some latency for +fetching the data, which can be up to 50ns in the worst case. Memory is +organized internally in pages or rows of typically 8KB size. The full +:math:`2\times 200` MHz data rate can only be achieved if the access is +within the same memory page (page hit), otherwise some latency has to be +added (page miss). The actual latency depends on some other aspects of +the memory organization which will not be discussed here, but the +penalty is at least 10ns, resulting in an effective memory transfer rate +of only 800MB/s. To remedy this, modern processors have a small amount +of low latency memory directly attached to the processor, the cache. + +The processor cache is organized in different levels. The level 1 (L1) +cache is built directly into the processor core, has no latency and +delivers the data immediately on demand, but has only a small size of +around 128KB. This is important since modern processors can issue +several simple operations such as additions simultaneously. The L2 cache +is larger, typically around 1MB, but is located outside the processor +core and delivers data at the processor clock rate or some fraction of +it. + +In a typical implementation of the link cell scheme, the order of the +particles is fairly random, determined e.g. by the order in which the +particles are set up or have been communicated across the processor +boundaries. The force loop therefore accesses the particle array in +arbitrary order, resulting in a lot of unfavorable page misses. In the +memory organization of |es|, the particles are accessed in a virtually +linear order. Because the force calculation goes through the cells in a +linear fashion, all accesses to a single cell occur close in time, for +the force calculation of the cell itself as well as for its neighbors. +Using the regular decomposition cell scheme, two cell layers have to be +kept in the processor cache. For 10000 particles and a typical cell grid +size of 20, these two cell layers consume roughly 200 KBytes, which +nearly fits into the L2 cache. Therefore every cell has to be read from +the main memory only once per force calculation. diff --git a/doc4.2.2/_sources/visualization.rst.txt b/doc4.2.2/_sources/visualization.rst.txt new file mode 100644 index 0000000000..3416d33631 --- /dev/null +++ b/doc4.2.2/_sources/visualization.rst.txt @@ -0,0 +1,301 @@ +.. _Online-visualization: + +Online-visualization +==================== + +|es| offers a direct rendering engine based on *pyopengl*. +It supports several features like shape-based constraints, +particle properties, the cell system, lattice-Boltzmann and more. +It can be adjusted with a large number of parameters to set colors, +materials, camera and interactive features like assigning callbacks +to user input. It requires the Python module *PyOpenGL*. +It is not meant to produce high quality renderings, but rather to +debug the simulation setup and equilibration process. + +.. _General usage: + +General usage +------------- + +The recommended usage is to instantiate the visualizer and pass it the +:class:`espressomd.System() ` object. Then write +your integration loop in a separate function, which is started in a +non-blocking thread. Whenever needed, call ``update()`` to synchronize +the renderer with your system. Finally start the blocking visualization +window with ``start()``. See the following minimal code example:: + + import espressomd + import espressomd.visualization + import threading + + system = espressomd.System(box_l=[10, 10, 10]) + system.cell_system.skin = 0.4 + system.time_step = 0.00001 + + system.part.add(pos=[1, 1, 1], v=[1, 0, 0]) + system.part.add(pos=[9, 9, 9], v=[0, 1, 0]) + + visualizer = espressomd.visualization.openGLLive(system) + + def main_thread(): + while True: + system.integrator.run(1) + visualizer.update() + + t = threading.Thread(target=main_thread) + t.daemon = True + t.start() + visualizer.start() + +.. _Setting up the visualizer: + +Setting up the visualizer +------------------------- + +:class:`espressomd.visualization.openGLLive()` + +The required parameter ``system`` is the :class:`~espressomd.system.System` object. +The optional keywords in ``**kwargs`` are used to adjust the appearance of the visualization. +These parameters have suitable default values for most simulations. + +:meth:`espressomd.visualization.openGLLive.update()` + +``update()`` synchronizes system and visualizer, handles keyboard events for +openGLLive. + +:meth:`espressomd.visualization.openGLLive.start()` + +``start()`` starts the blocking visualizer window. +Should be called after a separate thread containing ``update()`` has been started. + +:meth:`espressomd.visualization.openGLLive.register_callback()` + +Registers the method ``callback()``, which is called every ``interval`` milliseconds. Useful for +live plotting (see sample script :file:`/samples/visualization_ljliquid.py`). + +.. note:: + + The visualization of some constraints is either improved by (:class:`espressomd.shapes.SimplePore`) + or even relies on (:class:`espressomd.shapes.HollowConicalFrustum`) the presence of an installed + `OpenGL Extrusion library` on your system. Typically, the library will be available through the + default package manager of your operating system. On Ubuntu the required package is called ``libgle3-dev``, + on Fedora ``libgle`` -- just to name two examples. + + +.. _Running the visualizer: + +Running the visualizer +~~~~~~~~~~~~~~~~~~~~~~ + +:meth:`espressomd.visualization.openGLLive.run()` + +To visually debug your simulation, ``run(n)`` can be used to conveniently start +an integration loop with ``n`` integration steps in a separate thread once the +visualizer is initialized:: + + import espressomd + import espressomd.visualization + + system = espressomd.System(box_l=[10, 10, 10]) + system.cell_system.skin = 0.4 + system.time_step = 0.0001 + + system.part.add(pos=[1, 1, 1], v=[1, 0, 0]) + system.part.add(pos=[9, 9, 9], v=[0, 1, 0]) + + visualizer = espressomd.visualization.openGLLive(system, background_color=[1, 1, 1]) + visualizer.run(1) + + +.. _Screenshots: + +Screenshots +~~~~~~~~~~~ + +| :meth:`espressomd.visualization.openGLLive.screenshot()` + +The OpenGL visualizer can also be used for offline rendering. +After creating the visualizer object, call ``screenshot(path)`` +to save an image of your simulation to ``path``. Internally, the image is saved +with ``matplotlib.pyplot.imsave``, so the file format is specified by the +extension of the filename. The image size is determined by the keyword +argument ``window_size`` of the visualizer. This method can be used to create +screenshots without blocking the simulation script:: + + import espressomd + import espressomd.visualization + + system = espressomd.System(box_l=[10, 10, 10]) + system.cell_system.skin = 1.0 + system.time_step = 0.1 + + for i in range(1000): + system.part.add(pos=[5, 5, 5]) + + system.thermostat.set_langevin(kT=1, gamma=1, seed=42) + + visualizer = espressomd.visualization.openGLLive(system, window_size=[500, 500]) + + for i in range(100): + system.integrator.run(1) + visualizer.screenshot(f'screenshot_{i:0>5}.png') + + # You may consider creating a video with ffmpeg: + # ffmpeg -f image2 -framerate 30 -i 'screenshot_%05d.png' output.mp4 + +It is also possible to create a snapshot during online visualization. +Simply press the *enter* key to create a snapshot of the current window, +which saves it to :file:`_n.png` (with incrementing ``n``). + +.. _Colors and Materials: + +Colors and Materials +~~~~~~~~~~~~~~~~~~~~ + +Colors for particles, bonds and constraints are specified by RGB arrays. +Materials by an array for the ambient, diffuse, specular and shininess and opacity (ADSSO) +components. To distinguish particle groups, arrays of RGBA or ADSSO entries are +used, which are indexed circularly by the numerical particle type:: + + # Particle type 0 is red, type 1 is blue (type 2 is red etc).. + visualizer = espressomd.visualization.openGLLive(system, + particle_coloring='type', + particle_type_colors=[[1, 0, 0], [0, 0, 1]]) + +``particle_type_materials`` lists the materials by type:: + + # Particle type 0 is gold, type 1 is blue (type 2 is gold again etc). + visualizer = espressomd.visualization.openGLLive(system, + particle_coloring='type', + particle_type_colors=[[1, 1, 1], [0, 0, 1]], + particle_type_materials=["steel", "bright"]) + +Materials are stored in :attr:`espressomd.visualization.openGLLive.materials`. + +.. _Visualize vectorial properties: + +Visualize vectorial properties +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Most vectorial particle properties can be visualized by 3D-arrows on the +particles: + +* ``ext_force``: An external force. Activate with the keyword ``ext_force_arrows = True``. +* ``f``: The force acting on the particle. Activate with the keyword ``force_arrows = True``. +* ``v``: The velocity of the particle. Activate with the keyword ``velocity_arrows = True``. +* ``director``: A vector associated with the orientation of the particle. Activate with the keyword ``director_arrows = True``. + +Arrow colors, scales and radii can be adjusted. Again, the lists specifying +these quantities are indexed circularly by the numerical particle type. The +following code snippet demonstrates the visualization of the director property +and individual settings for two particle types (requires the ``ROTATION`` +feature):: + + import numpy as np + import espressomd + from espressomd.visualization import openGLLive, KeyboardButtonEvent, KeyboardFireEvent + + box_l = 10 + system = espressomd.System(box_l=[box_l, box_l, box_l]) + system.cell_system.skin = 0.4 + + system.time_step = 0.00001 + + visualizer = openGLLive(system, + director_arrows=True, + director_arrows_type_scale=[1.5, 1.0], + director_arrows_type_radii=[0.1, 0.4], + director_arrows_type_colors=[[1.0, 0, 0], [0, 1.0, 0]]) + + for i in range(10): + system.part.add(pos=np.random.random(3) * box_l, + rotation=[1, 1, 1], + ext_torque=[5, 0, 0], + v=[10, 0, 0], + type=0) + system.part.add(pos=np.random.random(3) * box_l, + rotation=[1, 1, 1], + ext_torque=[0, 5, 0], + v=[-10, 0, 0], + type=1) + + visualizer.run(1) + + + + +.. _Controls: + +Controls +~~~~~~~~ + +The camera can be controlled via mouse and keyboard: + +* hold left button: rotate the system +* hold right button: translate the system +* hold middle button: zoom / roll +* mouse wheel / key pair TG: zoom +* WASD-Keyboard control (WS: move forwards/backwards, AD: move sidewards) +* Key pairs QE, RF, ZC: rotate the system +* Double click on a particle: Show particle information +* Double click in empty space: Toggle system information +* Left/Right arrows: Cycle through particles +* Space: If started with ``run(n)``, this pauses the simulation +* Enter: Creates a snapshot of the current window and saves it to :file:`_n.png` (with incrementing ``n``) + +Additional input functionality for mouse and keyboard is possible by assigning +callbacks to specified keyboard or mouse buttons. This may be useful for +realtime adjustment of system parameters (temperature, interactions, particle +properties, etc.) or for demonstration purposes. The callbacks can be triggered +by a timer or keyboard input:: + + def foo(): + print("foo") + + # Registers timed calls of foo() + visualizer.register_callback(foo, interval=500) + + # Callbacks to control temperature + temperature = 1.0 + system.thermostat.set_langevin(kT=temperature, seed=42, gamma=1.0) + def increaseTemp(): + global temperature + temperature += 0.5 + system.thermostat.set_langevin(kT=temperature, gamma=1.0) + print(f"T = {system.thermostat.get_state()[0]['kT']:.1f}") + + def decreaseTemp(): + global temperature + temperature -= 0.5 + if temperature > 0: + system.thermostat.set_langevin(kT=temperature, gamma=1.0) + print(f"T = {system.thermostat.get_state()[0]['kT']:.1f}") + else: + temperature = 0 + system.thermostat.turn_off() + print("T = 0") + + # Registers input-based calls with keys Y and H + visualizer.keyboard_manager.register_button(KeyboardButtonEvent('y', KeyboardFireEvent.Hold, increaseTemp)) + visualizer.keyboard_manager.register_button(KeyboardButtonEvent('h', KeyboardFireEvent.Hold, decreaseTemp)) + + visualizer.run(1) + +Further examples can be found in :file:`/samples/billiard.py` or :file:`/samples/visualization_interactive.py`. + +.. _Dragging particles: + +Dragging particles +~~~~~~~~~~~~~~~~~~ + +With the keyword ``drag_enabled`` set to ``True``, the mouse can be used to +exert a force on particles in drag direction (scaled by ``drag_force`` and the +distance of particle and mouse cursor). + +.. _Visualization example scripts: + +Visualization example scripts +----------------------------- + +Various :ref:`Sample Scripts` can be found in :file:`/samples/visualization_*.py` +or in the :ref:`Tutorials` "Visualization" and "Charged Systems". diff --git a/doc4.2.2/_static/alabaster.css b/doc4.2.2/_static/alabaster.css new file mode 100644 index 0000000000..be0bd325c7 --- /dev/null +++ b/doc4.2.2/_static/alabaster.css @@ -0,0 +1,701 @@ +@import url("basic.css"); + +/* -- page layout ----------------------------------------------------------- */ + +body { + font-family: 'Lucida Grande', 'Arial', sans-serif; + font-size: 17px; + background-color: #fff; + color: #000; + margin: 0; + padding: 0; +} + + +div.document { + width: 1120px; + margin: 30px auto 0 auto; +} + +div.documentwrapper { + float: left; + width: 100%; +} + +div.bodywrapper { + margin: 0 0 0 260px; +} + +div.sphinxsidebar { + width: 260px; + font-size: 14px; + line-height: 1.5; +} + +hr { + border: 1px solid #B1B4B6; +} + +div.body { + background-color: #fff; + color: #3E4349; + padding: 0 30px 0 30px; +} + +div.body > .section { + text-align: left; +} + +div.footer { + width: 1120px; + margin: 20px auto 30px auto; + font-size: 14px; + color: #888; + text-align: right; +} + +div.footer a { + color: #888; +} + +p.caption { + font-family: 'Lucida Grande', 'Arial', sans-serif; + font-size: 17px; +} + + +div.relations { + display: none; +} + + +div.sphinxsidebar a { + color: #444; + text-decoration: none; + border-bottom: 1px dotted #999; +} + +div.sphinxsidebar a:hover { + border-bottom: 1px solid #999; +} + +div.sphinxsidebarwrapper { + padding: 18px 10px; +} + +div.sphinxsidebarwrapper p.logo { + padding: 0; + margin: -10px 0 0 0px; + text-align: center; +} + +div.sphinxsidebarwrapper h1.logo { + margin-top: -10px; + text-align: center; + margin-bottom: 5px; + text-align: left; +} + +div.sphinxsidebarwrapper h1.logo-name { + margin-top: 0px; +} + +div.sphinxsidebarwrapper p.blurb { + margin-top: 0; + font-style: normal; +} + +div.sphinxsidebar h3, +div.sphinxsidebar h4 { + font-family: 'Lucida Grande', 'Arial', sans-serif; + color: #444; + font-size: 24px; + font-weight: normal; + margin: 0 0 5px 0; + padding: 0; +} + +div.sphinxsidebar h4 { + font-size: 20px; +} + +div.sphinxsidebar h3 a { + color: #444; +} + +div.sphinxsidebar p.logo a, +div.sphinxsidebar h3 a, +div.sphinxsidebar p.logo a:hover, +div.sphinxsidebar h3 a:hover { + border: none; +} + +div.sphinxsidebar p { + color: #555; + margin: 10px 0; +} + +div.sphinxsidebar ul { + margin: 10px 0; + padding: 0; + color: #000; +} + +div.sphinxsidebar ul li.toctree-l1 > a { + font-size: 120%; +} + +div.sphinxsidebar ul li.toctree-l2 > a { + font-size: 110%; +} + +div.sphinxsidebar input { + border: 1px solid #CCC; + font-family: 'Lucida Grande', 'Arial', sans-serif; + font-size: 1em; +} + +div.sphinxsidebar hr { + border: none; + height: 1px; + color: #AAA; + background: #AAA; + + text-align: left; + margin-left: 0; + width: 50%; +} + +div.sphinxsidebar .badge { + border-bottom: none; +} + +div.sphinxsidebar .badge:hover { + border-bottom: none; +} + +/* To address an issue with donation coming after search */ +div.sphinxsidebar h3.donation { + margin-top: 10px; +} + +/* -- body styles ----------------------------------------------------------- */ + +a { + color: #004B6B; + text-decoration: underline; +} + +a:hover { + color: #6D4100; + text-decoration: underline; +} + +div.body h1, +div.body h2, +div.body h3, +div.body h4, +div.body h5, +div.body h6 { + font-family: 'Lucida Grande', 'Arial', sans-serif; + font-weight: normal; + margin: 30px 0px 10px 0px; + padding: 0; +} + +div.body h1 { margin-top: 0; padding-top: 0; font-size: 240%; } +div.body h2 { font-size: 180%; } +div.body h3 { font-size: 150%; } +div.body h4 { font-size: 130%; } +div.body h5 { font-size: 100%; } +div.body h6 { font-size: 100%; } + +a.headerlink { + color: #DDD; + padding: 0 4px; + text-decoration: none; +} + +a.headerlink:hover { + color: #444; + background: #EAEAEA; +} + +div.body p, div.body dd, div.body li { + line-height: 1.4em; +} + +div.admonition { + margin: 20px 0px; + padding: 10px 30px; + background-color: #EEE; + border: 1px solid #CCC; +} + +div.admonition tt.xref, div.admonition code.xref, div.admonition a tt { + background-color: #FBFBFB; + border-bottom: 1px solid #fafafa; +} + +div.admonition p.admonition-title { + font-family: 'Lucida Grande', 'Arial', sans-serif; + font-weight: normal; + font-size: 24px; + margin: 0 0 10px 0; + padding: 0; + line-height: 1; +} + +div.admonition p.last { + margin-bottom: 0; +} + +div.highlight { + background-color: #fff; +} + +dt:target, .highlight { + background: #FAF3E8; +} + +div.warning { + background-color: #FCC; + border: 1px solid #FAA; +} + +div.danger { + background-color: #FCC; + border: 1px solid #FAA; + -moz-box-shadow: 2px 2px 4px #D52C2C; + -webkit-box-shadow: 2px 2px 4px #D52C2C; + box-shadow: 2px 2px 4px #D52C2C; +} + +div.error { + background-color: #FCC; + border: 1px solid #FAA; + -moz-box-shadow: 2px 2px 4px #D52C2C; + -webkit-box-shadow: 2px 2px 4px #D52C2C; + box-shadow: 2px 2px 4px #D52C2C; +} + +div.caution { + background-color: #FCC; + border: 1px solid #FAA; +} + +div.attention { + background-color: #FCC; + border: 1px solid #FAA; +} + +div.important { + background-color: #EEE; + border: 1px solid #CCC; +} + +div.note { + background-color: #EEE; + border: 1px solid #CCC; +} + +div.tip { + background-color: #EEE; + border: 1px solid #CCC; +} + +div.hint { + background-color: #EEE; + border: 1px solid #CCC; +} + +div.seealso { + background-color: #EEE; + border: 1px solid #CCC; +} + +div.topic { + background-color: #EEE; +} + +p.admonition-title { + display: inline; +} + +p.admonition-title:after { + content: ":"; +} + +pre, tt, code { + font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; + font-size: 0.9em; +} + +.hll { + background-color: #FFC; + margin: 0 -12px; + padding: 0 12px; + display: block; +} + +img.screenshot { +} + +tt.descname, tt.descclassname, code.descname, code.descclassname { + font-size: 0.95em; +} + +tt.descname, code.descname { + padding-right: 0.08em; +} + +img.screenshot { + -moz-box-shadow: 2px 2px 4px #EEE; + -webkit-box-shadow: 2px 2px 4px #EEE; + box-shadow: 2px 2px 4px #EEE; +} + +table.docutils { + border: 1px solid #888; + -moz-box-shadow: 2px 2px 4px #EEE; + -webkit-box-shadow: 2px 2px 4px #EEE; + box-shadow: 2px 2px 4px #EEE; +} + +table.docutils td, table.docutils th { + border: 1px solid #888; + padding: 0.25em 0.7em; +} + +table.field-list, table.footnote { + border: none; + -moz-box-shadow: none; + -webkit-box-shadow: none; + box-shadow: none; +} + +table.footnote { + margin: 15px 0; + width: 100%; + border: 1px solid #EEE; + background: #FDFDFD; + font-size: 0.9em; +} + +table.footnote + table.footnote { + margin-top: -15px; + border-top: none; +} + +table.field-list th { + padding: 0 0.8em 0 0; +} + +table.field-list td { + padding: 0; +} + +table.field-list p { + margin-bottom: 0.8em; +} + +/* Cloned from + * https://github.com/sphinx-doc/sphinx/commit/ef60dbfce09286b20b7385333d63a60321784e68 + */ +.field-name { + -moz-hyphens: manual; + -ms-hyphens: manual; + -webkit-hyphens: manual; + hyphens: manual; +} + +table.footnote td.label { + width: .1px; + padding: 0.3em 0 0.3em 0.5em; +} + +table.footnote td { + padding: 0.3em 0.5em; +} + +dl { + margin: 0; + padding: 0; +} + +dl dd { + margin-left: 30px; +} + +blockquote { + margin: 0 0 0 30px; + padding: 0; +} + +ul, ol { + /* Matches the 30px from the narrow-screen "li > ul" selector below */ + margin: 10px 0 10px 30px; + padding: 0; +} + +pre { + background: #EEE; + padding: 7px 30px; + margin: 15px 0px; + line-height: 1.3em; +} + +div.viewcode-block:target { + background: #ffd; +} + +dl pre, blockquote pre, li pre { + margin-left: 0; + padding-left: 30px; +} + +tt, code { + background-color: #ecf0f3; + color: #222; + /* padding: 1px 2px; */ +} + +tt.xref, code.xref, a tt { + background-color: #FBFBFB; + border-bottom: 1px solid #fff; +} + +a.reference { + text-decoration: none; + border-bottom: 1px dotted #004B6B; +} + +/* Don't put an underline on images */ +a.image-reference, a.image-reference:hover { + border-bottom: none; +} + +a.reference:hover { + border-bottom: 1px solid #6D4100; +} + +a.footnote-reference { + text-decoration: none; + font-size: 0.7em; + vertical-align: top; + border-bottom: 1px dotted #004B6B; +} + +a.footnote-reference:hover { + border-bottom: 1px solid #6D4100; +} + +a:hover tt, a:hover code { + background: #EEE; +} + + +@media screen and (max-width: 870px) { + + div.sphinxsidebar { + display: none; + } + + div.document { + width: 100%; + + } + + div.documentwrapper { + margin-left: 0; + margin-top: 0; + margin-right: 0; + margin-bottom: 0; + } + + div.bodywrapper { + margin-top: 0; + margin-right: 0; + margin-bottom: 0; + margin-left: 0; + } + + ul { + margin-left: 0; + } + + li > ul { + /* Matches the 30px from the "ul, ol" selector above */ + margin-left: 30px; + } + + .document { + width: auto; + } + + .footer { + width: auto; + } + + .bodywrapper { + margin: 0; + } + + .footer { + width: auto; + } + + .github { + display: none; + } + + + +} + + + +@media screen and (max-width: 875px) { + + body { + margin: 0; + padding: 20px 30px; + } + + div.documentwrapper { + float: none; + background: #fff; + } + + div.sphinxsidebar { + display: block; + float: none; + width: 102.5%; + margin: 50px -30px -20px -30px; + padding: 10px 20px; + background: #333; + color: #FFF; + } + + div.sphinxsidebar h3, div.sphinxsidebar h4, div.sphinxsidebar p, + div.sphinxsidebar h3 a { + color: #fff; + } + + div.sphinxsidebar a { + color: #AAA; + } + + div.sphinxsidebar p.logo { + display: none; + } + + div.document { + width: 100%; + margin: 0; + } + + div.footer { + display: none; + } + + div.bodywrapper { + margin: 0; + } + + div.body { + min-height: 0; + padding: 0; + } + + .rtd_doc_footer { + display: none; + } + + .document { + width: auto; + } + + .footer { + width: auto; + } + + .footer { + width: auto; + } + + .github { + display: none; + } +} + + +/* misc. */ + +.revsys-inline { + display: none!important; +} + +/* Make nested-list/multi-paragraph items look better in Releases changelog + * pages. Without this, docutils' magical list fuckery causes inconsistent + * formatting between different release sub-lists. + */ +div#changelog > div.section > ul > li > p:only-child { + margin-bottom: 0; +} + +/* Hide fugly table cell borders in ..bibliography:: directive output */ +table.docutils.citation, table.docutils.citation td, table.docutils.citation th { + border: none; + /* Below needed in some edge cases; if not applied, bottom shadows appear */ + -moz-box-shadow: none; + -webkit-box-shadow: none; + box-shadow: none; +} + + +/* relbar */ + +.related { + line-height: 30px; + width: 100%; + font-size: 0.9rem; +} + +.related.top { + border-bottom: 1px solid #EEE; + margin-bottom: 20px; +} + +.related.bottom { + border-top: 1px solid #EEE; +} + +.related ul { + padding: 0; + margin: 0; + list-style: none; +} + +.related li { + display: inline; +} + +nav#rellinks { + float: right; +} + +nav#rellinks li+li:before { + content: "|"; +} + +nav#breadcrumbs li+li:before { + content: "\00BB"; +} + +/* Hide certain items when printing */ +@media print { + div.related { + display: none; + } +} \ No newline at end of file diff --git a/doc4.2.2/_static/basic.css b/doc4.2.2/_static/basic.css new file mode 100644 index 0000000000..3fc4f3dbec --- /dev/null +++ b/doc4.2.2/_static/basic.css @@ -0,0 +1,904 @@ +/* + * basic.css + * ~~~~~~~~~ + * + * Sphinx stylesheet -- basic theme. + * + * :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/* -- main layout ----------------------------------------------------------- */ + +div.clearer { + clear: both; +} + +div.section::after { + display: block; + content: ''; + clear: left; +} + +/* -- relbar ---------------------------------------------------------------- */ + +div.related { + width: 100%; + font-size: 90%; +} + +div.related h3 { + display: none; +} + +div.related ul { + margin: 0; + padding: 0 0 0 10px; + list-style: none; +} + +div.related li { + display: inline; +} + +div.related li.right { + float: right; + margin-right: 5px; +} + +/* -- sidebar --------------------------------------------------------------- */ + +div.sphinxsidebarwrapper { + padding: 10px 5px 0 10px; +} + +div.sphinxsidebar { + float: left; + width: 230px; + margin-left: -100%; + font-size: 90%; + word-wrap: break-word; + overflow-wrap : break-word; +} + +div.sphinxsidebar ul { + list-style: none; +} + +div.sphinxsidebar ul ul, +div.sphinxsidebar ul.want-points { + margin-left: 20px; + list-style: square; +} + +div.sphinxsidebar ul ul { + margin-top: 0; + margin-bottom: 0; +} + +div.sphinxsidebar form { + margin-top: 10px; +} + +div.sphinxsidebar input { + border: 1px solid #98dbcc; + font-family: sans-serif; + font-size: 1em; +} + +div.sphinxsidebar #searchbox form.search { + overflow: hidden; +} + +div.sphinxsidebar #searchbox input[type="text"] { + float: left; + width: 80%; + padding: 0.25em; + box-sizing: border-box; +} + +div.sphinxsidebar #searchbox input[type="submit"] { + float: left; + width: 20%; + border-left: none; + padding: 0.25em; + box-sizing: border-box; +} + + +img { + border: 0; + max-width: 100%; +} + +/* -- search page ----------------------------------------------------------- */ + +ul.search { + margin: 10px 0 0 20px; + padding: 0; +} + +ul.search li { + padding: 5px 0 5px 20px; + background-image: url(file.png); + background-repeat: no-repeat; + background-position: 0 7px; +} + +ul.search li a { + font-weight: bold; +} + +ul.search li p.context { + color: #888; + margin: 2px 0 0 30px; + text-align: left; +} + +ul.keywordmatches li.goodmatch a { + font-weight: bold; +} + +/* -- index page ------------------------------------------------------------ */ + +table.contentstable { + width: 90%; + margin-left: auto; + margin-right: auto; +} + +table.contentstable p.biglink { + line-height: 150%; +} + +a.biglink { + font-size: 1.3em; +} + +span.linkdescr { + font-style: italic; + padding-top: 5px; + font-size: 90%; +} + +/* -- general index --------------------------------------------------------- */ + +table.indextable { + width: 100%; +} + +table.indextable td { + text-align: left; + vertical-align: top; +} + +table.indextable ul { + margin-top: 0; + margin-bottom: 0; + list-style-type: none; +} + +table.indextable > tbody > tr > td > ul { + padding-left: 0em; +} + +table.indextable tr.pcap { + height: 10px; +} + +table.indextable tr.cap { + margin-top: 10px; + background-color: #f2f2f2; +} + +img.toggler { + margin-right: 3px; + margin-top: 3px; + cursor: pointer; +} + +div.modindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +div.genindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +/* -- domain module index --------------------------------------------------- */ + +table.modindextable td { + padding: 2px; + border-collapse: collapse; +} + +/* -- general body styles --------------------------------------------------- */ + +div.body { + min-width: 450px; + max-width: auto; +} + +div.body p, div.body dd, div.body li, div.body blockquote { + -moz-hyphens: auto; + -ms-hyphens: auto; + -webkit-hyphens: auto; + hyphens: auto; +} + +a.headerlink { + visibility: hidden; +} + +a.brackets:before, +span.brackets > a:before{ + content: "["; +} + +a.brackets:after, +span.brackets > a:after { + content: "]"; +} + +h1:hover > a.headerlink, +h2:hover > a.headerlink, +h3:hover > a.headerlink, +h4:hover > a.headerlink, +h5:hover > a.headerlink, +h6:hover > a.headerlink, +dt:hover > a.headerlink, +caption:hover > a.headerlink, +p.caption:hover > a.headerlink, +div.code-block-caption:hover > a.headerlink { + visibility: visible; +} + +div.body p.caption { + text-align: inherit; +} + +div.body td { + text-align: left; +} + +.first { + margin-top: 0 !important; +} + +p.rubric { + margin-top: 30px; + font-weight: bold; +} + +img.align-left, figure.align-left, .figure.align-left, object.align-left { + clear: left; + float: left; + margin-right: 1em; +} + +img.align-right, figure.align-right, .figure.align-right, object.align-right { + clear: right; + float: right; + margin-left: 1em; +} + +img.align-center, figure.align-center, .figure.align-center, object.align-center { + display: block; + margin-left: auto; + margin-right: auto; +} + +img.align-default, figure.align-default, .figure.align-default { + display: block; + margin-left: auto; + margin-right: auto; +} + +.align-left { + text-align: left; +} + +.align-center { + text-align: center; +} + +.align-default { + text-align: center; +} + +.align-right { + text-align: right; +} + +/* -- sidebars -------------------------------------------------------------- */ + +div.sidebar, +aside.sidebar { + margin: 0 0 0.5em 1em; + border: 1px solid #ddb; + padding: 7px; + background-color: #ffe; + width: 40%; + float: right; + clear: right; + overflow-x: auto; +} + +p.sidebar-title { + font-weight: bold; +} + +div.admonition, div.topic, blockquote { + clear: left; +} + +/* -- topics ---------------------------------------------------------------- */ + +div.topic { + border: 1px solid #ccc; + padding: 7px; + margin: 10px 0 10px 0; +} + +p.topic-title { + font-size: 1.1em; + font-weight: bold; + margin-top: 10px; +} + +/* -- admonitions ----------------------------------------------------------- */ + +div.admonition { + margin-top: 10px; + margin-bottom: 10px; + padding: 7px; +} + +div.admonition dt { + font-weight: bold; +} + +p.admonition-title { + margin: 0px 10px 5px 0px; + font-weight: bold; +} + +div.body p.centered { + text-align: center; + margin-top: 25px; +} + +/* -- content of sidebars/topics/admonitions -------------------------------- */ + +div.sidebar > :last-child, +aside.sidebar > :last-child, +div.topic > :last-child, +div.admonition > :last-child { + margin-bottom: 0; +} + +div.sidebar::after, +aside.sidebar::after, +div.topic::after, +div.admonition::after, +blockquote::after { + display: block; + content: ''; + clear: both; +} + +/* -- tables ---------------------------------------------------------------- */ + +table.docutils { + margin-top: 10px; + margin-bottom: 10px; + border: 0; + border-collapse: collapse; +} + +table.align-center { + margin-left: auto; + margin-right: auto; +} + +table.align-default { + margin-left: auto; + margin-right: auto; +} + +table caption span.caption-number { + font-style: italic; +} + +table caption span.caption-text { +} + +table.docutils td, table.docutils th { + padding: 1px 8px 1px 5px; + border-top: 0; + border-left: 0; + border-right: 0; + border-bottom: 1px solid #aaa; +} + +table.footnote td, table.footnote th { + border: 0 !important; +} + +th { + text-align: left; + padding-right: 5px; +} + +table.citation { + border-left: solid 1px gray; + margin-left: 1px; +} + +table.citation td { + border-bottom: none; +} + +th > :first-child, +td > :first-child { + margin-top: 0px; +} + +th > :last-child, +td > :last-child { + margin-bottom: 0px; +} + +/* -- figures --------------------------------------------------------------- */ + +div.figure, figure { + margin: 0.5em; + padding: 0.5em; +} + +div.figure p.caption, figcaption { + padding: 0.3em; +} + +div.figure p.caption span.caption-number, +figcaption span.caption-number { + font-style: italic; +} + +div.figure p.caption span.caption-text, +figcaption span.caption-text { +} + +/* -- field list styles ----------------------------------------------------- */ + +table.field-list td, table.field-list th { + border: 0 !important; +} + +.field-list ul { + margin: 0; + padding-left: 1em; +} + +.field-list p { + margin: 0; +} + +.field-name { + -moz-hyphens: manual; + -ms-hyphens: manual; + -webkit-hyphens: manual; + hyphens: manual; +} + +/* -- hlist styles ---------------------------------------------------------- */ + +table.hlist { + margin: 1em 0; +} + +table.hlist td { + vertical-align: top; +} + +/* -- object description styles --------------------------------------------- */ + +.sig { + font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; +} + +.sig-name, code.descname { + background-color: transparent; + font-weight: bold; +} + +.sig-name { + font-size: 1.1em; +} + +code.descname { + font-size: 1.2em; +} + +.sig-prename, code.descclassname { + background-color: transparent; +} + +.optional { + font-size: 1.3em; +} + +.sig-paren { + font-size: larger; +} + +.sig-param.n { + font-style: italic; +} + +/* C++ specific styling */ + +.sig-inline.c-texpr, +.sig-inline.cpp-texpr { + font-family: unset; +} + +.sig.c .k, .sig.c .kt, +.sig.cpp .k, .sig.cpp .kt { + color: #0033B3; +} + +.sig.c .m, +.sig.cpp .m { + color: #1750EB; +} + +.sig.c .s, .sig.c .sc, +.sig.cpp .s, .sig.cpp .sc { + color: #067D17; +} + + +/* -- other body styles ----------------------------------------------------- */ + +ol.arabic { + list-style: decimal; +} + +ol.loweralpha { + list-style: lower-alpha; +} + +ol.upperalpha { + list-style: upper-alpha; +} + +ol.lowerroman { + list-style: lower-roman; +} + +ol.upperroman { + list-style: upper-roman; +} + +:not(li) > ol > li:first-child > :first-child, +:not(li) > ul > li:first-child > :first-child { + margin-top: 0px; +} + +:not(li) > ol > li:last-child > :last-child, +:not(li) > ul > li:last-child > :last-child { + margin-bottom: 0px; +} + +ol.simple ol p, +ol.simple ul p, +ul.simple ol p, +ul.simple ul p { + margin-top: 0; +} + +ol.simple > li:not(:first-child) > p, +ul.simple > li:not(:first-child) > p { + margin-top: 0; +} + +ol.simple p, +ul.simple p { + margin-bottom: 0; +} + +dl.footnote > dt, +dl.citation > dt { + float: left; + margin-right: 0.5em; +} + +dl.footnote > dd, +dl.citation > dd { + margin-bottom: 0em; +} + +dl.footnote > dd:after, +dl.citation > dd:after { + content: ""; + clear: both; +} + +dl.field-list { + display: grid; + grid-template-columns: fit-content(30%) auto; +} + +dl.field-list > dt { + font-weight: bold; + word-break: break-word; + padding-left: 0.5em; + padding-right: 5px; +} + +dl.field-list > dt:after { + content: ":"; +} + +dl.field-list > dd { + padding-left: 0.5em; + margin-top: 0em; + margin-left: 0em; + margin-bottom: 0em; +} + +dl { + margin-bottom: 15px; +} + +dd > :first-child { + margin-top: 0px; +} + +dd ul, dd table { + margin-bottom: 10px; +} + +dd { + margin-top: 3px; + margin-bottom: 10px; + margin-left: 30px; +} + +dl > dd:last-child, +dl > dd:last-child > :last-child { + margin-bottom: 0; +} + +dt:target, span.highlighted { + background-color: #fbe54e; +} + +rect.highlighted { + fill: #fbe54e; +} + +dl.glossary dt { + font-weight: bold; + font-size: 1.1em; +} + +.versionmodified { + font-style: italic; +} + +.system-message { + background-color: #fda; + padding: 5px; + border: 3px solid red; +} + +.footnote:target { + background-color: #ffa; +} + +.line-block { + display: block; + margin-top: 1em; + margin-bottom: 1em; +} + +.line-block .line-block { + margin-top: 0; + margin-bottom: 0; + margin-left: 1.5em; +} + +.guilabel, .menuselection { + font-family: sans-serif; +} + +.accelerator { + text-decoration: underline; +} + +.classifier { + font-style: oblique; +} + +.classifier:before { + font-style: normal; + margin: 0.5em; + content: ":"; +} + +abbr, acronym { + border-bottom: dotted 1px; + cursor: help; +} + +/* -- code displays --------------------------------------------------------- */ + +pre { + overflow: auto; + overflow-y: hidden; /* fixes display issues on Chrome browsers */ +} + +pre, div[class*="highlight-"] { + clear: both; +} + +span.pre { + -moz-hyphens: none; + -ms-hyphens: none; + -webkit-hyphens: none; + hyphens: none; +} + +div[class*="highlight-"] { + margin: 1em 0; +} + +td.linenos pre { + border: 0; + background-color: transparent; + color: #aaa; +} + +table.highlighttable { + display: block; +} + +table.highlighttable tbody { + display: block; +} + +table.highlighttable tr { + display: flex; +} + +table.highlighttable td { + margin: 0; + padding: 0; +} + +table.highlighttable td.linenos { + padding-right: 0.5em; +} + +table.highlighttable td.code { + flex: 1; + overflow: hidden; +} + +.highlight .hll { + display: block; +} + +div.highlight pre, +table.highlighttable pre { + margin: 0; +} + +div.code-block-caption + div { + margin-top: 0; +} + +div.code-block-caption { + margin-top: 1em; + padding: 2px 5px; + font-size: small; +} + +div.code-block-caption code { + background-color: transparent; +} + +table.highlighttable td.linenos, +span.linenos, +div.highlight span.gp { /* gp: Generic.Prompt */ + user-select: none; + -webkit-user-select: text; /* Safari fallback only */ + -webkit-user-select: none; /* Chrome/Safari */ + -moz-user-select: none; /* Firefox */ + -ms-user-select: none; /* IE10+ */ +} + +div.code-block-caption span.caption-number { + padding: 0.1em 0.3em; + font-style: italic; +} + +div.code-block-caption span.caption-text { +} + +div.literal-block-wrapper { + margin: 1em 0; +} + +code.xref, a code { + background-color: transparent; + font-weight: bold; +} + +h1 code, h2 code, h3 code, h4 code, h5 code, h6 code { + background-color: transparent; +} + +.viewcode-link { + float: right; +} + +.viewcode-back { + float: right; + font-family: sans-serif; +} + +div.viewcode-block:target { + margin: -1px -10px; + padding: 0 10px; +} + +/* -- math display ---------------------------------------------------------- */ + +img.math { + vertical-align: middle; +} + +div.body div.math p { + text-align: center; +} + +span.eqno { + float: right; +} + +span.eqno a.headerlink { + position: absolute; + z-index: 1; +} + +div.math:hover a.headerlink { + visibility: visible; +} + +/* -- printout stylesheet --------------------------------------------------- */ + +@media print { + div.document, + div.documentwrapper, + div.bodywrapper { + margin: 0 !important; + width: 100%; + } + + div.sphinxsidebar, + div.related, + div.footer, + #top-link { + display: none; + } +} \ No newline at end of file diff --git a/doc4.2.2/_static/blockquotes.css b/doc4.2.2/_static/blockquotes.css new file mode 100644 index 0000000000..7548db82c7 --- /dev/null +++ b/doc4.2.2/_static/blockquotes.css @@ -0,0 +1,31 @@ +/* + * blockquotes.css + * ~~~~~~~~~~~~~~~ + * + * Extension for basic.css that highlights blockquotes. + * + */ + +/* -- general body styles --------------------------------------------------- */ + +div.body blockquote { + background: #f9f9f9; + border-left: 10px solid #ccc; + margin: 0.25em 10px; + padding: 0.35em 60px; + line-height: 1.45; + position: relative; + color: #383838; +} + +div.body blockquote:before { + color: #ccc; + display: block; + padding-left: 15px; + content: "\201C"; + font-size: 4.5em; + position: absolute; + left: 0px; + top: -5px; +} + diff --git a/doc4.2.2/_static/custom.css b/doc4.2.2/_static/custom.css new file mode 100644 index 0000000000..da4322630d --- /dev/null +++ b/doc4.2.2/_static/custom.css @@ -0,0 +1,52 @@ +/*****************************************/ +/* customization for the alabaster theme */ +/*****************************************/ + +/* color links to python objects */ +div.bodywrapper a.reference.internal code { + color: #355f7c; +} + +/* increase spacing between Python class methods */ +dl.py.method:not(:last-child) { + margin-bottom: 15px; +} + +/* decrease left-spacing in code blocks and notes */ +div.highlight pre { + padding-left: 20px; +} +div.admonition { + padding-left: 20px; +} + +/* make admonitions inline */ +div.admonition p.admonition-title { + font-size: 18px; + font-weight: bold; +} +div.admonition p { + display: inline; +} + +/* center main text by shifting it to the left by the width of the sidebar */ +div.document { + padding-right: 260px; +} + +/*************************************/ +/* customization for the basic theme */ +/*************************************/ + +/* remove automatic hyphenation */ +div.body p, div.body dd, div.body li, div.body blockquote { + -moz-hyphens: manual; + -ms-hyphens: manual; + -webkit-hyphens: manual; + hyphens: manual; +} + +/* hide todo notes */ +div.admonition-todo { + display: none; +} diff --git a/doc4.2.2/_static/doctools.js b/doc4.2.2/_static/doctools.js new file mode 100644 index 0000000000..8cbf1b161a --- /dev/null +++ b/doc4.2.2/_static/doctools.js @@ -0,0 +1,323 @@ +/* + * doctools.js + * ~~~~~~~~~~~ + * + * Sphinx JavaScript utilities for all documentation. + * + * :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/** + * select a different prefix for underscore + */ +$u = _.noConflict(); + +/** + * make the code below compatible with browsers without + * an installed firebug like debugger +if (!window.console || !console.firebug) { + var names = ["log", "debug", "info", "warn", "error", "assert", "dir", + "dirxml", "group", "groupEnd", "time", "timeEnd", "count", "trace", + "profile", "profileEnd"]; + window.console = {}; + for (var i = 0; i < names.length; ++i) + window.console[names[i]] = function() {}; +} + */ + +/** + * small helper function to urldecode strings + * + * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/decodeURIComponent#Decoding_query_parameters_from_a_URL + */ +jQuery.urldecode = function(x) { + if (!x) { + return x + } + return decodeURIComponent(x.replace(/\+/g, ' ')); +}; + +/** + * small helper function to urlencode strings + */ +jQuery.urlencode = encodeURIComponent; + +/** + * This function returns the parsed url parameters of the + * current request. Multiple values per key are supported, + * it will always return arrays of strings for the value parts. + */ +jQuery.getQueryParameters = function(s) { + if (typeof s === 'undefined') + s = document.location.search; + var parts = s.substr(s.indexOf('?') + 1).split('&'); + var result = {}; + for (var i = 0; i < parts.length; i++) { + var tmp = parts[i].split('=', 2); + var key = jQuery.urldecode(tmp[0]); + var value = jQuery.urldecode(tmp[1]); + if (key in result) + result[key].push(value); + else + result[key] = [value]; + } + return result; +}; + +/** + * highlight a given string on a jquery object by wrapping it in + * span elements with the given class name. + */ +jQuery.fn.highlightText = function(text, className) { + function highlight(node, addItems) { + if (node.nodeType === 3) { + var val = node.nodeValue; + var pos = val.toLowerCase().indexOf(text); + if (pos >= 0 && + !jQuery(node.parentNode).hasClass(className) && + !jQuery(node.parentNode).hasClass("nohighlight")) { + var span; + var isInSVG = jQuery(node).closest("body, svg, foreignObject").is("svg"); + if (isInSVG) { + span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); + } else { + span = document.createElement("span"); + span.className = className; + } + span.appendChild(document.createTextNode(val.substr(pos, text.length))); + node.parentNode.insertBefore(span, node.parentNode.insertBefore( + document.createTextNode(val.substr(pos + text.length)), + node.nextSibling)); + node.nodeValue = val.substr(0, pos); + if (isInSVG) { + var rect = document.createElementNS("http://www.w3.org/2000/svg", "rect"); + var bbox = node.parentElement.getBBox(); + rect.x.baseVal.value = bbox.x; + rect.y.baseVal.value = bbox.y; + rect.width.baseVal.value = bbox.width; + rect.height.baseVal.value = bbox.height; + rect.setAttribute('class', className); + addItems.push({ + "parent": node.parentNode, + "target": rect}); + } + } + } + else if (!jQuery(node).is("button, select, textarea")) { + jQuery.each(node.childNodes, function() { + highlight(this, addItems); + }); + } + } + var addItems = []; + var result = this.each(function() { + highlight(this, addItems); + }); + for (var i = 0; i < addItems.length; ++i) { + jQuery(addItems[i].parent).before(addItems[i].target); + } + return result; +}; + +/* + * backward compatibility for jQuery.browser + * This will be supported until firefox bug is fixed. + */ +if (!jQuery.browser) { + jQuery.uaMatch = function(ua) { + ua = ua.toLowerCase(); + + var match = /(chrome)[ \/]([\w.]+)/.exec(ua) || + /(webkit)[ \/]([\w.]+)/.exec(ua) || + /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) || + /(msie) ([\w.]+)/.exec(ua) || + ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || + []; + + return { + browser: match[ 1 ] || "", + version: match[ 2 ] || "0" + }; + }; + jQuery.browser = {}; + jQuery.browser[jQuery.uaMatch(navigator.userAgent).browser] = true; +} + +/** + * Small JavaScript module for the documentation. + */ +var Documentation = { + + init : function() { + this.fixFirefoxAnchorBug(); + this.highlightSearchWords(); + this.initIndexTable(); + if (DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) { + this.initOnKeyListeners(); + } + }, + + /** + * i18n support + */ + TRANSLATIONS : {}, + PLURAL_EXPR : function(n) { return n === 1 ? 0 : 1; }, + LOCALE : 'unknown', + + // gettext and ngettext don't access this so that the functions + // can safely bound to a different name (_ = Documentation.gettext) + gettext : function(string) { + var translated = Documentation.TRANSLATIONS[string]; + if (typeof translated === 'undefined') + return string; + return (typeof translated === 'string') ? translated : translated[0]; + }, + + ngettext : function(singular, plural, n) { + var translated = Documentation.TRANSLATIONS[singular]; + if (typeof translated === 'undefined') + return (n == 1) ? singular : plural; + return translated[Documentation.PLURALEXPR(n)]; + }, + + addTranslations : function(catalog) { + for (var key in catalog.messages) + this.TRANSLATIONS[key] = catalog.messages[key]; + this.PLURAL_EXPR = new Function('n', 'return +(' + catalog.plural_expr + ')'); + this.LOCALE = catalog.locale; + }, + + /** + * add context elements like header anchor links + */ + addContextElements : function() { + $('div[id] > :header:first').each(function() { + $('\u00B6'). + attr('href', '#' + this.id). + attr('title', _('Permalink to this headline')). + appendTo(this); + }); + $('dt[id]').each(function() { + $('\u00B6'). + attr('href', '#' + this.id). + attr('title', _('Permalink to this definition')). + appendTo(this); + }); + }, + + /** + * workaround a firefox stupidity + * see: https://bugzilla.mozilla.org/show_bug.cgi?id=645075 + */ + fixFirefoxAnchorBug : function() { + if (document.location.hash && $.browser.mozilla) + window.setTimeout(function() { + document.location.href += ''; + }, 10); + }, + + /** + * highlight the search words provided in the url in the text + */ + highlightSearchWords : function() { + var params = $.getQueryParameters(); + var terms = (params.highlight) ? params.highlight[0].split(/\s+/) : []; + if (terms.length) { + var body = $('div.body'); + if (!body.length) { + body = $('body'); + } + window.setTimeout(function() { + $.each(terms, function() { + body.highlightText(this.toLowerCase(), 'highlighted'); + }); + }, 10); + $('') + .appendTo($('#searchbox')); + } + }, + + /** + * init the domain index toggle buttons + */ + initIndexTable : function() { + var togglers = $('img.toggler').click(function() { + var src = $(this).attr('src'); + var idnum = $(this).attr('id').substr(7); + $('tr.cg-' + idnum).toggle(); + if (src.substr(-9) === 'minus.png') + $(this).attr('src', src.substr(0, src.length-9) + 'plus.png'); + else + $(this).attr('src', src.substr(0, src.length-8) + 'minus.png'); + }).css('display', ''); + if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) { + togglers.click(); + } + }, + + /** + * helper function to hide the search marks again + */ + hideSearchWords : function() { + $('#searchbox .highlight-link').fadeOut(300); + $('span.highlighted').removeClass('highlighted'); + }, + + /** + * make the url absolute + */ + makeURL : function(relativeURL) { + return DOCUMENTATION_OPTIONS.URL_ROOT + '/' + relativeURL; + }, + + /** + * get the current relative url + */ + getCurrentURL : function() { + var path = document.location.pathname; + var parts = path.split(/\//); + $.each(DOCUMENTATION_OPTIONS.URL_ROOT.split(/\//), function() { + if (this === '..') + parts.pop(); + }); + var url = parts.join('/'); + return path.substring(url.lastIndexOf('/') + 1, path.length - 1); + }, + + initOnKeyListeners: function() { + $(document).keydown(function(event) { + var activeElementType = document.activeElement.tagName; + // don't navigate when in search box, textarea, dropdown or button + if (activeElementType !== 'TEXTAREA' && activeElementType !== 'INPUT' && activeElementType !== 'SELECT' + && activeElementType !== 'BUTTON' && !event.altKey && !event.ctrlKey && !event.metaKey + && !event.shiftKey) { + switch (event.keyCode) { + case 37: // left + var prevHref = $('link[rel="prev"]').prop('href'); + if (prevHref) { + window.location.href = prevHref; + return false; + } + break; + case 39: // right + var nextHref = $('link[rel="next"]').prop('href'); + if (nextHref) { + window.location.href = nextHref; + return false; + } + break; + } + } + }); + } +}; + +// quick alias for translations +_ = Documentation.gettext; + +$(document).ready(function() { + Documentation.init(); +}); diff --git a/doc4.2.2/_static/documentation_options.js b/doc4.2.2/_static/documentation_options.js new file mode 100644 index 0000000000..1b8ab06346 --- /dev/null +++ b/doc4.2.2/_static/documentation_options.js @@ -0,0 +1,12 @@ +var DOCUMENTATION_OPTIONS = { + URL_ROOT: document.getElementById("documentation_options").getAttribute('data-url_root'), + VERSION: '4.2.2', + LANGUAGE: 'en', + COLLAPSE_INDEX: false, + BUILDER: 'html', + FILE_SUFFIX: '.html', + LINK_SUFFIX: '.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt', + NAVIGATION_WITH_KEYS: false +}; \ No newline at end of file diff --git a/doc4.2.2/_static/file.png b/doc4.2.2/_static/file.png new file mode 100644 index 0000000000..a858a410e4 Binary files /dev/null and b/doc4.2.2/_static/file.png differ diff --git a/doc4.2.2/_static/jquery-3.5.1.js b/doc4.2.2/_static/jquery-3.5.1.js new file mode 100644 index 0000000000..50937333b9 --- /dev/null +++ b/doc4.2.2/_static/jquery-3.5.1.js @@ -0,0 +1,10872 @@ +/*! + * jQuery JavaScript Library v3.5.1 + * https://jquery.com/ + * + * Includes Sizzle.js + * https://sizzlejs.com/ + * + * Copyright JS Foundation and other contributors + * Released under the MIT license + * https://jquery.org/license + * + * Date: 2020-05-04T22:49Z + */ +( function( global, factory ) { + + "use strict"; + + if ( typeof module === "object" && typeof module.exports === "object" ) { + + // For CommonJS and CommonJS-like environments where a proper `window` + // is present, execute the factory and get jQuery. + // For environments that do not have a `window` with a `document` + // (such as Node.js), expose a factory as module.exports. + // This accentuates the need for the creation of a real `window`. + // e.g. var jQuery = require("jquery")(window); + // See ticket #14549 for more info. + module.exports = global.document ? + factory( global, true ) : + function( w ) { + if ( !w.document ) { + throw new Error( "jQuery requires a window with a document" ); + } + return factory( w ); + }; + } else { + factory( global ); + } + +// Pass this if window is not defined yet +} )( typeof window !== "undefined" ? window : this, function( window, noGlobal ) { + +// Edge <= 12 - 13+, Firefox <=18 - 45+, IE 10 - 11, Safari 5.1 - 9+, iOS 6 - 9.1 +// throw exceptions when non-strict code (e.g., ASP.NET 4.5) accesses strict mode +// arguments.callee.caller (trac-13335). But as of jQuery 3.0 (2016), strict mode should be common +// enough that all such attempts are guarded in a try block. +"use strict"; + +var arr = []; + +var getProto = Object.getPrototypeOf; + +var slice = arr.slice; + +var flat = arr.flat ? function( array ) { + return arr.flat.call( array ); +} : function( array ) { + return arr.concat.apply( [], array ); +}; + + +var push = arr.push; + +var indexOf = arr.indexOf; + +var class2type = {}; + +var toString = class2type.toString; + +var hasOwn = class2type.hasOwnProperty; + +var fnToString = hasOwn.toString; + +var ObjectFunctionString = fnToString.call( Object ); + +var support = {}; + +var isFunction = function isFunction( obj ) { + + // Support: Chrome <=57, Firefox <=52 + // In some browsers, typeof returns "function" for HTML elements + // (i.e., `typeof document.createElement( "object" ) === "function"`). + // We don't want to classify *any* DOM node as a function. + return typeof obj === "function" && typeof obj.nodeType !== "number"; + }; + + +var isWindow = function isWindow( obj ) { + return obj != null && obj === obj.window; + }; + + +var document = window.document; + + + + var preservedScriptAttributes = { + type: true, + src: true, + nonce: true, + noModule: true + }; + + function DOMEval( code, node, doc ) { + doc = doc || document; + + var i, val, + script = doc.createElement( "script" ); + + script.text = code; + if ( node ) { + for ( i in preservedScriptAttributes ) { + + // Support: Firefox 64+, Edge 18+ + // Some browsers don't support the "nonce" property on scripts. + // On the other hand, just using `getAttribute` is not enough as + // the `nonce` attribute is reset to an empty string whenever it + // becomes browsing-context connected. + // See https://github.com/whatwg/html/issues/2369 + // See https://html.spec.whatwg.org/#nonce-attributes + // The `node.getAttribute` check was added for the sake of + // `jQuery.globalEval` so that it can fake a nonce-containing node + // via an object. + val = node[ i ] || node.getAttribute && node.getAttribute( i ); + if ( val ) { + script.setAttribute( i, val ); + } + } + } + doc.head.appendChild( script ).parentNode.removeChild( script ); + } + + +function toType( obj ) { + if ( obj == null ) { + return obj + ""; + } + + // Support: Android <=2.3 only (functionish RegExp) + return typeof obj === "object" || typeof obj === "function" ? + class2type[ toString.call( obj ) ] || "object" : + typeof obj; +} +/* global Symbol */ +// Defining this global in .eslintrc.json would create a danger of using the global +// unguarded in another place, it seems safer to define global only for this module + + + +var + version = "3.5.1", + + // Define a local copy of jQuery + jQuery = function( selector, context ) { + + // The jQuery object is actually just the init constructor 'enhanced' + // Need init if jQuery is called (just allow error to be thrown if not included) + return new jQuery.fn.init( selector, context ); + }; + +jQuery.fn = jQuery.prototype = { + + // The current version of jQuery being used + jquery: version, + + constructor: jQuery, + + // The default length of a jQuery object is 0 + length: 0, + + toArray: function() { + return slice.call( this ); + }, + + // Get the Nth element in the matched element set OR + // Get the whole matched element set as a clean array + get: function( num ) { + + // Return all the elements in a clean array + if ( num == null ) { + return slice.call( this ); + } + + // Return just the one element from the set + return num < 0 ? this[ num + this.length ] : this[ num ]; + }, + + // Take an array of elements and push it onto the stack + // (returning the new matched element set) + pushStack: function( elems ) { + + // Build a new jQuery matched element set + var ret = jQuery.merge( this.constructor(), elems ); + + // Add the old object onto the stack (as a reference) + ret.prevObject = this; + + // Return the newly-formed element set + return ret; + }, + + // Execute a callback for every element in the matched set. + each: function( callback ) { + return jQuery.each( this, callback ); + }, + + map: function( callback ) { + return this.pushStack( jQuery.map( this, function( elem, i ) { + return callback.call( elem, i, elem ); + } ) ); + }, + + slice: function() { + return this.pushStack( slice.apply( this, arguments ) ); + }, + + first: function() { + return this.eq( 0 ); + }, + + last: function() { + return this.eq( -1 ); + }, + + even: function() { + return this.pushStack( jQuery.grep( this, function( _elem, i ) { + return ( i + 1 ) % 2; + } ) ); + }, + + odd: function() { + return this.pushStack( jQuery.grep( this, function( _elem, i ) { + return i % 2; + } ) ); + }, + + eq: function( i ) { + var len = this.length, + j = +i + ( i < 0 ? len : 0 ); + return this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] ); + }, + + end: function() { + return this.prevObject || this.constructor(); + }, + + // For internal use only. + // Behaves like an Array's method, not like a jQuery method. + push: push, + sort: arr.sort, + splice: arr.splice +}; + +jQuery.extend = jQuery.fn.extend = function() { + var options, name, src, copy, copyIsArray, clone, + target = arguments[ 0 ] || {}, + i = 1, + length = arguments.length, + deep = false; + + // Handle a deep copy situation + if ( typeof target === "boolean" ) { + deep = target; + + // Skip the boolean and the target + target = arguments[ i ] || {}; + i++; + } + + // Handle case when target is a string or something (possible in deep copy) + if ( typeof target !== "object" && !isFunction( target ) ) { + target = {}; + } + + // Extend jQuery itself if only one argument is passed + if ( i === length ) { + target = this; + i--; + } + + for ( ; i < length; i++ ) { + + // Only deal with non-null/undefined values + if ( ( options = arguments[ i ] ) != null ) { + + // Extend the base object + for ( name in options ) { + copy = options[ name ]; + + // Prevent Object.prototype pollution + // Prevent never-ending loop + if ( name === "__proto__" || target === copy ) { + continue; + } + + // Recurse if we're merging plain objects or arrays + if ( deep && copy && ( jQuery.isPlainObject( copy ) || + ( copyIsArray = Array.isArray( copy ) ) ) ) { + src = target[ name ]; + + // Ensure proper type for the source value + if ( copyIsArray && !Array.isArray( src ) ) { + clone = []; + } else if ( !copyIsArray && !jQuery.isPlainObject( src ) ) { + clone = {}; + } else { + clone = src; + } + copyIsArray = false; + + // Never move original objects, clone them + target[ name ] = jQuery.extend( deep, clone, copy ); + + // Don't bring in undefined values + } else if ( copy !== undefined ) { + target[ name ] = copy; + } + } + } + } + + // Return the modified object + return target; +}; + +jQuery.extend( { + + // Unique for each copy of jQuery on the page + expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ), + + // Assume jQuery is ready without the ready module + isReady: true, + + error: function( msg ) { + throw new Error( msg ); + }, + + noop: function() {}, + + isPlainObject: function( obj ) { + var proto, Ctor; + + // Detect obvious negatives + // Use toString instead of jQuery.type to catch host objects + if ( !obj || toString.call( obj ) !== "[object Object]" ) { + return false; + } + + proto = getProto( obj ); + + // Objects with no prototype (e.g., `Object.create( null )`) are plain + if ( !proto ) { + return true; + } + + // Objects with prototype are plain iff they were constructed by a global Object function + Ctor = hasOwn.call( proto, "constructor" ) && proto.constructor; + return typeof Ctor === "function" && fnToString.call( Ctor ) === ObjectFunctionString; + }, + + isEmptyObject: function( obj ) { + var name; + + for ( name in obj ) { + return false; + } + return true; + }, + + // Evaluates a script in a provided context; falls back to the global one + // if not specified. + globalEval: function( code, options, doc ) { + DOMEval( code, { nonce: options && options.nonce }, doc ); + }, + + each: function( obj, callback ) { + var length, i = 0; + + if ( isArrayLike( obj ) ) { + length = obj.length; + for ( ; i < length; i++ ) { + if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { + break; + } + } + } else { + for ( i in obj ) { + if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { + break; + } + } + } + + return obj; + }, + + // results is for internal usage only + makeArray: function( arr, results ) { + var ret = results || []; + + if ( arr != null ) { + if ( isArrayLike( Object( arr ) ) ) { + jQuery.merge( ret, + typeof arr === "string" ? + [ arr ] : arr + ); + } else { + push.call( ret, arr ); + } + } + + return ret; + }, + + inArray: function( elem, arr, i ) { + return arr == null ? -1 : indexOf.call( arr, elem, i ); + }, + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + merge: function( first, second ) { + var len = +second.length, + j = 0, + i = first.length; + + for ( ; j < len; j++ ) { + first[ i++ ] = second[ j ]; + } + + first.length = i; + + return first; + }, + + grep: function( elems, callback, invert ) { + var callbackInverse, + matches = [], + i = 0, + length = elems.length, + callbackExpect = !invert; + + // Go through the array, only saving the items + // that pass the validator function + for ( ; i < length; i++ ) { + callbackInverse = !callback( elems[ i ], i ); + if ( callbackInverse !== callbackExpect ) { + matches.push( elems[ i ] ); + } + } + + return matches; + }, + + // arg is for internal usage only + map: function( elems, callback, arg ) { + var length, value, + i = 0, + ret = []; + + // Go through the array, translating each of the items to their new values + if ( isArrayLike( elems ) ) { + length = elems.length; + for ( ; i < length; i++ ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret.push( value ); + } + } + + // Go through every key on the object, + } else { + for ( i in elems ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret.push( value ); + } + } + } + + // Flatten any nested arrays + return flat( ret ); + }, + + // A global GUID counter for objects + guid: 1, + + // jQuery.support is not used in Core but other projects attach their + // properties to it so it needs to exist. + support: support +} ); + +if ( typeof Symbol === "function" ) { + jQuery.fn[ Symbol.iterator ] = arr[ Symbol.iterator ]; +} + +// Populate the class2type map +jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ), +function( _i, name ) { + class2type[ "[object " + name + "]" ] = name.toLowerCase(); +} ); + +function isArrayLike( obj ) { + + // Support: real iOS 8.2 only (not reproducible in simulator) + // `in` check used to prevent JIT error (gh-2145) + // hasOwn isn't used here due to false negatives + // regarding Nodelist length in IE + var length = !!obj && "length" in obj && obj.length, + type = toType( obj ); + + if ( isFunction( obj ) || isWindow( obj ) ) { + return false; + } + + return type === "array" || length === 0 || + typeof length === "number" && length > 0 && ( length - 1 ) in obj; +} +var Sizzle = +/*! + * Sizzle CSS Selector Engine v2.3.5 + * https://sizzlejs.com/ + * + * Copyright JS Foundation and other contributors + * Released under the MIT license + * https://js.foundation/ + * + * Date: 2020-03-14 + */ +( function( window ) { +var i, + support, + Expr, + getText, + isXML, + tokenize, + compile, + select, + outermostContext, + sortInput, + hasDuplicate, + + // Local document vars + setDocument, + document, + docElem, + documentIsHTML, + rbuggyQSA, + rbuggyMatches, + matches, + contains, + + // Instance-specific data + expando = "sizzle" + 1 * new Date(), + preferredDoc = window.document, + dirruns = 0, + done = 0, + classCache = createCache(), + tokenCache = createCache(), + compilerCache = createCache(), + nonnativeSelectorCache = createCache(), + sortOrder = function( a, b ) { + if ( a === b ) { + hasDuplicate = true; + } + return 0; + }, + + // Instance methods + hasOwn = ( {} ).hasOwnProperty, + arr = [], + pop = arr.pop, + pushNative = arr.push, + push = arr.push, + slice = arr.slice, + + // Use a stripped-down indexOf as it's faster than native + // https://jsperf.com/thor-indexof-vs-for/5 + indexOf = function( list, elem ) { + var i = 0, + len = list.length; + for ( ; i < len; i++ ) { + if ( list[ i ] === elem ) { + return i; + } + } + return -1; + }, + + booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|" + + "ismap|loop|multiple|open|readonly|required|scoped", + + // Regular expressions + + // http://www.w3.org/TR/css3-selectors/#whitespace + whitespace = "[\\x20\\t\\r\\n\\f]", + + // https://www.w3.org/TR/css-syntax-3/#ident-token-diagram + identifier = "(?:\\\\[\\da-fA-F]{1,6}" + whitespace + + "?|\\\\[^\\r\\n\\f]|[\\w-]|[^\0-\\x7f])+", + + // Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors + attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace + + + // Operator (capture 2) + "*([*^$|!~]?=)" + whitespace + + + // "Attribute values must be CSS identifiers [capture 5] + // or strings [capture 3 or capture 4]" + "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + + whitespace + "*\\]", + + pseudos = ":(" + identifier + ")(?:\\((" + + + // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments: + // 1. quoted (capture 3; capture 4 or capture 5) + "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" + + + // 2. simple (capture 6) + "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" + + + // 3. anything else (capture 2) + ".*" + + ")\\)|)", + + // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter + rwhitespace = new RegExp( whitespace + "+", "g" ), + rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + + whitespace + "+$", "g" ), + + rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ), + rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + + "*" ), + rdescend = new RegExp( whitespace + "|>" ), + + rpseudo = new RegExp( pseudos ), + ridentifier = new RegExp( "^" + identifier + "$" ), + + matchExpr = { + "ID": new RegExp( "^#(" + identifier + ")" ), + "CLASS": new RegExp( "^\\.(" + identifier + ")" ), + "TAG": new RegExp( "^(" + identifier + "|[*])" ), + "ATTR": new RegExp( "^" + attributes ), + "PSEUDO": new RegExp( "^" + pseudos ), + "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + + whitespace + "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + + whitespace + "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), + "bool": new RegExp( "^(?:" + booleans + ")$", "i" ), + + // For use in libraries implementing .is() + // We use this for POS matching in `select` + "needsContext": new RegExp( "^" + whitespace + + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + whitespace + + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" ) + }, + + rhtml = /HTML$/i, + rinputs = /^(?:input|select|textarea|button)$/i, + rheader = /^h\d$/i, + + rnative = /^[^{]+\{\s*\[native \w/, + + // Easily-parseable/retrievable ID or TAG or CLASS selectors + rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, + + rsibling = /[+~]/, + + // CSS escapes + // http://www.w3.org/TR/CSS21/syndata.html#escaped-characters + runescape = new RegExp( "\\\\[\\da-fA-F]{1,6}" + whitespace + "?|\\\\([^\\r\\n\\f])", "g" ), + funescape = function( escape, nonHex ) { + var high = "0x" + escape.slice( 1 ) - 0x10000; + + return nonHex ? + + // Strip the backslash prefix from a non-hex escape sequence + nonHex : + + // Replace a hexadecimal escape sequence with the encoded Unicode code point + // Support: IE <=11+ + // For values outside the Basic Multilingual Plane (BMP), manually construct a + // surrogate pair + high < 0 ? + String.fromCharCode( high + 0x10000 ) : + String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 ); + }, + + // CSS string/identifier serialization + // https://drafts.csswg.org/cssom/#common-serializing-idioms + rcssescape = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g, + fcssescape = function( ch, asCodePoint ) { + if ( asCodePoint ) { + + // U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER + if ( ch === "\0" ) { + return "\uFFFD"; + } + + // Control characters and (dependent upon position) numbers get escaped as code points + return ch.slice( 0, -1 ) + "\\" + + ch.charCodeAt( ch.length - 1 ).toString( 16 ) + " "; + } + + // Other potentially-special ASCII characters get backslash-escaped + return "\\" + ch; + }, + + // Used for iframes + // See setDocument() + // Removing the function wrapper causes a "Permission Denied" + // error in IE + unloadHandler = function() { + setDocument(); + }, + + inDisabledFieldset = addCombinator( + function( elem ) { + return elem.disabled === true && elem.nodeName.toLowerCase() === "fieldset"; + }, + { dir: "parentNode", next: "legend" } + ); + +// Optimize for push.apply( _, NodeList ) +try { + push.apply( + ( arr = slice.call( preferredDoc.childNodes ) ), + preferredDoc.childNodes + ); + + // Support: Android<4.0 + // Detect silently failing push.apply + // eslint-disable-next-line no-unused-expressions + arr[ preferredDoc.childNodes.length ].nodeType; +} catch ( e ) { + push = { apply: arr.length ? + + // Leverage slice if possible + function( target, els ) { + pushNative.apply( target, slice.call( els ) ); + } : + + // Support: IE<9 + // Otherwise append directly + function( target, els ) { + var j = target.length, + i = 0; + + // Can't trust NodeList.length + while ( ( target[ j++ ] = els[ i++ ] ) ) {} + target.length = j - 1; + } + }; +} + +function Sizzle( selector, context, results, seed ) { + var m, i, elem, nid, match, groups, newSelector, + newContext = context && context.ownerDocument, + + // nodeType defaults to 9, since context defaults to document + nodeType = context ? context.nodeType : 9; + + results = results || []; + + // Return early from calls with invalid selector or context + if ( typeof selector !== "string" || !selector || + nodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) { + + return results; + } + + // Try to shortcut find operations (as opposed to filters) in HTML documents + if ( !seed ) { + setDocument( context ); + context = context || document; + + if ( documentIsHTML ) { + + // If the selector is sufficiently simple, try using a "get*By*" DOM method + // (excepting DocumentFragment context, where the methods don't exist) + if ( nodeType !== 11 && ( match = rquickExpr.exec( selector ) ) ) { + + // ID selector + if ( ( m = match[ 1 ] ) ) { + + // Document context + if ( nodeType === 9 ) { + if ( ( elem = context.getElementById( m ) ) ) { + + // Support: IE, Opera, Webkit + // TODO: identify versions + // getElementById can match elements by name instead of ID + if ( elem.id === m ) { + results.push( elem ); + return results; + } + } else { + return results; + } + + // Element context + } else { + + // Support: IE, Opera, Webkit + // TODO: identify versions + // getElementById can match elements by name instead of ID + if ( newContext && ( elem = newContext.getElementById( m ) ) && + contains( context, elem ) && + elem.id === m ) { + + results.push( elem ); + return results; + } + } + + // Type selector + } else if ( match[ 2 ] ) { + push.apply( results, context.getElementsByTagName( selector ) ); + return results; + + // Class selector + } else if ( ( m = match[ 3 ] ) && support.getElementsByClassName && + context.getElementsByClassName ) { + + push.apply( results, context.getElementsByClassName( m ) ); + return results; + } + } + + // Take advantage of querySelectorAll + if ( support.qsa && + !nonnativeSelectorCache[ selector + " " ] && + ( !rbuggyQSA || !rbuggyQSA.test( selector ) ) && + + // Support: IE 8 only + // Exclude object elements + ( nodeType !== 1 || context.nodeName.toLowerCase() !== "object" ) ) { + + newSelector = selector; + newContext = context; + + // qSA considers elements outside a scoping root when evaluating child or + // descendant combinators, which is not what we want. + // In such cases, we work around the behavior by prefixing every selector in the + // list with an ID selector referencing the scope context. + // The technique has to be used as well when a leading combinator is used + // as such selectors are not recognized by querySelectorAll. + // Thanks to Andrew Dupont for this technique. + if ( nodeType === 1 && + ( rdescend.test( selector ) || rcombinators.test( selector ) ) ) { + + // Expand context for sibling selectors + newContext = rsibling.test( selector ) && testContext( context.parentNode ) || + context; + + // We can use :scope instead of the ID hack if the browser + // supports it & if we're not changing the context. + if ( newContext !== context || !support.scope ) { + + // Capture the context ID, setting it first if necessary + if ( ( nid = context.getAttribute( "id" ) ) ) { + nid = nid.replace( rcssescape, fcssescape ); + } else { + context.setAttribute( "id", ( nid = expando ) ); + } + } + + // Prefix every selector in the list + groups = tokenize( selector ); + i = groups.length; + while ( i-- ) { + groups[ i ] = ( nid ? "#" + nid : ":scope" ) + " " + + toSelector( groups[ i ] ); + } + newSelector = groups.join( "," ); + } + + try { + push.apply( results, + newContext.querySelectorAll( newSelector ) + ); + return results; + } catch ( qsaError ) { + nonnativeSelectorCache( selector, true ); + } finally { + if ( nid === expando ) { + context.removeAttribute( "id" ); + } + } + } + } + } + + // All others + return select( selector.replace( rtrim, "$1" ), context, results, seed ); +} + +/** + * Create key-value caches of limited size + * @returns {function(string, object)} Returns the Object data after storing it on itself with + * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength) + * deleting the oldest entry + */ +function createCache() { + var keys = []; + + function cache( key, value ) { + + // Use (key + " ") to avoid collision with native prototype properties (see Issue #157) + if ( keys.push( key + " " ) > Expr.cacheLength ) { + + // Only keep the most recent entries + delete cache[ keys.shift() ]; + } + return ( cache[ key + " " ] = value ); + } + return cache; +} + +/** + * Mark a function for special use by Sizzle + * @param {Function} fn The function to mark + */ +function markFunction( fn ) { + fn[ expando ] = true; + return fn; +} + +/** + * Support testing using an element + * @param {Function} fn Passed the created element and returns a boolean result + */ +function assert( fn ) { + var el = document.createElement( "fieldset" ); + + try { + return !!fn( el ); + } catch ( e ) { + return false; + } finally { + + // Remove from its parent by default + if ( el.parentNode ) { + el.parentNode.removeChild( el ); + } + + // release memory in IE + el = null; + } +} + +/** + * Adds the same handler for all of the specified attrs + * @param {String} attrs Pipe-separated list of attributes + * @param {Function} handler The method that will be applied + */ +function addHandle( attrs, handler ) { + var arr = attrs.split( "|" ), + i = arr.length; + + while ( i-- ) { + Expr.attrHandle[ arr[ i ] ] = handler; + } +} + +/** + * Checks document order of two siblings + * @param {Element} a + * @param {Element} b + * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b + */ +function siblingCheck( a, b ) { + var cur = b && a, + diff = cur && a.nodeType === 1 && b.nodeType === 1 && + a.sourceIndex - b.sourceIndex; + + // Use IE sourceIndex if available on both nodes + if ( diff ) { + return diff; + } + + // Check if b follows a + if ( cur ) { + while ( ( cur = cur.nextSibling ) ) { + if ( cur === b ) { + return -1; + } + } + } + + return a ? 1 : -1; +} + +/** + * Returns a function to use in pseudos for input types + * @param {String} type + */ +function createInputPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for buttons + * @param {String} type + */ +function createButtonPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return ( name === "input" || name === "button" ) && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for :enabled/:disabled + * @param {Boolean} disabled true for :disabled; false for :enabled + */ +function createDisabledPseudo( disabled ) { + + // Known :disabled false positives: fieldset[disabled] > legend:nth-of-type(n+2) :can-disable + return function( elem ) { + + // Only certain elements can match :enabled or :disabled + // https://html.spec.whatwg.org/multipage/scripting.html#selector-enabled + // https://html.spec.whatwg.org/multipage/scripting.html#selector-disabled + if ( "form" in elem ) { + + // Check for inherited disabledness on relevant non-disabled elements: + // * listed form-associated elements in a disabled fieldset + // https://html.spec.whatwg.org/multipage/forms.html#category-listed + // https://html.spec.whatwg.org/multipage/forms.html#concept-fe-disabled + // * option elements in a disabled optgroup + // https://html.spec.whatwg.org/multipage/forms.html#concept-option-disabled + // All such elements have a "form" property. + if ( elem.parentNode && elem.disabled === false ) { + + // Option elements defer to a parent optgroup if present + if ( "label" in elem ) { + if ( "label" in elem.parentNode ) { + return elem.parentNode.disabled === disabled; + } else { + return elem.disabled === disabled; + } + } + + // Support: IE 6 - 11 + // Use the isDisabled shortcut property to check for disabled fieldset ancestors + return elem.isDisabled === disabled || + + // Where there is no isDisabled, check manually + /* jshint -W018 */ + elem.isDisabled !== !disabled && + inDisabledFieldset( elem ) === disabled; + } + + return elem.disabled === disabled; + + // Try to winnow out elements that can't be disabled before trusting the disabled property. + // Some victims get caught in our net (label, legend, menu, track), but it shouldn't + // even exist on them, let alone have a boolean value. + } else if ( "label" in elem ) { + return elem.disabled === disabled; + } + + // Remaining elements are neither :enabled nor :disabled + return false; + }; +} + +/** + * Returns a function to use in pseudos for positionals + * @param {Function} fn + */ +function createPositionalPseudo( fn ) { + return markFunction( function( argument ) { + argument = +argument; + return markFunction( function( seed, matches ) { + var j, + matchIndexes = fn( [], seed.length, argument ), + i = matchIndexes.length; + + // Match elements found at the specified indexes + while ( i-- ) { + if ( seed[ ( j = matchIndexes[ i ] ) ] ) { + seed[ j ] = !( matches[ j ] = seed[ j ] ); + } + } + } ); + } ); +} + +/** + * Checks a node for validity as a Sizzle context + * @param {Element|Object=} context + * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value + */ +function testContext( context ) { + return context && typeof context.getElementsByTagName !== "undefined" && context; +} + +// Expose support vars for convenience +support = Sizzle.support = {}; + +/** + * Detects XML nodes + * @param {Element|Object} elem An element or a document + * @returns {Boolean} True iff elem is a non-HTML XML node + */ +isXML = Sizzle.isXML = function( elem ) { + var namespace = elem.namespaceURI, + docElem = ( elem.ownerDocument || elem ).documentElement; + + // Support: IE <=8 + // Assume HTML when documentElement doesn't yet exist, such as inside loading iframes + // https://bugs.jquery.com/ticket/4833 + return !rhtml.test( namespace || docElem && docElem.nodeName || "HTML" ); +}; + +/** + * Sets document-related variables once based on the current document + * @param {Element|Object} [doc] An element or document object to use to set the document + * @returns {Object} Returns the current document + */ +setDocument = Sizzle.setDocument = function( node ) { + var hasCompare, subWindow, + doc = node ? node.ownerDocument || node : preferredDoc; + + // Return early if doc is invalid or already selected + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( doc == document || doc.nodeType !== 9 || !doc.documentElement ) { + return document; + } + + // Update global variables + document = doc; + docElem = document.documentElement; + documentIsHTML = !isXML( document ); + + // Support: IE 9 - 11+, Edge 12 - 18+ + // Accessing iframe documents after unload throws "permission denied" errors (jQuery #13936) + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( preferredDoc != document && + ( subWindow = document.defaultView ) && subWindow.top !== subWindow ) { + + // Support: IE 11, Edge + if ( subWindow.addEventListener ) { + subWindow.addEventListener( "unload", unloadHandler, false ); + + // Support: IE 9 - 10 only + } else if ( subWindow.attachEvent ) { + subWindow.attachEvent( "onunload", unloadHandler ); + } + } + + // Support: IE 8 - 11+, Edge 12 - 18+, Chrome <=16 - 25 only, Firefox <=3.6 - 31 only, + // Safari 4 - 5 only, Opera <=11.6 - 12.x only + // IE/Edge & older browsers don't support the :scope pseudo-class. + // Support: Safari 6.0 only + // Safari 6.0 supports :scope but it's an alias of :root there. + support.scope = assert( function( el ) { + docElem.appendChild( el ).appendChild( document.createElement( "div" ) ); + return typeof el.querySelectorAll !== "undefined" && + !el.querySelectorAll( ":scope fieldset div" ).length; + } ); + + /* Attributes + ---------------------------------------------------------------------- */ + + // Support: IE<8 + // Verify that getAttribute really returns attributes and not properties + // (excepting IE8 booleans) + support.attributes = assert( function( el ) { + el.className = "i"; + return !el.getAttribute( "className" ); + } ); + + /* getElement(s)By* + ---------------------------------------------------------------------- */ + + // Check if getElementsByTagName("*") returns only elements + support.getElementsByTagName = assert( function( el ) { + el.appendChild( document.createComment( "" ) ); + return !el.getElementsByTagName( "*" ).length; + } ); + + // Support: IE<9 + support.getElementsByClassName = rnative.test( document.getElementsByClassName ); + + // Support: IE<10 + // Check if getElementById returns elements by name + // The broken getElementById methods don't pick up programmatically-set names, + // so use a roundabout getElementsByName test + support.getById = assert( function( el ) { + docElem.appendChild( el ).id = expando; + return !document.getElementsByName || !document.getElementsByName( expando ).length; + } ); + + // ID filter and find + if ( support.getById ) { + Expr.filter[ "ID" ] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + return elem.getAttribute( "id" ) === attrId; + }; + }; + Expr.find[ "ID" ] = function( id, context ) { + if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { + var elem = context.getElementById( id ); + return elem ? [ elem ] : []; + } + }; + } else { + Expr.filter[ "ID" ] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + var node = typeof elem.getAttributeNode !== "undefined" && + elem.getAttributeNode( "id" ); + return node && node.value === attrId; + }; + }; + + // Support: IE 6 - 7 only + // getElementById is not reliable as a find shortcut + Expr.find[ "ID" ] = function( id, context ) { + if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { + var node, i, elems, + elem = context.getElementById( id ); + + if ( elem ) { + + // Verify the id attribute + node = elem.getAttributeNode( "id" ); + if ( node && node.value === id ) { + return [ elem ]; + } + + // Fall back on getElementsByName + elems = context.getElementsByName( id ); + i = 0; + while ( ( elem = elems[ i++ ] ) ) { + node = elem.getAttributeNode( "id" ); + if ( node && node.value === id ) { + return [ elem ]; + } + } + } + + return []; + } + }; + } + + // Tag + Expr.find[ "TAG" ] = support.getElementsByTagName ? + function( tag, context ) { + if ( typeof context.getElementsByTagName !== "undefined" ) { + return context.getElementsByTagName( tag ); + + // DocumentFragment nodes don't have gEBTN + } else if ( support.qsa ) { + return context.querySelectorAll( tag ); + } + } : + + function( tag, context ) { + var elem, + tmp = [], + i = 0, + + // By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too + results = context.getElementsByTagName( tag ); + + // Filter out possible comments + if ( tag === "*" ) { + while ( ( elem = results[ i++ ] ) ) { + if ( elem.nodeType === 1 ) { + tmp.push( elem ); + } + } + + return tmp; + } + return results; + }; + + // Class + Expr.find[ "CLASS" ] = support.getElementsByClassName && function( className, context ) { + if ( typeof context.getElementsByClassName !== "undefined" && documentIsHTML ) { + return context.getElementsByClassName( className ); + } + }; + + /* QSA/matchesSelector + ---------------------------------------------------------------------- */ + + // QSA and matchesSelector support + + // matchesSelector(:active) reports false when true (IE9/Opera 11.5) + rbuggyMatches = []; + + // qSa(:focus) reports false when true (Chrome 21) + // We allow this because of a bug in IE8/9 that throws an error + // whenever `document.activeElement` is accessed on an iframe + // So, we allow :focus to pass through QSA all the time to avoid the IE error + // See https://bugs.jquery.com/ticket/13378 + rbuggyQSA = []; + + if ( ( support.qsa = rnative.test( document.querySelectorAll ) ) ) { + + // Build QSA regex + // Regex strategy adopted from Diego Perini + assert( function( el ) { + + var input; + + // Select is set to empty string on purpose + // This is to test IE's treatment of not explicitly + // setting a boolean content attribute, + // since its presence should be enough + // https://bugs.jquery.com/ticket/12359 + docElem.appendChild( el ).innerHTML = "" + + ""; + + // Support: IE8, Opera 11-12.16 + // Nothing should be selected when empty strings follow ^= or $= or *= + // The test attribute must be unknown in Opera but "safe" for WinRT + // https://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section + if ( el.querySelectorAll( "[msallowcapture^='']" ).length ) { + rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" ); + } + + // Support: IE8 + // Boolean attributes and "value" are not treated correctly + if ( !el.querySelectorAll( "[selected]" ).length ) { + rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" ); + } + + // Support: Chrome<29, Android<4.4, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.8+ + if ( !el.querySelectorAll( "[id~=" + expando + "-]" ).length ) { + rbuggyQSA.push( "~=" ); + } + + // Support: IE 11+, Edge 15 - 18+ + // IE 11/Edge don't find elements on a `[name='']` query in some cases. + // Adding a temporary attribute to the document before the selection works + // around the issue. + // Interestingly, IE 10 & older don't seem to have the issue. + input = document.createElement( "input" ); + input.setAttribute( "name", "" ); + el.appendChild( input ); + if ( !el.querySelectorAll( "[name='']" ).length ) { + rbuggyQSA.push( "\\[" + whitespace + "*name" + whitespace + "*=" + + whitespace + "*(?:''|\"\")" ); + } + + // Webkit/Opera - :checked should return selected option elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + // IE8 throws error here and will not see later tests + if ( !el.querySelectorAll( ":checked" ).length ) { + rbuggyQSA.push( ":checked" ); + } + + // Support: Safari 8+, iOS 8+ + // https://bugs.webkit.org/show_bug.cgi?id=136851 + // In-page `selector#id sibling-combinator selector` fails + if ( !el.querySelectorAll( "a#" + expando + "+*" ).length ) { + rbuggyQSA.push( ".#.+[+~]" ); + } + + // Support: Firefox <=3.6 - 5 only + // Old Firefox doesn't throw on a badly-escaped identifier. + el.querySelectorAll( "\\\f" ); + rbuggyQSA.push( "[\\r\\n\\f]" ); + } ); + + assert( function( el ) { + el.innerHTML = "" + + ""; + + // Support: Windows 8 Native Apps + // The type and name attributes are restricted during .innerHTML assignment + var input = document.createElement( "input" ); + input.setAttribute( "type", "hidden" ); + el.appendChild( input ).setAttribute( "name", "D" ); + + // Support: IE8 + // Enforce case-sensitivity of name attribute + if ( el.querySelectorAll( "[name=d]" ).length ) { + rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" ); + } + + // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled) + // IE8 throws error here and will not see later tests + if ( el.querySelectorAll( ":enabled" ).length !== 2 ) { + rbuggyQSA.push( ":enabled", ":disabled" ); + } + + // Support: IE9-11+ + // IE's :disabled selector does not pick up the children of disabled fieldsets + docElem.appendChild( el ).disabled = true; + if ( el.querySelectorAll( ":disabled" ).length !== 2 ) { + rbuggyQSA.push( ":enabled", ":disabled" ); + } + + // Support: Opera 10 - 11 only + // Opera 10-11 does not throw on post-comma invalid pseudos + el.querySelectorAll( "*,:x" ); + rbuggyQSA.push( ",.*:" ); + } ); + } + + if ( ( support.matchesSelector = rnative.test( ( matches = docElem.matches || + docElem.webkitMatchesSelector || + docElem.mozMatchesSelector || + docElem.oMatchesSelector || + docElem.msMatchesSelector ) ) ) ) { + + assert( function( el ) { + + // Check to see if it's possible to do matchesSelector + // on a disconnected node (IE 9) + support.disconnectedMatch = matches.call( el, "*" ); + + // This should fail with an exception + // Gecko does not error, returns false instead + matches.call( el, "[s!='']:x" ); + rbuggyMatches.push( "!=", pseudos ); + } ); + } + + rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join( "|" ) ); + rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join( "|" ) ); + + /* Contains + ---------------------------------------------------------------------- */ + hasCompare = rnative.test( docElem.compareDocumentPosition ); + + // Element contains another + // Purposefully self-exclusive + // As in, an element does not contain itself + contains = hasCompare || rnative.test( docElem.contains ) ? + function( a, b ) { + var adown = a.nodeType === 9 ? a.documentElement : a, + bup = b && b.parentNode; + return a === bup || !!( bup && bup.nodeType === 1 && ( + adown.contains ? + adown.contains( bup ) : + a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16 + ) ); + } : + function( a, b ) { + if ( b ) { + while ( ( b = b.parentNode ) ) { + if ( b === a ) { + return true; + } + } + } + return false; + }; + + /* Sorting + ---------------------------------------------------------------------- */ + + // Document order sorting + sortOrder = hasCompare ? + function( a, b ) { + + // Flag for duplicate removal + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + // Sort on method existence if only one input has compareDocumentPosition + var compare = !a.compareDocumentPosition - !b.compareDocumentPosition; + if ( compare ) { + return compare; + } + + // Calculate position if both inputs belong to the same document + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + compare = ( a.ownerDocument || a ) == ( b.ownerDocument || b ) ? + a.compareDocumentPosition( b ) : + + // Otherwise we know they are disconnected + 1; + + // Disconnected nodes + if ( compare & 1 || + ( !support.sortDetached && b.compareDocumentPosition( a ) === compare ) ) { + + // Choose the first element that is related to our preferred document + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( a == document || a.ownerDocument == preferredDoc && + contains( preferredDoc, a ) ) { + return -1; + } + + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( b == document || b.ownerDocument == preferredDoc && + contains( preferredDoc, b ) ) { + return 1; + } + + // Maintain original order + return sortInput ? + ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : + 0; + } + + return compare & 4 ? -1 : 1; + } : + function( a, b ) { + + // Exit early if the nodes are identical + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + var cur, + i = 0, + aup = a.parentNode, + bup = b.parentNode, + ap = [ a ], + bp = [ b ]; + + // Parentless nodes are either documents or disconnected + if ( !aup || !bup ) { + + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + /* eslint-disable eqeqeq */ + return a == document ? -1 : + b == document ? 1 : + /* eslint-enable eqeqeq */ + aup ? -1 : + bup ? 1 : + sortInput ? + ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : + 0; + + // If the nodes are siblings, we can do a quick check + } else if ( aup === bup ) { + return siblingCheck( a, b ); + } + + // Otherwise we need full lists of their ancestors for comparison + cur = a; + while ( ( cur = cur.parentNode ) ) { + ap.unshift( cur ); + } + cur = b; + while ( ( cur = cur.parentNode ) ) { + bp.unshift( cur ); + } + + // Walk down the tree looking for a discrepancy + while ( ap[ i ] === bp[ i ] ) { + i++; + } + + return i ? + + // Do a sibling check if the nodes have a common ancestor + siblingCheck( ap[ i ], bp[ i ] ) : + + // Otherwise nodes in our document sort first + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + /* eslint-disable eqeqeq */ + ap[ i ] == preferredDoc ? -1 : + bp[ i ] == preferredDoc ? 1 : + /* eslint-enable eqeqeq */ + 0; + }; + + return document; +}; + +Sizzle.matches = function( expr, elements ) { + return Sizzle( expr, null, null, elements ); +}; + +Sizzle.matchesSelector = function( elem, expr ) { + setDocument( elem ); + + if ( support.matchesSelector && documentIsHTML && + !nonnativeSelectorCache[ expr + " " ] && + ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) && + ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) { + + try { + var ret = matches.call( elem, expr ); + + // IE 9's matchesSelector returns false on disconnected nodes + if ( ret || support.disconnectedMatch || + + // As well, disconnected nodes are said to be in a document + // fragment in IE 9 + elem.document && elem.document.nodeType !== 11 ) { + return ret; + } + } catch ( e ) { + nonnativeSelectorCache( expr, true ); + } + } + + return Sizzle( expr, document, null, [ elem ] ).length > 0; +}; + +Sizzle.contains = function( context, elem ) { + + // Set document vars if needed + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( ( context.ownerDocument || context ) != document ) { + setDocument( context ); + } + return contains( context, elem ); +}; + +Sizzle.attr = function( elem, name ) { + + // Set document vars if needed + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( ( elem.ownerDocument || elem ) != document ) { + setDocument( elem ); + } + + var fn = Expr.attrHandle[ name.toLowerCase() ], + + // Don't get fooled by Object.prototype properties (jQuery #13807) + val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ? + fn( elem, name, !documentIsHTML ) : + undefined; + + return val !== undefined ? + val : + support.attributes || !documentIsHTML ? + elem.getAttribute( name ) : + ( val = elem.getAttributeNode( name ) ) && val.specified ? + val.value : + null; +}; + +Sizzle.escape = function( sel ) { + return ( sel + "" ).replace( rcssescape, fcssescape ); +}; + +Sizzle.error = function( msg ) { + throw new Error( "Syntax error, unrecognized expression: " + msg ); +}; + +/** + * Document sorting and removing duplicates + * @param {ArrayLike} results + */ +Sizzle.uniqueSort = function( results ) { + var elem, + duplicates = [], + j = 0, + i = 0; + + // Unless we *know* we can detect duplicates, assume their presence + hasDuplicate = !support.detectDuplicates; + sortInput = !support.sortStable && results.slice( 0 ); + results.sort( sortOrder ); + + if ( hasDuplicate ) { + while ( ( elem = results[ i++ ] ) ) { + if ( elem === results[ i ] ) { + j = duplicates.push( i ); + } + } + while ( j-- ) { + results.splice( duplicates[ j ], 1 ); + } + } + + // Clear input after sorting to release objects + // See https://github.com/jquery/sizzle/pull/225 + sortInput = null; + + return results; +}; + +/** + * Utility function for retrieving the text value of an array of DOM nodes + * @param {Array|Element} elem + */ +getText = Sizzle.getText = function( elem ) { + var node, + ret = "", + i = 0, + nodeType = elem.nodeType; + + if ( !nodeType ) { + + // If no nodeType, this is expected to be an array + while ( ( node = elem[ i++ ] ) ) { + + // Do not traverse comment nodes + ret += getText( node ); + } + } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { + + // Use textContent for elements + // innerText usage removed for consistency of new lines (jQuery #11153) + if ( typeof elem.textContent === "string" ) { + return elem.textContent; + } else { + + // Traverse its children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + ret += getText( elem ); + } + } + } else if ( nodeType === 3 || nodeType === 4 ) { + return elem.nodeValue; + } + + // Do not include comment or processing instruction nodes + + return ret; +}; + +Expr = Sizzle.selectors = { + + // Can be adjusted by the user + cacheLength: 50, + + createPseudo: markFunction, + + match: matchExpr, + + attrHandle: {}, + + find: {}, + + relative: { + ">": { dir: "parentNode", first: true }, + " ": { dir: "parentNode" }, + "+": { dir: "previousSibling", first: true }, + "~": { dir: "previousSibling" } + }, + + preFilter: { + "ATTR": function( match ) { + match[ 1 ] = match[ 1 ].replace( runescape, funescape ); + + // Move the given value to match[3] whether quoted or unquoted + match[ 3 ] = ( match[ 3 ] || match[ 4 ] || + match[ 5 ] || "" ).replace( runescape, funescape ); + + if ( match[ 2 ] === "~=" ) { + match[ 3 ] = " " + match[ 3 ] + " "; + } + + return match.slice( 0, 4 ); + }, + + "CHILD": function( match ) { + + /* matches from matchExpr["CHILD"] + 1 type (only|nth|...) + 2 what (child|of-type) + 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...) + 4 xn-component of xn+y argument ([+-]?\d*n|) + 5 sign of xn-component + 6 x of xn-component + 7 sign of y-component + 8 y of y-component + */ + match[ 1 ] = match[ 1 ].toLowerCase(); + + if ( match[ 1 ].slice( 0, 3 ) === "nth" ) { + + // nth-* requires argument + if ( !match[ 3 ] ) { + Sizzle.error( match[ 0 ] ); + } + + // numeric x and y parameters for Expr.filter.CHILD + // remember that false/true cast respectively to 0/1 + match[ 4 ] = +( match[ 4 ] ? + match[ 5 ] + ( match[ 6 ] || 1 ) : + 2 * ( match[ 3 ] === "even" || match[ 3 ] === "odd" ) ); + match[ 5 ] = +( ( match[ 7 ] + match[ 8 ] ) || match[ 3 ] === "odd" ); + + // other types prohibit arguments + } else if ( match[ 3 ] ) { + Sizzle.error( match[ 0 ] ); + } + + return match; + }, + + "PSEUDO": function( match ) { + var excess, + unquoted = !match[ 6 ] && match[ 2 ]; + + if ( matchExpr[ "CHILD" ].test( match[ 0 ] ) ) { + return null; + } + + // Accept quoted arguments as-is + if ( match[ 3 ] ) { + match[ 2 ] = match[ 4 ] || match[ 5 ] || ""; + + // Strip excess characters from unquoted arguments + } else if ( unquoted && rpseudo.test( unquoted ) && + + // Get excess from tokenize (recursively) + ( excess = tokenize( unquoted, true ) ) && + + // advance to the next closing parenthesis + ( excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length ) ) { + + // excess is a negative index + match[ 0 ] = match[ 0 ].slice( 0, excess ); + match[ 2 ] = unquoted.slice( 0, excess ); + } + + // Return only captures needed by the pseudo filter method (type and argument) + return match.slice( 0, 3 ); + } + }, + + filter: { + + "TAG": function( nodeNameSelector ) { + var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase(); + return nodeNameSelector === "*" ? + function() { + return true; + } : + function( elem ) { + return elem.nodeName && elem.nodeName.toLowerCase() === nodeName; + }; + }, + + "CLASS": function( className ) { + var pattern = classCache[ className + " " ]; + + return pattern || + ( pattern = new RegExp( "(^|" + whitespace + + ")" + className + "(" + whitespace + "|$)" ) ) && classCache( + className, function( elem ) { + return pattern.test( + typeof elem.className === "string" && elem.className || + typeof elem.getAttribute !== "undefined" && + elem.getAttribute( "class" ) || + "" + ); + } ); + }, + + "ATTR": function( name, operator, check ) { + return function( elem ) { + var result = Sizzle.attr( elem, name ); + + if ( result == null ) { + return operator === "!="; + } + if ( !operator ) { + return true; + } + + result += ""; + + /* eslint-disable max-len */ + + return operator === "=" ? result === check : + operator === "!=" ? result !== check : + operator === "^=" ? check && result.indexOf( check ) === 0 : + operator === "*=" ? check && result.indexOf( check ) > -1 : + operator === "$=" ? check && result.slice( -check.length ) === check : + operator === "~=" ? ( " " + result.replace( rwhitespace, " " ) + " " ).indexOf( check ) > -1 : + operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" : + false; + /* eslint-enable max-len */ + + }; + }, + + "CHILD": function( type, what, _argument, first, last ) { + var simple = type.slice( 0, 3 ) !== "nth", + forward = type.slice( -4 ) !== "last", + ofType = what === "of-type"; + + return first === 1 && last === 0 ? + + // Shortcut for :nth-*(n) + function( elem ) { + return !!elem.parentNode; + } : + + function( elem, _context, xml ) { + var cache, uniqueCache, outerCache, node, nodeIndex, start, + dir = simple !== forward ? "nextSibling" : "previousSibling", + parent = elem.parentNode, + name = ofType && elem.nodeName.toLowerCase(), + useCache = !xml && !ofType, + diff = false; + + if ( parent ) { + + // :(first|last|only)-(child|of-type) + if ( simple ) { + while ( dir ) { + node = elem; + while ( ( node = node[ dir ] ) ) { + if ( ofType ? + node.nodeName.toLowerCase() === name : + node.nodeType === 1 ) { + + return false; + } + } + + // Reverse direction for :only-* (if we haven't yet done so) + start = dir = type === "only" && !start && "nextSibling"; + } + return true; + } + + start = [ forward ? parent.firstChild : parent.lastChild ]; + + // non-xml :nth-child(...) stores cache data on `parent` + if ( forward && useCache ) { + + // Seek `elem` from a previously-cached index + + // ...in a gzip-friendly way + node = parent; + outerCache = node[ expando ] || ( node[ expando ] = {} ); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + ( outerCache[ node.uniqueID ] = {} ); + + cache = uniqueCache[ type ] || []; + nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; + diff = nodeIndex && cache[ 2 ]; + node = nodeIndex && parent.childNodes[ nodeIndex ]; + + while ( ( node = ++nodeIndex && node && node[ dir ] || + + // Fallback to seeking `elem` from the start + ( diff = nodeIndex = 0 ) || start.pop() ) ) { + + // When found, cache indexes on `parent` and break + if ( node.nodeType === 1 && ++diff && node === elem ) { + uniqueCache[ type ] = [ dirruns, nodeIndex, diff ]; + break; + } + } + + } else { + + // Use previously-cached element index if available + if ( useCache ) { + + // ...in a gzip-friendly way + node = elem; + outerCache = node[ expando ] || ( node[ expando ] = {} ); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + ( outerCache[ node.uniqueID ] = {} ); + + cache = uniqueCache[ type ] || []; + nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; + diff = nodeIndex; + } + + // xml :nth-child(...) + // or :nth-last-child(...) or :nth(-last)?-of-type(...) + if ( diff === false ) { + + // Use the same loop as above to seek `elem` from the start + while ( ( node = ++nodeIndex && node && node[ dir ] || + ( diff = nodeIndex = 0 ) || start.pop() ) ) { + + if ( ( ofType ? + node.nodeName.toLowerCase() === name : + node.nodeType === 1 ) && + ++diff ) { + + // Cache the index of each encountered element + if ( useCache ) { + outerCache = node[ expando ] || + ( node[ expando ] = {} ); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + ( outerCache[ node.uniqueID ] = {} ); + + uniqueCache[ type ] = [ dirruns, diff ]; + } + + if ( node === elem ) { + break; + } + } + } + } + } + + // Incorporate the offset, then check against cycle size + diff -= last; + return diff === first || ( diff % first === 0 && diff / first >= 0 ); + } + }; + }, + + "PSEUDO": function( pseudo, argument ) { + + // pseudo-class names are case-insensitive + // http://www.w3.org/TR/selectors/#pseudo-classes + // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters + // Remember that setFilters inherits from pseudos + var args, + fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] || + Sizzle.error( "unsupported pseudo: " + pseudo ); + + // The user may use createPseudo to indicate that + // arguments are needed to create the filter function + // just as Sizzle does + if ( fn[ expando ] ) { + return fn( argument ); + } + + // But maintain support for old signatures + if ( fn.length > 1 ) { + args = [ pseudo, pseudo, "", argument ]; + return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ? + markFunction( function( seed, matches ) { + var idx, + matched = fn( seed, argument ), + i = matched.length; + while ( i-- ) { + idx = indexOf( seed, matched[ i ] ); + seed[ idx ] = !( matches[ idx ] = matched[ i ] ); + } + } ) : + function( elem ) { + return fn( elem, 0, args ); + }; + } + + return fn; + } + }, + + pseudos: { + + // Potentially complex pseudos + "not": markFunction( function( selector ) { + + // Trim the selector passed to compile + // to avoid treating leading and trailing + // spaces as combinators + var input = [], + results = [], + matcher = compile( selector.replace( rtrim, "$1" ) ); + + return matcher[ expando ] ? + markFunction( function( seed, matches, _context, xml ) { + var elem, + unmatched = matcher( seed, null, xml, [] ), + i = seed.length; + + // Match elements unmatched by `matcher` + while ( i-- ) { + if ( ( elem = unmatched[ i ] ) ) { + seed[ i ] = !( matches[ i ] = elem ); + } + } + } ) : + function( elem, _context, xml ) { + input[ 0 ] = elem; + matcher( input, null, xml, results ); + + // Don't keep the element (issue #299) + input[ 0 ] = null; + return !results.pop(); + }; + } ), + + "has": markFunction( function( selector ) { + return function( elem ) { + return Sizzle( selector, elem ).length > 0; + }; + } ), + + "contains": markFunction( function( text ) { + text = text.replace( runescape, funescape ); + return function( elem ) { + return ( elem.textContent || getText( elem ) ).indexOf( text ) > -1; + }; + } ), + + // "Whether an element is represented by a :lang() selector + // is based solely on the element's language value + // being equal to the identifier C, + // or beginning with the identifier C immediately followed by "-". + // The matching of C against the element's language value is performed case-insensitively. + // The identifier C does not have to be a valid language name." + // http://www.w3.org/TR/selectors/#lang-pseudo + "lang": markFunction( function( lang ) { + + // lang value must be a valid identifier + if ( !ridentifier.test( lang || "" ) ) { + Sizzle.error( "unsupported lang: " + lang ); + } + lang = lang.replace( runescape, funescape ).toLowerCase(); + return function( elem ) { + var elemLang; + do { + if ( ( elemLang = documentIsHTML ? + elem.lang : + elem.getAttribute( "xml:lang" ) || elem.getAttribute( "lang" ) ) ) { + + elemLang = elemLang.toLowerCase(); + return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0; + } + } while ( ( elem = elem.parentNode ) && elem.nodeType === 1 ); + return false; + }; + } ), + + // Miscellaneous + "target": function( elem ) { + var hash = window.location && window.location.hash; + return hash && hash.slice( 1 ) === elem.id; + }, + + "root": function( elem ) { + return elem === docElem; + }, + + "focus": function( elem ) { + return elem === document.activeElement && + ( !document.hasFocus || document.hasFocus() ) && + !!( elem.type || elem.href || ~elem.tabIndex ); + }, + + // Boolean properties + "enabled": createDisabledPseudo( false ), + "disabled": createDisabledPseudo( true ), + + "checked": function( elem ) { + + // In CSS3, :checked should return both checked and selected elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + var nodeName = elem.nodeName.toLowerCase(); + return ( nodeName === "input" && !!elem.checked ) || + ( nodeName === "option" && !!elem.selected ); + }, + + "selected": function( elem ) { + + // Accessing this property makes selected-by-default + // options in Safari work properly + if ( elem.parentNode ) { + // eslint-disable-next-line no-unused-expressions + elem.parentNode.selectedIndex; + } + + return elem.selected === true; + }, + + // Contents + "empty": function( elem ) { + + // http://www.w3.org/TR/selectors/#empty-pseudo + // :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5), + // but not by others (comment: 8; processing instruction: 7; etc.) + // nodeType < 6 works because attributes (2) do not appear as children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + if ( elem.nodeType < 6 ) { + return false; + } + } + return true; + }, + + "parent": function( elem ) { + return !Expr.pseudos[ "empty" ]( elem ); + }, + + // Element/input types + "header": function( elem ) { + return rheader.test( elem.nodeName ); + }, + + "input": function( elem ) { + return rinputs.test( elem.nodeName ); + }, + + "button": function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === "button" || name === "button"; + }, + + "text": function( elem ) { + var attr; + return elem.nodeName.toLowerCase() === "input" && + elem.type === "text" && + + // Support: IE<8 + // New HTML5 attribute values (e.g., "search") appear with elem.type === "text" + ( ( attr = elem.getAttribute( "type" ) ) == null || + attr.toLowerCase() === "text" ); + }, + + // Position-in-collection + "first": createPositionalPseudo( function() { + return [ 0 ]; + } ), + + "last": createPositionalPseudo( function( _matchIndexes, length ) { + return [ length - 1 ]; + } ), + + "eq": createPositionalPseudo( function( _matchIndexes, length, argument ) { + return [ argument < 0 ? argument + length : argument ]; + } ), + + "even": createPositionalPseudo( function( matchIndexes, length ) { + var i = 0; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + } ), + + "odd": createPositionalPseudo( function( matchIndexes, length ) { + var i = 1; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + } ), + + "lt": createPositionalPseudo( function( matchIndexes, length, argument ) { + var i = argument < 0 ? + argument + length : + argument > length ? + length : + argument; + for ( ; --i >= 0; ) { + matchIndexes.push( i ); + } + return matchIndexes; + } ), + + "gt": createPositionalPseudo( function( matchIndexes, length, argument ) { + var i = argument < 0 ? argument + length : argument; + for ( ; ++i < length; ) { + matchIndexes.push( i ); + } + return matchIndexes; + } ) + } +}; + +Expr.pseudos[ "nth" ] = Expr.pseudos[ "eq" ]; + +// Add button/input type pseudos +for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) { + Expr.pseudos[ i ] = createInputPseudo( i ); +} +for ( i in { submit: true, reset: true } ) { + Expr.pseudos[ i ] = createButtonPseudo( i ); +} + +// Easy API for creating new setFilters +function setFilters() {} +setFilters.prototype = Expr.filters = Expr.pseudos; +Expr.setFilters = new setFilters(); + +tokenize = Sizzle.tokenize = function( selector, parseOnly ) { + var matched, match, tokens, type, + soFar, groups, preFilters, + cached = tokenCache[ selector + " " ]; + + if ( cached ) { + return parseOnly ? 0 : cached.slice( 0 ); + } + + soFar = selector; + groups = []; + preFilters = Expr.preFilter; + + while ( soFar ) { + + // Comma and first run + if ( !matched || ( match = rcomma.exec( soFar ) ) ) { + if ( match ) { + + // Don't consume trailing commas as valid + soFar = soFar.slice( match[ 0 ].length ) || soFar; + } + groups.push( ( tokens = [] ) ); + } + + matched = false; + + // Combinators + if ( ( match = rcombinators.exec( soFar ) ) ) { + matched = match.shift(); + tokens.push( { + value: matched, + + // Cast descendant combinators to space + type: match[ 0 ].replace( rtrim, " " ) + } ); + soFar = soFar.slice( matched.length ); + } + + // Filters + for ( type in Expr.filter ) { + if ( ( match = matchExpr[ type ].exec( soFar ) ) && ( !preFilters[ type ] || + ( match = preFilters[ type ]( match ) ) ) ) { + matched = match.shift(); + tokens.push( { + value: matched, + type: type, + matches: match + } ); + soFar = soFar.slice( matched.length ); + } + } + + if ( !matched ) { + break; + } + } + + // Return the length of the invalid excess + // if we're just parsing + // Otherwise, throw an error or return tokens + return parseOnly ? + soFar.length : + soFar ? + Sizzle.error( selector ) : + + // Cache the tokens + tokenCache( selector, groups ).slice( 0 ); +}; + +function toSelector( tokens ) { + var i = 0, + len = tokens.length, + selector = ""; + for ( ; i < len; i++ ) { + selector += tokens[ i ].value; + } + return selector; +} + +function addCombinator( matcher, combinator, base ) { + var dir = combinator.dir, + skip = combinator.next, + key = skip || dir, + checkNonElements = base && key === "parentNode", + doneName = done++; + + return combinator.first ? + + // Check against closest ancestor/preceding element + function( elem, context, xml ) { + while ( ( elem = elem[ dir ] ) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + return matcher( elem, context, xml ); + } + } + return false; + } : + + // Check against all ancestor/preceding elements + function( elem, context, xml ) { + var oldCache, uniqueCache, outerCache, + newCache = [ dirruns, doneName ]; + + // We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching + if ( xml ) { + while ( ( elem = elem[ dir ] ) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + if ( matcher( elem, context, xml ) ) { + return true; + } + } + } + } else { + while ( ( elem = elem[ dir ] ) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + outerCache = elem[ expando ] || ( elem[ expando ] = {} ); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ elem.uniqueID ] || + ( outerCache[ elem.uniqueID ] = {} ); + + if ( skip && skip === elem.nodeName.toLowerCase() ) { + elem = elem[ dir ] || elem; + } else if ( ( oldCache = uniqueCache[ key ] ) && + oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) { + + // Assign to newCache so results back-propagate to previous elements + return ( newCache[ 2 ] = oldCache[ 2 ] ); + } else { + + // Reuse newcache so results back-propagate to previous elements + uniqueCache[ key ] = newCache; + + // A match means we're done; a fail means we have to keep checking + if ( ( newCache[ 2 ] = matcher( elem, context, xml ) ) ) { + return true; + } + } + } + } + } + return false; + }; +} + +function elementMatcher( matchers ) { + return matchers.length > 1 ? + function( elem, context, xml ) { + var i = matchers.length; + while ( i-- ) { + if ( !matchers[ i ]( elem, context, xml ) ) { + return false; + } + } + return true; + } : + matchers[ 0 ]; +} + +function multipleContexts( selector, contexts, results ) { + var i = 0, + len = contexts.length; + for ( ; i < len; i++ ) { + Sizzle( selector, contexts[ i ], results ); + } + return results; +} + +function condense( unmatched, map, filter, context, xml ) { + var elem, + newUnmatched = [], + i = 0, + len = unmatched.length, + mapped = map != null; + + for ( ; i < len; i++ ) { + if ( ( elem = unmatched[ i ] ) ) { + if ( !filter || filter( elem, context, xml ) ) { + newUnmatched.push( elem ); + if ( mapped ) { + map.push( i ); + } + } + } + } + + return newUnmatched; +} + +function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) { + if ( postFilter && !postFilter[ expando ] ) { + postFilter = setMatcher( postFilter ); + } + if ( postFinder && !postFinder[ expando ] ) { + postFinder = setMatcher( postFinder, postSelector ); + } + return markFunction( function( seed, results, context, xml ) { + var temp, i, elem, + preMap = [], + postMap = [], + preexisting = results.length, + + // Get initial elements from seed or context + elems = seed || multipleContexts( + selector || "*", + context.nodeType ? [ context ] : context, + [] + ), + + // Prefilter to get matcher input, preserving a map for seed-results synchronization + matcherIn = preFilter && ( seed || !selector ) ? + condense( elems, preMap, preFilter, context, xml ) : + elems, + + matcherOut = matcher ? + + // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results, + postFinder || ( seed ? preFilter : preexisting || postFilter ) ? + + // ...intermediate processing is necessary + [] : + + // ...otherwise use results directly + results : + matcherIn; + + // Find primary matches + if ( matcher ) { + matcher( matcherIn, matcherOut, context, xml ); + } + + // Apply postFilter + if ( postFilter ) { + temp = condense( matcherOut, postMap ); + postFilter( temp, [], context, xml ); + + // Un-match failing elements by moving them back to matcherIn + i = temp.length; + while ( i-- ) { + if ( ( elem = temp[ i ] ) ) { + matcherOut[ postMap[ i ] ] = !( matcherIn[ postMap[ i ] ] = elem ); + } + } + } + + if ( seed ) { + if ( postFinder || preFilter ) { + if ( postFinder ) { + + // Get the final matcherOut by condensing this intermediate into postFinder contexts + temp = []; + i = matcherOut.length; + while ( i-- ) { + if ( ( elem = matcherOut[ i ] ) ) { + + // Restore matcherIn since elem is not yet a final match + temp.push( ( matcherIn[ i ] = elem ) ); + } + } + postFinder( null, ( matcherOut = [] ), temp, xml ); + } + + // Move matched elements from seed to results to keep them synchronized + i = matcherOut.length; + while ( i-- ) { + if ( ( elem = matcherOut[ i ] ) && + ( temp = postFinder ? indexOf( seed, elem ) : preMap[ i ] ) > -1 ) { + + seed[ temp ] = !( results[ temp ] = elem ); + } + } + } + + // Add elements to results, through postFinder if defined + } else { + matcherOut = condense( + matcherOut === results ? + matcherOut.splice( preexisting, matcherOut.length ) : + matcherOut + ); + if ( postFinder ) { + postFinder( null, results, matcherOut, xml ); + } else { + push.apply( results, matcherOut ); + } + } + } ); +} + +function matcherFromTokens( tokens ) { + var checkContext, matcher, j, + len = tokens.length, + leadingRelative = Expr.relative[ tokens[ 0 ].type ], + implicitRelative = leadingRelative || Expr.relative[ " " ], + i = leadingRelative ? 1 : 0, + + // The foundational matcher ensures that elements are reachable from top-level context(s) + matchContext = addCombinator( function( elem ) { + return elem === checkContext; + }, implicitRelative, true ), + matchAnyContext = addCombinator( function( elem ) { + return indexOf( checkContext, elem ) > -1; + }, implicitRelative, true ), + matchers = [ function( elem, context, xml ) { + var ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || ( + ( checkContext = context ).nodeType ? + matchContext( elem, context, xml ) : + matchAnyContext( elem, context, xml ) ); + + // Avoid hanging onto element (issue #299) + checkContext = null; + return ret; + } ]; + + for ( ; i < len; i++ ) { + if ( ( matcher = Expr.relative[ tokens[ i ].type ] ) ) { + matchers = [ addCombinator( elementMatcher( matchers ), matcher ) ]; + } else { + matcher = Expr.filter[ tokens[ i ].type ].apply( null, tokens[ i ].matches ); + + // Return special upon seeing a positional matcher + if ( matcher[ expando ] ) { + + // Find the next relative operator (if any) for proper handling + j = ++i; + for ( ; j < len; j++ ) { + if ( Expr.relative[ tokens[ j ].type ] ) { + break; + } + } + return setMatcher( + i > 1 && elementMatcher( matchers ), + i > 1 && toSelector( + + // If the preceding token was a descendant combinator, insert an implicit any-element `*` + tokens + .slice( 0, i - 1 ) + .concat( { value: tokens[ i - 2 ].type === " " ? "*" : "" } ) + ).replace( rtrim, "$1" ), + matcher, + i < j && matcherFromTokens( tokens.slice( i, j ) ), + j < len && matcherFromTokens( ( tokens = tokens.slice( j ) ) ), + j < len && toSelector( tokens ) + ); + } + matchers.push( matcher ); + } + } + + return elementMatcher( matchers ); +} + +function matcherFromGroupMatchers( elementMatchers, setMatchers ) { + var bySet = setMatchers.length > 0, + byElement = elementMatchers.length > 0, + superMatcher = function( seed, context, xml, results, outermost ) { + var elem, j, matcher, + matchedCount = 0, + i = "0", + unmatched = seed && [], + setMatched = [], + contextBackup = outermostContext, + + // We must always have either seed elements or outermost context + elems = seed || byElement && Expr.find[ "TAG" ]( "*", outermost ), + + // Use integer dirruns iff this is the outermost matcher + dirrunsUnique = ( dirruns += contextBackup == null ? 1 : Math.random() || 0.1 ), + len = elems.length; + + if ( outermost ) { + + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + outermostContext = context == document || context || outermost; + } + + // Add elements passing elementMatchers directly to results + // Support: IE<9, Safari + // Tolerate NodeList properties (IE: "length"; Safari: ) matching elements by id + for ( ; i !== len && ( elem = elems[ i ] ) != null; i++ ) { + if ( byElement && elem ) { + j = 0; + + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( !context && elem.ownerDocument != document ) { + setDocument( elem ); + xml = !documentIsHTML; + } + while ( ( matcher = elementMatchers[ j++ ] ) ) { + if ( matcher( elem, context || document, xml ) ) { + results.push( elem ); + break; + } + } + if ( outermost ) { + dirruns = dirrunsUnique; + } + } + + // Track unmatched elements for set filters + if ( bySet ) { + + // They will have gone through all possible matchers + if ( ( elem = !matcher && elem ) ) { + matchedCount--; + } + + // Lengthen the array for every element, matched or not + if ( seed ) { + unmatched.push( elem ); + } + } + } + + // `i` is now the count of elements visited above, and adding it to `matchedCount` + // makes the latter nonnegative. + matchedCount += i; + + // Apply set filters to unmatched elements + // NOTE: This can be skipped if there are no unmatched elements (i.e., `matchedCount` + // equals `i`), unless we didn't visit _any_ elements in the above loop because we have + // no element matchers and no seed. + // Incrementing an initially-string "0" `i` allows `i` to remain a string only in that + // case, which will result in a "00" `matchedCount` that differs from `i` but is also + // numerically zero. + if ( bySet && i !== matchedCount ) { + j = 0; + while ( ( matcher = setMatchers[ j++ ] ) ) { + matcher( unmatched, setMatched, context, xml ); + } + + if ( seed ) { + + // Reintegrate element matches to eliminate the need for sorting + if ( matchedCount > 0 ) { + while ( i-- ) { + if ( !( unmatched[ i ] || setMatched[ i ] ) ) { + setMatched[ i ] = pop.call( results ); + } + } + } + + // Discard index placeholder values to get only actual matches + setMatched = condense( setMatched ); + } + + // Add matches to results + push.apply( results, setMatched ); + + // Seedless set matches succeeding multiple successful matchers stipulate sorting + if ( outermost && !seed && setMatched.length > 0 && + ( matchedCount + setMatchers.length ) > 1 ) { + + Sizzle.uniqueSort( results ); + } + } + + // Override manipulation of globals by nested matchers + if ( outermost ) { + dirruns = dirrunsUnique; + outermostContext = contextBackup; + } + + return unmatched; + }; + + return bySet ? + markFunction( superMatcher ) : + superMatcher; +} + +compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) { + var i, + setMatchers = [], + elementMatchers = [], + cached = compilerCache[ selector + " " ]; + + if ( !cached ) { + + // Generate a function of recursive functions that can be used to check each element + if ( !match ) { + match = tokenize( selector ); + } + i = match.length; + while ( i-- ) { + cached = matcherFromTokens( match[ i ] ); + if ( cached[ expando ] ) { + setMatchers.push( cached ); + } else { + elementMatchers.push( cached ); + } + } + + // Cache the compiled function + cached = compilerCache( + selector, + matcherFromGroupMatchers( elementMatchers, setMatchers ) + ); + + // Save selector and tokenization + cached.selector = selector; + } + return cached; +}; + +/** + * A low-level selection function that works with Sizzle's compiled + * selector functions + * @param {String|Function} selector A selector or a pre-compiled + * selector function built with Sizzle.compile + * @param {Element} context + * @param {Array} [results] + * @param {Array} [seed] A set of elements to match against + */ +select = Sizzle.select = function( selector, context, results, seed ) { + var i, tokens, token, type, find, + compiled = typeof selector === "function" && selector, + match = !seed && tokenize( ( selector = compiled.selector || selector ) ); + + results = results || []; + + // Try to minimize operations if there is only one selector in the list and no seed + // (the latter of which guarantees us context) + if ( match.length === 1 ) { + + // Reduce context if the leading compound selector is an ID + tokens = match[ 0 ] = match[ 0 ].slice( 0 ); + if ( tokens.length > 2 && ( token = tokens[ 0 ] ).type === "ID" && + context.nodeType === 9 && documentIsHTML && Expr.relative[ tokens[ 1 ].type ] ) { + + context = ( Expr.find[ "ID" ]( token.matches[ 0 ] + .replace( runescape, funescape ), context ) || [] )[ 0 ]; + if ( !context ) { + return results; + + // Precompiled matchers will still verify ancestry, so step up a level + } else if ( compiled ) { + context = context.parentNode; + } + + selector = selector.slice( tokens.shift().value.length ); + } + + // Fetch a seed set for right-to-left matching + i = matchExpr[ "needsContext" ].test( selector ) ? 0 : tokens.length; + while ( i-- ) { + token = tokens[ i ]; + + // Abort if we hit a combinator + if ( Expr.relative[ ( type = token.type ) ] ) { + break; + } + if ( ( find = Expr.find[ type ] ) ) { + + // Search, expanding context for leading sibling combinators + if ( ( seed = find( + token.matches[ 0 ].replace( runescape, funescape ), + rsibling.test( tokens[ 0 ].type ) && testContext( context.parentNode ) || + context + ) ) ) { + + // If seed is empty or no tokens remain, we can return early + tokens.splice( i, 1 ); + selector = seed.length && toSelector( tokens ); + if ( !selector ) { + push.apply( results, seed ); + return results; + } + + break; + } + } + } + } + + // Compile and execute a filtering function if one is not provided + // Provide `match` to avoid retokenization if we modified the selector above + ( compiled || compile( selector, match ) )( + seed, + context, + !documentIsHTML, + results, + !context || rsibling.test( selector ) && testContext( context.parentNode ) || context + ); + return results; +}; + +// One-time assignments + +// Sort stability +support.sortStable = expando.split( "" ).sort( sortOrder ).join( "" ) === expando; + +// Support: Chrome 14-35+ +// Always assume duplicates if they aren't passed to the comparison function +support.detectDuplicates = !!hasDuplicate; + +// Initialize against the default document +setDocument(); + +// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27) +// Detached nodes confoundingly follow *each other* +support.sortDetached = assert( function( el ) { + + // Should return 1, but returns 4 (following) + return el.compareDocumentPosition( document.createElement( "fieldset" ) ) & 1; +} ); + +// Support: IE<8 +// Prevent attribute/property "interpolation" +// https://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx +if ( !assert( function( el ) { + el.innerHTML = ""; + return el.firstChild.getAttribute( "href" ) === "#"; +} ) ) { + addHandle( "type|href|height|width", function( elem, name, isXML ) { + if ( !isXML ) { + return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 ); + } + } ); +} + +// Support: IE<9 +// Use defaultValue in place of getAttribute("value") +if ( !support.attributes || !assert( function( el ) { + el.innerHTML = ""; + el.firstChild.setAttribute( "value", "" ); + return el.firstChild.getAttribute( "value" ) === ""; +} ) ) { + addHandle( "value", function( elem, _name, isXML ) { + if ( !isXML && elem.nodeName.toLowerCase() === "input" ) { + return elem.defaultValue; + } + } ); +} + +// Support: IE<9 +// Use getAttributeNode to fetch booleans when getAttribute lies +if ( !assert( function( el ) { + return el.getAttribute( "disabled" ) == null; +} ) ) { + addHandle( booleans, function( elem, name, isXML ) { + var val; + if ( !isXML ) { + return elem[ name ] === true ? name.toLowerCase() : + ( val = elem.getAttributeNode( name ) ) && val.specified ? + val.value : + null; + } + } ); +} + +return Sizzle; + +} )( window ); + + + +jQuery.find = Sizzle; +jQuery.expr = Sizzle.selectors; + +// Deprecated +jQuery.expr[ ":" ] = jQuery.expr.pseudos; +jQuery.uniqueSort = jQuery.unique = Sizzle.uniqueSort; +jQuery.text = Sizzle.getText; +jQuery.isXMLDoc = Sizzle.isXML; +jQuery.contains = Sizzle.contains; +jQuery.escapeSelector = Sizzle.escape; + + + + +var dir = function( elem, dir, until ) { + var matched = [], + truncate = until !== undefined; + + while ( ( elem = elem[ dir ] ) && elem.nodeType !== 9 ) { + if ( elem.nodeType === 1 ) { + if ( truncate && jQuery( elem ).is( until ) ) { + break; + } + matched.push( elem ); + } + } + return matched; +}; + + +var siblings = function( n, elem ) { + var matched = []; + + for ( ; n; n = n.nextSibling ) { + if ( n.nodeType === 1 && n !== elem ) { + matched.push( n ); + } + } + + return matched; +}; + + +var rneedsContext = jQuery.expr.match.needsContext; + + + +function nodeName( elem, name ) { + + return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); + +}; +var rsingleTag = ( /^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i ); + + + +// Implement the identical functionality for filter and not +function winnow( elements, qualifier, not ) { + if ( isFunction( qualifier ) ) { + return jQuery.grep( elements, function( elem, i ) { + return !!qualifier.call( elem, i, elem ) !== not; + } ); + } + + // Single element + if ( qualifier.nodeType ) { + return jQuery.grep( elements, function( elem ) { + return ( elem === qualifier ) !== not; + } ); + } + + // Arraylike of elements (jQuery, arguments, Array) + if ( typeof qualifier !== "string" ) { + return jQuery.grep( elements, function( elem ) { + return ( indexOf.call( qualifier, elem ) > -1 ) !== not; + } ); + } + + // Filtered directly for both simple and complex selectors + return jQuery.filter( qualifier, elements, not ); +} + +jQuery.filter = function( expr, elems, not ) { + var elem = elems[ 0 ]; + + if ( not ) { + expr = ":not(" + expr + ")"; + } + + if ( elems.length === 1 && elem.nodeType === 1 ) { + return jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : []; + } + + return jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) { + return elem.nodeType === 1; + } ) ); +}; + +jQuery.fn.extend( { + find: function( selector ) { + var i, ret, + len = this.length, + self = this; + + if ( typeof selector !== "string" ) { + return this.pushStack( jQuery( selector ).filter( function() { + for ( i = 0; i < len; i++ ) { + if ( jQuery.contains( self[ i ], this ) ) { + return true; + } + } + } ) ); + } + + ret = this.pushStack( [] ); + + for ( i = 0; i < len; i++ ) { + jQuery.find( selector, self[ i ], ret ); + } + + return len > 1 ? jQuery.uniqueSort( ret ) : ret; + }, + filter: function( selector ) { + return this.pushStack( winnow( this, selector || [], false ) ); + }, + not: function( selector ) { + return this.pushStack( winnow( this, selector || [], true ) ); + }, + is: function( selector ) { + return !!winnow( + this, + + // If this is a positional/relative selector, check membership in the returned set + // so $("p:first").is("p:last") won't return true for a doc with two "p". + typeof selector === "string" && rneedsContext.test( selector ) ? + jQuery( selector ) : + selector || [], + false + ).length; + } +} ); + + +// Initialize a jQuery object + + +// A central reference to the root jQuery(document) +var rootjQuery, + + // A simple way to check for HTML strings + // Prioritize #id over to avoid XSS via location.hash (#9521) + // Strict HTML recognition (#11290: must start with <) + // Shortcut simple #id case for speed + rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/, + + init = jQuery.fn.init = function( selector, context, root ) { + var match, elem; + + // HANDLE: $(""), $(null), $(undefined), $(false) + if ( !selector ) { + return this; + } + + // Method init() accepts an alternate rootjQuery + // so migrate can support jQuery.sub (gh-2101) + root = root || rootjQuery; + + // Handle HTML strings + if ( typeof selector === "string" ) { + if ( selector[ 0 ] === "<" && + selector[ selector.length - 1 ] === ">" && + selector.length >= 3 ) { + + // Assume that strings that start and end with <> are HTML and skip the regex check + match = [ null, selector, null ]; + + } else { + match = rquickExpr.exec( selector ); + } + + // Match html or make sure no context is specified for #id + if ( match && ( match[ 1 ] || !context ) ) { + + // HANDLE: $(html) -> $(array) + if ( match[ 1 ] ) { + context = context instanceof jQuery ? context[ 0 ] : context; + + // Option to run scripts is true for back-compat + // Intentionally let the error be thrown if parseHTML is not present + jQuery.merge( this, jQuery.parseHTML( + match[ 1 ], + context && context.nodeType ? context.ownerDocument || context : document, + true + ) ); + + // HANDLE: $(html, props) + if ( rsingleTag.test( match[ 1 ] ) && jQuery.isPlainObject( context ) ) { + for ( match in context ) { + + // Properties of context are called as methods if possible + if ( isFunction( this[ match ] ) ) { + this[ match ]( context[ match ] ); + + // ...and otherwise set as attributes + } else { + this.attr( match, context[ match ] ); + } + } + } + + return this; + + // HANDLE: $(#id) + } else { + elem = document.getElementById( match[ 2 ] ); + + if ( elem ) { + + // Inject the element directly into the jQuery object + this[ 0 ] = elem; + this.length = 1; + } + return this; + } + + // HANDLE: $(expr, $(...)) + } else if ( !context || context.jquery ) { + return ( context || root ).find( selector ); + + // HANDLE: $(expr, context) + // (which is just equivalent to: $(context).find(expr) + } else { + return this.constructor( context ).find( selector ); + } + + // HANDLE: $(DOMElement) + } else if ( selector.nodeType ) { + this[ 0 ] = selector; + this.length = 1; + return this; + + // HANDLE: $(function) + // Shortcut for document ready + } else if ( isFunction( selector ) ) { + return root.ready !== undefined ? + root.ready( selector ) : + + // Execute immediately if ready is not present + selector( jQuery ); + } + + return jQuery.makeArray( selector, this ); + }; + +// Give the init function the jQuery prototype for later instantiation +init.prototype = jQuery.fn; + +// Initialize central reference +rootjQuery = jQuery( document ); + + +var rparentsprev = /^(?:parents|prev(?:Until|All))/, + + // Methods guaranteed to produce a unique set when starting from a unique set + guaranteedUnique = { + children: true, + contents: true, + next: true, + prev: true + }; + +jQuery.fn.extend( { + has: function( target ) { + var targets = jQuery( target, this ), + l = targets.length; + + return this.filter( function() { + var i = 0; + for ( ; i < l; i++ ) { + if ( jQuery.contains( this, targets[ i ] ) ) { + return true; + } + } + } ); + }, + + closest: function( selectors, context ) { + var cur, + i = 0, + l = this.length, + matched = [], + targets = typeof selectors !== "string" && jQuery( selectors ); + + // Positional selectors never match, since there's no _selection_ context + if ( !rneedsContext.test( selectors ) ) { + for ( ; i < l; i++ ) { + for ( cur = this[ i ]; cur && cur !== context; cur = cur.parentNode ) { + + // Always skip document fragments + if ( cur.nodeType < 11 && ( targets ? + targets.index( cur ) > -1 : + + // Don't pass non-elements to Sizzle + cur.nodeType === 1 && + jQuery.find.matchesSelector( cur, selectors ) ) ) { + + matched.push( cur ); + break; + } + } + } + } + + return this.pushStack( matched.length > 1 ? jQuery.uniqueSort( matched ) : matched ); + }, + + // Determine the position of an element within the set + index: function( elem ) { + + // No argument, return index in parent + if ( !elem ) { + return ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1; + } + + // Index in selector + if ( typeof elem === "string" ) { + return indexOf.call( jQuery( elem ), this[ 0 ] ); + } + + // Locate the position of the desired element + return indexOf.call( this, + + // If it receives a jQuery object, the first element is used + elem.jquery ? elem[ 0 ] : elem + ); + }, + + add: function( selector, context ) { + return this.pushStack( + jQuery.uniqueSort( + jQuery.merge( this.get(), jQuery( selector, context ) ) + ) + ); + }, + + addBack: function( selector ) { + return this.add( selector == null ? + this.prevObject : this.prevObject.filter( selector ) + ); + } +} ); + +function sibling( cur, dir ) { + while ( ( cur = cur[ dir ] ) && cur.nodeType !== 1 ) {} + return cur; +} + +jQuery.each( { + parent: function( elem ) { + var parent = elem.parentNode; + return parent && parent.nodeType !== 11 ? parent : null; + }, + parents: function( elem ) { + return dir( elem, "parentNode" ); + }, + parentsUntil: function( elem, _i, until ) { + return dir( elem, "parentNode", until ); + }, + next: function( elem ) { + return sibling( elem, "nextSibling" ); + }, + prev: function( elem ) { + return sibling( elem, "previousSibling" ); + }, + nextAll: function( elem ) { + return dir( elem, "nextSibling" ); + }, + prevAll: function( elem ) { + return dir( elem, "previousSibling" ); + }, + nextUntil: function( elem, _i, until ) { + return dir( elem, "nextSibling", until ); + }, + prevUntil: function( elem, _i, until ) { + return dir( elem, "previousSibling", until ); + }, + siblings: function( elem ) { + return siblings( ( elem.parentNode || {} ).firstChild, elem ); + }, + children: function( elem ) { + return siblings( elem.firstChild ); + }, + contents: function( elem ) { + if ( elem.contentDocument != null && + + // Support: IE 11+ + // elements with no `data` attribute has an object + // `contentDocument` with a `null` prototype. + getProto( elem.contentDocument ) ) { + + return elem.contentDocument; + } + + // Support: IE 9 - 11 only, iOS 7 only, Android Browser <=4.3 only + // Treat the template element as a regular one in browsers that + // don't support it. + if ( nodeName( elem, "template" ) ) { + elem = elem.content || elem; + } + + return jQuery.merge( [], elem.childNodes ); + } +}, function( name, fn ) { + jQuery.fn[ name ] = function( until, selector ) { + var matched = jQuery.map( this, fn, until ); + + if ( name.slice( -5 ) !== "Until" ) { + selector = until; + } + + if ( selector && typeof selector === "string" ) { + matched = jQuery.filter( selector, matched ); + } + + if ( this.length > 1 ) { + + // Remove duplicates + if ( !guaranteedUnique[ name ] ) { + jQuery.uniqueSort( matched ); + } + + // Reverse order for parents* and prev-derivatives + if ( rparentsprev.test( name ) ) { + matched.reverse(); + } + } + + return this.pushStack( matched ); + }; +} ); +var rnothtmlwhite = ( /[^\x20\t\r\n\f]+/g ); + + + +// Convert String-formatted options into Object-formatted ones +function createOptions( options ) { + var object = {}; + jQuery.each( options.match( rnothtmlwhite ) || [], function( _, flag ) { + object[ flag ] = true; + } ); + return object; +} + +/* + * Create a callback list using the following parameters: + * + * options: an optional list of space-separated options that will change how + * the callback list behaves or a more traditional option object + * + * By default a callback list will act like an event callback list and can be + * "fired" multiple times. + * + * Possible options: + * + * once: will ensure the callback list can only be fired once (like a Deferred) + * + * memory: will keep track of previous values and will call any callback added + * after the list has been fired right away with the latest "memorized" + * values (like a Deferred) + * + * unique: will ensure a callback can only be added once (no duplicate in the list) + * + * stopOnFalse: interrupt callings when a callback returns false + * + */ +jQuery.Callbacks = function( options ) { + + // Convert options from String-formatted to Object-formatted if needed + // (we check in cache first) + options = typeof options === "string" ? + createOptions( options ) : + jQuery.extend( {}, options ); + + var // Flag to know if list is currently firing + firing, + + // Last fire value for non-forgettable lists + memory, + + // Flag to know if list was already fired + fired, + + // Flag to prevent firing + locked, + + // Actual callback list + list = [], + + // Queue of execution data for repeatable lists + queue = [], + + // Index of currently firing callback (modified by add/remove as needed) + firingIndex = -1, + + // Fire callbacks + fire = function() { + + // Enforce single-firing + locked = locked || options.once; + + // Execute callbacks for all pending executions, + // respecting firingIndex overrides and runtime changes + fired = firing = true; + for ( ; queue.length; firingIndex = -1 ) { + memory = queue.shift(); + while ( ++firingIndex < list.length ) { + + // Run callback and check for early termination + if ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false && + options.stopOnFalse ) { + + // Jump to end and forget the data so .add doesn't re-fire + firingIndex = list.length; + memory = false; + } + } + } + + // Forget the data if we're done with it + if ( !options.memory ) { + memory = false; + } + + firing = false; + + // Clean up if we're done firing for good + if ( locked ) { + + // Keep an empty list if we have data for future add calls + if ( memory ) { + list = []; + + // Otherwise, this object is spent + } else { + list = ""; + } + } + }, + + // Actual Callbacks object + self = { + + // Add a callback or a collection of callbacks to the list + add: function() { + if ( list ) { + + // If we have memory from a past run, we should fire after adding + if ( memory && !firing ) { + firingIndex = list.length - 1; + queue.push( memory ); + } + + ( function add( args ) { + jQuery.each( args, function( _, arg ) { + if ( isFunction( arg ) ) { + if ( !options.unique || !self.has( arg ) ) { + list.push( arg ); + } + } else if ( arg && arg.length && toType( arg ) !== "string" ) { + + // Inspect recursively + add( arg ); + } + } ); + } )( arguments ); + + if ( memory && !firing ) { + fire(); + } + } + return this; + }, + + // Remove a callback from the list + remove: function() { + jQuery.each( arguments, function( _, arg ) { + var index; + while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) { + list.splice( index, 1 ); + + // Handle firing indexes + if ( index <= firingIndex ) { + firingIndex--; + } + } + } ); + return this; + }, + + // Check if a given callback is in the list. + // If no argument is given, return whether or not list has callbacks attached. + has: function( fn ) { + return fn ? + jQuery.inArray( fn, list ) > -1 : + list.length > 0; + }, + + // Remove all callbacks from the list + empty: function() { + if ( list ) { + list = []; + } + return this; + }, + + // Disable .fire and .add + // Abort any current/pending executions + // Clear all callbacks and values + disable: function() { + locked = queue = []; + list = memory = ""; + return this; + }, + disabled: function() { + return !list; + }, + + // Disable .fire + // Also disable .add unless we have memory (since it would have no effect) + // Abort any pending executions + lock: function() { + locked = queue = []; + if ( !memory && !firing ) { + list = memory = ""; + } + return this; + }, + locked: function() { + return !!locked; + }, + + // Call all callbacks with the given context and arguments + fireWith: function( context, args ) { + if ( !locked ) { + args = args || []; + args = [ context, args.slice ? args.slice() : args ]; + queue.push( args ); + if ( !firing ) { + fire(); + } + } + return this; + }, + + // Call all the callbacks with the given arguments + fire: function() { + self.fireWith( this, arguments ); + return this; + }, + + // To know if the callbacks have already been called at least once + fired: function() { + return !!fired; + } + }; + + return self; +}; + + +function Identity( v ) { + return v; +} +function Thrower( ex ) { + throw ex; +} + +function adoptValue( value, resolve, reject, noValue ) { + var method; + + try { + + // Check for promise aspect first to privilege synchronous behavior + if ( value && isFunction( ( method = value.promise ) ) ) { + method.call( value ).done( resolve ).fail( reject ); + + // Other thenables + } else if ( value && isFunction( ( method = value.then ) ) ) { + method.call( value, resolve, reject ); + + // Other non-thenables + } else { + + // Control `resolve` arguments by letting Array#slice cast boolean `noValue` to integer: + // * false: [ value ].slice( 0 ) => resolve( value ) + // * true: [ value ].slice( 1 ) => resolve() + resolve.apply( undefined, [ value ].slice( noValue ) ); + } + + // For Promises/A+, convert exceptions into rejections + // Since jQuery.when doesn't unwrap thenables, we can skip the extra checks appearing in + // Deferred#then to conditionally suppress rejection. + } catch ( value ) { + + // Support: Android 4.0 only + // Strict mode functions invoked without .call/.apply get global-object context + reject.apply( undefined, [ value ] ); + } +} + +jQuery.extend( { + + Deferred: function( func ) { + var tuples = [ + + // action, add listener, callbacks, + // ... .then handlers, argument index, [final state] + [ "notify", "progress", jQuery.Callbacks( "memory" ), + jQuery.Callbacks( "memory" ), 2 ], + [ "resolve", "done", jQuery.Callbacks( "once memory" ), + jQuery.Callbacks( "once memory" ), 0, "resolved" ], + [ "reject", "fail", jQuery.Callbacks( "once memory" ), + jQuery.Callbacks( "once memory" ), 1, "rejected" ] + ], + state = "pending", + promise = { + state: function() { + return state; + }, + always: function() { + deferred.done( arguments ).fail( arguments ); + return this; + }, + "catch": function( fn ) { + return promise.then( null, fn ); + }, + + // Keep pipe for back-compat + pipe: function( /* fnDone, fnFail, fnProgress */ ) { + var fns = arguments; + + return jQuery.Deferred( function( newDefer ) { + jQuery.each( tuples, function( _i, tuple ) { + + // Map tuples (progress, done, fail) to arguments (done, fail, progress) + var fn = isFunction( fns[ tuple[ 4 ] ] ) && fns[ tuple[ 4 ] ]; + + // deferred.progress(function() { bind to newDefer or newDefer.notify }) + // deferred.done(function() { bind to newDefer or newDefer.resolve }) + // deferred.fail(function() { bind to newDefer or newDefer.reject }) + deferred[ tuple[ 1 ] ]( function() { + var returned = fn && fn.apply( this, arguments ); + if ( returned && isFunction( returned.promise ) ) { + returned.promise() + .progress( newDefer.notify ) + .done( newDefer.resolve ) + .fail( newDefer.reject ); + } else { + newDefer[ tuple[ 0 ] + "With" ]( + this, + fn ? [ returned ] : arguments + ); + } + } ); + } ); + fns = null; + } ).promise(); + }, + then: function( onFulfilled, onRejected, onProgress ) { + var maxDepth = 0; + function resolve( depth, deferred, handler, special ) { + return function() { + var that = this, + args = arguments, + mightThrow = function() { + var returned, then; + + // Support: Promises/A+ section 2.3.3.3.3 + // https://promisesaplus.com/#point-59 + // Ignore double-resolution attempts + if ( depth < maxDepth ) { + return; + } + + returned = handler.apply( that, args ); + + // Support: Promises/A+ section 2.3.1 + // https://promisesaplus.com/#point-48 + if ( returned === deferred.promise() ) { + throw new TypeError( "Thenable self-resolution" ); + } + + // Support: Promises/A+ sections 2.3.3.1, 3.5 + // https://promisesaplus.com/#point-54 + // https://promisesaplus.com/#point-75 + // Retrieve `then` only once + then = returned && + + // Support: Promises/A+ section 2.3.4 + // https://promisesaplus.com/#point-64 + // Only check objects and functions for thenability + ( typeof returned === "object" || + typeof returned === "function" ) && + returned.then; + + // Handle a returned thenable + if ( isFunction( then ) ) { + + // Special processors (notify) just wait for resolution + if ( special ) { + then.call( + returned, + resolve( maxDepth, deferred, Identity, special ), + resolve( maxDepth, deferred, Thrower, special ) + ); + + // Normal processors (resolve) also hook into progress + } else { + + // ...and disregard older resolution values + maxDepth++; + + then.call( + returned, + resolve( maxDepth, deferred, Identity, special ), + resolve( maxDepth, deferred, Thrower, special ), + resolve( maxDepth, deferred, Identity, + deferred.notifyWith ) + ); + } + + // Handle all other returned values + } else { + + // Only substitute handlers pass on context + // and multiple values (non-spec behavior) + if ( handler !== Identity ) { + that = undefined; + args = [ returned ]; + } + + // Process the value(s) + // Default process is resolve + ( special || deferred.resolveWith )( that, args ); + } + }, + + // Only normal processors (resolve) catch and reject exceptions + process = special ? + mightThrow : + function() { + try { + mightThrow(); + } catch ( e ) { + + if ( jQuery.Deferred.exceptionHook ) { + jQuery.Deferred.exceptionHook( e, + process.stackTrace ); + } + + // Support: Promises/A+ section 2.3.3.3.4.1 + // https://promisesaplus.com/#point-61 + // Ignore post-resolution exceptions + if ( depth + 1 >= maxDepth ) { + + // Only substitute handlers pass on context + // and multiple values (non-spec behavior) + if ( handler !== Thrower ) { + that = undefined; + args = [ e ]; + } + + deferred.rejectWith( that, args ); + } + } + }; + + // Support: Promises/A+ section 2.3.3.3.1 + // https://promisesaplus.com/#point-57 + // Re-resolve promises immediately to dodge false rejection from + // subsequent errors + if ( depth ) { + process(); + } else { + + // Call an optional hook to record the stack, in case of exception + // since it's otherwise lost when execution goes async + if ( jQuery.Deferred.getStackHook ) { + process.stackTrace = jQuery.Deferred.getStackHook(); + } + window.setTimeout( process ); + } + }; + } + + return jQuery.Deferred( function( newDefer ) { + + // progress_handlers.add( ... ) + tuples[ 0 ][ 3 ].add( + resolve( + 0, + newDefer, + isFunction( onProgress ) ? + onProgress : + Identity, + newDefer.notifyWith + ) + ); + + // fulfilled_handlers.add( ... ) + tuples[ 1 ][ 3 ].add( + resolve( + 0, + newDefer, + isFunction( onFulfilled ) ? + onFulfilled : + Identity + ) + ); + + // rejected_handlers.add( ... ) + tuples[ 2 ][ 3 ].add( + resolve( + 0, + newDefer, + isFunction( onRejected ) ? + onRejected : + Thrower + ) + ); + } ).promise(); + }, + + // Get a promise for this deferred + // If obj is provided, the promise aspect is added to the object + promise: function( obj ) { + return obj != null ? jQuery.extend( obj, promise ) : promise; + } + }, + deferred = {}; + + // Add list-specific methods + jQuery.each( tuples, function( i, tuple ) { + var list = tuple[ 2 ], + stateString = tuple[ 5 ]; + + // promise.progress = list.add + // promise.done = list.add + // promise.fail = list.add + promise[ tuple[ 1 ] ] = list.add; + + // Handle state + if ( stateString ) { + list.add( + function() { + + // state = "resolved" (i.e., fulfilled) + // state = "rejected" + state = stateString; + }, + + // rejected_callbacks.disable + // fulfilled_callbacks.disable + tuples[ 3 - i ][ 2 ].disable, + + // rejected_handlers.disable + // fulfilled_handlers.disable + tuples[ 3 - i ][ 3 ].disable, + + // progress_callbacks.lock + tuples[ 0 ][ 2 ].lock, + + // progress_handlers.lock + tuples[ 0 ][ 3 ].lock + ); + } + + // progress_handlers.fire + // fulfilled_handlers.fire + // rejected_handlers.fire + list.add( tuple[ 3 ].fire ); + + // deferred.notify = function() { deferred.notifyWith(...) } + // deferred.resolve = function() { deferred.resolveWith(...) } + // deferred.reject = function() { deferred.rejectWith(...) } + deferred[ tuple[ 0 ] ] = function() { + deferred[ tuple[ 0 ] + "With" ]( this === deferred ? undefined : this, arguments ); + return this; + }; + + // deferred.notifyWith = list.fireWith + // deferred.resolveWith = list.fireWith + // deferred.rejectWith = list.fireWith + deferred[ tuple[ 0 ] + "With" ] = list.fireWith; + } ); + + // Make the deferred a promise + promise.promise( deferred ); + + // Call given func if any + if ( func ) { + func.call( deferred, deferred ); + } + + // All done! + return deferred; + }, + + // Deferred helper + when: function( singleValue ) { + var + + // count of uncompleted subordinates + remaining = arguments.length, + + // count of unprocessed arguments + i = remaining, + + // subordinate fulfillment data + resolveContexts = Array( i ), + resolveValues = slice.call( arguments ), + + // the master Deferred + master = jQuery.Deferred(), + + // subordinate callback factory + updateFunc = function( i ) { + return function( value ) { + resolveContexts[ i ] = this; + resolveValues[ i ] = arguments.length > 1 ? slice.call( arguments ) : value; + if ( !( --remaining ) ) { + master.resolveWith( resolveContexts, resolveValues ); + } + }; + }; + + // Single- and empty arguments are adopted like Promise.resolve + if ( remaining <= 1 ) { + adoptValue( singleValue, master.done( updateFunc( i ) ).resolve, master.reject, + !remaining ); + + // Use .then() to unwrap secondary thenables (cf. gh-3000) + if ( master.state() === "pending" || + isFunction( resolveValues[ i ] && resolveValues[ i ].then ) ) { + + return master.then(); + } + } + + // Multiple arguments are aggregated like Promise.all array elements + while ( i-- ) { + adoptValue( resolveValues[ i ], updateFunc( i ), master.reject ); + } + + return master.promise(); + } +} ); + + +// These usually indicate a programmer mistake during development, +// warn about them ASAP rather than swallowing them by default. +var rerrorNames = /^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/; + +jQuery.Deferred.exceptionHook = function( error, stack ) { + + // Support: IE 8 - 9 only + // Console exists when dev tools are open, which can happen at any time + if ( window.console && window.console.warn && error && rerrorNames.test( error.name ) ) { + window.console.warn( "jQuery.Deferred exception: " + error.message, error.stack, stack ); + } +}; + + + + +jQuery.readyException = function( error ) { + window.setTimeout( function() { + throw error; + } ); +}; + + + + +// The deferred used on DOM ready +var readyList = jQuery.Deferred(); + +jQuery.fn.ready = function( fn ) { + + readyList + .then( fn ) + + // Wrap jQuery.readyException in a function so that the lookup + // happens at the time of error handling instead of callback + // registration. + .catch( function( error ) { + jQuery.readyException( error ); + } ); + + return this; +}; + +jQuery.extend( { + + // Is the DOM ready to be used? Set to true once it occurs. + isReady: false, + + // A counter to track how many items to wait for before + // the ready event fires. See #6781 + readyWait: 1, + + // Handle when the DOM is ready + ready: function( wait ) { + + // Abort if there are pending holds or we're already ready + if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) { + return; + } + + // Remember that the DOM is ready + jQuery.isReady = true; + + // If a normal DOM Ready event fired, decrement, and wait if need be + if ( wait !== true && --jQuery.readyWait > 0 ) { + return; + } + + // If there are functions bound, to execute + readyList.resolveWith( document, [ jQuery ] ); + } +} ); + +jQuery.ready.then = readyList.then; + +// The ready event handler and self cleanup method +function completed() { + document.removeEventListener( "DOMContentLoaded", completed ); + window.removeEventListener( "load", completed ); + jQuery.ready(); +} + +// Catch cases where $(document).ready() is called +// after the browser event has already occurred. +// Support: IE <=9 - 10 only +// Older IE sometimes signals "interactive" too soon +if ( document.readyState === "complete" || + ( document.readyState !== "loading" && !document.documentElement.doScroll ) ) { + + // Handle it asynchronously to allow scripts the opportunity to delay ready + window.setTimeout( jQuery.ready ); + +} else { + + // Use the handy event callback + document.addEventListener( "DOMContentLoaded", completed ); + + // A fallback to window.onload, that will always work + window.addEventListener( "load", completed ); +} + + + + +// Multifunctional method to get and set values of a collection +// The value/s can optionally be executed if it's a function +var access = function( elems, fn, key, value, chainable, emptyGet, raw ) { + var i = 0, + len = elems.length, + bulk = key == null; + + // Sets many values + if ( toType( key ) === "object" ) { + chainable = true; + for ( i in key ) { + access( elems, fn, i, key[ i ], true, emptyGet, raw ); + } + + // Sets one value + } else if ( value !== undefined ) { + chainable = true; + + if ( !isFunction( value ) ) { + raw = true; + } + + if ( bulk ) { + + // Bulk operations run against the entire set + if ( raw ) { + fn.call( elems, value ); + fn = null; + + // ...except when executing function values + } else { + bulk = fn; + fn = function( elem, _key, value ) { + return bulk.call( jQuery( elem ), value ); + }; + } + } + + if ( fn ) { + for ( ; i < len; i++ ) { + fn( + elems[ i ], key, raw ? + value : + value.call( elems[ i ], i, fn( elems[ i ], key ) ) + ); + } + } + } + + if ( chainable ) { + return elems; + } + + // Gets + if ( bulk ) { + return fn.call( elems ); + } + + return len ? fn( elems[ 0 ], key ) : emptyGet; +}; + + +// Matches dashed string for camelizing +var rmsPrefix = /^-ms-/, + rdashAlpha = /-([a-z])/g; + +// Used by camelCase as callback to replace() +function fcamelCase( _all, letter ) { + return letter.toUpperCase(); +} + +// Convert dashed to camelCase; used by the css and data modules +// Support: IE <=9 - 11, Edge 12 - 15 +// Microsoft forgot to hump their vendor prefix (#9572) +function camelCase( string ) { + return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); +} +var acceptData = function( owner ) { + + // Accepts only: + // - Node + // - Node.ELEMENT_NODE + // - Node.DOCUMENT_NODE + // - Object + // - Any + return owner.nodeType === 1 || owner.nodeType === 9 || !( +owner.nodeType ); +}; + + + + +function Data() { + this.expando = jQuery.expando + Data.uid++; +} + +Data.uid = 1; + +Data.prototype = { + + cache: function( owner ) { + + // Check if the owner object already has a cache + var value = owner[ this.expando ]; + + // If not, create one + if ( !value ) { + value = {}; + + // We can accept data for non-element nodes in modern browsers, + // but we should not, see #8335. + // Always return an empty object. + if ( acceptData( owner ) ) { + + // If it is a node unlikely to be stringify-ed or looped over + // use plain assignment + if ( owner.nodeType ) { + owner[ this.expando ] = value; + + // Otherwise secure it in a non-enumerable property + // configurable must be true to allow the property to be + // deleted when data is removed + } else { + Object.defineProperty( owner, this.expando, { + value: value, + configurable: true + } ); + } + } + } + + return value; + }, + set: function( owner, data, value ) { + var prop, + cache = this.cache( owner ); + + // Handle: [ owner, key, value ] args + // Always use camelCase key (gh-2257) + if ( typeof data === "string" ) { + cache[ camelCase( data ) ] = value; + + // Handle: [ owner, { properties } ] args + } else { + + // Copy the properties one-by-one to the cache object + for ( prop in data ) { + cache[ camelCase( prop ) ] = data[ prop ]; + } + } + return cache; + }, + get: function( owner, key ) { + return key === undefined ? + this.cache( owner ) : + + // Always use camelCase key (gh-2257) + owner[ this.expando ] && owner[ this.expando ][ camelCase( key ) ]; + }, + access: function( owner, key, value ) { + + // In cases where either: + // + // 1. No key was specified + // 2. A string key was specified, but no value provided + // + // Take the "read" path and allow the get method to determine + // which value to return, respectively either: + // + // 1. The entire cache object + // 2. The data stored at the key + // + if ( key === undefined || + ( ( key && typeof key === "string" ) && value === undefined ) ) { + + return this.get( owner, key ); + } + + // When the key is not a string, or both a key and value + // are specified, set or extend (existing objects) with either: + // + // 1. An object of properties + // 2. A key and value + // + this.set( owner, key, value ); + + // Since the "set" path can have two possible entry points + // return the expected data based on which path was taken[*] + return value !== undefined ? value : key; + }, + remove: function( owner, key ) { + var i, + cache = owner[ this.expando ]; + + if ( cache === undefined ) { + return; + } + + if ( key !== undefined ) { + + // Support array or space separated string of keys + if ( Array.isArray( key ) ) { + + // If key is an array of keys... + // We always set camelCase keys, so remove that. + key = key.map( camelCase ); + } else { + key = camelCase( key ); + + // If a key with the spaces exists, use it. + // Otherwise, create an array by matching non-whitespace + key = key in cache ? + [ key ] : + ( key.match( rnothtmlwhite ) || [] ); + } + + i = key.length; + + while ( i-- ) { + delete cache[ key[ i ] ]; + } + } + + // Remove the expando if there's no more data + if ( key === undefined || jQuery.isEmptyObject( cache ) ) { + + // Support: Chrome <=35 - 45 + // Webkit & Blink performance suffers when deleting properties + // from DOM nodes, so set to undefined instead + // https://bugs.chromium.org/p/chromium/issues/detail?id=378607 (bug restricted) + if ( owner.nodeType ) { + owner[ this.expando ] = undefined; + } else { + delete owner[ this.expando ]; + } + } + }, + hasData: function( owner ) { + var cache = owner[ this.expando ]; + return cache !== undefined && !jQuery.isEmptyObject( cache ); + } +}; +var dataPriv = new Data(); + +var dataUser = new Data(); + + + +// Implementation Summary +// +// 1. Enforce API surface and semantic compatibility with 1.9.x branch +// 2. Improve the module's maintainability by reducing the storage +// paths to a single mechanism. +// 3. Use the same single mechanism to support "private" and "user" data. +// 4. _Never_ expose "private" data to user code (TODO: Drop _data, _removeData) +// 5. Avoid exposing implementation details on user objects (eg. expando properties) +// 6. Provide a clear path for implementation upgrade to WeakMap in 2014 + +var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/, + rmultiDash = /[A-Z]/g; + +function getData( data ) { + if ( data === "true" ) { + return true; + } + + if ( data === "false" ) { + return false; + } + + if ( data === "null" ) { + return null; + } + + // Only convert to a number if it doesn't change the string + if ( data === +data + "" ) { + return +data; + } + + if ( rbrace.test( data ) ) { + return JSON.parse( data ); + } + + return data; +} + +function dataAttr( elem, key, data ) { + var name; + + // If nothing was found internally, try to fetch any + // data from the HTML5 data-* attribute + if ( data === undefined && elem.nodeType === 1 ) { + name = "data-" + key.replace( rmultiDash, "-$&" ).toLowerCase(); + data = elem.getAttribute( name ); + + if ( typeof data === "string" ) { + try { + data = getData( data ); + } catch ( e ) {} + + // Make sure we set the data so it isn't changed later + dataUser.set( elem, key, data ); + } else { + data = undefined; + } + } + return data; +} + +jQuery.extend( { + hasData: function( elem ) { + return dataUser.hasData( elem ) || dataPriv.hasData( elem ); + }, + + data: function( elem, name, data ) { + return dataUser.access( elem, name, data ); + }, + + removeData: function( elem, name ) { + dataUser.remove( elem, name ); + }, + + // TODO: Now that all calls to _data and _removeData have been replaced + // with direct calls to dataPriv methods, these can be deprecated. + _data: function( elem, name, data ) { + return dataPriv.access( elem, name, data ); + }, + + _removeData: function( elem, name ) { + dataPriv.remove( elem, name ); + } +} ); + +jQuery.fn.extend( { + data: function( key, value ) { + var i, name, data, + elem = this[ 0 ], + attrs = elem && elem.attributes; + + // Gets all values + if ( key === undefined ) { + if ( this.length ) { + data = dataUser.get( elem ); + + if ( elem.nodeType === 1 && !dataPriv.get( elem, "hasDataAttrs" ) ) { + i = attrs.length; + while ( i-- ) { + + // Support: IE 11 only + // The attrs elements can be null (#14894) + if ( attrs[ i ] ) { + name = attrs[ i ].name; + if ( name.indexOf( "data-" ) === 0 ) { + name = camelCase( name.slice( 5 ) ); + dataAttr( elem, name, data[ name ] ); + } + } + } + dataPriv.set( elem, "hasDataAttrs", true ); + } + } + + return data; + } + + // Sets multiple values + if ( typeof key === "object" ) { + return this.each( function() { + dataUser.set( this, key ); + } ); + } + + return access( this, function( value ) { + var data; + + // The calling jQuery object (element matches) is not empty + // (and therefore has an element appears at this[ 0 ]) and the + // `value` parameter was not undefined. An empty jQuery object + // will result in `undefined` for elem = this[ 0 ] which will + // throw an exception if an attempt to read a data cache is made. + if ( elem && value === undefined ) { + + // Attempt to get data from the cache + // The key will always be camelCased in Data + data = dataUser.get( elem, key ); + if ( data !== undefined ) { + return data; + } + + // Attempt to "discover" the data in + // HTML5 custom data-* attrs + data = dataAttr( elem, key ); + if ( data !== undefined ) { + return data; + } + + // We tried really hard, but the data doesn't exist. + return; + } + + // Set the data... + this.each( function() { + + // We always store the camelCased key + dataUser.set( this, key, value ); + } ); + }, null, value, arguments.length > 1, null, true ); + }, + + removeData: function( key ) { + return this.each( function() { + dataUser.remove( this, key ); + } ); + } +} ); + + +jQuery.extend( { + queue: function( elem, type, data ) { + var queue; + + if ( elem ) { + type = ( type || "fx" ) + "queue"; + queue = dataPriv.get( elem, type ); + + // Speed up dequeue by getting out quickly if this is just a lookup + if ( data ) { + if ( !queue || Array.isArray( data ) ) { + queue = dataPriv.access( elem, type, jQuery.makeArray( data ) ); + } else { + queue.push( data ); + } + } + return queue || []; + } + }, + + dequeue: function( elem, type ) { + type = type || "fx"; + + var queue = jQuery.queue( elem, type ), + startLength = queue.length, + fn = queue.shift(), + hooks = jQuery._queueHooks( elem, type ), + next = function() { + jQuery.dequeue( elem, type ); + }; + + // If the fx queue is dequeued, always remove the progress sentinel + if ( fn === "inprogress" ) { + fn = queue.shift(); + startLength--; + } + + if ( fn ) { + + // Add a progress sentinel to prevent the fx queue from being + // automatically dequeued + if ( type === "fx" ) { + queue.unshift( "inprogress" ); + } + + // Clear up the last queue stop function + delete hooks.stop; + fn.call( elem, next, hooks ); + } + + if ( !startLength && hooks ) { + hooks.empty.fire(); + } + }, + + // Not public - generate a queueHooks object, or return the current one + _queueHooks: function( elem, type ) { + var key = type + "queueHooks"; + return dataPriv.get( elem, key ) || dataPriv.access( elem, key, { + empty: jQuery.Callbacks( "once memory" ).add( function() { + dataPriv.remove( elem, [ type + "queue", key ] ); + } ) + } ); + } +} ); + +jQuery.fn.extend( { + queue: function( type, data ) { + var setter = 2; + + if ( typeof type !== "string" ) { + data = type; + type = "fx"; + setter--; + } + + if ( arguments.length < setter ) { + return jQuery.queue( this[ 0 ], type ); + } + + return data === undefined ? + this : + this.each( function() { + var queue = jQuery.queue( this, type, data ); + + // Ensure a hooks for this queue + jQuery._queueHooks( this, type ); + + if ( type === "fx" && queue[ 0 ] !== "inprogress" ) { + jQuery.dequeue( this, type ); + } + } ); + }, + dequeue: function( type ) { + return this.each( function() { + jQuery.dequeue( this, type ); + } ); + }, + clearQueue: function( type ) { + return this.queue( type || "fx", [] ); + }, + + // Get a promise resolved when queues of a certain type + // are emptied (fx is the type by default) + promise: function( type, obj ) { + var tmp, + count = 1, + defer = jQuery.Deferred(), + elements = this, + i = this.length, + resolve = function() { + if ( !( --count ) ) { + defer.resolveWith( elements, [ elements ] ); + } + }; + + if ( typeof type !== "string" ) { + obj = type; + type = undefined; + } + type = type || "fx"; + + while ( i-- ) { + tmp = dataPriv.get( elements[ i ], type + "queueHooks" ); + if ( tmp && tmp.empty ) { + count++; + tmp.empty.add( resolve ); + } + } + resolve(); + return defer.promise( obj ); + } +} ); +var pnum = ( /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/ ).source; + +var rcssNum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" ); + + +var cssExpand = [ "Top", "Right", "Bottom", "Left" ]; + +var documentElement = document.documentElement; + + + + var isAttached = function( elem ) { + return jQuery.contains( elem.ownerDocument, elem ); + }, + composed = { composed: true }; + + // Support: IE 9 - 11+, Edge 12 - 18+, iOS 10.0 - 10.2 only + // Check attachment across shadow DOM boundaries when possible (gh-3504) + // Support: iOS 10.0-10.2 only + // Early iOS 10 versions support `attachShadow` but not `getRootNode`, + // leading to errors. We need to check for `getRootNode`. + if ( documentElement.getRootNode ) { + isAttached = function( elem ) { + return jQuery.contains( elem.ownerDocument, elem ) || + elem.getRootNode( composed ) === elem.ownerDocument; + }; + } +var isHiddenWithinTree = function( elem, el ) { + + // isHiddenWithinTree might be called from jQuery#filter function; + // in that case, element will be second argument + elem = el || elem; + + // Inline style trumps all + return elem.style.display === "none" || + elem.style.display === "" && + + // Otherwise, check computed style + // Support: Firefox <=43 - 45 + // Disconnected elements can have computed display: none, so first confirm that elem is + // in the document. + isAttached( elem ) && + + jQuery.css( elem, "display" ) === "none"; + }; + + + +function adjustCSS( elem, prop, valueParts, tween ) { + var adjusted, scale, + maxIterations = 20, + currentValue = tween ? + function() { + return tween.cur(); + } : + function() { + return jQuery.css( elem, prop, "" ); + }, + initial = currentValue(), + unit = valueParts && valueParts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ), + + // Starting value computation is required for potential unit mismatches + initialInUnit = elem.nodeType && + ( jQuery.cssNumber[ prop ] || unit !== "px" && +initial ) && + rcssNum.exec( jQuery.css( elem, prop ) ); + + if ( initialInUnit && initialInUnit[ 3 ] !== unit ) { + + // Support: Firefox <=54 + // Halve the iteration target value to prevent interference from CSS upper bounds (gh-2144) + initial = initial / 2; + + // Trust units reported by jQuery.css + unit = unit || initialInUnit[ 3 ]; + + // Iteratively approximate from a nonzero starting point + initialInUnit = +initial || 1; + + while ( maxIterations-- ) { + + // Evaluate and update our best guess (doubling guesses that zero out). + // Finish if the scale equals or crosses 1 (making the old*new product non-positive). + jQuery.style( elem, prop, initialInUnit + unit ); + if ( ( 1 - scale ) * ( 1 - ( scale = currentValue() / initial || 0.5 ) ) <= 0 ) { + maxIterations = 0; + } + initialInUnit = initialInUnit / scale; + + } + + initialInUnit = initialInUnit * 2; + jQuery.style( elem, prop, initialInUnit + unit ); + + // Make sure we update the tween properties later on + valueParts = valueParts || []; + } + + if ( valueParts ) { + initialInUnit = +initialInUnit || +initial || 0; + + // Apply relative offset (+=/-=) if specified + adjusted = valueParts[ 1 ] ? + initialInUnit + ( valueParts[ 1 ] + 1 ) * valueParts[ 2 ] : + +valueParts[ 2 ]; + if ( tween ) { + tween.unit = unit; + tween.start = initialInUnit; + tween.end = adjusted; + } + } + return adjusted; +} + + +var defaultDisplayMap = {}; + +function getDefaultDisplay( elem ) { + var temp, + doc = elem.ownerDocument, + nodeName = elem.nodeName, + display = defaultDisplayMap[ nodeName ]; + + if ( display ) { + return display; + } + + temp = doc.body.appendChild( doc.createElement( nodeName ) ); + display = jQuery.css( temp, "display" ); + + temp.parentNode.removeChild( temp ); + + if ( display === "none" ) { + display = "block"; + } + defaultDisplayMap[ nodeName ] = display; + + return display; +} + +function showHide( elements, show ) { + var display, elem, + values = [], + index = 0, + length = elements.length; + + // Determine new display value for elements that need to change + for ( ; index < length; index++ ) { + elem = elements[ index ]; + if ( !elem.style ) { + continue; + } + + display = elem.style.display; + if ( show ) { + + // Since we force visibility upon cascade-hidden elements, an immediate (and slow) + // check is required in this first loop unless we have a nonempty display value (either + // inline or about-to-be-restored) + if ( display === "none" ) { + values[ index ] = dataPriv.get( elem, "display" ) || null; + if ( !values[ index ] ) { + elem.style.display = ""; + } + } + if ( elem.style.display === "" && isHiddenWithinTree( elem ) ) { + values[ index ] = getDefaultDisplay( elem ); + } + } else { + if ( display !== "none" ) { + values[ index ] = "none"; + + // Remember what we're overwriting + dataPriv.set( elem, "display", display ); + } + } + } + + // Set the display of the elements in a second loop to avoid constant reflow + for ( index = 0; index < length; index++ ) { + if ( values[ index ] != null ) { + elements[ index ].style.display = values[ index ]; + } + } + + return elements; +} + +jQuery.fn.extend( { + show: function() { + return showHide( this, true ); + }, + hide: function() { + return showHide( this ); + }, + toggle: function( state ) { + if ( typeof state === "boolean" ) { + return state ? this.show() : this.hide(); + } + + return this.each( function() { + if ( isHiddenWithinTree( this ) ) { + jQuery( this ).show(); + } else { + jQuery( this ).hide(); + } + } ); + } +} ); +var rcheckableType = ( /^(?:checkbox|radio)$/i ); + +var rtagName = ( /<([a-z][^\/\0>\x20\t\r\n\f]*)/i ); + +var rscriptType = ( /^$|^module$|\/(?:java|ecma)script/i ); + + + +( function() { + var fragment = document.createDocumentFragment(), + div = fragment.appendChild( document.createElement( "div" ) ), + input = document.createElement( "input" ); + + // Support: Android 4.0 - 4.3 only + // Check state lost if the name is set (#11217) + // Support: Windows Web Apps (WWA) + // `name` and `type` must use .setAttribute for WWA (#14901) + input.setAttribute( "type", "radio" ); + input.setAttribute( "checked", "checked" ); + input.setAttribute( "name", "t" ); + + div.appendChild( input ); + + // Support: Android <=4.1 only + // Older WebKit doesn't clone checked state correctly in fragments + support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked; + + // Support: IE <=11 only + // Make sure textarea (and checkbox) defaultValue is properly cloned + div.innerHTML = ""; + support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue; + + // Support: IE <=9 only + // IE <=9 replaces "; + support.option = !!div.lastChild; +} )(); + + +// We have to close these tags to support XHTML (#13200) +var wrapMap = { + + // XHTML parsers do not magically insert elements in the + // same way that tag soup parsers do. So we cannot shorten + // this by omitting or other required elements. + thead: [ 1, "", "
" ], + col: [ 2, "", "
" ], + tr: [ 2, "", "
" ], + td: [ 3, "", "
" ], + + _default: [ 0, "", "" ] +}; + +wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; +wrapMap.th = wrapMap.td; + +// Support: IE <=9 only +if ( !support.option ) { + wrapMap.optgroup = wrapMap.option = [ 1, "" ]; +} + + +function getAll( context, tag ) { + + // Support: IE <=9 - 11 only + // Use typeof to avoid zero-argument method invocation on host objects (#15151) + var ret; + + if ( typeof context.getElementsByTagName !== "undefined" ) { + ret = context.getElementsByTagName( tag || "*" ); + + } else if ( typeof context.querySelectorAll !== "undefined" ) { + ret = context.querySelectorAll( tag || "*" ); + + } else { + ret = []; + } + + if ( tag === undefined || tag && nodeName( context, tag ) ) { + return jQuery.merge( [ context ], ret ); + } + + return ret; +} + + +// Mark scripts as having already been evaluated +function setGlobalEval( elems, refElements ) { + var i = 0, + l = elems.length; + + for ( ; i < l; i++ ) { + dataPriv.set( + elems[ i ], + "globalEval", + !refElements || dataPriv.get( refElements[ i ], "globalEval" ) + ); + } +} + + +var rhtml = /<|&#?\w+;/; + +function buildFragment( elems, context, scripts, selection, ignored ) { + var elem, tmp, tag, wrap, attached, j, + fragment = context.createDocumentFragment(), + nodes = [], + i = 0, + l = elems.length; + + for ( ; i < l; i++ ) { + elem = elems[ i ]; + + if ( elem || elem === 0 ) { + + // Add nodes directly + if ( toType( elem ) === "object" ) { + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem ); + + // Convert non-html into a text node + } else if ( !rhtml.test( elem ) ) { + nodes.push( context.createTextNode( elem ) ); + + // Convert html into DOM nodes + } else { + tmp = tmp || fragment.appendChild( context.createElement( "div" ) ); + + // Deserialize a standard representation + tag = ( rtagName.exec( elem ) || [ "", "" ] )[ 1 ].toLowerCase(); + wrap = wrapMap[ tag ] || wrapMap._default; + tmp.innerHTML = wrap[ 1 ] + jQuery.htmlPrefilter( elem ) + wrap[ 2 ]; + + // Descend through wrappers to the right content + j = wrap[ 0 ]; + while ( j-- ) { + tmp = tmp.lastChild; + } + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( nodes, tmp.childNodes ); + + // Remember the top-level container + tmp = fragment.firstChild; + + // Ensure the created nodes are orphaned (#12392) + tmp.textContent = ""; + } + } + } + + // Remove wrapper from fragment + fragment.textContent = ""; + + i = 0; + while ( ( elem = nodes[ i++ ] ) ) { + + // Skip elements already in the context collection (trac-4087) + if ( selection && jQuery.inArray( elem, selection ) > -1 ) { + if ( ignored ) { + ignored.push( elem ); + } + continue; + } + + attached = isAttached( elem ); + + // Append to fragment + tmp = getAll( fragment.appendChild( elem ), "script" ); + + // Preserve script evaluation history + if ( attached ) { + setGlobalEval( tmp ); + } + + // Capture executables + if ( scripts ) { + j = 0; + while ( ( elem = tmp[ j++ ] ) ) { + if ( rscriptType.test( elem.type || "" ) ) { + scripts.push( elem ); + } + } + } + } + + return fragment; +} + + +var + rkeyEvent = /^key/, + rmouseEvent = /^(?:mouse|pointer|contextmenu|drag|drop)|click/, + rtypenamespace = /^([^.]*)(?:\.(.+)|)/; + +function returnTrue() { + return true; +} + +function returnFalse() { + return false; +} + +// Support: IE <=9 - 11+ +// focus() and blur() are asynchronous, except when they are no-op. +// So expect focus to be synchronous when the element is already active, +// and blur to be synchronous when the element is not already active. +// (focus and blur are always synchronous in other supported browsers, +// this just defines when we can count on it). +function expectSync( elem, type ) { + return ( elem === safeActiveElement() ) === ( type === "focus" ); +} + +// Support: IE <=9 only +// Accessing document.activeElement can throw unexpectedly +// https://bugs.jquery.com/ticket/13393 +function safeActiveElement() { + try { + return document.activeElement; + } catch ( err ) { } +} + +function on( elem, types, selector, data, fn, one ) { + var origFn, type; + + // Types can be a map of types/handlers + if ( typeof types === "object" ) { + + // ( types-Object, selector, data ) + if ( typeof selector !== "string" ) { + + // ( types-Object, data ) + data = data || selector; + selector = undefined; + } + for ( type in types ) { + on( elem, type, selector, data, types[ type ], one ); + } + return elem; + } + + if ( data == null && fn == null ) { + + // ( types, fn ) + fn = selector; + data = selector = undefined; + } else if ( fn == null ) { + if ( typeof selector === "string" ) { + + // ( types, selector, fn ) + fn = data; + data = undefined; + } else { + + // ( types, data, fn ) + fn = data; + data = selector; + selector = undefined; + } + } + if ( fn === false ) { + fn = returnFalse; + } else if ( !fn ) { + return elem; + } + + if ( one === 1 ) { + origFn = fn; + fn = function( event ) { + + // Can use an empty set, since event contains the info + jQuery().off( event ); + return origFn.apply( this, arguments ); + }; + + // Use same guid so caller can remove using origFn + fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); + } + return elem.each( function() { + jQuery.event.add( this, types, fn, data, selector ); + } ); +} + +/* + * Helper functions for managing events -- not part of the public interface. + * Props to Dean Edwards' addEvent library for many of the ideas. + */ +jQuery.event = { + + global: {}, + + add: function( elem, types, handler, data, selector ) { + + var handleObjIn, eventHandle, tmp, + events, t, handleObj, + special, handlers, type, namespaces, origType, + elemData = dataPriv.get( elem ); + + // Only attach events to objects that accept data + if ( !acceptData( elem ) ) { + return; + } + + // Caller can pass in an object of custom data in lieu of the handler + if ( handler.handler ) { + handleObjIn = handler; + handler = handleObjIn.handler; + selector = handleObjIn.selector; + } + + // Ensure that invalid selectors throw exceptions at attach time + // Evaluate against documentElement in case elem is a non-element node (e.g., document) + if ( selector ) { + jQuery.find.matchesSelector( documentElement, selector ); + } + + // Make sure that the handler has a unique ID, used to find/remove it later + if ( !handler.guid ) { + handler.guid = jQuery.guid++; + } + + // Init the element's event structure and main handler, if this is the first + if ( !( events = elemData.events ) ) { + events = elemData.events = Object.create( null ); + } + if ( !( eventHandle = elemData.handle ) ) { + eventHandle = elemData.handle = function( e ) { + + // Discard the second event of a jQuery.event.trigger() and + // when an event is called after a page has unloaded + return typeof jQuery !== "undefined" && jQuery.event.triggered !== e.type ? + jQuery.event.dispatch.apply( elem, arguments ) : undefined; + }; + } + + // Handle multiple events separated by a space + types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[ t ] ) || []; + type = origType = tmp[ 1 ]; + namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); + + // There *must* be a type, no attaching namespace-only handlers + if ( !type ) { + continue; + } + + // If event changes its type, use the special event handlers for the changed type + special = jQuery.event.special[ type ] || {}; + + // If selector defined, determine special event api type, otherwise given type + type = ( selector ? special.delegateType : special.bindType ) || type; + + // Update special based on newly reset type + special = jQuery.event.special[ type ] || {}; + + // handleObj is passed to all event handlers + handleObj = jQuery.extend( { + type: type, + origType: origType, + data: data, + handler: handler, + guid: handler.guid, + selector: selector, + needsContext: selector && jQuery.expr.match.needsContext.test( selector ), + namespace: namespaces.join( "." ) + }, handleObjIn ); + + // Init the event handler queue if we're the first + if ( !( handlers = events[ type ] ) ) { + handlers = events[ type ] = []; + handlers.delegateCount = 0; + + // Only use addEventListener if the special events handler returns false + if ( !special.setup || + special.setup.call( elem, data, namespaces, eventHandle ) === false ) { + + if ( elem.addEventListener ) { + elem.addEventListener( type, eventHandle ); + } + } + } + + if ( special.add ) { + special.add.call( elem, handleObj ); + + if ( !handleObj.handler.guid ) { + handleObj.handler.guid = handler.guid; + } + } + + // Add to the element's handler list, delegates in front + if ( selector ) { + handlers.splice( handlers.delegateCount++, 0, handleObj ); + } else { + handlers.push( handleObj ); + } + + // Keep track of which events have ever been used, for event optimization + jQuery.event.global[ type ] = true; + } + + }, + + // Detach an event or set of events from an element + remove: function( elem, types, handler, selector, mappedTypes ) { + + var j, origCount, tmp, + events, t, handleObj, + special, handlers, type, namespaces, origType, + elemData = dataPriv.hasData( elem ) && dataPriv.get( elem ); + + if ( !elemData || !( events = elemData.events ) ) { + return; + } + + // Once for each type.namespace in types; type may be omitted + types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[ t ] ) || []; + type = origType = tmp[ 1 ]; + namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); + + // Unbind all events (on this namespace, if provided) for the element + if ( !type ) { + for ( type in events ) { + jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); + } + continue; + } + + special = jQuery.event.special[ type ] || {}; + type = ( selector ? special.delegateType : special.bindType ) || type; + handlers = events[ type ] || []; + tmp = tmp[ 2 ] && + new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ); + + // Remove matching events + origCount = j = handlers.length; + while ( j-- ) { + handleObj = handlers[ j ]; + + if ( ( mappedTypes || origType === handleObj.origType ) && + ( !handler || handler.guid === handleObj.guid ) && + ( !tmp || tmp.test( handleObj.namespace ) ) && + ( !selector || selector === handleObj.selector || + selector === "**" && handleObj.selector ) ) { + handlers.splice( j, 1 ); + + if ( handleObj.selector ) { + handlers.delegateCount--; + } + if ( special.remove ) { + special.remove.call( elem, handleObj ); + } + } + } + + // Remove generic event handler if we removed something and no more handlers exist + // (avoids potential for endless recursion during removal of special event handlers) + if ( origCount && !handlers.length ) { + if ( !special.teardown || + special.teardown.call( elem, namespaces, elemData.handle ) === false ) { + + jQuery.removeEvent( elem, type, elemData.handle ); + } + + delete events[ type ]; + } + } + + // Remove data and the expando if it's no longer used + if ( jQuery.isEmptyObject( events ) ) { + dataPriv.remove( elem, "handle events" ); + } + }, + + dispatch: function( nativeEvent ) { + + var i, j, ret, matched, handleObj, handlerQueue, + args = new Array( arguments.length ), + + // Make a writable jQuery.Event from the native event object + event = jQuery.event.fix( nativeEvent ), + + handlers = ( + dataPriv.get( this, "events" ) || Object.create( null ) + )[ event.type ] || [], + special = jQuery.event.special[ event.type ] || {}; + + // Use the fix-ed jQuery.Event rather than the (read-only) native event + args[ 0 ] = event; + + for ( i = 1; i < arguments.length; i++ ) { + args[ i ] = arguments[ i ]; + } + + event.delegateTarget = this; + + // Call the preDispatch hook for the mapped type, and let it bail if desired + if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { + return; + } + + // Determine handlers + handlerQueue = jQuery.event.handlers.call( this, event, handlers ); + + // Run delegates first; they may want to stop propagation beneath us + i = 0; + while ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) { + event.currentTarget = matched.elem; + + j = 0; + while ( ( handleObj = matched.handlers[ j++ ] ) && + !event.isImmediatePropagationStopped() ) { + + // If the event is namespaced, then each handler is only invoked if it is + // specially universal or its namespaces are a superset of the event's. + if ( !event.rnamespace || handleObj.namespace === false || + event.rnamespace.test( handleObj.namespace ) ) { + + event.handleObj = handleObj; + event.data = handleObj.data; + + ret = ( ( jQuery.event.special[ handleObj.origType ] || {} ).handle || + handleObj.handler ).apply( matched.elem, args ); + + if ( ret !== undefined ) { + if ( ( event.result = ret ) === false ) { + event.preventDefault(); + event.stopPropagation(); + } + } + } + } + } + + // Call the postDispatch hook for the mapped type + if ( special.postDispatch ) { + special.postDispatch.call( this, event ); + } + + return event.result; + }, + + handlers: function( event, handlers ) { + var i, handleObj, sel, matchedHandlers, matchedSelectors, + handlerQueue = [], + delegateCount = handlers.delegateCount, + cur = event.target; + + // Find delegate handlers + if ( delegateCount && + + // Support: IE <=9 + // Black-hole SVG instance trees (trac-13180) + cur.nodeType && + + // Support: Firefox <=42 + // Suppress spec-violating clicks indicating a non-primary pointer button (trac-3861) + // https://www.w3.org/TR/DOM-Level-3-Events/#event-type-click + // Support: IE 11 only + // ...but not arrow key "clicks" of radio inputs, which can have `button` -1 (gh-2343) + !( event.type === "click" && event.button >= 1 ) ) { + + for ( ; cur !== this; cur = cur.parentNode || this ) { + + // Don't check non-elements (#13208) + // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764) + if ( cur.nodeType === 1 && !( event.type === "click" && cur.disabled === true ) ) { + matchedHandlers = []; + matchedSelectors = {}; + for ( i = 0; i < delegateCount; i++ ) { + handleObj = handlers[ i ]; + + // Don't conflict with Object.prototype properties (#13203) + sel = handleObj.selector + " "; + + if ( matchedSelectors[ sel ] === undefined ) { + matchedSelectors[ sel ] = handleObj.needsContext ? + jQuery( sel, this ).index( cur ) > -1 : + jQuery.find( sel, this, null, [ cur ] ).length; + } + if ( matchedSelectors[ sel ] ) { + matchedHandlers.push( handleObj ); + } + } + if ( matchedHandlers.length ) { + handlerQueue.push( { elem: cur, handlers: matchedHandlers } ); + } + } + } + } + + // Add the remaining (directly-bound) handlers + cur = this; + if ( delegateCount < handlers.length ) { + handlerQueue.push( { elem: cur, handlers: handlers.slice( delegateCount ) } ); + } + + return handlerQueue; + }, + + addProp: function( name, hook ) { + Object.defineProperty( jQuery.Event.prototype, name, { + enumerable: true, + configurable: true, + + get: isFunction( hook ) ? + function() { + if ( this.originalEvent ) { + return hook( this.originalEvent ); + } + } : + function() { + if ( this.originalEvent ) { + return this.originalEvent[ name ]; + } + }, + + set: function( value ) { + Object.defineProperty( this, name, { + enumerable: true, + configurable: true, + writable: true, + value: value + } ); + } + } ); + }, + + fix: function( originalEvent ) { + return originalEvent[ jQuery.expando ] ? + originalEvent : + new jQuery.Event( originalEvent ); + }, + + special: { + load: { + + // Prevent triggered image.load events from bubbling to window.load + noBubble: true + }, + click: { + + // Utilize native event to ensure correct state for checkable inputs + setup: function( data ) { + + // For mutual compressibility with _default, replace `this` access with a local var. + // `|| data` is dead code meant only to preserve the variable through minification. + var el = this || data; + + // Claim the first handler + if ( rcheckableType.test( el.type ) && + el.click && nodeName( el, "input" ) ) { + + // dataPriv.set( el, "click", ... ) + leverageNative( el, "click", returnTrue ); + } + + // Return false to allow normal processing in the caller + return false; + }, + trigger: function( data ) { + + // For mutual compressibility with _default, replace `this` access with a local var. + // `|| data` is dead code meant only to preserve the variable through minification. + var el = this || data; + + // Force setup before triggering a click + if ( rcheckableType.test( el.type ) && + el.click && nodeName( el, "input" ) ) { + + leverageNative( el, "click" ); + } + + // Return non-false to allow normal event-path propagation + return true; + }, + + // For cross-browser consistency, suppress native .click() on links + // Also prevent it if we're currently inside a leveraged native-event stack + _default: function( event ) { + var target = event.target; + return rcheckableType.test( target.type ) && + target.click && nodeName( target, "input" ) && + dataPriv.get( target, "click" ) || + nodeName( target, "a" ); + } + }, + + beforeunload: { + postDispatch: function( event ) { + + // Support: Firefox 20+ + // Firefox doesn't alert if the returnValue field is not set. + if ( event.result !== undefined && event.originalEvent ) { + event.originalEvent.returnValue = event.result; + } + } + } + } +}; + +// Ensure the presence of an event listener that handles manually-triggered +// synthetic events by interrupting progress until reinvoked in response to +// *native* events that it fires directly, ensuring that state changes have +// already occurred before other listeners are invoked. +function leverageNative( el, type, expectSync ) { + + // Missing expectSync indicates a trigger call, which must force setup through jQuery.event.add + if ( !expectSync ) { + if ( dataPriv.get( el, type ) === undefined ) { + jQuery.event.add( el, type, returnTrue ); + } + return; + } + + // Register the controller as a special universal handler for all event namespaces + dataPriv.set( el, type, false ); + jQuery.event.add( el, type, { + namespace: false, + handler: function( event ) { + var notAsync, result, + saved = dataPriv.get( this, type ); + + if ( ( event.isTrigger & 1 ) && this[ type ] ) { + + // Interrupt processing of the outer synthetic .trigger()ed event + // Saved data should be false in such cases, but might be a leftover capture object + // from an async native handler (gh-4350) + if ( !saved.length ) { + + // Store arguments for use when handling the inner native event + // There will always be at least one argument (an event object), so this array + // will not be confused with a leftover capture object. + saved = slice.call( arguments ); + dataPriv.set( this, type, saved ); + + // Trigger the native event and capture its result + // Support: IE <=9 - 11+ + // focus() and blur() are asynchronous + notAsync = expectSync( this, type ); + this[ type ](); + result = dataPriv.get( this, type ); + if ( saved !== result || notAsync ) { + dataPriv.set( this, type, false ); + } else { + result = {}; + } + if ( saved !== result ) { + + // Cancel the outer synthetic event + event.stopImmediatePropagation(); + event.preventDefault(); + return result.value; + } + + // If this is an inner synthetic event for an event with a bubbling surrogate + // (focus or blur), assume that the surrogate already propagated from triggering the + // native event and prevent that from happening again here. + // This technically gets the ordering wrong w.r.t. to `.trigger()` (in which the + // bubbling surrogate propagates *after* the non-bubbling base), but that seems + // less bad than duplication. + } else if ( ( jQuery.event.special[ type ] || {} ).delegateType ) { + event.stopPropagation(); + } + + // If this is a native event triggered above, everything is now in order + // Fire an inner synthetic event with the original arguments + } else if ( saved.length ) { + + // ...and capture the result + dataPriv.set( this, type, { + value: jQuery.event.trigger( + + // Support: IE <=9 - 11+ + // Extend with the prototype to reset the above stopImmediatePropagation() + jQuery.extend( saved[ 0 ], jQuery.Event.prototype ), + saved.slice( 1 ), + this + ) + } ); + + // Abort handling of the native event + event.stopImmediatePropagation(); + } + } + } ); +} + +jQuery.removeEvent = function( elem, type, handle ) { + + // This "if" is needed for plain objects + if ( elem.removeEventListener ) { + elem.removeEventListener( type, handle ); + } +}; + +jQuery.Event = function( src, props ) { + + // Allow instantiation without the 'new' keyword + if ( !( this instanceof jQuery.Event ) ) { + return new jQuery.Event( src, props ); + } + + // Event object + if ( src && src.type ) { + this.originalEvent = src; + this.type = src.type; + + // Events bubbling up the document may have been marked as prevented + // by a handler lower down the tree; reflect the correct value. + this.isDefaultPrevented = src.defaultPrevented || + src.defaultPrevented === undefined && + + // Support: Android <=2.3 only + src.returnValue === false ? + returnTrue : + returnFalse; + + // Create target properties + // Support: Safari <=6 - 7 only + // Target should not be a text node (#504, #13143) + this.target = ( src.target && src.target.nodeType === 3 ) ? + src.target.parentNode : + src.target; + + this.currentTarget = src.currentTarget; + this.relatedTarget = src.relatedTarget; + + // Event type + } else { + this.type = src; + } + + // Put explicitly provided properties onto the event object + if ( props ) { + jQuery.extend( this, props ); + } + + // Create a timestamp if incoming event doesn't have one + this.timeStamp = src && src.timeStamp || Date.now(); + + // Mark it as fixed + this[ jQuery.expando ] = true; +}; + +// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding +// https://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html +jQuery.Event.prototype = { + constructor: jQuery.Event, + isDefaultPrevented: returnFalse, + isPropagationStopped: returnFalse, + isImmediatePropagationStopped: returnFalse, + isSimulated: false, + + preventDefault: function() { + var e = this.originalEvent; + + this.isDefaultPrevented = returnTrue; + + if ( e && !this.isSimulated ) { + e.preventDefault(); + } + }, + stopPropagation: function() { + var e = this.originalEvent; + + this.isPropagationStopped = returnTrue; + + if ( e && !this.isSimulated ) { + e.stopPropagation(); + } + }, + stopImmediatePropagation: function() { + var e = this.originalEvent; + + this.isImmediatePropagationStopped = returnTrue; + + if ( e && !this.isSimulated ) { + e.stopImmediatePropagation(); + } + + this.stopPropagation(); + } +}; + +// Includes all common event props including KeyEvent and MouseEvent specific props +jQuery.each( { + altKey: true, + bubbles: true, + cancelable: true, + changedTouches: true, + ctrlKey: true, + detail: true, + eventPhase: true, + metaKey: true, + pageX: true, + pageY: true, + shiftKey: true, + view: true, + "char": true, + code: true, + charCode: true, + key: true, + keyCode: true, + button: true, + buttons: true, + clientX: true, + clientY: true, + offsetX: true, + offsetY: true, + pointerId: true, + pointerType: true, + screenX: true, + screenY: true, + targetTouches: true, + toElement: true, + touches: true, + + which: function( event ) { + var button = event.button; + + // Add which for key events + if ( event.which == null && rkeyEvent.test( event.type ) ) { + return event.charCode != null ? event.charCode : event.keyCode; + } + + // Add which for click: 1 === left; 2 === middle; 3 === right + if ( !event.which && button !== undefined && rmouseEvent.test( event.type ) ) { + if ( button & 1 ) { + return 1; + } + + if ( button & 2 ) { + return 3; + } + + if ( button & 4 ) { + return 2; + } + + return 0; + } + + return event.which; + } +}, jQuery.event.addProp ); + +jQuery.each( { focus: "focusin", blur: "focusout" }, function( type, delegateType ) { + jQuery.event.special[ type ] = { + + // Utilize native event if possible so blur/focus sequence is correct + setup: function() { + + // Claim the first handler + // dataPriv.set( this, "focus", ... ) + // dataPriv.set( this, "blur", ... ) + leverageNative( this, type, expectSync ); + + // Return false to allow normal processing in the caller + return false; + }, + trigger: function() { + + // Force setup before trigger + leverageNative( this, type ); + + // Return non-false to allow normal event-path propagation + return true; + }, + + delegateType: delegateType + }; +} ); + +// Create mouseenter/leave events using mouseover/out and event-time checks +// so that event delegation works in jQuery. +// Do the same for pointerenter/pointerleave and pointerover/pointerout +// +// Support: Safari 7 only +// Safari sends mouseenter too often; see: +// https://bugs.chromium.org/p/chromium/issues/detail?id=470258 +// for the description of the bug (it existed in older Chrome versions as well). +jQuery.each( { + mouseenter: "mouseover", + mouseleave: "mouseout", + pointerenter: "pointerover", + pointerleave: "pointerout" +}, function( orig, fix ) { + jQuery.event.special[ orig ] = { + delegateType: fix, + bindType: fix, + + handle: function( event ) { + var ret, + target = this, + related = event.relatedTarget, + handleObj = event.handleObj; + + // For mouseenter/leave call the handler if related is outside the target. + // NB: No relatedTarget if the mouse left/entered the browser window + if ( !related || ( related !== target && !jQuery.contains( target, related ) ) ) { + event.type = handleObj.origType; + ret = handleObj.handler.apply( this, arguments ); + event.type = fix; + } + return ret; + } + }; +} ); + +jQuery.fn.extend( { + + on: function( types, selector, data, fn ) { + return on( this, types, selector, data, fn ); + }, + one: function( types, selector, data, fn ) { + return on( this, types, selector, data, fn, 1 ); + }, + off: function( types, selector, fn ) { + var handleObj, type; + if ( types && types.preventDefault && types.handleObj ) { + + // ( event ) dispatched jQuery.Event + handleObj = types.handleObj; + jQuery( types.delegateTarget ).off( + handleObj.namespace ? + handleObj.origType + "." + handleObj.namespace : + handleObj.origType, + handleObj.selector, + handleObj.handler + ); + return this; + } + if ( typeof types === "object" ) { + + // ( types-object [, selector] ) + for ( type in types ) { + this.off( type, selector, types[ type ] ); + } + return this; + } + if ( selector === false || typeof selector === "function" ) { + + // ( types [, fn] ) + fn = selector; + selector = undefined; + } + if ( fn === false ) { + fn = returnFalse; + } + return this.each( function() { + jQuery.event.remove( this, types, fn, selector ); + } ); + } +} ); + + +var + + // Support: IE <=10 - 11, Edge 12 - 13 only + // In IE/Edge using regex groups here causes severe slowdowns. + // See https://connect.microsoft.com/IE/feedback/details/1736512/ + rnoInnerhtml = /\s*$/g; + +// Prefer a tbody over its parent table for containing new rows +function manipulationTarget( elem, content ) { + if ( nodeName( elem, "table" ) && + nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ) { + + return jQuery( elem ).children( "tbody" )[ 0 ] || elem; + } + + return elem; +} + +// Replace/restore the type attribute of script elements for safe DOM manipulation +function disableScript( elem ) { + elem.type = ( elem.getAttribute( "type" ) !== null ) + "/" + elem.type; + return elem; +} +function restoreScript( elem ) { + if ( ( elem.type || "" ).slice( 0, 5 ) === "true/" ) { + elem.type = elem.type.slice( 5 ); + } else { + elem.removeAttribute( "type" ); + } + + return elem; +} + +function cloneCopyEvent( src, dest ) { + var i, l, type, pdataOld, udataOld, udataCur, events; + + if ( dest.nodeType !== 1 ) { + return; + } + + // 1. Copy private data: events, handlers, etc. + if ( dataPriv.hasData( src ) ) { + pdataOld = dataPriv.get( src ); + events = pdataOld.events; + + if ( events ) { + dataPriv.remove( dest, "handle events" ); + + for ( type in events ) { + for ( i = 0, l = events[ type ].length; i < l; i++ ) { + jQuery.event.add( dest, type, events[ type ][ i ] ); + } + } + } + } + + // 2. Copy user data + if ( dataUser.hasData( src ) ) { + udataOld = dataUser.access( src ); + udataCur = jQuery.extend( {}, udataOld ); + + dataUser.set( dest, udataCur ); + } +} + +// Fix IE bugs, see support tests +function fixInput( src, dest ) { + var nodeName = dest.nodeName.toLowerCase(); + + // Fails to persist the checked state of a cloned checkbox or radio button. + if ( nodeName === "input" && rcheckableType.test( src.type ) ) { + dest.checked = src.checked; + + // Fails to return the selected option to the default selected state when cloning options + } else if ( nodeName === "input" || nodeName === "textarea" ) { + dest.defaultValue = src.defaultValue; + } +} + +function domManip( collection, args, callback, ignored ) { + + // Flatten any nested arrays + args = flat( args ); + + var fragment, first, scripts, hasScripts, node, doc, + i = 0, + l = collection.length, + iNoClone = l - 1, + value = args[ 0 ], + valueIsFunction = isFunction( value ); + + // We can't cloneNode fragments that contain checked, in WebKit + if ( valueIsFunction || + ( l > 1 && typeof value === "string" && + !support.checkClone && rchecked.test( value ) ) ) { + return collection.each( function( index ) { + var self = collection.eq( index ); + if ( valueIsFunction ) { + args[ 0 ] = value.call( this, index, self.html() ); + } + domManip( self, args, callback, ignored ); + } ); + } + + if ( l ) { + fragment = buildFragment( args, collection[ 0 ].ownerDocument, false, collection, ignored ); + first = fragment.firstChild; + + if ( fragment.childNodes.length === 1 ) { + fragment = first; + } + + // Require either new content or an interest in ignored elements to invoke the callback + if ( first || ignored ) { + scripts = jQuery.map( getAll( fragment, "script" ), disableScript ); + hasScripts = scripts.length; + + // Use the original fragment for the last item + // instead of the first because it can end up + // being emptied incorrectly in certain situations (#8070). + for ( ; i < l; i++ ) { + node = fragment; + + if ( i !== iNoClone ) { + node = jQuery.clone( node, true, true ); + + // Keep references to cloned scripts for later restoration + if ( hasScripts ) { + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( scripts, getAll( node, "script" ) ); + } + } + + callback.call( collection[ i ], node, i ); + } + + if ( hasScripts ) { + doc = scripts[ scripts.length - 1 ].ownerDocument; + + // Reenable scripts + jQuery.map( scripts, restoreScript ); + + // Evaluate executable scripts on first document insertion + for ( i = 0; i < hasScripts; i++ ) { + node = scripts[ i ]; + if ( rscriptType.test( node.type || "" ) && + !dataPriv.access( node, "globalEval" ) && + jQuery.contains( doc, node ) ) { + + if ( node.src && ( node.type || "" ).toLowerCase() !== "module" ) { + + // Optional AJAX dependency, but won't run scripts if not present + if ( jQuery._evalUrl && !node.noModule ) { + jQuery._evalUrl( node.src, { + nonce: node.nonce || node.getAttribute( "nonce" ) + }, doc ); + } + } else { + DOMEval( node.textContent.replace( rcleanScript, "" ), node, doc ); + } + } + } + } + } + } + + return collection; +} + +function remove( elem, selector, keepData ) { + var node, + nodes = selector ? jQuery.filter( selector, elem ) : elem, + i = 0; + + for ( ; ( node = nodes[ i ] ) != null; i++ ) { + if ( !keepData && node.nodeType === 1 ) { + jQuery.cleanData( getAll( node ) ); + } + + if ( node.parentNode ) { + if ( keepData && isAttached( node ) ) { + setGlobalEval( getAll( node, "script" ) ); + } + node.parentNode.removeChild( node ); + } + } + + return elem; +} + +jQuery.extend( { + htmlPrefilter: function( html ) { + return html; + }, + + clone: function( elem, dataAndEvents, deepDataAndEvents ) { + var i, l, srcElements, destElements, + clone = elem.cloneNode( true ), + inPage = isAttached( elem ); + + // Fix IE cloning issues + if ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) && + !jQuery.isXMLDoc( elem ) ) { + + // We eschew Sizzle here for performance reasons: https://jsperf.com/getall-vs-sizzle/2 + destElements = getAll( clone ); + srcElements = getAll( elem ); + + for ( i = 0, l = srcElements.length; i < l; i++ ) { + fixInput( srcElements[ i ], destElements[ i ] ); + } + } + + // Copy the events from the original to the clone + if ( dataAndEvents ) { + if ( deepDataAndEvents ) { + srcElements = srcElements || getAll( elem ); + destElements = destElements || getAll( clone ); + + for ( i = 0, l = srcElements.length; i < l; i++ ) { + cloneCopyEvent( srcElements[ i ], destElements[ i ] ); + } + } else { + cloneCopyEvent( elem, clone ); + } + } + + // Preserve script evaluation history + destElements = getAll( clone, "script" ); + if ( destElements.length > 0 ) { + setGlobalEval( destElements, !inPage && getAll( elem, "script" ) ); + } + + // Return the cloned set + return clone; + }, + + cleanData: function( elems ) { + var data, elem, type, + special = jQuery.event.special, + i = 0; + + for ( ; ( elem = elems[ i ] ) !== undefined; i++ ) { + if ( acceptData( elem ) ) { + if ( ( data = elem[ dataPriv.expando ] ) ) { + if ( data.events ) { + for ( type in data.events ) { + if ( special[ type ] ) { + jQuery.event.remove( elem, type ); + + // This is a shortcut to avoid jQuery.event.remove's overhead + } else { + jQuery.removeEvent( elem, type, data.handle ); + } + } + } + + // Support: Chrome <=35 - 45+ + // Assign undefined instead of using delete, see Data#remove + elem[ dataPriv.expando ] = undefined; + } + if ( elem[ dataUser.expando ] ) { + + // Support: Chrome <=35 - 45+ + // Assign undefined instead of using delete, see Data#remove + elem[ dataUser.expando ] = undefined; + } + } + } + } +} ); + +jQuery.fn.extend( { + detach: function( selector ) { + return remove( this, selector, true ); + }, + + remove: function( selector ) { + return remove( this, selector ); + }, + + text: function( value ) { + return access( this, function( value ) { + return value === undefined ? + jQuery.text( this ) : + this.empty().each( function() { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + this.textContent = value; + } + } ); + }, null, value, arguments.length ); + }, + + append: function() { + return domManip( this, arguments, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + var target = manipulationTarget( this, elem ); + target.appendChild( elem ); + } + } ); + }, + + prepend: function() { + return domManip( this, arguments, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + var target = manipulationTarget( this, elem ); + target.insertBefore( elem, target.firstChild ); + } + } ); + }, + + before: function() { + return domManip( this, arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this ); + } + } ); + }, + + after: function() { + return domManip( this, arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this.nextSibling ); + } + } ); + }, + + empty: function() { + var elem, + i = 0; + + for ( ; ( elem = this[ i ] ) != null; i++ ) { + if ( elem.nodeType === 1 ) { + + // Prevent memory leaks + jQuery.cleanData( getAll( elem, false ) ); + + // Remove any remaining nodes + elem.textContent = ""; + } + } + + return this; + }, + + clone: function( dataAndEvents, deepDataAndEvents ) { + dataAndEvents = dataAndEvents == null ? false : dataAndEvents; + deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents; + + return this.map( function() { + return jQuery.clone( this, dataAndEvents, deepDataAndEvents ); + } ); + }, + + html: function( value ) { + return access( this, function( value ) { + var elem = this[ 0 ] || {}, + i = 0, + l = this.length; + + if ( value === undefined && elem.nodeType === 1 ) { + return elem.innerHTML; + } + + // See if we can take a shortcut and just use innerHTML + if ( typeof value === "string" && !rnoInnerhtml.test( value ) && + !wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) { + + value = jQuery.htmlPrefilter( value ); + + try { + for ( ; i < l; i++ ) { + elem = this[ i ] || {}; + + // Remove element nodes and prevent memory leaks + if ( elem.nodeType === 1 ) { + jQuery.cleanData( getAll( elem, false ) ); + elem.innerHTML = value; + } + } + + elem = 0; + + // If using innerHTML throws an exception, use the fallback method + } catch ( e ) {} + } + + if ( elem ) { + this.empty().append( value ); + } + }, null, value, arguments.length ); + }, + + replaceWith: function() { + var ignored = []; + + // Make the changes, replacing each non-ignored context element with the new content + return domManip( this, arguments, function( elem ) { + var parent = this.parentNode; + + if ( jQuery.inArray( this, ignored ) < 0 ) { + jQuery.cleanData( getAll( this ) ); + if ( parent ) { + parent.replaceChild( elem, this ); + } + } + + // Force callback invocation + }, ignored ); + } +} ); + +jQuery.each( { + appendTo: "append", + prependTo: "prepend", + insertBefore: "before", + insertAfter: "after", + replaceAll: "replaceWith" +}, function( name, original ) { + jQuery.fn[ name ] = function( selector ) { + var elems, + ret = [], + insert = jQuery( selector ), + last = insert.length - 1, + i = 0; + + for ( ; i <= last; i++ ) { + elems = i === last ? this : this.clone( true ); + jQuery( insert[ i ] )[ original ]( elems ); + + // Support: Android <=4.0 only, PhantomJS 1 only + // .get() because push.apply(_, arraylike) throws on ancient WebKit + push.apply( ret, elems.get() ); + } + + return this.pushStack( ret ); + }; +} ); +var rnumnonpx = new RegExp( "^(" + pnum + ")(?!px)[a-z%]+$", "i" ); + +var getStyles = function( elem ) { + + // Support: IE <=11 only, Firefox <=30 (#15098, #14150) + // IE throws on elements created in popups + // FF meanwhile throws on frame elements through "defaultView.getComputedStyle" + var view = elem.ownerDocument.defaultView; + + if ( !view || !view.opener ) { + view = window; + } + + return view.getComputedStyle( elem ); + }; + +var swap = function( elem, options, callback ) { + var ret, name, + old = {}; + + // Remember the old values, and insert the new ones + for ( name in options ) { + old[ name ] = elem.style[ name ]; + elem.style[ name ] = options[ name ]; + } + + ret = callback.call( elem ); + + // Revert the old values + for ( name in options ) { + elem.style[ name ] = old[ name ]; + } + + return ret; +}; + + +var rboxStyle = new RegExp( cssExpand.join( "|" ), "i" ); + + + +( function() { + + // Executing both pixelPosition & boxSizingReliable tests require only one layout + // so they're executed at the same time to save the second computation. + function computeStyleTests() { + + // This is a singleton, we need to execute it only once + if ( !div ) { + return; + } + + container.style.cssText = "position:absolute;left:-11111px;width:60px;" + + "margin-top:1px;padding:0;border:0"; + div.style.cssText = + "position:relative;display:block;box-sizing:border-box;overflow:scroll;" + + "margin:auto;border:1px;padding:1px;" + + "width:60%;top:1%"; + documentElement.appendChild( container ).appendChild( div ); + + var divStyle = window.getComputedStyle( div ); + pixelPositionVal = divStyle.top !== "1%"; + + // Support: Android 4.0 - 4.3 only, Firefox <=3 - 44 + reliableMarginLeftVal = roundPixelMeasures( divStyle.marginLeft ) === 12; + + // Support: Android 4.0 - 4.3 only, Safari <=9.1 - 10.1, iOS <=7.0 - 9.3 + // Some styles come back with percentage values, even though they shouldn't + div.style.right = "60%"; + pixelBoxStylesVal = roundPixelMeasures( divStyle.right ) === 36; + + // Support: IE 9 - 11 only + // Detect misreporting of content dimensions for box-sizing:border-box elements + boxSizingReliableVal = roundPixelMeasures( divStyle.width ) === 36; + + // Support: IE 9 only + // Detect overflow:scroll screwiness (gh-3699) + // Support: Chrome <=64 + // Don't get tricked when zoom affects offsetWidth (gh-4029) + div.style.position = "absolute"; + scrollboxSizeVal = roundPixelMeasures( div.offsetWidth / 3 ) === 12; + + documentElement.removeChild( container ); + + // Nullify the div so it wouldn't be stored in the memory and + // it will also be a sign that checks already performed + div = null; + } + + function roundPixelMeasures( measure ) { + return Math.round( parseFloat( measure ) ); + } + + var pixelPositionVal, boxSizingReliableVal, scrollboxSizeVal, pixelBoxStylesVal, + reliableTrDimensionsVal, reliableMarginLeftVal, + container = document.createElement( "div" ), + div = document.createElement( "div" ); + + // Finish early in limited (non-browser) environments + if ( !div.style ) { + return; + } + + // Support: IE <=9 - 11 only + // Style of cloned element affects source element cloned (#8908) + div.style.backgroundClip = "content-box"; + div.cloneNode( true ).style.backgroundClip = ""; + support.clearCloneStyle = div.style.backgroundClip === "content-box"; + + jQuery.extend( support, { + boxSizingReliable: function() { + computeStyleTests(); + return boxSizingReliableVal; + }, + pixelBoxStyles: function() { + computeStyleTests(); + return pixelBoxStylesVal; + }, + pixelPosition: function() { + computeStyleTests(); + return pixelPositionVal; + }, + reliableMarginLeft: function() { + computeStyleTests(); + return reliableMarginLeftVal; + }, + scrollboxSize: function() { + computeStyleTests(); + return scrollboxSizeVal; + }, + + // Support: IE 9 - 11+, Edge 15 - 18+ + // IE/Edge misreport `getComputedStyle` of table rows with width/height + // set in CSS while `offset*` properties report correct values. + // Behavior in IE 9 is more subtle than in newer versions & it passes + // some versions of this test; make sure not to make it pass there! + reliableTrDimensions: function() { + var table, tr, trChild, trStyle; + if ( reliableTrDimensionsVal == null ) { + table = document.createElement( "table" ); + tr = document.createElement( "tr" ); + trChild = document.createElement( "div" ); + + table.style.cssText = "position:absolute;left:-11111px"; + tr.style.height = "1px"; + trChild.style.height = "9px"; + + documentElement + .appendChild( table ) + .appendChild( tr ) + .appendChild( trChild ); + + trStyle = window.getComputedStyle( tr ); + reliableTrDimensionsVal = parseInt( trStyle.height ) > 3; + + documentElement.removeChild( table ); + } + return reliableTrDimensionsVal; + } + } ); +} )(); + + +function curCSS( elem, name, computed ) { + var width, minWidth, maxWidth, ret, + + // Support: Firefox 51+ + // Retrieving style before computed somehow + // fixes an issue with getting wrong values + // on detached elements + style = elem.style; + + computed = computed || getStyles( elem ); + + // getPropertyValue is needed for: + // .css('filter') (IE 9 only, #12537) + // .css('--customProperty) (#3144) + if ( computed ) { + ret = computed.getPropertyValue( name ) || computed[ name ]; + + if ( ret === "" && !isAttached( elem ) ) { + ret = jQuery.style( elem, name ); + } + + // A tribute to the "awesome hack by Dean Edwards" + // Android Browser returns percentage for some values, + // but width seems to be reliably pixels. + // This is against the CSSOM draft spec: + // https://drafts.csswg.org/cssom/#resolved-values + if ( !support.pixelBoxStyles() && rnumnonpx.test( ret ) && rboxStyle.test( name ) ) { + + // Remember the original values + width = style.width; + minWidth = style.minWidth; + maxWidth = style.maxWidth; + + // Put in the new values to get a computed value out + style.minWidth = style.maxWidth = style.width = ret; + ret = computed.width; + + // Revert the changed values + style.width = width; + style.minWidth = minWidth; + style.maxWidth = maxWidth; + } + } + + return ret !== undefined ? + + // Support: IE <=9 - 11 only + // IE returns zIndex value as an integer. + ret + "" : + ret; +} + + +function addGetHookIf( conditionFn, hookFn ) { + + // Define the hook, we'll check on the first run if it's really needed. + return { + get: function() { + if ( conditionFn() ) { + + // Hook not needed (or it's not possible to use it due + // to missing dependency), remove it. + delete this.get; + return; + } + + // Hook needed; redefine it so that the support test is not executed again. + return ( this.get = hookFn ).apply( this, arguments ); + } + }; +} + + +var cssPrefixes = [ "Webkit", "Moz", "ms" ], + emptyStyle = document.createElement( "div" ).style, + vendorProps = {}; + +// Return a vendor-prefixed property or undefined +function vendorPropName( name ) { + + // Check for vendor prefixed names + var capName = name[ 0 ].toUpperCase() + name.slice( 1 ), + i = cssPrefixes.length; + + while ( i-- ) { + name = cssPrefixes[ i ] + capName; + if ( name in emptyStyle ) { + return name; + } + } +} + +// Return a potentially-mapped jQuery.cssProps or vendor prefixed property +function finalPropName( name ) { + var final = jQuery.cssProps[ name ] || vendorProps[ name ]; + + if ( final ) { + return final; + } + if ( name in emptyStyle ) { + return name; + } + return vendorProps[ name ] = vendorPropName( name ) || name; +} + + +var + + // Swappable if display is none or starts with table + // except "table", "table-cell", or "table-caption" + // See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display + rdisplayswap = /^(none|table(?!-c[ea]).+)/, + rcustomProp = /^--/, + cssShow = { position: "absolute", visibility: "hidden", display: "block" }, + cssNormalTransform = { + letterSpacing: "0", + fontWeight: "400" + }; + +function setPositiveNumber( _elem, value, subtract ) { + + // Any relative (+/-) values have already been + // normalized at this point + var matches = rcssNum.exec( value ); + return matches ? + + // Guard against undefined "subtract", e.g., when used as in cssHooks + Math.max( 0, matches[ 2 ] - ( subtract || 0 ) ) + ( matches[ 3 ] || "px" ) : + value; +} + +function boxModelAdjustment( elem, dimension, box, isBorderBox, styles, computedVal ) { + var i = dimension === "width" ? 1 : 0, + extra = 0, + delta = 0; + + // Adjustment may not be necessary + if ( box === ( isBorderBox ? "border" : "content" ) ) { + return 0; + } + + for ( ; i < 4; i += 2 ) { + + // Both box models exclude margin + if ( box === "margin" ) { + delta += jQuery.css( elem, box + cssExpand[ i ], true, styles ); + } + + // If we get here with a content-box, we're seeking "padding" or "border" or "margin" + if ( !isBorderBox ) { + + // Add padding + delta += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); + + // For "border" or "margin", add border + if ( box !== "padding" ) { + delta += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + + // But still keep track of it otherwise + } else { + extra += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + } + + // If we get here with a border-box (content + padding + border), we're seeking "content" or + // "padding" or "margin" + } else { + + // For "content", subtract padding + if ( box === "content" ) { + delta -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); + } + + // For "content" or "padding", subtract border + if ( box !== "margin" ) { + delta -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + } + } + } + + // Account for positive content-box scroll gutter when requested by providing computedVal + if ( !isBorderBox && computedVal >= 0 ) { + + // offsetWidth/offsetHeight is a rounded sum of content, padding, scroll gutter, and border + // Assuming integer scroll gutter, subtract the rest and round down + delta += Math.max( 0, Math.ceil( + elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] - + computedVal - + delta - + extra - + 0.5 + + // If offsetWidth/offsetHeight is unknown, then we can't determine content-box scroll gutter + // Use an explicit zero to avoid NaN (gh-3964) + ) ) || 0; + } + + return delta; +} + +function getWidthOrHeight( elem, dimension, extra ) { + + // Start with computed style + var styles = getStyles( elem ), + + // To avoid forcing a reflow, only fetch boxSizing if we need it (gh-4322). + // Fake content-box until we know it's needed to know the true value. + boxSizingNeeded = !support.boxSizingReliable() || extra, + isBorderBox = boxSizingNeeded && + jQuery.css( elem, "boxSizing", false, styles ) === "border-box", + valueIsBorderBox = isBorderBox, + + val = curCSS( elem, dimension, styles ), + offsetProp = "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ); + + // Support: Firefox <=54 + // Return a confounding non-pixel value or feign ignorance, as appropriate. + if ( rnumnonpx.test( val ) ) { + if ( !extra ) { + return val; + } + val = "auto"; + } + + + // Support: IE 9 - 11 only + // Use offsetWidth/offsetHeight for when box sizing is unreliable. + // In those cases, the computed value can be trusted to be border-box. + if ( ( !support.boxSizingReliable() && isBorderBox || + + // Support: IE 10 - 11+, Edge 15 - 18+ + // IE/Edge misreport `getComputedStyle` of table rows with width/height + // set in CSS while `offset*` properties report correct values. + // Interestingly, in some cases IE 9 doesn't suffer from this issue. + !support.reliableTrDimensions() && nodeName( elem, "tr" ) || + + // Fall back to offsetWidth/offsetHeight when value is "auto" + // This happens for inline elements with no explicit setting (gh-3571) + val === "auto" || + + // Support: Android <=4.1 - 4.3 only + // Also use offsetWidth/offsetHeight for misreported inline dimensions (gh-3602) + !parseFloat( val ) && jQuery.css( elem, "display", false, styles ) === "inline" ) && + + // Make sure the element is visible & connected + elem.getClientRects().length ) { + + isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box"; + + // Where available, offsetWidth/offsetHeight approximate border box dimensions. + // Where not available (e.g., SVG), assume unreliable box-sizing and interpret the + // retrieved value as a content box dimension. + valueIsBorderBox = offsetProp in elem; + if ( valueIsBorderBox ) { + val = elem[ offsetProp ]; + } + } + + // Normalize "" and auto + val = parseFloat( val ) || 0; + + // Adjust for the element's box model + return ( val + + boxModelAdjustment( + elem, + dimension, + extra || ( isBorderBox ? "border" : "content" ), + valueIsBorderBox, + styles, + + // Provide the current computed size to request scroll gutter calculation (gh-3589) + val + ) + ) + "px"; +} + +jQuery.extend( { + + // Add in style property hooks for overriding the default + // behavior of getting and setting a style property + cssHooks: { + opacity: { + get: function( elem, computed ) { + if ( computed ) { + + // We should always get a number back from opacity + var ret = curCSS( elem, "opacity" ); + return ret === "" ? "1" : ret; + } + } + } + }, + + // Don't automatically add "px" to these possibly-unitless properties + cssNumber: { + "animationIterationCount": true, + "columnCount": true, + "fillOpacity": true, + "flexGrow": true, + "flexShrink": true, + "fontWeight": true, + "gridArea": true, + "gridColumn": true, + "gridColumnEnd": true, + "gridColumnStart": true, + "gridRow": true, + "gridRowEnd": true, + "gridRowStart": true, + "lineHeight": true, + "opacity": true, + "order": true, + "orphans": true, + "widows": true, + "zIndex": true, + "zoom": true + }, + + // Add in properties whose names you wish to fix before + // setting or getting the value + cssProps: {}, + + // Get and set the style property on a DOM Node + style: function( elem, name, value, extra ) { + + // Don't set styles on text and comment nodes + if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) { + return; + } + + // Make sure that we're working with the right name + var ret, type, hooks, + origName = camelCase( name ), + isCustomProp = rcustomProp.test( name ), + style = elem.style; + + // Make sure that we're working with the right name. We don't + // want to query the value if it is a CSS custom property + // since they are user-defined. + if ( !isCustomProp ) { + name = finalPropName( origName ); + } + + // Gets hook for the prefixed version, then unprefixed version + hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; + + // Check if we're setting a value + if ( value !== undefined ) { + type = typeof value; + + // Convert "+=" or "-=" to relative numbers (#7345) + if ( type === "string" && ( ret = rcssNum.exec( value ) ) && ret[ 1 ] ) { + value = adjustCSS( elem, name, ret ); + + // Fixes bug #9237 + type = "number"; + } + + // Make sure that null and NaN values aren't set (#7116) + if ( value == null || value !== value ) { + return; + } + + // If a number was passed in, add the unit (except for certain CSS properties) + // The isCustomProp check can be removed in jQuery 4.0 when we only auto-append + // "px" to a few hardcoded values. + if ( type === "number" && !isCustomProp ) { + value += ret && ret[ 3 ] || ( jQuery.cssNumber[ origName ] ? "" : "px" ); + } + + // background-* props affect original clone's values + if ( !support.clearCloneStyle && value === "" && name.indexOf( "background" ) === 0 ) { + style[ name ] = "inherit"; + } + + // If a hook was provided, use that value, otherwise just set the specified value + if ( !hooks || !( "set" in hooks ) || + ( value = hooks.set( elem, value, extra ) ) !== undefined ) { + + if ( isCustomProp ) { + style.setProperty( name, value ); + } else { + style[ name ] = value; + } + } + + } else { + + // If a hook was provided get the non-computed value from there + if ( hooks && "get" in hooks && + ( ret = hooks.get( elem, false, extra ) ) !== undefined ) { + + return ret; + } + + // Otherwise just get the value from the style object + return style[ name ]; + } + }, + + css: function( elem, name, extra, styles ) { + var val, num, hooks, + origName = camelCase( name ), + isCustomProp = rcustomProp.test( name ); + + // Make sure that we're working with the right name. We don't + // want to modify the value if it is a CSS custom property + // since they are user-defined. + if ( !isCustomProp ) { + name = finalPropName( origName ); + } + + // Try prefixed name followed by the unprefixed name + hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; + + // If a hook was provided get the computed value from there + if ( hooks && "get" in hooks ) { + val = hooks.get( elem, true, extra ); + } + + // Otherwise, if a way to get the computed value exists, use that + if ( val === undefined ) { + val = curCSS( elem, name, styles ); + } + + // Convert "normal" to computed value + if ( val === "normal" && name in cssNormalTransform ) { + val = cssNormalTransform[ name ]; + } + + // Make numeric if forced or a qualifier was provided and val looks numeric + if ( extra === "" || extra ) { + num = parseFloat( val ); + return extra === true || isFinite( num ) ? num || 0 : val; + } + + return val; + } +} ); + +jQuery.each( [ "height", "width" ], function( _i, dimension ) { + jQuery.cssHooks[ dimension ] = { + get: function( elem, computed, extra ) { + if ( computed ) { + + // Certain elements can have dimension info if we invisibly show them + // but it must have a current display style that would benefit + return rdisplayswap.test( jQuery.css( elem, "display" ) ) && + + // Support: Safari 8+ + // Table columns in Safari have non-zero offsetWidth & zero + // getBoundingClientRect().width unless display is changed. + // Support: IE <=11 only + // Running getBoundingClientRect on a disconnected node + // in IE throws an error. + ( !elem.getClientRects().length || !elem.getBoundingClientRect().width ) ? + swap( elem, cssShow, function() { + return getWidthOrHeight( elem, dimension, extra ); + } ) : + getWidthOrHeight( elem, dimension, extra ); + } + }, + + set: function( elem, value, extra ) { + var matches, + styles = getStyles( elem ), + + // Only read styles.position if the test has a chance to fail + // to avoid forcing a reflow. + scrollboxSizeBuggy = !support.scrollboxSize() && + styles.position === "absolute", + + // To avoid forcing a reflow, only fetch boxSizing if we need it (gh-3991) + boxSizingNeeded = scrollboxSizeBuggy || extra, + isBorderBox = boxSizingNeeded && + jQuery.css( elem, "boxSizing", false, styles ) === "border-box", + subtract = extra ? + boxModelAdjustment( + elem, + dimension, + extra, + isBorderBox, + styles + ) : + 0; + + // Account for unreliable border-box dimensions by comparing offset* to computed and + // faking a content-box to get border and padding (gh-3699) + if ( isBorderBox && scrollboxSizeBuggy ) { + subtract -= Math.ceil( + elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] - + parseFloat( styles[ dimension ] ) - + boxModelAdjustment( elem, dimension, "border", false, styles ) - + 0.5 + ); + } + + // Convert to pixels if value adjustment is needed + if ( subtract && ( matches = rcssNum.exec( value ) ) && + ( matches[ 3 ] || "px" ) !== "px" ) { + + elem.style[ dimension ] = value; + value = jQuery.css( elem, dimension ); + } + + return setPositiveNumber( elem, value, subtract ); + } + }; +} ); + +jQuery.cssHooks.marginLeft = addGetHookIf( support.reliableMarginLeft, + function( elem, computed ) { + if ( computed ) { + return ( parseFloat( curCSS( elem, "marginLeft" ) ) || + elem.getBoundingClientRect().left - + swap( elem, { marginLeft: 0 }, function() { + return elem.getBoundingClientRect().left; + } ) + ) + "px"; + } + } +); + +// These hooks are used by animate to expand properties +jQuery.each( { + margin: "", + padding: "", + border: "Width" +}, function( prefix, suffix ) { + jQuery.cssHooks[ prefix + suffix ] = { + expand: function( value ) { + var i = 0, + expanded = {}, + + // Assumes a single number if not a string + parts = typeof value === "string" ? value.split( " " ) : [ value ]; + + for ( ; i < 4; i++ ) { + expanded[ prefix + cssExpand[ i ] + suffix ] = + parts[ i ] || parts[ i - 2 ] || parts[ 0 ]; + } + + return expanded; + } + }; + + if ( prefix !== "margin" ) { + jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber; + } +} ); + +jQuery.fn.extend( { + css: function( name, value ) { + return access( this, function( elem, name, value ) { + var styles, len, + map = {}, + i = 0; + + if ( Array.isArray( name ) ) { + styles = getStyles( elem ); + len = name.length; + + for ( ; i < len; i++ ) { + map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles ); + } + + return map; + } + + return value !== undefined ? + jQuery.style( elem, name, value ) : + jQuery.css( elem, name ); + }, name, value, arguments.length > 1 ); + } +} ); + + +function Tween( elem, options, prop, end, easing ) { + return new Tween.prototype.init( elem, options, prop, end, easing ); +} +jQuery.Tween = Tween; + +Tween.prototype = { + constructor: Tween, + init: function( elem, options, prop, end, easing, unit ) { + this.elem = elem; + this.prop = prop; + this.easing = easing || jQuery.easing._default; + this.options = options; + this.start = this.now = this.cur(); + this.end = end; + this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" ); + }, + cur: function() { + var hooks = Tween.propHooks[ this.prop ]; + + return hooks && hooks.get ? + hooks.get( this ) : + Tween.propHooks._default.get( this ); + }, + run: function( percent ) { + var eased, + hooks = Tween.propHooks[ this.prop ]; + + if ( this.options.duration ) { + this.pos = eased = jQuery.easing[ this.easing ]( + percent, this.options.duration * percent, 0, 1, this.options.duration + ); + } else { + this.pos = eased = percent; + } + this.now = ( this.end - this.start ) * eased + this.start; + + if ( this.options.step ) { + this.options.step.call( this.elem, this.now, this ); + } + + if ( hooks && hooks.set ) { + hooks.set( this ); + } else { + Tween.propHooks._default.set( this ); + } + return this; + } +}; + +Tween.prototype.init.prototype = Tween.prototype; + +Tween.propHooks = { + _default: { + get: function( tween ) { + var result; + + // Use a property on the element directly when it is not a DOM element, + // or when there is no matching style property that exists. + if ( tween.elem.nodeType !== 1 || + tween.elem[ tween.prop ] != null && tween.elem.style[ tween.prop ] == null ) { + return tween.elem[ tween.prop ]; + } + + // Passing an empty string as a 3rd parameter to .css will automatically + // attempt a parseFloat and fallback to a string if the parse fails. + // Simple values such as "10px" are parsed to Float; + // complex values such as "rotate(1rad)" are returned as-is. + result = jQuery.css( tween.elem, tween.prop, "" ); + + // Empty strings, null, undefined and "auto" are converted to 0. + return !result || result === "auto" ? 0 : result; + }, + set: function( tween ) { + + // Use step hook for back compat. + // Use cssHook if its there. + // Use .style if available and use plain properties where available. + if ( jQuery.fx.step[ tween.prop ] ) { + jQuery.fx.step[ tween.prop ]( tween ); + } else if ( tween.elem.nodeType === 1 && ( + jQuery.cssHooks[ tween.prop ] || + tween.elem.style[ finalPropName( tween.prop ) ] != null ) ) { + jQuery.style( tween.elem, tween.prop, tween.now + tween.unit ); + } else { + tween.elem[ tween.prop ] = tween.now; + } + } + } +}; + +// Support: IE <=9 only +// Panic based approach to setting things on disconnected nodes +Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = { + set: function( tween ) { + if ( tween.elem.nodeType && tween.elem.parentNode ) { + tween.elem[ tween.prop ] = tween.now; + } + } +}; + +jQuery.easing = { + linear: function( p ) { + return p; + }, + swing: function( p ) { + return 0.5 - Math.cos( p * Math.PI ) / 2; + }, + _default: "swing" +}; + +jQuery.fx = Tween.prototype.init; + +// Back compat <1.8 extension point +jQuery.fx.step = {}; + + + + +var + fxNow, inProgress, + rfxtypes = /^(?:toggle|show|hide)$/, + rrun = /queueHooks$/; + +function schedule() { + if ( inProgress ) { + if ( document.hidden === false && window.requestAnimationFrame ) { + window.requestAnimationFrame( schedule ); + } else { + window.setTimeout( schedule, jQuery.fx.interval ); + } + + jQuery.fx.tick(); + } +} + +// Animations created synchronously will run synchronously +function createFxNow() { + window.setTimeout( function() { + fxNow = undefined; + } ); + return ( fxNow = Date.now() ); +} + +// Generate parameters to create a standard animation +function genFx( type, includeWidth ) { + var which, + i = 0, + attrs = { height: type }; + + // If we include width, step value is 1 to do all cssExpand values, + // otherwise step value is 2 to skip over Left and Right + includeWidth = includeWidth ? 1 : 0; + for ( ; i < 4; i += 2 - includeWidth ) { + which = cssExpand[ i ]; + attrs[ "margin" + which ] = attrs[ "padding" + which ] = type; + } + + if ( includeWidth ) { + attrs.opacity = attrs.width = type; + } + + return attrs; +} + +function createTween( value, prop, animation ) { + var tween, + collection = ( Animation.tweeners[ prop ] || [] ).concat( Animation.tweeners[ "*" ] ), + index = 0, + length = collection.length; + for ( ; index < length; index++ ) { + if ( ( tween = collection[ index ].call( animation, prop, value ) ) ) { + + // We're done with this property + return tween; + } + } +} + +function defaultPrefilter( elem, props, opts ) { + var prop, value, toggle, hooks, oldfire, propTween, restoreDisplay, display, + isBox = "width" in props || "height" in props, + anim = this, + orig = {}, + style = elem.style, + hidden = elem.nodeType && isHiddenWithinTree( elem ), + dataShow = dataPriv.get( elem, "fxshow" ); + + // Queue-skipping animations hijack the fx hooks + if ( !opts.queue ) { + hooks = jQuery._queueHooks( elem, "fx" ); + if ( hooks.unqueued == null ) { + hooks.unqueued = 0; + oldfire = hooks.empty.fire; + hooks.empty.fire = function() { + if ( !hooks.unqueued ) { + oldfire(); + } + }; + } + hooks.unqueued++; + + anim.always( function() { + + // Ensure the complete handler is called before this completes + anim.always( function() { + hooks.unqueued--; + if ( !jQuery.queue( elem, "fx" ).length ) { + hooks.empty.fire(); + } + } ); + } ); + } + + // Detect show/hide animations + for ( prop in props ) { + value = props[ prop ]; + if ( rfxtypes.test( value ) ) { + delete props[ prop ]; + toggle = toggle || value === "toggle"; + if ( value === ( hidden ? "hide" : "show" ) ) { + + // Pretend to be hidden if this is a "show" and + // there is still data from a stopped show/hide + if ( value === "show" && dataShow && dataShow[ prop ] !== undefined ) { + hidden = true; + + // Ignore all other no-op show/hide data + } else { + continue; + } + } + orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop ); + } + } + + // Bail out if this is a no-op like .hide().hide() + propTween = !jQuery.isEmptyObject( props ); + if ( !propTween && jQuery.isEmptyObject( orig ) ) { + return; + } + + // Restrict "overflow" and "display" styles during box animations + if ( isBox && elem.nodeType === 1 ) { + + // Support: IE <=9 - 11, Edge 12 - 15 + // Record all 3 overflow attributes because IE does not infer the shorthand + // from identically-valued overflowX and overflowY and Edge just mirrors + // the overflowX value there. + opts.overflow = [ style.overflow, style.overflowX, style.overflowY ]; + + // Identify a display type, preferring old show/hide data over the CSS cascade + restoreDisplay = dataShow && dataShow.display; + if ( restoreDisplay == null ) { + restoreDisplay = dataPriv.get( elem, "display" ); + } + display = jQuery.css( elem, "display" ); + if ( display === "none" ) { + if ( restoreDisplay ) { + display = restoreDisplay; + } else { + + // Get nonempty value(s) by temporarily forcing visibility + showHide( [ elem ], true ); + restoreDisplay = elem.style.display || restoreDisplay; + display = jQuery.css( elem, "display" ); + showHide( [ elem ] ); + } + } + + // Animate inline elements as inline-block + if ( display === "inline" || display === "inline-block" && restoreDisplay != null ) { + if ( jQuery.css( elem, "float" ) === "none" ) { + + // Restore the original display value at the end of pure show/hide animations + if ( !propTween ) { + anim.done( function() { + style.display = restoreDisplay; + } ); + if ( restoreDisplay == null ) { + display = style.display; + restoreDisplay = display === "none" ? "" : display; + } + } + style.display = "inline-block"; + } + } + } + + if ( opts.overflow ) { + style.overflow = "hidden"; + anim.always( function() { + style.overflow = opts.overflow[ 0 ]; + style.overflowX = opts.overflow[ 1 ]; + style.overflowY = opts.overflow[ 2 ]; + } ); + } + + // Implement show/hide animations + propTween = false; + for ( prop in orig ) { + + // General show/hide setup for this element animation + if ( !propTween ) { + if ( dataShow ) { + if ( "hidden" in dataShow ) { + hidden = dataShow.hidden; + } + } else { + dataShow = dataPriv.access( elem, "fxshow", { display: restoreDisplay } ); + } + + // Store hidden/visible for toggle so `.stop().toggle()` "reverses" + if ( toggle ) { + dataShow.hidden = !hidden; + } + + // Show elements before animating them + if ( hidden ) { + showHide( [ elem ], true ); + } + + /* eslint-disable no-loop-func */ + + anim.done( function() { + + /* eslint-enable no-loop-func */ + + // The final step of a "hide" animation is actually hiding the element + if ( !hidden ) { + showHide( [ elem ] ); + } + dataPriv.remove( elem, "fxshow" ); + for ( prop in orig ) { + jQuery.style( elem, prop, orig[ prop ] ); + } + } ); + } + + // Per-property setup + propTween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim ); + if ( !( prop in dataShow ) ) { + dataShow[ prop ] = propTween.start; + if ( hidden ) { + propTween.end = propTween.start; + propTween.start = 0; + } + } + } +} + +function propFilter( props, specialEasing ) { + var index, name, easing, value, hooks; + + // camelCase, specialEasing and expand cssHook pass + for ( index in props ) { + name = camelCase( index ); + easing = specialEasing[ name ]; + value = props[ index ]; + if ( Array.isArray( value ) ) { + easing = value[ 1 ]; + value = props[ index ] = value[ 0 ]; + } + + if ( index !== name ) { + props[ name ] = value; + delete props[ index ]; + } + + hooks = jQuery.cssHooks[ name ]; + if ( hooks && "expand" in hooks ) { + value = hooks.expand( value ); + delete props[ name ]; + + // Not quite $.extend, this won't overwrite existing keys. + // Reusing 'index' because we have the correct "name" + for ( index in value ) { + if ( !( index in props ) ) { + props[ index ] = value[ index ]; + specialEasing[ index ] = easing; + } + } + } else { + specialEasing[ name ] = easing; + } + } +} + +function Animation( elem, properties, options ) { + var result, + stopped, + index = 0, + length = Animation.prefilters.length, + deferred = jQuery.Deferred().always( function() { + + // Don't match elem in the :animated selector + delete tick.elem; + } ), + tick = function() { + if ( stopped ) { + return false; + } + var currentTime = fxNow || createFxNow(), + remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ), + + // Support: Android 2.3 only + // Archaic crash bug won't allow us to use `1 - ( 0.5 || 0 )` (#12497) + temp = remaining / animation.duration || 0, + percent = 1 - temp, + index = 0, + length = animation.tweens.length; + + for ( ; index < length; index++ ) { + animation.tweens[ index ].run( percent ); + } + + deferred.notifyWith( elem, [ animation, percent, remaining ] ); + + // If there's more to do, yield + if ( percent < 1 && length ) { + return remaining; + } + + // If this was an empty animation, synthesize a final progress notification + if ( !length ) { + deferred.notifyWith( elem, [ animation, 1, 0 ] ); + } + + // Resolve the animation and report its conclusion + deferred.resolveWith( elem, [ animation ] ); + return false; + }, + animation = deferred.promise( { + elem: elem, + props: jQuery.extend( {}, properties ), + opts: jQuery.extend( true, { + specialEasing: {}, + easing: jQuery.easing._default + }, options ), + originalProperties: properties, + originalOptions: options, + startTime: fxNow || createFxNow(), + duration: options.duration, + tweens: [], + createTween: function( prop, end ) { + var tween = jQuery.Tween( elem, animation.opts, prop, end, + animation.opts.specialEasing[ prop ] || animation.opts.easing ); + animation.tweens.push( tween ); + return tween; + }, + stop: function( gotoEnd ) { + var index = 0, + + // If we are going to the end, we want to run all the tweens + // otherwise we skip this part + length = gotoEnd ? animation.tweens.length : 0; + if ( stopped ) { + return this; + } + stopped = true; + for ( ; index < length; index++ ) { + animation.tweens[ index ].run( 1 ); + } + + // Resolve when we played the last frame; otherwise, reject + if ( gotoEnd ) { + deferred.notifyWith( elem, [ animation, 1, 0 ] ); + deferred.resolveWith( elem, [ animation, gotoEnd ] ); + } else { + deferred.rejectWith( elem, [ animation, gotoEnd ] ); + } + return this; + } + } ), + props = animation.props; + + propFilter( props, animation.opts.specialEasing ); + + for ( ; index < length; index++ ) { + result = Animation.prefilters[ index ].call( animation, elem, props, animation.opts ); + if ( result ) { + if ( isFunction( result.stop ) ) { + jQuery._queueHooks( animation.elem, animation.opts.queue ).stop = + result.stop.bind( result ); + } + return result; + } + } + + jQuery.map( props, createTween, animation ); + + if ( isFunction( animation.opts.start ) ) { + animation.opts.start.call( elem, animation ); + } + + // Attach callbacks from options + animation + .progress( animation.opts.progress ) + .done( animation.opts.done, animation.opts.complete ) + .fail( animation.opts.fail ) + .always( animation.opts.always ); + + jQuery.fx.timer( + jQuery.extend( tick, { + elem: elem, + anim: animation, + queue: animation.opts.queue + } ) + ); + + return animation; +} + +jQuery.Animation = jQuery.extend( Animation, { + + tweeners: { + "*": [ function( prop, value ) { + var tween = this.createTween( prop, value ); + adjustCSS( tween.elem, prop, rcssNum.exec( value ), tween ); + return tween; + } ] + }, + + tweener: function( props, callback ) { + if ( isFunction( props ) ) { + callback = props; + props = [ "*" ]; + } else { + props = props.match( rnothtmlwhite ); + } + + var prop, + index = 0, + length = props.length; + + for ( ; index < length; index++ ) { + prop = props[ index ]; + Animation.tweeners[ prop ] = Animation.tweeners[ prop ] || []; + Animation.tweeners[ prop ].unshift( callback ); + } + }, + + prefilters: [ defaultPrefilter ], + + prefilter: function( callback, prepend ) { + if ( prepend ) { + Animation.prefilters.unshift( callback ); + } else { + Animation.prefilters.push( callback ); + } + } +} ); + +jQuery.speed = function( speed, easing, fn ) { + var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : { + complete: fn || !fn && easing || + isFunction( speed ) && speed, + duration: speed, + easing: fn && easing || easing && !isFunction( easing ) && easing + }; + + // Go to the end state if fx are off + if ( jQuery.fx.off ) { + opt.duration = 0; + + } else { + if ( typeof opt.duration !== "number" ) { + if ( opt.duration in jQuery.fx.speeds ) { + opt.duration = jQuery.fx.speeds[ opt.duration ]; + + } else { + opt.duration = jQuery.fx.speeds._default; + } + } + } + + // Normalize opt.queue - true/undefined/null -> "fx" + if ( opt.queue == null || opt.queue === true ) { + opt.queue = "fx"; + } + + // Queueing + opt.old = opt.complete; + + opt.complete = function() { + if ( isFunction( opt.old ) ) { + opt.old.call( this ); + } + + if ( opt.queue ) { + jQuery.dequeue( this, opt.queue ); + } + }; + + return opt; +}; + +jQuery.fn.extend( { + fadeTo: function( speed, to, easing, callback ) { + + // Show any hidden elements after setting opacity to 0 + return this.filter( isHiddenWithinTree ).css( "opacity", 0 ).show() + + // Animate to the value specified + .end().animate( { opacity: to }, speed, easing, callback ); + }, + animate: function( prop, speed, easing, callback ) { + var empty = jQuery.isEmptyObject( prop ), + optall = jQuery.speed( speed, easing, callback ), + doAnimation = function() { + + // Operate on a copy of prop so per-property easing won't be lost + var anim = Animation( this, jQuery.extend( {}, prop ), optall ); + + // Empty animations, or finishing resolves immediately + if ( empty || dataPriv.get( this, "finish" ) ) { + anim.stop( true ); + } + }; + doAnimation.finish = doAnimation; + + return empty || optall.queue === false ? + this.each( doAnimation ) : + this.queue( optall.queue, doAnimation ); + }, + stop: function( type, clearQueue, gotoEnd ) { + var stopQueue = function( hooks ) { + var stop = hooks.stop; + delete hooks.stop; + stop( gotoEnd ); + }; + + if ( typeof type !== "string" ) { + gotoEnd = clearQueue; + clearQueue = type; + type = undefined; + } + if ( clearQueue ) { + this.queue( type || "fx", [] ); + } + + return this.each( function() { + var dequeue = true, + index = type != null && type + "queueHooks", + timers = jQuery.timers, + data = dataPriv.get( this ); + + if ( index ) { + if ( data[ index ] && data[ index ].stop ) { + stopQueue( data[ index ] ); + } + } else { + for ( index in data ) { + if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) { + stopQueue( data[ index ] ); + } + } + } + + for ( index = timers.length; index--; ) { + if ( timers[ index ].elem === this && + ( type == null || timers[ index ].queue === type ) ) { + + timers[ index ].anim.stop( gotoEnd ); + dequeue = false; + timers.splice( index, 1 ); + } + } + + // Start the next in the queue if the last step wasn't forced. + // Timers currently will call their complete callbacks, which + // will dequeue but only if they were gotoEnd. + if ( dequeue || !gotoEnd ) { + jQuery.dequeue( this, type ); + } + } ); + }, + finish: function( type ) { + if ( type !== false ) { + type = type || "fx"; + } + return this.each( function() { + var index, + data = dataPriv.get( this ), + queue = data[ type + "queue" ], + hooks = data[ type + "queueHooks" ], + timers = jQuery.timers, + length = queue ? queue.length : 0; + + // Enable finishing flag on private data + data.finish = true; + + // Empty the queue first + jQuery.queue( this, type, [] ); + + if ( hooks && hooks.stop ) { + hooks.stop.call( this, true ); + } + + // Look for any active animations, and finish them + for ( index = timers.length; index--; ) { + if ( timers[ index ].elem === this && timers[ index ].queue === type ) { + timers[ index ].anim.stop( true ); + timers.splice( index, 1 ); + } + } + + // Look for any animations in the old queue and finish them + for ( index = 0; index < length; index++ ) { + if ( queue[ index ] && queue[ index ].finish ) { + queue[ index ].finish.call( this ); + } + } + + // Turn off finishing flag + delete data.finish; + } ); + } +} ); + +jQuery.each( [ "toggle", "show", "hide" ], function( _i, name ) { + var cssFn = jQuery.fn[ name ]; + jQuery.fn[ name ] = function( speed, easing, callback ) { + return speed == null || typeof speed === "boolean" ? + cssFn.apply( this, arguments ) : + this.animate( genFx( name, true ), speed, easing, callback ); + }; +} ); + +// Generate shortcuts for custom animations +jQuery.each( { + slideDown: genFx( "show" ), + slideUp: genFx( "hide" ), + slideToggle: genFx( "toggle" ), + fadeIn: { opacity: "show" }, + fadeOut: { opacity: "hide" }, + fadeToggle: { opacity: "toggle" } +}, function( name, props ) { + jQuery.fn[ name ] = function( speed, easing, callback ) { + return this.animate( props, speed, easing, callback ); + }; +} ); + +jQuery.timers = []; +jQuery.fx.tick = function() { + var timer, + i = 0, + timers = jQuery.timers; + + fxNow = Date.now(); + + for ( ; i < timers.length; i++ ) { + timer = timers[ i ]; + + // Run the timer and safely remove it when done (allowing for external removal) + if ( !timer() && timers[ i ] === timer ) { + timers.splice( i--, 1 ); + } + } + + if ( !timers.length ) { + jQuery.fx.stop(); + } + fxNow = undefined; +}; + +jQuery.fx.timer = function( timer ) { + jQuery.timers.push( timer ); + jQuery.fx.start(); +}; + +jQuery.fx.interval = 13; +jQuery.fx.start = function() { + if ( inProgress ) { + return; + } + + inProgress = true; + schedule(); +}; + +jQuery.fx.stop = function() { + inProgress = null; +}; + +jQuery.fx.speeds = { + slow: 600, + fast: 200, + + // Default speed + _default: 400 +}; + + +// Based off of the plugin by Clint Helfers, with permission. +// https://web.archive.org/web/20100324014747/http://blindsignals.com/index.php/2009/07/jquery-delay/ +jQuery.fn.delay = function( time, type ) { + time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time; + type = type || "fx"; + + return this.queue( type, function( next, hooks ) { + var timeout = window.setTimeout( next, time ); + hooks.stop = function() { + window.clearTimeout( timeout ); + }; + } ); +}; + + +( function() { + var input = document.createElement( "input" ), + select = document.createElement( "select" ), + opt = select.appendChild( document.createElement( "option" ) ); + + input.type = "checkbox"; + + // Support: Android <=4.3 only + // Default value for a checkbox should be "on" + support.checkOn = input.value !== ""; + + // Support: IE <=11 only + // Must access selectedIndex to make default options select + support.optSelected = opt.selected; + + // Support: IE <=11 only + // An input loses its value after becoming a radio + input = document.createElement( "input" ); + input.value = "t"; + input.type = "radio"; + support.radioValue = input.value === "t"; +} )(); + + +var boolHook, + attrHandle = jQuery.expr.attrHandle; + +jQuery.fn.extend( { + attr: function( name, value ) { + return access( this, jQuery.attr, name, value, arguments.length > 1 ); + }, + + removeAttr: function( name ) { + return this.each( function() { + jQuery.removeAttr( this, name ); + } ); + } +} ); + +jQuery.extend( { + attr: function( elem, name, value ) { + var ret, hooks, + nType = elem.nodeType; + + // Don't get/set attributes on text, comment and attribute nodes + if ( nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + // Fallback to prop when attributes are not supported + if ( typeof elem.getAttribute === "undefined" ) { + return jQuery.prop( elem, name, value ); + } + + // Attribute hooks are determined by the lowercase version + // Grab necessary hook if one is defined + if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { + hooks = jQuery.attrHooks[ name.toLowerCase() ] || + ( jQuery.expr.match.bool.test( name ) ? boolHook : undefined ); + } + + if ( value !== undefined ) { + if ( value === null ) { + jQuery.removeAttr( elem, name ); + return; + } + + if ( hooks && "set" in hooks && + ( ret = hooks.set( elem, value, name ) ) !== undefined ) { + return ret; + } + + elem.setAttribute( name, value + "" ); + return value; + } + + if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { + return ret; + } + + ret = jQuery.find.attr( elem, name ); + + // Non-existent attributes return null, we normalize to undefined + return ret == null ? undefined : ret; + }, + + attrHooks: { + type: { + set: function( elem, value ) { + if ( !support.radioValue && value === "radio" && + nodeName( elem, "input" ) ) { + var val = elem.value; + elem.setAttribute( "type", value ); + if ( val ) { + elem.value = val; + } + return value; + } + } + } + }, + + removeAttr: function( elem, value ) { + var name, + i = 0, + + // Attribute names can contain non-HTML whitespace characters + // https://html.spec.whatwg.org/multipage/syntax.html#attributes-2 + attrNames = value && value.match( rnothtmlwhite ); + + if ( attrNames && elem.nodeType === 1 ) { + while ( ( name = attrNames[ i++ ] ) ) { + elem.removeAttribute( name ); + } + } + } +} ); + +// Hooks for boolean attributes +boolHook = { + set: function( elem, value, name ) { + if ( value === false ) { + + // Remove boolean attributes when set to false + jQuery.removeAttr( elem, name ); + } else { + elem.setAttribute( name, name ); + } + return name; + } +}; + +jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( _i, name ) { + var getter = attrHandle[ name ] || jQuery.find.attr; + + attrHandle[ name ] = function( elem, name, isXML ) { + var ret, handle, + lowercaseName = name.toLowerCase(); + + if ( !isXML ) { + + // Avoid an infinite loop by temporarily removing this function from the getter + handle = attrHandle[ lowercaseName ]; + attrHandle[ lowercaseName ] = ret; + ret = getter( elem, name, isXML ) != null ? + lowercaseName : + null; + attrHandle[ lowercaseName ] = handle; + } + return ret; + }; +} ); + + + + +var rfocusable = /^(?:input|select|textarea|button)$/i, + rclickable = /^(?:a|area)$/i; + +jQuery.fn.extend( { + prop: function( name, value ) { + return access( this, jQuery.prop, name, value, arguments.length > 1 ); + }, + + removeProp: function( name ) { + return this.each( function() { + delete this[ jQuery.propFix[ name ] || name ]; + } ); + } +} ); + +jQuery.extend( { + prop: function( elem, name, value ) { + var ret, hooks, + nType = elem.nodeType; + + // Don't get/set properties on text, comment and attribute nodes + if ( nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { + + // Fix name and attach hooks + name = jQuery.propFix[ name ] || name; + hooks = jQuery.propHooks[ name ]; + } + + if ( value !== undefined ) { + if ( hooks && "set" in hooks && + ( ret = hooks.set( elem, value, name ) ) !== undefined ) { + return ret; + } + + return ( elem[ name ] = value ); + } + + if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { + return ret; + } + + return elem[ name ]; + }, + + propHooks: { + tabIndex: { + get: function( elem ) { + + // Support: IE <=9 - 11 only + // elem.tabIndex doesn't always return the + // correct value when it hasn't been explicitly set + // https://web.archive.org/web/20141116233347/http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ + // Use proper attribute retrieval(#12072) + var tabindex = jQuery.find.attr( elem, "tabindex" ); + + if ( tabindex ) { + return parseInt( tabindex, 10 ); + } + + if ( + rfocusable.test( elem.nodeName ) || + rclickable.test( elem.nodeName ) && + elem.href + ) { + return 0; + } + + return -1; + } + } + }, + + propFix: { + "for": "htmlFor", + "class": "className" + } +} ); + +// Support: IE <=11 only +// Accessing the selectedIndex property +// forces the browser to respect setting selected +// on the option +// The getter ensures a default option is selected +// when in an optgroup +// eslint rule "no-unused-expressions" is disabled for this code +// since it considers such accessions noop +if ( !support.optSelected ) { + jQuery.propHooks.selected = { + get: function( elem ) { + + /* eslint no-unused-expressions: "off" */ + + var parent = elem.parentNode; + if ( parent && parent.parentNode ) { + parent.parentNode.selectedIndex; + } + return null; + }, + set: function( elem ) { + + /* eslint no-unused-expressions: "off" */ + + var parent = elem.parentNode; + if ( parent ) { + parent.selectedIndex; + + if ( parent.parentNode ) { + parent.parentNode.selectedIndex; + } + } + } + }; +} + +jQuery.each( [ + "tabIndex", + "readOnly", + "maxLength", + "cellSpacing", + "cellPadding", + "rowSpan", + "colSpan", + "useMap", + "frameBorder", + "contentEditable" +], function() { + jQuery.propFix[ this.toLowerCase() ] = this; +} ); + + + + + // Strip and collapse whitespace according to HTML spec + // https://infra.spec.whatwg.org/#strip-and-collapse-ascii-whitespace + function stripAndCollapse( value ) { + var tokens = value.match( rnothtmlwhite ) || []; + return tokens.join( " " ); + } + + +function getClass( elem ) { + return elem.getAttribute && elem.getAttribute( "class" ) || ""; +} + +function classesToArray( value ) { + if ( Array.isArray( value ) ) { + return value; + } + if ( typeof value === "string" ) { + return value.match( rnothtmlwhite ) || []; + } + return []; +} + +jQuery.fn.extend( { + addClass: function( value ) { + var classes, elem, cur, curValue, clazz, j, finalValue, + i = 0; + + if ( isFunction( value ) ) { + return this.each( function( j ) { + jQuery( this ).addClass( value.call( this, j, getClass( this ) ) ); + } ); + } + + classes = classesToArray( value ); + + if ( classes.length ) { + while ( ( elem = this[ i++ ] ) ) { + curValue = getClass( elem ); + cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); + + if ( cur ) { + j = 0; + while ( ( clazz = classes[ j++ ] ) ) { + if ( cur.indexOf( " " + clazz + " " ) < 0 ) { + cur += clazz + " "; + } + } + + // Only assign if different to avoid unneeded rendering. + finalValue = stripAndCollapse( cur ); + if ( curValue !== finalValue ) { + elem.setAttribute( "class", finalValue ); + } + } + } + } + + return this; + }, + + removeClass: function( value ) { + var classes, elem, cur, curValue, clazz, j, finalValue, + i = 0; + + if ( isFunction( value ) ) { + return this.each( function( j ) { + jQuery( this ).removeClass( value.call( this, j, getClass( this ) ) ); + } ); + } + + if ( !arguments.length ) { + return this.attr( "class", "" ); + } + + classes = classesToArray( value ); + + if ( classes.length ) { + while ( ( elem = this[ i++ ] ) ) { + curValue = getClass( elem ); + + // This expression is here for better compressibility (see addClass) + cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); + + if ( cur ) { + j = 0; + while ( ( clazz = classes[ j++ ] ) ) { + + // Remove *all* instances + while ( cur.indexOf( " " + clazz + " " ) > -1 ) { + cur = cur.replace( " " + clazz + " ", " " ); + } + } + + // Only assign if different to avoid unneeded rendering. + finalValue = stripAndCollapse( cur ); + if ( curValue !== finalValue ) { + elem.setAttribute( "class", finalValue ); + } + } + } + } + + return this; + }, + + toggleClass: function( value, stateVal ) { + var type = typeof value, + isValidValue = type === "string" || Array.isArray( value ); + + if ( typeof stateVal === "boolean" && isValidValue ) { + return stateVal ? this.addClass( value ) : this.removeClass( value ); + } + + if ( isFunction( value ) ) { + return this.each( function( i ) { + jQuery( this ).toggleClass( + value.call( this, i, getClass( this ), stateVal ), + stateVal + ); + } ); + } + + return this.each( function() { + var className, i, self, classNames; + + if ( isValidValue ) { + + // Toggle individual class names + i = 0; + self = jQuery( this ); + classNames = classesToArray( value ); + + while ( ( className = classNames[ i++ ] ) ) { + + // Check each className given, space separated list + if ( self.hasClass( className ) ) { + self.removeClass( className ); + } else { + self.addClass( className ); + } + } + + // Toggle whole class name + } else if ( value === undefined || type === "boolean" ) { + className = getClass( this ); + if ( className ) { + + // Store className if set + dataPriv.set( this, "__className__", className ); + } + + // If the element has a class name or if we're passed `false`, + // then remove the whole classname (if there was one, the above saved it). + // Otherwise bring back whatever was previously saved (if anything), + // falling back to the empty string if nothing was stored. + if ( this.setAttribute ) { + this.setAttribute( "class", + className || value === false ? + "" : + dataPriv.get( this, "__className__" ) || "" + ); + } + } + } ); + }, + + hasClass: function( selector ) { + var className, elem, + i = 0; + + className = " " + selector + " "; + while ( ( elem = this[ i++ ] ) ) { + if ( elem.nodeType === 1 && + ( " " + stripAndCollapse( getClass( elem ) ) + " " ).indexOf( className ) > -1 ) { + return true; + } + } + + return false; + } +} ); + + + + +var rreturn = /\r/g; + +jQuery.fn.extend( { + val: function( value ) { + var hooks, ret, valueIsFunction, + elem = this[ 0 ]; + + if ( !arguments.length ) { + if ( elem ) { + hooks = jQuery.valHooks[ elem.type ] || + jQuery.valHooks[ elem.nodeName.toLowerCase() ]; + + if ( hooks && + "get" in hooks && + ( ret = hooks.get( elem, "value" ) ) !== undefined + ) { + return ret; + } + + ret = elem.value; + + // Handle most common string cases + if ( typeof ret === "string" ) { + return ret.replace( rreturn, "" ); + } + + // Handle cases where value is null/undef or number + return ret == null ? "" : ret; + } + + return; + } + + valueIsFunction = isFunction( value ); + + return this.each( function( i ) { + var val; + + if ( this.nodeType !== 1 ) { + return; + } + + if ( valueIsFunction ) { + val = value.call( this, i, jQuery( this ).val() ); + } else { + val = value; + } + + // Treat null/undefined as ""; convert numbers to string + if ( val == null ) { + val = ""; + + } else if ( typeof val === "number" ) { + val += ""; + + } else if ( Array.isArray( val ) ) { + val = jQuery.map( val, function( value ) { + return value == null ? "" : value + ""; + } ); + } + + hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ]; + + // If set returns undefined, fall back to normal setting + if ( !hooks || !( "set" in hooks ) || hooks.set( this, val, "value" ) === undefined ) { + this.value = val; + } + } ); + } +} ); + +jQuery.extend( { + valHooks: { + option: { + get: function( elem ) { + + var val = jQuery.find.attr( elem, "value" ); + return val != null ? + val : + + // Support: IE <=10 - 11 only + // option.text throws exceptions (#14686, #14858) + // Strip and collapse whitespace + // https://html.spec.whatwg.org/#strip-and-collapse-whitespace + stripAndCollapse( jQuery.text( elem ) ); + } + }, + select: { + get: function( elem ) { + var value, option, i, + options = elem.options, + index = elem.selectedIndex, + one = elem.type === "select-one", + values = one ? null : [], + max = one ? index + 1 : options.length; + + if ( index < 0 ) { + i = max; + + } else { + i = one ? index : 0; + } + + // Loop through all the selected options + for ( ; i < max; i++ ) { + option = options[ i ]; + + // Support: IE <=9 only + // IE8-9 doesn't update selected after form reset (#2551) + if ( ( option.selected || i === index ) && + + // Don't return options that are disabled or in a disabled optgroup + !option.disabled && + ( !option.parentNode.disabled || + !nodeName( option.parentNode, "optgroup" ) ) ) { + + // Get the specific value for the option + value = jQuery( option ).val(); + + // We don't need an array for one selects + if ( one ) { + return value; + } + + // Multi-Selects return an array + values.push( value ); + } + } + + return values; + }, + + set: function( elem, value ) { + var optionSet, option, + options = elem.options, + values = jQuery.makeArray( value ), + i = options.length; + + while ( i-- ) { + option = options[ i ]; + + /* eslint-disable no-cond-assign */ + + if ( option.selected = + jQuery.inArray( jQuery.valHooks.option.get( option ), values ) > -1 + ) { + optionSet = true; + } + + /* eslint-enable no-cond-assign */ + } + + // Force browsers to behave consistently when non-matching value is set + if ( !optionSet ) { + elem.selectedIndex = -1; + } + return values; + } + } + } +} ); + +// Radios and checkboxes getter/setter +jQuery.each( [ "radio", "checkbox" ], function() { + jQuery.valHooks[ this ] = { + set: function( elem, value ) { + if ( Array.isArray( value ) ) { + return ( elem.checked = jQuery.inArray( jQuery( elem ).val(), value ) > -1 ); + } + } + }; + if ( !support.checkOn ) { + jQuery.valHooks[ this ].get = function( elem ) { + return elem.getAttribute( "value" ) === null ? "on" : elem.value; + }; + } +} ); + + + + +// Return jQuery for attributes-only inclusion + + +support.focusin = "onfocusin" in window; + + +var rfocusMorph = /^(?:focusinfocus|focusoutblur)$/, + stopPropagationCallback = function( e ) { + e.stopPropagation(); + }; + +jQuery.extend( jQuery.event, { + + trigger: function( event, data, elem, onlyHandlers ) { + + var i, cur, tmp, bubbleType, ontype, handle, special, lastElement, + eventPath = [ elem || document ], + type = hasOwn.call( event, "type" ) ? event.type : event, + namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split( "." ) : []; + + cur = lastElement = tmp = elem = elem || document; + + // Don't do events on text and comment nodes + if ( elem.nodeType === 3 || elem.nodeType === 8 ) { + return; + } + + // focus/blur morphs to focusin/out; ensure we're not firing them right now + if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { + return; + } + + if ( type.indexOf( "." ) > -1 ) { + + // Namespaced trigger; create a regexp to match event type in handle() + namespaces = type.split( "." ); + type = namespaces.shift(); + namespaces.sort(); + } + ontype = type.indexOf( ":" ) < 0 && "on" + type; + + // Caller can pass in a jQuery.Event object, Object, or just an event type string + event = event[ jQuery.expando ] ? + event : + new jQuery.Event( type, typeof event === "object" && event ); + + // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true) + event.isTrigger = onlyHandlers ? 2 : 3; + event.namespace = namespaces.join( "." ); + event.rnamespace = event.namespace ? + new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ) : + null; + + // Clean up the event in case it is being reused + event.result = undefined; + if ( !event.target ) { + event.target = elem; + } + + // Clone any incoming data and prepend the event, creating the handler arg list + data = data == null ? + [ event ] : + jQuery.makeArray( data, [ event ] ); + + // Allow special events to draw outside the lines + special = jQuery.event.special[ type ] || {}; + if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) { + return; + } + + // Determine event propagation path in advance, per W3C events spec (#9951) + // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) + if ( !onlyHandlers && !special.noBubble && !isWindow( elem ) ) { + + bubbleType = special.delegateType || type; + if ( !rfocusMorph.test( bubbleType + type ) ) { + cur = cur.parentNode; + } + for ( ; cur; cur = cur.parentNode ) { + eventPath.push( cur ); + tmp = cur; + } + + // Only add window if we got to document (e.g., not plain obj or detached DOM) + if ( tmp === ( elem.ownerDocument || document ) ) { + eventPath.push( tmp.defaultView || tmp.parentWindow || window ); + } + } + + // Fire handlers on the event path + i = 0; + while ( ( cur = eventPath[ i++ ] ) && !event.isPropagationStopped() ) { + lastElement = cur; + event.type = i > 1 ? + bubbleType : + special.bindType || type; + + // jQuery handler + handle = ( + dataPriv.get( cur, "events" ) || Object.create( null ) + )[ event.type ] && + dataPriv.get( cur, "handle" ); + if ( handle ) { + handle.apply( cur, data ); + } + + // Native handler + handle = ontype && cur[ ontype ]; + if ( handle && handle.apply && acceptData( cur ) ) { + event.result = handle.apply( cur, data ); + if ( event.result === false ) { + event.preventDefault(); + } + } + } + event.type = type; + + // If nobody prevented the default action, do it now + if ( !onlyHandlers && !event.isDefaultPrevented() ) { + + if ( ( !special._default || + special._default.apply( eventPath.pop(), data ) === false ) && + acceptData( elem ) ) { + + // Call a native DOM method on the target with the same name as the event. + // Don't do default actions on window, that's where global variables be (#6170) + if ( ontype && isFunction( elem[ type ] ) && !isWindow( elem ) ) { + + // Don't re-trigger an onFOO event when we call its FOO() method + tmp = elem[ ontype ]; + + if ( tmp ) { + elem[ ontype ] = null; + } + + // Prevent re-triggering of the same event, since we already bubbled it above + jQuery.event.triggered = type; + + if ( event.isPropagationStopped() ) { + lastElement.addEventListener( type, stopPropagationCallback ); + } + + elem[ type ](); + + if ( event.isPropagationStopped() ) { + lastElement.removeEventListener( type, stopPropagationCallback ); + } + + jQuery.event.triggered = undefined; + + if ( tmp ) { + elem[ ontype ] = tmp; + } + } + } + } + + return event.result; + }, + + // Piggyback on a donor event to simulate a different one + // Used only for `focus(in | out)` events + simulate: function( type, elem, event ) { + var e = jQuery.extend( + new jQuery.Event(), + event, + { + type: type, + isSimulated: true + } + ); + + jQuery.event.trigger( e, null, elem ); + } + +} ); + +jQuery.fn.extend( { + + trigger: function( type, data ) { + return this.each( function() { + jQuery.event.trigger( type, data, this ); + } ); + }, + triggerHandler: function( type, data ) { + var elem = this[ 0 ]; + if ( elem ) { + return jQuery.event.trigger( type, data, elem, true ); + } + } +} ); + + +// Support: Firefox <=44 +// Firefox doesn't have focus(in | out) events +// Related ticket - https://bugzilla.mozilla.org/show_bug.cgi?id=687787 +// +// Support: Chrome <=48 - 49, Safari <=9.0 - 9.1 +// focus(in | out) events fire after focus & blur events, +// which is spec violation - http://www.w3.org/TR/DOM-Level-3-Events/#events-focusevent-event-order +// Related ticket - https://bugs.chromium.org/p/chromium/issues/detail?id=449857 +if ( !support.focusin ) { + jQuery.each( { focus: "focusin", blur: "focusout" }, function( orig, fix ) { + + // Attach a single capturing handler on the document while someone wants focusin/focusout + var handler = function( event ) { + jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ) ); + }; + + jQuery.event.special[ fix ] = { + setup: function() { + + // Handle: regular nodes (via `this.ownerDocument`), window + // (via `this.document`) & document (via `this`). + var doc = this.ownerDocument || this.document || this, + attaches = dataPriv.access( doc, fix ); + + if ( !attaches ) { + doc.addEventListener( orig, handler, true ); + } + dataPriv.access( doc, fix, ( attaches || 0 ) + 1 ); + }, + teardown: function() { + var doc = this.ownerDocument || this.document || this, + attaches = dataPriv.access( doc, fix ) - 1; + + if ( !attaches ) { + doc.removeEventListener( orig, handler, true ); + dataPriv.remove( doc, fix ); + + } else { + dataPriv.access( doc, fix, attaches ); + } + } + }; + } ); +} +var location = window.location; + +var nonce = { guid: Date.now() }; + +var rquery = ( /\?/ ); + + + +// Cross-browser xml parsing +jQuery.parseXML = function( data ) { + var xml; + if ( !data || typeof data !== "string" ) { + return null; + } + + // Support: IE 9 - 11 only + // IE throws on parseFromString with invalid input. + try { + xml = ( new window.DOMParser() ).parseFromString( data, "text/xml" ); + } catch ( e ) { + xml = undefined; + } + + if ( !xml || xml.getElementsByTagName( "parsererror" ).length ) { + jQuery.error( "Invalid XML: " + data ); + } + return xml; +}; + + +var + rbracket = /\[\]$/, + rCRLF = /\r?\n/g, + rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i, + rsubmittable = /^(?:input|select|textarea|keygen)/i; + +function buildParams( prefix, obj, traditional, add ) { + var name; + + if ( Array.isArray( obj ) ) { + + // Serialize array item. + jQuery.each( obj, function( i, v ) { + if ( traditional || rbracket.test( prefix ) ) { + + // Treat each array item as a scalar. + add( prefix, v ); + + } else { + + // Item is non-scalar (array or object), encode its numeric index. + buildParams( + prefix + "[" + ( typeof v === "object" && v != null ? i : "" ) + "]", + v, + traditional, + add + ); + } + } ); + + } else if ( !traditional && toType( obj ) === "object" ) { + + // Serialize object item. + for ( name in obj ) { + buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add ); + } + + } else { + + // Serialize scalar item. + add( prefix, obj ); + } +} + +// Serialize an array of form elements or a set of +// key/values into a query string +jQuery.param = function( a, traditional ) { + var prefix, + s = [], + add = function( key, valueOrFunction ) { + + // If value is a function, invoke it and use its return value + var value = isFunction( valueOrFunction ) ? + valueOrFunction() : + valueOrFunction; + + s[ s.length ] = encodeURIComponent( key ) + "=" + + encodeURIComponent( value == null ? "" : value ); + }; + + if ( a == null ) { + return ""; + } + + // If an array was passed in, assume that it is an array of form elements. + if ( Array.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) { + + // Serialize the form elements + jQuery.each( a, function() { + add( this.name, this.value ); + } ); + + } else { + + // If traditional, encode the "old" way (the way 1.3.2 or older + // did it), otherwise encode params recursively. + for ( prefix in a ) { + buildParams( prefix, a[ prefix ], traditional, add ); + } + } + + // Return the resulting serialization + return s.join( "&" ); +}; + +jQuery.fn.extend( { + serialize: function() { + return jQuery.param( this.serializeArray() ); + }, + serializeArray: function() { + return this.map( function() { + + // Can add propHook for "elements" to filter or add form elements + var elements = jQuery.prop( this, "elements" ); + return elements ? jQuery.makeArray( elements ) : this; + } ) + .filter( function() { + var type = this.type; + + // Use .is( ":disabled" ) so that fieldset[disabled] works + return this.name && !jQuery( this ).is( ":disabled" ) && + rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) && + ( this.checked || !rcheckableType.test( type ) ); + } ) + .map( function( _i, elem ) { + var val = jQuery( this ).val(); + + if ( val == null ) { + return null; + } + + if ( Array.isArray( val ) ) { + return jQuery.map( val, function( val ) { + return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; + } ); + } + + return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; + } ).get(); + } +} ); + + +var + r20 = /%20/g, + rhash = /#.*$/, + rantiCache = /([?&])_=[^&]*/, + rheaders = /^(.*?):[ \t]*([^\r\n]*)$/mg, + + // #7653, #8125, #8152: local protocol detection + rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/, + rnoContent = /^(?:GET|HEAD)$/, + rprotocol = /^\/\//, + + /* Prefilters + * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example) + * 2) These are called: + * - BEFORE asking for a transport + * - AFTER param serialization (s.data is a string if s.processData is true) + * 3) key is the dataType + * 4) the catchall symbol "*" can be used + * 5) execution will start with transport dataType and THEN continue down to "*" if needed + */ + prefilters = {}, + + /* Transports bindings + * 1) key is the dataType + * 2) the catchall symbol "*" can be used + * 3) selection will start with transport dataType and THEN go to "*" if needed + */ + transports = {}, + + // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression + allTypes = "*/".concat( "*" ), + + // Anchor tag for parsing the document origin + originAnchor = document.createElement( "a" ); + originAnchor.href = location.href; + +// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport +function addToPrefiltersOrTransports( structure ) { + + // dataTypeExpression is optional and defaults to "*" + return function( dataTypeExpression, func ) { + + if ( typeof dataTypeExpression !== "string" ) { + func = dataTypeExpression; + dataTypeExpression = "*"; + } + + var dataType, + i = 0, + dataTypes = dataTypeExpression.toLowerCase().match( rnothtmlwhite ) || []; + + if ( isFunction( func ) ) { + + // For each dataType in the dataTypeExpression + while ( ( dataType = dataTypes[ i++ ] ) ) { + + // Prepend if requested + if ( dataType[ 0 ] === "+" ) { + dataType = dataType.slice( 1 ) || "*"; + ( structure[ dataType ] = structure[ dataType ] || [] ).unshift( func ); + + // Otherwise append + } else { + ( structure[ dataType ] = structure[ dataType ] || [] ).push( func ); + } + } + } + }; +} + +// Base inspection function for prefilters and transports +function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) { + + var inspected = {}, + seekingTransport = ( structure === transports ); + + function inspect( dataType ) { + var selected; + inspected[ dataType ] = true; + jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) { + var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR ); + if ( typeof dataTypeOrTransport === "string" && + !seekingTransport && !inspected[ dataTypeOrTransport ] ) { + + options.dataTypes.unshift( dataTypeOrTransport ); + inspect( dataTypeOrTransport ); + return false; + } else if ( seekingTransport ) { + return !( selected = dataTypeOrTransport ); + } + } ); + return selected; + } + + return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" ); +} + +// A special extend for ajax options +// that takes "flat" options (not to be deep extended) +// Fixes #9887 +function ajaxExtend( target, src ) { + var key, deep, + flatOptions = jQuery.ajaxSettings.flatOptions || {}; + + for ( key in src ) { + if ( src[ key ] !== undefined ) { + ( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ]; + } + } + if ( deep ) { + jQuery.extend( true, target, deep ); + } + + return target; +} + +/* Handles responses to an ajax request: + * - finds the right dataType (mediates between content-type and expected dataType) + * - returns the corresponding response + */ +function ajaxHandleResponses( s, jqXHR, responses ) { + + var ct, type, finalDataType, firstDataType, + contents = s.contents, + dataTypes = s.dataTypes; + + // Remove auto dataType and get content-type in the process + while ( dataTypes[ 0 ] === "*" ) { + dataTypes.shift(); + if ( ct === undefined ) { + ct = s.mimeType || jqXHR.getResponseHeader( "Content-Type" ); + } + } + + // Check if we're dealing with a known content-type + if ( ct ) { + for ( type in contents ) { + if ( contents[ type ] && contents[ type ].test( ct ) ) { + dataTypes.unshift( type ); + break; + } + } + } + + // Check to see if we have a response for the expected dataType + if ( dataTypes[ 0 ] in responses ) { + finalDataType = dataTypes[ 0 ]; + } else { + + // Try convertible dataTypes + for ( type in responses ) { + if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[ 0 ] ] ) { + finalDataType = type; + break; + } + if ( !firstDataType ) { + firstDataType = type; + } + } + + // Or just use first one + finalDataType = finalDataType || firstDataType; + } + + // If we found a dataType + // We add the dataType to the list if needed + // and return the corresponding response + if ( finalDataType ) { + if ( finalDataType !== dataTypes[ 0 ] ) { + dataTypes.unshift( finalDataType ); + } + return responses[ finalDataType ]; + } +} + +/* Chain conversions given the request and the original response + * Also sets the responseXXX fields on the jqXHR instance + */ +function ajaxConvert( s, response, jqXHR, isSuccess ) { + var conv2, current, conv, tmp, prev, + converters = {}, + + // Work with a copy of dataTypes in case we need to modify it for conversion + dataTypes = s.dataTypes.slice(); + + // Create converters map with lowercased keys + if ( dataTypes[ 1 ] ) { + for ( conv in s.converters ) { + converters[ conv.toLowerCase() ] = s.converters[ conv ]; + } + } + + current = dataTypes.shift(); + + // Convert to each sequential dataType + while ( current ) { + + if ( s.responseFields[ current ] ) { + jqXHR[ s.responseFields[ current ] ] = response; + } + + // Apply the dataFilter if provided + if ( !prev && isSuccess && s.dataFilter ) { + response = s.dataFilter( response, s.dataType ); + } + + prev = current; + current = dataTypes.shift(); + + if ( current ) { + + // There's only work to do if current dataType is non-auto + if ( current === "*" ) { + + current = prev; + + // Convert response if prev dataType is non-auto and differs from current + } else if ( prev !== "*" && prev !== current ) { + + // Seek a direct converter + conv = converters[ prev + " " + current ] || converters[ "* " + current ]; + + // If none found, seek a pair + if ( !conv ) { + for ( conv2 in converters ) { + + // If conv2 outputs current + tmp = conv2.split( " " ); + if ( tmp[ 1 ] === current ) { + + // If prev can be converted to accepted input + conv = converters[ prev + " " + tmp[ 0 ] ] || + converters[ "* " + tmp[ 0 ] ]; + if ( conv ) { + + // Condense equivalence converters + if ( conv === true ) { + conv = converters[ conv2 ]; + + // Otherwise, insert the intermediate dataType + } else if ( converters[ conv2 ] !== true ) { + current = tmp[ 0 ]; + dataTypes.unshift( tmp[ 1 ] ); + } + break; + } + } + } + } + + // Apply converter (if not an equivalence) + if ( conv !== true ) { + + // Unless errors are allowed to bubble, catch and return them + if ( conv && s.throws ) { + response = conv( response ); + } else { + try { + response = conv( response ); + } catch ( e ) { + return { + state: "parsererror", + error: conv ? e : "No conversion from " + prev + " to " + current + }; + } + } + } + } + } + } + + return { state: "success", data: response }; +} + +jQuery.extend( { + + // Counter for holding the number of active queries + active: 0, + + // Last-Modified header cache for next request + lastModified: {}, + etag: {}, + + ajaxSettings: { + url: location.href, + type: "GET", + isLocal: rlocalProtocol.test( location.protocol ), + global: true, + processData: true, + async: true, + contentType: "application/x-www-form-urlencoded; charset=UTF-8", + + /* + timeout: 0, + data: null, + dataType: null, + username: null, + password: null, + cache: null, + throws: false, + traditional: false, + headers: {}, + */ + + accepts: { + "*": allTypes, + text: "text/plain", + html: "text/html", + xml: "application/xml, text/xml", + json: "application/json, text/javascript" + }, + + contents: { + xml: /\bxml\b/, + html: /\bhtml/, + json: /\bjson\b/ + }, + + responseFields: { + xml: "responseXML", + text: "responseText", + json: "responseJSON" + }, + + // Data converters + // Keys separate source (or catchall "*") and destination types with a single space + converters: { + + // Convert anything to text + "* text": String, + + // Text to html (true = no transformation) + "text html": true, + + // Evaluate text as a json expression + "text json": JSON.parse, + + // Parse text as xml + "text xml": jQuery.parseXML + }, + + // For options that shouldn't be deep extended: + // you can add your own custom options here if + // and when you create one that shouldn't be + // deep extended (see ajaxExtend) + flatOptions: { + url: true, + context: true + } + }, + + // Creates a full fledged settings object into target + // with both ajaxSettings and settings fields. + // If target is omitted, writes into ajaxSettings. + ajaxSetup: function( target, settings ) { + return settings ? + + // Building a settings object + ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) : + + // Extending ajaxSettings + ajaxExtend( jQuery.ajaxSettings, target ); + }, + + ajaxPrefilter: addToPrefiltersOrTransports( prefilters ), + ajaxTransport: addToPrefiltersOrTransports( transports ), + + // Main method + ajax: function( url, options ) { + + // If url is an object, simulate pre-1.5 signature + if ( typeof url === "object" ) { + options = url; + url = undefined; + } + + // Force options to be an object + options = options || {}; + + var transport, + + // URL without anti-cache param + cacheURL, + + // Response headers + responseHeadersString, + responseHeaders, + + // timeout handle + timeoutTimer, + + // Url cleanup var + urlAnchor, + + // Request state (becomes false upon send and true upon completion) + completed, + + // To know if global events are to be dispatched + fireGlobals, + + // Loop variable + i, + + // uncached part of the url + uncached, + + // Create the final options object + s = jQuery.ajaxSetup( {}, options ), + + // Callbacks context + callbackContext = s.context || s, + + // Context for global events is callbackContext if it is a DOM node or jQuery collection + globalEventContext = s.context && + ( callbackContext.nodeType || callbackContext.jquery ) ? + jQuery( callbackContext ) : + jQuery.event, + + // Deferreds + deferred = jQuery.Deferred(), + completeDeferred = jQuery.Callbacks( "once memory" ), + + // Status-dependent callbacks + statusCode = s.statusCode || {}, + + // Headers (they are sent all at once) + requestHeaders = {}, + requestHeadersNames = {}, + + // Default abort message + strAbort = "canceled", + + // Fake xhr + jqXHR = { + readyState: 0, + + // Builds headers hashtable if needed + getResponseHeader: function( key ) { + var match; + if ( completed ) { + if ( !responseHeaders ) { + responseHeaders = {}; + while ( ( match = rheaders.exec( responseHeadersString ) ) ) { + responseHeaders[ match[ 1 ].toLowerCase() + " " ] = + ( responseHeaders[ match[ 1 ].toLowerCase() + " " ] || [] ) + .concat( match[ 2 ] ); + } + } + match = responseHeaders[ key.toLowerCase() + " " ]; + } + return match == null ? null : match.join( ", " ); + }, + + // Raw string + getAllResponseHeaders: function() { + return completed ? responseHeadersString : null; + }, + + // Caches the header + setRequestHeader: function( name, value ) { + if ( completed == null ) { + name = requestHeadersNames[ name.toLowerCase() ] = + requestHeadersNames[ name.toLowerCase() ] || name; + requestHeaders[ name ] = value; + } + return this; + }, + + // Overrides response content-type header + overrideMimeType: function( type ) { + if ( completed == null ) { + s.mimeType = type; + } + return this; + }, + + // Status-dependent callbacks + statusCode: function( map ) { + var code; + if ( map ) { + if ( completed ) { + + // Execute the appropriate callbacks + jqXHR.always( map[ jqXHR.status ] ); + } else { + + // Lazy-add the new callbacks in a way that preserves old ones + for ( code in map ) { + statusCode[ code ] = [ statusCode[ code ], map[ code ] ]; + } + } + } + return this; + }, + + // Cancel the request + abort: function( statusText ) { + var finalText = statusText || strAbort; + if ( transport ) { + transport.abort( finalText ); + } + done( 0, finalText ); + return this; + } + }; + + // Attach deferreds + deferred.promise( jqXHR ); + + // Add protocol if not provided (prefilters might expect it) + // Handle falsy url in the settings object (#10093: consistency with old signature) + // We also use the url parameter if available + s.url = ( ( url || s.url || location.href ) + "" ) + .replace( rprotocol, location.protocol + "//" ); + + // Alias method option to type as per ticket #12004 + s.type = options.method || options.type || s.method || s.type; + + // Extract dataTypes list + s.dataTypes = ( s.dataType || "*" ).toLowerCase().match( rnothtmlwhite ) || [ "" ]; + + // A cross-domain request is in order when the origin doesn't match the current origin. + if ( s.crossDomain == null ) { + urlAnchor = document.createElement( "a" ); + + // Support: IE <=8 - 11, Edge 12 - 15 + // IE throws exception on accessing the href property if url is malformed, + // e.g. http://example.com:80x/ + try { + urlAnchor.href = s.url; + + // Support: IE <=8 - 11 only + // Anchor's host property isn't correctly set when s.url is relative + urlAnchor.href = urlAnchor.href; + s.crossDomain = originAnchor.protocol + "//" + originAnchor.host !== + urlAnchor.protocol + "//" + urlAnchor.host; + } catch ( e ) { + + // If there is an error parsing the URL, assume it is crossDomain, + // it can be rejected by the transport if it is invalid + s.crossDomain = true; + } + } + + // Convert data if not already a string + if ( s.data && s.processData && typeof s.data !== "string" ) { + s.data = jQuery.param( s.data, s.traditional ); + } + + // Apply prefilters + inspectPrefiltersOrTransports( prefilters, s, options, jqXHR ); + + // If request was aborted inside a prefilter, stop there + if ( completed ) { + return jqXHR; + } + + // We can fire global events as of now if asked to + // Don't fire events if jQuery.event is undefined in an AMD-usage scenario (#15118) + fireGlobals = jQuery.event && s.global; + + // Watch for a new set of requests + if ( fireGlobals && jQuery.active++ === 0 ) { + jQuery.event.trigger( "ajaxStart" ); + } + + // Uppercase the type + s.type = s.type.toUpperCase(); + + // Determine if request has content + s.hasContent = !rnoContent.test( s.type ); + + // Save the URL in case we're toying with the If-Modified-Since + // and/or If-None-Match header later on + // Remove hash to simplify url manipulation + cacheURL = s.url.replace( rhash, "" ); + + // More options handling for requests with no content + if ( !s.hasContent ) { + + // Remember the hash so we can put it back + uncached = s.url.slice( cacheURL.length ); + + // If data is available and should be processed, append data to url + if ( s.data && ( s.processData || typeof s.data === "string" ) ) { + cacheURL += ( rquery.test( cacheURL ) ? "&" : "?" ) + s.data; + + // #9682: remove data so that it's not used in an eventual retry + delete s.data; + } + + // Add or update anti-cache param if needed + if ( s.cache === false ) { + cacheURL = cacheURL.replace( rantiCache, "$1" ); + uncached = ( rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + ( nonce.guid++ ) + + uncached; + } + + // Put hash and anti-cache on the URL that will be requested (gh-1732) + s.url = cacheURL + uncached; + + // Change '%20' to '+' if this is encoded form body content (gh-2658) + } else if ( s.data && s.processData && + ( s.contentType || "" ).indexOf( "application/x-www-form-urlencoded" ) === 0 ) { + s.data = s.data.replace( r20, "+" ); + } + + // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. + if ( s.ifModified ) { + if ( jQuery.lastModified[ cacheURL ] ) { + jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] ); + } + if ( jQuery.etag[ cacheURL ] ) { + jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] ); + } + } + + // Set the correct header, if data is being sent + if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) { + jqXHR.setRequestHeader( "Content-Type", s.contentType ); + } + + // Set the Accepts header for the server, depending on the dataType + jqXHR.setRequestHeader( + "Accept", + s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[ 0 ] ] ? + s.accepts[ s.dataTypes[ 0 ] ] + + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) : + s.accepts[ "*" ] + ); + + // Check for headers option + for ( i in s.headers ) { + jqXHR.setRequestHeader( i, s.headers[ i ] ); + } + + // Allow custom headers/mimetypes and early abort + if ( s.beforeSend && + ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || completed ) ) { + + // Abort if not done already and return + return jqXHR.abort(); + } + + // Aborting is no longer a cancellation + strAbort = "abort"; + + // Install callbacks on deferreds + completeDeferred.add( s.complete ); + jqXHR.done( s.success ); + jqXHR.fail( s.error ); + + // Get transport + transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR ); + + // If no transport, we auto-abort + if ( !transport ) { + done( -1, "No Transport" ); + } else { + jqXHR.readyState = 1; + + // Send global event + if ( fireGlobals ) { + globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] ); + } + + // If request was aborted inside ajaxSend, stop there + if ( completed ) { + return jqXHR; + } + + // Timeout + if ( s.async && s.timeout > 0 ) { + timeoutTimer = window.setTimeout( function() { + jqXHR.abort( "timeout" ); + }, s.timeout ); + } + + try { + completed = false; + transport.send( requestHeaders, done ); + } catch ( e ) { + + // Rethrow post-completion exceptions + if ( completed ) { + throw e; + } + + // Propagate others as results + done( -1, e ); + } + } + + // Callback for when everything is done + function done( status, nativeStatusText, responses, headers ) { + var isSuccess, success, error, response, modified, + statusText = nativeStatusText; + + // Ignore repeat invocations + if ( completed ) { + return; + } + + completed = true; + + // Clear timeout if it exists + if ( timeoutTimer ) { + window.clearTimeout( timeoutTimer ); + } + + // Dereference transport for early garbage collection + // (no matter how long the jqXHR object will be used) + transport = undefined; + + // Cache response headers + responseHeadersString = headers || ""; + + // Set readyState + jqXHR.readyState = status > 0 ? 4 : 0; + + // Determine if successful + isSuccess = status >= 200 && status < 300 || status === 304; + + // Get response data + if ( responses ) { + response = ajaxHandleResponses( s, jqXHR, responses ); + } + + // Use a noop converter for missing script + if ( !isSuccess && jQuery.inArray( "script", s.dataTypes ) > -1 ) { + s.converters[ "text script" ] = function() {}; + } + + // Convert no matter what (that way responseXXX fields are always set) + response = ajaxConvert( s, response, jqXHR, isSuccess ); + + // If successful, handle type chaining + if ( isSuccess ) { + + // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. + if ( s.ifModified ) { + modified = jqXHR.getResponseHeader( "Last-Modified" ); + if ( modified ) { + jQuery.lastModified[ cacheURL ] = modified; + } + modified = jqXHR.getResponseHeader( "etag" ); + if ( modified ) { + jQuery.etag[ cacheURL ] = modified; + } + } + + // if no content + if ( status === 204 || s.type === "HEAD" ) { + statusText = "nocontent"; + + // if not modified + } else if ( status === 304 ) { + statusText = "notmodified"; + + // If we have data, let's convert it + } else { + statusText = response.state; + success = response.data; + error = response.error; + isSuccess = !error; + } + } else { + + // Extract error from statusText and normalize for non-aborts + error = statusText; + if ( status || !statusText ) { + statusText = "error"; + if ( status < 0 ) { + status = 0; + } + } + } + + // Set data for the fake xhr object + jqXHR.status = status; + jqXHR.statusText = ( nativeStatusText || statusText ) + ""; + + // Success/Error + if ( isSuccess ) { + deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] ); + } else { + deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] ); + } + + // Status-dependent callbacks + jqXHR.statusCode( statusCode ); + statusCode = undefined; + + if ( fireGlobals ) { + globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError", + [ jqXHR, s, isSuccess ? success : error ] ); + } + + // Complete + completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] ); + + if ( fireGlobals ) { + globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] ); + + // Handle the global AJAX counter + if ( !( --jQuery.active ) ) { + jQuery.event.trigger( "ajaxStop" ); + } + } + } + + return jqXHR; + }, + + getJSON: function( url, data, callback ) { + return jQuery.get( url, data, callback, "json" ); + }, + + getScript: function( url, callback ) { + return jQuery.get( url, undefined, callback, "script" ); + } +} ); + +jQuery.each( [ "get", "post" ], function( _i, method ) { + jQuery[ method ] = function( url, data, callback, type ) { + + // Shift arguments if data argument was omitted + if ( isFunction( data ) ) { + type = type || callback; + callback = data; + data = undefined; + } + + // The url can be an options object (which then must have .url) + return jQuery.ajax( jQuery.extend( { + url: url, + type: method, + dataType: type, + data: data, + success: callback + }, jQuery.isPlainObject( url ) && url ) ); + }; +} ); + +jQuery.ajaxPrefilter( function( s ) { + var i; + for ( i in s.headers ) { + if ( i.toLowerCase() === "content-type" ) { + s.contentType = s.headers[ i ] || ""; + } + } +} ); + + +jQuery._evalUrl = function( url, options, doc ) { + return jQuery.ajax( { + url: url, + + // Make this explicit, since user can override this through ajaxSetup (#11264) + type: "GET", + dataType: "script", + cache: true, + async: false, + global: false, + + // Only evaluate the response if it is successful (gh-4126) + // dataFilter is not invoked for failure responses, so using it instead + // of the default converter is kludgy but it works. + converters: { + "text script": function() {} + }, + dataFilter: function( response ) { + jQuery.globalEval( response, options, doc ); + } + } ); +}; + + +jQuery.fn.extend( { + wrapAll: function( html ) { + var wrap; + + if ( this[ 0 ] ) { + if ( isFunction( html ) ) { + html = html.call( this[ 0 ] ); + } + + // The elements to wrap the target around + wrap = jQuery( html, this[ 0 ].ownerDocument ).eq( 0 ).clone( true ); + + if ( this[ 0 ].parentNode ) { + wrap.insertBefore( this[ 0 ] ); + } + + wrap.map( function() { + var elem = this; + + while ( elem.firstElementChild ) { + elem = elem.firstElementChild; + } + + return elem; + } ).append( this ); + } + + return this; + }, + + wrapInner: function( html ) { + if ( isFunction( html ) ) { + return this.each( function( i ) { + jQuery( this ).wrapInner( html.call( this, i ) ); + } ); + } + + return this.each( function() { + var self = jQuery( this ), + contents = self.contents(); + + if ( contents.length ) { + contents.wrapAll( html ); + + } else { + self.append( html ); + } + } ); + }, + + wrap: function( html ) { + var htmlIsFunction = isFunction( html ); + + return this.each( function( i ) { + jQuery( this ).wrapAll( htmlIsFunction ? html.call( this, i ) : html ); + } ); + }, + + unwrap: function( selector ) { + this.parent( selector ).not( "body" ).each( function() { + jQuery( this ).replaceWith( this.childNodes ); + } ); + return this; + } +} ); + + +jQuery.expr.pseudos.hidden = function( elem ) { + return !jQuery.expr.pseudos.visible( elem ); +}; +jQuery.expr.pseudos.visible = function( elem ) { + return !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length ); +}; + + + + +jQuery.ajaxSettings.xhr = function() { + try { + return new window.XMLHttpRequest(); + } catch ( e ) {} +}; + +var xhrSuccessStatus = { + + // File protocol always yields status code 0, assume 200 + 0: 200, + + // Support: IE <=9 only + // #1450: sometimes IE returns 1223 when it should be 204 + 1223: 204 + }, + xhrSupported = jQuery.ajaxSettings.xhr(); + +support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported ); +support.ajax = xhrSupported = !!xhrSupported; + +jQuery.ajaxTransport( function( options ) { + var callback, errorCallback; + + // Cross domain only allowed if supported through XMLHttpRequest + if ( support.cors || xhrSupported && !options.crossDomain ) { + return { + send: function( headers, complete ) { + var i, + xhr = options.xhr(); + + xhr.open( + options.type, + options.url, + options.async, + options.username, + options.password + ); + + // Apply custom fields if provided + if ( options.xhrFields ) { + for ( i in options.xhrFields ) { + xhr[ i ] = options.xhrFields[ i ]; + } + } + + // Override mime type if needed + if ( options.mimeType && xhr.overrideMimeType ) { + xhr.overrideMimeType( options.mimeType ); + } + + // X-Requested-With header + // For cross-domain requests, seeing as conditions for a preflight are + // akin to a jigsaw puzzle, we simply never set it to be sure. + // (it can always be set on a per-request basis or even using ajaxSetup) + // For same-domain requests, won't change header if already provided. + if ( !options.crossDomain && !headers[ "X-Requested-With" ] ) { + headers[ "X-Requested-With" ] = "XMLHttpRequest"; + } + + // Set headers + for ( i in headers ) { + xhr.setRequestHeader( i, headers[ i ] ); + } + + // Callback + callback = function( type ) { + return function() { + if ( callback ) { + callback = errorCallback = xhr.onload = + xhr.onerror = xhr.onabort = xhr.ontimeout = + xhr.onreadystatechange = null; + + if ( type === "abort" ) { + xhr.abort(); + } else if ( type === "error" ) { + + // Support: IE <=9 only + // On a manual native abort, IE9 throws + // errors on any property access that is not readyState + if ( typeof xhr.status !== "number" ) { + complete( 0, "error" ); + } else { + complete( + + // File: protocol always yields status 0; see #8605, #14207 + xhr.status, + xhr.statusText + ); + } + } else { + complete( + xhrSuccessStatus[ xhr.status ] || xhr.status, + xhr.statusText, + + // Support: IE <=9 only + // IE9 has no XHR2 but throws on binary (trac-11426) + // For XHR2 non-text, let the caller handle it (gh-2498) + ( xhr.responseType || "text" ) !== "text" || + typeof xhr.responseText !== "string" ? + { binary: xhr.response } : + { text: xhr.responseText }, + xhr.getAllResponseHeaders() + ); + } + } + }; + }; + + // Listen to events + xhr.onload = callback(); + errorCallback = xhr.onerror = xhr.ontimeout = callback( "error" ); + + // Support: IE 9 only + // Use onreadystatechange to replace onabort + // to handle uncaught aborts + if ( xhr.onabort !== undefined ) { + xhr.onabort = errorCallback; + } else { + xhr.onreadystatechange = function() { + + // Check readyState before timeout as it changes + if ( xhr.readyState === 4 ) { + + // Allow onerror to be called first, + // but that will not handle a native abort + // Also, save errorCallback to a variable + // as xhr.onerror cannot be accessed + window.setTimeout( function() { + if ( callback ) { + errorCallback(); + } + } ); + } + }; + } + + // Create the abort callback + callback = callback( "abort" ); + + try { + + // Do send the request (this may raise an exception) + xhr.send( options.hasContent && options.data || null ); + } catch ( e ) { + + // #14683: Only rethrow if this hasn't been notified as an error yet + if ( callback ) { + throw e; + } + } + }, + + abort: function() { + if ( callback ) { + callback(); + } + } + }; + } +} ); + + + + +// Prevent auto-execution of scripts when no explicit dataType was provided (See gh-2432) +jQuery.ajaxPrefilter( function( s ) { + if ( s.crossDomain ) { + s.contents.script = false; + } +} ); + +// Install script dataType +jQuery.ajaxSetup( { + accepts: { + script: "text/javascript, application/javascript, " + + "application/ecmascript, application/x-ecmascript" + }, + contents: { + script: /\b(?:java|ecma)script\b/ + }, + converters: { + "text script": function( text ) { + jQuery.globalEval( text ); + return text; + } + } +} ); + +// Handle cache's special case and crossDomain +jQuery.ajaxPrefilter( "script", function( s ) { + if ( s.cache === undefined ) { + s.cache = false; + } + if ( s.crossDomain ) { + s.type = "GET"; + } +} ); + +// Bind script tag hack transport +jQuery.ajaxTransport( "script", function( s ) { + + // This transport only deals with cross domain or forced-by-attrs requests + if ( s.crossDomain || s.scriptAttrs ) { + var script, callback; + return { + send: function( _, complete ) { + script = jQuery( " + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +
+

18. Advanced methods

+

This page documents advanced features of ESPResSo. Be sure to read the relevant +literature before using them.

+
+

18.1. Creating bonds when particles collide

+

Please cite [Arnold et al., 2013] when using dynamic binding.

+

With the help of this feature, bonds between particles can be created +automatically during the simulation, every time two particles collide. +This is useful for simulations of chemical reactions and irreversible +adhesion processes. Both, sliding and non-sliding contacts can be created.

+

The collision detection is controlled via the system +collision_detection attribute, +which is an instance of the class +CollisionDetection.

+

Several modes are available for different types of binding.

+
    +
  • "bind_centers": adds a pair-bond between two particles at their first collision. +By making the bonded interaction stiff enough, the particles can be held together +after the collision. Note that the particles can still slide on each others’ surface, +as the pair bond is not directional. This mode is set up as follows:

    +
    import espressomd
    +import espressomd.interactions
    +
    +system = espressomd.System(box_l=[1, 1, 1])
    +bond_centers = espressomd.interactions.HarmonicBond(k=1000, r_0=1.5)
    +system.bonded_inter.add(bond_centers)
    +system.collision_detection.set_params(mode="bind_centers", distance=1.5,
    +                                      bond_centers=bond_centers)
    +
    +
    +

    The parameters are as follows:

    +
      +
    • distance is the distance between two particles at which the binding is triggered. +This cutoff distance, 1.5 in the example above, is typically chosen slightly larger +than the particle diameter. It is also a good choice for the equilibrium length of the bond.

    • +
    • bond_centers is the bonded interaction to be created between the particles +(an instance of HarmonicBond in the example above). +No guarantees are made regarding which of the two colliding particles gets the bond. +Once there is a bond of this type on any of the colliding particles, +no further binding occurs for this pair of particles.

    • +
    +
  • +
  • "bind_at_point_of_collision": this mode prevents sliding of the colliding particles at the contact. +This is achieved by creating two virtual sites at the point of collision. +They are rigidly connected to each of the colliding particles. +A bond is then created between the virtual sites, or an angular bond between +the two colliding particles and the virtual particles. In the latter case, +the virtual particles are the centers of the angle potentials +(particle 2 in the description of the angle potential, see Bond-angle interactions). +Due to the rigid connection between each of the +particles in the collision and its respective virtual site, a sliding +at the contact point is no longer possible. See the documentation on +Rigid arrangements of particles for details. In addition to the bond between the virtual +sites, the bond between the colliding particles is also created, i.e., +the "bind_at_point_of_collision" mode implicitly includes the "bind_centers" mode. +You can either use a real bonded interaction to prevent wobbling around +the point of contact or you can use espressomd.interactions.Virtual which acts as a marker, only. +The method is setup as follows:

    +
    system.virtual_sites = espressomd.virtual_sites.VirtualSitesRelative()
    +system.collision_detection.set_params(
    +    mode="bind_at_point_of_collision",
    +    distance=0.1,
    +    bond_centers=harmonic_bond1,
    +    bond_vs=harmonic_bond2,
    +    part_type_vs=1,
    +    vs_placement=0)
    +
    +
    +

    The parameters distance and bond_centers have the same meaning +as in the "bind_centers" mode. The remaining parameters are as follows:

    +
      +
    • bond_vs is the bond to be added between the two virtual sites created on collision. +This is either a pair-bond with an equilibrium length matching the distance between +the virtual sites, or an angle bond fully stretched in its equilibrium configuration.

    • +
    • part_type_vs is the particle type assigned to the virtual sites created on collision. +In nearly all cases, no non-bonded interactions should be defined for this particle type.

    • +
    • vs_placement controls, where on the line connecting the centers of the colliding +particles, the virtual sites are placed. A value of 0 means that the virtual sites are +placed at the same position as the colliding particles on which they are based. +A value of 0.5 will result in the virtual sites being placed at the mid-point between +the two colliding particles. A value of 1 will result the virtual site associated +to the first colliding particle to be placed at the position of the second colliding +particle. In most cases, 0.5, is a good choice. Then, the bond connecting the virtual +sites should have an equilibrium length of zero.

    • +
    +
  • +
  • "glue_to_surface": This mode is used to irreversibly attach small particles +to the surface of a big particle. It is asymmetric in that several small particles +can be bound to a big particle but not vice versa. The small particles can change type +after collision to make them inert. On collision, a single virtual site is placed +and related to the big particle. Then, a bond (bond_centers) connects the big +and the small particle. A second bond (bond_vs) connects the virtual site and +the small particle. Further required parameters are:

    +
      +
    • part_type_to_attach_vs_to: Type of the particle to which the virtual site is attached, i.e., the big particle.

    • +
    • part_type_to_be_glued: Type of the particle bound to the virtual site (the small particle).

    • +
    • part_type_after_glueing: The type assigned to the particle bound to the virtual site (small particle) after the collision.

    • +
    • part_type_vs: Particle type assigned to the virtual site created during the collision.

    • +
    • distance_glued_particle_to_vs: Distance of the virtual site to the particle being bound to it (small particle).

    • +
    +

    Note: When the type of a particle is changed on collision, this makes the +particle inert with regards to further collision. Should a particle of +type part_type_to_be_glued collide with two particles in a single +time step, no guarantees are made with regards to which partner is selected. +In particular, there is no guarantee that the choice is unbiased.

    +

    The method is used as follows:

    +
    system.virtual_sites = espressomd.virtual_sites.VirtualSitesRelative()
    +system.collision_detection.set_params(
    +      mode="glue_to_surface",
    +      distance=0.1,
    +      distance_glued_particle_to_vs=0.02,
    +      bond_centers=harmonic_bond1,
    +      bond_vs=harmonic_bond2,
    +      part_type_vs=1,
    +      part_type_to_attach_vs_to=2,
    +      part_type_to_be_glued=3,
    +      part_type_after_glueing=4)
    +
    +
    +
  • +
  • "bind_three_particles" allows for the creation of agglomerates which maintain +their shape similarly to those create by the mode "bind_at_point_of_collision". +The present approach works without virtual sites. Instead, for each two-particle +collision, the surrounding is searched for a third particle. If one is found, +angular bonds are placed to maintain the local shape. +If all three particles are within the cutoff distance, an angle bond is added +on each of the three particles in addition +to the distance based bonds between the particle centers. +If two particles are within the cutoff of a central particle (e.g., chain of three particles) +an angle bond is placed on the central particle. +The angular bonds being added are determined from the angle between the particles. +This method does not depend on the particles’ rotational +degrees of freedom being integrated. Virtual sites are not required. +The method, along with the corresponding bonds are setup as follows:

    +
    n_angle_bonds = 181  # 0 to 180 degrees in one degree steps
    +for i in range(0, n_angle_bonds, 1):
    +    system.bonded_inter[i] = espressomd.interactions.AngleHarmonic(
    +        bend=1., phi0=float(i) / float(n_angle_bonds - 1) * np.pi)
    +
    +bond_centers = espressomd.interactions.HarmonicBond(k=1., r_0=0.1, r_cut=0.5)
    +system.bonded_inter.add(bond_centers)
    +
    +system.collision_detection.set_params(
    +    mode="bind_three_particles",
    +    bond_centers=bond_centers,
    +    bond_three_particles=0,
    +    three_particle_binding_angle_resolution=n_angle_bonds,
    +    distance=0.1)
    +
    +
    +

    Important: The bonds for the angles are mapped via their numerical bond ids. +In this example, ids from 0 to 180 are used. All other bonds required for +the simulation need to be added to the system after those bonds. In particular, +this applies to the bonded interaction passed via bond_centers

    +
  • +
+

The following limitations currently apply for the collision detection:

+
    +
  • No distinction is currently made between different particle types for the "bind_centers" method.

  • +
  • The "bind_at_point_of_collision" and "glue_to_surface" approaches require +the feature VIRTUAL_SITES_RELATIVE to be activated in myconfig.hpp.

  • +
  • The "bind_at_point_of_collision" approach cannot handle collisions +between virtual sites

  • +
+
+
+

18.2. Deleting bonds when particles are pulled apart

+

With this feature, bonds between particles can be deleted automatically +when the bond length exceeds a critical distance. This is used to model +breakable bonds.

+

The bond breakage action is specified for individual bonds via the system +bond_breakage attribute.

+

Several modes are available:

+
    +
  • "delete_bond": delete a bond from the first particle

  • +
  • "revert_bind_at_point_of_collision": delete a bond between the virtual site

  • +
  • "none": cancel an existing bond breakage specification

  • +
+

Example:

+
import espressomd
+import espressomd.interactions
+import espressomd.bond_breakage
+import numpy as np
+
+system = espressomd.System(box_l=[10] * 3)
+system.cell_system.skin = 0.4
+system.time_step = 0.1
+system.min_global_cut = 2.
+
+h1 = espressomd.interactions.HarmonicBond(k=0.01, r_0=0.4)
+h2 = espressomd.interactions.HarmonicBond(k=0.01, r_0=0.5)
+system.bonded_inter.add(h1)
+system.bonded_inter.add(h2)
+system.bond_breakage[h1] = espressomd.bond_breakage.BreakageSpec(
+    breakage_length=0.5, action_type="delete_bond")
+
+p1 = system.part.add(id=1, pos=[0.00, 0.0, 0.0], v=[0.0, 0.0, 0.0])
+p2 = system.part.add(id=2, pos=[0.46, 0.0, 0.0], v=[0.1, 0.0, 0.0])
+p1.add_bond((h1, p2))
+p1.add_bond((h2, p2))
+for i in range(3):
+    system.integrator.run(2)
+    bond_length = np.linalg.norm(system.distance_vec(p1, p2))
+    print(f"length = {bond_length:.2f}, bonds = {p1.bonds}")
+
+
+

Output:

+
length = 0.48, bonds = ((<HarmonicBond({'r_0': 0.4, 'k': 0.01})>, 2), (<HarmonicBond({'r_0': 0.5, 'k': 0.01})>, 2))
+length = 0.50, bonds = ((<HarmonicBond({'r_0': 0.4, 'k': 0.01})>, 2), (<HarmonicBond({'r_0': 0.5, 'k': 0.01})>, 2))
+length = 0.52, bonds = ((<HarmonicBond({'r_0': 0.5, 'k': 0.01})>, 2),)
+
+
+

Please note there is no special treatment for the energy released or consumed +by bond removal. This can lead to physical inconsistencies.

+
+
+

18.3. Modeling reversible bonds

+

The collision detection +and bond breakage +features can be combined to model reversible bonds.

+

Two combinations are possible:

+
    +
  • "delete_bond" mode for breakable bonds together with +"bind_centers" mode for collision detection: +used to create or delete a bond between two real particles

  • +
  • "revert_bind_at_point_of_collision" mode for breakable bonds together +with "bind_at_point_of_collision" mode for collision detection: +used to create or delete virtual sites (the implicitly created +bond between the real particles isn’t affected)

  • +
+

Please note that virtual sites are not automatically removed from the +simulation, therefore the particle number will increase. If you want to +remove virtual sites, you need to do so manually, either by tracking which +virtual sites were introduced by collision detection, or by periodically +looping over the particle list and removing virtual sites which have no +corresponding bond.

+
+
+

18.4. Immersed Boundary Method for soft elastic objects

+

Please contact the Biofluid Simulation and Modeling Group at the +University of Bayreuth if you plan to use this feature.

+

With the Immersed Boundary Method (IBM), soft particles are considered as an infinitely +thin shell filled with liquid (see e.g. [Crowl and Fogelson, 2010, Krüger, 2011, Peskin, 2002]). When the +shell is deformed by an external flow, it responds with elastic restoring +forces which are transmitted into the fluid. In the present case, the +inner and outer liquid are of the same type and are simulated using +lattice-Boltzmann.

+

Numerically, the shell is discretized by a set of marker points +connected by triangles. The marker points are advected with exactly +the local fluid velocity, i.e., they do not possess a mass nor a +friction coefficient (this is different from the Object-in-Fluid method +below). We implement these marker points as virtual tracer +particles which are not integrated using the usual velocity-Verlet +scheme, but instead are propagated using a simple Euler algorithm with +the local fluid velocity.

+

The immersed boundary method consists of two components, which can be used independently:

+ +

For a more detailed description, see e.g. [Guckenberger and Gekle, 2017] or contact us. +This feature probably does not work with advanced LB features such as electrokinetics.

+

A sample script is provided in the /samples/immersed_boundary/ directory.

+
+
+

18.5. Object-in-fluid

+

If you plan to use this feature, please contact the Cell-in-fluid Research Group at the +University of Zilina: ivan.cimrak@fri.uniza.sk or iveta.jancigova@fri.uniza.sk.

+

When using this module, please cite [Cimrák et al., 2014] (BibTeX key +cimrak14a in doc/bibliography.bib) and [Cimrák et al., 2012] +(BibTeX key cimrak12a in doc/bibliography.bib)

+

This documentation introduces the features of module Object-in-fluid (OIF). +Even though ESPResSo was not primarily intended to work with closed +objects, it is a flexible package and appears very suitable when one +wants to model closed objects with elastic properties, especially if +they are immersed in a moving fluid. Here we describe the module +itself and offer some additional information to get you started with. +Additionally, we provide a step by step tutorial that will show you how +to use this module.

+

The OIF module was developed for simulations of red blood cells +flowing through microfluidic devices and therefore the elasticity +features were designed with this application in mind. However, they +are completely tunable and can be modified easily to allow the user to +model any elastic object moving in fluid flow.

+

image1 image2 image3

+
+

18.5.1. Triangulations of elastic objects

+

To create an elastic object, we need a triangulation of the surface of +this object. Sample triangulations are provided at +http://cell-in-fluid.fri.uniza.sk/en/content/oif-espresso. +Users can create their own meshes, for example in gmsh, salome or any other +meshing software. Two files are needed, one for the node positions and one +for the connectivity of triangles:

+
    +
  • oif_nodes.dat should contain triplets of floats (one +triplet per line), where each triplet represents the \(x, y\) and +\(z\) coordinates of one node of the surface triangulation. No +additional information should be written in this file, so this means +that the number of lines is equals to the number of surface nodes. The +coordinates of the nodes should be specified in such a way that the +approximate center of mass of the object corresponds to the origin +(0,0,0). This is for convenience when placing the objects at desired +locations later.

  • +
  • oif_triangles.dat should contain triplets of numbers, +this time integers. These integers refer to the IDs of the nodes in +the oif_nodes.dat file and specify which three nodes form a +triangle. Please note that the nodes’ IDs start at 0, i.e. +the node written in the first line of oif_nodes.dat has ID 0, the +node in the second line, has ID 1, etc.

  • +
+
+_images/oif.png +
+
+
+

18.5.2. Description of sample script

+
+

Note

+

The following features are required: +LB_BOUNDARIES, +EXTERNAL_FORCES, +MASS, SOFT_SPHERE

+
+

The script described in this section is available in samples/object-in-fluid/motivation.py and also at +http://cell-in-fluid.fri.uniza.sk/en/content/oif-espresso.

+

In the first few lines, the script includes several imports related to +the red blood cell model, fluid, boundaries and interactions. Then we +have:

+
system = espressomd.System(box_l=(22, 14, 15))
+system.time_step = 0.1
+system.cell_system.skin = 0.2
+
+
+

Here we set up a system and its most important parameters. The skin +depth tunes the system’s performance. The one important thing a user needs to know +about it is that it has to be strictly less than half the grid size.

+

box_l sets up the dimensions of the 3D simulation box. You might +wonder what the units are. For now, you can think of them as +micrometers, we will return to them later.

+

time_step is the time step that will be used in the simulation, for +the purposes here, in microseconds. It allows separate specification of +time step for the particles and for the fluid. This is useful when one +takes into account also thermal fluctuations relevant on molecular +level, however, for us, both of these time steps will mostly be +identical.

+
+

18.5.2.1. Specification of immersed objects

+
cell_type = OifCellType(nodesfile="input/rbc374nodes.dat",
+    trianglesfile="input/rbc374triangles.dat", system=system,
+    ks=0.02, kb=0.016, kal=0.02, kag=0.9, kv=0.5, resize=[2.0, 2.0, 2.0])
+
+
+

We do not create elastic objects directly but rather each one has to +correspond to a template, cell_type, that has been created first. +The advantage of this approach is clear when creating many objects of +the same type that only differ by e.g. position or rotation, because in +such case it significantly speeds up the creation of objects that are +just copies of the same template.

+

The three mandatory arguments are nodes-file and triangles-file +that specify input data files with desired triangulation and system +that specifies the ESPResSo system. The relaxed mesh triangles should be +as close to equilateral as possible with average edge length +approximately equal to the space discretisation step \(\Delta x\). +While these lengths vary during the simulation, the connectivity of the +mesh nodes never changes. Basic meshes can be downloaded from our +website. This script assumes that the two necessary files are located +inside an input directory that resides in the same folder as the +simulation script.

+

All other arguments are optional. resize defines resizing in the +\(x, y, z\) directions with respect to unit size of the object, so +in this case, the cell radius will be 2. ks, kb, kal, +kag, kv specify the elastic properties: stretching, bending, +local area conservation, global area conservation and volume +conservation respectively. These properties are described in +Object-in-fluid interactions.

+
cell = OifCell(cellType=cell_type, partType=0, origin=[5.0, 5.0, 3.0])
+
+
+

Next, an actual object is created and its initial position is saved to a +.vtk file (the directory output/sim1 needs to exist before the +script is executed). Each object has to have a unique ID, specified using the +keyword partType. The IDs have to start at 0 and increase +consecutively. The other two mandatory arguments are cellType and +origin. cellType specifies which previously defined cell type +will be used for this object. origin gives placement of object’s +center in the simulation box.

+
+
+

18.5.2.2. Specification of fluid and movement

+
lbf = espressomd.lb.LBFluid(agrid=1, dens=1.0, visc=1.5, fric=1.5,
+                            tau=time_step, ext_force_density=[0.002, 0.0, 0.0])
+system.actors.add(lbf)
+
+
+

This part of the script specifies the fluid that will get the system +moving. Here agrid \(=\Delta x\) is the spatial discretisation +step, tau is the time step that will be the same as the time step +for particles, viscosity visc and density dens of the fluid are +physical parameters scaled to lattice units. fric is a +(non-physical) friction parameter that enters the fluid-object +interaction and has to be set carefully. Finally, ext_force_density sets the +force-per-unit-volume vector that drives the fluid. Another option to +add momentum to fluid is by specifying the velocity on the boundaries.

+

Here we achieved the movement of the fluid by applying external force. +Another alternative is to set up a wall/rhomboid with velocity. This +does not mean that the physical boundary is moving, but rather that it +transfers specified momentum onto the fluid.

+
+
+

18.5.2.3. Specification of boundaries

+

To set up the geometry of the channels, we mostly use rhomboids and +cylinders, but there are also other shape types available in ESPResSo. +Their usage is described elsewhere.

+

image4 image5 image6

+

Each wall and obstacle has to be specified separately as a fluid +boundary and as a particle constraint. The former enters the simulation +as a boundary condition for the fluid, the latter serves for +particle-boundary interactions. Sample cylinder and rhomboid can then be +defined as follows. First we define the two shapes:

+
boundary1 = shapes.Rhomboid(corner=[0.0, 0.0, 0.0],
+                            a=[boxX, 0.0, 0.0],
+                            b=[0.0, boxY, 0.0],
+                            c=[0.0, 0.0, 1.0],
+                            direction=1)
+boundary2 = shapes.Cylinder(center=[11.0, 2.0, 7.0],
+                            axis=[0.0, 0.0, 1.0],
+                            length=7.0,
+                            radius=2.0,
+                            direction=1)
+
+
+

The direction=1 determines that the fluid is on the outside. Next +we create boundaries for the fluid:

+
system.lbboundaries.add(lbboundaries.LBBoundary(shape=boundary1))
+system.lbboundaries.add(lbboundaries.LBBoundary(shape=boundary2))
+
+
+

Followed by creating the constraints for cells:

+
system.constraints.add(shape=boundary1, particle_type=10)
+system.constraints.add(shape=boundary2, particle_type=10)
+
+
+

The particle_type=10 will be important for specifying cell-wall +interactions later. And finally, we output the boundaries for +visualisation:

+
output_vtk_rhomboid(corner=[0.0, 0.0, 0.0],
+                    a=[boxX, 0.0, 0.0],
+                    b=[0.0, boxY, 0.0],
+                    c=[0.0, 0.0, 1.0],
+                    out_file="output/sim1/wallBack.vtk")
+output_vtk_cylinder(center=[11.0, 2.0, 7.0],
+                    axis=[0.0, 0.0, 1.0],
+                    length=7.0,
+                    radius=2.0,
+                    n=20,
+                    out_file="output/sim1/obstacle.vtk")
+
+
+

Note that the method for cylinder output also has an argument n. +This specifies number of rectangular faces on the side.

+

It is a good idea to output and visualize the boundaries and objects +just prior to running the actual simulation, to make sure that the +geometry is correct and no objects intersect with any boundaries.

+
+
+

18.5.2.4. Specification of interactions

+

We can define an interaction with the boundaries:

+
system.non_bonded_inter[0, 10].soft_sphere.set_params(
+    soft_a=0.0001, soft_n=1.2, soft_cut=0.1, soft_offset=0.0)
+
+
+

These interactions are also pointwise, e.g. each particle of type 0 +(that means all mesh points of cell) will have a repulsive soft-sphere +interaction with all boundaries of type 10 (here all boundaries) once it +gets closer than soft_cut. The parameters soft_a and soft_n +adjust how strong the interaction is and soft_offset is a distance +offset, which will always be zero for our purposes.

+
+
+

18.5.2.5. System integration

+

And finally, the heart of this script is the integration loop at the +end:

+
for i in range(1, 101):
+    system.integrator.run(steps=500)
+    cell.output_vtk_pos_folded(filename=f"output/sim1/cell_{i}.vtk")
+    print(f"time: {i * time_step}")
+print("Simulation completed.")
+
+
+

This simulation runs for 100 cycles. In each cycle, 500 integration +steps are performed and output is saved into files +output/sim1/cell_*.vtk. Note that they differ only by the number +before the .vtk extension (this variable changes due to the for +loop) and this will allow us to animate them in the visualisation +software. str changes the type of i from integer to string, so +that it can be used in the filename. The strings can be joined together +by the + sign. Also, in each pass of the loop, the simulation time is +printed in the terminal window and when the integration is complete, we +should get a message about it.

+

To sum up, the proper order of setting up individual simulation +parts is as follows:

+
    +
  • cell types

  • +
  • cells

  • +
  • fluid

  • +
  • fluid boundaries

  • +
  • interactions

  • +
+

If cell types and cells are specified after the fluid, the simulation +is slower. Also, interactions can only be defined once the objects +and boundaries both exist. Technically, the fluid boundaries can be +specified before fluid, but it is really not recommended.

+
+
+

18.5.2.6. Running the simulation

+

The script can be executed in the terminal with

+
../pypresso script.py
+
+
+

Here script.py is the name of the script we just went over and +../pypresso should be replaced with the path to your executable. +This command assumes that we are currently in the same directory as the +script. Once the command is executed, messages should appear on the +terminal about the creation of cell type, cell and the integration +steps.

+
+
+

18.5.2.7. Writing out data

+

In the script, we have used the commands such as

+
cell.output_vtk_pos_folded(filename=f"output/sim1/cell_{i}.vtk")
+
+
+

to output the information about cell in every pass of the simulation +loop. These files can then be used for inspection in ParaView and +creation of animations. It is also possible to save a .vtk file for the +fluid. And obviously, one can save various types of other data into text +or data files for further processing and analysis.

+
+
+
+

18.5.3. Visualization in ParaView

+

For visualization we suggest the free software ParaView 5. All .vtk +files (boundaries, fluid, objects at all time steps) can be loaded at +the same time. The loading is a two step process, because only after +pressing the Apply button, are the files actually imported. Using the +eye icon to the left of file names, one can turn on and off the +individual objects and/or boundaries.

+

Fluid can be visualized using Filters/Alphabetical/Glyph (or other +options from this menu. Please, refer to the ParaView user’s guide for +more details).

+

Note, that ParaView does not automatically reload the data if they +have been changed in the input folder, but a useful thing to know is +that the created filters can be “recycled”. Once you delete the old +data, load the new data and right-click on the existing filters, you +can re-attach them to the new data.

+

It is a good idea to output and visualize the boundaries and objects +just prior to running the actual simulation, to make sure that the +geometry is correct and no objects intersect with any boundaries. This +would cause “particle out of range” error and crash the simulation.

+
+

18.5.3.1. File format

+

ParaView (download at https://www.paraview.org) accepts .vtk files. For +our cells we use the following format:

+
# vtk DataFile Version 3.0
+Data
+ASCII
+DATASET POLYDATA
+POINTS 393 float
+p0x p0y p0z
+p1x p1y p1z
+...
+p391x p391y p391z
+p392x p392y p392z
+TRIANGLE_STRIPS num_triang 4*num_triang
+3 p1 p2 p3
+3 p1 p3 p5
+...
+3 p390 p391 p392
+
+
+

where the cell has 393 surface nodes (particles). After initial +specification, the list of points is present, with x, y, z coordinates for +each. Then we write the triangulation, since that is how our +surface is specified. We need to know the number of triangles +(num_triang) and the each line/triangle is specified by 4 numbers +(so we are telling ParaView to expect 4 * num_triang  numbers in +the following lines. Each line begins with 3 (which stands for a +triangle) and three point IDs that tell us which three points (from +the order above) form this specific triangle.

+
+
+

18.5.3.2. Color coding of scalar data by surface points

+

It is possible to save (and visualize) data corresponding to individual +surface points. These data can be scalar or vector values associated +with all surface points. At the end of the .vtk file above, add the +following lines:

+
POINT_DATA 393
+SCALARS sample_scalars float 1
+LOOKUP_TABLE default
+value-at-p0
+value-at-p1
+...
+value-at-p392
+
+
+

This says that data for each of 393 points are coming. Next line says +that the data are scalar in this case, one float for each point. To +color code the values in the visualization, a default (red-to-blue) +table will be used. It is also possible to specify your own lookup +table. As an example, we might want to see a force magnitude in each +surface node

+
+_images/oifstretched-sphere.png +
+

Stretched sphere after some relaxation, showing magnitude +of total stretching force in each node.

+
+
+
+
+

18.5.3.3. Color coding of scalar data by triangles

+

It is also possible to save (and visualize) data corresponding to +individual triangles

+
+_images/oifcolored-triangles.png +
+

Red blood cell showing which triangles (local surface areas) are under +most strain in shear flow.

+
+
+

In such case, the keyword POINT_DATA is changed to CELL_DATA and the number of +triangles is given instead of number of mesh points.

+
# vtk DataFile Version 3.0
+Data
+ASCII
+DATASET POLYDATA
+POINTS 4 float
+1 1 1
+3 1 1
+1 3 1
+1 1 3
+TRIANGLE_STRIPS 3 12
+3 0 1 2
+3 0 2 3
+3 0 1 3
+CELL_DATA 3
+SCALARS sample_scalars float 1
+LOOKUP_TABLE default
+0.0
+0.5
+1.0
+
+
+

Note - it is also possible to save (and visualize) data corresponding to edges.

+
+
+

18.5.3.4. Multiple scalar data in one .vtk file

+

If one wants to switch between several types of scalar values +corresponding to mesh nodes, these are specifies consecutively in the +.vtk file, as follows. Their names (scalars1 and scalars2 in the +following example) appear in a drop-down menu in ParaView.

+
POINT_DATA 393
+SCALARS scalars1 float 1
+LOOKUP_TABLE default
+value1-at-p0
+value1-at-p1
+...
+value1-at-p392
+SCALARS scalars2 float 1
+LOOKUP_TABLE default
+value2-at-p0
+value2-at-p1
+...
+value2-at-p392
+
+
+
+
+

18.5.3.5. Vector data for objects .vtk file

+
+
If we want to observe some vector data (e.g. outward normal, +fig. [fig:vectordata]) at points of the saved objects, we can use the +following structure of the .vtk file, where the vector at one point is +[v1, v2, v3]:
+
+
POINT_DATA 393
+VECTORS vector_field float
+v1-at-p0 v2-at-p0 v3-at-p0
+v1-at-p1 v2-at-p1 v3-at-p1
+...
+v1-at-p391 v2-at-p391 v3-at-p392
+
+
+
+_images/oifvectordata.png +
+

Example of vector data stored in points of the object

+
+
+
+
More info on .vtk files and possible options:
+ +
+
+
+

18.5.3.6. Automatic loading

+
+
Sometimes it is frustrating to reload data in ParaView: manually open +all the files, click all the properties etc. This however, can be done +automatically.
+
Scenario:
+
Load file data.vtk with the fluid velocity field.
+
Add filter called slice to visualize the flow field on the +cross-section.
+
To do it automatically, ParaView has a feature for tracking steps. To +record the steps that create the scenario above, first choose +Tools/Start Trace. From that moment, all the steps done in ParaView +will be recorded. Then you Tools/Stop Trace. Afterwards, a window +appears with a python code with recorded steps. It needs to be saved +as, e.g. loading-script.py.
+
Next time you open ParaView with command +paraview --script=loading-script.py and all the steps for creating +that scenario will be executed and you end up with the velocity field +visualized.
+
+
+
+
+

18.5.4. Available Object-in-fluid (OIF) classes

+
+
Here we describe the currently available OIF classes and commands. +Note that there are more still being added. We would be pleased to +hear from you about any suggestions on further functionality.
+
+
+
Notation: keywords, parameter values, vectors
+
The keywords do not have to be in a specific order.
+
+
+

18.5.4.1. class OifCellType

+

For those familiar with earlier version of object-in-fluid framework, +this class corresponds to the oif_emplate in tcl. It contains a “recipe” +for creating cells of the same type. These cells can then be placed at +different locations with different orientation, but their elasticity and +size is determined by the CellType. There are no actual particles +created at this stage. Also, while the interactions are defined, no +bonds are created here.

+
OifCellType.print_info()
+OifCellType.mesh.output_mesh_triangles(filename)
+
+
+
+
nodesfile=nodes.dat - input file. Each line contains three +real numbers. These are the x, y, z coordinates of individual +surface mesh nodes of the objects centered at [0,0,0] and normalized +so that the “radius” of the object is 1.
+
+
+
trianglesfile=triangles.dat - input file. Each line contains +three integers. These are the ID numbers of the mesh nodes as they +appear in nodes.dat. Note that the first node has ID 0.
+
+
+
system=system Particles of cells created using this +template will be added to this system. Note that there can be only one +system per simulation.
+
+
+
ks=value - elastic modulus for stretching forces.
+
+
+
kslin= value - elastic modulus for linear stretching forces.
+
+
+
kb= value - elastic modulus for bending forces.
+
+
+
kal= value - elastic modulus for local area forces.
+
+
+
The switches ks, kb and kal set elastic parameters for +local interactions: ks for edge stiffness, kb for angle +preservation stiffness and kal for triangle area preservation +stiffness. Currently, the stiffness is implemented to be uniform over +the whole object, but with some tweaking, it is possible to have +non-uniform local interactions.
+
+
+
Note, the difference between stretching (ks) and linear stretching +(kslin) - these two options cannot be used simultaneously:
+
+
+
Linear stretching behaves like linear spring, where the stretching +force is calculated as \(\mathbf{F}_s=k_s*\Delta L\), where +\(\Delta L\) is the prolongation of the given edge. By default, +the stretching is non-linear (neo-Hookian).
+
+
+
kvisc=value - elastic modulus for viscosity of the membrane. +Viscosity slows down the reaction of the membrane.
+
+
+
kag=value - elastic modulus for global area forces
+
+
+
kv=value - elastic modulus for volume forces
+
+
+
Note: At least one of the elastic moduli should be set.
+
+
+
resize=(x, y, z) - coefficients, by which the coordinates +stored in nodesfile will be stretched in the x, y, z +direction. The default value is (1.0, 1.0, 1.0).
+
+
+
mirror=(x, y, z) - whether the respective coordinates should +be flipped around 0. Arguments x, y, z must be either 0 or 1. +The reflection of only one coordinate is allowed so at most one +argument is set to 1, others are 0. For example mirror=(0, 1, 0) +results in flipping the coordinates (x, y, z) to (x, -y, z). The +default value is (0, 0, 0).
+
+
+
normal - by default set to False, however without this +option enabled, the membrane collision (and thus cell-cell +interactions) will not work.
+
+
+
check_orientation - by default set to True. This options +performs a check, whether the supplied trianglesfile contains +triangles with correct orientation. If not, it corrects the +orientation and created cells with corrected triangles. It is useful +for new or unknown meshes, but not necessary for meshes that have +already been tried out. Since it can take a few minutes for larger +meshes (with thousands of nodes), it can be set to False. In +that case, the check is skipped when creating the CellType and a +warning is displayed.
+
+
+
The order of indices in triangles.dat is important. Normally, each +triangle ABC should be oriented in such a way, that the normal vector +computed as vector product ABxAC must point inside the object. For +example, a sphere (or any other sufficiently convex object) contains +such triangles that the normals of these triangles point towards the +center of the sphere (almost).
+
+
+
The check runs over all triangles, makes sure that they have the +correct orientation and then calculates the volume of the object. If +the result is negative, it flips the orientation of all triangles.
+
+
+
Note, this method tells the user about the correction it makes. If +there is any, it might be useful to save the corrected triangulation +for future simulations using the method +CellType.mesh.OutputMeshTriangles(filename), so that the +check does not have to be used repeatedly.
+
+
+
CellType.mesh.output_mesh_triangles(filename) - this is +useful after checking orientation, if any of the triangles where +corrected. This method saves the current triangles into a file that +can be used as input in the next simulations.
+
+
+
CellType.print_info() - prints the information about the template.
+
+
+
+

18.5.4.2. class OifCell

+
OifCell.set_origin([x, y, z])
+OifCell.get_origin()
+OifCell.get_origin_folded()
+OifCell.get_approx_origin()
+OifCell.get_velocity()
+OifCell.set_velocity([x, y, z])
+OifCell.pos_bounds()
+OifCell.surface()
+OifCell.volume()
+OifCell.diameter()
+OifCell.get_n_nodes()
+OifCell.set_force([x, y, z])
+OifCell.kill_motion()
+OifCell.unkill_motion()
+OifCell.output_vtk_pos(filename.vtk)
+OifCell.output_vtk_pos_folded(filename.vtk)
+OifCell.append_point_data_to_vtk(filename.vtk, dataname, data, firstAppend)
+OifCell.output_raw_data(filename, rawdata)
+OifCell.output_mesh_points(filename)
+OifCell.set_mesh_points(filename)
+OifCell.elastic_forces(elasticforces, fmetric, vtkfile, rawdatafile)
+OifCell.print_info()
+
+
+
+
cell_type - object will be created using nodes, triangle +incidences, elasticity parameters and initial stretching saved in this +cellType.
+
+
+
part_type=type - must start at 0 for the first cell and +increase consecutively for different cells. Volume calculation of +individual objects and interactions between objects are set up using +these types.
+
+
+
origin=(x, y, z) - center of the object will be at this +point.
+
+
+
rotate=(x, y, z) - angles in radians, by which the object +will be rotated about the x, y, z axis. Default value is (0.0, +0.0, 0.0). Value (\(\pi/2, 0.0, 0.0\)) means that the object will +be rotated by \(\pi/2\) radians clockwise around the x +axis when looking in the positive direction of the axis.
+
+
+
mass=m - mass of one particle. Default value is 1.0.
+
+
+
OifCell.set_origin(o) - moves the object such that the origin +has coordinates o=(x, y, z).
+
+
+
OifCell.get_origin() - outputs the location of the center of the +object.
+
+
+
OifCell.get_origin_folded() - outputs the location of the center of +the object. For periodical movements the coordinates are folded +(always within the computational box).
+
+
+
OifCell.get_approx_origin() - outputs the approximate location of +the center of the object. It is computed as average of 6 mesh points +that have extremal x, y and z coordinates at the time +of object loading.
+
+
+
OifCell.get_velocity() - outputs the average velocity of the +object. Runs over all mesh points and outputs their average velocity.
+
+
+
OifCell.set_velocity(v) - sets the velocities of all mesh +points to v=(\(v_x\), \(v_y\), \(v_z\)).
+
+
+
OifCell.pos_bounds() - computes six extremal coordinates of the +object. More precisely, runs through the all mesh points and returns +the minimal and maximal \(x\)-coordinate, \(y\)-coordinate and +\(z\)-coordinate in the order (\(x_{max}\), \(x_{min}\), +\(y_{max}\), \(y_{min}\), \(z_{max}\), \(z_{min}\)).
+
+
+
OifCell.surface() - outputs the surface of the object.
+
+
+
OifCell.volume() - outputs the volume of the object.
+
+
+
OifCell.diameter() - outputs the largest diameter of the object.
+
+
+
OifCell.get_n_nodes() - returns the number of mesh nodes.
+
+
+
OifCell.set_force(f) - sets the external force vector +f=(\(f_x\), \(f_y\), \(f_z\)) to all mesh nodes of +the object. Setting is done using command p.set_force(f). +Note, that this command sets the external force in each integration +step. So if you want to use the external force only in one iteration, +you need to set zero external force in the following integration step.
+
+
+
OifCell.kill_motion() - stops all the particles in the object +(analogue to the command p.kill_motion()).
+
+
+
OifCell.unkill_motion() - enables the movement of all the particles +in the object (analogue to the command p.unkill_motion()).
+
+
+
OifCell.output_vtk_pos(filename.vtk) - outputs the mesh of the +object to the desired filename.vtk. ParaView can directly visualize +this file.
+
+
+
OifCell.output_vtk_pos_folded(filename.vtk) - outputs the mesh of +the object to the desired filename.vtk. ParaView can directly +visualize this file. For periodical movements the coordinates are +folded (always within the computational box).
+
+
+
OifCell.append_point_data_to_vtk(filename.vtk, dataname, +data, firstAppend) - outputs the specified scalar data to an +existing filename.vtk. This is useful for ParaView +visualisation of local velocity magnitudes, magnitudes of forces, etc. +in the meshnodes and can be shown in ParaView by selecting the +dataname in the Properties toolbar. It is possible to +consecutively write multiple datasets into one filename.vtk. +For the first one, the firstAppend parameter is set to +True, for the following datasets, it needs to be set to +False. This is to ensure the proper structure of the output +file.
+
+
+
OifCell.output_raw_data(filename, rawdata) - outputs the +vector rawdata about the object into the filename.
+
+
+
OifCell.output_mesh_points(filename) - outputs the positions of +the mesh nodes to filename. In fact, this command creates a new +nodes.dat file that can be used by the method +OifCell.set_mesh_points(nodes.dat). The center of the object is +located at point (0.0, 0.0, 0.0). This command is aimed to store the +deformed shape in order to be loaded later.
+
+
+
OifCell.set_mesh_points(filename) - deforms the object in such a +way that its origin stays unchanged, however the relative positions of +the mesh points are taken from file filename. The filename should +contain the coordinates of the mesh points with the origin location at +(0.0, 0.0, 0.0). The procedure also checks whether number of lines in +the filename is the same as the corresponding value from +OifCell.get_n_nodes().
+
+
+
OifCell.elastic_forces(elasticforces, fmetric, vtkfile, +rawdatafile) - this method can be used in two different ways. One is +to compute the elastic forces locally for each mesh node and the other +is to compute the f-metric, which is an approximation of elastic +energy.
+
+
+
To compute the elastic forces, use the vector +elasticforces. It is a sextuple of zeros and ones, +e.g. elasticforces = (1,0,0,1,0,0), where the ones +denote the elastic forces to be computed. The order is (stretching, +bending, local area, global area, volume, total). The output can be +saved in two different ways: either by setting +vtkfile = filename.vtk, which saves a .vtk file that can be +visualized using ParaView. If more than one elastic force was +selected, they can be chosen in the Properties window in ParaView. The +other type of output is rawdatafile=filename.dat, which will +save a datafile with the selected type of elastic force - one force +per row, where each row corresponds to a single mesh node. Note that +only one type of elastic force can be written this way at a time. +Thus, if you need output for several elastic forces, this method +should be called several times.
+
+
+
To compute the f-metric, use the vector fmetric. It +is again a sextuple of zeros and ones, e.g. +fmetric = (1,1,0,0,0,0), where the ones denote the +elastic forces to be computed. The order is (stretching, bending, +local area, global area, volume, total). The output is again a vector +with six elements, each corresponding to the requested f-metric/“naive +energy” computed as a sum of magnitudes of respective elastic forces +over all nodes of the object.
+
+
+
OifCell.print_info() - prints the information about the elastic +object.
+
+
+
+

18.5.4.3. Short utility procedures

+
+
get_n_triangle(a, b, c) - returns the normal n +to the triangle given by points (a, b, c).
+
+
+
norm(v) - returns the norm of the vector v.
+
+
+
distance(a, b) - returns the distance between +points a and b.
+
+
+
area_triangle(a, b, c) - returns the area of the +given triangle (a, b, c).
+
+
+
angle_btw_triangles(\(\mathbf{p}_1\), \(\mathbf{p}_2\), +\(\mathbf{p}_3\), \(\mathbf{p}_4\) - returns the angle +\(\phi\) between two triangles: (\(\mathbf{p}_1\), +\(\mathbf{p}_2\), \(\mathbf{p}_3\)) and (\(\mathbf{p}_3\), +\(\mathbf{p}_2\), \(\mathbf{p}_4\)) that have a common edge +(\(\mathbf{p}_2\), \(\mathbf{p}_3\)).
+
+
+
discard_epsilon(x) - needed for rotation; discards very +small numbers x.
+
+
+
oif_neo_hookean_nonlin(\(\lambda\)) - nonlinearity for neo-Hookean stretching
+
+
+
calc_stretching_force(\(k_s,\ \mathbf{p}_A,\ \mathbf{p}_B\), dist0, dist) +- computes the nonlinear stretching force with given \(k_s\) for +points \(\mathbf{p}_A\) and \(\mathbf{p}_B\) given by their +coordinates, whose initial distance was dist0 and current distance +is dist.
+
+
+
calc_linear_stretching_force(\(k_s,\ \mathbf{p}_A,\ \mathbf{p}_B\), dist0, dist) +- computes the linear stretching force with given \(k_s\) for +points \(\mathbf{p}_A\) and \(\mathbf{p}_B\) given by their +coordinates, whose initial distance was dist0 and current distance +is dist.
+
+
+
calc_bending_force(\(k_b,\ \mathbf{p}_A,\ \mathbf{p}_B,\ \mathbf{p}_C,\ \mathbf{p}_D,\ \phi_0,\ \phi\)) +- computes the bending force with given \(k_b\) for points +\(\mathbf{p}_A\), \(\mathbf{p}_B\), \(\mathbf{p}_C\) and +\(\mathbf{p}_D\) (\(\triangle_1\)=BAC; +\(\triangle_2\)=BCD) given by their coordinates; the initial +angle for these two triangles was \(\phi_0\), the current angle is +\(\phi\).
+
+
+
calc_local_area_force(\(k_{al},\ \mathbf{p}_A,\ \mathbf{p}_B,\ \mathbf{p}_C,\ A_0,\ A\)) +- computes the local area force with given \(k_{al}\) for points +\(\mathbf{p}_A\), \(\mathbf{p}_B\) and \(\mathbf{p}_C\) +given by their coordinates; the initial area of triangle ABC was +\(A_0\), the current area is \(A\).
+
+
+
calc_global_area_force(\(k_{ag},\ \mathbf{p}_A,\ \mathbf{p}_B,\ \mathbf{p}_C,\ A_{g0},\ A_g\)) +- computes the global area force with given \(k_{ag}\) for points +\(\mathbf{p}_A\), \(\mathbf{p}_B\) and \(\mathbf{p}_C\) +given by their coordinates; the initial surface area of the object was +\(A_{g0}\), the current surface area of the object is \(A_g\).
+
+
+
calc_volume_force(\(k_v,\ \mathbf{p}_A,\ \mathbf{p}_B,\ \mathbf{p}_C,\ V_0,\ V\)) +- computes the volume force with given \(k_v\) for points +\(\mathbf{p}_A\), \(\mathbf{p}_B\) and \(\mathbf{p}_C\) +given by their coordinates; the initial volume of the object was +\(V_0\), the current volume of the object is \(V\).
+
+
+
output_vtk_rhomboid(corner, a, b, c, outFile.vtk) +- outputs rhomboid boundary for later visualisation in ParaView.
+
+
+
output_vtk_cylinder(center, normal, L, r, n, outFile.vtk) +- outputs cylinder boundary for later visualisation in ParaView.
+
+
+
output_vtk_lines(lines, outFile.vtk) - outputs a set of +line segments for later visualisation in ParaView.
+
+
+
+

18.5.4.4. Description of helper classes

+

Awareness of these classes is not necessary for a user of OIF module, +but is essential for developers who wish to modify it because it shows +how the object data are stored.

+

classes FixedPoint and PartPoint

+

Class PartPoint represents a particle. These particles are then used as +building blocks for edges, angles, triangles and ultimately the whole +object mesh. Since we use a two-step process to create the objects, it +is necessary to distinguish between a FixedPoint and PartPoint. +FixedPoint is a point used by template and does not correspond to +particle. The FixedPoints of one OifCellType form a mesh that is +centered around origin. Only after it is stretched and shifted to the +object origin are the PartPoints of the given object created.

+

classes Edge, Angle, Triangle, ThreeNeighbors

+

These classes represent the building blocks of a mesh. They are used to +compute the elastic interactions: Edge is for stretching, Angle for +bending, Triangle for local and global area and volume and ThreeNeigbors +for calculation of outward normal vector needed for cell-cell +interaction.

+

class Mesh

+

This class holds all the information about the geometry of the object, +including nodes, edges, angles, triangles and neighboring points. The +mesh of OifCellType is copied every time a new object (i.e. OifCell) of +this type is created. This saves computational time, since the data for +elastic interactions of the given object do not need to be recalculated +every time.

+
+
5
+

https://www.paraview.org/

+
+
+
+
+
+
+

18.6. Particle polarizability with thermalized cold Drude oscillators

+
+

Note

+

Requires features THOLE, P3M, THERMOSTAT_PER_PARTICLE.

+
+
+

Note

+

Drude is only available for the P3M electrostatics solver and the Langevin thermostat.

+
+

Thermalized cold Drude oscillators can be used to simulate +polarizable particles. The basic idea is to add a ‘charge-on-a-spring’ (Drude +charge) to a particle (Drude core) that mimics an electron cloud which can be +elongated to create a dynamically inducible dipole. The energetic minimum of +the Drude charge can be obtained self-consistently, which requires several +iterations of the system’s electrostatics and is usually considered +computationally expensive. However, with thermalized cold Drude oscillators, the +distance between Drude charge and core is coupled to a thermostat so that it +fluctuates around the SCF solution. This thermostat is kept at a low +temperature compared to the global temperature to minimize the heat flow into +the system. A second thermostat is applied on the centre of mass of the Drude +charge + core system to maintain the global temperature. The downside of this +approach is that usually a smaller time step has to be used to resolve the high +frequency oscillations of the spring to get a stable system.

+

In ESPResSo, the basic ingredients to simulate such a system are split into three bonds:

+
    +
  1. A Harmonic bond to account for the spring.

  2. +
  3. A Thermalized distance bond with a cold thermostat on the Drude-Core distance.

  4. +
  5. A Subtract P3M short-range bond to cancel the electrostatic interaction between Drude and core particles.

  6. +
+

The system-wide thermostat has to be applied to the centre of mass and not to +the core particle directly. Therefore, the particles have to be excluded from +global thermostatting. With THERMOSTAT_PER_PARTICLE enabled, we set the +friction coefficient of the Drude complex to zero, which allows +to still use a global Langevin thermostat for non-polarizable particles.

+

As the Drude charge should not alter the charge or mass of the Drude +complex, both properties have to be subtracted from the core when adding the +Drude particle. In the following convention, we assume that the Drude charge is +always negative. It is calculated via the spring constant \(k\) and +polarizability \(\alpha\) (in units of inverse volume) with \(q_d = +-\sqrt{k \cdot \alpha}\).

+

The following helper method takes into account all the preceding considerations +and can be used to conveniently add a Drude particle to a given core particle. +It returns an espressomd.particle_data.ParticleHandle to the created Drude +particle. Note that as the function also adds the first two bonds between Drude +and core, these bonds have to be already available.:

+
import espressomd.drude_helpers
+dh = espressomd.drude_helpers.DrudeHelpers()
+drude_part = dh.add_drude_particle_to_core(<system>, <harmonic_bond>,
+    <thermalized_bond>, <core particle>, <type drude>, <alpha>,
+    <mass drude>, <coulomb_prefactor>, <thole damping>, <verbose>)
+
+
+
+
The arguments of the helper function are:
    +
  • <system>: The espressomd.System().

  • +
  • <harmonic_bond>: The harmonic bond of the charge-on-a-spring. This is +added between core and newly generated Drude particle

  • +
  • <thermalized_bond>: The thermalized distance bond for the cold and hot +thermostats.

  • +
  • <core particle>: The core particle on which the Drude particle is added.

  • +
  • <type drude>: The user-defined type of the Drude particle. +Each Drude particle of each complex should have an +individual type (e.g. in an ionic system with Anions (type 0) and Cations +(type 1), two new, individual Drude types have to be assigned).

  • +
  • <alpha>: The polarizability volume.

  • +
  • <coulomb_prefactor>: The Coulomb prefactor of the system. Used to +calculate the Drude charge from the polarizability and the spring constant +of the Drude bond.

  • +
  • <thole damping>: (optional) An individual Thole damping parameter for the +core-Drude pair. Only relevant if Thole damping is used (defaults to 2.6).

  • +
  • <verbose>: (bool, optional) Prints out information about the added Drude +particles (default: False)

  • +
+
+
+

What is still missing is the short-range exclusion bond between all Drude-core pairs. +One bond type of this kind is needed per Drude type. The above helper function also +tracks particle types, ids and charges of Drude and core particles, so a simple call of +another helper function:

+
dh.setup_and_add_drude_exclusion_bonds(system)
+
+
+

will use this data to create a Subtract P3M short-range bond per Drude type +and set it up it between all Drude and core particles collected in calls of +add_drude_particle_to_core().

+
+

18.6.1. Canceling intramolecular electrostatics

+

Note that for polarizable molecules (i.e. connected particles, coarse grained +models etc.) with partial charges on the molecule sites, the Drude charges will +have electrostatic interaction with other cores of the molecule. Often, this +is unwanted, as it might be already part of the force-field (via. partial +charges or parametrization of the covalent bonds). Without any further +measures, the elongation of the Drude particles will be greatly affected be the +close-by partial charges of the molecule. To prevent this, one has to cancel +the interaction of the Drude charge with the partial charges of the cores +within the molecule. This can be done with special bonds that subtracts the P3M +short-range interaction of the charge portion \(q_d q_{partial}\). This ensures +that only the dipolar interaction inside the molecule remains. It should be +considered that the error of this approximation increases with the share of the +long-range part of the electrostatic interaction. Two helper methods assist +with setting up this exclusion. If used, they have to be called +after all Drude particles are added to the system:

+
espressomd.drude_helpers.setup_intramol_exclusion_bonds(<system>, <molecule drude types>,
+    <molecule core types>, <molecule core partial charges>, <verbose>)
+
+
+

This function creates the required number of bonds which are later added to the +particles. It has to be called only once. In a molecule with \(N\) polarizable +sites, \(N \cdot (N-1)\) bond types are needed to cover all the combinations. +Parameters are:

+
    +
  • <system>: The espressomd.System().

  • +
  • <molecule drude types>: List of the Drude types within the molecule.

  • +
  • <molecule core types>: List of the core types within the molecule that have partial charges.

  • +
  • <molecule core partial charges>: List of the partial charges on the cores.

  • +
  • <verbose>: (bool, optional) Prints out information about the created bonds (default: False)

  • +
+

After setting up the bonds, one has to add them to each molecule with the +following method:

+
espressomd.drude_helpers.add_intramol_exclusion_bonds(<system>, <drude ids>, <core ids>, <verbose>)
+
+
+

This method has to be called for all molecules and needs the following parameters:

+
    +
  • <system>: The espressomd.System().

  • +
  • <drude ids>: The ids of the Drude particles within one molecule.

  • +
  • <core ids>: The ids of the core particles within one molecule.

  • +
  • <verbose>: (bool, optional) Prints out information about the added bonds (default: False)

  • +
+

Internally, this is done with the bond described in Subtract P3M short-range bond, that +simply adds the p3m shortrange pair-force of scale \(- q_{\textrm{d}} q_{\textrm{partial}}\) the to +bonded particles.

+
+

See also

+

Often used in conjunction with Drude oscillators is the Thole correction +to damp dipole-dipole interactions on short distances. It is available in ESPResSo +as a non-bonded interaction.

+
+
+
+
+ + +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/doc4.2.2/analysis.html b/doc4.2.2/analysis.html new file mode 100644 index 0000000000..dbd23a8d25 --- /dev/null +++ b/doc4.2.2/analysis.html @@ -0,0 +1,755 @@ + + + + + + + + + 15. Analysis — ESPResSo 4.2.2 documentation + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +
+

15. Analysis

+

ESPResSo provides two concepts of system analysis:

+ +
+

15.1. Direct analysis routines

+

The direct analysis commands only take into account the current configuration of the system. +Available commands are:

+ +
+

15.1.1. Energies

+

espressomd.analyze.Analysis.energy()

+

Returns the energies of the system. +The different energetic contributions to the total energy can also be obtained (kinetic, bonded, non-bonded, Coulomb).

+

For example,

+
>>> energy = system.analysis.energy()
+>>> print(energy["total"])
+>>> print(energy["kinetic"])
+>>> print(energy["bonded"])
+>>> print(energy["non_bonded"])
+
+
+
+
+

15.1.2. Momentum of the System

+

espressomd.analyze.Analysis.linear_momentum()

+

This command returns the total linear momentum of the particles and the +lattice-Boltzmann (LB) fluid, if one exists. Giving the optional +parameters either causes the command to ignore the contribution of LB or +of the particles.

+
+
+

15.1.3. Minimal distances between particles

+

espressomd.analyze.Analysis.min_dist() +Returns the minimal distance between all particles in the system.

+

When used with type-lists as arguments, then the minimal distance between particles of only those types is determined.

+

For example,

+
>>> import espressomd
+>>> system = espressomd.System(box_l=[100, 100, 100])
+>>> for i in range(10):
+...     system.part.add(pos=[1.0, 1.0, i**2], type=0)
+>>> system.analysis.min_dist()
+1.0
+
+
+
+
+

15.1.4. Particles in the neighborhood

+

espressomd.analyze.Analysis.nbhood()

+

Returns a list of the ids of particles that fall within a given radius of a target position. +For example,

+
ids = system.analysis.nbhood(pos=system.box_l * 0.5, r_catch=5.0)
+
+
+
+
+

15.1.5. Particle distribution

+

espressomd.analyze.Analysis.distribution()

+

Returns the distance distribution of particles +(probability of finding a particle of a certain type at a specified distance around +a particle of another specified type, disregarding the fact that a spherical shell of a +larger radius covers a larger volume). +The distance is defined as the minimal distance between a particle of one group to any of the other +group.

+

Two arrays are returned corresponding to the normalized distribution and the bins midpoints, for example

+
>>> system = espressomd.System(box_l=[10, 10, 10])
+>>> for i in range(5):
+...     system.part.add(pos=i * system.box_l, type=0)
+>>> bins, count = system.analysis.distribution(type_list_a=[0], type_list_b=[0],
+...                                            r_min=0.0, r_max=10.0, r_bins=10)
+>>> print(bins)
+[ 0.5  1.5  2.5  3.5  4.5  5.5  6.5  7.5  8.5  9.5]
+>>> print(count)
+[ 1.  0.  0.  0.  0.  0.  0.  0.  0.  0.]
+
+
+
+
+

15.1.6. Structure factor

+

espressomd.analyze.Analysis.structure_factor()

+

Calculate the structure factor for given types.

+

Returns the spherically averaged structure factor \(S(q)\) of +particles specified in sf_types. \(S(q)\) is calculated for all possible +wave vectors \(\frac{2\pi}{L} \leq q \leq \frac{2\pi}{L}\) up to sf_order.

+
+
+

15.1.7. Center of mass

+

espressomd.analyze.Analysis.center_of_mass()

+

Returns the center of mass of particles of the given type given by part_type.

+
+
+

15.1.8. Moment of inertia matrix

+

espressomd.analyze.Analysis.moment_of_inertia_matrix()

+

Returns the 3x3 moment of inertia matrix for particles of a given type.

+
+
+

15.1.9. Gyration tensor

+

espressomd.analyze.Analysis.gyration_tensor()

+

Analyze the gyration tensor of particles of a given type, or of all particles in the system if no type is given. Returns a dictionary containing the squared radius of gyration, three shape descriptors (asphericity, acylindricity, and relative shape anisotropy), eigenvalues of the gyration tensor and their corresponding eigenvectors. The eigenvalues are sorted in descending order.

+
+
+

15.1.10. Pressure

+

espressomd.analyze.Analysis.pressure()

+

Computes the instantaneous virial pressure for an isotropic and homogeneous system. It +returns all the contributions to the total pressure as well as the total pressure (see espressomd.analyze.Analysis.pressure()).

+

The instantaneous pressure is calculated (if there are no electrostatic interactions) +by the volume averaged, direction averaged instantaneous virial pressure

+
+(1)\[p = \frac{2E_{\text{kinetic}}}{Vf} + \frac{\sum_{j>i} {F_{ij}r_{ij}}}{3V}\]
+

where \(f=3\) is the number of translational degrees of freedom of +each particle, \(V\) is the volume of the system, +\(E_{\text{kinetic}}\) is the kinetic energy, \(F_{ij}\) the force +between particles i and j, and \(r_{ij}\) is the distance between +them. The kinetic energy divided by the degrees of freedom is

+
+\[\frac{2E_{\text{kinetic}}}{f} = \frac{1}{3}\sum_{i} {m_{i}v_{i}^{2}}.\]
+

Note that Equation (1) can only be applied to pair potentials and +central forces. Description of how contributions from other interactions +are calculated is beyond the scope of this manual. Three body potentials +are implemented following the procedure in +Ref. [Thompson et al., 2009]. A different formula is used to +calculate contribution from electrostatic interactions. For +electrostatic interactions in P3M, the \(k\)-space contribution is implemented according to [Essmann et al., 1995]. +The implementation of the Coulomb P3M pressure is tested against LAMMPS.

+

Four-body dihedral potentials are not included. Except of +VIRTUAL_SITES_RELATIVE constraints all other +constraints of any kind are not currently accounted for in the pressure +calculations. The pressure is no longer correct, e.g., when particles +are confined to a plane.

+

Note: The different contributions which are returned are the summands that arise from force splitting \(\vec{F}_{i,j}={\vec{F}_{i,j}}_\text{bonded}+{\vec{F}_{i,j}}_\text{nonbonded}+...\) in the virial pressure formula. Later when the user calculates the ensemble average via e.g. \(\langle p \rangle \approx 1/N \sum_{i=1}^N p_i\) however the ensemble average with all interactions present is performed. That means the contributions are not easy to interpret! Those are the contributions to the pressure in a system where all interactions are present and therefore in a coupled system.

+
+
+

15.1.11. Pressure Tensor

+

espressomd.analyze.Analysis.pressure_tensor()

+

Computes the volume averaged instantaneous pressure tensor of the system with options which are +described by in espressomd.analyze.Analysis.pressure_tensor(). +In general do only use it for (on average) homogeneous systems. For inhomogeneous systems you need to use the local pressure tensor.

+

The instantaneous virial pressure tensor is calculated by

+
+\[p_{(k,l)} = \frac{\sum_{i} {m_{i}v_{i}^{(k)}v_{i}^{(l)}}}{V} + \frac{\sum_{j>i}{F_{ij}^{(k)}r_{ij}^{(l)}}}{V}\]
+

where the notation is the same as for the pressure. The superscripts \(k\) +and \(l\) correspond to the components in the tensors and vectors.

+

If electrostatic interactions are present then also the coulombic parts of the pressure tensor need to be calculated. If P3M is present, then the instantaneous pressure tensor is added to the above equation in accordance with [Essmann et al., 1995] :

+
+\[p^\text{Coulomb, P3M}_{(k,l)} =p^\text{Coulomb, P3M, dir}_{(k,l)} + p^\text{Coulomb, P3M, rec}_{(k,l)},\]
+

where the first summand is the short ranged part and the second summand is the long ranged part.

+

The short ranged part is given by:

+
+\[\begin{split}p^\text{Coulomb, P3M, dir}_{(k,l)}= \frac{1}{4\pi \varepsilon_0 \varepsilon_r} \frac{1}{2V} \sum_{\vec{n}}^* \sum_{i,j=1}^N q_i q_j \left( \frac{ \mathrm{erfc}(\beta |\vec{r}_j-\vec{r}_i+\vec{n}|)}{|\vec{r}_j-\vec{r}_i+\vec{n}|^3} + \\ \frac{2\beta \pi^{-1/2} \exp(-(\beta |\vec{r}_j-\vec{r}_i+\vec{n}|)^2)}{|\vec{r}_j-\vec{r}_i+\vec{n}|^2} \right) (\vec{r}_j-\vec{r}_i+\vec{n})_k (\vec{r}_j-\vec{r}_i+\vec{n})_l,\end{split}\]
+

where \(\beta\) is the P3M splitting parameter, \(\vec{n}\) identifies the periodic images, the asterisk denotes that terms with \(\vec{n}=\vec{0}\) and i=j are omitted. +The long ranged (k-space) part is given by:

+
+\[p^\text{Coulomb, P3M, rec}_{(k,l)}= \frac{1}{4\pi \varepsilon_0 \varepsilon_r} \frac{1}{2 \pi V^2} \sum_{\vec{k} \neq \vec{0}} \frac{\exp(-\pi^2 \vec{k}^2/\beta^2)}{\vec{k}^2} |S(\vec{k})|^2 \cdot (\delta_{k,l}-2\frac{1+\pi^2\vec{k}^2/\beta^2}{\vec{k}^2} \vec{k}_k \vec{k}_l),\]
+

where \(S(\vec{k})\) is the Fourier transformed charge density. Compared to Essmann we do not have the contribution \(p^\text{corr}_{k,l}\) since we want to calculate the pressure that arises from all particles in the system.

+

Note: The different contributions which are returned are the summands that arise from force splitting \(\vec{F}_{i,j}={\vec{F}_{i,j}}_\text{bonded}+{\vec{F}_{i,j}}_\text{nonbonded}+...\) in the virial pressure tensor formula. +Later when the user calculates the pressure tensor via \(\langle p_{(k,l)}\rangle \approx 1/N \sum_{i=1}^N p_{k,l}\) however the ensemble average with all interactions present is performed. +That means the contributions are not easy to interpret! Those are the contributions to the pressure in a system where all interactions are present and therefore in a coupled system.

+

Note that the angular velocities of the particles are not included in +the calculation of the pressure tensor.

+
+
+

15.1.12. Chains

+

All analysis functions in this section require the topology of the chains to be set correctly. +A chain needs to be set up with a contiguous range of particle IDs, and the +head resp. tail particle must be have the first resp. last id in the range. +For chain observables that rely on connectivity information, the chain topology +must be linear, i.e. particle \(n\) is connected to \(n+1\) and so on. +Each chain is a set of consecutively numbered particles and all chains are +supposed to consist of the same number of particles.

+

The particles image_box +values must also be consistent, since these observables are calculated using +unfolded coordinates. For example, if all particles were to be inserted in +the central box except for the tail particle, which would be e.g. inserted in +the fourth periodic image, the end-to-end distance and radius of gyration +would be quite large, even if the tail particle is in close proximity to the +penultimate particle in folded coordinates, because the last inter-particle +distance would be evaluated as being 4 times the box length plus the bond +length. Particles can have different image_box values, for example +in a chain with equilibrium bond length 2, if the penultimate particle is at +[box_l - 1, 0, 0] and the tail particle at [box_l + 1, 0, 0], their +inter-particle distance would be evaluated as 2 and the observables would +be correctly calculated. This can lead to counter-intuitive behavior when +chains are longer than half the box size in a fully periodic system. As an +example, consider the end-to-end distance of a linear polymer growing on +the x-axis. While espressomd.system.System.distance() would feature +a triangle wave with a period equal to the box length in the x-direction, +espressomd.analyze.Analysis.calc_re() would be monotonically increasing, +assuming the image_box values were properly set up. This is important to +consider when setting up systems where the polymers are much longer than the +box length, which is common when simulating polymer melts.

+
+

15.1.12.1. Available chain analysis functions

+ +
+
+
+
+

15.2. Observables framework

+

Observables extract properties of the particles and the LB fluid and +return either the raw data or a statistic derived from them. +Correlators and accumulators provide functionality to collect and +process the output of observables automatically throughout the course +of the simulation.

+

The Observables framework is progressively replacing the Analysis framework. +This is motivated by the fact, that sometimes it is desirable that the +analysis functions do more than just return a value to the scripting +interface. For some observables it is desirable to be sampled every few +integration steps. In addition, it should be possible to pass the +observable values to other functions which compute history-dependent +quantities, such as correlation functions. All this should be done +without the need to interrupt the integration by passing the control to +the script level and back, which produces a significant overhead when +performed too often.

+

Some observables in the core have their corresponding counterparts in +the espressomd.analyze module. However, only the core-observables +can be used on the fly with the toolbox of accumulators and correlators.

+

The first step of the core analysis is to create an observable. +An observable in the sense of the core analysis can be considered as a +rule how to compute a certain set of numbers from a given state of the +system or a rule how to collect data from other observables. Any +observable is represented as a single array of double values in the core. +Any more complex shape (tensor, complex number, …) must be compatible to this +prerequisite. Every observable however documents the storage order and returns +a reshaped numpy array.

+

The observables can be used in parallel simulations. However, +not all observables carry out their calculations in parallel. +Instead, the entire particle configuration is collected on the head node, +and the calculations are carried out there. +This is only performance-relevant if the number of processor cores is large +and/or interactions are calculated very frequently.

+
+

15.2.1. Using observables

+

The observables are represented as Python classes derived from +espressomd.observables.Observable. They are contained in +the espressomd.observables module. An observable is instantiated as +follows

+
import espressomd.observables
+part_pos = espressomd.observables.ParticlePositions(ids=(1, 2, 3, 4, 5))
+
+
+

Here, the keyword argument ids specifies the ids of the particles, +which the observable should take into account.

+

The current value of an observable can be obtained using its +calculate() method:

+
print(part_pos.calculate())
+
+
+

Profile observables have additional methods +bin_centers() and +bin_edges() to facilitate +plotting of histogram slices with functions that require either bin centers +or bin edges for the axes. Example:

+
import matplotlib.pyplot as plt
+import numpy as np
+import espressomd
+import espressomd.observables
+
+system = espressomd.System(box_l=[10.0, 10.0, 10.0])
+p1 = system.part.add(pos=[4.0, 3.0, 6.0])
+p2 = system.part.add(pos=[7.0, 3.0, 6.0])
+
+# histogram in Cartesian coordinates
+density_profile = espressomd.observables.DensityProfile(
+    ids=[p1.id, p2.id],
+    n_x_bins=8, min_x=1.0, max_x=9.0,
+    n_y_bins=8, min_y=1.0, max_y=9.0,
+    n_z_bins=4, min_z=4.0, max_z=8.0)
+obs_data = density_profile.calculate()
+obs_bins = density_profile.bin_centers()
+
+# 1D slice: requires bin centers
+plt.plot(obs_bins[:, 2, 2, 0], obs_data[:, 2, 2])
+plt.show()
+
+# 2D slice: requires extent
+plt.imshow(obs_data[:, :, 2].T, origin='lower',
+           extent=[density_profile.min_x, density_profile.max_x,
+                   density_profile.min_y, density_profile.max_y])
+plt.show()
+
+
+

Observables based on cylindrical coordinates are also available. +They require special parameters if the cylindrical coordinate system is non-standard, +e.g. if you want the origin of the cylindrical coordinates to be at a special location +of the box or if you want to make use of symmetries along an axis that is not parallel to the z-axis. +For this purpose, use espressomd.math.CylindricalTransformationParameters +to create a consistent set of the parameters needed. Example:

+
import espressomd.math
+
+# shifted and rotated cylindrical coordinates
+cyl_transform_params = espressomd.math.CylindricalTransformationParameters(
+    center=[5.0, 0.0, 5.0], axis=[0, 1, 0], orientation=[0, 0, 1])
+
+# histogram in cylindrical coordinates
+density_profile = espressomd.observables.CylindricalDensityProfile(
+    ids=[p1.id, p2.id],
+    transform_params = cyl_transform_params,
+    n_r_bins=8, min_r=1.0, max_r=4.0,
+    n_phi_bins=16, min_phi=-np.pi, max_phi=np.pi,
+    n_z_bins=4, min_z=0.0, max_z=8.0)
+obs_data = density_profile.calculate()
+obs_bins = density_profile.bin_edges()
+
+# 2D slice: requires bin edges
+fig = plt.figure()
+ax = fig.add_subplot(111, polar='True')
+r = obs_bins[:, 0, 0, 0]
+phi = obs_bins[0, :, 0, 1]
+ax.pcolormesh(phi, r, obs_data[:, :, 1])
+plt.show()
+
+
+
+
+

15.2.2. Available observables

+

The following list contains some of the available observables. You can find +documentation for all available observables in espressomd.observables.

+ +
+
+

15.2.3. Accumulators

+
+

15.2.3.1. Time series

+

In order to take snapshots of an observable, +espressomd.accumulators.TimeSeries can be used:

+
import espressomd
+import espressomd.observables
+import espressomd.accumulators
+
+system = espressomd.System(box_l=[10.0, 10.0, 10.0])
+system.cell_system.skin = 0.4
+system.time_step = 0.01
+p1 = system.part.add(pos=[5.0, 5.0, 5.0], v=[0, 2, 0])
+position_observable = espressomd.observables.ParticlePositions(ids=[p1.id])
+accumulator = espressomd.accumulators.TimeSeries(
+    obs=position_observable, delta_N=2)
+system.auto_update_accumulators.add(accumulator)
+system.integrator.run(10)
+print(accumulator.time_series())
+
+
+

In the example above the automatic update of the accumulator is used. However, +it’s also possible to manually update the accumulator by calling +espressomd.accumulators.TimeSeries.update().

+
+
+

15.2.3.2. Mean-variance calculator

+

In order to calculate the running mean and variance of an observable, +espressomd.accumulators.MeanVarianceCalculator can be used:

+
import espressomd
+import espressomd.observables
+import espressomd.accumulators
+
+system = espressomd.System(box_l=[10.0, 10.0, 10.0])
+system.cell_system.skin = 0.4
+system.time_step = 0.01
+p1 = system.part.add(pos=[5.0, 5.0, 5.0], v=[0, 2, 0])
+position_observable = espressomd.observables.ParticlePositions(ids=[p1.id])
+accumulator = espressomd.accumulators.MeanVarianceCalculator(
+    obs=position_observable, delta_N=2)
+system.auto_update_accumulators.add(accumulator)
+system.integrator.run(10)
+print(accumulator.mean())
+print(accumulator.variance())
+
+
+

In the example above the automatic update of the accumulator is used. However, +it’s also possible to manually update the accumulator by calling +espressomd.accumulators.MeanVarianceCalculator.update().

+
+
+
+

15.2.4. Correlations

+

Time correlation functions are ubiquitous in statistical mechanics and +molecular simulations when dynamical properties of many-body systems are +concerned. A prominent example is the velocity autocorrelation function, +\(\left< \mathbf{v}(t) \cdot \mathbf{v}(t+\tau) \right>\) which is +used in the Green-Kubo relations. In general, time correlation functions +are of the form

+
+\[C(\tau) = \left<A\left(t\right) \otimes B\left(t+\tau\right)\right>\]
+

where \(t\) is time, \(\tau\) is the lag time (time difference) +between the measurements of (vector) observables \(A\) and +\(B\), and \(\otimes\) is an operator which produces the vector +quantity \(C\) from \(A\) and \(B\). The ensemble average +\(\left< \cdot \right>\) is taken over all time origins \(t\). +Correlation functions describing dynamics of large and complex molecules +such as polymers span many orders of magnitude, ranging from MD time +step up to the total simulation time.

+

A correlator takes one or two observables, obtains values from them during the simulation and +finally uses a fast correlation algorithm which enables efficient computation +of correlation functions spanning many orders of magnitude in the lag time.

+

The implementation for computing averages and error estimates of a time series +of observables relies on estimates of autocorrelation functions and the +respective autocorrelation times. The correlator provides the same +functionality as a by-product of computing the correlation function.

+

An example of the usage of observables and correlations is provided in +the script samples/observables_correlators.py.

+
+

15.2.4.1. Creating a correlation

+

Each correlator is represented by an instance of the espressomd.accumulators.Correlator. +Please see its documentation for an explanation of the arguments that have to be passed to the constructor.

+

Correlators can be registered for automatic updating during the +integration by adding them to espressomd.system.System.auto_update_accumulators.

+
system.auto_update_accumulators.add(corr)
+
+
+

Alternatively, an update can triggered by calling the update() method of the correlator instance. +In that case, one has to make sure to call the update in the correct time intervals.

+

The current on-the-fly correlation result can of a correlator can be obtained using its result() method. +The final result (including the latest data in the buffers) is obtained using the finalize() method. +After this, no further update of the correlator is possible.

+
+
+

15.2.4.2. Example: Calculating a particle’s diffusion coefficient

+

For setting up an observable and correlator to obtain the mean square displacement of particle 0, use:

+
pos_obs = ParticlePositions(ids=[p1.id])
+c_pos = Correlator(obs1=pos_obs, tau_lin=16, tau_max=100., delta_N=10,
+                   corr_operation="square_distance_componentwise", compress1="discard1")
+
+
+

To obtain the velocity auto-correlation function of particle 0, use:

+
obs = ParticleVelocities(ids=[p1.id])
+c_vel = Correlator(obs1=vel_obs, tau_lin=16, tau_max=20., delta_N=1,
+                   corr_operation="scalar_product", compress1="discard1")
+
+
+

The full example can be found in samples/diffusion_coefficient.py. +Note that in this example, the operation square_distance_componentwise +is used, which is not a correlation function in the mathematical sense. Other +available operations include actual correlation functions, as described +in the source documentation of espressomd.accumulators.Correlator.

+
+
+
+

15.2.5. Details of the multiple tau correlation algorithm

+

Here we briefly describe the multiple tau correlator which is +implemented in ESPResSo. For a more detailed description and discussion of its +behavior with respect to statistical and systematic errors, please read +the cited literature. This type of correlator has been in use for years +in the analysis of dynamic light +scattering [Schätzel et al., 1988]. About a decade later it +found its way to the Fluorescence Correlation Spectroscopy +(FCS) [Magatti and Ferri, 2001]. The book of Frenkel and +Smit [Frenkel and Smit, 2002] describes its application for the +special case of the velocity autocorrelation function.

+
+Schematic representation of buffers in the correlator. +
+

Schematic representation of buffers in the correlator.

+
+
+

Let us consider a set of \(N\) observable values as schematically +shown in the figure above, where a value of index \(i\) was +measured at times \(i\delta t\). We are interested in computing the +correlation function for a range +of lag times \(\tau = (i-j)\delta t\) between the measurements +\(i\) and \(j\). To simplify the notation, we drop +\(\delta t\) when referring to observables and lag times.

+

The trivial implementation takes all possible pairs of values +corresponding to lag times +\(\tau \in [{\tau_{\mathrm{min}}}:{\tau_{\mathrm{max}}}]\). Without +loss of generality, we consider +\({\tau_{\mathrm{min}}}=0\). The computational effort for such an +algorithm scales as +\({\cal O} \bigl({\tau_{\mathrm{max}}}^2\bigr)\). As a rule of +thumb, this is feasible if \({\tau_{\mathrm{max}}}< 10^3\). The +multiple tau correlator provides a solution to compute the correlation +functions for arbitrary range of the lag times by coarse-graining the +high \(\tau\) values. It applies the naive algorithm to a relatively +small range of lag times \(\tau \in [0:p-1]\) +(\(p\) corresponds to parameter tau_lin). +This we refer to as compression level 0. +To compute the correlations for lag times +\(\tau \in [p:2(p-1)]\), the original data are first coarse-grained, +so that \(m\) values of the original data are compressed to produce +a single data point in the higher compression level. Thus the lag time +between the neighboring values in the higher compression level +increases by a factor of \(m\), while the number of stored values +decreases by the same factor and the number of correlation operations at +this level reduces by a factor of \(m^2\). Correlations for lag +times \(\tau \in [2p:4(p-1)]\) are computed at compression level 2, +which is created in an analogous manner from level 1. This can continue +hierarchically up to an arbitrary level for which enough data is +available. Due to the hierarchical reduction of the data, the algorithm +scales as +\({\cal O} \bigl( p^2 \log({\tau_{\mathrm{max}}}) \bigr)\). Thus an +additional order of magnitude in \({\tau_{\mathrm{max}}}\) costs +just a constant extra effort.

+

The speedup is gained at the expense of statistical accuracy. The loss +of accuracy occurs at the compression step. In principle one can use any +value of \(m\) and \(p\) to tune the algorithm performance. +However, it turns out that using a high \(m\) dilutes the data at +high \(\tau\). Therefore \(m=2\) is hard-coded in the correlator +and cannot be modified by user. The value of \(p\) remains an +adjustable parameter which can be modified by user by setting when +defining a correlation. In general, one should choose \(p \gg m\) to +avoid loss of statistical accuracy. Choosing \(p=16\) seems to be +safe but it may depend on the properties of the analyzed correlation +functions. A detailed analysis has been performed in +Ref. [Ramirez et al., 2010].

+

The choice of the compression function also influences the statistical +accuracy and can even lead to systematic errors. The default compression +function discards the second value and +pushes the first one to the higher level. This is robust and can be +applied universally to any combination of observables and correlation +operation. On the other hand, it reduces the statistical accuracy as the +compression level increases. In many cases, the compression operation +can be applied, which averages the two neighboring values and the +average then enters the higher level, preserving almost the full +statistical accuracy of the original data. In general, if averaging can +be safely used or not, depends on the properties of the difference

+
+\[\frac{1}{2} (A_i \otimes B_{i+p} + A_{i+1} \otimes B_{i+p+1} ) - +\frac{1}{2} (A_i + A_{i+1} ) \otimes \frac{1}{2} (B_{i+p} + B_{i+p+1}) +\label{eq:difference}\]
+

For example in the case of velocity autocorrelation function, the +above-mentioned difference has a small value and a random sign, +different contributions cancel each other. On the other hand, in the of +the case of mean square displacement the difference is always positive, +resulting in a non-negligible systematic error. A more general +discussion is presented in Ref. [Ramirez et al., 2010].

+
+
+
+

15.3. Cluster analysis

+

ESPResSo provides support for online cluster analysis. Here, a cluster +is a group of particles, such that you can get from any particle +to any second particle by at least one path of neighboring particles. +I.e., if particle B is a neighbor of particle A, particle C is a neighbor +of A and particle D is a neighbor of particle B, all four particles are +part of the same cluster. The cluster analysis is available in parallel +simulations, but the analysis is carried out on the head node, only.

+

Whether or not two particles are neighbors is defined by a pair criterion. +The available criteria can be found in espressomd.pair_criteria. +For example, a distance criterion which will consider particles as neighbors +if they are closer than 0.11 is created as follows:

+
import espressomd.pair_criteria
+dc = espressomd.pair_criteria.DistanceCriterion(cut_off=0.11)
+
+
+

To obtain the cluster structure of a system, an instance of +espressomd.cluster_analysis.ClusterStructure has to be created. +To to create a cluster structure with above criterion:

+
import espressomd.cluster_analysis
+cs = espressomd.cluster_analysis.ClusterStructure(distance_criterion=dc)
+
+
+

In most cases, the cluster analysis is carried out by calling the +espressomd.cluster_analysis.ClusterStructure.run_for_all_pairs method. +When the pair criterion is purely based on bonds, +espressomd.cluster_analysis.ClusterStructure.run_for_bonded_particles can be used.

+

The results can be accessed via ClusterStructure.clusters, which is an instance of +espressomd.cluster_analysis.Clusters.

+

Individual clusters are represented by instances of +espressomd.cluster_analysis.Cluster, which provides access to the +particles contained in a cluster as well as per-cluster analysis routines +such as radius of gyration, center of mass and longest distance. +Note that the cluster objects do not contain copies of the particles, +but refer to the particles in the simulation. Hence, the objects become +outdated if the simulation system changes. On the other hand, it is possible +to directly manipulate the particles contained in a cluster.

+
+
+ + +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/doc4.2.2/appendix.html b/doc4.2.2/appendix.html new file mode 100644 index 0000000000..7d35bf7c26 --- /dev/null +++ b/doc4.2.2/appendix.html @@ -0,0 +1,503 @@ + + + + + + + + + 23. Appendix — ESPResSo 4.2.2 documentation + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +
+

23. Appendix

+
+

23.1. The MMM family of algorithms

+
+

23.1.1. Introduction

+

In the MMM family of algorithms for the electrostatic interaction, a +convergence factor approach to tackle the conditionally convergent +Coulomb sum is used (even the authors of the original MMM method have no +idea what this acronym stands for). Instead of defining the summation +order, one multiplies each summand by a continuous factor +\(c(\beta,r_{ij},n_{klm})\) such that the sum is absolutely +convergent for \(\beta>0\), but \(c(0,.,.)=1\). The energy is +then defined as the limit \(\beta\rightarrow 0\) of the sum, i.e. +\(\beta\) is an artificial convergence parameter. For a convergence +factor of \(e^{-\beta n_{klm}^2}\) the limit is the same as the spherical +limit, and one can derive the classical Ewald method quite conveniently through +this approach [Smith, 1981]. To derive the formulas for MMM, +one has to use a different convergence factor, namely +\(e^{-\beta|r_{ij}+n_{klm}|}\), which defines the alternative energy

+
+\[\tilde{E}=\,\frac{1}{2}\lim_{\beta\rightarrow + 0}\sum_{k,l,m}{\sum_{i,j=1}^N}' \frac{q_i q_je^{-\beta|p_{ij} + + n_{klm}|}} {|p_{ij} + n_{klm}|} +=:\,\frac{1}{2}\lim_{\beta\rightarrow 0}\sum_{i,j=1}^N +q_iq_j\phi_\beta(x_{ij}, y_{ij},z_{ij}).\]
+

\(\phi_\beta\) is given by +\(\phi_\beta(x,y,z)=\,\tilde\phi_\beta(x,y,z) ++ \frac{e^{-\beta r}}{r}\) for \((x,y,z)\neq 0\) and +\(\phi_\beta(0,0,0)=\,\tilde\phi_\beta(0,0,0)\), where

+
+\[\tilde\phi_\beta(x,y,z)=\,\sum_{(k,l,m)\neq 0} \frac{e^{-\beta + r_{klm}}}{r_{klm}}.\]
+

The limit \(\tilde{E}\) exists, but differs for three-dimensionally +periodic systems by some multiple of the square of the dipole moment +from the spherical limit as obtained by the Ewald +summation [Smith, 1981]. From the physical point of view +the Coulomb interaction is replaced by a screened Coulomb interaction +with screening length \(1/\beta\). \(\tilde{E}\) is then the +energy in the limit of infinite screening length. But because of the +conditional convergence of the electrostatic sum, this is not +necessarily the same as the energy of an unscreened system. Since the +difference to the Ewald methods only depends on the dipole moment of the +system, the correction can be calculated easily in linear time and can +be ignored with respect to accuracy as well as to computation time.

+

For one- or two-dimensionally systems, however, \(\tilde{E}=E\), the +convergence factor approach equals the spherical summation limit of the +Ewald sum, and MMM1D and MMM2D do not require a dipole correction.

+

Starting from this convergence factor approach, Strebel constructed a +method of computational order \(O(N\log N)\), which is called MMM +[Strebel, 1999]. The favorable scaling is obtained, +very much like in the Ewald case, by technical tricks in the calculation +of the far formula. The far formula has a product decomposition and can +be evaluated hierarchically similarly to the fast multipole methods.

+

For particles sufficiently separated in the z-axis one can Fourier +transform the potential along both x and y. We obtain the far formula as

+
+\[\phi(x,y,z) =\, u_x u_y\sum_{p,q\neq 0} \frac{e^{2\pi f_{pq}z} + + e^{2\pi f_{pq}(\lambda_z-z)}}{f_{pq} \left(e^{2\pi f_{pq}\lambda_z} + - 1\right)} e^{2\pi i u_y q y}e^{2\pi i u_x p x} + 2\pi u_x +u_y\left(u_z z^2 - z + \frac{\lambda_z}{6}\right).\]
+

where \(\lambda_{x,y,z}\) are the box dimensions, \(f_{pq} =\, +\sqrt{(u_x p)^2 + (u_y q)^2},\quad f_p =\, u_x p,\quad f_q =\, u_x q\), +\(\omega_p=2\pi u_x p\) and \(\omega_q=2\pi u_y q\). The +advantage of this formula is that it allows for a product decomposition +into components of the particles. For example

+
+\[e^{2\pi f_{pq}z}=e^{2\pi f_{pq}(z_i-z_j)}=e^{2\pi + f_{pq}z_i}e^{-2\pi f_{pq}z_j}\]
+

etc. Therefore one just has to calculate the sum over all these +exponentials on the left side and on the right side and multiply them +together, which can be done in \(O(N)\) computation time. As can be +seen easily, the convergence of the series is excellent as long as z is +sufficiently large. By symmetry one can choose the coordinate with the +largest distance as z to optimize the convergence. Similar to the Lekner +sum, we need a different formula if all coordinates are small, i.e. for +particles close to each other. For sufficiently small \(u_y\rho\) +and \(u_xx\) we obtain the near formula as

+
+\[\begin{split}\begin{array}{rl} \tilde\phi(x,y,z)=\, & 2 u_x + u_y\sum\limits_{p,q>0} \frac{\cosh(2\pi f_{pq}z)}{f_{pq} + \left(e^{2\pi f_{pq}\lambda_z} - 1\right)} e^{2\pi i u_y q + y}e^{2\pi i u_x p x} +\\ & 4u_x\sum\limits_{l,p>0}\left(K_0(2\pi + u_x p\rho_l) + K_N(2\pi u_x p\rho_{-l})\right)cos(2\pi u_x p x) + -\\ & 2u_x\sum\limits_{n\ge 1}\frac{b_{2n}}{2n(2n)!}\Re\bigl((2\pi + u_y (z+iy))^{2n}\bigr) +\\ & u_x\sum\limits_{n\ge + 0}\left(\begin{array}{c}-\frac{1}{2}\\ + n\end{array}\right)\frac{\left( \psi^{(2n)}(1 + u_x x) + + \psi^{(2n)}(1 - u_x x)\right)}{(2n)!}\rho^{2n} -\\ & + 2\log(4\pi). \end{array}\end{split}\]
+

Note that this time we calculate \(\tilde{\phi}\) instead of +\(\phi\), i.e. we omit the contribution of the primary simulation +box. This is very convenient as it includes the case of self energy and +makes \(\tilde{\phi}\) a smooth function. To obtain \(\phi\) one +has to add the \(1/r\) contribution of the primary box. The self +energy is given by

+
+\[\tilde\phi(0,0,0)=\, 2 u_x u_y\sum\limits_{p,q>0} \frac{1}{f_{pq} + \left(e^{2\pi f_{pq}\lambda_z} - 1\right)}+ +8u_x\sum\limits_{l,p>0}K_N(2\pi u_x\lambda_y p l) + 2 u_x\psi^{(0)}(1) +- 2\log(4\pi).\]
+

Both the near and far formula are derived using the same convergence +factor approach, and consequently the same singularity in \(\beta\) +is obtained. This is important since otherwise the charge neutrality +argument does not hold.

+

To obtain the \(O(N\log N)\) scaling, some algorithm tricks are +needed, which are not used in MMM1D, MMM2D or ELC and are therefore not +discussed here. For details, see [Strebel, 1999].

+
+
+

23.1.2. MMM2D theory

+

In the case of periodicity only in the x and y directions, the far +formula looks like

+
+\[\begin{split}\begin{array}{rl} \phi(x,y,z) = \, & 4 u_x u_y\sum_{p,q>0} + \frac{e^{-2\pi f_{pq}|z|}} {f_{pq}} \cos(\omega_p x)\cos(\omega_q y) + +\\ & 2 u_x u_y\left(\sum_{q>0} \frac{e^{-2\pi f_q|z|}}{f_q} + \cos(\omega_q y) + \sum_{p>0} \frac{e^{-2\pi f_p|z|}}{f_p} + \cos(\omega_p x)\right) -\\ & 2\pi u_x u_y |z|, \end{array}\end{split}\]
+

and the near formula is

+
+\[\begin{split}\begin{array}{rl} \tilde\phi(x,y,z)=\, & + 4u_x\sum_{l,p>0}\left(K_0(\omega_p\rho_l) + + K_0(\omega_p\rho_{-l})\right)\cos(\omega_p x) -\\ & 2u_x\sum_{n\ge + 1}\frac{b_{2n}}{2n(2n)!} \Re\bigl((2\pi u_y + (z+iy))^{2n}\bigr)\,+\, \sum_{k=1}^{N_\psi-1}\left(\frac{1}{r_{k}} + + \frac{1}{r_{-k}}\right) -\\ & u_x\sum_{n\ge + 0}\left(\begin{array}{c}-\frac{1}{2}\\n\end{array}\right)\frac{\left( + \psi^{(2n)}(N_\psi + u_x x) + \psi^{(2n)}(N_\psi - u_x + x)\right)}{(2n)!}(u_x\rho)^{2n} -\\ & + 2u_x\log\left(4\pi\frac{u_y}{u_x}\right). \end{array}\end{split}\]
+

As said before, the energy obtained from these potentials is equal to +the electrostatic energy obtained by the spherical summation limit. The +deeper reason for this is that in some sense the electrostatic sum is +absolutely convergent [Arnold and Holm, 2002].

+

The near formula is used for particles with a small distance along the z +axis, for all other particles the far formula is used. Below is shown, +that the far formula can be evaluated much more efficiently, however, +its convergence breaks down for small z distance. To efficiently +implement MMM2D, the layered cell system is required, which splits up +the system in equally sized gaps along the z axis. The interaction of +all particles in a layer S with all particles in the layers S-1,S,S+1 is +calculated using the near formula, for the particles in layers +\(1,\dots,S-2\), and in layers \(S+2,\dots,N\), the far formula +is used.

+

The implementation of the near formula is relatively straight forward +and can be treated as any short ranged force is treated using the link +cell algorithm, here in the layered variant. The special functions in +the formula are somewhat demanding, but for the polygamma functions +Taylor series can be achieved, which are implemented in mmm-common.hpp. +The Bessel functions are calculated using a Chebychev series.

+

The treatment of the far formula is algorithmically more complicated. +For a particle i in layer \(S_i\), the formula can product +decomposed, as in

+
+\[\begin{split}\begin{array}{rl} \sum_{j\in I_S, S < S_i - 1} q_iq_j\frac{e^{-2\pi + f_{pq}|z_i-z_j|}}{f_{pq}} \cos(\omega_p (x_i - + x_j))\cos(\omega_q (y_i - y_j)) = \\ + q_i\frac{e^{-2\pi f_{pq}z_i}}{f_{pq}} \cos(\omega_p + x_i)\cos(\omega_q y_i) \sum_{j\in I_S, S < S_i - 1}q_je^{2\pi + f_{pq}z_j} \cos(\omega_p x_j)\cos(\omega_q y_j) + \\ + q_i\frac{e^{-2\pi f_{pq}z_i}}{f_{pq}} \cos(\omega_p + x_i)\sin(\omega_q y_i) \sum_{j\in I_S, S < S_i - 1}q_je^{2\pi + f_{pq}z_j} \cos(\omega_p x_j)\sin(\omega_q y_j) + \\ + q_i\frac{e^{-2\pi f_{pq}z_i}}{f_{pq}} \sin(\omega_p + x_i)\cos(\omega_q y_i) \sum_{j\in I_S, S < S_i - 1}q_je^{2\pi + f_{pq}z_j} \sin(\omega_p x_j)\cos(\omega_q y_j) + \\ + q_i\frac{e^{-2\pi f_{pq}z_i}}{f_{pq}} \sin(\omega_p + x_i)\sin(\omega_q y_i) \sum_{j\in I_S, S < S_i - 1}q_je^{2\pi + f_{pq}z_j} \sin(\omega_p x_j)\sin(\omega_q y_j). \end{array}\end{split}\]
+

This representation has the advantage, that the contributions of the two +particles are decoupled. For all particles j only the eight terms

+
+\[\xi^{(\pm,s/c,s/c)}_j= q_je^{\pm 2\pi f_{pq}z_j} \sin/\cos(\omega_p +x_j)\sin/\cos(\omega_q y_j)\]
+

are needed. The upper index describes the sign of the exponential term +and whether sine or cosine is used for \(x_j\) and \(y_j\) in +the obvious way. These terms can be used for all expressions on the +right hand side of the product decomposition. Moreover it is easy to see +from the addition theorem for the sine function that these terms also +can be used to calculate the force information up to simple prefactors +that depend only on p and q.

+

Every processor starts with the calculation of the terms +\(\xi^{(\pm,s/c,s/c)}_j\) and adds them up in each layer, so that +one obtains

+
+\[\Xi^{(\pm,s/c,s/c)}_s= \sum_{j\in S_s}\xi^{(\pm,s/c,s/c)}_j.\]
+

Now we calculate

+
+\[\Xi^{(l,s/c,s/c)}_s=\sum_{t < s - 1}\Xi^{(+,s/c,s/c)}_t\]
+

and

+
+\[\Xi^{(h,s/c,s/c)}_s=\sum_{t > s + 1}\Xi^{(-,s/c,s/c)}_t,\]
+

which are needed for the evaluation of the product decomposition. While +the bottom processor can calculate \(\Xi^{(l,s/c,s/c)}_s\) directly, +the other processors are dependent on its results. Therefore the bottom +processor starts with the calculation of its \(\Xi^{(l,s/c,s/c)}_s\) +and sends up \(\Xi^{(l,s/c,s/c)}_s\) and \(\Xi^{(+,s/c,s/c)}_s\) +of its top layer s to the next processor dealing with the layers above. +Simultaneously the top processor starts with the calculation of the +\(\Xi^{(h,s/c,s/c)}_s\) and sends them down. After the communicated +has been completed, every processor can use the +\(\Xi^{(l/h,s/c,s/c)}_j\) and the \(\xi^{(\pm,s/c,s/c)}_j\) to +calculate the force rsp. energy contributions for its particles.

+

In pseudo code, the far formula algorithm looks like:

+
    +
  1. for each layer \(s=1,\ldots,S\)

    +
      +
    1. \(\Xi^{(\pm,s/c,s/c)}_s=0\)

    2. +
    3. for each particle \(j\) in layer \(s\)

      +
        +
      1. calculate \(\xi^{(\pm,s/c,s/c)}_j\)

      2. +
      3. \(\Xi^{(\pm,s/c,s/c)}_s += \xi^{(\pm,s/c,s/c)}_j\)

      4. +
      +
    4. +
    +
  2. +
  3. \(\Xi^{(l,s/c,s/c)}_3=\Xi^{(+,s/c,s/c)}_1\)

  4. +
  5. for each layer \(s=4,\ldots,S\)

    +
      +
    1. +\[\Xi^{(l,s/c,s/c)}_s=\Xi^{(l,s/c,s/c)}_{s-1} +\ + \Xi^{(+,s/c,s/c)}_{s-2}\]
      +
    2. +
    +
  6. +
  7. \(\Xi^{(l,s/c,s/c)}_{S-2}=\Xi^{(-,s/c,s/c)}_S\)

  8. +
  9. for each layer \(s=(S-3),...,1\)

    +
      +
    1. +\[\Xi^{(l,s/c,s/c)}_s=\Xi^{(l,s/c,s/c)}_{s+1} +\ + \Xi^{(-,s/c,s/c)}_{s+2}\]
      +
    2. +
    +
  10. +
  11. for each layer \(s=1,...,S\)

    +
      +
    1. for each particle \(j\) in layer \(s\)

      +
        +
      1. calculate particle interaction from +\(\xi^{(+,s/c,s/c)}_j\Xi^{(l,s/c,s/c)}_s\) and +\(\xi^{(-,s/c,s/c)}_j\Xi^{(h,s/c,s/c)}_s\)

      2. +
      +
    2. +
    +
  12. +
+

For further details, see [Arnold et al., 2002, Arnold et al., 2002, Arnold and Holm, 2002, Arnold and Holm, 2002].

+
+

23.1.2.1. Dielectric contrast

+

A dielectric contrast at the lower and/or upper simulation box boundary +can be included comparatively easy by using image charges. Apart from +the images of the lowest and topmost layer, the image charges are far +enough to be treated by the far formula, and can be included as starting +points in the calculation of the \(\Xi\) terms. The remaining +particles from the lowest and topmost layer are treated by direct +summation of the near formula.

+

This means, that in addition to the algorithm above, one has to only a +few things: during the calculation of the particle and cell blocks +\(\xi\) and \(\Xi\), one additionally calculates the +contributions of the image charges and puts them either in a separate +array or, for the boundary layers, into two extra \(\xi\) cell +blocks outside the simulation box. The entries in the separate array are +then added up over all processors and stored in the \(\Xi\)-terms of +the lowest/topmost layer. This are all modifications necessary for the +far formula part. In addition to the far formula part, there is an +additional loop over the particles at the boundary to directly calculate +their interactions with their images. For details, refer to +[Tyagi et al., 2007].

+
+
+
+

23.1.3. MMM1D theory

+

In one-dimensionally periodic systems with z being the periodic +coordinate, the far formula looks like

+
+\[\begin{split}\begin{array}{rl} \phi(\rho,z) &=\, 4 u_z\sum_{p\neq 0} + K_0(\omega\rho)\cos(\omega z) - 2u_z\log(\frac{\rho}{2\lambda_z}) - + 2u_z\gamma\\ F_\rho(\rho,z) &=\, 8\pi u_z^2\sum_{p\neq 0} p + K_1(\omega\rho)\cos(\omega z) + \frac{2 u_z}{\rho}\\ F_z(\rho,z) + &=\, 8\pi u_z^2 \sum_{p\neq 0} pK_0(\omega\rho)\sin(\omega z), +\end{array}\end{split}\]
+

the near formula is

+
+\[\begin{split}\begin{array}{rl} \tilde{\phi}(\rho,z) &=\, -u_z\sum_{n\ge 0} + \left(\begin{array}{c}-\frac{1}{2}\\n\end{array}\right) + \frac{\left(\psi^{(2n)}(N_\psi + u_z z) + \psi^{(2n)}(N_\psi - u_z + z)\right)}{(2n)!}(u_z\rho)^{2n} - 2u_z\gamma + \\ + &\phantom{=\,++} + \sum_{k=1}^{N_\psi-1}\left(\frac{1}{r_k}+\frac{1}{r_{-k}}\right)\\ + \tilde{F}_\rho(\rho,z) &=\, -u_z^3 \sum_{n\ge 0} + \left(\begin{array}{c}-\frac{1}{2}\\n\end{array}\right) + \frac{\left(\psi^{(2n)}(N_\psi + u_z z) + \psi^{(2n)}(N_\psi - u_z + z)\right)}{(2n)!}(u_z\rho)^{2n-1} + \\ &\phantom{=\,++} + \sum_{k=1}^{N_\psi-1}\left(\frac{\rho}{r_k^3}+\frac{\rho}{r_{-k}^3}\right) + \\ \tilde{F}_z(\rho,z) &=\, -u_z^2 \sum_{n\ge 0} + \left(\begin{array}{c}-\frac{1}{2}\\n\end{array}\right) + \frac{\left(\psi^{(2n + 1)}(N_\psi + u_z z) + \psi^{(2n + 1)}(N_\psi + - u_z z)\right)}{(2n)!}(u_z\rho)^{2n} + \\ &\phantom{=\,++} + \sum_{k=1}^{N_\psi-1}\left(\frac{z+k\lambda_z}{r_k^3}+\frac{z-k\lambda_z}{r_{-k}^3}\right), +\end{array}\end{split}\]
+

where \(\rho\) denotes the xy-distance of the particles. As for the +two-dimensional periodic case, the obtained energy is equal to the +one-dimensional Ewald sum. Algorithmically, MMM1D is uninteresting, since +neither the near nor far formula allow a product decomposition or +similar tricks. MMM1D has to be implemented as a simple NxN loop. +However, the formulas can be evaluated efficiently, so that MMM1D can +still be used reasonably for up to 400 particles on a single processor +[Arnold and Holm, 2005].

+
+
+

23.1.4. ELC theory

+

The ELC method differs from the other MMM algorithms in that it is not +an algorithm for the calculation of the electrostatic interaction, but +rather represents a correction term which allows to use any method for +three-dimensionally periodic systems with spherical summation order for +two-dimensional periodicity. The basic idea is to expand the +two-dimensional slab system of height h in the non-periodic z-coordinate to +a system with periodicity in all three dimensions, with a period of +\(\lambda_z > h\), which leaves an empty gap of height +\(\delta = \lambda_z - h\) above the particles in the simulation box.

+

Since the electrostatic potential is only finite if the total system is +charge neutral, the additional image layers (those layers above or below +the original slab system) are charge neutral, too. Now let us consider +the n-th image layer which has an offset of \(n\lambda_z\) to the +original layer. If \(n\lambda_z\) is large enough, each particle of +charge \(q_j\) at position \((x_j,y_j,z_j+n\lambda_z)\) and its +replicas in the xy-plane can be viewed as constituting a homogeneous +charged sheet of charge density +\(\sigma_j = \frac{q_j}{\lambda_x\lambda_y}\). The potential of such +a charged sheet at distance \(z\) is \(2\pi \sigma_j |z|\). +Now we consider the contribution from a pair of image layers +located at \(\pm n\lambda_z\), n>0 to the energy of a charge \(q_i\) at +position \((x_i,y_i,z_i)\) in the central layer. Since +\(|z_j - z_i| < n\lambda_z\), we have +\(|z_j - z_i + n\lambda_z| = n\lambda_z + z_j - z_i\) +and \(|z_j - z_i - n\lambda_z|= n\lambda_z - z_j + z_i\), and +hence the interaction energy from those two image layers with the charge +\(q_i\) vanishes by charge neutrality:

+
+\[2\pi q_i \sum_{j=1}^N \sigma_j(|z_j - z_i + n\lambda_z| + |z_j - +z_i - n\lambda_z|) = 4\pi q_i n\lambda_z \sum_{j=1}^N \sigma_j = 0.\]
+

The only errors occurring are those coming from the approximation of +assuming homogeneously charged, infinite sheets instead of discrete +charges. This assumption should become better when increasing the +distance \(n\lambda_z\) from the central layer.

+

However, in a naive implementation, even large gap sizes will result in +large errors. This is due to the order of summation for the standard +Ewald sum, which is spherical, while the above approach orders the cells +in layers, called slab-wise summation. Smith has shown that by adding to +the Ewald energy the term

+
+\[E_c=2\pi M_z^2 - \frac{2\pi M^2}{3},\]
+

where M is the total dipole moment, one obtains the result of a +slab-wise summation instead of the spherical limit +[Smith, 1981]. Although this is a major change in the +summation order, the difference is a very simple term. In fact, Smith +shows that changes of the summation order always result in a difference +that depends only on the total dipole moment.

+

Using the far formula of MMM2D, one can calculate the contributions of +the additional layers up to arbitrarily precision, even for small gap +sizes. This method is called electrostatic layer correction, ELC. The +advantage of this approach is that for the image layers, z is +necessarily large enough, so that all interactions can be represented +using the product decomposition. This allows for an order N evaluation +of the ELC term.

+

The electrostatic layer correction term is given by

+
+\[E_{lc}=\sum_{i,j=1}^Nq_iq_j\psi(p_i-p_j),\]
+

where

+
+\[\begin{split}\begin{array}{rl} \psi(x,y,z)=&4u_xu_y\sum_{p,q>0}\frac{\cosh(2\pi + f_{pq}z)}{f_{pq}(e^{2\pi f_{pq}\lambda_z} - 1)} \cos(\omega_p + x)\cos(\omega_q y) + \\ &2u_xu_y\sum_{p>0}\frac{\cosh(2\pi f_p + z)}{f_p(e^{2\pi f_p\lambda_z} - 1)}\cos(\omega_p x)+\\ + &2u_xu_y\sum_{q>0}\frac{\cosh(2\pi f_q z)}{f_q(e^{2\pi f_q\lambda_z} + - 1)}\cos(\omega_q y). \end{array}\end{split}\]
+

The implementation is very similar to MMM2D, except that the separation +between slices close by, and above and below is not necessary.

+
+
+

23.1.5. Errors

+

Common to all algorithms of the MMM family is that accuracy is cheap +with respect to computation time. More precisely, the maximal pairwise +error, i.e. the maximal error of the \(\psi\) expression decreases +exponentially with the cutoffs. In turn, the computation time grows +logarithmically with the accuracy. This is quite in contrast to the +Ewald methods, for which decreasing the error bound can lead to +excessive computation time. For example, P3M cannot reach a precision +beyond \(10^{-5}\) in general. The precise form of the error +estimates is of little importance here, for details see +[Arnold et al., 2002, Arnold et al., 2002].

+

One important aspect is that the error estimates are also exponential in +the non-periodic coordinate. Since the number of close by and far away +particles is different for particles near the border and in the center +of the system, the error distribution is highly non-homogeneous. This is +unproblematic as long as the maximal error is really much smaller than +the thermal energy. However, one cannot interpret the error simply as an +additional error source.

+
+Error distribution of the ELC method. +
+

Error distribution of the ELC method.

+
+
+

The figure shows the error distribution of the ELC method +for a gap size of \(10\%\) of the total system height. For MMM2D and +MMM1D the error distribution is less homogeneous, however, also here it +is always better to have some extra precision, especially since it is +computationally cheap.

+
+
+
+ + +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/doc4.2.2/bibliography.html b/doc4.2.2/bibliography.html new file mode 100644 index 0000000000..cc5a165c98 --- /dev/null +++ b/doc4.2.2/bibliography.html @@ -0,0 +1,302 @@ + + + + + + + + + 24. Bibliography — ESPResSo 4.2.2 documentation + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +
+

24. Bibliography

+

+
1
+

Patrick Ahlrichs and Burkhard Dünweg. Simulation of a single polymer chain in solution by combining lattice Boltzmann and molecular dynamics. The Journal of Chemical Physics, 111(17):8225–8239, 1999. doi:10.1063/1.480156.

+
+
2
+

Michael P. Allen and Dominic J. Tildesley. Computer simulation of liquids. Oxford University Press, 2nd edition, 2017. ISBN 9780198803195. doi:10.1093/oso/9780198803195.001.0001.

+
+
3
+

Hans C. Andersen. Rattle: a "velocity" version of the shake algorithm for molecular dynamics calculations. Journal of Computational Physics, 52:24–34, 1983. doi:10.1016/0021-9991(83)90014-1.

+
+
4
+

A. Arnold, J. de Joannis, and C. Holm. Electrostatics in periodic slab geometries II. The Journal of Chemical Physics, 117:2503–2512, 2002. doi:10.1063/1.1491954.

+
+
5
+

A. Arnold, J. de Joannis, and C. Holm. Electrostatics in periodic slab geometries I. The Journal of Chemical Physics, 117:2496–2502, 2002. doi:10.1063/1.1491955.

+
+
6
+

A. Arnold and C. Holm. MMM1D: A method for calculating electrostatic interactions in one-dimensional periodic geometries. The Journal of Chemical Physics, 123(12):144103, 2005. doi:10.1063/1.2052647.

+
+
7
+

A. Arnold, O. Lenz, S. Kesselheim, R. Weeber, F. Fahrenberger, D. Röhm, P. Košovan, and C. Holm. ESPResSo 3.1 — molecular dynamics software for coarse-grained models. In M. Griebel and M. A. Schweitzer, editors, Meshfree Methods for Partial Differential Equations VI, volume 89 of Lecture Notes in Computational Science and Engineering, pages 1–23. Springer Berlin Heidelberg, 2013. doi:10.1007/978-3-642-32979-1_1.

+
+
8
+

Axel Arnold and Christian Holm. A novel method for calculating electrostatic interactions in 2D periodic slab geometries. Chemical Physics Letters, 354:324–330, 2002. doi:10.1016/S0009-2614(02)00131-8.

+
+
9
+

Axel Arnold and Christian Holm. MMM2D: a fast and accurate summation method for electrostatic interactions in 2D slab geometries. Computer Physics Communications, 148(3):327–348, 2002. doi:10.1016/S0010-4655(02)00586-6.

+
+
10
+

V. Ballenegger, A. Arnold, and J. J. Cerda. Simulations of non-neutral slab systems with long-range electrostatic interactions in two-dimensional periodic boundary conditions. The Journal of Chemical Physics, 131(9):094107, 2009. doi:10.1063/1.3216473.

+
+
11
+

Sebastian Bindgen, Florian Weik, Rudolf Weeber, Erin Koos, and Pierre de Buyl. Lees-edwards boundary conditions for translation invariant shear flow: implementation and transport properties. Physics of Fluids, 33(8):083615, 2021. doi:10.1063/5.0055396.

+
+
12
+

A. Bródka. Ewald summation method with electrostatic layer correction for interactions of point dipoles in slab geometry. Chemical Physics Letters, 400(1–3):62–67, 2004. doi:10.1016/j.cplett.2004.10.086.

+
+
13
+

David Brown and Sylvie Neyertz. A general pressure tensor calculation for molecular dynamics simulations. Molecular Physics, 84(3):577–595, 1995. doi:10.1080/00268979500100371.

+
+
14
+

Juan J. Cerdà, Vincent Ballenegger, Olaf Lenz, and Christian Holm. P3M algorithm for dipolar interactions. The Journal of Chemical Physics, 129:234104, 2008. doi:10.1063/1.3000389.

+
+
15
+

I. Cimrák, M. Gusenbauer, and I. Jančigová. An ESPResSo implementation of elastic objects immersed in a fluid. Computer Physics Communications, 185(3):900–907, 2014. doi:10.1016/j.cpc.2013.12.013.

+
+
16
+

I. Cimrák, M. Gusenbauer, and T. Schrefl. Modelling and simulation of processes in microfluidic devices for biomedical applications. Computers & Mathematics with Applications, 64(3):278–288, 2012. doi:10.1016/j.camwa.2012.01.062.

+
+
17
+

Lindsay M. Crowl and Aaron L. Fogelson. Computational model of whole blood exhibiting lateral platelet motion induced by red blood cells. International Journal for Numerical Methods in Biomedical Engineering, 26(3–4):471–487, 2010. doi:10.1002/cnm.1274.

+
+
18
+

Pierre de Buyl. tidynamics: A tiny package to compute the dynamics of stochastic and molecular simulations. Journal of Open Source Software, 3(28):877, 2018. doi:10.21105/joss.00877.

+
+
19
+

Joost de Graaf, Henri Menke, Arnold J.T.M. Mathijssen, Marc Fabritius, Christian Holm, and Tyler N. Shendruk. Lattice-Boltzmann hydrodynamics of anisotropic active matter. The Journal of Chemical Physics, 144:134106, 2016. doi:10.1063/1.4944962.

+
+
20
+

Markus Deserno. Counterion condensation for rigid linear polyelectrolytes. PhD thesis, Universität Mainz, February 2000. doi:10.25358/openscience-1411.

+
+
21
+

Markus Deserno and Christian Holm. How to mesh up Ewald sums. I. A theoretical and numerical comparison of various particle mesh routines. The Journal of Chemical Physics, 109:7678, 1998. doi:10.1063/1.477414.

+
+
22
+

Markus Deserno and Christian Holm. How to mesh up Ewald sums. II. An accurate error estimate for the Particle-Particle-Particle-Mesh algorithm. The Journal of Chemical Physics, 109:7694, 1998. doi:10.1063/1.477415.

+
+
23
+

Markus Deserno, Christian Holm, and Hans Jörg Limbach. How to mesh up Ewald sums. In R. Esser, P. Grassberger, J. Grotendorst, and M. Lewerenz, editors, Molecular Dynamics on Parallel Computers, 319–320. World Scientific, Singapore, 2000. doi:10.1142/9789812793768_0023.

+
+
24
+

Masao Doi and Samuel Frederick Edwards. The Theory of Polymer Dynamics. Clarendon Press: Oxford, 1986. ISBN 9780198519768.

+
+
25
+

Michael M. Dupin, Ian Halliday, Chris M. Care, Lyuba Alboul, and Lance L. Munn. Modeling the flow of dense suspensions of deformable particles in three dimensions. Physical Review E, 75(6):066707, 2007. doi:10.1103/PhysRevE.75.066707.

+
+
26
+

L. Durlofsky, J. F. Brady, and G. Bossis. Dynamic simulation of hydrodynamically interacting particles. Journal of Fluid Mechanics, 180:21–49, 1987. doi:10.1017/S002211208700171X.

+
+
27
+

Burkhard Dünweg and Anthony J. C. Ladd. Lattice Boltzmann simulations of soft matter systems. In Christian Holm and Kurt Kremer, editors, Advanced Computer Simulation Approaches for Soft Matter Sciences III, volume 221 of Advances in Polymer Science, pages 89–166. Springer Berlin Heidelberg, 2009. doi:10.1007/978-3-540-87706-6_2.

+
+
28
+

Donald L Ermak and J Andrew McCammon. Brownian dynamics with hydrodynamic interactions. The Journal of Chemical Physics, 69(4):1352–1360, 1978. doi:10.1063/1.436761.

+
+
29
+

Ulrich Essmann, Lalith Perera, Max L. Berkowitz, Tom Darden, Hsing Lee, and Lee G. Pedersen. A smooth particle mesh Ewald method. The Journal of Chemical Physics, 103(19):8577–8593, 1995. doi:10.1063/1.470117.

+
+
30
+

P. P. Ewald. Die Berechnung optischer und elektrostatischer Gitterpotentiale. Annalen der Physik, 369(3):253–287, 1921. doi:10.1002/andp.19213690304.

+
+
31
+

Daan Frenkel and Berend Smit. Understanding molecular simulation: From algorithms to applications. Academic Press, San Diego, 2nd edition, 2002. ISBN 978-0-12-267351-1. doi:10.1016/B978-0-12-267351-1.X5000-7.

+
+
32
+

J. G. Gay and B. J. Berne. Modification of the overlap potential to mimic a linear site-site potential. The Journal of Chemical Physics, 74(6):3316–3319, 1981. doi:10.1063/1.441483.

+
+
33
+

Achim Guckenberger and Stephan Gekle. Theory and algorithms to compute Helfrich bending forces: A review. Journal of Physics: Condensed Matter, 29(20):203001, 2017. doi:10.1088/1361-648x/aa6313.

+
+
34
+

Felix Höfling, Karl-Ulrich Bamberg, and Thomas Franosch. Anomalous transport resolved in space and time by fluorescence correlation spectroscopy. Soft Matter, 7:1358, 2011. doi:10.1039/C0SM00718H.

+
+
35
+

Owen A. Hickey, Christian Holm, James L. Harden, and Gary W. Slater. Implicit method for simulating electrohydrodynamics of polyelectrolytes. Physical Review Letters, 2010. doi:10.1103/PhysRevLett.105.148301.

+
+
36
+

R. W. Hockney and J. W. Eastwood. Computer Simulation Using Particles. CRC Press, 1988. ISBN 9780852743928.

+
+
37
+

W. Humphrey, A. Dalke, and K. Schulten. VMD: visual molecular dynamics. Journal of Molecular Graphics, 14:33–38, 1996. doi:10.1016/0263-7855(96)00018-5.

+
+
38
+

J. Karl Johnson, Athanassios Z. Panagiotopoulos, and Keith E. Gubbins. Reactive canonical Monte Carlo: A new simulation technique for reacting or associating fluids. Molecular Physics, 81(3):717–733, 1994. doi:10.1080/00268979400100481.

+
+
39
+

Stefan Kesselheim, Marcello Sega, and Christian Holm. Applying ICC* to DNA translocation. Effect of dielectric boundaries. Computer Physics Communications, 182(1):33–35, 2011. doi:10.1016/j.cpc.2010.08.014.

+
+
40
+

Jiri Kolafa and John W. Perram. Cutoff errors in the Ewald summation formulae for point charge systems. Molecular Simulation, 9(5):351–368, 1992. doi:10.1080/08927029208049126.

+
+
41
+

A. Kolb and B. Dünweg. Optimized constant pressure stochastic dynamics. The Journal of Chemical Physics, 111(10):4453–59, 1999. doi:10.1063/1.479208.

+
+
42
+

Timm Krüger. Computer simulation study of collective phenomena in dense suspensions of red blood cells under shear. PhD thesis, Universität Bochum, 2011.

+
+
43
+

Timm Krüger. Computer simulation study of collective phenomena in dense suspensions of red blood cells under shear. Vieweg+Teubner Verlag, Wiesbaden, 2012. ISBN 978-3-8348-2376-2. doi:10.1007/978-3-8348-2376-2.

+
+
44
+

Timm Krüger, Halim Kusumaatmaja, Alexandr Kuzmin, Orest Shardt, Goncalo Silva, and Erlend Magnus Viggen. The Lattice Boltzmann Method. Springer International Publishing, 2017. ISBN 978-3-319-44649-3. doi:10.1007/978-3-319-44649-3.

+
+
45
+

Pijush K. Kundu, Ira M. Cohen, and Howard Hu. Fluid Mechanics. Elsevier Science, 2nd edition, 2001. ISBN 9780080545585.

+
+
46
+

Jonas Landsgesell, Christian Holm, and Jens Smiatek. Simulation of weak polyelectrolytes: A comparison between the constant pH and the reaction ensemble method. European Physical Journal Special Topics, 226(4):725–736, 2017. doi:10.1140/epjst/e2016-60324-3.

+
+
47
+

A. W. Lees and S. F. Edwards. The computer study of transport processes under extreme conditions. Journal of Physics C: Solid State Physics, 1972. doi:10.1088/0022-3719/5/15/006.

+
+
48
+

H. J. Limbach, A. Arnold, B. A. Mann, and C. Holm. ESPResSo – an extensible simulation package for research on soft matter systems. Computer Physics Communications, 174(9):704–727, 2006. doi:10.1016/j.cpc.2005.10.005.

+
+
49
+

D Magatti and F Ferri. Fast multi-tau real-time software correlator for dynamic light scattering. Applied Optics, 40(24):4011–4021, 2001. doi:10.1364/AO.40.004011.

+
+
50
+

Igor P. Omelyan. On the numerical integration of motion for rigid polyatomics: the modified quaternion approach. Computers in Physics, 12(1):97–103, 1998. doi:10.1063/1.168642.

+
+
51
+

Charles S. Peskin. The immersed boundary method. Acta Numerica, 11:479–517, 2002. doi:10.1017/S0962492902000077.

+
+
52
+

A. Yu. Polyakov, T. V. Lyutyy, S. Denisov, V. V. Reva, and P. Hänggi. Large-scale ferrofluid simulations on graphics processing units. Computer Physics Communications, 184:1483–1489, 2013. doi:10.1016/j.cpc.2013.01.016.

+
+
53
+

Jorge Ramirez, Sathish K. Sukumaran, Bart Vorselaars, and Alexei E. Likhtman. Efficient on the fly calculation of time correlation functions in computer simulations. The Journal of Chemical Physics, 133(15):154103, 2010. doi:10.1063/1.3491098.

+
+
54
+

D. C. Rapaport. The Art of Molecular Dynamics Simulation. Cambridge University Press, New York, NY, USA, 2nd edition, 2004. ISBN 9780511816581. doi:10.1017/CBO9780511816581.

+
+
55
+

Christopher E Reed and Wayne F Reed. Monte Carlo study of titration of linear polyelectrolytes. The Journal of Chemical Physics, 96(2):1609–1620, 1992. doi:10.1063/1.462145.

+
+
56
+

D. Roehm and A. Arnold. Lattice Boltzmann simulations on GPUs with ESPResSo. European Physical Journal Special Topics, 210:89–100, 2012. doi:10.1140/epjst/e2012-01639-6.

+
+
57
+

Michael Rubinstein and Ralph H. Colby. Polymer Physics. Oxford University Press, Oxford, UK, 2003.

+
+
58
+

K. Schätzel, M. Drewel, and S Stimac. Photon correlation measurements at large lag times: improving statistical accuracy. Journal of Modern Optics, 35(4):711–718, 1988. doi:10.1080/09500348814550731.

+
+
59
+

Tamar Schlick. Molecular Modeling and Simulation: An Interdisciplinary Guide. Volume 21 of Interdisciplinary Applied Mathematics. Springer New York, New York, NY, 2010. ISBN 978-1-4419-6350-5. doi:10.1007/978-1-4419-6351-2.

+
+
60
+

E. R. Smith. Electrostatic energy in ionic crystals. Proceedings of the Royal Society of London A: Mathematical and Physical Sciences, 375:475–505, 1981. doi:10.1098/rspa.1981.0064.

+
+
61
+

W. R. Smith and B. Triska. The reaction ensemble method for the computer simulation of chemical and phase equilibria. I. Theory and basic examples. The Journal of Chemical Physics, 100(4):3019–3027, 1994. doi:10.1063/1.466443.

+
+
62
+

T. Soddemann, B. Dünweg, and K. Kremer. A generic computer model for amphiphilic systems. European Physical Journal E, 6:409–419, 2001. doi:10.1007/s10189-001-8054-4.

+
+
63
+

T. Soddemann, B. Dünweg, and K. Kremer. Dissipative particle dynamics: a useful thermostat for equilibrium and nonequilibrium molecular dynamics simulations. Physical Review E, 68(4):046702, 2003. doi:10.1103/PhysRevE.68.046702.

+
+
64
+

R. Strebel. Pieces of software for the Coulombic m body problem. Dissertation, ETH Zürich, 1999. doi:10.3929/ethz-a-003856704.

+
+
65
+

S. Succi. The lattice Boltzmann equation for fluid dynamics and beyond. Oxford University Press, USA, 2001.

+
+
66
+

A. P. Thompson, S. J. Plimpton, and W. Mattson. General formulation of pressure and stress tensor for arbitrary many-body interaction potentials under periodic boundary conditions. The Journal of Chemical Physics, 131(15):154107, 2009. doi:10.1063/1.3245303.

+
+
67
+

Ilario G. Tironi, René Sperb, Paul E. Smith, and Wilfred F. van Gunsteren. A generalized reaction field method for molecular-dynamics simulations. The Journal of Chemical Physics, 102(13):5451–5459, 1995. doi:10.1063/1.469273.

+
+
68
+

C. Heath Turner, John K. Brennan, Martin Lísal, William R. Smith, J. Karl Johnson, and Keith E. Gubbins. Simulation of chemical reaction equilibria by the reaction ensemble Monte Carlo method: A review. Molecular Simulation, 34(2):119–146, 2008. doi:10.1080/08927020801986564.

+
+
69
+

S. Tyagi, A. Arnold, and C. Holm. ICMMM2D: an accurate method to include planar dielectric interfaces via image charge summation. The Journal of Chemical Physics, 127:154723, 2007. doi:10.1063/1.2790428.

+
+
70
+

Sandeep Tyagi, Axel Arnold, and Christian Holm. Electrostatic layer correction with image charges: a linear scaling method to treat slab 2D + h systems with dielectric interfaces. The Journal of Chemical Physics, 129(20):204102, 2008. doi:10.1063/1.3021064.

+
+
71
+

Sandeep Tyagi, Mehmet Süzen, Marcello Sega, Marcia C. Barbosa, Sofia S. Kantorovich, and Christian Holm. An iterative, fast, linear-scaling method for computing induced charges on arbitrary dielectric boundaries. The Journal of Chemical Physics, 132:154112, 2010. doi:10.1063/1.3376011.

+
+
72
+

Florian Weik, Rudolf Weeber, Kai Szuttor, Konrad Breitsprecher, Joost de Graaf, Michael Kuron, Jonas Landsgesell, Henri Menke, David Sean, and Christian Holm. ESPResSo 4.0 – an extensible software package for simulating soft matter systems. The European Physical Journal Special Topics, 227(14):1789–1816, 2019. doi:10.1140/epjst/e2019-800186-9.

+
+
73
+

B. Widom. Some topics in the theory of fluids. The Journal of Chemical Physics, 39(11):2802–2812, 1963. doi:10.1063/1.1734110.

+
+
74
+

S. Yaghoubi, E. Shirani, A. R. Pishevar, and Y. Afshar. New modified weight function for the dissipative force in the DPD method to increase the Schmidt number. EPL (Europhysics Letters), 110(2):24002, 2015. doi:10.1209/0295-5075/110/24002.

+
+
+

+
+ + +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/doc4.2.2/community.html b/doc4.2.2/community.html new file mode 100644 index 0000000000..b989d6c618 --- /dev/null +++ b/doc4.2.2/community.html @@ -0,0 +1,124 @@ + + + + + + + + + 21. Community — ESPResSo 4.2.2 documentation + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +
+

21. Community

+
+

21.1. Community support

+

If you have any questions concerning ESPResSo which you cannot resolve by +yourself, you may search for an answer on:

+ +

If you still didn’t find a solution, you may consider either opening a new +issue or discussion on GitHub, or sending an email on the mailing list. +Instructions on how to register to the mailing lists and post messages can be +found in Mailing Lists. +It is recommended to use these communication channels rather than to contact +individual developers, for several reasons:

+
    +
  • All users get your message and you have a higher +probability that it is answered soon.

  • +
  • Your question and the answers are archived and the archives can be +searched by others.

  • +
  • The answer may be useful also to other users.

  • +
  • There may not be a unique answer to your problem and it may be useful +to get suggestions from different people.

  • +
+

Please remember that this is a community mailing list and a community GitHub +forum. It is other users and developers who are answering your questions. +They do it in their free time and are not paid for doing it.

+
+
+

21.2. Summer Schools

+

Every year in October, a 5-day workshop is organized at University of Stuttgart, Germany. +Registration is free of charge and is managed by CECAM. +Past events are archived on the ESPResSo official website, under Summer Schools. +The teaching material can be found in the online documentation, section +Tutorials. The lectures +can be found on the ESPResSo Simulation Package YouTube channel.

+
+
+ + +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/doc4.2.2/constraints.html b/doc4.2.2/constraints.html new file mode 100644 index 0000000000..fe5988a448 --- /dev/null +++ b/doc4.2.2/constraints.html @@ -0,0 +1,555 @@ + + + + + + + + + 12. Single particle forces (constraints) — ESPResSo 4.2.2 documentation + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +
+

12. Single particle forces (constraints)

+

espressomd.constraints.Constraint

+

A Constraint is an immobile surface which can interact with particles via a +non-bonded potential, where the distance between the two particles is +replaced by the distance of the center of the particle to the surface.

+

The constraints are identified like a particle via its type particle_type for the +non-bonded interaction. After a type is defined for each constraint one +has to define the interaction of all different particle types with the +constraint using the espressomd.interactions.NonBondedInteractions class.

+
+

12.1. Shaped-based constraints

+

In order to use shapes you first have to import the espressomd.shapes +module. This module provides classes for the different available shapes:

+
import espressomd.shapes
+
+
+

Shapes define geometries which can be used in ESPResSo either as +constraints in particle interactions or as a boundary for a +lattice-Boltzmann fluid.

+

To avoid unexpected behavior, make sure all parts of your shape are +within the central box since the distance to the shape is calculated only +within the central box. If parts of the shape are placed outside of the +central box, these parts are truncated by the box boundaries. This may +be desired as for example in the case of a cylinder shape whose end caps +could extend outside the box boundaries to create an infinite rod.

+

In addition, particles will not interact with periodic images of shapes, +therefore make sure the shapes are not too close to any of the six sides +of the box. If the distance between the shape and the nearest box boundary +is less than the interaction cutoff, the potential will be discontinuous +when the particle crosses that periodic boundary.

+

A shape is instantiated by calling its constructor. If you wanted to +create a wall shape you could do:

+
wall = espressomd.shapes.Wall()
+
+
+

Available shapes are listed below.

+ +
+

12.1.1. Adding shape-based constraints to the system

+

Usually you want to use constraints based on a shape. +The module espressomd.constraints provides the class +espressomd.constraints.ShapeBasedConstraint:

+
shape_constraint = espressomd.constraints.ShapeBasedConstraint(shape=my_shape)
+
+
+

In order to add the constraint to the system +invoke the add() method:

+
system.constraints.add(shape_constraint)
+
+
+

All previously listed shapes can be added to the system constraints +by passing an initialized shape object to add(), returning a constraint object

+
misshaped = Wall(dist=20, normal=[0.1, 0.0, 1])
+myConstraint = system.constraints.add(shape=myShape, particle_type=p_type)
+
+
+

The extra argument particle_type specifies the non-bonded interaction to be used with +that constraint.

+

There are two additional optional parameters +to fine-tune the behavior of the constraint. If penetrable is set to +True then particles can move through the constraint. In this case the +other option only_positive controls where the particle is subjected to the +interaction potential (see Available options). +If the penetrable option is ignored or is set to False, the +constraint cannot be violated, i.e. no +particle can go through the constraint surface (ESPResSo will exit if any does). +If we wanted to add a non-penetrable pore constraint to our simulation, +we could do the following:

+
pore = espressomd.shapes.SimplePore(
+    axis=[1, 0, 0], length=2, pos=[15, 15, 15], radius=1, smoothing_radius=0.5)
+pore_constraint = espressomd.constraints.ShapeBasedConstraint(
+    shape=pore, penetrable=False, particle_type=1)
+system.constraints.add(pore_constraint)
+
+
+

Interactions between the pore and other particles are then defined +as usual (Non-bonded interactions) to prevent particles from crossing +the shape surface.

+
+
+

12.1.2. Deleting a constraint

+

Constraints can be removed in a similar fashion using espressomd.constraints.Constraints.remove()

+
system.constraints.remove(myConstraint)
+
+
+

This command will delete the specified constraint.

+
+
+

12.1.3. Getting the currently defined constraints

+

One can iterate through constraints, for example

+
>>> for c in system.constraints:
+...     print(c.shape)
+
+
+

will print the shape information for all defined constraints.

+
+
+

12.1.4. Getting the force on a constraint

+

espressomd.constraints.ShapeBasedConstraint.total_force()

+

Returns the force acting on the constraint. Note, however, that this is +only due to forces from interactions with particles, not with other +constraints. Also, these forces still do not mean that the constraints +move, they are just the negative of the sum of forces acting on all +particles due to this constraint. Similarly, the total energy does not +contain constraint-constraint contributions.

+

For example the pressure from wall

+
>>> p = system.constraints[0].total_force()
+>>> print(p)
+
+
+
+
+

12.1.5. Getting the minimal distance to a constraint

+

espressomd.constraints.ShapeBasedConstraint.min_dist()

+

Calculates the smallest distance to all interacting +constraints that can be repulsive (wall, cylinder, sphere, rhomboid, +pore, slitpore). Negative distances mean that the position is +within the area that particles should not access. Helpful to find +initial configurations.

+
+
+

12.1.6. Available shapes

+

espressomd.shapes

+

Python syntax:

+
import espressomd.shapes
+shape = espressomd.shapes.<SHAPE>
+
+
+

<SHAPE> can be any of the available shapes.

+

The surface’s geometry is defined via a few available shapes. +The following shapes can be used as constraints.

+
+

Warning

+

When using shapes with concave edges and corners, the fact that a particle +only interacts with the closest point on the constraint surface leads to discontinuous +force fields acting on the particles. This breaks energy conservation in otherwise +symplectic integrators. Often, the total energy of the system increases exponentially.

+
+
+

12.1.6.1. Wall

+

espressomd.shapes.Wall

+

An infinite plane defined by the normal vector normal +and the distance dist from the origin (in the direction of the normal vector). +The force acts in the direction of the normal. +Note that dist describes the distance from the origin in units of the normal +vector so that the product of dist and normal is a point on the surface. +Therefore negative distances are quite common!

+
+Visualization of a constraint with a Wall shape. +
+

Pictured is an example constraint with a Wall shape created with

+
wall = Wall(dist=20, normal=[0.1, 0.0, 1])
+system.constraints.add(shape=wall, particle_type=0)
+
+
+

For penetrable walls, if the only_positive flag is set to True, interactions +are only calculated if the particle is on the side of the wall in which the +normal vector is pointing.

+
+
+

12.1.6.2. Sphere

+

espressomd.shapes.Sphere

+

A sphere with center center and radius radius. +The direction direction determines the force direction, -1 for inward +and +1 for outward.

+
+Visualization of a constraint with a Sphere shape. +
+

Pictured is an example constraint with a Sphere shape created with

+
sphere = Sphere(center=[25, 25, 25], radius=15, direction=1)
+system.constraints.add(shape=sphere, particle_type=0)
+
+
+
+
+

12.1.6.3. Ellipsoid

+

espressomd.shapes.Ellipsoid

+

An ellipsoid with center center, semiaxis a along the symmetry axis and +equatorial semiaxes b. The symmetry axis is aligned parallel to the x-axis. +The direction direction determines the force direction, -1 for inward and +1 for outward. +The distance to the surface is determined iteratively via Newton’s method.

+
+Visualization of a constraint with an Ellipsoid shape. +
+

Pictured is an example constraint with an Ellipsoid shape created with

+
ellipsoid = Ellipsoid(center=[25, 25, 25], a=25, b=15)
+system.constraints.add(shape=ellipsoid, particle_type=0)
+
+
+
+
+

12.1.6.4. Cylinder

+

espressomd.shapes.Cylinder

+

A cylinder with center center, radius radius and length length. +The axis parameter is a vector along the cylinder axis, which is normalized in the program. +The direction direction determines the force direction, -1 for inward and +1 for outward.

+
+Visualization of a constraint with a Cylinder shape. +
+

Pictured is an example constraint with a Cylinder shape created with

+
cylinder = Cylinder(center=[25, 25, 25],
+                    axis=[1, 0, 0],
+                    direction=1,
+                    radius=10,
+                    length=30)
+system.constraints.add(shape=cylinder, particle_type=0)
+
+
+
+
+

12.1.6.5. Rhomboid

+

espressomd.shapes.Rhomboid

+

A rhomboid or parallelepiped, defined by one corner located at corner +and three adjacent edges, defined by the three vectors connecting the +corner corner with its three neighboring corners: a, b and c. +The direction direction determines the force direction, -1 for inward and +1 for outward.

+
rhomboid = Rhomboid(corner=[5.0, 5.0, 5.0],
+                    a=[1.0, 1.0, 0.0],
+                    b=[0.0, 0.0, 1.0],
+                    c=[0.0, 1.0, 0.0],
+                    direction=1)
+system.constraints.add(shape=rhomboid, particle_type=0, penetrable=True)
+
+
+

creates a rhomboid defined by one corner located at [5.0, 5.0, 5.0] and three +adjacent edges, defined by the three vectors connecting the corner with its three neighboring corners, (1,1,0) , (0,0,1) and (0,1,0).

+
+
+

12.1.6.6. SimplePore

+

espressomd.shapes.SimplePore

+

Two parallel infinite planes, connected by a cylindrical orifice. The cylinder +is connected to the planes by torus segments with an adjustable radius.

+

Length and radius of the cylindrical pore can be set via the corresponding parameters +length and radius. The parameter center defines the central point of the pore. +The orientation of the pore is given by the vector axis, which points along the cylinder’s symmetry axis. +The pore openings are smoothed with radius smoothing_radius.

+
+Visualization of a constraint with a SimplePore shape. +
+

Pictured is an example constraint with a SimplePore shape created with

+
pore = SimplePore(axis=[1, 0, 0],
+                  length=15,
+                  radius=12.5,
+                  smoothing_radius=2,
+                  center=[25, 25, 25])
+system.constraints.add(shape=pore, particle_type=0, penetrable=True)
+
+
+

Note: in the OpenGL visualizer, if the OpenGL Extrusion library is not available, +the smooth pore openings will be rendered using a sliced torus. You can safely +ignore this visual artifact, it has no impact on the force/energy calculation.

+
+
+

12.1.6.7. Slitpore

+

espressomd.shapes.Slitpore

+

A T-shaped channel that extends in the z-direction. +The cross sectional geometry is depicted in Fig. schematic. +It is translationally invariant in y direction.

+

The region is described as a pore (lower vertical part of the “T”-shape) and a channel (upper horizontal part of the “T”-shape).

+
+Schematic for the Slitpore shape with labeled geometrical parameters. +
+

The parameter channel_width specifies the distance between the top and the plateau edge. +The parameter pore_length specifies the distance between the bottom and the plateau edge. +The parameter pore_width specifies the distance between the two plateau edges, it is the space between the left and right walls of the pore region. +The parameters pore_mouth and dividing_plane specify the location in the z-coordinate resp. x-coordinate of the pore opening.

+

All the edges are smoothed via the parameters upper_smoothing_radius (for the concave corner at the edge of the plateau region) and lower_smoothing_radius (for the convex corner at the bottom of the pore region). +The meaning of the geometrical parameters can be inferred from the schematic in Fig. slitpore.

+
+Visualization of a constraint with a Slitpore shape. +
+

Pictured is an example constraint with a Slitpore shape created with

+
slitpore = Slitpore(channel_width=15,
+                    lower_smoothing_radius=1.5,
+                    upper_smoothing_radius=2,
+                    pore_length=20,
+                    pore_mouth=30,
+                    pore_width=5,
+                    dividing_plane=25)
+
+system.constraints.add(shape=slitpore, particle_type=0, penetrable=True)
+
+
+
+
+

12.1.6.8. SpheroCylinder

+

espressomd.shapes.SpheroCylinder

+

A cylinder capped by hemispheres on both ends. Generates a capsule, pill, or spherocylinder depending on the choice of parameters. +Similar to espressomd.shapes.Cylinder, it is positioned at center and has a radius radius. +The length parameter is the cylinder length, and does not include the contribution from the hemispherical ends. +The axis parameter is a vector along the cylinder axis, which is normalized in the program. +The direction direction determines the force direction, -1 for inward and +1 for outward.

+
+Visualization of a constraint with a SpheroCylinder shape. +
+

Pictured is an example constraint with a SpheroCylinder shape created with

+
spherocylinder = SpheroCylinder(center=[25, 25, 25],
+                                axis=[1, 0, 0],
+                                direction=1,
+                                radius=10,
+                                length=30)
+system.constraints.add(shape=spherocylinder, particle_type=0)
+
+
+
+
+

12.1.6.9. Torus

+

espressomd.shapes.Torus

+

It is positioned at center and has a radius radius with tube radius tube_radius. +The normal parameter is the torus rotation axis, which is normalized in the program. +The direction direction determines the force direction, -1 for inward and +1 for outward.

+
+Visualization of a constraint with a Torus shape. +
+

Pictured is an example constraint with a Torus shape created with

+
torus = Torus(center=[25, 25, 25], normal=[1, 1, 1],
+              direction=1, radius=15, tube_radius=6)
+system.constraints.add(shape=torus, particle_type=0)
+
+
+
+
+

12.1.6.10. HollowConicalFrustum

+

espressomd.shapes.HollowConicalFrustum

+

A hollow cone with round corners. +Can include an opening in the side (see figures below). The specific parameters +are described in the shape’s class espressomd.shapes.HollowConicalFrustum.

+
+Visualization of a constraint with a HollowConicalFrustum shape. +
+
+Visualization a HollowConicalFrustum shape with central angle +
+
+Schematic for the HollowConicalFrustum shape with labeled geometrical parameters. +
+

Note: in the OpenGL visualizer, if the OpenGL Extrusion library is not available, +the shape surface will be rendered with dots.

+
+
+

12.1.6.11. Union

+

espressomd.shapes.Union

+

A meta-shape which is the union of given shapes. Note that only the regions where +all shapes have a “positive distance” (see Available options) can be used for the +union. The distance to the union is defined as the minimum distance to any contained shape. +This shape cannot be checkpointed when multiple MPI ranks are used.

+
+
+
+

12.1.7. Available options

+

There are some options to help control the behavior of shaped-based +constraints. Some of the options, like direction need to be specified for +the shape espressomd.shapes, and some options are specified for the +constraint espressomd.constraints.ShapeBasedConstraint. We will +discuss them together in this section in the context of a specific example.

+

The direction option typically specifies which volumes are inside versus +outside the shape. Consider a constraint based on the sphere shape. If one +wishes to place particles inside the sphere, one would usually use +direction=-1, if one wishes to place particles outside, one would use +direction=1. In this example, we place a sphere centre at position +(25,0,0). A particle is continuously displaced on the x-axis in order to probe +the effect of different options. For this, we need to first define a repulsive +interaction between the probe and the constraint.

+

The plot below demonstrates how the distance between the probe and the +constraint surface is calculated when the distance option is toggled +between direction=1 and direction=-1. In the plot, a schematic of a +circle centered at x=25 is used to represent the spherical constraint.

+
+Distance measure from an example spherical constraint. +
+

When the option direction=1 is used for the sphere shape, positive +distances are measured whenever the particle is outside the sphere and negative +distances are measured whenever the particle is inside the sphere. Conversely, +when the option direction=-1 is used for the sphere shape, negative +distances are measured whenever the particle is outside the sphere and positive +distances are measured whenever the particle is inside the sphere. In other +words, this option helps defines the sign of the normal surface vector.

+

For now, this may not sound useful but it can be practical when used with +together with constraint options such as penetrable or only_positive. +In the former case, using non-penetrable surfaces with penetrable=False will +cause ESPResSo to throw an error is any distances between interacting particles and +constraints are found to be negative. This can be used to stop a simulation if +for one reason or another particles end up in an unwanted location.

+

The only_positive constraint option is used to define if a force should be +applied to a particle that has a negative distance. For example, consider the +same probe particle as in the previous case. The plot below shows the particle +force with only_positive=True. Notice that when the distance is negative, +forces are not applied at all to the particle. Thus the constraint surface is +either purely radially outwards (when direction=1) or radially inwards +(when direction=-1). Note that in both cases the constraint was set to be +penetrable with penetrable=True or else the simulation would crash whenever +the particle was found in any location that yields a negative distance.

+
+Force measure from an example spherical constraint. +
+

The next figure shows what happens if we turn off the only_positive flag by +setting only_positive=False. In this case the particle is pushed radially +inward if it is inside the sphere and radially outward if it is outside. As +with the previous example, the constraint was set to be penetrable for this to +make sense.

+
+Force measure from an example spherical constraint. +
+

Most shapes have a clear interpretation of what is inside versus outside with +the exception of a planar wall. For this, there is no direction option, but +the normal vector of the wall points in the direction that is considered to +yield positive distances. Outside their use in constraints, shapes can also be +used as a way to define LB boundary nodes. In this case, negative distances +define nodes which are part of a boundary (please refer to Using shapes as lattice-Boltzmann boundary).

+
+
+
+

12.2. External Fields

+

There is a variety of external fields, which differ by how their +values are obtained and how they couple to particles.

+
+

12.2.1. Constant fields

+

These are fields that are constant in space or simple linear functions +of the position. The available fields are:

+ +

A detailed description can be found in the class documentation.

+

Please be aware of the fact that a constant per-particle force can be +set via the ext_force property of the particles and is not provided +here.

+
+
+

12.2.2. Interpolated Force and Potential fields

+

The values of these fields are obtained by interpolating table data, +which has to be provided by the user. The fields differ by how +they couple to particles, for a detailed description see their respective +class documentation.

+ +
+
+
+ + +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/doc4.2.2/contributing.html b/doc4.2.2/contributing.html new file mode 100644 index 0000000000..eb13a8eafc --- /dev/null +++ b/doc4.2.2/contributing.html @@ -0,0 +1,148 @@ + + + + + + + + + 22. Contributing — ESPResSo 4.2.2 documentation + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +
+

22. Contributing

+

Up to date information about the development of ESPResSo can be found in the +ESPResSo wiki:

+
    +
  • proceedings of the ESPResSo meetings

  • +
  • list of planned releases

  • +
  • developer’s guide

  • +
+

The official website at https://espressomd.org provides additional information:

+
    +
  • Latest stable release of ESPResSo and older releases

  • +
  • Obtaining development version of ESPResSo

  • +
  • Archives of both developers’ and users’ mailing lists

  • +
  • Registering to mailing lists

  • +
+
+

22.1. Contributing your own code

+

If you are planning to make an extension to or already have a piece of +your own code which could be useful to others, you are very welcome to +contribute it to the community. Before you start making any changes to +the code, you should fork the espressomd/espresso repository and work in a new branch.

+

It is also generally a good idea to contact the developers on the mailing lists +before you start major coding projects. It might be that someone else is already +working on the problem or has a solution at hand.

+

You will find more detailed information on our development processes in +Contributing to ESPResSo. +Please also refer to our developer’s guide in the +ESPResSo wiki.

+
+

22.1.1. Required Development Tools

+
    +
  • First of all, please install the dependencies for compiling ESPResSo. +See the section Installation.

  • +
  • To be able to access the development version of ESPResSo, you will need the +distributed versioning control system git and a GitHub account to fork the +espressomd/espresso repository

  • +
  • To build the user documentation, you will need Sphinx.

  • +
  • To build the tutorials, you will need Jupyter.

  • +
  • To build the core documentation, you will need Doxygen.

  • +
+

All of these tools should be easy to install on most Unix operating systems.

+

You can find all Python dependencies of ESPResSo in requirements.txt in the +top-level source directory. Several optional packages for graphics, external +devices and continuous integration (CI) are not strictly essential and can be +safely removed if you’re planning on installing dependencies via pip:

+
pip3 install --upgrade --user -r requirements.txt
+
+
+

Note that some distributions now use pip3 for Python3 and pip2 for +Python2.

+
+
+
+

22.2. Building the User’s guide

+

If, while reading this documentation, you notice any mistakes or +undocumented features, you are very welcome to +contribute to the guide and have others benefit from your knowledge.

+

For this, you should clone the development version at espressomd/espresso. Next build the software as shown +in Installation and then the documentation with make sphinx.

+
+
+ + +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/doc4.2.2/ek.html b/doc4.2.2/ek.html new file mode 100644 index 0000000000..b5117aeca4 --- /dev/null +++ b/doc4.2.2/ek.html @@ -0,0 +1,375 @@ + + + + + + + + + 14. Electrokinetics — ESPResSo 4.2.2 documentation + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +
+

14. Electrokinetics

+

The electrokinetics setup in ESPResSo allows for the description of +electro-hydrodynamic systems on the level of ion density distributions +coupled to a lattice-Boltzmann (LB) fluid. The ion density distributions +may also interact with explicit charged particles, which are +interpolated on the LB grid. In the following paragraph we briefly +explain the electrokinetic model implemented in ESPResSo, before we come to the +description of the interface.

+
+

14.1. Electrokinetic equations

+

In the electrokinetics code we solve the following system of coupled +continuity, diffusion-advection, Poisson, and Navier-Stokes equations:

+
+\[\begin{split}\begin{aligned} +\label{eq:ek-model-continuity} \frac{\partial n_k}{\partial t} & = & -\, \nabla \cdot \vec{j}_k \vphantom{\left(\frac{\partial}{\partial}\right)} ; \\ +\label{eq:ek-model-fluxes} \vec{j}_{k} & = & -D_k \nabla n_k - \nu_k \, q_k n_k\, \nabla \Phi + n_k \vec{v}_{\mathrm{fl}} \vphantom{\left(\frac{\partial}{\partial}\right)} + \sqrt{n_k}\vec{\mathcal{W}}_k; \\ +\label{eq:ek-model-poisson} \Delta \Phi & = & -4 \pi \, {l_\mathrm{B}}\, {k_\mathrm{B}T}\sum_k q_k n_k \vphantom{\left(\frac{\partial}{\partial}\right)}; \\ +\nonumber \left(\frac{\partial \vec{v}_{\mathrm{fl}}}{\partial t} + \vec{v}_{\mathrm{fl}} \cdot \nabla \vec{v}_{\mathrm{fl}} \right) \rho_\mathrm{fl} & = & -{k_\mathrm{B}T}\, \nabla \rho_\mathrm{fl} - q_k n_k \nabla \Phi \\ +\label{eq:ek-model-velocity} & & +\, \eta \Delta \vec{v}_{\mathrm{fl}} + (\eta / 3 + \eta_{\text{b}}) \nabla (\nabla \cdot \vec{v}_{\mathrm{fl}}) \vphantom{\left(\frac{\partial}{\partial}\right)} ; \\ +\label{eq:ek-model-continuity-fl} \frac{\partial \rho_\mathrm{fl}}{\partial t} & = & -\,\nabla\cdot\left( \rho_\mathrm{fl} \vec{v}_{\mathrm{fl}} \right) \vphantom{\left(\frac{\partial}{\partial}\right)} , \end{aligned}\end{split}\]
+

which define relations between the following observables

+
+
\(n_k\)

the number density of the particles of species \(k\),

+
+
\(\vec{j}_k\)

the number density flux of the particles of species \(k\),

+
+
\(\Phi\)

the electrostatic potential,

+
+
\(\rho_{\mathrm{fl}}\)

the mass density of the fluid,

+
+
\(\vec{v}_{\mathrm{fl}}\)

the advective velocity of the fluid,

+
+
+

and input parameters

+
+
\(D_k\)

the diffusion constant of species \(k\),

+
+
\(\nu_k\)

the mobility of species \(k\),

+
+
\(\vec{\mathcal{W}}_k\)

the white-noise term for the fluctuations of species \(k\),

+
+
\(q_k\)

the charge of a single particle of species \(k\),

+
+
\({l_\mathrm{B}}\)

the Bjerrum length,

+
+
\({k_\mathrm{B}T}\)
+
the thermal energy given by the product of Boltzmann’s constant +\(k_\text{B}\)
+
and the temperature \(T\),
+
+
+
\(\eta\)

the dynamic viscosity of the fluid,

+
+
\(\eta_{\text{b}}\)

the bulk viscosity of the fluid.

+
+
+

The temperature \(T\), and diffusion constants \(D_k\) and +mobilities \(\nu_k\) of individual species are linked through the +Einstein-Smoluchowski relation \(D_k / +\nu_k = {k_\mathrm{B}T}\). This system of equations +combining diffusion-advection, electrostatics, and hydrodynamics is +conventionally referred to as the Electrokinetic Equations.

+

The electrokinetic equations have the following properties:

+
    +
  • On the coarse time and length scale of the model, the dynamics of the +particle species can be described in terms of smooth density +distributions and potentials as opposed to the microscale where +highly localized densities cause singularities in the potential.

    +

    In most situations, this restricts the application of the model to +species of monovalent ions, since ions of higher valency typically +show strong condensation and correlation effects – the localization +of individual ions in local potential minima and the subsequent +correlated motion with the charges causing this minima.

    +
  • +
  • Only the entropy of an ideal gas and electrostatic interactions are +accounted for. In particular, there is no excluded volume.

    +

    This restricts the application of the model to monovalent ions and +moderate charge densities. At higher valencies or densities, +overcharging and layering effects can occur, which lead to +non-monotonic charge densities and potentials, that can not be +covered by a mean-field model such as Poisson–Boltzmann or this one.

    +

    Even in salt free systems containing only counter ions, the +counter-ion densities close to highly charged objects can be +overestimated when neglecting excluded volume effects. Decades of the +application of Poisson–Boltzmann theory to systems of electrolytic +solutions, however, show that those conditions are fulfilled for +monovalent salt ions (such as sodium chloride or potassium chloride) +at experimentally realizable concentrations.

    +
  • +
  • Electrodynamic and magnetic effects play no role. Electrolytic +solutions fulfill those conditions as long as they don’t contain +magnetic particles.

  • +
  • The diffusion coefficient is a scalar, which means there can not be +any cross-diffusion. Additionally, the diffusive behavior has been +deduced using a formalism relying on the notion of a local +equilibrium. The resulting diffusion equation, however, is known to +be valid also far from equilibrium.

  • +
  • The temperature is constant throughout the system.

  • +
  • The density fluxes instantaneously relax to their local equilibrium +values. Obviously one can not extract information about processes on +length and time scales not covered by the model, such as dielectric +spectra at frequencies, high enough that they correspond to times +faster than the diffusive time scales of the charged species.

  • +
+
+
+

14.2. Setup

+
+

14.2.1. Initialization

+

Electrokinetics is used to initialize +the LB fluid of the EK method:

+
import espressomd
+import espressomd.electrokinetics
+system = espressomd.System(box_l=[10.0, 10.0, 10.0])
+system.time_step = 0.0
+system.cell_system.skin = 0.4
+ek = espressomd.electrokinetics.Electrokinetics(agrid=1.0, lb_density=1.0,
+    viscosity=1.0, ext_force_density = [1,0,0], friction=1.0, T=1.0, prefactor=1.0,
+    stencil='linkcentered', advection=True, fluid_coupling='friction')
+system.actors.add(ek)
+
+
+
+

Note

+

Features ELECTROKINETICS and CUDA required

+
+

It is very similar to the lattice-Boltzmann command in set-up. +We therefore refer the reader to chapter Lattice-Boltzmann +for details on the implementation of LB in ESPResSo and describe only +the major differences here.

+

The first major difference with the LB implementation is that the +electrokinetics set-up is a GPU-only implementation. A CPU version +will become available in the 4.3 line of ESPResSo. To use the electrokinetics +features it is therefore imperative that your computer contains +a CUDA-capable GPU.

+

To set up a proper LB fluid using this command, one has to specify at +least the following options: agrid, lb_density, viscosity, +friction, T, and prefactor. The other options can be +used to modify the behavior of the LB fluid. Note that the command does +not allow the user to set the time step parameter as is the case for the +lattice-Boltzmann command, this parameter is instead taken directly from +the value set for time_step. +The LB mass density is set independently from the +electrokinetic number densities, since the LB fluid serves only as a +medium through which hydrodynamic interactions are propagated, as will +be explained further in the next paragraph. If no lb_density is specified, then our +algorithm assumes lb_density= 1.0. The two ‘new’ parameters are the temperature T at +which the diffusive species are simulated and the prefactor +associated with the electrostatic properties of the medium. See the +above description of the electrokinetic equations for an explanation of +the introduction of a temperature, which does not come in directly via a +thermostat that produces thermal fluctuations.

+

advection can be set to True or False. It controls whether there should be an +advective contribution to the diffusive species’ fluxes. Default is +True.

+

fluid_coupling can be set to "friction" or "estatics". +This option determines the force term acting on the fluid. +The former specifies the force term to be the +sum of the species fluxes divided by their respective mobilities while +the latter simply uses the electrostatic force density acting on all +species. Note that this switching is only possible for the "linkcentered" +stencil. For all other stencils, this choice is hardcoded. The default +is "friction".

+

es_coupling enables the action of the electrostatic potential due to the +electrokinetics species and charged boundaries on the MD particles. The +forces on the particles are calculated by interpolation from the +electric field which is in turn calculated from the potential via finite +differences. This only includes interactions between the species and +boundaries and MD particles, not between MD particles and MD particles. +To get complete electrostatic interactions a particles Coulomb method +like Ewald or P3M has to be activated too.

+

The fluctuation of the EK species can be turned on by the flag fluctuations. +This adds a white-noise term to the fluxes. The amplitude of this noise term +can be controlled by fluctuation_amplitude. To circumvent that these fluctuations +lead to negative densities, they are modified by a smoothed Heaviside function, +which decreases the magnitude of the fluctuation for densities close to 0. +By default the fluctuations are turned off.

+

Another difference with LB is that EK parameters are immutables, +and the EK object cannot be checkpointed.

+
+
+

14.2.2. Diffusive species

+
species = espressomd.electrokinetics.Species(density=density, D=D, valency=valency,
+    ext_force_density=ext_force)
+
+
+

Species is used to initialize a diffusive species. Here the +options specify: the number density density, the diffusion coefficient D, the +valency of the particles of that species valency, and an optional external +(electric) force which is applied to the diffusive species. As mentioned +before, the LB density is completely decoupled from the electrokinetic +densities. This has the advantage that greater freedom can be achieved +in matching the internal parameters to an experimental system. Moreover, +it is possible to choose parameters for which the LB is more stable. +The species can be added to a LB fluid:

+
ek.add_species(species)
+
+
+

One can also add the species during the initialization step of the +Electrokinetics class by defining +the list variable species:

+
ek = espressomd.electrokinetics.Electrokinetics(species=[species], ...)
+
+
+

The variables density, D, and +valency must be set to properly initialize the diffusive species; the +ext_force_density is optional.

+
+
+

14.2.3. EK boundaries

+

EKBoundary is used to set up +internal (or external) boundaries for the electrokinetics algorithm in much +the same way as the LBBoundary class is +used for the LB fluid:

+
ek_boundary = espressomd.ekboundaries.EKBoundary(charge_density=1.0, shape=my_shape)
+system.ekboundaries.add(ek_boundary)
+
+
+
+

Note

+

Feature EK_BOUNDARIES required

+
+

The major difference with the LB class is the option charge_density, +with which a boundary can be endowed with a volume charge density. +To create a surface charge density, a combination of two +oppositely charged boundaries, one inside the other, can be used. However, +care should be taken to maintain the surface charge density when the value of agrid +is changed. Examples for possible shapes are wall, sphere, ellipsoid, cylinder, +rhomboid and hollow conical frustum. We refer to the documentation of the +espressomd.shapes module for more possible shapes and information on +the options associated to these shapes. In order to properly set up the +boundaries, the charge_density and shape must be specified.

+
+
+

14.2.4. Output

+
+

14.2.4.1. Fields

+
ek.write_vtk_boundary(path)
+ek.write_vtk_density(path)
+ek.write_vtk_velocity(path)
+ek.write_vtk_potential(path)
+
+
+

A property of the fluid field can be exported into a file in one go. +Currently supported fields are: density, velocity, potential and boundary, +which give the LB fluid density, the LB fluid velocity, +the electrostatic potential, and the location and type of the +boundaries, respectively. The boundaries can only be printed when the +EK_BOUNDARIES is compiled in. The output is a vtk-file, which is readable by +visualization software such as ParaView 5 and Mayavi2 6.

+
species.write_vtk_flux(path)
+species.write_vtk_density(path)
+
+
+

These commands are similar to the above. They enable the +export of diffusive species properties, namely: density and flux, which specify the +number density and flux of species species, respectively.

+
+
+

14.2.4.2. Local quantities

+

Local quantities like velocity or fluid density for single nodes can be accessed in the same way +as for an LB fluid, see Lattice-Boltzmann. The only EK-specific quantity is the potential.

+
ek[0, 0, 0].potential
+ek[0, 0, 0].velocity
+ek[0, 0, 0].boundary
+
+
+

The local density and flux of a species can be obtained in the same fashion:

+
species[0, 0, 0].density
+species[0, 0, 0].flux
+
+
+
+
5
+

https://www.paraview.org/

+
+
6
+

http://code.enthought.com/projects/mayavi/

+
+
+
+
+
+
+ + +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/doc4.2.2/electrostatics.html b/doc4.2.2/electrostatics.html new file mode 100644 index 0000000000..429fadd9d6 --- /dev/null +++ b/doc4.2.2/electrostatics.html @@ -0,0 +1,449 @@ + + + + + + + + + 9. Electrostatics — ESPResSo 4.2.2 documentation + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +
+

9. Electrostatics

+

The Coulomb (or electrostatic) interaction is defined as +follows. For a pair of particles at distance \(r\) with charges +\(q_1\) and \(q_2\), the interaction is given by

+
+\[U_C(r)=C \cdot \frac{q_1 q_2}{r}\]
+

where

+
+(1)\[C=\frac{1}{4\pi \varepsilon_0 \varepsilon_r}\]
+

is a prefactor which can be set by the user. The commonly used Bjerrum length +\(l_B = e^2 / (4 \pi \varepsilon_0 \varepsilon_r k_B T)\) is the length at +which the Coulomb energy between two unit charges is equal to the thermal +energy \(k_B T\). +Based on this length, the prefactor is given by \(C=l_B k_B T / e^2\).

+

Computing electrostatic interactions is computationally very expensive. +ESPResSo features some state-of-the-art algorithms to deal with these +interactions as efficiently as possible, but almost all of them require +some knowledge to use them properly. Uneducated use can result in +completely unphysical simulations.

+

Coulomb interactions have to be added to the list of active actors of the system object to become +active. This is done by calling the add-method of espressomd.system.System.actors. +Only one electrostatics method can be active at any time.

+

Note that using the electrostatic interaction also requires assigning charges to +the particles via the particle property +q.

+

All solvers need a prefactor and a set of other required parameters. +This example shows the general usage of the electrostatic method P3M. +An instance of the solver is created and added to the actors list, at which +point it will be automatically activated. This activation will internally +call a tuning function to achieve the requested accuracy:

+
import espressomd
+import espressomd.electrostatics
+
+system = espressomd.System(box_l=[10, 10, 10])
+system.time_step = 0.01
+system.part.add(pos=[[0, 0, 0], [1, 1, 1]], q=[-1, 1])
+solver = espressomd.electrostatics.P3M(prefactor=2., accuracy=1e-3)
+system.actors.add(solver)
+
+
+

where the prefactor is defined as \(C\) in Eqn. (1).

+

The list of actors can be cleared with +system.actors.clear() and +system.actors.remove(actor).

+
+

9.1. Coulomb P3M

+

espressomd.electrostatics.P3M

+

For this feature to work, you need to have the fftw3 library +installed on your system. In ESPResSo, you can check if it is compiled in by +checking for the feature FFTW with espressomd.features. +P3M requires full periodicity (1 1 1). When using a non-metallic dielectric +constant (epsilon != 0.0), the box must be cubic. +Make sure that you know the relevance of the P3M parameters before using P3M! +If you are not sure, read the following references: +[Cerdà et al., 2008, Deserno, 2000, Deserno and Holm, 1998, Deserno and Holm, 1998, Deserno et al., 2000, Ewald, 1921, Hockney and Eastwood, 1988, Kolafa and Perram, 1992].

+
+

9.1.1. Tuning Coulomb P3M

+

It is not easy to calculate the various parameters of the P3M method +such that the method provides the desired accuracy at maximum speed. To +simplify this, it provides a function to automatically tune the algorithm. +Note that for this function to work properly, your system should already +contain an initial configuration of charges and the correct initial box size. +The tuning method is called when the handle of the Coulomb P3M is added to +the actor list. Some parameters can be fixed (r_cut, cao, mesh) +to speed up the tuning if the parameters are already known.

+

Please note that the provided tuning algorithms works very well on +homogeneous charge distributions, but might not achieve the requested +precision for highly inhomogeneous or symmetric systems. For example, +because of the nature of the P3M algorithm, systems are problematic +where most charges are placed in one plane, one small region, or on a +regular grid.

+

The function employs the analytical expression of the error estimate for +the P3M method [Hockney and Eastwood, 1988] and its real space error [Kolafa and Perram, 1992] to +obtain sets of parameters that yield the desired accuracy, then it measures how +long it takes to compute the Coulomb interaction using these parameter sets and +chooses the set with the shortest run time.

+

During tuning, the algorithm reports the tested parameter sets, +the corresponding k-space and real-space errors and the timings needed +for force calculations. In the output, the timings are given in units of +milliseconds, length scales are in units of inverse box lengths.

+
+
+

9.1.2. Coulomb P3M on GPU

+

espressomd.electrostatics.P3MGPU

+

The GPU implementation of P3M calculates the far field contribution to the +forces on the GPU. The near-field contribution to the forces, as well as the +near- and far-field contributions to the energies are calculated on the CPU. +It uses the same parameters +and interface functionality as the CPU version of the solver. +It should be noted that this does not always provide significant +increase in performance. Furthermore it computes the far field interactions +with only single precision which limits the maximum precision. +The algorithm does not work in combination with the electrostatic extension +Dielectric interfaces with the ICC* algorithm.

+

The algorithm doesn’t have kernels to compute energies, and will therefore +contribute 0 to the long-range potential energy of the system. This can be +an issue for other algorithms, such as reaction methods +and energy-based steepest descent.

+
+
+
+

9.2. Debye-Hückel potential

+

espressomd.electrostatics.DH

+

The Debye-Hückel electrostatic potential is defined by

+
+\[U^{C-DH} = C \cdot \frac{q_1 q_2 \exp(-\kappa r)}{r}\quad \mathrm{for}\quad r<r_{\mathrm{cut}}\]
+

where \(C\) is defined as in Eqn. (1) and +\(\kappa\) is the inverse Debye screening length. +The Debye-Hückel potential is an approximate method for calculating +electrostatic interactions, but technically it is treated as other +short-ranged non-bonding potentials. For \(r > r_{\textrm{cut}}\) it is +set to zero which introduces a step in energy. Therefore, it introduces +fluctuations in energy.

+

For \(\kappa = 0\), this corresponds to the plain Coulomb potential.

+
+
+

9.3. Reaction Field method

+

espressomd.electrostatics.ReactionField

+

The Reaction Field electrostatic potential is defined by

+
+\[U^{C-RF} = C \cdot q_1 q_2 \left[\frac{1}{r} - \frac{B r^2}{2r_{\mathrm{cut}}^3} - \frac{1 - B/2}{r_{\mathrm{cut}}}\right] \quad \mathrm{for}\quad r<r_{\mathrm{cut}}\]
+

where \(C\) is defined as in Eqn. (1) and \(B\) +is defined as:

+
+\[B = \frac{2(\varepsilon_1 - \varepsilon_2)(1 + \kappa r_{\mathrm{cut}}) - \varepsilon_2 (\kappa r_{\mathrm{cut}})^2}{(\varepsilon_1 + 2\varepsilon_2)(1 + \kappa r_{\mathrm{cut}}) + \varepsilon_2 (\kappa r_{\mathrm{cut}})^2}\]
+

with \(\kappa\) the inverse Debye screening length, \(\varepsilon_1\) the dielectric +constant inside the cavity and \(\varepsilon_2\) the dielectric constant +outside the cavity [Tironi et al., 1995].

+

The term in \(1 - B/2\) is a correction to make the +potential continuous at \(r = r_{\mathrm{cut}}\).

+
+
+

9.4. Dielectric interfaces with the ICC\(\star\) algorithm

+

espressomd.electrostatic_extensions.ICC

+

The ICC\(\star\) algorithm allows to take into account arbitrarily shaped +dielectric interfaces and dynamic charge induction. For instance, it can be +used to simulate a curved metallic boundary. This is done by iterating the +charge on a set of spatially fixed ICC particles until they correctly +represent the influence of the dielectric discontinuity. All ICC particles +need a certain area, normal vector and dielectric constant to fully specify the +surface. ICC relies on a Coulomb solver that is already initialized. So far, it +is implemented and well tested with the Coulomb solver P3M. ICC is an ESPResSo +actor and can be activated via:

+
import espressomd.electrostatic_extensions
+icc = espressomd.electrostatic_extensions.ICC(...)
+system.actors.add(icc)
+
+
+

The ICC particles are setup as normal ESPResSo particles. Note that they should +be fixed in space and need an initial non-zero charge. The following example +sets up parallel metallic plates and activates ICC:

+
# Set the ICC line density and calculate the number of
+# ICC particles according to the box size
+box_l = 9.
+system.box_l = [box_l, box_l, 12.]
+nicc = 3  # linear density
+nicc_per_electrode = nicc**2  # surface density
+nicc_tot = 2 * nicc_per_electrode
+iccArea = box_l**2 / nicc_per_electrode
+l = box_l / nicc
+
+# Lists to collect required parameters
+iccNormals = []
+iccAreas = []
+iccSigmas = []
+iccEpsilons = []
+
+# Add the fixed ICC particles:
+
+# Left electrode (normal [0, 0, 1])
+for xi in range(nicc):
+    for yi in range(nicc):
+        system.part.add(pos=[l * xi, l * yi, 0.], q=-0.0001,
+                        type=icc_type, fix=[True, True, True])
+iccNormals.extend([0, 0, 1] * nicc_per_electrode)
+
+# Right electrode (normal [0, 0, -1])
+for xi in range(nicc):
+    for yi in range(nicc):
+        system.part.add(pos=[l * xi, l * yi, box_l], q=0.0001,
+                        type=icc_type, fix=[True, True, True])
+iccNormals.extend([0, 0, -1] * nicc_per_electrode)
+
+# Common area, sigma and metallic epsilon
+iccAreas.extend([iccArea] * nicc_tot)
+iccSigmas.extend([0] * nicc_tot)
+iccEpsilons.extend([100000] * nicc_tot)
+
+icc = espressomd.electrostatic_extensions.ICC(
+    first_id=0,
+    n_icc=nicc_tot,
+    convergence=1e-4,
+    relaxation=0.75,
+    ext_field=[0, 0, 0],
+    max_iterations=100,
+    eps_out=1.0,
+    normals=iccNormals,
+    areas=iccAreas,
+    sigmas=iccSigmas,
+    epsilons=iccEpsilons)
+
+system.actors.add(icc)
+
+
+

With each iteration, ICC has to solve electrostatics which can severely slow +down the integration. The performance can be improved by using multiple cores, +a minimal set of ICC particles and convergence and relaxation parameters that +result in a minimal number of iterations. Also please make sure to read the +corresponding articles, mainly [Arnold et al., 2013, Kesselheim et al., 2011, Tyagi et al., 2010] before +using it.

+
+
+

9.5. Electrostatic Layer Correction (ELC)

+

espressomd.electrostatics.ELC

+

ELC is an extension of the P3M electrostatics solver for explicit 2D periodic +systems. It can account for different dielectric jumps on both sides of the +non-periodic direction. In more detail, it is a special procedure that +converts a 3D electrostatic method to a 2D method in computational order N. +The periodicity has to be set to (1 1 1). ELC cancels the electrostatic +contribution of the periodic replica in z-direction. Make sure that you +read the papers on ELC ([Arnold et al., 2002, Arnold et al., 2002, Tyagi et al., 2008]) before using it. +See ELC theory for more details.

+

Usage notes:

+
    +
  • The non-periodic direction is always the z-direction.

  • +
  • The method relies on a slab of the simulation box perpendicular to the +z-direction not to contain particles. The size in z-direction of this slab +is controlled by the gap_size parameter. The user has to ensure that +no particles enter this region by means of constraints or by fixing the +particles’ z-coordinate. When particles enter the slab of the specified +size, an error will be thrown.

  • +
+

ELC is an ESPResSo actor and is used with:

+
import espressomd.electrostatics
+p3m = espressomd.electrostatics.P3M(prefactor=1, accuracy=1e-4)
+elc = espressomd.electrostatics.ELC(actor=p3m, gap_size=box_l * 0.2, maxPWerror=1e-3)
+system.actors.add(elc)
+
+
+

Although it is technically feasible to remove elc from the list of actors +and then to add the p3m object, it is not recommended because the P3M +parameters are mutated by ELC, e.g. the epsilon is made metallic. +It is safer to instantiate a new P3M object instead of recycling one that +has been adapted by ELC.

+

ELC can also be used to simulate 2D periodic systems with image charges, +specified by dielectric contrasts on the non-periodic boundaries +([Tyagi et al., 2008]). This is achieved by setting the dielectric jump from the +simulation region (middle) to bottom (at \(z=0\)) and from middle to +top (at \(z = L_z - h\)), where \(L_z\) denotes the box length in +\(z\)-direction and \(h\) the gap size. The corresponding expressions +are \(\Delta_t=\frac{\varepsilon_m-\varepsilon_t}{\varepsilon_m+\varepsilon_t}\) +and \(\Delta_b=\frac{\varepsilon_m-\varepsilon_b}{\varepsilon_m+\varepsilon_b}\):

+
elc = espressomd.electrostatics.ELC(actor=p3m, gap_size=box_l * 0.2, maxPWerror=1e-3,
+                                    delta_mid_top=0.9, delta_mid_bot=0.1)
+
+
+

The fully metallic case \(\Delta_t=\Delta_b=-1\) would lead to divergence +of the forces/energies in ELC and is therefore only possible with the +const_pot option.

+

Toggle const_pot on to maintain a constant electric potential difference +pot_diff between the xy-planes at \(z=0\) and \(z = L_z - h\):

+
elc = espressomd.electrostatics.ELC(actor=p3m, gap_size=box_l * 0.2, maxPWerror=1e-3,
+                                    const_pot=True, delta_mid_bot=100.0)
+
+
+

This is done by countering the total dipole moment of the system with the +electric field \(E_{\textrm{induced}}\) and superposing a homogeneous +electric field \(E_{\textrm{applied}} = \frac{U}{L}\) to retain \(U\). +This mimics the induction of surface charges +\(\pm\sigma = E_{\textrm{induced}} \cdot \varepsilon_0\) +for planar electrodes at \(z=0\) and \(z=L_z - h\) in a capacitor +connected to a battery with voltage pot_diff.

+
+
+

9.6. MMM1D

+

espressomd.electrostatics.MMM1D

+
+

Note

+

Required features: ELECTROSTATICS for MMM1D, the GPU version +additionally needs the features CUDA and MMM1D_GPU.

+
+

Please cite [Arnold and Holm, 2005] when using MMM1D. See MMM1D theory for +the details.

+

MMM1D is used with:

+
import espressomd.electrostatics
+mmm1d = espressomd.electrostatics.MMM1D(prefactor=C, far_switch_radius=fr,
+                                        maxPWerror=err, tune=False, bessel_cutoff=bc)
+mmm1d = espressomd.electrostatics.MMM1D(prefactor=C, maxPWerror=err)
+
+
+

where the prefactor \(C\) is defined in Eqn. (1). +MMM1D requires for systems with periodicity (0 0 1) and the N-squared +cell system (see section Cell systems). The first form sets parameters +manually. The switch radius determines at which xy-distance the force +calculation switches from the near to the far formula. The Bessel cutoff +does not need to be specified as it is automatically determined from the +particle distances and maximal pairwise error. The second tuning form +just takes the maximal pairwise error and tries out a lot of switching +radii to find out the fastest one. If this takes too long, you can +change the value of the timings argument of the +MMM1D class, +which controls the number of test force calculations.

+
+

9.6.1. MMM1D on GPU

+

espressomd.electrostatics.MMM1DGPU

+

MMM1D is also available in a GPU implementation. Unlike its CPU +counterpart, it does not need the N-squared cell system.

+
import espressomd.electrostatics
+mmm1d = espressomd.electrostatics.MMM1DGPU(prefactor=C, far_switch_radius=fr,
+                                           maxPWerror=err, tune=False, bessel_cutoff=bc)
+mmm1d = espressomd.electrostatics.MMM1DGPU(prefactor=C, maxPWerror=err)
+
+
+

The first form sets parameters manually. The switch radius determines at which +xy-distance the force calculation switches from the near to the far +formula. If the Bessel cutoff is not explicitly given, it is determined +from the maximal pairwise error, otherwise this error only counts for +the near formula. The second tuning form just takes the maximal pairwise +error and tries out a lot of switching radii to find out the fastest one.

+

For details on the MMM family of algorithms, refer to appendix +The MMM family of algorithms.

+
+
+
+

9.7. ScaFaCoS electrostatics

+

espressomd.electrostatics.Scafacos

+

ESPResSo can use the methods from the ScaFaCoS Scalable fast Coulomb solvers +library. The specific methods available depend on the compile-time options of +the library, and can be queried with +espressomd.electrostatics.Scafacos.get_available_methods().

+

To use ScaFaCoS, create an instance of Scafacos +and add it to the list of active actors. Three parameters have to be specified: +prefactor (as defined in (1)), method_name, +method_params. The method-specific parameters are described in the +ScaFaCoS manual. In addition, methods supporting tuning have a parameter +tolerance_field which sets the desired root mean square accuracy for +the electric field.

+

To use a specific electrostatics solver from ScaFaCoS for your system, +e.g. ewald, set its cutoff to \(1.5\) and tune the other parameters +for an accuracy of \(10^{-3}\):

+
import espressomd.electrostatics
+scafacos = espressomd.electrostatics.Scafacos(
+   prefactor=1, method_name="ewald",
+   method_params={"ewald_r_cut": 1.5, "tolerance_field": 1e-3})
+system.actors.add(scafacos)
+
+
+

For details of the various methods and their parameters please refer to +the ScaFaCoS manual. To use this feature, ScaFaCoS has to be built as a +shared library.

+
+
+ + +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/doc4.2.2/espressomd.MDA_ESP.html b/doc4.2.2/espressomd.MDA_ESP.html new file mode 100644 index 0000000000..4cce3690ba --- /dev/null +++ b/doc4.2.2/espressomd.MDA_ESP.html @@ -0,0 +1,201 @@ + + + + + + + + + espressomd.MDA_ESP package — ESPResSo 4.2.2 documentation + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +
+

espressomd.MDA_ESP package

+
+

Module contents

+

This modules exposes ESPResSo’s coordinates and particle attributes +to MDAnalysis without the need to save any information to files.

+

The main class is Stream, which is used to initialize the stream of +data to MDAnalysis’ readers. These are the topology reader ESPParser +and the coordinates reader ESPReader.

+

A minimal working example is the following:

+
>>> import espressomd
+>>> import espressomd.MDA_ESP
+>>> import MDAnalysis as mda
+>>> # system setup
+>>> system = espressomd.System(box_l=[10., 10., 10.])
+>>> system.time_step = 1.
+>>> system.cell_system.skin = 1.
+>>> system.part.add(pos=[1., 2., 3.])
+>>> # set up the stream
+>>> eos = espressomd.MDA_ESP.Stream(system)
+>>> # feed Universe with a topology and coordinates
+>>> u = mda.Universe(eos.topology, eos.trajectory)
+>>> print(u)
+<Universe with 1 atoms>
+
+
+
+
+class espressomd.MDA_ESP.ESPParser(filename, **kwargs)[source]
+

Bases: MDAnalysis.topology.base.TopologyReaderBase

+

An MDAnalysis reader of ESPResSo’s topology.

+
+
+format = 'ESP'
+
+ +
+
+parse()[source]
+

Access ESPResSo data and return the topology object.

+
+
Returns
+

top – a topology object

+
+
Return type
+

MDAnalysis.core.topology.Topology

+
+
+
+ +
+ +
+
+class espressomd.MDA_ESP.ESPReader(filename, convert_units=True, n_atoms=None, **kwargs)[source]
+

Bases: MDAnalysis.coordinates.base.SingleFrameReaderBase

+

An MDAnalysis single frame reader for the stream provided by Stream.

+
+
+format = 'ESP'
+
+ +
+
+units = {'length': 'nm', 'time': None, 'velocity': 'nm/ps'}
+

dict with units of of time and length (and velocity, force, +… for formats that support it)

+
+ +
+ +
+
+class espressomd.MDA_ESP.Stream(system)[source]
+

Bases: object

+

Create an object that provides a MDAnalysis topology and a coordinate reader

+
>>> eos = espressomd.MDA_ESP.Stream(system)
+>>> u = mda.Universe(eos.topology, eos.trajectory)
+
+
+
+
Parameters
+

system (espressomd.system.System)

+
+
+
+
+property trajectory
+

Particles’ coordinates at the current time

+
+
Returns
+

stream – A stream in the format that can be parsed by ESPReader

+
+
Return type
+

MDAnalysis.lib.util.NamedStream

+
+
+
+ +
+ +
+
+class espressomd.MDA_ESP.Timestep(n_atoms, **kwargs)[source]
+

Bases: MDAnalysis.coordinates.base.Timestep

+
+
+property dimensions
+

unitcell dimensions (A, B, C, alpha, beta, gamma)

+

lengths a, b, c are in the MDAnalysis length unit (Å), and +angles are in degrees.

+

Setting dimensions will populate the underlying native format +description of box dimensions

+
+ +
+ +
+
+ + +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/doc4.2.2/espressomd.html b/doc4.2.2/espressomd.html new file mode 100644 index 0000000000..aec5f8b040 --- /dev/null +++ b/doc4.2.2/espressomd.html @@ -0,0 +1,11731 @@ + + + + + + + + + espressomd package — ESPResSo 4.2.2 documentation + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +
+

espressomd package

+
+

Subpackages

+ +
+
+

Submodules

+
+
+

espressomd.accumulators module

+
+
+class espressomd.accumulators.AutoUpdateAccumulators(**kwargs)[source]
+

Bases: espressomd.script_interface.ScriptObjectList

+

Class for handling the auto-update of accumulators used by +espressomd.system.System.

+
+
+add(accumulator)[source]
+

Adds an accumulator instance to the auto-update list.

+
+ +
+
+clear()[source]
+

Removes all accumulators from the auto-update list.

+
+ +
+
+remove(accumulator)[source]
+

Removes an accumulator from the auto-update list.

+
+ +
+ +
+
+class espressomd.accumulators.Correlator(**kwargs)[source]
+

Bases: espressomd.script_interface.ScriptInterfaceHelper

+

Calculates the correlation of two observables \(A\) and \(B\), +or of one observable against itself (i.e. \(B = A\)). +The correlation can be compressed using the multiple tau correlation +algorithm.

+

The operation that is performed on \(A(t)\) and \(B(t+\tau)\) +to obtain \(C(\tau)\) depends on the corr_operation argument:

+
    +
  • "scalar_product": Scalar product of \(A\) and +\(B\), i.e., \(C=\sum\limits_{i} A_i B_i\)

  • +
  • "componentwise_product": Componentwise product of +\(A\) and \(B\), i.e., \(C_i = A_i B_i\)

  • +
  • "square_distance_componentwise": Each component of +the correlation vector is the square of the difference +between the corresponding components of the observables, i.e., +\(C_i = (A_i-B_i)^2\). Example: when \(A\) is +espressomd.observables.ParticlePositions, it produces the +mean square displacement (for each component separately).

  • +
  • "tensor_product": Tensor product of \(A\) and +\(B\), i.e., \(C_{i \cdot l_B + j} = A_i B_j\) +with \(l_B\) the length of \(B\).

  • +
  • "fcs_acf": Fluorescence Correlation Spectroscopy (FCS) +autocorrelation function, i.e.,

    +
    +\[G_i(\tau) = +\frac{1}{N} \left< \exp \left( +- \frac{\Delta x_i^2(\tau)}{w_x^2} +- \frac{\Delta y_i^2(\tau)}{w_y^2} +- \frac{\Delta z_i^2(\tau)}{w_z^2} +\right) \right>\]
    +

    where \(N\) is the average number of fluorophores in the +illumination area,

    +
    +\[\Delta x_i^2(\tau) = \left( x_i(0) - x_i(\tau) \right)^2\]
    +

    is the square displacement of particle +\(i\) in the \(x\) direction, and \(w_x\) +is the beam waist of the intensity profile of the +exciting laser beam,

    +
    +\[W(x,y,z) = I_0 \exp +\left( - \frac{2x^2}{w_x^2} - \frac{2y^2}{w_y^2} - +\frac{2z^2}{w_z^2} \right).\]
    +

    The values of \(w_x\), \(w_y\), and \(w_z\) +are passed to the correlator as args. The correlator calculates

    +
    +\[C_i(\tau) = +\exp \left( +- \frac{\Delta x_i^2(\tau)}{w_x^2} +- \frac{\Delta y_i^2(\tau)}{w_y^2} +- \frac{\Delta z_i^2(\tau)}{w_z^2} +\right)\]
    +

    Per each 3 dimensions of the observable, one dimension of the correlation +output is produced. If "fcs_acf" is used with other observables than +espressomd.observables.ParticlePositions, the physical meaning +of the result is unclear.

    +

    The above equations are a generalization of the formula presented by +Höfling et al. [Höfling et al., 2011]. For more information, see references +therein.

    +
  • +
+
+
Parameters
+
    +
  • obs1 (espressomd.observables.Observable) – The observable \(A\) to be correlated with \(B\) (obs2). +If obs2 is omitted, autocorrelation of obs1 is calculated by +default.

  • +
  • obs2 (espressomd.observables.Observable, optional) – The observable \(B\) to be correlated with \(A\) (obs1).

  • +
  • corr_operation (str) – The operation that is performed on \(A(t)\) and \(B(t+\tau)\).

  • +
  • delta_N (int) – Number of timesteps between subsequent samples for the auto update mechanism.

  • +
  • tau_max (float) – This is the maximum value of \(\tau\) for which the +correlation should be computed. Warning: Unless you are using +the multiple tau correlator, choosing tau_max of more than +100 * dt will result in a huge computational overhead. In a +multiple tau correlator with reasonable parameters, tau_max +can span the entire simulation without too much additional cpu time.

  • +
  • tau_lin (int) – The number of data-points for which the results are linearly spaced +in tau. This is a parameter of the multiple tau correlator. If you +want to use it, make sure that you know how it works. tau_lin must +be divisible by 2. By setting tau_lin such that +tau_max >= dt * delta_N * tau_lin, the +multiple tau correlator is used, otherwise the trivial linear +correlator is used. By setting tau_lin = 1, the value will be +overridden by tau_lin = ceil(tau_max / (dt * delta_N)), which +will result in either the multiple or linear tau correlator. +In many cases, tau_lin=16 is a +good choice but this may strongly depend on the observables you are +correlating. For more information, we recommend to read +ref. [Ramirez et al., 2010] or to perform your own tests.

  • +
  • compress1 (str) – These functions are used to compress the data when +going to the next level of the multiple tau +correlator. This is done by producing one value out of two. +The following compression functions are available:

    +
      +
    • "discard2": (default value) discard the second value from the time series, use the first value as the result

    • +
    • "discard1": discard the first value from the time series, use the second value as the result

    • +
    • "linear": make a linear combination (average) of the two values

    • +
    +

    If only compress1 is specified, then +the same compression function is used for both +observables. If both compress1 and compress2 are specified, +then compress1 is used for obs1 and compress2 for obs2.

    +

    Both discard1 and discard2 are safe for all +observables but produce poor statistics in the +tail. For some observables, "linear" compression +can be used which makes an average of two +neighboring values but produces systematic +errors. Depending on the observable, the +systematic error using the "linear" compression +can be anything between harmless and disastrous. +For more information, we recommend to read ref. +[Ramirez et al., 2010] or to perform your own tests.

    +
  • +
  • compress2 (str, optional) – See compress1.

  • +
  • args (float of length 3) – Three floats which are passed as arguments to the correlation +function. Currently it is only used by "fcs_acf", which +will square these values in the core; if you later decide to +update these weights with obs.args = [...], you’ll have to +provide already squared values! Other correlation operations +will ignore these values.

  • +
+
+
+
+
+lag_times()[source]
+
+
Returns
+

Lag times of the correlation.

+
+
Return type
+

ndarray of float

+
+
+
+ +
+
+result()[source]
+

Get correlation.

+
+
Returns
+

The result of the correlation function. The shape of the array +is determined by the shape of the input observable(s) and the +correlation operation.

+
+
Return type
+

ndarray of float

+
+
+
+ +
+
+sample_sizes()[source]
+
+
Returns
+

Samples sizes for each lag time.

+
+
Return type
+

ndarray of int

+
+
+
+ +
+ +
+
+class espressomd.accumulators.MeanVarianceCalculator(**kwargs)[source]
+

Bases: espressomd.script_interface.ScriptInterfaceHelper

+

Accumulates results from observables.

+
+
Parameters
+
+
+
+
+
+update()
+

Update the accumulator (get the current values from the observable).

+
+ +
+
+mean()[source]
+

Returns the samples mean values of the respective observable with +which the accumulator was initialized.

+
+ +
+
+std_error()[source]
+

Returns the standard error calculated from the samples variance for the observable by +assuming uncorrelated samples.

+
+ +
+
+variance()[source]
+

Returns the samples variance for the observable.

+
+ +
+ +
+
+class espressomd.accumulators.TimeSeries(**kwargs)[source]
+

Bases: espressomd.script_interface.ScriptInterfaceHelper

+

Records results from observables.

+
+
Parameters
+
+
+
+
+
+update()
+

Update the accumulator (get the current values from the observable).

+
+ +
+
+clear()
+

Clear the data

+
+ +
+
+time_series()[source]
+

Returns the recorded values of the observable.

+
+ +
+ +
+
+

espressomd.actors module

+
+
+class espressomd.actors.Actors[source]
+

Bases: object

+

Container for actor objects.

+
+
+active_actors = []
+
+ +
+
+add(actor)[source]
+
+
Parameters
+

actor – Actor to add to this container.

+
+
+
+ +
+
+clear()[source]
+

Remove all actors.

+
+ +
+
+remove(actor)[source]
+
+
Parameters
+

actor – Actor to remove from this container.

+
+
+
+ +
+ +
+
+

espressomd.analyze module

+
+
+class espressomd.analyze.Analysis(system)
+

Bases: object

+
+
+angular_momentum(self, p_type=None)
+

Calculates the system’s angular momentum with respect to the origin.

+

Note that virtual sites are not included, as they do not have a meaningful mass.

+
+
Parameters
+

p_type (int) – Particle type for +which to calculate the center of mass.

+
+
Returns
+

The center of mass of the system.

+
+
Return type
+

(3,) ndarray of float

+
+
+
+ +
+
+calc_re(self, chain_start=None, number_of_chains=None, chain_length=None)
+

Calculate the mean end-to-end distance of chains and its +standard deviation, as well as mean square end-to-end distance of +chains and its standard deviation.

+

This requires that a set of chains of equal length which start +with the particle number chain_start and are consecutively +numbered, the last particle in that topology having id number +chain_start + number_of_chains * chain_length - 1.

+
+
Parameters
+
    +
  • chain_start (int) – The id of the first monomer of the first chain.

  • +
  • number_of_chains (int) – Number of chains contained in the range.

  • +
  • chain_length (int) – The length of every chain.

  • +
+
+
Returns
+

Where [0] is the mean end-to-end distance of chains and [1] its +standard deviation, [2] the mean square end-to-end distance and +[3] its standard deviation.

+
+
Return type
+

(4,) array_like of float

+
+
+
+ +
+
+calc_rg(self, chain_start=None, number_of_chains=None, chain_length=None)
+

Calculate the mean radius of gyration of chains and its standard +deviation, as well as the mean square radius of gyration of chains +and its standard deviation.

+

This requires that a set of chains of equal length which start +with the particle number chain_start and are consecutively +numbered, the last particle in that topology having id number +chain_start + number_of_chains * chain_length - 1.

+

The radius of gyration is the radius of a sphere which would have +the same moment of inertia as a polymer, and is defined as

+
+\[R_{\mathrm G}^2 = \frac{1}{N} \sum\limits_{i=1}^{N} \left(\vec r_i - \vec r_{\mathrm{cm}}\right)^2\,,\]
+

where \(\vec r_i\) are position vectors of individual particles +constituting the polymer and \(\vec r_{\mathrm{cm}}\) is the +position of its center of mass. The sum runs over all \(N\) +particles comprising the polymer. For more information see any +polymer science book, e.g. [Rubinstein and Colby, 2003].

+
+
Parameters
+
    +
  • chain_start (int) – The id of the first monomer of the first chain.

  • +
  • number_of_chains (int) – Number of chains contained in the range.

  • +
  • chain_length (int) – The length of every chain.

  • +
+
+
Returns
+

Where [0] is the mean radius of gyration of the chains and [1] its +standard deviation, [2] the mean square radius of gyration and [3] +its standard deviation.

+
+
Return type
+

(4,) array_like of float

+
+
+
+ +
+
+calc_rh(self, chain_start=None, number_of_chains=None, chain_length=None)
+

Calculate the hydrodynamic mean radius of chains and its standard +deviation.

+

This requires that a set of chains of equal length which start +with the particle number chain_start and are consecutively +numbered, the last particle in that topology having id number +chain_start + number_of_chains * chain_length - 1.

+

The following formula is used for the calculation:

+
+\[\frac{1}{R_{\mathrm H}} = \frac{2}{N(N-1)} \sum\limits_{i=1}^{N} \sum\limits_{j<i}^{N} \frac{1}{|\vec r_i - \vec r_j|}\,,\]
+

This formula is only valid under certain assumptions. For more +information, see chapter 4 and equation 4.102 in [Doi and Edwards, 1986]. +Note that the hydrodynamic radius is sometimes defined in a similar +fashion but with a denominator of \(N^2\) instead of \(N(N-1)\) +in the prefactor. Both versions are equivalent in the +\(N\rightarrow \infty\) limit but give numerically different +values for finite polymers.

+
+
Parameters
+
    +
  • chain_start (int) – The id of the first monomer of the first chain

  • +
  • number_of_chains (int) – Number of chains contained in the range.

  • +
  • chain_length (int) – The length of every chain.

  • +
+
+
Returns
+

Where [0] is the mean hydrodynamic radius of the chains +and [1] its standard deviation.

+
+
Return type
+

(2,) array_like of float

+
+
+
+ +
+
+center_of_mass(self, p_type=None)
+

Calculate the system’s center of mass.

+

Note that virtual sites are not included, as they do not have a +meaningful mass.

+
+
Parameters
+

p_type (int) – Particle type for +which to calculate the center of mass.

+
+
Returns
+

The center of mass of the system.

+
+
Return type
+

array of float

+
+
+
+ +
+
+check_topology(self, chain_start=None, number_of_chains=None, chain_length=None)
+
+ +
+
+distribution(self, type_list_a=None, type_list_b=None, r_min=0.0, r_max=None, r_bins=100, log_flag=0, int_flag=0)
+

Calculates the distance distribution of particles (probability of +finding a particle of type A at a certain distance around a particle of +type B, disregarding the fact that a spherical shell of a larger radius +covers a larger volume). The distance is defined as the minimal distance +between a particle of group type_list_a to any of the group +type_list_b (excluding the self-contribution). Returns two arrays, +the bins and the (normalized) distribution.

+
+
Parameters
+
    +
  • type_list_a (list of int) – List of particle type, +only consider distances from these types.

  • +
  • type_list_b (list of int) – List of particle type, +only consider distances to these types.

  • +
  • r_min (float) – Minimum distance.

  • +
  • r_max (float) – Maximum distance. By default, it is half the box size. +A value larger than half the box size is allowed for systems +with open boundary conditions.

  • +
  • r_bins (int) – Number of bins.

  • +
  • log_flag (bool) – When set to False, the bins are linearly equidistant; when set +to True, the bins are logarithmically equidistant.

  • +
  • int_flag (bool) – When set to True, the result is an integrated distribution.

  • +
+
+
Returns
+

Where [0] contains the midpoints of the bins, +and [1] contains the values of the rdf.

+
+
Return type
+

ndarray

+
+
+
+ +
+
+dpd_stress(self)
+
+ +
+
+energy(self)
+

Calculate the system energy in parallel.

+
+
Returns
+

A dictionary with the following keys:

+
    +
  • "total": total energy

  • +
  • "kinetic": linear and rotational kinetic energy

  • +
  • "bonded": total bonded energy

  • +
  • "bonded", <bond_id>: bonded energy from the bond +identified by bond_id

  • +
  • "non_bonded": total non-bonded energy

  • +
  • "non_bonded", <type_i>, <type_j>: non-bonded energy +from short-range interactions between type_i and type_j

  • +
  • "non_bonded_intra", <type_i>, <type_j>: non-bonded energy +from short-range interactions between type_i and type_j +with the same mol_id

  • +
  • "non_bonded_inter", <type_i>, <type_j>: non-bonded energy +from short-range interactions between type_i and type_j +with different mol_id

  • +
  • "coulomb": Coulomb energy, how it is calculated depends +on the method

  • +
  • "coulomb", <i>: Coulomb energy from particle pairs +(i=0), electrostatics solvers (i=1)

  • +
  • "dipolar": dipolar energy

  • +
  • "dipolar", <i>: dipolar energy from particle pairs and +magnetic field constraints (i=0), magnetostatics solvers +(i=1)

  • +
  • "external_fields": external fields contribution

  • +
+

+
+
Return type
+

dict

+
+
+

Examples

+
>>> energy = system.analysis.energy()
+>>> print(energy["total"])
+>>> print(energy["kinetic"])
+>>> print(energy["bonded"])
+>>> print(energy["non_bonded"])
+>>> print(energy["external_fields"])
+
+
+
+ +
+
+gyration_tensor(self, p_type=None)
+

Analyze the gyration tensor of particles of a given type or of all +particles in the system if no type is given.

+
+
Parameters
+

p_type (list of int, optional) – A particle type, +or list of all particle types to be considered.

+
+
Returns
+

A dictionary with the following keys:

+
    +
  • "Rg^2": squared radius of gyration

  • +
  • "shape": three shape descriptors (asphericity, acylindricity, and relative shape anisotropy)

  • +
  • "eva0": eigenvalue 0 of the gyration tensor and its corresponding eigenvector.

  • +
  • "eva1": eigenvalue 1 of the gyration tensor and its corresponding eigenvector.

  • +
  • "eva2": eigenvalue 2 of the gyration tensor and its corresponding eigenvector.

  • +
+

The eigenvalues are sorted in descending order.

+

+
+
Return type
+

dict

+
+
+
+ +
+
+linear_momentum(self, include_particles=True, include_lbfluid=True)
+

Calculates the system’s linear momentum.

+
+
Parameters
+
    +
  • include_particles (bool, optional) – whether to include the particles contribution to the linear +momentum.

  • +
  • include_lbfluid (bool, optional) – whether to include the lattice-Boltzmann fluid contribution +to the linear momentum.

  • +
+
+
Returns
+

The linear momentum of the system.

+
+
Return type
+

float

+
+
+
+ +
+
+min_dist(self, p1='default', p2='default')
+

Minimal distance between two sets of particle types.

+
+
Parameters
+

p1, p2 (lists of int) – Particle type in +both sets. If both are set to 'default', the minimum distance +of all pairs is returned.

+
+
+
+ +
+
+moment_of_inertia_matrix(self, p_type=None)
+

Returns the 3x3 moment of inertia matrix for particles of a given type.

+
+
Parameters
+

p_type (int) – A particle type

+
+
Returns
+

3x3 moment of inertia matrix.

+
+
Return type
+

ndarray

+
+
+
+ +
+
+nbhood(self, pos=None, r_catch=None)
+

Get all particles in a defined neighborhood.

+
+
Parameters
+
    +
  • pos (array of float) – Reference position for the neighborhood.

  • +
  • r_catch (float) – Radius of the region.

  • +
+
+
Returns
+

The neighbouring particle ids.

+
+
Return type
+

array of int

+
+
+
+ +
+
+particle_energy(self, particle)
+

Calculate the non-bonded energy of a single given particle.

+
+
Parameters
+

particle (ParticleHandle)

+
+
Returns
+

non-bonded energy of that particle

+
+
Return type
+

obj: float

+
+
+
+ +
+
+pressure(self)
+

Calculate the instantaneous scalar pressure in parallel. This is only +sensible in an isotropic system which is homogeneous (on average)! Do +not use this in an anisotropic or inhomogeneous system. In order to +obtain the pressure, the ensemble average needs to be calculated.

+
+
Returns
+

A dictionary with the following keys:

+
    +
  • "total": total pressure

  • +
  • "kinetic": kinetic pressure

  • +
  • "bonded": total bonded pressure

  • +
  • "bonded", <bond_id>: bonded pressure from the bond +identified by bond_id

  • +
  • "non_bonded": total non-bonded pressure

  • +
  • "non_bonded", <type_i>, <type_j>: non-bonded pressure which +arises from the interactions between type_i and type_j

  • +
  • "non_bonded_intra", <type_i>, <type_j>: non-bonded pressure +from short-range forces between type_i and type_j +with the same mol_id

  • +
  • "non_bonded_inter", <type_i>, <type_j>: non-bonded pressure +from short-range forces between type_i and type_j +with different mol_id

  • +
  • "coulomb": Coulomb pressure, how it is calculated depends on +the method. It is equivalent to 1/3 of the trace of the Coulomb +pressure tensor. For how the pressure tensor is calculated, +see Pressure Tensor. The averaged value in an isotropic +NVT simulation is equivalent to the average of +\(E^{\mathrm{coulomb}}/(3V)\), see [Brown and Neyertz, 1995].

  • +
  • "coulomb", <i>: Coulomb pressure from particle pairs +(i=0), electrostatics solvers (i=1)

  • +
  • "dipolar": not implemented

  • +
  • "virtual_sites": Pressure contribution from virtual sites

  • +
  • "external_fields": external fields contribution

  • +
+

+
+
Return type
+

dict

+
+
+
+ +
+
+pressure_tensor(self)
+

Calculate the instantaneous pressure tensor in parallel. This is +sensible in an anisotropic system. Still it assumes that the system is +homogeneous since the volume-averaged pressure tensor is used. Do not use +this pressure tensor in an (on average) inhomogeneous system. If the +system is (on average inhomogeneous) then use a local pressure tensor. +In order to obtain the pressure tensor, the ensemble average needs to be +calculated.

+
+
Returns
+

A dictionary with the following keys:

+
    +
  • "total": total pressure tensor

  • +
  • "kinetic": kinetic pressure tensor

  • +
  • "bonded": total bonded pressure tensor

  • +
  • "bonded", <bond_id>: bonded pressure tensor from the bond +identified by bond_id

  • +
  • "non_bonded": total non-bonded pressure tensor

  • +
  • "non_bonded", <type_i>, <type_j>: non-bonded pressure tensor +from short-range forces between type_i and type_j

  • +
  • "non_bonded_intra", <type_i>, <type_j>: non-bonded pressure +tensor from short-range forces between type_i and type_j +with the same mol_id

  • +
  • "non_bonded_inter", <type_i>, <type_j>: non-bonded pressure +tensor from short-range forces between type_i and type_j +with different mol_id

  • +
  • "coulomb": Maxwell pressure tensor, how it is calculated +depends on the method

  • +
  • "coulomb", <i>: Maxwell pressure tensor from particle pairs +(i=0), electrostatics solvers (i=1)

  • +
  • "dipolar": not implemented

  • +
  • "virtual_sites": pressure tensor contribution from virtual sites

  • +
  • "external_fields": external fields contribution

  • +
+

+
+
Return type
+

dict

+
+
+
+ +
+
+structure_factor(self, sf_types=None, sf_order=None)
+

Calculate the structure factor for given types. Returns the +spherically averaged structure factor of particles specified in +sf_types. The structure factor is calculated for all possible wave +vectors q up to sf_order. Do not choose parameter sf_order too +large because the number of calculations grows as sf_order to the +third power.

+
+
Parameters
+
    +
  • sf_types (list of int) – Specifies which particle type +should be considered.

  • +
  • sf_order (int) – Specifies the maximum wavevector.

  • +
+
+
Returns
+

Where [0] contains q +and [1] contains the structure factor s(q)

+
+
Return type
+

ndarray

+
+
+
+ +
+ +
+
+espressomd.analyze.autocorrelation(time_series)
+

Calculate the unnormalized autocorrelation function \(R_{XX}\) +of an observable \(X\) measured at time \(t\) with constant +time step for lag times \(\tau\) such that:

+

\(\displaystyle R_{XX}(\tau) = \frac{1}{N - \tau} \sum_{t=0}^{N - \tau} X_{t} \cdot X_{t + \tau}\)

+

This is a scipy implementation of the algorithm described +in [de Buyl, 2018] that uses FFT. This implementation:

+
    +
  • doesn’t subtract the mean of the time series before calculating the ACF,

  • +
  • doesn’t normalize the ACF by the variance of the time series,

  • +
  • assumes the time series is aperiodic (i.e. uses zero-padding).

  • +
+
+
Parameters
+

time_series ((N,) or (N, M) array_like of float) – Time series to correlate. For multi-dimensional data, M is the +number of columns.

+
+
Returns
+

The time series autocorrelation function.

+
+
Return type
+

(N,) array_like of float

+
+
+
+ +
+
+

espressomd.bond_breakage module

+
+
+class espressomd.bond_breakage.BreakageSpec(**kwargs)[source]
+

Bases: espressomd.script_interface.ScriptInterfaceHelper

+

Specifications for bond breakage. +See Deleting bonds when particles are pulled apart for more details.

+
+
Parameters
+
    +
  • breakage_length (float) – Maximal bond extension until the bond breaks.

  • +
  • action_type (str, {‘delete_bond’, ‘revert_bind_at_point_of_collision’, ‘none’}) – Action triggered when the bond reaches its maximal extension.

  • +
+
+
+
+ +
+
+class espressomd.bond_breakage.BreakageSpecs(**kwargs)[source]
+

Bases: espressomd.script_interface.ScriptObjectMap

+
+ +
+
+

espressomd.cell_system module

+
+
+class espressomd.cell_system.CellSystem(**kwargs)[source]
+

Bases: espressomd.script_interface.ScriptInterfaceHelper

+

This class controls the particle decomposition.

+
+
+decomposition_type
+

Name of the currently active particle decomposition.

+
+
Type
+

str

+
+
+
+ +
+
+use_verlet_lists
+

Whether to use Verlet lists.

+
+
Type
+

bool

+
+
+
+ +
+
+skin
+

Verlet list skin.

+
+
Type
+

float

+
+
+
+ +
+
+node_grid
+

MPI repartition for the regular decomposition cell system.

+
+
Type
+

(3,) array_like of int

+
+
+
+ +
+
+max_cut_bonded
+

Maximal range from bonded interactions.

+
+
Type
+

float

+
+
+
+ +
+
+max_cut_nonbonded
+

Maximal range from non-bonded interactions.

+
+
Type
+

float

+
+
+
+ +
+
+interaction_range
+

Maximal interaction range from all interactions, +or -1 when no interactions are active (or their +cutoff has no impact when only 1 MPI rank is used).

+
+
Type
+

float

+
+
+
+ +
+
+resort()
+

Resort the particles in the cell system.

+
+
Parameters
+

global_flag (bool, optional) – If true (default), a global resorting is done, otherwise particles +are only exchanged between neighboring nodes.

+
+
Returns
+

The number of particles per node.

+
+
Return type
+

(N,) array_like of int

+
+
+
+ +
+
+tune_skin()
+

Tune the skin by measuring the integration time and bisecting over the +given range of skins. The best skin is set in the simulation core.

+
+
Parameters
+
    +
  • min_skin (float) – Minimum skin to test.

  • +
  • max_skin (float) – Maximum skin.

  • +
  • tol (float) – Accuracy in skin to tune to.

  • +
  • int_steps (int) – Integration steps to time.

  • +
  • adjust_max_skin (bool, optional) – If True, the value of max_skin is reduced +to the maximum permissible skin (in case the passed +value is too large). Defaults to False.

  • +
+
+
Returns
+

The skin

+
+
Return type
+

float

+
+
+
+ +
+
+get_state()
+

Get the current state of the cell system.

+
+
Returns
+

The cell system state.

+
+
Return type
+

dict

+
+
+
+ +
+
+get_neighbors(particle, distance)[source]
+

Get neighbors of a given particle up to a certain distance.

+

The choice of cell systems has an impact on +how far the algorithm can detect particle pairs:

+
    +
  • N-square: no restriction on the search distance, no double counting +if search distance is larger than the box size

  • +
  • regular decomposition: the search distance is bounded by half +the local cell geometry

  • +
  • hybrid decomposition: not supported

  • +
+
+
Parameters
+
    +
  • particle (ParticleHandle)

  • +
  • distance (float) – Pairs of particles closer than distance are found.

  • +
+
+
Returns
+

The list of neighbor particles surrounding the particle

+
+
Return type
+

(N,) array_like of int

+
+
+
+ +
+
+get_pairs(distance, types='all')[source]
+

Get pairs of particles closer than threshold value.

+
+
Parameters
+
    +
  • distance (float) – Pairs of particles closer than distance are found.

  • +
  • types (list of int or 'all', optional) – Restrict the pair search to the specified types. +Defaults to 'all', in which case all particles are considered.

  • +
+
+
Returns
+

The particle pairs identified by their index

+
+
Return type
+

list of tuples of int

+
+
Raises
+

Exception – If the pair search distance is greater than the cell size

+
+
+
+ +
+
+non_bonded_loop_trace()[source]
+
+ +
+
+set_hybrid_decomposition(**kwargs)[source]
+

Activate the hybrid domain decomposition.

+
+
Parameters
+
    +
  • cutoff_regular (float) – Maximum cutoff to consider in regular decomposition. +Should be as low as the system permits.

  • +
  • n_square_types (list of int, optional) – Particles types that should be handled in the N-square cell system. +Defaults to an empty list.

  • +
  • use_verlet_lists (bool, optional) – Activates or deactivates the usage of Verlet lists. +Defaults to True.

  • +
+
+
+
+ +
+
+set_n_square(**kwargs)[source]
+

Activate the N-square cell system.

+
+
Parameters
+

use_verlet_lists (bool, optional) – Activates or deactivates the usage of Verlet lists. +Defaults to True.

+
+
+
+ +
+
+set_regular_decomposition(**kwargs)[source]
+

Activate the regular decomposition cell system.

+
+
Parameters
+

use_verlet_lists (bool, optional) – Activates or deactivates the usage of Verlet lists. +Defaults to True.

+
+
+
+ +
+ +
+
+

espressomd.checkpointing module

+
+
+class espressomd.checkpointing.Checkpoint(checkpoint_id=None, checkpoint_path='.')[source]
+

Bases: object

+

Checkpoint handling (reading and writing).

+
+
Parameters
+
    +
  • checkpoint_id (str) – A string identifying a specific checkpoint.

  • +
  • checkpoint_path (str, optional) – Path for reading and writing the checkpoint. +If not given, the current working directory is used.

  • +
+
+
+
+
+get_last_checkpoint_index()[source]
+

Returns the last index of the given checkpoint id. Will raise exception +if no checkpoints are found.

+
+ +
+
+get_registered_objects()[source]
+

Returns a list of all object names that are registered for +checkpointing.

+
+ +
+
+has_checkpoints()[source]
+

Check for checkpoints.

+
+
Returns
+

True if any checkpoints exist that match checkpoint_id and +checkpoint_path otherwise False.

+
+
Return type
+

bool

+
+
+
+ +
+
+load(checkpoint_index=None)[source]
+

Loads the python objects using (c)Pickle and sets them in the calling +module.

+
+
Parameters
+

checkpoint_index (int, optional) – If not given, the last checkpoint_index will be used.

+
+
+
+ +
+
+read_signals()[source]
+

Reads all registered signals from the signal file and returns a list of +integers.

+
+ +
+
+register(*args)[source]
+

Register python objects for checkpointing.

+
+
Parameters
+

args (list of str) – Names of python objects to be registered for checkpointing.

+
+
+
+ +
+
+register_signal(signum=None)[source]
+

Register a signal that will trigger the signal handler.

+
+
Parameters
+

signum (int) – Signal to be registered.

+
+
+
+ +
+
+save(checkpoint_index=None)[source]
+

Saves all registered python objects in the given checkpoint directory +using cPickle.

+
+ +
+
+unregister(*args)[source]
+

Unregister python objects for checkpointing.

+
+
Parameters
+

args (list of str) – Names of python objects to be unregistered for checkpointing.

+
+
+
+ +
+ +
+
+

espressomd.cluster_analysis module

+
+
+class espressomd.cluster_analysis.Cluster(**kwargs)[source]
+

Bases: espressomd.script_interface.ScriptInterfaceHelper

+

Class representing a cluster of particles.

+
+
+particle_ids()
+

Returns list of particle ids in the cluster

+
+ +
+
+size()
+

Returns the number of particles in the cluster

+
+ +
+
+center_of_mass()
+

Center of mass of the cluster (folded coordinates)

+
+ +
+
+longest_distance()
+

Longest distance between any combination of two particles in the cluster

+
+ +
+
+fractal_dimension(dr=None)
+

Estimates the cluster’s fractal dimension by fitting the number of +particles \(n\) in spheres of growing radius around the center of mass +to \(c*r_g^d\), where \(r_g\) is the radius of gyration of the +particles within the sphere, and \(d\) is the fractal dimension.

+
+

Note

+

Requires GSL external feature, enabled with -DWITH_GSL=ON.

+
+
+
Parameters
+

dr (float) – Minimum increment for the radius of the spheres.

+
+
Returns
+

Fractal dimension and mean square residual.

+
+
Return type
+

tuple

+
+
+
+ +
+
+particles()[source]
+

Get particles in the cluster.

+
+
Returns
+

+
+
Return type
+

espressomd.particle_data.ParticleSlice

+
+
+
+ +
+ +
+
+class espressomd.cluster_analysis.ClusterStructure(*args, **kwargs)[source]
+

Bases: espressomd.script_interface.ScriptInterfaceHelper

+

Cluster structure of a simulation system, and access to cluster analysis

+
+
Parameters
+

pair_criterion (espressomd.pair_criteria._PairCriterion) – Criterion to decide whether two particles are neighbors.

+
+
+
+
+cid_for_particle(p)[source]
+

Returns cluster id for the particle.

+
+
Parameters
+

p (espressomd.particle_data.ParticleHandle or int containing the particle id) – Particle.

+
+
+
+ +
+
+clear()[source]
+

Clears the cluster structure.

+
+ +
+
+cluster_ids()[source]
+

Returns a list of all cluster ids of the clusters in the structure.

+
+ +
+
+property clusters
+

Gives access to the clusters in the cluster structure via an +instance of Clusters.

+
+ +
+
+run_for_all_pairs()[source]
+

Runs the cluster analysis, considering all pairs of particles in the system

+
+ +
+
+run_for_bonded_particles()[source]
+

Runs the cluster analysis, considering only pairs of particles connected by a pair-bond.

+
+ +
+ +
+
+class espressomd.cluster_analysis.Clusters(cluster_structure)[source]
+

Bases: object

+

Access to the clusters in the cluster structure.

+

Access is as follows:

+
    +
  • number of clusters: len(clusters)

  • +
  • access a cluster via its id: clusters[id]

  • +
  • iterate over clusters (yields (id, cluster) tuples)

  • +
+

Example:

+
>>> for cluster_id, cluster in clusters:
+...     print(f"{cluster_id=} CoM={cluster.center_of_mass()}")
+cluster_id=1 CoM=[1.71834061 1.54988961 1.54734631]
+
+
+
+ +
+
+

espressomd.collision_detection module

+
+
+class espressomd.collision_detection.CollisionDetection(**kwargs)[source]
+

Bases: espressomd.script_interface.ScriptInterfaceHelper

+

Interface to the collision detection / dynamic binding.

+

See Creating bonds when particles collide for detailed instructions.

+

This class should not be instantiated by the user. Instead, use +the collision_detection attribute +of the system class to access the collision detection.

+

Use method set_params() +to change the parameters of the collision detection.

+
+
+get_parameter(name)[source]
+

Gets a single parameter from the collision detection.

+
+ +
+
+get_params()[source]
+

Returns the parameters of the collision detection as dict.

+
+ +
+
+set_params(**kwargs)[source]
+

Set the parameters for the collision detection

+

See Creating bonds when particles collide for detailed instructions.

+
+
Parameters
+
    +
  • mode (str, {“off”, “bind_centers”, “bind_at_point_of_collision”, “bind_three_particles”, “glue_to_surface”}) – Collision detection mode

  • +
  • distance (float) – Distance below which a pair of particles is considered in the +collision detection

  • +
  • bond_centers (espressomd.interactions.BondedInteraction) – Bond to add between the colliding particles

  • +
  • bond_vs (espressomd.interactions.BondedInteraction) – Bond to add between virtual sites (for modes using virtual sites)

  • +
  • part_type_vs (int) – Particle type of the virtual sites being created on collision +(virtual sites based modes)

  • +
  • part_type_to_be_glued (int) – particle type for "glue_to_surface" mode. See user guide.

  • +
  • part_type_to_attach_vs_to (int) – particle type for "glue_to_surface" mode. See user guide.

  • +
  • part_type_after_glueing (int) – particle type for "glue_to_surface" mode. See user guide.

  • +
  • distance_glued_particle_to_vs (float) – Distance for "glue_to_surface" mode. See user guide.

  • +
  • bond_three_particles (espressomd.interactions.BondedInteraction) – First angular bond for the "bind_three_particles" mode. See +user guide

  • +
  • three_particle_binding_angle_resolution (int) – Resolution for the angular bonds (mode "bind_three_particles"). +Resolution+1 bonds are needed to accommodate the case of 180 degrees +angles

  • +
+
+
+
+ +
+ +
+
+

espressomd.comfixed module

+
+
+class espressomd.comfixed.ComFixed(**kwargs)[source]
+

Bases: espressomd.script_interface.ScriptInterfaceHelper

+

Fix the center of mass of specific types.

+

Subtracts mass-weighted fraction of the total +force action on all particles of the type from +the particles after each force calculation. This +keeps the center of mass of the type fixed iff +the total momentum of the type is zero.

+
+
Parameters
+

types (array_like) – List of types for which the center of mass should be fixed.

+
+
+
+ +
+
+

espressomd.constraints module

+
+
+class espressomd.constraints.Constraint(**kwargs)[source]
+

Bases: espressomd.script_interface.ScriptInterfaceHelper

+

Base class for constraints. A constraint provides a force and +an energy contribution for a single particle.

+
+ +
+
+class espressomd.constraints.Constraints(**kwargs)[source]
+

Bases: espressomd.script_interface.ScriptObjectList

+

List of active constraints. Add a espressomd.constraints.Constraint +to make it active in the system, or remove it to make it inactive.

+
+
+add(*args, **kwargs)[source]
+

Add a constraint to the list.

+
+
Parameters
+
+
+
Returns
+

constraint – The added constraint

+
+
Return type
+

espressomd.constraints.Constraint

+
+
+
+ +
+
+clear()[source]
+

Remove all constraints.

+
+ +
+
+remove(constraint)[source]
+

Remove a constraint from the list.

+
+
Parameters
+

constraint (espressomd.constraints.Constraint)

+
+
+
+ +
+ +
+
+class espressomd.constraints.ElectricPlaneWave(phi=0, **kwargs)[source]
+

Bases: espressomd.constraints.Constraint

+

Electric field of the form

+

\(\vec{E} = \vec{E_0} \cdot \sin(\vec{k} \cdot \vec{x} + \omega \cdot t + \phi)\)

+

The resulting force on the particles are then

+

\(\vec{F} = q \cdot \vec{E}\)

+

where \(q\) and \(\vec{x}\) are the particle charge and position +in folded coordinates. +This can be used to generate a homogeneous AC +field by setting \(\vec{k}\) to the null vector. +For periodic systems, \(\vec{k}\) must be an integer multiple +of \(2\pi \vec{L}^{-1}\) with \(\vec{L}\) the box length.

+
+
Parameters
+
    +
  • E0 (array_like of float) – Amplitude of the electric field.

  • +
  • k (array_like of float) – Wave vector of the wave

  • +
  • omega (float) – Frequency of the wave

  • +
  • phi (float, optional) – Phase

  • +
+
+
+
+
+property E0
+
+ +
+
+property k
+
+ +
+
+property omega
+
+ +
+
+property phi
+
+ +
+ +
+
+class espressomd.constraints.ElectricPotential(**kwargs)[source]
+

Bases: espressomd.constraints._Interpolated

+

Electric potential interpolated from +provided data. The electric field \(\vec{E}\) is +calculated numerically from the potential, +and the resulting force on the particles are

+

\(\vec{F} = q \cdot \vec{E}\)

+

where \(q\) is the charge of the particle.

+
+
Parameters
+
    +
  • field ((M, N, O, 1) array_like of float) – Potential on a grid of size (M, N, O)

  • +
  • grid_spacing ((3,) array_like of float) – Spacing of the grid points.

  • +
+
+
+
+ +
+
+class espressomd.constraints.FlowField(**kwargs)[source]
+

Bases: espressomd.constraints._Interpolated

+

Viscous coupling to a flow field that is +interpolated from tabulated data like

+

\(\vec{F} = -\gamma \cdot \left( \vec{u}(\vec{x}) - \vec{v} \right)\)

+

where \(\vec{v}\) and \(\vec{x}\) are the particle velocity and position +in folded coordinates, and \(\vec{u}(\vec{x})\) is a 3D flow field on a grid.

+
+
Parameters
+
    +
  • field ((M, N, O, 3) array_like of float) – Field velocity on a grid of size (M, N, O)

  • +
  • grid_spacing ((3,) array_like of float) – Spacing of the grid points.

  • +
  • gamma (float) – Coupling constant

  • +
+
+
+
+ +
+
+class espressomd.constraints.ForceField(**kwargs)[source]
+

Bases: espressomd.constraints._Interpolated

+

A generic tabulated force field that applies a per-particle scaling factor.

+
+
Parameters
+
    +
  • field ((M, N, O, 3) array_like of float) – Forcefield amplitude on a grid of size (M, N, O).

  • +
  • grid_spacing ((3,) array_like of float) – Spacing of the grid points.

  • +
  • default_scale (float) – Scaling factor for particles that have no individual scaling factor.

  • +
  • particle_scales (dict) – A dictionary mapping particle ids to scaling factors. +For these particles, the interaction is scaled with +their individual scaling factor. Other particles are +scaled with the default scaling factor.

  • +
+
+
+
+ +
+
+class espressomd.constraints.Gravity(**kwargs)[source]
+

Bases: espressomd.constraints.Constraint

+

Gravity force

+

\(\vec{F} = m \cdot \vec{g}\)

+
+
Parameters
+

g ((3,) array_like of float) – The gravitational constant.

+
+
+
+
+property g
+
+ +
+ +
+
+class espressomd.constraints.HomogeneousFlowField(**kwargs)[source]
+

Bases: espressomd.constraints.Constraint

+

Viscous coupling to a flow field that is +constant in space with the force

+

\(\vec{F} = -\gamma \cdot (\vec{u} - \vec{v})\)

+

where \(\vec{v}\) is the velocity of the particle +and \(\vec{u}\) is the constant flow field.

+
+
+gamma
+

Coupling constant

+
+
Type
+

float

+
+
+
+ +
+
+property u
+

Field velocity ((3,) array_like of float).

+
+ +
+ +
+
+class espressomd.constraints.HomogeneousMagneticField(**kwargs)[source]
+

Bases: espressomd.constraints.Constraint

+

Homogeneous magnetic field \(\vec{H}\). +The resulting force \(\vec{F}\), torque \(\vec{\tau}\) +and energy U on the particles are then

+

\(\vec{F} = \vec{0}\)

+

\(\vec{\tau} = \vec{\mu} \times \vec{H}\)

+

\(U = -\vec{\mu} \cdot \vec{H}\)

+

where \(\vec{\mu}\) is the particle dipole moment.

+
+
+H
+

Magnetic field vector. Describes both field direction and +strength of the magnetic field (via length of the vector).

+
+
Type
+

(3,) array_like of float

+
+
+
+ +
+ +
+
+class espressomd.constraints.LinearElectricPotential(phi0=0, **kwargs)[source]
+

Bases: espressomd.constraints.Constraint

+

Electric potential of the form

+

\(\phi = -\vec{E} \cdot \vec{x} + \phi_0\),

+

resulting in the electric field \(\vec{E}\) everywhere. +The resulting force on the particles are then

+

\(\vec{F} = q \cdot \vec{E}\)

+

where \(q\) and \(\vec{x}\) are the particle charge and position +in folded coordinates. +This can be used to model a plate capacitor.

+
+
Parameters
+
    +
  • E (array_like of float) – The electric field.

  • +
  • phi0 (float) – The potential at the origin

  • +
+
+
+
+
+property E
+
+ +
+
+property phi0
+
+ +
+ +
+
+class espressomd.constraints.PotentialField(**kwargs)[source]
+

Bases: espressomd.constraints._Interpolated

+

A generic tabulated force field that applies a per-particle +scaling factor. The forces are calculated numerically from +the data by finite differences. The potential is interpolated +from the provided data.

+
+
Parameters
+
    +
  • field ((M, N, O, 1) array_like of float) – Potential on a grid of size (M, N, O).

  • +
  • grid_spacing ((3,) array_like of float) – Spacing of the grid points.

  • +
  • default_scale (float) – Scaling factor for particles that have no individual scaling factor.

  • +
  • particle_scales (dict) – A dictionary mapping particle ids to scaling factors. +For these particles, the interaction is scaled with +their individual scaling factor. Other particles are +scaled with the default scaling factor.

  • +
+
+
+
+ +
+
+class espressomd.constraints.ShapeBasedConstraint(**kwargs)[source]
+

Bases: espressomd.constraints.Constraint

+
+
+only_positive
+

Act only in the direction of positive normal, +only useful if penetrable is True.

+
+
Type
+

bool

+
+
+
+ +
+
+particle_type
+

Interaction type of the constraint.

+
+
Type
+

int

+
+
+
+ +
+
+particle_velocity
+

Interaction velocity of the boundary

+
+
Type
+

array_like of float

+
+
+
+ +
+
+penetrable
+

Whether particles are allowed to penetrate the constraint.

+
+
Type
+

bool

+
+
+
+ +
+
+shape
+

One of the shapes from espressomd.shapes

+
+
Type
+

espressomd.shapes.Shape

+
+
+
+ +
+

See also

+
+
espressomd.shapes

shape module that defines mathematical surfaces

+
+
+
+

Examples

+
>>> import espressomd
+>>> import espressomd.shapes
+>>> system = espressomd.System(box_l=3 * [10.])
+>>>
+>>> # create first a shape-object to define the constraint surface
+>>> spherical_cavity = espressomd.shapes.Sphere(center=system.box_l / 2, radius=2.0, direction=-1.0)
+>>>
+>>> # now create an un-penetrable shape-based constraint of type 0
+>>> spherical_constraint = system.constraints.add(particle_type=0, penetrable=False, shape=spherical_cavity)
+>>>
+>>> # place a trapped particle inside this sphere
+>>> system.part.add(pos=0.51 * system.box_l, type=1)
+
+
+
+
+min_dist()[source]
+

Calculates the minimum distance to all interacting particles.

+
+
Returns
+

The minimum distance

+
+
Return type
+

float

+
+
+
+ +
+
+total_force()[source]
+

Get total force acting on this constraint.

+

Examples

+
>>> import espressomd
+>>> import espressomd.shapes
+>>> system = espressomd.System(box_l=[50., 50., 50.])
+>>> system.time_step = 0.01
+>>> system.thermostat.set_langevin(kT=0.0, gamma=1.0)
+>>> system.cell_system.set_n_square(use_verlet_lists=False)
+>>> system.non_bonded_inter[0, 0].lennard_jones.set_params(
+...     epsilon=1, sigma=1, cutoff=2**(1. / 6), shift="auto")
+>>>
+>>> floor = system.constraints.add(
+...    shape=espressomd.shapes.Wall(normal=[0, 0, 1], dist=0.0),
+...    particle_type=0, penetrable=False, only_positive=False)
+>>>
+>>> p = system.part.add(pos=[0,0,1.5], type=0, ext_force=[0, 0, -.1])
+>>> # print the particle position as it falls
+>>> # and print the force it applies on the floor
+>>> for t in range(10):
+...     system.integrator.run(100)
+...     print(p.pos, floor.total_force())
+
+
+
+ +
+
+total_normal_force()[source]
+

Get the total summed normal force acting on this constraint.

+
+ +
+ +
+
+

espressomd.cuda_init module

+
+
+class espressomd.cuda_init.CudaInitHandle
+

Bases: object

+
+
+device
+

Get device.

+
+
Returns
+

Id of current set device.

+
+
Return type
+

int

+
+
+
+ +
+
+list_devices(self)
+

List devices.

+
+
Returns
+

List of available CUDA devices.

+
+
Return type
+

dict

+
+
+
+ +
+
+list_devices_properties(self)
+

List devices with their properties on each host machine.

+
+
Returns
+

List of available CUDA devices with their properties.

+
+
Return type
+

dict

+
+
+
+ +
+ +
+
+espressomd.cuda_init.gpu_available()
+
+ +
+
+

espressomd.drude_helpers module

+
+
+class espressomd.drude_helpers.DrudeHelpers[source]
+

Bases: object

+

Provides helper functions to assist in the creation of Drude particles.

+
+
+add_all_thole(system, verbose=False)[source]
+

Calls add_thole_pair_damping() for all necessary combinations to +create the interactions.

+
+
Parameters
+
+
+
+
+ +
+
+add_drude_particle_to_core(system, harmonic_bond, thermalized_bond, p_core, type_drude, alpha, mass_drude, coulomb_prefactor, thole_damping=2.6, verbose=False)[source]
+

Adds a Drude particle with specified type and mass to the system and +returns its espressomd.particle_data.ParticleHandle. +Checks if different Drude particles have different types. +Collects types/charges/polarizations/Thole factors for intramolecular +core-Drude short-range exclusion and Thole interaction.

+
+
Parameters
+
    +
  • system (espressomd.system.System)

  • +
  • harmonic_bond (espressomd.interactions.HarmonicBond) – Add this harmonic bond to between Drude particle and core

  • +
  • thermalized_bond (espressomd.interactions.ThermalizedBond) – Add this thermalized_bond to between Drude particle and core

  • +
  • p_core (espressomd.particle_data.ParticleHandle) – The existing core particle

  • +
  • type_drude (int) – The type of the newly created Drude particle

  • +
  • alpha (float) – The polarizability in units of inverse volume. Related to the charge +of the Drude particle.

  • +
  • mass_drude (float) – The mass of the newly created Drude particle

  • +
  • coulomb_prefactor (float) – Required to calculate the charge of the Drude particle.

  • +
  • thole_damping (float) – Thole damping factor of the Drude pair. Comes to effect if +add_all_thole() method is used.

  • +
  • verbose (bool) – Turns on verbosity.

  • +
+
+
Returns
+

The created Drude Particle.

+
+
Return type
+

espressomd.particle_data.ParticleHandle

+
+
+
+ +
+
+add_intramol_exclusion_bonds(drude_parts, core_parts, verbose=False)[source]
+

Applies electrostatic short-range exclusion bonds for the given ids. +Has to be applied for all molecules.

+
+
Parameters
+
    +
  • system (espressomd.system.System)

  • +
  • drude_parts – List of Drude particles within a molecule.

  • +
  • core_parts – List of core particles within a molecule.

  • +
  • verbose (bool) – Turns on verbosity.

  • +
+
+
+
+ +
+
+add_thole_pair_damping(system, t1, t2, verbose=False)[source]
+

Calculates mixed Thole factors depending on Thole damping and polarization. +Adds non-bonded Thole interactions to the system.

+
+
Parameters
+
+
+
+
+ +
+
+setup_and_add_drude_exclusion_bonds(system, verbose=False)[source]
+

Creates electrostatic short-range exclusion bonds for global exclusion +between Drude particles and core charges and adds the bonds to the cores. +Has to be called once after all Drude particles have been created.

+
+
Parameters
+
+
+
+
+ +
+
+setup_intramol_exclusion_bonds(system, mol_drude_types, mol_core_types, mol_core_partial_charges, verbose=False)[source]
+

Creates electrostatic short-range exclusion bonds for intramolecular exclusion +between Drude particles and partial charges of the cores. Has to be called once +after all Drude particles have been created.

+
+
Parameters
+
    +
  • system (espressomd.system.System)

  • +
  • mol_drude_types – List of types of Drude particles within the molecule

  • +
  • mol_core_types – List of types of core particles within the molecule

  • +
  • mol_core_partial_charges – List of partial charges of core particles within the molecule

  • +
  • verbose (bool) – Turns on verbosity.

  • +
+
+
+
+ +
+ +
+
+

espressomd.ekboundaries module

+
+
+class espressomd.ekboundaries.EKBoundaries(**kwargs)[source]
+

Bases: espressomd.lbboundaries.LBBoundaries

+

Creates a set of electrokinetics boundaries.

+
+ +
+
+class espressomd.ekboundaries.EKBoundary(**kwargs)[source]
+

Bases: espressomd.lbboundaries.LBBoundary

+

Creates a EK boundary.

+
+ +
+
+

espressomd.electrokinetics module

+
+
+class espressomd.electrokinetics.Electrokinetics
+

Bases: espressomd.lb.HydrodynamicInteraction

+

Creates the electrokinetic method using the GPU unit.

+
+
+add_boundary(self, shape)
+
+ +
+
+add_reaction(self, shape)
+
+ +
+
+add_species(self, species)
+

Initializes a new species for the electrokinetic method.

+
+
Parameters
+

species (int) – Species to be initialized.

+
+
+
+ +
+
+default_params(self)
+

Returns the default parameters.

+
+ +
+
+ek_init(self)
+

Initializes the electrokinetic system. +This automatically initializes the lattice-Boltzmann method on the GPU.

+
+ +
+
+get_params(self)
+

Prints out the parameters of the electrokinetic system.

+
+ +
+
+load_checkpoint(self, path)
+
+ +
+
+neutralize_system(self, species)
+

Sets the global density of a species to a specific value +for which the whole system will have no net charge.

+
+

Note

+

The previous density of the species will be ignored and +it will be homogeneous distributed over the whole system +The species must be charged to begin with. If the +neutralization would lead to a negative species density +an exception will be raised.

+
+
+
Parameters
+

species (int) – The species which will be changed to neutralize the system.

+
+
+
+ +
+
+required_keys(self)
+

Returns the necessary options to initialize the electrokinetic method.

+
+ +
+
+save_checkpoint(self, path)
+
+ +
+
+set_density(self, species=None, density=None, node=None)
+

Sets the density of a species at a specific node. +If no node is given the density will be set global for the species.

+
+
Parameters
+
    +
  • species (int) – species for which the density will apply.

  • +
  • density (float) – The value to which the density will be set to.

  • +
  • node (numpy-array of type int of length (3)) – If set the density will be only applied on this specific node.

  • +
+
+
+
+ +
+
+valid_keys(self)
+

Returns the valid options used for the electrokinetic method.

+
+ +
+
+validate_params(self)
+

Checks if the parameters for “stencil” and “fluid_coupling” are valid.

+
+ +
+
+write_vtk_boundary(self, path)
+

Writes the boundary information into a vtk-file.

+
+
Parameters
+

path (str) – Path of the .vtk file the boundary is written to.

+
+
+
+ +
+
+write_vtk_density(self, path)
+

Writes the LB density information into a vtk-file.

+
+
Parameters
+

path (str) – Path of the .vtk file the LB density is written to.

+
+
+
+ +
+
+write_vtk_lbforce(self, path)
+

Writes the LB force information into a vtk-file.

+
+
Parameters
+

path (str) – Path of the .vtk file the LB force is written to.

+
+
+
+ +
+
+write_vtk_particle_potential(self, path)
+

Writes the electrostatic particle potential into a vtk-file.

+
+

Note

+

This only works if ‘es_coupling’ is active.

+
+
+
Parameters
+

path (str) – Path of the .vtk file the electrostatic potential is written to.

+
+
+
+ +
+
+write_vtk_potential(self, path)
+

Writes the electrostatic potential into a vtk-file.

+
+
Parameters
+

path (str) – Path of the .vtk file the electrostatic potential is written to.

+
+
+
+ +
+
+write_vtk_velocity(self, path)
+

Writes the lattice-Boltzmann velocity information into a vtk-file.

+
+
Parameters
+

path (str) – Path of the .vtk file the velocity is written to.

+
+
+
+ +
+ +
+
+class espressomd.electrokinetics.ElectrokineticsRoutines
+

Bases: espressomd.lb.LBFluidRoutines

+
+
+potential
+
+ +
+ +
+
+class espressomd.electrokinetics.SpecieRoutines(key, id)
+

Bases: object

+
+
+density
+
+ +
+
+flux
+
+ +
+ +
+
+class espressomd.electrokinetics.Species(**kwargs)
+

Bases: object

+

Creates a species object that is passed to the ek instance.

+
+
+default_params(self)
+

Returns the default parameters for the species.

+
+ +
+
+get_params(self)
+

Returns the parameters of the species.

+
+ +
+
+id = -1
+
+ +
+
+py_number_of_species = 0
+
+ +
+
+required_keys(self)
+

Returns the required keys for the species.

+
+ +
+
+valid_keys(self)
+

Returns the valid keys for the species.

+
+ +
+
+write_vtk_density(self, path)
+

Writes the species density into a vtk-file.

+
+
Parameters
+

path (str) – Path of the .vtk file the species density is written to.

+
+
+
+ +
+
+write_vtk_flux(self, path)
+

Writes the species flux into a vtk-file.

+
+
Parameters
+

path (str) – Path of the .vtk file the species flux is written to.

+
+
+
+ +
+
+write_vtk_flux_fluc(self, path)
+
+ +
+ +
+ +
+ +
+
+

espressomd.electrostatic_extensions module

+
+
+class espressomd.electrostatic_extensions.ElectrostaticExtensions(**kwargs)[source]
+

Bases: espressomd.script_interface.ScriptInterfaceHelper

+
+
+default_params()[source]
+
+ +
+
+required_keys()[source]
+
+ +
+
+valid_keys()[source]
+
+ +
+
+validate_params(params)[source]
+
+ +
+ +
+
+class espressomd.electrostatic_extensions.ICC(**kwargs)[source]
+

Bases: espressomd.electrostatic_extensions.ElectrostaticExtensions

+

Interface to the induced charge calculation scheme for dielectric +interfaces. See Dielectric interfaces with the ICC\star algorithm +for more details.

+
+
Parameters
+
    +
  • n_icc (int) – Total number of ICC Particles.

  • +
  • first_id (int, optional) – ID of the first ICC Particle.

  • +
  • convergence (float, optional) – Abort criteria of the iteration. It corresponds to the maximum relative +change of any of the interface particle’s charge.

  • +
  • relaxation (float, optional) – SOR relaxation parameter.

  • +
  • ext_field (float, optional) – Homogeneous electric field added to the calculation of dielectric boundary forces.

  • +
  • max_iterations (int, optional) – Maximal number of iterations.

  • +
  • eps_out (float, optional) – Relative permittivity of the outer region (where the particles are).

  • +
  • normals ((n_icc, 3) array_like float) – Normal vectors pointing into the outer region.

  • +
  • areas ((n_icc, ) array_like float) – Areas of the discretized surface.

  • +
  • sigmas ((n_icc, ) array_like float, optional) – Additional surface charge density in the absence of any charge +induction.

  • +
  • epsilons ((n_icc, ) array_like float) – Dielectric constant associated to the areas.

  • +
+
+
+
+
+default_params()[source]
+
+ +
+
+last_iterations()[source]
+

Number of iterations needed in last relaxation to +reach the convergence criterion.

+
+
Returns
+

iterations – Number of iterations

+
+
Return type
+

int

+
+
+
+ +
+
+required_keys()[source]
+
+ +
+
+valid_keys()[source]
+
+ +
+
+validate_params(params)[source]
+
+ +
+ +
+
+

espressomd.electrostatics module

+
+
+class espressomd.electrostatics.DH(**kwargs)[source]
+

Bases: espressomd.electrostatics.ElectrostaticInteraction

+

Electrostatics solver based on the Debye-Hueckel framework. +See Debye-Hückel potential for more details.

+
+
Parameters
+
    +
  • prefactor (float) – Electrostatics prefactor (see (1)).

  • +
  • kappa (float) – Inverse Debye screening length.

  • +
  • r_cut (float) – Cutoff radius for this interaction.

  • +
+
+
+
+
+default_params()[source]
+
+ +
+
+required_keys()[source]
+
+ +
+
+valid_keys()[source]
+
+ +
+ +
+
+class espressomd.electrostatics.ELC(**kwargs)[source]
+

Bases: espressomd.electrostatics.ElectrostaticInteraction

+

Electrostatics solver for systems with two periodic dimensions. +See Electrostatic Layer Correction (ELC) for more details.

+
+
Parameters
+
    +
  • actor (P3M, required) – Base P3M actor.

  • +
  • gap_size (float, required) – The gap size gives the height \(h\) of the empty region between +the system box and the neighboring artificial images. ESPResSo checks +that the gap is empty and will throw an error if it isn’t. Therefore +you should really make sure that the gap region is empty (e.g. +with wall constraints).

  • +
  • maxPWerror (float, required) – The maximal pairwise error sets the least upper bound (LUB) error +of the force between any two charges without prefactors (see the +papers). The algorithm tries to find parameters to meet this LUB +requirements or will throw an error if there are none.

  • +
  • delta_mid_top (float, optional) – Dielectric contrast \(\Delta_t\) between the upper boundary +and the simulation box. Value between -1 and +1 (inclusive).

  • +
  • delta_mid_bottom (float, optional) – Dielectric contrast \(\Delta_b\) between the lower boundary +and the simulation box. Value between -1 and +1 (inclusive).

  • +
  • const_pot (bool, optional) – Activate a constant electric potential between the top and bottom +of the simulation box.

  • +
  • pot_diff (float, optional) – If const_pot is enabled, this parameter controls the applied +voltage between the boundaries of the simulation box in the +z-direction (at \(z = 0\) and \(z = L_z - h\)).

  • +
  • neutralize (bool, optional) – By default, ELC just as P3M adds a homogeneous neutralizing +background to the system in case of a net charge. However, unlike +in three dimensions, this background adds a parabolic potential +across the slab [Ballenegger et al., 2009]. Therefore, under normal +circumstances, you will probably want to disable the neutralization +for non-neutral systems. This corresponds then to a formal +regularization of the forces and energies [Ballenegger et al., 2009]. +Also, if you add neutralizing walls explicitly as constraints, you +have to disable the neutralization. When using a dielectric +contrast or full metallic walls (delta_mid_top != 0 or +delta_mid_bot != 0 or const_pot=True), neutralize is +overwritten and switched off internally. Note that the special +case of non-neutral systems with a non-metallic dielectric jump +(e.g. delta_mid_top or delta_mid_bot in ]-1,1[) is not +covered by the algorithm and will throw an error.

  • +
  • far_cut (float, optional) – Cutoff radius, use with care, intended for testing purposes. When +setting the cutoff directly, the maximal pairwise error is ignored.

  • +
+
+
+
+
+default_params()[source]
+
+ +
+
+required_keys()[source]
+
+ +
+
+valid_keys()[source]
+
+ +
+
+validate_params(params)[source]
+

Check validity of given parameters.

+
+ +
+ +
+
+class espressomd.electrostatics.ElectrostaticInteraction(**kwargs)[source]
+

Bases: espressomd.script_interface.ScriptInterfaceHelper

+

Common interface for electrostatics solvers.

+
+
Parameters
+

prefactor (float) – Electrostatics prefactor \(\frac{1}{4\pi\varepsilon_0\varepsilon_r}\)

+
+
+
+
+default_params()[source]
+
+ +
+
+required_keys()[source]
+
+ +
+
+valid_keys()[source]
+
+ +
+
+validate_params(params)[source]
+

Check validity of given parameters.

+
+ +
+ +
+
+class espressomd.electrostatics.MMM1D(**kwargs)[source]
+

Bases: espressomd.electrostatics.ElectrostaticInteraction

+

Electrostatics solver for systems with one periodic direction. +See MMM1D for more details.

+
+
Parameters
+
    +
  • prefactor (float) – Electrostatics prefactor (see (1)).

  • +
  • maxWPerror (float) – Maximal pairwise error.

  • +
  • far_switch_radius (float, optional) – Radius where near-field and far-field calculation are switched.

  • +
  • verbose (bool, optional) – If False, disable log output during tuning.

  • +
  • timings (int, optional) – Number of force calculations during tuning.

  • +
  • check_neutrality (bool, optional) – Raise a warning if the system is not electrically neutral when +set to True (default).

  • +
+
+
+
+
+default_params()[source]
+
+ +
+
+required_keys()[source]
+
+ +
+
+valid_keys()[source]
+
+ +
+
+validate_params(params)[source]
+

Check validity of given parameters.

+
+ +
+ +
+
+class espressomd.electrostatics.MMM1DGPU(**kwargs)[source]
+

Bases: espressomd.electrostatics.ElectrostaticInteraction

+

Electrostatics solver with GPU support for systems with one periodic +direction. See MMM1D on GPU for more details.

+
+
Parameters
+
    +
  • prefactor (float) – Electrostatics prefactor (see (1)).

  • +
  • maxWPerror (float) – Maximal pairwise error.

  • +
  • far_switch_radius (float, optional) – Radius where near-field and far-field calculation are switched

  • +
  • bessel_cutoff (int, optional)

  • +
  • timings (int, optional) – Number of force calculations during tuning.

  • +
  • check_neutrality (bool, optional) – Raise a warning if the system is not electrically neutral when +set to True (default).

  • +
+
+
+
+
+default_params()[source]
+
+ +
+
+required_keys()[source]
+
+ +
+
+valid_keys()[source]
+
+ +
+
+validate_params(params)[source]
+

Check validity of given parameters.

+
+ +
+ +
+
+class espressomd.electrostatics.P3M(**kwargs)[source]
+

Bases: espressomd.electrostatics._P3MBase

+

P3M electrostatics solver.

+

Particle–Particle–Particle–Mesh (P3M) is a Fourier-based Ewald +summation method to calculate potentials in N-body simulation. +See Coulomb P3M for more details.

+
+
Parameters
+
    +
  • prefactor (float) – Electrostatics prefactor (see (1)).

  • +
  • accuracy (float) – P3M tunes its parameters to provide this target accuracy.

  • +
  • alpha (float, optional) – The Ewald parameter.

  • +
  • cao (float, optional) – The charge-assignment order, an integer between 1 and 7.

  • +
  • epsilon (float or str, optional) – A positive number for the dielectric constant of the +surrounding medium. Use 'metallic' to set the dielectric +constant of the surrounding medium to infinity (default).

  • +
  • mesh (int or (3,) array_like of int, optional) – The number of mesh points in x, y and z direction. Use a single +value for cubic boxes.

  • +
  • mesh_off ((3,) array_like of float, optional) – Mesh offset.

  • +
  • r_cut (float, optional) – The real space cutoff.

  • +
  • tune (bool, optional) – Used to activate/deactivate the tuning method on activation. +Defaults to True.

  • +
  • timings (int) – Number of force calculations during tuning.

  • +
  • verbose (bool, optional) – If False, disable log output during tuning.

  • +
  • check_neutrality (bool, optional) – Raise a warning if the system is not electrically neutral when +set to True (default).

  • +
+
+
+
+ +
+
+class espressomd.electrostatics.P3MGPU(**kwargs)[source]
+

Bases: espressomd.electrostatics._P3MBase

+

P3M electrostatics solver with GPU support.

+

Particle–Particle–Particle–Mesh (P3M) is a Fourier-based Ewald +summation method to calculate potentials in N-body simulation. +See Coulomb P3M on GPU for more details.

+
+
Parameters
+
    +
  • prefactor (float) – Electrostatics prefactor (see (1)).

  • +
  • accuracy (float) – P3M tunes its parameters to provide this target accuracy.

  • +
  • alpha (float, optional) – The Ewald parameter.

  • +
  • cao (float, optional) – The charge-assignment order, an integer between 0 and 7.

  • +
  • epsilon (float or str, optional) – A positive number for the dielectric constant of the +surrounding medium. Use 'metallic' to set the dielectric +constant of the surrounding medium to infinity (default).

  • +
  • mesh (int or (3,) array_like of int, optional) – The number of mesh points in x, y and z direction. Use a single +value for cubic boxes.

  • +
  • mesh_off ((3,) array_like of float, optional) – Mesh offset.

  • +
  • r_cut (float, optional) – The real space cutoff

  • +
  • tune (bool, optional) – Used to activate/deactivate the tuning method on activation. +Defaults to True.

  • +
  • timings (int) – Number of force calculations during tuning.

  • +
  • verbose (bool, optional) – If False, disable log output during tuning.

  • +
  • check_neutrality (bool, optional) – Raise a warning if the system is not electrically neutral when +set to True (default).

  • +
+
+
+
+ +
+
+class espressomd.electrostatics.ReactionField(**kwargs)[source]
+

Bases: espressomd.electrostatics.ElectrostaticInteraction

+

Electrostatics solver based on the Reaction Field framework. +See Reaction Field method for more details.

+
+
Parameters
+
    +
  • prefactor (float) – Electrostatics prefactor (see (1)).

  • +
  • kappa (float) – Inverse Debye screening length.

  • +
  • epsilon1 (float) – interior dielectric constant

  • +
  • epsilon2 (float) – exterior dielectric constant

  • +
  • r_cut (float) – Cutoff radius for this interaction.

  • +
+
+
+
+
+default_params()[source]
+
+ +
+
+required_keys()[source]
+
+ +
+
+valid_keys()[source]
+
+ +
+ +
+
+class espressomd.electrostatics.Scafacos(**kwargs)[source]
+

Bases: espressomd.electrostatics.ElectrostaticInteraction

+

Calculate the Coulomb interaction using the ScaFaCoS library. +See ScaFaCoS electrostatics for more details.

+
+
Parameters
+
    +
  • prefactor (float) – Coulomb prefactor as defined in (1).

  • +
  • method_name (str) – Name of the ScaFaCoS method to use.

  • +
  • method_params (dict) – Dictionary containing the method-specific parameters.

  • +
+
+
+
+
+get_available_methods()
+

List long-range methods available in the ScaFaCoS library.

+
+ +
+
+set_near_field_delegation()
+

Choose whether to delegate short-range calculation to ESPResSo +(this is the default when the method supports it) or ScaFaCos.

+
+
Parameters
+

delegate (bool) – Delegate to ESPResSo if True and the method supports it.

+
+
+
+ +
+
+get_near_field_delegation()
+

Find whether the short-range calculation is delegated to ESPResSo +(this is the default when the method supports it) or ScaFaCos.

+
+
Returns
+

delegate – Delegate to ESPResSo if True and the method supports it, +False if delegated to ScaFaCoS or the method doesn’t have a +short-range kernel.

+
+
Return type
+

bool

+
+
+
+ +
+
+default_params()[source]
+
+ +
+
+required_keys()[source]
+
+ +
+
+valid_keys()[source]
+
+ +
+
+validate_params(params)[source]
+

Check validity of given parameters.

+
+ +
+ +
+
+

espressomd.galilei module

+
+
+class espressomd.galilei.GalileiTransform
+

Bases: object

+
+
+galilei_transform(self)
+

Remove the center of mass velocity of the system. Assumes equal unit +mass if the mass feature is not used. This is often used when switching +from Langevin Dynamics to lattice-Boltzmann. This is due to the random +nature of LD that yield a non-zero net system momentum at any given +time.

+
+ +
+
+kill_particle_forces(self, torque=False)
+

Set the forces on the particles to zero.

+
+
Parameters
+

torque (bool, optional) – Whether or not to kill the torques on all particles too.

+
+
+
+ +
+
+kill_particle_motion(self, rotation=False)
+

Stop the motion of the particles.

+
+
Parameters
+

rotation (bool, optional) – Whether or not to kill the rotations too.

+
+
+
+ +
+
+system_CMS(self)
+

Calculate the center of mass of the system. Assumes equal unit mass if the mass feature is not used.

+
+
Returns
+

cms – The of the center of mass position vector.

+
+
Return type
+

(3,) array_like of float

+
+
+
+ +
+
+system_CMS_velocity(self)
+

Calculate the center of mass velocity of the system. Assumes equal unit +mass if the mass feature is not used.

+
+
Returns
+

cms_vel – The of the center of mass velocity vector.

+
+
Return type
+

(3,) array_like of float

+
+
+
+ +
+ +
+
+

espressomd.highlander module

+
+
+exception espressomd.highlander.ThereCanOnlyBeOne(cls)[source]
+

Bases: BaseException

+
+ +
+
+espressomd.highlander.highlander(klass)[source]
+
+ +
+
+

espressomd.integrate module

+
+
+class espressomd.integrate.BrownianDynamics
+

Bases: espressomd.integrate.Integrator

+

Brownian Dynamics integrator.

+
+
+default_params(self)
+
+ +
+
+required_keys(self)
+

Parameters that have to be set.

+
+ +
+
+valid_keys(self)
+

All parameters that can be set.

+
+ +
+
+validate_params(self)
+

Check that parameters are valid.

+
+ +
+ +
+
+class espressomd.integrate.Integrator(*args, **kwargs)
+

Bases: object

+

Integrator class.

+
+
+default_params(self)
+

Virtual method.

+
+ +
+
+get_params(self)
+

Get integrator parameters.

+
+ +
+
+required_keys(self)
+

Virtual method.

+
+ +
+
+run(self, steps=1, recalc_forces=False, reuse_forces=False)
+

Run the integrator.

+
+
Parameters
+
    +
  • steps (int) – Number of time steps to integrate.

  • +
  • recalc_forces (bool, optional) – Recalculate the forces regardless of whether they are reusable.

  • +
  • reuse_forces (bool, optional) – Reuse the forces from previous time step.

  • +
+
+
+
+ +
+
+valid_keys(self)
+

Virtual method.

+
+ +
+
+validate_params(self)
+

Check that parameters are valid.

+
+ +
+ +
+
+class espressomd.integrate.IntegratorHandle
+

Bases: object

+

Provide access to all integrators.

+
+
+force_cap
+
+ +
+
+get_state(self)
+

Return the integrator.

+
+ +
+
+run(self, *args, **kwargs)
+

Run the integrator.

+
+ +
+
+set_brownian_dynamics(self)
+

Set the integration method to BD.

+
+ +
+
+set_isotropic_npt(self, *args, **kwargs)
+

Set the integration method to a modified velocity Verlet designed for +simulations in the NpT ensemble (VelocityVerletIsotropicNPT).

+
+ +
+
+set_nvt(self)
+

Set the integration method to velocity Verlet, which is suitable for +simulations in the NVT ensemble (VelocityVerlet).

+
+ +
+
+set_steepest_descent(self, *args, **kwargs)
+

Set the integration method to steepest descent +(SteepestDescent).

+
+ +
+
+set_stokesian_dynamics(self, *args, **kwargs)
+

Set the integration method to Stokesian Dynamics (StokesianDynamics).

+
+ +
+
+set_vv(self)
+

Set the integration method to velocity Verlet, which is suitable for +simulations in the NVT ensemble (VelocityVerlet).

+
+ +
+
+time
+
+ +
+
+time_step
+
+ +
+ +
+
+class espressomd.integrate.SteepestDescent
+

Bases: espressomd.integrate.Integrator

+

Steepest descent algorithm for energy minimization.

+

Particles located at \(\vec{r}_i\) at integration step \(i\) and +experiencing a potential \(\mathcal{H}(\vec{r}_i)\) are displaced +according to the equation:

+

\(\vec{r}_{i+1} = \vec{r}_i - \gamma\nabla\mathcal{H}(\vec{r}_i)\)

+
+
Parameters
+
    +
  • f_max (float) – Convergence criterion. Minimization stops when the maximal force on +particles in the system is lower than this threshold. Set this to 0 +when running minimization in a loop that stops when a custom +convergence criterion is met.

  • +
  • gamma (float) – Dampening constant.

  • +
  • max_displacement (float) – Maximal allowed displacement per step. Typical values for a LJ liquid +are in the range of 0.1% to 10% of the particle sigma.

  • +
+
+
+
+
+default_params(self)
+
+ +
+
+required_keys(self)
+

Parameters that have to be set.

+
+ +
+
+run(self, steps=1, **kwargs)
+

Run the steepest descent.

+
+
Parameters
+

steps (int) – Maximal number of time steps to integrate.

+
+
Returns
+

Number of integrated steps.

+
+
Return type
+

int

+
+
+
+ +
+
+valid_keys(self)
+

All parameters that can be set.

+
+ +
+
+validate_params(self)
+
+ +
+ +
+
+class espressomd.integrate.StokesianDynamics
+

Bases: espressomd.integrate.Integrator

+

Stokesian Dynamics integrator.

+
+
Parameters
+
    +
  • viscosity (float) – Bulk viscosity.

  • +
  • radii (dict) – Dictionary that maps particle types to radii.

  • +
  • approximation_method (str, optional, {‘ft’, ‘fts’}) – Chooses the method of the mobility approximation. +'fts' is more accurate. Default is 'fts'.

  • +
  • self_mobility (bool, optional) – Switches off or on the mobility terms for single particles. Default +is True.

  • +
  • pair_mobility (bool, optional) – Switches off or on the hydrodynamic interactions between particles. +Default is True.

  • +
+
+
+
+
+default_params(self)
+
+ +
+
+required_keys(self)
+

Parameters that have to be set.

+
+ +
+
+valid_keys(self)
+

All parameters that can be set.

+
+ +
+
+validate_params(self)
+

Check that parameters are valid.

+
+ +
+ +
+
+class espressomd.integrate.VelocityVerlet
+

Bases: espressomd.integrate.Integrator

+

Velocity Verlet integrator, suitable for simulations in the NVT ensemble.

+
+
+default_params(self)
+
+ +
+
+required_keys(self)
+

Parameters that have to be set.

+
+ +
+
+valid_keys(self)
+

All parameters that can be set.

+
+ +
+
+validate_params(self)
+

Check that parameters are valid.

+
+ +
+ +
+
+class espressomd.integrate.VelocityVerletIsotropicNPT
+

Bases: espressomd.integrate.Integrator

+

Modified velocity Verlet integrator, suitable for simulations in the +NpT ensemble with isotropic rescaling. Requires the NpT thermostat, +activated with espressomd.thermostat.Thermostat.set_npt().

+
+
Parameters
+
    +
  • ext_pressure (float) – The external pressure.

  • +
  • piston (float) – The mass of the applied piston.

  • +
  • direction ((3,) array_like of bool, optional) – Select which dimensions are allowed to fluctuate by assigning +them to True.

  • +
  • cubic_box (bool, optional) – If True, a cubic box is assumed and the value of direction +will be ignored when rescaling the box. This is required e.g. for +electrostatics and magnetostatics.

  • +
+
+
+
+
+default_params(self)
+
+ +
+
+required_keys(self)
+

Parameters that have to be set.

+
+ +
+
+valid_keys(self)
+

All parameters that can be set.

+
+ +
+
+validate_params(self)
+
+ +
+ +
+
+

espressomd.interactions module

+
+
+class espressomd.interactions.AngleCosine(*args, **kwargs)
+

Bases: espressomd.interactions.BondedInteraction

+

Bond-angle-dependent cosine potential.

+
+
Parameters
+
    +
  • phi0 (float) – Equilibrium bond angle in radians.

  • +
  • bend (float) – Magnitude of the bond interaction.

  • +
+
+
+
+
+get_default_params(self)
+

Gets default values of optional parameters.

+
+ +
+
+type_name(self)
+

Name of interaction type.

+
+ +
+
+type_number(self)
+
+ +
+ +
+
+class espressomd.interactions.AngleCossquare(*args, **kwargs)
+

Bases: espressomd.interactions.BondedInteraction

+

Bond-angle-dependent cosine squared potential.

+
+
Parameters
+
    +
  • phi0 (float) – Equilibrium bond angle in radians.

  • +
  • bend (float) – Magnitude of the bond interaction.

  • +
+
+
+
+
+get_default_params(self)
+

Gets default values of optional parameters.

+
+ +
+
+type_name(self)
+

Name of interaction type.

+
+ +
+
+type_number(self)
+
+ +
+ +
+
+class espressomd.interactions.AngleHarmonic(*args, **kwargs)
+

Bases: espressomd.interactions.BondedInteraction

+

Bond-angle-dependent harmonic potential.

+
+
Parameters
+
    +
  • phi0 (float) – Equilibrium bond angle in radians.

  • +
  • bend (float) – Magnitude of the bond interaction.

  • +
+
+
+
+
+get_default_params(self)
+

Gets default values of optional parameters.

+
+ +
+
+type_name(self)
+

Name of interaction type.

+
+ +
+
+type_number(self)
+
+ +
+ +
+
+class espressomd.interactions.BMHTFInteraction
+

Bases: espressomd.interactions.NonBondedInteraction

+
+
+default_params(self)
+

Python dictionary of default parameters.

+
+ +
+
+is_active(self)
+

Check if interaction is active.

+
+ +
+
+required_keys(self)
+

Parameters that have to be set.

+
+ +
+
+set_params(self, **kwargs)
+

Set parameters for the BMHTF interaction.

+
+
Parameters
+
    +
  • a (float) – Magnitude of exponential part of the interaction.

  • +
  • b (float) – Exponential factor of the interaction.

  • +
  • c (float) – Magnitude of the term decaying with the sixth power of r.

  • +
  • d (float) – Magnitude of the term decaying with the eighth power of r.

  • +
  • sig (float) – Shift in the exponent.

  • +
  • cutoff (float) – Cutoff distance of the interaction.

  • +
+
+
+
+ +
+
+type_name(self)
+

Name of interaction type.

+
+ +
+
+valid_keys(self)
+

All parameters that can be set.

+
+ +
+
+validate_params(self)
+

Check that parameters are valid.

+
+ +
+ +
+
+class espressomd.interactions.BondedCoulomb(*args, **kwargs)
+

Bases: espressomd.interactions.BondedInteraction

+

Bonded Coulomb bond.

+
+
Parameters
+

prefactor (float) – Coulomb prefactor of the bonded Coulomb interaction.

+
+
+
+
+get_default_params(self)
+

Gets default values of optional parameters.

+
+ +
+
+type_name(self)
+
+ +
+
+type_number(self)
+
+ +
+ +
+
+class espressomd.interactions.BondedCoulombSRBond(*args, **kwargs)
+

Bases: espressomd.interactions.BondedInteraction

+

Bonded Coulomb short range bond. Calculates the short range part of +Coulomb interactions.

+
+
Parameters
+

q1q2 (float) – Charge factor of the involved particle pair. Note the +particle charges are used to allow e.g. only partial subtraction +of the involved charges.

+
+
+
+
+get_default_params(self)
+
+ +
+
+type_name(self)
+
+ +
+
+type_number(self)
+
+ +
+ +
+
+class espressomd.interactions.BondedInteraction(*args, **kwargs)
+

Bases: espressomd.script_interface.ScriptInterfaceHelper

+

Base class for bonded interactions.

+

Either called with an interaction id, in which case the interaction +will represent the bonded interaction as it is defined in ESPResSo core, +or called with keyword arguments describing a new interaction.

+
+
+get_default_params(self)
+

Gets default values of optional parameters.

+
+ +
+
+property params
+
+ +
+
+required_keys(self)
+

Parameters that have to be set.

+
+ +
+
+type_name(self)
+

Name of interaction type.

+
+ +
+
+type_number(self)
+
+ +
+
+valid_keys(self)
+

All parameters that can be set.

+
+ +
+
+validate_params(self, params)
+

Check that parameters are valid.

+
+ +
+ +
+
+class espressomd.interactions.BondedInteractionNotDefined(*args, **kwargs)
+

Bases: object

+
+
+get_default_params(self)
+

Gets default values of optional parameters.

+
+ +
+
+required_keys(self)
+

Parameters that have to be set.

+
+ +
+
+type_name(self)
+

Name of interaction type.

+
+ +
+
+type_number(self)
+
+ +
+
+valid_keys(self)
+

All parameters that can be set.

+
+ +
+ +
+
+class espressomd.interactions.BondedInteractions(**kwargs)
+

Bases: espressomd.script_interface.ScriptObjectMap

+

Represents the bonded interactions list.

+

Individual interactions can be accessed using BondedInteractions[i], +where i is the bond id.

+
+
+remove():
+

Remove a bond from the list. +This is a no-op if the bond does not exist.

+
+
Parameters
+

bond_id (int)

+
+
+
+ +
+
+clear()
+

Remove all bonds.

+
+ +
+
+add(self, *args, **kwargs)
+

Add a bond to the list.

+
+
Parameters
+
+
+
+
+ +
+ +
+
+class espressomd.interactions.BuckinghamInteraction
+

Bases: espressomd.interactions.NonBondedInteraction

+
+
+default_params(self)
+

Python dictionary of default parameters.

+
+ +
+
+is_active(self)
+

Check if interaction is active.

+
+ +
+
+required_keys(self)
+

Parameters that have to be set.

+
+ +
+
+set_params(self, **kwargs)
+

Set parameters for the Buckingham interaction.

+
+
Parameters
+
    +
  • a (float) – Magnitude of the exponential part of the interaction.

  • +
  • b (float, optional) – Exponent of the exponential part of the interaction.

  • +
  • c (float) – Prefactor of term decaying with the sixth power of distance.

  • +
  • d (float) – Prefactor of term decaying with the fourth power of distance.

  • +
  • discont (float) – Distance below which the potential is linearly continued.

  • +
  • cutoff (float) – Cutoff distance of the interaction.

  • +
  • shift (float, optional) – Constant potential shift.

  • +
+
+
+
+ +
+
+type_name(self)
+

Name of interaction type.

+
+ +
+
+valid_keys(self)
+

All parameters that can be set.

+
+ +
+
+validate_params(self)
+

Check that parameters are valid.

+
+ +
+ +
+
+class espressomd.interactions.DPDInteraction
+

Bases: espressomd.interactions.NonBondedInteraction

+
+
+default_params(self)
+
+ +
+
+is_active(self)
+
+ +
+
+required_keys(self)
+
+ +
+
+set_params(self, **kwargs)
+

Set parameters for the DPD interaction.

+
+
Parameters
+
    +
  • weight_function (int, {0, 1}) – The distance dependence of the parallel part, +either 0 (constant) or 1 (linear)

  • +
  • gamma (float) – Friction coefficient of the parallel part

  • +
  • k (float) – Exponent in the modified weight function

  • +
  • r_cut (float) – Cutoff of the parallel part

  • +
  • trans_weight_function (int, {0, 1}) – The distance dependence of the orthogonal part, +either 0 (constant) or 1 (linear)

  • +
  • trans_gamma (float) – Friction coefficient of the orthogonal part

  • +
  • trans_r_cut (float) – Cutoff of the orthogonal part

  • +
+
+
+
+ +
+
+type_name(self)
+
+ +
+
+valid_keys(self)
+
+ +
+
+validate_params(self)
+

Check that parameters are valid.

+
+ +
+ +
+
+class espressomd.interactions.Dihedral(*args, **kwargs)
+

Bases: espressomd.interactions.BondedInteraction

+

Dihedral potential with phase shift.

+
+
Parameters
+
    +
  • mult (int) – Multiplicity of the potential (number of minima).

  • +
  • bend (float) – Bending constant.

  • +
  • phase (float) – Angle of the first local minimum in radians.

  • +
+
+
+
+
+get_default_params(self)
+

Gets default values of optional parameters.

+
+ +
+
+type_name(self)
+

Name of interaction type.

+
+ +
+
+type_number(self)
+
+ +
+
+validate_params(self, params)
+

Check that parameters are valid.

+
+ +
+ +
+
+class espressomd.interactions.FeneBond(*args, **kwargs)
+

Bases: espressomd.interactions.BondedInteraction

+

FENE bond.

+
+
Parameters
+
    +
  • k (float) – Magnitude of the bond interaction.

  • +
  • d_r_max (float) – Maximum stretch and compression length of the bond.

  • +
  • r_0 (float, optional) – Equilibrium bond length.

  • +
+
+
+
+
+get_default_params(self)
+

Gets default values of optional parameters.

+
+ +
+
+type_name(self)
+

Name of interaction type.

+
+ +
+
+type_number(self)
+
+ +
+ +
+
+class espressomd.interactions.GaussianInteraction
+

Bases: espressomd.interactions.NonBondedInteraction

+
+
+default_params(self)
+

Python dictionary of default parameters.

+
+ +
+
+is_active(self)
+

Check if interaction is active.

+
+ +
+
+required_keys(self)
+

Parameters that have to be set.

+
+ +
+
+set_params(self, **kwargs)
+

Set parameters for the Gaussian interaction.

+
+
Parameters
+
    +
  • eps (float) – Overlap energy epsilon.

  • +
  • sig (float) – Variance sigma of the Gaussian interaction.

  • +
  • cutoff (float) – Cutoff distance of the interaction.

  • +
+
+
+
+ +
+
+type_name(self)
+

Name of interaction type.

+
+ +
+
+valid_keys(self)
+

All parameters that can be set.

+
+ +
+
+validate_params(self)
+

Check that parameters are valid.

+
+ +
+ +
+
+class espressomd.interactions.GayBerneInteraction
+

Bases: espressomd.interactions.NonBondedInteraction

+
+
+default_params(self)
+

Python dictionary of default parameters.

+
+ +
+
+is_active(self)
+

Check if interaction is active.

+
+ +
+
+required_keys(self)
+

Parameters that have to be set.

+
+ +
+
+set_params(self, **kwargs)
+

Set parameters for the Gay-Berne interaction.

+
+
Parameters
+
    +
  • eps (float) – Potential well depth.

  • +
  • sig (float) – Interaction range.

  • +
  • cut (float) – Cutoff distance of the interaction.

  • +
  • k1 (float or str) – Molecular elongation.

  • +
  • k2 (float, optional) – Ratio of the potential well depths for the side-by-side +and end-to-end configurations.

  • +
  • mu (float, optional) – Adjustable exponent.

  • +
  • nu (float, optional) – Adjustable exponent.

  • +
+
+
+
+ +
+
+type_name(self)
+

Name of interaction type.

+
+ +
+
+valid_keys(self)
+

All parameters that can be set.

+
+ +
+
+validate_params(self)
+

Check that parameters are valid.

+
+ +
+ +
+
+class espressomd.interactions.GenericLennardJonesInteraction
+

Bases: espressomd.interactions.NonBondedInteraction

+
+
+default_params(self)
+

Python dictionary of default parameters.

+
+ +
+
+is_active(self)
+

Check if interaction is active.

+
+ +
+
+required_keys(self)
+

Parameters that have to be set.

+
+ +
+
+set_params(self, **kwargs)
+

Set parameters for the generic Lennard-Jones interaction.

+
+
Parameters
+
    +
  • epsilon (float) – Magnitude of the interaction.

  • +
  • sigma (float) – Interaction length scale.

  • +
  • cutoff (float) – Cutoff distance of the interaction.

  • +
  • shift (float or str {‘auto’}) – Constant shift of the potential. If 'auto', a default value +is computed from the other parameters. The LJ potential +will be shifted by \(\epsilon\cdot\text{shift}\).

  • +
  • offset (float) – Offset distance of the interaction.

  • +
  • e1 (int) – Exponent of the repulsion term.

  • +
  • e2 (int) – Exponent of the attraction term.

  • +
  • b1 (float) – Prefactor of the repulsion term.

  • +
  • b2 (float) – Prefactor of the attraction term.

  • +
  • delta (float, optional) – LJGEN_SOFTCORE parameter delta. Allows control over how +smoothly the potential drops to zero as lambda approaches zero.

  • +
  • lam (float, optional) – LJGEN_SOFTCORE parameter lambda. Tune the strength of the +interaction.

  • +
+
+
+
+ +
+
+type_name(self)
+

Name of interaction type.

+
+ +
+
+valid_keys(self)
+

All parameters that can be set.

+
+ +
+
+validate_params(self)
+

Check that parameters are valid.

+
+
Raises
+

ValueError – If not true.

+
+
+
+ +
+ +
+
+class espressomd.interactions.HarmonicBond(*args, **kwargs)
+

Bases: espressomd.interactions.BondedInteraction

+

Harmonic bond.

+
+
Parameters
+
    +
  • k (float) – Magnitude of the bond interaction.

  • +
  • r_0 (float) – Equilibrium bond length.

  • +
  • r_cut (float, optional) – Maximum distance beyond which the bond is considered broken.

  • +
+
+
+
+
+get_default_params(self)
+

Gets default values of optional parameters.

+
+ +
+
+type_name(self)
+

Name of interaction type.

+
+ +
+
+type_number(self)
+
+ +
+ +
+
+class espressomd.interactions.HatInteraction
+

Bases: espressomd.interactions.NonBondedInteraction

+
+
+default_params(self)
+
+ +
+
+is_active(self)
+
+ +
+
+required_keys(self)
+
+ +
+
+set_params(self, **kwargs)
+

Set parameters for the Hat interaction.

+
+
Parameters
+
    +
  • F_max (float) – Magnitude of the interaction.

  • +
  • cutoff (float) – Cutoff distance of the interaction.

  • +
+
+
+
+ +
+
+type_name(self)
+
+ +
+
+valid_keys(self)
+
+ +
+
+validate_params(self)
+
+ +
+ +
+
+class espressomd.interactions.HertzianInteraction
+

Bases: espressomd.interactions.NonBondedInteraction

+
+
+default_params(self)
+

Python dictionary of default parameters.

+
+ +
+
+is_active(self)
+

Check if interaction is active.

+
+ +
+
+required_keys(self)
+

Parameters that have to be set.

+
+ +
+
+set_params(self, **kwargs)
+

Set parameters for the Hertzian interaction.

+
+
Parameters
+
    +
  • eps (float) – Magnitude of the interaction.

  • +
  • sig (float) – Parameter sigma. Determines the length over which the potential +decays.

  • +
+
+
+
+ +
+
+type_name(self)
+

Name of interaction type.

+
+ +
+
+valid_keys(self)
+

All parameters that can be set.

+
+ +
+
+validate_params(self)
+

Check that parameters are valid.

+
+ +
+ +
+
+class espressomd.interactions.IBM_Tribend(*args, **kwargs)
+

Bases: espressomd.interactions.BondedInteraction

+

IBM Tribend bond.

+

See Figure C.2 in [Krüger, 2012].

+
+
Parameters
+
    +
  • ind1, ind2, ind3, ind4 (int) – First, second, third and fourth bonding partner. Used for +initializing reference state

  • +
  • kb (float) – Bending modulus

  • +
  • refShape (str, optional, {‘Flat’, ‘Initial’}) – Reference shape, default is 'Flat'

  • +
+
+
+
+
+get_default_params(self)
+

Gets default values of optional parameters.

+
+ +
+
+type_name(self)
+
+ +
+
+type_number(self)
+
+ +
+
+valid_keys(self)
+
+ +
+
+validate_params(self, params)
+

Check that parameters are valid.

+
+ +
+ +
+
+class espressomd.interactions.IBM_Triel(*args, **kwargs)
+

Bases: espressomd.interactions.BondedInteraction

+

IBM Triel bond.

+

See Figure C.1 in [Krüger, 2012].

+
+
Parameters
+
    +
  • ind1, ind2, ind3 (int) – First, second and third bonding partner. Used for +initializing reference state

  • +
  • k1 (float) – Shear elasticity for Skalak and Neo-Hookean

  • +
  • k2 (float, optional) – Area resistance for Skalak

  • +
  • maxDist (float) – Gives an error if an edge becomes longer than maxDist

  • +
  • elasticLaw (str, {‘NeoHookean’, ‘Skalak’}) – Type of elastic bond

  • +
+
+
+
+
+get_default_params(self)
+

Gets default values of optional parameters.

+
+ +
+
+type_name(self)
+
+ +
+
+type_number(self)
+
+ +
+
+valid_keys(self)
+
+ +
+
+validate_params(self, params)
+

Check that parameters are valid.

+
+ +
+ +
+
+class espressomd.interactions.IBM_VolCons(*args, **kwargs)
+

Bases: espressomd.interactions.BondedInteraction

+

IBM volume conservation bond.

+

See Figure C.3 in [Krüger, 2012].

+
+
Parameters
+
    +
  • softID (int) – Used to identify the object to which this bond belongs. Each object +(cell) needs its own ID. For performance reasons, it is best to +start from softID=0 and increment by 1 for each subsequent bond.

  • +
  • kappaV (float) – Modulus for volume force

  • +
+
+
+
+
+current_volume(self)
+

Query the current volume of the soft object associated to this bond. +The volume is initialized once all IBM_Triel bonds have +been added and the forces have been recalculated.

+
+ +
+
+get_default_params(self)
+

Gets default values of optional parameters.

+
+ +
+
+type_name(self)
+
+ +
+
+type_number(self)
+
+ +
+ +
+
+class espressomd.interactions.LennardJonesCos2Interaction
+

Bases: espressomd.interactions.NonBondedInteraction

+
+
+default_params(self)
+
+ +
+
+is_active(self)
+
+ +
+
+required_keys(self)
+

Parameters that have to be set.

+
+ +
+
+set_params(self, **kwargs)
+

Set parameters for the Lennard-Jones cosine squared interaction.

+
+
Parameters
+
    +
  • epsilon (float) – Magnitude of the interaction.

  • +
  • sigma (float) – Interaction length scale.

  • +
  • offset (float, optional) – Offset distance of the interaction.

  • +
  • width (float) – Width of interaction.

  • +
+
+
+
+ +
+
+type_name(self)
+

Name of interaction type.

+
+ +
+
+valid_keys(self)
+

All parameters that can be set.

+
+ +
+
+validate_params(self)
+
+ +
+ +
+
+class espressomd.interactions.LennardJonesCosInteraction
+

Bases: espressomd.interactions.NonBondedInteraction

+
+
+default_params(self)
+
+ +
+
+is_active(self)
+
+ +
+
+required_keys(self)
+

Parameters that have to be set.

+
+ +
+
+set_params(self, **kwargs)
+

Set parameters for the Lennard-Jones cosine interaction.

+
+
Parameters
+
    +
  • epsilon (float) – Magnitude of the interaction.

  • +
  • sigma (float) – Interaction length scale.

  • +
  • cutoff (float) – Cutoff distance of the interaction.

  • +
  • offset (float, optional) – Offset distance of the interaction.

  • +
+
+
+
+ +
+
+type_name(self)
+

Name of interaction type.

+
+ +
+
+valid_keys(self)
+

All parameters that can be set.

+
+ +
+
+validate_params(self)
+
+ +
+ +
+
+class espressomd.interactions.LennardJonesInteraction
+

Bases: espressomd.interactions.NonBondedInteraction

+
+
+default_params(self)
+

Python dictionary of default parameters.

+
+ +
+
+is_active(self)
+

Check if interaction is active.

+
+ +
+
+required_keys(self)
+

Parameters that have to be set.

+
+ +
+
+set_params(self, **kwargs)
+

Set parameters for the Lennard-Jones interaction.

+
+
Parameters
+
    +
  • epsilon (float) – Magnitude of the interaction.

  • +
  • sigma (float) – Interaction length scale.

  • +
  • cutoff (float) – Cutoff distance of the interaction.

  • +
  • shift (float or str {‘auto’}) – Constant shift of the potential. If 'auto', a default value +is computed from sigma and cutoff. The LJ potential +will be shifted by \(4\epsilon\cdot\text{shift}\).

  • +
  • offset (float, optional) – Offset distance of the interaction.

  • +
  • min (float, optional) – Restricts the interaction to a minimal distance.

  • +
+
+
+
+ +
+
+type_name(self)
+

Name of interaction type.

+
+ +
+
+valid_keys(self)
+

All parameters that can be set.

+
+ +
+
+validate_params(self)
+

Check that parameters are valid.

+
+
Raises
+

ValueError – If not true.

+
+
+
+ +
+ +
+
+class espressomd.interactions.MorseInteraction
+

Bases: espressomd.interactions.NonBondedInteraction

+
+
+default_params(self)
+

Python dictionary of default parameters.

+
+ +
+
+is_active(self)
+

Check if interaction is active.

+
+ +
+
+required_keys(self)
+

Parameters that have to be set.

+
+ +
+
+set_params(self, **kwargs)
+

Set parameters for the Morse interaction.

+
+
Parameters
+
    +
  • eps (float) – The magnitude of the interaction.

  • +
  • alpha (float) – Stiffness of the Morse interaction.

  • +
  • rmin (float) – Distance of potential minimum

  • +
  • cutoff (float, optional) – Cutoff distance of the interaction.

  • +
+
+
+
+ +
+
+type_name(self)
+

Name of interaction type.

+
+ +
+
+valid_keys(self)
+

All parameters that can be set.

+
+ +
+
+validate_params(self)
+

Check that parameters are valid.

+
+ +
+ +
+
+class espressomd.interactions.NonBondedInteraction(*args, **kwargs)
+

Bases: object

+

Represents an instance of a non-bonded interaction, such as Lennard-Jones. +Either called with two particle type id, in which case, the interaction +will represent the bonded interaction as it is defined in ESPResSo core, +or called with keyword arguments describing a new interaction.

+
+
+default_params(self)
+

Virtual method.

+
+ +
+
+get_params(self)
+

Get interaction parameters.

+
+ +
+
+is_active(self)
+

Virtual method.

+
+ +
+
+is_valid(self)
+

Check, if the data stored in the instance still matches what is in ESPResSo.

+
+ +
+
+required_keys(self)
+

Virtual method.

+
+ +
+
+set_params(self, **p)
+

Update the given parameters.

+
+ +
+
+type_name(self)
+

Virtual method.

+
+ +
+
+user_interactions
+

object

+
+
Type
+

user_interactions

+
+
+
+ +
+
+valid_keys(self)
+

Virtual method.

+
+ +
+
+validate_params(self)
+

Check that parameters are valid.

+
+ +
+ +
+
+class espressomd.interactions.NonBondedInteractionHandle(_type1, _type2)
+

Bases: object

+

Provides access to all non-bonded interactions between two particle types.

+
+
+bmhtf = None
+
+ +
+
+buckingham = None
+
+ +
+
+dpd = None
+
+ +
+
+gaussian = None
+
+ +
+
+gay_berne = None
+
+ +
+
+generic_lennard_jones = None
+
+ +
+
+hat = None
+
+ +
+
+hertzian = None
+
+ +
+
+lennard_jones = None
+
+ +
+
+lennard_jones_cos = None
+
+ +
+
+lennard_jones_cos2 = None
+
+ +
+
+morse = None
+
+ +
+
+smooth_step = None
+
+ +
+
+soft_sphere = None
+
+ +
+
+tabulated = None
+
+ +
+
+thole = None
+
+ +
+
+type1 = -1
+
+ +
+
+type2 = -1
+
+ +
+ +
+
+class espressomd.interactions.NonBondedInteractions
+

Bases: object

+

Access to non-bonded interaction parameters via [i,j], where i, j +are particle types. Returns a NonBondedInteractionHandle object. +Also: access to force capping.

+
+
+reset(self)
+

Reset all interaction parameters to their default values.

+
+ +
+ +
+
+class espressomd.interactions.OifGlobalForces(*args, **kwargs)
+

Bases: espressomd.interactions.BondedInteraction

+

Characterize the distribution of the force of the global mesh deformation +onto individual vertices of the mesh.

+

Part of the Object-in-fluid method.

+
+
Parameters
+
    +
  • A0_g (float) – Relaxed area of the mesh

  • +
  • ka_g (float) – Area coefficient

  • +
  • V0 (float) – Relaxed volume of the mesh

  • +
  • kv (float) – Volume coefficient

  • +
+
+
+
+
+get_default_params(self)
+

Gets default values of optional parameters.

+
+ +
+
+type_name(self)
+

Name of interaction type.

+
+ +
+
+type_number(self)
+
+ +
+ +
+
+class espressomd.interactions.OifLocalForces(*args, **kwargs)
+

Bases: espressomd.interactions.BondedInteraction

+

Characterize the deformation of two triangles sharing an edge.

+

Part of the Object-in-fluid method.

+
+
Parameters
+
    +
  • r0 (float) – Equilibrium bond length of triangle edges

  • +
  • ks (float) – Non-linear stretching coefficient of triangle edges

  • +
  • kslin (float) – Linear stretching coefficient of triangle edges

  • +
  • phi0 (float) – Equilibrium angle between the two triangles

  • +
  • kb (float) – Bending coefficient for the angle between the two triangles

  • +
  • A01 (float) – Equilibrium surface of the first triangle

  • +
  • A02 (float) – Equilibrium surface of the second triangle

  • +
  • kal (float) – Stretching coefficient of a triangle surface

  • +
  • kvisc (float) – Viscous coefficient of the triangle vertices

  • +
+
+
+
+
+get_default_params(self)
+

Gets default values of optional parameters.

+
+ +
+
+type_name(self)
+

Name of interaction type.

+
+ +
+
+type_number(self)
+
+ +
+ +
+
+class espressomd.interactions.QuarticBond(*args, **kwargs)
+

Bases: espressomd.interactions.BondedInteraction

+

Quartic bond.

+
+
Parameters
+
    +
  • k0 (float) – Magnitude of the square term.

  • +
  • k1 (float) – Magnitude of the fourth order term.

  • +
  • r (float) – Equilibrium bond length.

  • +
  • r_cut (float) – Maximum interaction length.

  • +
+
+
+
+
+get_default_params(self)
+

Gets default values of optional parameters.

+
+ +
+
+type_name(self)
+

Name of interaction type.

+
+ +
+
+type_number(self)
+
+ +
+ +
+
+class espressomd.interactions.RigidBond(*args, **kwargs)
+

Bases: espressomd.interactions.BondedInteraction

+

Rigid bond.

+
+
Parameters
+
    +
  • r (float) – Bond length.

  • +
  • ptol (float, optional) – Tolerance for positional deviations.

  • +
  • vtop (float, optional) – Tolerance for velocity deviations.

  • +
+
+
+
+
+get_default_params(self)
+

Gets default values of optional parameters.

+
+ +
+
+type_name(self)
+

Name of interaction type.

+
+ +
+
+type_number(self)
+
+ +
+ +
+
+class espressomd.interactions.SmoothStepInteraction
+

Bases: espressomd.interactions.NonBondedInteraction

+
+
+default_params(self)
+

Python dictionary of default parameters.

+
+ +
+
+is_active(self)
+

Check if interaction is active.

+
+ +
+
+required_keys(self)
+

Parameters that have to be set.

+
+ +
+
+set_params(self, **kwargs)
+

Set parameters for the smooth-step interaction.

+
+
Parameters
+
    +
  • d (float) – Short range repulsion parameter.

  • +
  • n (int, optional) – Exponent of short range repulsion.

  • +
  • eps (float) – Magnitude of the second (soft) repulsion.

  • +
  • k0 (float, optional) – Exponential factor in second (soft) repulsion.

  • +
  • sig (float, optional) – Length scale of second (soft) repulsion.

  • +
  • cutoff (float) – Cutoff distance of the interaction.

  • +
+
+
+
+ +
+
+type_name(self)
+

Name of interaction type.

+
+ +
+
+valid_keys(self)
+

All parameters that can be set.

+
+ +
+
+validate_params(self)
+

Check that parameters are valid.

+
+ +
+ +
+
+class espressomd.interactions.SoftSphereInteraction
+

Bases: espressomd.interactions.NonBondedInteraction

+
+
+default_params(self)
+

Python dictionary of default parameters.

+
+ +
+
+is_active(self)
+

Check if interaction is active.

+
+ +
+
+required_keys(self)
+

Parameters that have to be set.

+
+ +
+
+set_params(self, **kwargs)
+

Set parameters for the Soft-sphere interaction.

+
+
Parameters
+
    +
  • a (float) – Magnitude of the interaction.

  • +
  • n (float) – Exponent of the power law.

  • +
  • cutoff (float) – Cutoff distance of the interaction.

  • +
  • offset (float, optional) – Offset distance of the interaction.

  • +
+
+
+
+ +
+
+type_name(self)
+

Name of interaction type.

+
+ +
+
+valid_keys(self)
+

All parameters that can be set.

+
+ +
+
+validate_params(self)
+

Check that parameters are valid.

+
+ +
+ +
+
+class espressomd.interactions.TabulatedAngle(*args, **kwargs)
+

Bases: espressomd.interactions._TabulatedBase

+

Tabulated bond angle.

+
+
Parameters
+
    +
  • energy (array_like of float) – The energy table for the range \(0-\pi\).

  • +
  • force (array_like of float) – The force table for the range \(0-\pi\).

  • +
+
+
+
+
+pi = 3.14159265358979
+
+ +
+
+type_name(self)
+

Name of interaction type.

+
+ +
+
+type_number(self)
+
+ +
+
+validate_params(self, params)
+

Check that parameters are valid.

+
+ +
+ +
+
+class espressomd.interactions.TabulatedDihedral(*args, **kwargs)
+

Bases: espressomd.interactions._TabulatedBase

+

Tabulated bond dihedral.

+
+
Parameters
+
    +
  • energy (array_like of float) – The energy table for the range \(0-2\pi\).

  • +
  • force (array_like of float) – The force table for the range \(0-2\pi\).

  • +
+
+
+
+
+pi = 3.14159265358979
+
+ +
+
+type_name(self)
+

Name of interaction type.

+
+ +
+
+type_number(self)
+
+ +
+
+validate_params(self, params)
+

Check that parameters are valid.

+
+ +
+ +
+
+class espressomd.interactions.TabulatedDistance(*args, **kwargs)
+

Bases: espressomd.interactions._TabulatedBase

+

Tabulated bond length.

+
+
Parameters
+
    +
  • min (float) – The minimal interaction distance.

  • +
  • max (float) – The maximal interaction distance.

  • +
  • energy (array_like of float) – The energy table.

  • +
  • force (array_like of float) – The force table.

  • +
+
+
+
+
+type_name(self)
+

Name of interaction type.

+
+ +
+
+type_number(self)
+
+ +
+ +
+
+class espressomd.interactions.TabulatedNonBonded(*args, **kwargs)
+

Bases: espressomd.interactions.NonBondedInteraction

+
+
+is_active(self)
+

Check if interaction is active.

+
+ +
+
+required_keys(self)
+

Parameters that have to be set.

+
+ +
+
+set_default_params(self)
+

Set parameters that are not required to their default value.

+
+ +
+
+set_params(self, **kwargs)
+

Set parameters for the TabulatedNonBonded interaction.

+
+
Parameters
+
    +
  • min (float,) – The minimal interaction distance.

  • +
  • max (float,) – The maximal interaction distance.

  • +
  • energy (array_like of float) – The energy table.

  • +
  • force (array_like of float) – The force table.

  • +
+
+
+
+ +
+
+type_name(self)
+

Name of the potential.

+
+ +
+
+type_number(self)
+
+ +
+
+valid_keys(self)
+

All parameters that can be set.

+
+ +
+ +
+
+class espressomd.interactions.ThermalizedBond(*args, **kwargs)
+

Bases: espressomd.interactions.BondedInteraction

+

Thermalized bond.

+
+
Parameters
+
    +
  • temp_com (float) – Temperature of the Langevin thermostat for the center of mass of the +particle pair.

  • +
  • gamma_com (float) – Friction coefficient of the Langevin thermostat for the center of mass +of the particle pair.

  • +
  • temp_distance (float) – Temperature of the Langevin thermostat for the distance vector +of the particle pair.

  • +
  • gamma_distance (float) – Friction coefficient of the Langevin thermostat for the +distance vector of the particle pair.

  • +
  • r_cut (float, optional) – Maximum distance beyond which the bond is considered broken.

  • +
  • seed (int) – Initial counter value (or seed) of the philox RNG. +Required on the first thermalized bond in the system. Must be positive. +If prompted, it does not return the initially set counter value +(the seed) but the current state of the RNG.

  • +
+
+
+
+
+get_default_params(self)
+
+ +
+
+type_name(self)
+
+ +
+
+type_number(self)
+
+ +
+
+validate_params(self, params)
+
+ +
+ +
+
+class espressomd.interactions.Virtual(*args, **kwargs)
+

Bases: espressomd.interactions.BondedInteraction

+

Virtual bond.

+
+
+get_default_params(self)
+

Gets default values of optional parameters.

+
+ +
+
+type_name(self)
+

Name of interaction type.

+
+ +
+
+type_number(self)
+
+ +
+ +
+
+class espressomd.interactions.WCAInteraction
+

Bases: espressomd.interactions.NonBondedInteraction

+
+
+default_params(self)
+

Python dictionary of default parameters.

+
+ +
+
+is_active(self)
+

Check if interaction is active.

+
+ +
+
+required_keys(self)
+

Parameters that have to be set.

+
+ +
+
+set_params(self, **kwargs)
+

Set parameters for the WCA interaction.

+
+
Parameters
+
    +
  • epsilon (float) – Magnitude of the interaction.

  • +
  • sigma (float) – Interaction length scale.

  • +
+
+
+
+ +
+
+type_name(self)
+

Name of interaction type.

+
+ +
+
+valid_keys(self)
+

All parameters that can be set.

+
+ +
+
+validate_params(self)
+

Check that parameters are valid.

+
+
Raises
+

ValueError – If not true.

+
+
+
+ +
+ +
+
+espressomd.interactions.get_bonded_interaction_type_from_es_core(bond_id)
+
+ +
+
+

espressomd.lb module

+
+
+class espressomd.lb.FluidActor(*args, **kwargs)
+

Bases: object

+

Abstract base class for interactions affecting particles in the system, +such as LB fluids. Derived classes must implement the interface to the +relevant core objects and global variables.

+
+
+active_list = {'HydrodynamicInteraction': False}
+
+ +
+
+class_lookup(self, cls)
+
+ +
+
+default_params(self)
+

Virtual method.

+
+ +
+
+get_params(self)
+

Get interaction parameters

+
+ +
+
+is_active(self)
+
+ +
+
+is_valid(self)
+

Check if the data stored in this instance still matches the +corresponding data in the core.

+
+ +
+
+required_keys(self)
+

Virtual method.

+
+ +
+
+set_params(self, **p)
+

Update the given parameters.

+
+ +
+
+system
+

object

+
+
Type
+

system

+
+
+
+ +
+
+valid_keys(self)
+

Virtual method.

+
+ +
+
+validate_params(self)
+

Virtual method.

+
+ +
+ +
+
+class espressomd.lb.HydrodynamicInteraction
+

Bases: espressomd.lb.FluidActor

+

Base class for LB implementations.

+
+
Parameters
+
    +
  • agrid (float) – Lattice constant. The box size in every direction must be an integer +multiple of agrid.

  • +
  • tau (float) – LB time step, must be an integer multiple of the MD time step.

  • +
  • dens (float) – Fluid density.

  • +
  • visc (float) – Fluid kinematic viscosity.

  • +
  • bulk_visc (float, optional) – Fluid bulk viscosity.

  • +
  • gamma_odd (int, optional) – Relaxation parameter \(\gamma_{\textrm{odd}}\) for kinetic modes.

  • +
  • gamma_even (int, optional) – Relaxation parameter \(\gamma_{\textrm{even}}\) for kinetic modes.

  • +
  • ext_force_density ((3,) array_like of float, optional) – Force density applied on the fluid.

  • +
  • kT (float, optional) – Thermal energy of the simulated heat bath (for thermalized fluids). +Set it to 0 for an unthermalized fluid.

  • +
  • seed (int, optional) – Initial counter value (or seed) of the philox RNG. +Required for a thermalized fluid. Must be positive.

  • +
+
+
+
+
+agrid
+
+ +
+
+bulk_viscosity
+
+ +
+
+default_params(self)
+
+ +
+
+density
+
+ +
+
+ext_force_density
+
+ +
+
+get_interpolated_velocity(self, pos)
+

Get LB fluid velocity at specified position.

+
+
Parameters
+

pos ((3,) array_like of float) – The position at which velocity is requested.

+
+
Returns
+

v – The LB fluid velocity at pos.

+
+
Return type
+

(3,) array_like float

+
+
+
+ +
+
+kT
+
+ +
+
+load_checkpoint(self, path, binary)
+

Load LB node populations from a file. +LBBoundaries +information is not available in the file. The boundary +information of the grid will be set to zero, +even if LBBoundaries +contains LBBoundary +objects (they are ignored).

+
+ +
+
+nodes(self)
+

Provides a generator for iterating over all lb nodes

+
+ +
+
+pressure_tensor
+
+ +
+
+required_keys(self)
+
+ +
+
+save_checkpoint(self, path, binary)
+

Write LB node populations to a file. +LBBoundaries +information is not written to the file.

+
+ +
+
+seed
+
+ +
+
+set_interpolation_order(self, interpolation_order)
+

Set the order for the fluid interpolation scheme.

+
+
Parameters
+

interpolation_order (str, {“linear”, “quadratic”}) – "linear" for trilinear interpolation, "quadratic" for +quadratic interpolation. For the CPU implementation of LB, only +"linear" is available.

+
+
+
+ +
+
+shape
+
+ +
+
+tau
+
+ +
+
+valid_keys(self)
+
+ +
+
+validate_params(self)
+
+ +
+
+viscosity
+
+ +
+
+write_boundary(self, path)
+

Write the LB boundaries to a data file that can be loaded by numpy, +with format “x y z u”.

+
+
Parameters
+

path (str) – Path to the output data file.

+
+
+
+ +
+
+write_velocity(self, path)
+

Write the LB fluid velocity to a data file that can be loaded by +numpy, with format “x y z vx vy vz”.

+
+
Parameters
+

path (str) – Path to the output data file.

+
+
+
+ +
+
+write_vtk_boundary(self, path)
+

Write the LB boundaries to a VTK file.

+
+
Parameters
+

path (str) – Path to the output ASCII file.

+
+
+
+ +
+
+write_vtk_velocity(self, path, bb1=None, bb2=None)
+

Write the LB fluid velocity to a VTK file. +If both bb1 and bb2 are specified, return a subset of the grid.

+
+
Parameters
+
    +
  • path (str) – Path to the output ASCII file.

  • +
  • bb1 ((3,) array_like of int, optional) – Node indices of the lower corner of the bounding box.

  • +
  • bb2 ((3,) array_like of int, optional) – Node indices of the upper corner of the bounding box.

  • +
+
+
+
+ +
+ +
+
+class espressomd.lb.LBFluid
+

Bases: espressomd.lb.HydrodynamicInteraction

+

Initialize the lattice-Boltzmann method for hydrodynamic flow using the CPU. +See HydrodynamicInteraction for the list of parameters.

+
+ +
+
+class espressomd.lb.LBFluidGPU
+

Bases: espressomd.lb.HydrodynamicInteraction

+

Initialize the lattice-Boltzmann method for hydrodynamic flow using the GPU. +See HydrodynamicInteraction for the list of parameters.

+
+
+get_interpolated_fluid_velocity_at_positions(self, ndarray positions, three_point=False)
+

Calculate the fluid velocity at given positions.

+
+
Parameters
+

positions ((N,3) numpy-array of type float) – The 3-dimensional positions.

+
+
Returns
+

velocities – The 3-dimensional LB fluid velocities.

+
+
Return type
+

(N,3) numpy-array of type float

+
+
Raises
+

AssertionError – If shape of positions not (N,3).

+
+
+
+ +
+ +
+
+class espressomd.lb.LBFluidRoutines(key)
+

Bases: object

+
+
+boundary
+
+ +
+
+density
+
+ +
+
+index
+
+ +
+
+population
+
+ +
+
+pressure_tensor
+
+ +
+
+pressure_tensor_neq
+
+ +
+
+velocity
+
+ +
+ +
+
+class espressomd.lb.LBSlice(key, shape)
+

Bases: object

+
+
+property boundary
+

boundary for a slice

+
+ +
+
+property density
+

density for a slice

+
+ +
+
+get_indices(self, key, shape_x, shape_y, shape_z)
+
+ +
+
+get_values(self, x_indices, y_indices, z_indices, prop_name)
+
+ +
+
+property index
+

index for a slice

+
+ +
+
+property population
+

population for a slice

+
+ +
+
+property pressure_tensor
+

pressure_tensor for a slice

+
+ +
+
+property pressure_tensor_neq
+

pressure_tensor_neq for a slice

+
+ +
+
+set_values(self, x_indices, y_indices, z_indices, prop_name, value)
+
+ +
+
+property velocity
+

velocity for a slice

+
+ +
+ +
+
+

espressomd.lbboundaries module

+
+
+class espressomd.lbboundaries.LBBoundaries(**kwargs)[source]
+

Bases: espressomd.script_interface.ScriptObjectList

+

Creates a set of lattice-Boltzmann boundaries.

+
+
+size()
+

Get the number of active boundaries.

+
+ +
+
+empty()
+

Return True if there are not active boundaries.

+
+ +
+
+clear()
+

Clear the list of boundaries.

+
+ +
+
+add(*args, **kwargs)[source]
+

Adds a boundary to the set of boundaries. +Either pass a valid boundary as argument, +or a valid set of parameters to create a boundary.

+
+ +
+
+remove(lbboundary)[source]
+

Removes a boundary from the set.

+
+
Parameters
+

lbboundary (LBBoundary) – The boundary to be removed from the set.

+
+
+
+ +
+ +
+
+class espressomd.lbboundaries.LBBoundary(**kwargs)[source]
+

Bases: espressomd.script_interface.ScriptInterfaceHelper

+

Creates a LB boundary from a shape.

+

The fluid velocity is limited to \(v_{\mathrm{max}} = 0.20\) +(see quasi-incompressible limit in [Krüger et al., 2017], +chapter 7, page 272), which corresponds to Mach 0.35.

+

The relative error in the fluid density between a compressible fluid +and an incompressible fluid at Mach 0.30 is less than 5% (see +constant density assumption in [Kundu et al., 2001] chapter 16, page +663). Since the speed of sound is \(c_s = 1 / \sqrt{3}\) in LB +velocity units in a D3Q19 lattice, the velocity limit at Mach 0.30 +is \(v_{\mathrm{max}} = 0.30 / \sqrt{3} \approx 0.17\). +At Mach 0.35 the relative error is around 6% and +\(v_{\mathrm{max}} = 0.35 / \sqrt{3} \approx 0.20\).

+
+
Parameters
+
    +
  • shape (espressomd.shapes.Shape) – The shape from which to build the boundary.

  • +
  • velocity ((3,) array_like of float, optional) – The boundary slip velocity. By default, a velocity of zero is used +(no-slip boundary condition).

  • +
+
+
+
+ +
+
+

espressomd.lees_edwards module

+
+
+class espressomd.lees_edwards.LeesEdwards(**kwargs)[source]
+

Bases: espressomd.script_interface.ScriptInterfaceHelper

+

Interface to the Lees–Edwards boundary conditions. +When writing H5MD files, the shear direction and shear plane normals +are written as integers instead of characters, with 0 = x-axis, +1 = y-axis, 2 = z-axis.

+
+
+protocol
+

Lees–Edwards protocol.

+
+
Type
+

object

+
+
+
+ +
+
+shear_velocity
+

Current shear velocity.

+
+
Type
+

float

+
+
+
+ +
+
+pos_offset
+

Current position offset

+
+
Type
+

float

+
+
+
+ +
+
+shear_direction
+

Shear direction.

+
+
Type
+

str, {‘x’, ‘y’, ‘z’}

+
+
+
+ +
+
+shear_plane_normal
+

Shear plane normal.

+
+
Type
+

str, {‘x’, ‘y’, ‘z’}

+
+
+
+ +
+
+set_boundary_conditions()
+

Set a protocol, the shear direction and shear normal.

+
+
Parameters
+
    +
  • protocol (object)

  • +
  • shear_direction (str, {‘x’, ‘y’, ‘z’})

  • +
  • shear_plane_normal (str, {‘x’, ‘y’, ‘z’})

  • +
+
+
+
+ +
+ +
+
+class espressomd.lees_edwards.LinearShear(**kwargs)[source]
+

Bases: espressomd.script_interface.ScriptInterfaceHelper

+

Lees–Edwards protocol for linear shear.

+
+
Parameters
+
    +
  • initial_pos_offset (float) – Positional offset at the Lees–Edwards boundary at t=0.

  • +
  • shear_velocity (float) – Shear velocity (velocity jump) across the Lees–Edwards boundary.

  • +
+
+
+
+ +
+
+class espressomd.lees_edwards.Off(**kwargs)[source]
+

Bases: espressomd.script_interface.ScriptInterfaceHelper

+

Lees–Edwards protocol resulting in un-shifted boundaries.

+
+ +
+
+class espressomd.lees_edwards.OscillatoryShear(**kwargs)[source]
+

Bases: espressomd.script_interface.ScriptInterfaceHelper

+

Lees–Edwards protocol for oscillatory shear.

+
+
Parameters
+
    +
  • initial_pos_offset (float) – Positional offset at the Lees–Edwards boundary at t=0.

  • +
  • amplitude (float) – Maximum amplitude of the positional offset at the Lees–Edwards boundary.

  • +
  • omega (float) – Radian frequency of the oscillation.

  • +
  • time_0 (float) – Time offset of the oscillation.

  • +
+
+
+
+ +
+
+

espressomd.magnetostatics module

+
+
+class espressomd.magnetostatics.DLC(**kwargs)[source]
+

Bases: espressomd.magnetostatics.MagnetostaticInteraction

+

Electrostatics solver for systems with two periodic dimensions. +See Dipolar Layer Correction (DLC) for more details.

+

Notes

+

At present, the empty gap (volume without any particles), is assumed to be +along the z-axis. As a reference for the DLC method, see [Bródka, 2004].

+
+
Parameters
+
    +
  • gap_size (float) – The gap size gives the height \(h\) of the empty region between +the system box and the neighboring artificial images. ESPResSo checks +that the gap is empty and will throw an error if it isn’t. Therefore +you should really make sure that the gap region is empty (e.g. +with wall constraints).

  • +
  • maxPWerror (float) – Maximal pairwise error of the potential and force.

  • +
  • far_cut (float, optional) – Cutoff of the exponential sum.

  • +
+
+
+
+
+default_params()[source]
+
+ +
+
+required_keys()[source]
+
+ +
+
+valid_keys()[source]
+
+ +
+
+validate_params(params)[source]
+

Check validity of given parameters.

+
+ +
+ +
+
+class espressomd.magnetostatics.DipolarBarnesHutGpu(**kwargs)[source]
+

Bases: espressomd.magnetostatics.MagnetostaticInteraction

+

Calculates magnetostatic interactions by direct summation over all +pairs. See Barnes-Hut octree sum on GPU for more details.

+

TODO: If the system has periodic boundaries, the minimum image +convention is applied.

+

Requires feature DIPOLAR_BARNES_HUT, which depends on +DIPOLES and CUDA.

+
+
+default_params()[source]
+
+ +
+
+required_keys()[source]
+
+ +
+
+valid_keys()[source]
+
+ +
+ +
+
+class espressomd.magnetostatics.DipolarDirectSumCpu(**kwargs)[source]
+

Bases: espressomd.magnetostatics.MagnetostaticInteraction

+

Calculate magnetostatic interactions by direct summation over all pairs. +See Dipolar direct sum for more details.

+

If the system has periodic boundaries, the minimum image convention is +applied in the respective directions.

+
+
Parameters
+

prefactor (float) – Magnetostatics prefactor (\(\mu_0/(4\pi)\))

+
+
+
+
+default_params()[source]
+
+ +
+
+required_keys()[source]
+
+ +
+
+valid_keys()[source]
+
+ +
+ +
+
+class espressomd.magnetostatics.DipolarDirectSumGpu(**kwargs)[source]
+

Bases: espressomd.magnetostatics.MagnetostaticInteraction

+

Calculate magnetostatic interactions by direct summation over all +pairs. See Dipolar direct sum for more details.

+

If the system has periodic boundaries, the minimum image convention +is applied in the respective directions.

+

This is the GPU version of espressomd.magnetostatics.DipolarDirectSumCpu +but uses floating point precision.

+

Requires feature DIPOLAR_DIRECT_SUM, which depends on +DIPOLES and CUDA.

+
+
Parameters
+

prefactor (float) – Magnetostatics prefactor (\(\mu_0/(4\pi)\))

+
+
+
+
+default_params()[source]
+
+ +
+
+required_keys()[source]
+
+ +
+
+valid_keys()[source]
+
+ +
+ +
+
+class espressomd.magnetostatics.DipolarDirectSumWithReplicaCpu(**kwargs)[source]
+

Bases: espressomd.magnetostatics.MagnetostaticInteraction

+

Calculate magnetostatic interactions by direct summation over all pairs. +See Dipolar direct sum for more details.

+

If the system has periodic boundaries, n_replica copies of the system are +taken into account in the respective directions. Spherical cutoff is applied.

+
+
Parameters
+
    +
  • prefactor (float) – Magnetostatics prefactor (\(\mu_0/(4\pi)\))

  • +
  • n_replica (int) – Number of replicas to be taken into account at periodic boundaries.

  • +
+
+
+
+
+default_params()[source]
+
+ +
+
+required_keys()[source]
+
+ +
+
+valid_keys()[source]
+
+ +
+ +
+
+class espressomd.magnetostatics.DipolarP3M(**kwargs)[source]
+

Bases: espressomd.magnetostatics.MagnetostaticInteraction

+

Calculate magnetostatic interactions using the dipolar P3M method. +See Dipolar P3M for more details.

+
+
Parameters
+
    +
  • prefactor (float) – Magnetostatics prefactor (\(\mu_0/(4\pi)\))

  • +
  • accuracy (float) – P3M tunes its parameters to provide this target accuracy.

  • +
  • alpha (float) – Ewald parameter.

  • +
  • cao (int) – Charge-assignment order, an integer between 1 and 7.

  • +
  • mesh (int or (3,) array_like of int) – The number of mesh points in x, y and z direction. Use a single +value for cubic boxes.

  • +
  • mesh_off ((3,) array_like of float, optional) – Mesh offset.

  • +
  • r_cut (float) – Real space cutoff.

  • +
  • tune (bool, optional) – Activate/deactivate the tuning method on activation +(default is True, i.e., activated).

  • +
  • timings (int) – Number of force calculations during tuning.

  • +
+
+
+
+
+default_params()[source]
+
+ +
+
+required_keys()[source]
+
+ +
+
+valid_keys()[source]
+
+ +
+
+validate_params(params)[source]
+

Check validity of parameters.

+
+ +
+ +
+
+class espressomd.magnetostatics.MagnetostaticInteraction(**kwargs)[source]
+

Bases: espressomd.script_interface.ScriptInterfaceHelper

+

Common interface for magnetostatics solvers.

+
+
Parameters
+

prefactor (float) – Magnetostatics prefactor \(\frac{\mu_0\mu}{4\pi}\)

+
+
+
+
+default_params()[source]
+
+ +
+
+get_magnetostatics_prefactor()[source]
+

Get the magnetostatics prefactor

+
+ +
+
+required_keys()[source]
+
+ +
+
+valid_keys()[source]
+
+ +
+
+validate_params(params)[source]
+

Check validity of given parameters.

+
+ +
+ +
+
+class espressomd.magnetostatics.Scafacos(**kwargs)[source]
+

Bases: espressomd.magnetostatics.MagnetostaticInteraction

+

Calculate the dipolar interaction using dipoles-capable methods +from the ScaFaCoS library. See ScaFaCoS magnetostatics for +more details.

+
+
Parameters
+
    +
  • prefactor (float) – Magnetostatics prefactor (\(\mu_0/(4\pi)\)).

  • +
  • method_name (str) – Name of the ScaFaCoS method to use.

  • +
  • method_params (dict) – Dictionary with the key-value pairs of the method parameters as +defined in ScaFaCoS. Note that the values are cast to strings +to match ScaFaCoS’ interface.

  • +
+
+
+
+
+get_available_methods()
+

List long-range methods available in the ScaFaCoS library.

+
+ +
+
+default_params()[source]
+
+ +
+
+required_keys()[source]
+
+ +
+
+valid_keys()[source]
+
+ +
+
+validate_params(params)[source]
+

Check validity of given parameters.

+
+ +
+ +
+
+

espressomd.math module

+
+
+class espressomd.math.CylindricalTransformationParameters(**kwargs)[source]
+

Bases: espressomd.script_interface.ScriptInterfaceHelper

+

Class to hold and validate the parameters needed for a cylindrical transformation. +The three parameters are available as attributes but are read-only.

+
+
Parameters
+
    +
  • center ((3,) array_like of float, default = [0, 0, 0]) – Position of the origin of the cylindrical coordinate system.

  • +
  • axis ((3,) array_like of float, default = [0, 0, 1]) – Orientation vector of the z-axis of the cylindrical coordinate system.

  • +
  • orientation ((3,) array_like of float, default = [1, 0, 0]) – The axis on which phi = 0.

  • +
+
+
+

Notes

+

If you provide no arguments, the defaults above are set. +If you provide only a center and an axis, an orientation will be automatically generated that is orthogonal to axis.

+
+ +
+
+

espressomd.observables module

+
+
+class espressomd.observables.BondAngles(**kwargs)[source]
+

Bases: espressomd.observables.Observable

+

Calculates the angles between bonds of particles with given ids along a +polymer chain.

+
+
Parameters
+

ids (array_like of int) – The ids of (existing) particles to take into account.

+
+
+
+
+calculate()
+

Run the observable.

+
+
Returns
+

+
+
Return type
+

(N - 2,) ndarray of float

+
+
+
+ +
+ +
+
+class espressomd.observables.BondDihedrals(**kwargs)[source]
+

Bases: espressomd.observables.Observable

+

Calculates the dihedrals between particles with given ids along a +polymer chain.

+
+
Parameters
+

ids (array_like of int) – The ids of (existing) particles to take into account.

+
+
+
+
+calculate()
+

Run the observable.

+
+
Returns
+

+
+
Return type
+

(N - 3,) ndarray of float

+
+
+
+ +
+ +
+
+class espressomd.observables.ComPosition(**kwargs)[source]
+

Bases: espressomd.observables.Observable

+

Calculates the center of mass for particles with given ids.

+

Note that virtual sites are not included since they do not have a meaningful mass.

+

Output format: \(\frac{1}{\sum_i m_i} \left( \sum_i m_i r^x_i, \sum_i m_i r^y_i, \sum_i m_i r^z_i\right)\)

+
+
Parameters
+

ids (array_like of int) – The ids of (existing) particles to take into account.

+
+
+
+
+calculate()
+

Run the observable.

+
+
Returns
+

+
+
Return type
+

(3,) ndarray of float

+
+
+
+ +
+ +
+
+class espressomd.observables.ComVelocity(**kwargs)[source]
+

Bases: espressomd.observables.Observable

+

Calculates the center of mass velocity for particles with given ids.

+

Note that virtual sites are not included since they do not have a meaningful mass.

+

Output format: \(\frac{1}{\sum_i m_i} \left( \sum_i m_i v^x_i, \sum_i m_i v^y_i, \sum_i m_i v^z_i\right)\)

+
+
Parameters
+

ids (array_like of int) – The ids of (existing) particles to take into account.

+
+
+
+
+calculate()
+

Run the observable.

+
+
Returns
+

+
+
Return type
+

(3,) ndarray of float

+
+
+
+ +
+ +
+
+class espressomd.observables.CosPersistenceAngles(**kwargs)[source]
+

Bases: espressomd.observables.Observable

+

Calculates the cosine of mutual bond angles for chained particles with given ids.

+

The i-th value of the result contains the cosine of the angle between bonds that +are separated by i bonds. The values are averaged over the chain.

+
+
Parameters
+

ids (array_like of int) – The ids of (existing) particles to take into account.

+
+
+
+
+calculate()
+

Run the observable.

+
+
Returns
+

+
+
Return type
+

(N - 2,) ndarray of float

+
+
+
+ +
+ +
+
+class espressomd.observables.CylindricalDensityProfile(transform_params=<espressomd.math.CylindricalTransformationParameters object>, **kwargs)[source]
+

Bases: espressomd.observables.CylindricalProfileObservable

+

Calculates the particle density in cylindrical coordinates.

+
+
Parameters
+
    +
  • ids (array_like of int) – The ids of (existing) particles to take into account.

  • +
  • transform_params (espressomd.math.CylindricalTransformationParameters, optional) – Parameters of the cylinder transformation. Defaults to the default of espressomd.math.CylindricalTransformationParameters

  • +
  • n_r_bins (int, default = 1) – Number of bins in radial direction.

  • +
  • n_phi_bins (int, default = 1) – Number of bins for the azimuthal direction.

  • +
  • n_z_bins (int, default = 1) – Number of bins in z direction.

  • +
  • min_r (float, default = 0) – Minimum r to consider.

  • +
  • min_phi (float, default = \(-\pi\)) – Minimum phi to consider. Must be in \([-\pi,\pi)\).

  • +
  • min_z (float) – Minimum z to consider.

  • +
  • max_r (float) – Maximum r to consider.

  • +
  • max_phi (float, default = \(\pi\)) – Maximum phi to consider. Must be in \((-\pi,\pi]\).

  • +
  • max_z (float) – Maximum z to consider.

  • +
+
+
+
+
+calculate()
+

Run the observable.

+
+
Returns
+

+
+
Return type
+

(n_r_bins, n_phi_bins, n_z_bins) ndarray of float

+
+
+
+ +
+ +
+
+class espressomd.observables.CylindricalFluxDensityProfile(transform_params=<espressomd.math.CylindricalTransformationParameters object>, **kwargs)[source]
+

Bases: espressomd.observables.CylindricalProfileObservable

+

Calculates the particle flux density in cylindrical coordinates.

+
+
Parameters
+
    +
  • ids (array_like of int) – The ids of (existing) particles to take into account.

  • +
  • transform_params (espressomd.math.CylindricalTransformationParameters, optional) – Parameters of the cylinder transformation. Defaults to the default of espressomd.math.CylindricalTransformationParameters

  • +
  • n_r_bins (int, default = 1) – Number of bins in radial direction.

  • +
  • n_phi_bins (int, default = 1) – Number of bins for the azimuthal direction.

  • +
  • n_z_bins (int, default = 1) – Number of bins in z direction.

  • +
  • min_r (float, default = 0) – Minimum r to consider.

  • +
  • min_phi (float, default = \(-\pi\)) – Minimum phi to consider. Must be in \([-\pi,\pi)\).

  • +
  • min_z (float) – Minimum z to consider.

  • +
  • max_r (float) – Maximum r to consider.

  • +
  • max_phi (float, default = \(\pi\)) – Maximum phi to consider. Must be in \((-\pi,\pi]\).

  • +
  • max_z (float) – Maximum z to consider.

  • +
+
+
+
+
+calculate()
+

Run the observable.

+
+
Returns
+

The fourth dimension of the array stores the histogram for the +radial distance, azimuth and axial coordinate of the particle +flux density field, respectively.

+
+
Return type
+

(n_r_bins, n_phi_bins, n_z_bins, 3) ndarray of float

+
+
+
+ +
+ +
+
+class espressomd.observables.CylindricalLBFluxDensityProfileAtParticlePositions(transform_params=<espressomd.math.CylindricalTransformationParameters object>, **kwargs)[source]
+

Bases: espressomd.observables.CylindricalProfileObservable

+

Calculates the LB fluid flux density at the particle positions in +cylindrical coordinates.

+
+
Parameters
+
    +
  • ids (array_like of int) – The ids of (existing) particles to take into account.

  • +
  • transform_params (espressomd.math.CylindricalTransformationParameters, optional) – Parameters of the cylinder transformation. Defaults to the default of espressomd.math.CylindricalTransformationParameters

  • +
  • n_r_bins (int, default = 1) – Number of bins in radial direction.

  • +
  • n_phi_bins (int, default = 1) – Number of bins for the azimuthal direction.

  • +
  • n_z_bins (int, default = 1) – Number of bins in z direction.

  • +
  • min_r (float, default = 0) – Minimum r to consider.

  • +
  • min_phi (float, default = \(-\pi\)) – Minimum phi to consider. Must be in \([-\pi,\pi)\).

  • +
  • min_z (float) – Minimum z to consider.

  • +
  • max_r (float) – Maximum r to consider.

  • +
  • max_phi (float, default = \(\pi\)) – Maximum phi to consider. Must be in \((-\pi,\pi]\).

  • +
  • max_z (float) – Maximum z to consider.

  • +
+
+
+
+
+calculate()
+

Run the observable.

+
+
Returns
+

The fourth dimension of the array stores the histogram for the +radial distance, azimuth and axial coordinate of the LB flux +density field, respectively.

+
+
Return type
+

(n_r_bins, n_phi_bins, n_z_bins, 3) ndarray of float

+
+
+
+ +
+ +
+
+class espressomd.observables.CylindricalLBVelocityProfile(transform_params=<espressomd.math.CylindricalTransformationParameters object>, **kwargs)[source]
+

Bases: espressomd.observables.CylindricalProfileObservable

+

Calculates the LB fluid velocity profile in cylindrical coordinates.

+

This observable samples the fluid in on a regular grid defined by variable +sampling_density. Note that a small delta leads to a large number of +sample points and carries a performance cost.

+
+
Parameters
+
    +
  • transform_params (espressomd.math.CylindricalTransformationParameters, optional) – Parameters of the cylinder transformation. Defaults to the default of espressomd.math.CylindricalTransformationParameters

  • +
  • n_r_bins (int, default = 1) – Number of bins in radial direction.

  • +
  • n_phi_bins (int, default = 1) – Number of bins for the azimuthal direction.

  • +
  • n_z_bins (int, default = 1) – Number of bins in z direction.

  • +
  • min_r (float, default = 0) – Minimum r to consider.

  • +
  • min_phi (float, default = \(-\pi\)) – Minimum phi to consider. Must be in \([-\pi,\pi)\).

  • +
  • min_z (float) – Minimum z to consider.

  • +
  • max_r (float) – Maximum r to consider.

  • +
  • max_phi (float, default = \(\pi\)) – Maximum phi to consider. Must be in \((-\pi,\pi]\).

  • +
  • max_z (float) – Maximum z to consider.

  • +
  • sampling_density (float) – Samples per unit volume for the LB velocity interpolation.

  • +
+
+
+
+
+calculate()
+

Run the observable.

+
+
Returns
+

The fourth dimension of the array stores the histogram for the +radial distance, azimuth and axial coordinate of the LB velocity +field, respectively.

+
+
Return type
+

(n_r_bins, n_phi_bins, n_z_bins, 3) ndarray of float

+
+
+
+ +
+ +
+
+class espressomd.observables.CylindricalLBVelocityProfileAtParticlePositions(transform_params=<espressomd.math.CylindricalTransformationParameters object>, **kwargs)[source]
+

Bases: espressomd.observables.CylindricalProfileObservable

+

Calculates the LB fluid velocity at the particle positions in +cylindrical coordinates.

+
+
Parameters
+
    +
  • ids (array_like of int) – The ids of (existing) particles to take into account.

  • +
  • transform_params (espressomd.math.CylindricalTransformationParameters, optional) – Parameters of the cylinder transformation. Defaults to the default of espressomd.math.CylindricalTransformationParameters

  • +
  • n_r_bins (int, default = 1) – Number of bins in radial direction.

  • +
  • n_phi_bins (int, default = 1) – Number of bins for the azimuthal direction.

  • +
  • n_z_bins (int, default = 1) – Number of bins in z direction.

  • +
  • min_r (float, default = 0) – Minimum r to consider.

  • +
  • min_phi (float, default = \(-\pi\)) – Minimum phi to consider. Must be in \([-\pi,\pi)\).

  • +
  • min_z (float) – Minimum z to consider.

  • +
  • max_r (float) – Maximum r to consider.

  • +
  • max_phi (float, default = \(\pi\)) – Maximum phi to consider. Must be in \((-\pi,\pi]\).

  • +
  • max_z (float) – Maximum z to consider.

  • +
+
+
+
+
+calculate()
+

Run the observable.

+
+
Returns
+

The fourth dimension of the array stores the histogram for the +radial distance, azimuth and axial coordinate of the LB velocity +field, respectively.

+
+
Return type
+

(n_r_bins, n_phi_bins, n_z_bins, 3) ndarray of float

+
+
+
+ +
+ +
+
+class espressomd.observables.CylindricalProfileObservable(transform_params=<espressomd.math.CylindricalTransformationParameters object>, **kwargs)[source]
+

Bases: espressomd.observables.ProfileObservable

+

Base class for observables that work with cylinder coordinates

+
+ +
+
+class espressomd.observables.CylindricalVelocityProfile(transform_params=<espressomd.math.CylindricalTransformationParameters object>, **kwargs)[source]
+

Bases: espressomd.observables.CylindricalProfileObservable

+

Calculates the particle velocity profile in cylindrical coordinates.

+
+
Parameters
+
    +
  • ids (array_like of int) – The ids of (existing) particles to take into account.

  • +
  • transform_params (espressomd.math.CylindricalTransformationParameters, optional) – Parameters of the cylinder transformation. Defaults to the default of espressomd.math.CylindricalTransformationParameters

  • +
  • n_r_bins (int, default = 1) – Number of bins in radial direction.

  • +
  • n_phi_bins (int, default = 1) – Number of bins for the azimuthal direction.

  • +
  • n_z_bins (int, default = 1) – Number of bins in z direction.

  • +
  • min_r (float, default = 0) – Minimum r to consider.

  • +
  • min_phi (float, default = \(-\pi\)) – Minimum phi to consider. Must be in \([-\pi,\pi)\).

  • +
  • min_z (float) – Minimum z to consider.

  • +
  • max_r (float) – Maximum r to consider.

  • +
  • max_phi (float, default = \(\pi\)) – Maximum phi to consider. Must be in \((-\pi,\pi]\).

  • +
  • max_z (float) – Maximum z to consider.

  • +
+
+
+
+
+calculate()
+

Run the observable.

+
+
Returns
+

The fourth dimension of the array stores the histogram for the +radial distance, azimuth and axial coordinate of the particle +velocity field, respectively.

+
+
Return type
+

(n_r_bins, n_phi_bins, n_z_bins, 3) ndarray of float

+
+
+
+ +
+ +
+
+class espressomd.observables.DPDStress(**kwargs)[source]
+

Bases: espressomd.observables.Observable

+

Calculates the non-equilibrium contribution of the DPD interaction +to the stress tensor.

+
+
Parameters
+

None

+
+
+
+
+calculate()
+

Run the observable.

+
+
Returns
+

+
+
Return type
+

(3, 3) ndarray of float

+
+
+
+ +
+ +
+
+class espressomd.observables.DensityProfile(**kwargs)[source]
+

Bases: espressomd.observables.ProfileObservable

+

Calculates the particle density profile for particles with given ids.

+
+
Parameters
+
    +
  • ids (array_like of int) – The ids of (existing) particles to take into account.

  • +
  • n_x_bins (int) – Number of bins in x direction.

  • +
  • n_y_bins (int) – Number of bins in y direction.

  • +
  • n_z_bins (int) – Number of bins in z direction.

  • +
  • min_x (float) – Minimum x to consider.

  • +
  • min_y (float) – Minimum y to consider.

  • +
  • min_z (float) – Minimum z to consider.

  • +
  • max_x (float) – Maximum x to consider.

  • +
  • max_y (float) – Maximum y to consider.

  • +
  • max_z (float) – Maximum z to consider.

  • +
+
+
+
+
+calculate()
+

Run the observable.

+
+
Returns
+

+
+
Return type
+

(n_x_bins, n_y_bins, n_z_bins) ndarray of float

+
+
+
+ +
+ +
+
+class espressomd.observables.DipoleMoment(**kwargs)[source]
+

Bases: espressomd.observables.Observable

+

Calculates the electric dipole moment for particles with given ids.

+

Output format: \(\left(\sum_i q_i r^x_i, \sum_i q_i r^y_i, \sum_i q_i r^z_i\right)\)

+
+
Parameters
+

ids (array_like of int) – The ids of (existing) particles to take into account.

+
+
+
+
+calculate()
+

Run the observable.

+
+
Returns
+

+
+
Return type
+

(3,) ndarray of float

+
+
+
+ +
+ +
+
+class espressomd.observables.Energy(**kwargs)[source]
+

Bases: espressomd.observables.Observable

+

Calculates the total energy.

+
+
+calculate()
+

Run the observable.

+
+
Returns
+

+
+
Return type
+

float

+
+
+
+ +
+ +
+
+class espressomd.observables.FluxDensityProfile(**kwargs)[source]
+

Bases: espressomd.observables.ProfileObservable

+

Calculates the particle flux density for particles with given ids.

+
+
Parameters
+
    +
  • ids (array_like of int) – The ids of (existing) particles to take into account.

  • +
  • n_x_bins (int) – Number of bins in x direction.

  • +
  • n_y_bins (int) – Number of bins in y direction.

  • +
  • n_z_bins (int) – Number of bins in z direction.

  • +
  • min_x (float) – Minimum x to consider.

  • +
  • min_y (float) – Minimum y to consider.

  • +
  • min_z (float) – Minimum z to consider.

  • +
  • max_x (float) – Maximum x to consider.

  • +
  • max_y (float) – Maximum y to consider.

  • +
  • max_z (float) – Maximum z to consider.

  • +
+
+
+
+
+calculate()
+

Run the observable.

+
+
Returns
+

The fourth dimension of the array stores the histogram for the x, +y and z components of the flux density, respectively.

+
+
Return type
+

(n_x_bins, n_y_bins, n_z_bins, 3) ndarray of float

+
+
+
+ +
+ +
+
+class espressomd.observables.ForceDensityProfile(**kwargs)[source]
+

Bases: espressomd.observables.ProfileObservable

+

Calculates the force density profile for particles with given ids.

+
+
Parameters
+
    +
  • ids (array_like of int) – The ids of (existing) particles to take into account.

  • +
  • n_x_bins (int) – Number of bins in x direction.

  • +
  • n_y_bins (int) – Number of bins in y direction.

  • +
  • n_z_bins (int) – Number of bins in z direction.

  • +
  • min_x (float) – Minimum x to consider.

  • +
  • min_y (float) – Minimum y to consider.

  • +
  • min_z (float) – Minimum z to consider.

  • +
  • max_x (float) – Maximum x to consider.

  • +
  • max_y (float) – Maximum y to consider.

  • +
  • max_z (float) – Maximum z to consider.

  • +
+
+
+
+
+calculate()
+

Run the observable.

+
+
Returns
+

The fourth dimension of the array stores the histogram for the x, +y and z components of the force, respectively.

+
+
Return type
+

(n_x_bins, n_y_bins, n_z_bins, 3) ndarray of float

+
+
+
+ +
+ +
+
+class espressomd.observables.LBFluidPressureTensor(**kwargs)[source]
+

Bases: espressomd.observables.Observable

+

Calculates the average pressure tensor of the LB fluid for all nodes.

+
+
Parameters
+

None

+
+
+
+
+calculate()
+

Run the observable.

+
+
Returns
+

+
+
Return type
+

(3, 3) ndarray of float

+
+
+
+ +
+ +
+
+class espressomd.observables.LBVelocityProfile(**kwargs)[source]
+

Bases: espressomd.observables.ProfileObservable

+

Calculates the LB fluid velocity profile.

+

This observable samples the fluid in on a regular grid defined by the variables +sampling_*. Note that a small delta leads to a large number of sample +points and carries a performance cost.

+
+
Parameters
+
    +
  • n_x_bins (int) – Number of bins in x direction.

  • +
  • n_y_bins (int) – Number of bins in y direction.

  • +
  • n_z_bins (int) – Number of bins in z direction.

  • +
  • min_x (float) – Minimum x to consider.

  • +
  • min_y (float) – Minimum y to consider.

  • +
  • min_z (float) – Minimum z to consider.

  • +
  • max_x (float) – Maximum x to consider.

  • +
  • max_y (float) – Maximum y to consider.

  • +
  • max_z (float) – Maximum z to consider.

  • +
  • sampling_delta_x (float, default=1.0) – Spacing for the sampling grid in x-direction.

  • +
  • sampling_delta_y (float, default=1.0) – Spacing for the sampling grid in y-direction.

  • +
  • sampling_delta_z (float, default=1.0) – Spacing for the sampling grid in z-direction.

  • +
  • sampling_offset_x (float, default=0.0) – Offset for the sampling grid in x-direction.

  • +
  • sampling_offset_y (float, default=0.0) – Offset for the sampling grid in y-direction.

  • +
  • sampling_offset_z (float, default=0.0) – Offset for the sampling grid in z-direction.

  • +
  • allow_empty_bins (bool, default=False) – Whether or not to allow bins that will not be sampled at all.

  • +
+
+
+
+
+calculate()
+

Run the observable.

+
+
Returns
+

The fourth dimension of the array stores the histogram for the x, +y and z components of the LB velocity, respectively.

+
+
Return type
+

(n_x_bins, n_y_bins, n_z_bins, 3) ndarray of float

+
+
+
+ +
+ +
+
+class espressomd.observables.MagneticDipoleMoment(**kwargs)[source]
+

Bases: espressomd.observables.Observable

+

Calculates the magnetic dipole moment for particles with given ids.

+

Output format: \(\left(\sum_i \mu^x_i, \sum_i \mu^y_i, \sum_i \mu^z_i\right)\)

+
+
Parameters
+

ids (array_like of int) – The ids of (existing) particles to take into account.

+
+
+
+
+calculate()
+

Run the observable.

+
+
Returns
+

+
+
Return type
+

(3,) ndarray of float

+
+
+
+ +
+ +
+
+class espressomd.observables.Observable(**kwargs)[source]
+

Bases: espressomd.script_interface.ScriptInterfaceHelper

+

Base class for all observables.

+
+
+shape()
+

Get the shape of the numpy array returned by the observable.

+
+ +
+
+calculate()[source]
+
+ +
+ +
+
+class espressomd.observables.ParticleAngularVelocities(**kwargs)[source]
+

Bases: espressomd.observables.Observable

+

Calculates the angular velocity (omega) in the spaced-fixed frame of reference

+

Output format: \((\omega^x_1,\ \omega^y_1,\ \omega^z_1),\ (\omega^x_2,\ \omega^y_2,\ \omega^z_2), \dots,\ (\omega^x_n,\ \omega^y_n,\ \omega^z_n)\).

+

The particles are ordered according to the list of ids passed to the observable.

+
+
Parameters
+

ids (array_like of int) – The ids of (existing) particles to take into account.

+
+
+
+
+calculate()
+

Run the observable.

+
+
Returns
+

+
+
Return type
+

(N, 3) ndarray of float

+
+
+
+ +
+ +
+
+class espressomd.observables.ParticleBodyAngularVelocities(**kwargs)[source]
+

Bases: espressomd.observables.Observable

+

Calculates the angular velocity (omega) in the particles’ body-fixed frame of reference.

+

For each particle, the body-fixed frame of reference is obtained from the particle’s +orientation stored in the quaternions.

+

Output format: \((\omega^x_1,\ \omega^y_1,\ \omega^z_1),\ (\omega^x_2,\ \omega^y_2,\ \omega^z_2), \dots,\ (\omega^x_n,\ \omega^y_n,\ \omega^z_n)\).

+

The particles are ordered according to the list of ids passed to the observable.

+
+
Parameters
+

ids (array_like of int) – The ids of (existing) particles to take into account.

+
+
+
+
+calculate()
+

Run the observable.

+
+
Returns
+

+
+
Return type
+

(N, 3) ndarray of float

+
+
+
+ +
+ +
+
+class espressomd.observables.ParticleBodyVelocities(**kwargs)[source]
+

Bases: espressomd.observables.Observable

+

Calculates the particle velocity in the particles’ body-fixed frame of reference.

+

For each particle, the body-fixed frame of reference is obtained from the particle’s +orientation stored in the quaternions.

+

Output format: \((v^x_1,\ v^y_1,\ v^z_1),\ (v^x_2,\ v^y_2,\ v^z_2),\ \dots,\ (v^x_n,\ v^y_n,\ v^z_n)\).

+

The particles are ordered according to the list of ids passed to the observable.

+
+
Parameters
+

ids (array_like of int) – The ids of (existing) particles to take into account.

+
+
+
+
+calculate()
+

Run the observable.

+
+
Returns
+

+
+
Return type
+

(N, 3) ndarray of float

+
+
+
+ +
+ +
+
+class espressomd.observables.ParticleDistances(**kwargs)[source]
+

Bases: espressomd.observables.Observable

+

Calculates the distances between particles with given ids along a +polymer chain.

+
+
Parameters
+

ids (array_like of int) – The ids of (existing) particles to take into account.

+
+
+
+
+calculate()
+

Run the observable.

+
+
Returns
+

+
+
Return type
+

(N - 1,) ndarray of float

+
+
+
+ +
+ +
+
+class espressomd.observables.ParticleForces(**kwargs)[source]
+

Bases: espressomd.observables.Observable

+

Calculates the particle forces for particles with given ids.

+

Output format: \((f^x_1,\ f^y_1,\ f^z_1),\ (f^x_2,\ f^y_2,\ f^z_2),\ \dots,\ (f^x_n,\ f^y_n,\ f^z_n)\).

+

The particles are ordered according to the list of ids passed to the observable.

+
+
Parameters
+

ids (array_like of int) – The ids of (existing) particles to take into account.

+
+
+
+
+calculate()
+

Run the observable.

+
+
Returns
+

+
+
Return type
+

(N, 3) ndarray of float

+
+
+
+ +
+ +
+
+class espressomd.observables.ParticlePositions(**kwargs)[source]
+

Bases: espressomd.observables.Observable

+

Calculates the particle positions for particles with given ids.

+

Output format: \((x_1,\ y_1,\ z_1),\ (x_2,\ y_2,\ z_2),\ \dots,\ (x_n,\ y_n,\ z_n)\).

+

The particles are ordered according to the list of ids passed to the observable.

+
+
Parameters
+

ids (array_like of int) – The ids of (existing) particles to take into account.

+
+
+
+
+calculate()
+

Run the observable.

+
+
Returns
+

+
+
Return type
+

(N, 3) ndarray of float

+
+
+
+ +
+ +
+
+class espressomd.observables.ParticleVelocities(**kwargs)[source]
+

Bases: espressomd.observables.Observable

+

Calculates the particle velocities for particles with given ids.

+

Output format: \((v^x_1,\ v^y_1,\ v^z_1),\ (v^x_2,\ v^y_2,\ v^z_2),\ \dots,\ (v^x_n,\ v^y_n,\ v^z_n)\).

+

The particles are ordered according to the list of ids passed to the observable.

+
+
Parameters
+

ids (array_like of int) – The ids of (existing) particles to take into account.

+
+
+
+
+calculate()
+

Run the observable.

+
+
Returns
+

+
+
Return type
+

(N, 3) ndarray of float

+
+
+
+ +
+ +
+
+class espressomd.observables.Pressure(**kwargs)[source]
+

Bases: espressomd.observables.Observable

+

Calculates the total scalar pressure.

+
+
+calculate()
+

Run the observable.

+
+
Returns
+

+
+
Return type
+

float

+
+
+
+ +
+ +
+
+class espressomd.observables.PressureTensor(**kwargs)[source]
+

Bases: espressomd.observables.Observable

+

Calculates the total pressure tensor.

+
+
+calculate()
+

Run the observable.

+
+
Returns
+

+
+
Return type
+

(3, 3) ndarray of float

+
+
+
+ +
+ +
+
+class espressomd.observables.ProfileObservable(**kwargs)[source]
+

Bases: espressomd.observables.Observable

+

Base class for histogram-based observables.

+
+
+bin_centers()[source]
+
+
Returns
+

Positions of the bins centers. If the histogram has dimensions +(M,N,O), the bin centers have dimensions (M,N,O,3).

+
+
Return type
+

ndarray of float

+
+
+
+ +
+
+bin_edges()[source]
+
+
Returns
+

Positions between the bins. If the histogram has dimensions +(M,N,O), the bin edges have dimensions (M+1,N+1,O+1,3).

+
+
Return type
+

ndarray of float

+
+
+
+ +
+ +
+
+class espressomd.observables.RDF(**kwargs)[source]
+

Bases: espressomd.observables.Observable

+

Calculates a radial distribution function. +The result is normalized by the bulk concentration.

+
+
Parameters
+
    +
  • ids1 (array_like of int) – The ids of (existing) particles to calculate the distance from.

  • +
  • ids2 (array_like of int, optional) – The ids of (existing) particles to calculate the distance to. +If not provided, use ids1.

  • +
  • n_r_bins (int) – Number of bins in radial direction.

  • +
  • min_r (float) – Minimum r to consider.

  • +
  • max_r (float) – Maximum r to consider.

  • +
+
+
+
+
+calculate()
+

Run the observable.

+
+
Returns
+

The RDF.

+
+
Return type
+

(n_r_bins,) ndarray of float

+
+
+
+ +
+
+bin_centers()[source]
+
+ +
+ +
+
+class espressomd.observables.TotalForce(**kwargs)[source]
+

Bases: espressomd.observables.Observable

+

Calculates the total force on particles with given ids.

+

Note that virtual sites are not included since forces on them do not enter the equation of motion directly.

+

Output format: \(\left(\sum_i f^x_i, \sum_i f^y_i, \sum_i f^z_i\right)\)

+
+
Parameters
+

ids (array_like of int) – The ids of (existing) particles to take into account.

+
+
+
+
+calculate()
+

Run the observable.

+
+
Returns
+

+
+
Return type
+

(3,) ndarray of float

+
+
+
+ +
+ +
+
+

espressomd.pair_criteria module

+
+
+class espressomd.pair_criteria.BondCriterion(**kwargs)[source]
+

Bases: espressomd.pair_criteria._PairCriterion

+

Pair criterion returning true, if a pair bond of given type exists between them

+

The following parameters can be passed to the constructor, changed via +set_params() and retrieved via get_params().

+
+
Parameters
+

bond_type (int) – numeric type of the bond

+
+
+
+ +
+
+class espressomd.pair_criteria.DistanceCriterion(**kwargs)[source]
+

Bases: espressomd.pair_criteria._PairCriterion

+

Pair criterion returning true, if particles are closer than a cutoff. +Periodic boundaries are treated via minimum image convention.

+

The following parameters can be passed to the constructor, changed via +set_params() and retrieved via get_params().

+
+
Parameters
+

cut_off (float) – distance cutoff for the criterion

+
+
+
+ +
+
+class espressomd.pair_criteria.EnergyCriterion(**kwargs)[source]
+

Bases: espressomd.pair_criteria._PairCriterion

+

Pair criterion returning true, if the short range energy between the +particles is superior or equal to the cutoff.

+

Be aware that the short range energy contains the short range part of +dipolar and electrostatic interactions, but not the long range part.

+

The following parameters can be passed to the constructor, changed via +set_params() and retrieved via get_params().

+
+
Parameters
+

cut_off (float) – energy cutoff for the criterion

+
+
+
+ +
+
+

espressomd.particle_data module

+
+
+class espressomd.particle_data.ParticleHandle
+

Bases: object

+
+
+add_bond(self, bond)
+

Add a single bond to the particle.

+
+
Parameters
+

bond (tuple) – tuple where the first element is either a bond ID or a bond object, +and the next elements are particle ids or particle objects to be +bonded to.

+
+
+
+

See also

+
+
bonds

Particle property containing a list of all current bonds held by Particle.

+
+
+
+

Examples

+
>>> import espressomd.interactions
+>>>
+>>> system = espressomd.System(box_l=3 * [10])
+>>>
+>>> # define a harmonic potential and add it to the system
+>>> harm_bond = espressomd.interactions.HarmonicBond(r_0=1, k=5)
+>>> system.bonded_inter.add(harm_bond)
+>>>
+>>> # add two particles
+>>> p1 = system.part.add(pos=(1, 0, 0))
+>>> p2 = system.part.add(pos=(2, 0, 0))
+>>>
+>>> # bond them via the bond type
+>>> p1.add_bond((harm_bond, p2))
+>>> # or via the bond index (zero in this case since it is the first one added)
+>>> p1.add_bond((0, p2))
+
+
+
+ +
+
+add_exclusion(self, partner)
+

Exclude non-bonded interactions with the given partner.

+
+

Note

+

This needs the feature EXCLUSIONS.

+
+
+
Parameters
+

partner (ParticleHandle or int) – Particle to exclude.

+
+
+
+ +
+
+add_verified_bond(self, bond)
+

Add a bond, the validity of which has already been verified.

+
+

See also

+
+
add_bond

Add an unverified bond to the Particle.

+
+
bonds

Particle property containing a list of all current bonds held by Particle.

+
+
+
+
+ +
+
+bonds
+

The bonds stored by this particle. Note that bonds are only stored by +one partner. You need to define a bonded interaction.

+

bonds : list/tuple of tuples/lists

+

A bond tuple is specified as a bond identifier associated with +a particle (bond_ID, part_ID). A single particle may contain +multiple such tuples.

+
+

See also

+
+
espressomd.particle_data.ParticleHandle.add_bond

Method to add bonds to a Particle

+
+
espressomd.particle_data.ParticleHandle.delete_bond

Method to remove bonds from a Particle

+
+

Bond ids have to be an integer >= 0.

+
+
+
+
+ +
+
+convert_vector_body_to_space(self, vec)
+

Converts the given vector from the particle’s body frame to the space frame

+
+ +
+
+convert_vector_space_to_body(self, vec)
+

Converts the given vector from the space frame to the particle’s body frame

+
+ +
+
+delete_all_bonds(self)
+

Delete all bonds from the particle.

+
+

See also

+
+
delete_bond

Delete an unverified bond held by the particle.

+
+
bonds

Particle property containing a list of all current bonds held by Particle.

+
+
+
+
+ +
+
+delete_bond(self, bond)
+

Delete a single bond from the particle.

+
+
Parameters
+

bond (tuple) – tuple where the first element is either a bond ID or a bond object, +and the next elements are particle ids or particle objects that are +bonded to.

+
+
+
+

See also

+
+
bonds

Particle property containing a list of all bonds currently held by Particle.

+
+
+
+

Examples

+
>>> import espressomd.interactions
+>>>
+>>> system = espressomd.System(box_l=3 * [10])
+>>>
+>>> # define a harmonic potential and add it to the system
+>>> harm_bond = espressomd.interactions.HarmonicBond(r_0=1, k=5)
+>>> system.bonded_inter.add(harm_bond)
+>>>
+>>> # bond two particles to the first one
+>>> p0 = system.part.add(pos=(1, 0, 0))
+>>> p1 = system.part.add(pos=(2, 0, 0))
+>>> p2 = system.part.add(pos=(1, 1, 0))
+>>> p0.add_bond((harm_bond, p1))
+>>> p0.add_bond((harm_bond, p2))
+>>>
+>>> print(p0.bonds)
+((HarmonicBond(0): {'r_0': 1.0, 'k': 5.0, 'r_cut': 0.0}, 1),
+ (HarmonicBond(0): {'r_0': 1.0, 'k': 5.0, 'r_cut': 0.0}, 2))
+>>> # delete the first bond
+>>> p0.delete_bond(p0.bonds[0])
+>>> print(p0.bonds)
+((HarmonicBond(0): {'r_0': 1.0, 'k': 5.0, 'r_cut': 0.0}, 2),)
+
+
+
+ +
+
+delete_exclusion(self, partner)
+

Remove exclusion of non-bonded interactions with the given partner.

+
+

Note

+

This needs the feature EXCLUSIONS.

+
+
+
Parameters
+

partner (ParticleHandle or int) – Particle to remove from exclusions.

+
+
+
+ +
+
+delete_verified_bond(self, bond)
+

Delete a single bond from the particle. The validity of which has already been verified.

+
+
Parameters
+

bond (tuple) – tuple where the first element is either a bond ID of a bond type, +and the last element is the ID of the partner particle to be bonded +to.

+
+
+
+

See also

+
+
delete_bond

Delete an unverified bond held by the Particle.

+
+
bonds

Particle property containing a list of all current bonds held by Particle.

+
+
+
+
+ +
+
+dip
+

The orientation of the dipole axis.

+

dip : (3,) array_like of float

+
+

Note

+

This needs the feature DIPOLES.

+
+
+ +
+
+dipm
+

The magnitude of the dipole moment.

+

dipm : float

+
+

Note

+

This needs the feature DIPOLES.

+
+
+ +
+
+director
+

The particle director.

+

The director defines the the z-axis in the body-fixed frame. +If particle rotations happen, the director, i.e., the body-fixed +coordinate system co-rotates. Properties such as the angular +velocity espressomd.particle_data.ParticleHandle.omega_body +are evaluated in this body-fixed coordinate system. +When using particle dipoles, the dipole moment is co-aligned with +the particle director. Setting the director thus modifies the +dipole moment orientation (espressomd.particle_data.ParticleHandle.dip) +and vice versa. +See also Rotational degrees of freedom and particle anisotropy.

+

director : (3,) array_like of float

+
+

Note

+

This needs the feature ROTATION.

+
+
+ +
+
+exclusions
+

The exclusion list of particles where non-bonded interactions are ignored.

+
+

Note

+

This needs the feature EXCLUSIONS.

+
+

exclusions : (N,) array_like of int

+
+ +
+
+ext_force
+

An additional external force applied to the particle.

+

ext_force : (3,) array_like of float

+
+

Note

+

This needs the feature EXTERNAL_FORCES.

+
+
+ +
+
+ext_torque
+

An additional external torque is applied to the particle.

+

ext_torque : (3,) array_like of float

+
+

Note

+
    +
  • This torque is specified in the laboratory frame!

  • +
  • This needs features EXTERNAL_FORCES and ROTATION.

  • +
+
+
+ +
+
+f
+

The instantaneous force acting on this particle.

+

f : (3,) array_like of float

+
+

Note

+

Whereas the velocity is modified with respect to the velocity you set +upon integration, the force it recomputed during the integration step and any +force set in this way is immediately lost at the next integration step.

+
+
+ +
+
+fix
+

Fixes the particle motion in the specified cartesian directions.

+

fix : (3,) array_like of bool

+

Fixes the particle in space. By supplying a set of 3 bools as +arguments it is possible to fix motion in x, y, or z coordinates +independently. For example:

+
part[<INDEX>].fix = [False, False, True]
+
+
+

will fix motion for particle with index INDEX only in z.

+
+

Note

+

This needs the feature EXTERNAL_FORCES.

+
+
+ +
+
+gamma
+

The body-fixed frictional coefficient used in the Langevin +and Brownian thermostats.

+

gamma : float or (3,) array_like of float

+
+

Note

+

This needs features PARTICLE_ANISOTROPY and +THERMOSTAT_PER_PARTICLE.

+
+
+

See also

+
+
espressomd.thermostat.Thermostat.set_langevin()

Setting the parameters of the Langevin thermostat

+
+
+
+
+ +
+
+gamma_rot
+

The particle translational frictional coefficient used in +the Langevin and Brownian thermostats.

+

gamma_rot : float or (3,) array_like of float

+
+

Note

+

This needs features ROTATION, PARTICLE_ANISOTROPY +and THERMOSTAT_PER_PARTICLE.

+
+
+ +
+
+id
+

Integer particle id

+
+ +
+
+image_box
+

The image box the particles is in.

+

This is the number of times the particle position has been folded by +the box length in each direction.

+
+ +
+
+lees_edwards_flag
+

The Lees-Edwards flag that indicate if the particle crossed +the upper or lower boundary.

+
+ +
+
+lees_edwards_offset
+

The accumulated Lees-Edwards offset. +Can be used to reconstruct continuous trajectories.

+

offset : (3,) array_like of float

+
+ +
+
+mass
+

Particle mass.

+

mass : float

+
+

See also

+
+
espressomd.thermostat.Thermostat.set_langevin()

Setting the parameters of the Langevin thermostat

+
+
+
+
+ +
+
+mol_id
+

The molecule id of the Particle.

+

mol_id : int

+

The particle mol_id is used to differentiate between +particles belonging to different molecules, e.g. when virtual +sites are used, or object-in-fluid cells. The default +mol_id for all particles is 0.

+
+

Note

+

The value of mol_id has to be an integer >= 0.

+
+
+ +
+
+mu_E
+

Particle electrophoretic velocity.

+

mu_E : float

+

This effectively acts as a velocity offset between +a lattice-Boltzmann fluid and the particle. Has only +an effect if LB is turned on.

+
+

Note

+

This needs the feature LB_ELECTROHYDRODYNAMICS.

+
+
+ +
+
+node
+

The node the particle is on, identified by its MPI rank.

+
+ +
+
+normalize_and_check_bond_or_throw_exception(self, bond)
+

Checks the validity of the given bond:

+
    +
  • If the bondtype is given as an object or a numerical id

  • +
  • If all partners are of type int

  • +
  • If the number of partners satisfies the bond

  • +
  • If the bond type used exists (is lower than n_bonded_ia)

  • +
  • If the number of bond partners fits the bond type

  • +
+

Throws an exception if any of these are not met.

+

Normalize the bond, i.e. replace bond ids by bond objects and particle +objects by particle ids.

+
+ +
+
+omega_body
+

The particle angular velocity in body frame.

+

omega_body : (3,) array_like of float

+

This property sets the angular momentum of this particle in the +particles co-rotating frame (or body frame).

+
+

Note

+

This needs the feature ROTATION.

+
+
+ +
+
+omega_lab
+

The particle angular velocity the lab frame.

+

omega_lab : (3,) array_like of float

+
+

Note

+

This needs the feature ROTATION.

+

If you set the angular velocity of the particle in the lab +frame, the orientation of the particle +(quat) must be +set before setting omega_lab, otherwise the conversion from +lab to body frame will not be handled properly.

+
+
+

See also

+

omega_body

+
+
+ +
+
+pos
+

The unwrapped (not folded into central box) particle position.

+

pos : (3,) array_like of float

+
+ +
+
+pos_folded
+

The wrapped (folded into central box) position vector of a particle.

+

pos : (3,) array_like of float

+
+

Note

+

Setting the folded position is ambiguous and is thus not possible, please use pos.

+
+

Examples

+
>>> import espressomd
+>>> system = espressomd.System(box_l=[10, 10, 10])
+>>> system.part.add(pos=(5, 0, 0))
+>>> system.part.add(pos=(10, 0, 0))
+>>> system.part.add(pos=(25, 0, 0))
+>>> for p in system.part:
+...     print(p.pos)
+[ 5.  0.  0.]
+[ 10.   0.   0.]
+[ 25.   0.   0.]
+>>> for p in system.part:
+...     print(p.pos_folded)
+[5.0, 0.0, 0.0]
+[0.0, 0.0, 0.0]
+[5.0, 0.0, 0.0]
+
+
+
+ +
+
+q
+

Particle charge.

+

q : float

+
+

Note

+

This needs the feature ELECTROSTATICS.

+
+
+ +
+
+quat
+

Quaternion representation of the particle rotational position.

+

quat : (4,) array_like of float

+
+

Note

+

This needs the feature ROTATION.

+
+
+ +
+
+remove(self)
+

Delete the particle.

+ +
+ +
+
+rinertia
+

The particle rotational inertia.

+

rinertia : (3,) array_like of float

+

Sets the diagonal elements of this particle’s rotational inertia +tensor. These correspond with the inertial moments along the +coordinate axes in the particle’s co-rotating coordinate system. +When the particle’s quaternions are set to [1, 0, 0, 0,], the +co-rotating and the fixed (lab) frames are co-aligned.

+
+

Note

+

This needs the feature ROTATIONAL_INERTIA.

+
+
+ +
+
+rotate(self, axis, angle)
+

Rotates the particle around the given axis

+
+
Parameters
+
    +
  • axis ((3,) array_like of float)

  • +
  • angle (float)

  • +
+
+
+
+ +
+
+rotation
+

Switches the particle’s rotational degrees of freedom in the +Cartesian axes in the body-fixed frame. The content of the torque +and omega variables are meaningless for the co-ordinates for which +rotation is disabled.

+

The default is not to integrate any rotational degrees of freedom.

+

rotation : (3,) array_like of bool

+
+

Note

+

This needs the feature ROTATION.

+
+
+ +
+
+swimming
+

Set swimming parameters.

+

This property takes a dictionary with a different number of +entries depending whether there is an implicit fluid (i.e. with the +Langevin thermostat) of an explicit fluid (with LB).

+

Swimming enables the particle to be self-propelled in the direction +determined by its quaternion. For setting the quaternion of the +particle see quat. The +self-propulsion speed will relax to a constant velocity, that is specified by +v_swim. Alternatively it is possible to achieve a constant velocity by +imposing a constant force term f_swim that is balanced by friction of a +(Langevin) thermostat. The way the velocity of the particle decays to the +constant terminal velocity in either of these methods is completely +determined by the friction coefficient. You may only set one of the +possibilities v_swim or f_swim as you cannot relax to constant force +and constant velocity at the same time. Setting both v_swim and +f_swim to 0.0 disables swimming. This option applies to all +non-lattice-Boltzmann thermostats. Note that there is no real difference +between v_swim and f_swim since the latter may always be chosen such that +the same terminal velocity is achieved for a given friction coefficient.

+
+
Parameters
+
    +
  • f_swim (float) – Achieve a constant velocity by imposing a constant +force term f_swim that is balanced by friction of a +(Langevin) thermostat. This excludes the option v_swim.

  • +
  • v_swim (float) – Achieve a constant velocity by imposing a constant terminal +velocity v_swim. This excludes the option f_swim.

  • +
  • mode (str, {‘pusher’, ‘puller’, ‘N/A’}) – The LB flow field can be generated by a pushing or a +pulling mechanism, leading to change in the sign of the +dipolar flow field with respect to the direction of motion.

  • +
  • dipole_length (float) – This determines the distance of the source of +propulsion from the particle’s center.

  • +
+
+
+

Notes

+

This needs the feature ENGINE. The keys 'mode', +and 'dipole_length' are only +available if ENGINE is used with LB or CUDA.

+

Examples

+
>>> import espressomd
+>>> system = espressomd.System(box_l=[10, 10, 10])
+>>> # Langevin swimmer
+>>> system.part.add(pos=[1, 0, 0], swimming={'f_swim': 0.03})
+>>> # LB swimmer
+>>> system.part.add(pos=[2, 0, 0], swimming={'f_swim': 0.01,
+...     'mode': 'pusher', 'dipole_length': 2.0})
+
+
+
+ +
+
+to_dict(self)
+

Returns the particle’s attributes as a dictionary.

+

It includes the content of particle_attributes, minus a few exceptions:

+
    +
  • dip, director: +Setting only the director will overwrite the orientation of the +particle around the axis parallel to dipole moment/director. +Quaternions contain the full info.

  • +
  • image_box, node

  • +
+
+ +
+
+torque_lab
+

The particle torque in the lab frame.

+

torque_lab : (3,) array_like of float

+

This property defines the torque of this particle +in the fixed frame (or laboratory frame).

+
+

Note

+

The orientation of the particle +(quat) must be +set before setting this property, otherwise the conversion from +lab to body frame will not be handled properly.

+
+
+ +
+
+type
+

The particle type for nonbonded interactions.

+

type : int

+
+

Note

+

The value of type has to be an integer >= 0.

+
+
+ +
+
+update(self, new_properties)
+

Update properties of a particle.

+
+
Parameters
+

new_properties (dict) – Map particle property names to values. All properties except +for the particle id can be changed.

+
+
+

Examples

+
>>> import espressomd
+>>> system = espressomd.System(box_l=[10, 10, 10])
+>>> p = system.part.add(pos=[1, 2, 3], q=1, virtual=True)
+>>> print(p.pos, p.q, p.virtual)
+[1. 2. 3.] 1.0 True
+>>> p.update({'pos': [4, 5, 6], 'virtual': False, 'q': 0})
+>>> print(p.pos, p.q, p.virtual)
+[4. 5. 6.] 0.0 False
+
+
+
+ +
+
+v
+

The particle velocity in the lab frame.

+

v : (3,) array_like of float

+
+

Note

+

The velocity remains variable and will be changed during integration.

+
+
+ +
+
+virtual
+

Virtual flag.

+

Declares the particles as virtual (True) or non-virtual +(False, default).

+

virtual : bool

+
+

Note

+

This needs the feature VIRTUAL_SITES

+
+
+ +
+
+vs_auto_relate_to(self, rel_to)
+

Setup this particle as virtual site relative to the particle +in argument rel_to. A particle cannot relate to itself.

+
+
Parameters
+

rel_to (int or ParticleHandle) – Particle to relate to (either particle id or particle object).

+
+
+
+ +
+
+vs_quat
+

Virtual site quaternion.

+

This quaternion describes the virtual particles orientation in the +body fixed frame of the related real particle.

+

vs_quat : (4,) array_like of float

+
+

Note

+

This needs the feature VIRTUAL_SITES_RELATIVE.

+
+
+ +
+
+vs_relative
+

Virtual sites relative parameters.

+

Allows for manual access to the attributes of virtual sites in the “relative” +implementation. PID denotes the id of the particle to which this virtual site +is related and distance the distance between non-virtual and virtual particle. +The relative orientation is specified as a quaternion of 4 floats.

+

vs_relative : tuple (PID, distance, quaternion)

+
+

Note

+

This needs the feature VIRTUAL_SITES_RELATIVE

+
+
+ +
+ +
+
+class espressomd.particle_data.ParticleList
+

Bases: object

+

Provides access to the particles.

+
+
+add(self, *args, **kwargs)
+

Adds one or several particles to the system

+
+
Parameters
+

Either a dictionary or a bunch of keyword args.

+
+
Returns
+

+
+
Return type
+

Returns an instance of espressomd.particle_data.ParticleHandle for each added particle.

+
+
+ +

Examples

+
>>> import espressomd
+>>> system = espressomd.System(box_l=[10, 10, 10])
+>>> # add two particles
+>>> system.part.add(id=0, pos=(1, 0, 0))
+>>> system.part.add(id=1, pos=(2, 0, 0))
+
+
+

pos is mandatory, id can be omitted, in which case it is assigned automatically. +Several particles can be added by passing one value per particle to each property:

+
system.part.add(pos=((1, 2, 3), (4, 5, 6)), q=(1, -1))
+
+
+
+ +
+
+all(self)
+

Get a slice containing all particles.

+
+ +
+
+by_id(self, id)
+

Access a particle by its integer id.

+
+ +
+
+by_ids(self, ids)
+

Get a slice of particles by their integer ids.

+
+ +
+
+clear(self)
+

Removes all particles.

+ +
+ +
+
+exists(self, idx)
+
+ +
+
+highest_particle_id
+

Largest particle id.

+
+ +
+
+n_part_types
+

Number of particle types.

+
+ +
+
+n_rigidbonds
+

Number of rigid bonds.

+
+ +
+
+pairs(self)
+

Generator returns all pairs of particles.

+
+ +
+
+select(self, *args, **kwargs)
+

Generates a particle slice by filtering particles via a user-defined criterion

+

Parameters:

+

Either: a keyword arguments in which the keys are names of particle +properties and the values are the values to filter for. E.g.,:

+
system.part.select(type=0, q=1)
+
+
+

Or: a function taking a ParticleHandle as argument and returning True if +the particle is to be filtered for. E.g.,:

+
system.part.select(lambda p: p.pos[0] < 0.5)
+
+
+
+
Returns
+

An instance of ParticleSlice containing the selected particles

+
+
Return type
+

ParticleSlice

+
+
+
+ +
+
+writevtk(self, fname, types='all')
+

Write the positions and velocities of particles with specified +types to a VTK file.

+
+
Parameters
+
    +
  • fname (str) – Filename of the target output file

  • +
  • types (list of int or the string ‘all’, optional (default: ‘all’)) – A list of particle types which should be output to ‘fname’

  • +
+
+
+

Examples

+
>>> import espressomd
+>>> system = espressomd.System(box_l=[10, 10, 10])
+>>> # add several particles
+>>> system.part.add(pos=0.5 * system.box_l, v=[1, 0, 0], type=0)
+>>> system.part.add(pos=0.4 * system.box_l, v=[0, 2, 0], type=1)
+>>> system.part.add(pos=0.7 * system.box_l, v=[2, 0, 1], type=1)
+>>> system.part.add(pos=0.1 * system.box_l, v=[0, 0, 1], type=2)
+>>> # write to VTK
+>>> system.part.writevtk("part_type_0_1.vtk", types=[0, 1])
+>>> system.part.writevtk("part_type_2.vtk", types=[2])
+>>> system.part.writevtk("part_all.vtk")
+
+
+
+

Todo

+

move to ./io/writer/

+
+
+ +
+ +
+
+class espressomd.particle_data.ParticleSlice
+

Bases: espressomd.particle_data._ParticleSliceImpl

+

Handles slice inputs e.g. part[0:2]. Sets values for selected slices or +returns values as a single list.

+
+
+property bonds
+

The bonds stored by this particle. Note that bonds are only stored by +one partner. You need to define a bonded interaction.

+

bonds : list/tuple of tuples/lists

+

A bond tuple is specified as a bond identifier associated with +a particle (bond_ID, part_ID). A single particle may contain +multiple such tuples.

+
+

See also

+
+
espressomd.particle_data.ParticleHandle.add_bond

Method to add bonds to a Particle

+
+
espressomd.particle_data.ParticleHandle.delete_bond

Method to remove bonds from a Particle

+
+

Bond ids have to be an integer >= 0.

+
+
+
+
+ +
+
+property dip
+

The orientation of the dipole axis.

+

dip : (3,) array_like of float

+
+

Note

+

This needs the feature DIPOLES.

+
+
+ +
+
+property dipm
+

The magnitude of the dipole moment.

+

dipm : float

+
+

Note

+

This needs the feature DIPOLES.

+
+
+ +
+
+property director
+

The particle director.

+

The director defines the the z-axis in the body-fixed frame. +If particle rotations happen, the director, i.e., the body-fixed +coordinate system co-rotates. Properties such as the angular +velocity espressomd.particle_data.ParticleHandle.omega_body +are evaluated in this body-fixed coordinate system. +When using particle dipoles, the dipole moment is co-aligned with +the particle director. Setting the director thus modifies the +dipole moment orientation (espressomd.particle_data.ParticleHandle.dip) +and vice versa. +See also Rotational degrees of freedom and particle anisotropy.

+

director : (3,) array_like of float

+
+

Note

+

This needs the feature ROTATION.

+
+
+ +
+
+property exclusions
+

The exclusion list of particles where non-bonded interactions are ignored.

+
+

Note

+

This needs the feature EXCLUSIONS.

+
+

exclusions : (N,) array_like of int

+
+ +
+
+property ext_force
+

An additional external force applied to the particle.

+

ext_force : (3,) array_like of float

+
+

Note

+

This needs the feature EXTERNAL_FORCES.

+
+
+ +
+
+property ext_torque
+

An additional external torque is applied to the particle.

+

ext_torque : (3,) array_like of float

+
+

Note

+
    +
  • This torque is specified in the laboratory frame!

  • +
  • This needs features EXTERNAL_FORCES and ROTATION.

  • +
+
+
+ +
+
+property f
+

The instantaneous force acting on this particle.

+

f : (3,) array_like of float

+
+

Note

+

Whereas the velocity is modified with respect to the velocity you set +upon integration, the force it recomputed during the integration step and any +force set in this way is immediately lost at the next integration step.

+
+
+ +
+
+property fix
+

Fixes the particle motion in the specified cartesian directions.

+

fix : (3,) array_like of bool

+

Fixes the particle in space. By supplying a set of 3 bools as +arguments it is possible to fix motion in x, y, or z coordinates +independently. For example:

+
part[<INDEX>].fix = [False, False, True]
+
+
+

will fix motion for particle with index INDEX only in z.

+
+

Note

+

This needs the feature EXTERNAL_FORCES.

+
+
+ +
+
+property gamma
+

The body-fixed frictional coefficient used in the Langevin +and Brownian thermostats.

+

gamma : float or (3,) array_like of float

+
+

Note

+

This needs features PARTICLE_ANISOTROPY and +THERMOSTAT_PER_PARTICLE.

+
+
+

See also

+
+
espressomd.thermostat.Thermostat.set_langevin()

Setting the parameters of the Langevin thermostat

+
+
+
+
+ +
+
+property gamma_rot
+

The particle translational frictional coefficient used in +the Langevin and Brownian thermostats.

+

gamma_rot : float or (3,) array_like of float

+
+

Note

+

This needs features ROTATION, PARTICLE_ANISOTROPY +and THERMOSTAT_PER_PARTICLE.

+
+
+ +
+
+property id
+

Integer particle id

+
+ +
+
+property image_box
+

The image box the particles is in.

+

This is the number of times the particle position has been folded by +the box length in each direction.

+
+ +
+
+property lees_edwards_flag
+

The Lees-Edwards flag that indicate if the particle crossed +the upper or lower boundary.

+
+ +
+
+property lees_edwards_offset
+

The accumulated Lees-Edwards offset. +Can be used to reconstruct continuous trajectories.

+

offset : (3,) array_like of float

+
+ +
+
+property mass
+

Particle mass.

+

mass : float

+
+

See also

+
+
espressomd.thermostat.Thermostat.set_langevin()

Setting the parameters of the Langevin thermostat

+
+
+
+
+ +
+
+property mol_id
+

The molecule id of the Particle.

+

mol_id : int

+

The particle mol_id is used to differentiate between +particles belonging to different molecules, e.g. when virtual +sites are used, or object-in-fluid cells. The default +mol_id for all particles is 0.

+
+

Note

+

The value of mol_id has to be an integer >= 0.

+
+
+ +
+
+property mu_E
+

Particle electrophoretic velocity.

+

mu_E : float

+

This effectively acts as a velocity offset between +a lattice-Boltzmann fluid and the particle. Has only +an effect if LB is turned on.

+
+

Note

+

This needs the feature LB_ELECTROHYDRODYNAMICS.

+
+
+ +
+
+property node
+

The node the particle is on, identified by its MPI rank.

+
+ +
+
+property omega_body
+

The particle angular velocity in body frame.

+

omega_body : (3,) array_like of float

+

This property sets the angular momentum of this particle in the +particles co-rotating frame (or body frame).

+
+

Note

+

This needs the feature ROTATION.

+
+
+ +
+
+property omega_lab
+

The particle angular velocity the lab frame.

+

omega_lab : (3,) array_like of float

+
+

Note

+

This needs the feature ROTATION.

+

If you set the angular velocity of the particle in the lab +frame, the orientation of the particle +(quat) must be +set before setting omega_lab, otherwise the conversion from +lab to body frame will not be handled properly.

+
+
+

See also

+

omega_body

+
+
+ +
+
+property pos
+

The unwrapped (not folded into central box) particle position.

+

pos : (3,) array_like of float

+
+ +
+
+property q
+

Particle charge.

+

q : float

+
+

Note

+

This needs the feature ELECTROSTATICS.

+
+
+ +
+
+property quat
+

Quaternion representation of the particle rotational position.

+

quat : (4,) array_like of float

+
+

Note

+

This needs the feature ROTATION.

+
+
+ +
+
+property rinertia
+

The particle rotational inertia.

+

rinertia : (3,) array_like of float

+

Sets the diagonal elements of this particle’s rotational inertia +tensor. These correspond with the inertial moments along the +coordinate axes in the particle’s co-rotating coordinate system. +When the particle’s quaternions are set to [1, 0, 0, 0,], the +co-rotating and the fixed (lab) frames are co-aligned.

+
+

Note

+

This needs the feature ROTATIONAL_INERTIA.

+
+
+ +
+
+property rotation
+

Switches the particle’s rotational degrees of freedom in the +Cartesian axes in the body-fixed frame. The content of the torque +and omega variables are meaningless for the co-ordinates for which +rotation is disabled.

+

The default is not to integrate any rotational degrees of freedom.

+

rotation : (3,) array_like of bool

+
+

Note

+

This needs the feature ROTATION.

+
+
+ +
+
+property swimming
+

Set swimming parameters.

+

This property takes a dictionary with a different number of +entries depending whether there is an implicit fluid (i.e. with the +Langevin thermostat) of an explicit fluid (with LB).

+

Swimming enables the particle to be self-propelled in the direction +determined by its quaternion. For setting the quaternion of the +particle see quat. The +self-propulsion speed will relax to a constant velocity, that is specified by +v_swim. Alternatively it is possible to achieve a constant velocity by +imposing a constant force term f_swim that is balanced by friction of a +(Langevin) thermostat. The way the velocity of the particle decays to the +constant terminal velocity in either of these methods is completely +determined by the friction coefficient. You may only set one of the +possibilities v_swim or f_swim as you cannot relax to constant force +and constant velocity at the same time. Setting both v_swim and +f_swim to 0.0 disables swimming. This option applies to all +non-lattice-Boltzmann thermostats. Note that there is no real difference +between v_swim and f_swim since the latter may always be chosen such that +the same terminal velocity is achieved for a given friction coefficient.

+
+
Parameters
+
    +
  • f_swim (float) – Achieve a constant velocity by imposing a constant +force term f_swim that is balanced by friction of a +(Langevin) thermostat. This excludes the option v_swim.

  • +
  • v_swim (float) – Achieve a constant velocity by imposing a constant terminal +velocity v_swim. This excludes the option f_swim.

  • +
  • mode (str, {‘pusher’, ‘puller’, ‘N/A’}) – The LB flow field can be generated by a pushing or a +pulling mechanism, leading to change in the sign of the +dipolar flow field with respect to the direction of motion.

  • +
  • dipole_length (float) – This determines the distance of the source of +propulsion from the particle’s center.

  • +
+
+
+

Notes

+

This needs the feature ENGINE. The keys 'mode', +and 'dipole_length' are only +available if ENGINE is used with LB or CUDA.

+

Examples

+
>>> import espressomd
+>>> system = espressomd.System(box_l=[10, 10, 10])
+>>> # Langevin swimmer
+>>> system.part.add(pos=[1, 0, 0], swimming={'f_swim': 0.03})
+>>> # LB swimmer
+>>> system.part.add(pos=[2, 0, 0], swimming={'f_swim': 0.01,
+...     'mode': 'pusher', 'dipole_length': 2.0})
+
+
+
+ +
+
+to_dict(self)
+

Returns the particles attributes as a dictionary.

+

It can be used to save the particle data and recover it by using

+
>>> p = system.part.add(...)
+>>> particle_dict = p.to_dict()
+>>> system.part.add(particle_dict)
+
+
+

It includes the content of particle_attributes, minus a few exceptions:

+
    +
  • dip, director: +Setting only the director will overwrite the orientation of the +particle around the axis parallel to dipole moment/director. +Quaternions contain the full info.

  • +
  • image_box, node

  • +
+
+ +
+
+property torque_lab
+

The particle torque in the lab frame.

+

torque_lab : (3,) array_like of float

+

This property defines the torque of this particle +in the fixed frame (or laboratory frame).

+
+

Note

+

The orientation of the particle +(quat) must be +set before setting this property, otherwise the conversion from +lab to body frame will not be handled properly.

+
+
+ +
+
+property type
+

The particle type for nonbonded interactions.

+

type : int

+
+

Note

+

The value of type has to be an integer >= 0.

+
+
+ +
+
+property v
+

The particle velocity in the lab frame.

+

v : (3,) array_like of float

+
+

Note

+

The velocity remains variable and will be changed during integration.

+
+
+ +
+
+property virtual
+

Virtual flag.

+

Declares the particles as virtual (True) or non-virtual +(False, default).

+

virtual : bool

+
+

Note

+

This needs the feature VIRTUAL_SITES

+
+
+ +
+
+property vs_quat
+

Virtual site quaternion.

+

This quaternion describes the virtual particles orientation in the +body fixed frame of the related real particle.

+

vs_quat : (4,) array_like of float

+
+

Note

+

This needs the feature VIRTUAL_SITES_RELATIVE.

+
+
+ +
+
+property vs_relative
+

Virtual sites relative parameters.

+

Allows for manual access to the attributes of virtual sites in the “relative” +implementation. PID denotes the id of the particle to which this virtual site +is related and distance the distance between non-virtual and virtual particle. +The relative orientation is specified as a quaternion of 4 floats.

+

vs_relative : tuple (PID, distance, quaternion)

+
+

Note

+

This needs the feature VIRTUAL_SITES_RELATIVE

+
+
+ +
+ +
+
+espressomd.particle_data.set_slice_one_for_all(particle_slice, attribute, values)
+
+ +
+
+espressomd.particle_data.set_slice_one_for_each(particle_slice, attribute, values)
+
+ +
+
+

espressomd.polymer module

+
+
+espressomd.polymer.linear_polymer_positions(**kwargs)
+

Generates particle positions for polymer creation.

+
+
Parameters
+
    +
  • n_polymers (int, required) – Number of polymer chains

  • +
  • beads_per_chain (int, required) – Number of monomers per chain

  • +
  • bond_length (float, required) – distance between adjacent monomers in a chain

  • +
  • seed (int, required) – Seed for the RNG used to generate the particle positions.

  • +
  • bond_angle (float, optional) – If set, this parameter defines the angle between adjacent bonds +within a polymer.

  • +
  • start_positions (array_like float.) – If set, this vector defines the start positions for the polymers, i.e., +the position of each polymer’s first monomer bead. +Here, a numpy array of shape (n_polymers, 3) is expected.

  • +
  • min_distance (float, optional) – Minimum distance between all generated positions. Defaults to 0

  • +
  • respect_constraints (bool, optional) – If True, the particle setup tries to obey previously defined constraints. +Default value is False.

  • +
  • max_tries (int, optional) – Maximal number of attempts to generate every monomer position, +as well as maximal number of retries per polymer, if choosing +suitable monomer positions fails. Default value is 1000. +Depending on the total number of beads and constraints, +this value needs to be adapted.

  • +
+
+
Returns
+

Three-dimensional numpy array, namely a list of polymers containing the +coordinates of the respective monomers.

+
+
Return type
+

ndarray

+
+
+
+ +
+
+espressomd.polymer.setup_diamond_polymer(system=None, bond=None, MPC=0, dist_cM=1, val_cM=0.0, val_nodes=0.0, start_id='auto', no_bonds=False, type_nodes=0, type_nM=1, type_cM=2)
+

Places particles to form a diamond lattice shaped polymer. +Can also assign charges and bonds at the appropriate places.

+
+
Parameters
+
    +
  • system (espressomd.system.System, required) – System to which the particles will be added.

  • +
  • bond (espressomd.interactions.BondedInteraction, required if no_bonds == False) – The bond to be created between monomers. Should be compatible with the +spacing system.box_l[0]*(0.25 * sqrt(3))/(MPC + 1) between monomers.

  • +
  • no_bonds (bool, optional) – If True, the particles will only be placed in the system but not connected by bonds. +In that case, the bond argument can be omitted. Defaults to False.

  • +
  • MPC (int, optional) – Monomers per chain, where chain refers to the connection +between the 8 lattice nodes of the diamond lattice. +Defaults to 0.

  • +
  • dist_cM (int, optional) – Distance between charged monomers in the chains. Defaults to 1.

  • +
  • val_cM (float, optional) – Valence of the charged monomers in the chains. Defaults to 0.

  • +
  • val_nodes (float, optional) – Valence of the node particles. Defaults to 0.

  • +
  • start_id (int or 'auto', optional) – Start id for particle creation. Subsequent ids will be contiguous integers. +If 'auto', particle ids will start after the highest id of particles already in the system.

  • +
  • type_nodes (int, optional) – Type assigned to the node particles. Defaults to 0.

  • +
  • type_nM (int, optional) – Type assigned to the neutral monomers in the chains. Defaults to 1.

  • +
  • type_cM (int, optional) – Type assigned to the charged monomers in the chains. Defaults to 2.

  • +
+
+
+
+ +
+
+espressomd.polymer.validate_params(_params, default)
+
+ +
+
+

espressomd.profiler module

+
+
+espressomd.profiler.begin_section(name)
+

Start named section in profiler.

+
+
Parameters
+

name (str) – Name of the section

+
+
+
+ +
+
+espressomd.profiler.end_section(name)
+

End named section in profiler.

+
+
Parameters
+

name (str) – Name of the section

+
+
+
+ +
+
+

espressomd.reaction_methods module

+
+
+class espressomd.reaction_methods.ConstantpHEnsemble(**kwargs)[source]
+

Bases: espressomd.reaction_methods.ReactionAlgorithm

+

This class implements the constant pH Ensemble.

+

When adding an acid-base reaction, the acid and base particle types +are always assumed to be at index 0 of the lists passed to arguments +reactant_types and product_types.

+
+
+constant_pH
+

Constant pH value.

+
+
Type
+

float

+
+
+
+ +
+
+add_reaction(*args, **kwargs)[source]
+

Sets up a reaction in the forward and backward direction.

+
+
Parameters
+
    +
  • gamma (float) – Equilibrium constant \(\Gamma\) of the reaction in simulation +units (see section Reaction ensemble for its definition).

  • +
  • reactant_types (list of int) – List of particle types of reactants in the reaction.

  • +
  • reactant_coefficients (list of int) – List of stoichiometric coefficients of the reactants in the same +order as the list of their types.

  • +
  • product_types (list of int) – List of particle types of products in the reaction.

  • +
  • product_coefficients (list of int) – List of stoichiometric coefficients of products of the reaction in +the same order as the list of their types

  • +
  • default_charges (dict) – A dictionary of default charges for types that occur +in the provided reaction.

  • +
  • check_for_electroneutrality (bool) – Check for electroneutrality of the given reaction. +Default is True.

  • +
+
+
+
+ +
+
+required_keys()[source]
+
+ +
+
+valid_keys()[source]
+
+ +
+ +
+
+class espressomd.reaction_methods.ReactionAlgorithm(**kwargs)[source]
+

Bases: espressomd.script_interface.ScriptInterfaceHelper

+

This class provides the base class for Reaction Algorithms like +the Reaction Ensemble algorithm and the constant pH method. +Initialize the reaction algorithm by setting the +standard pressure, temperature, and the exclusion range.

+

Note: When creating particles the velocities of the new particles are set +according the Maxwell-Boltzmann distribution. In this step the mass of the +new particle is assumed to equal 1.

+
+
Parameters
+
    +
  • kT (float) – Thermal energy of the system in simulation units

  • +
  • exclusion_range (float) – Minimal distance from any particle, within which new particles will not +be inserted.

  • +
  • seed (int) – Initial counter value (or seed) of the Mersenne Twister RNG.

  • +
  • exclusion_radius_per_type (dict, optional) – Mapping of particle types to exclusion radii.

  • +
  • search_algorithm (str) – Pair search algorithm. Default is "order_n", which evaluates the +distance between the inserted particle and all other particles in the +system, which scales with O(N). For MPI-parallel simulations, the +"parallel" method is faster. The "parallel" method is not +recommended for simulations on 1 MPI rank, since it comes with the +overhead of a ghost particle update.

  • +
+
+
+
+
+remove_constraint()
+

Remove any previously defined constraint. +Requires setting the volume using set_volume().

+
+ +
+
+set_cylindrical_constraint_in_z_direction()
+

Constrain the reaction moves within a cylinder aligned on the z-axis. +Requires setting the volume using set_volume().

+
+
Parameters
+
    +
  • center_x (float) – x coordinate of center of the cylinder.

  • +
  • center_y (float) – y coordinate of center of the cylinder.

  • +
  • radius_of_cylinder (float) – radius of the cylinder

  • +
+
+
+
+ +
+
+set_wall_constraints_in_z_direction()
+

Restrict the sampling area to a slab in z-direction. Requires setting +the volume using set_volume(). This constraint is necessary when +working with Electrostatic Layer Correction (ELC).

+
+
Parameters
+
    +
  • slab_start_z (float) – z coordinate of the bottom wall.

  • +
  • slab_end_z (float) – z coordinate of the top wall.

  • +
+
+
+

Examples

+
>>> import espressomd
+>>> import espressomd.shapes
+>>> import espressomd.electrostatics
+>>> import espressomd.reaction_methods
+>>> import numpy as np
+>>> # setup a charged system
+>>> box_l = 20
+>>> elc_gap = 10
+>>> system = espressomd.System(box_l=[box_l, box_l, box_l + elc_gap])
+>>> system.time_step = 0.001
+>>> system.cell_system.skin = 0.4
+>>> types = {"HA": 0, "A-": 1, "H+": 2, "wall": 3}
+>>> charges = {types["HA"]: 0, types["A-"]: -1, types["H+"]: +1}
+>>> for i in range(10):
+...     system.part.add(pos=np.random.random(3) * box_l, type=types["A-"], q=charges[types["A-"]])
+...     system.part.add(pos=np.random.random(3) * box_l, type=types["H+"], q=charges[types["H+"]])
+>>> for particle_type in charges.keys():
+...     system.non_bonded_inter[particle_type, types["wall"]].wca.set_params(epsilon=1.0, sigma=1.0)
+>>> # add ELC actor
+>>> p3m = espressomd.electrostatics.P3M(prefactor=1.0, accuracy=1e-2)
+>>> elc = espressomd.electrostatics.ELC(actor=p3m, maxPWerror=1.0, gap_size=elc_gap)
+>>> system.actors.add(elc)
+>>> # add constant pH method
+>>> RE = espressomd.reaction_methods.ConstantpHEnsemble(kT=1, exclusion_range=1, seed=77)
+>>> RE.constant_pH = 2
+>>> RE.add_reaction(gamma=0.0088, reactant_types=[types["HA"]],
+...                 product_types=[types["A-"], types["H+"]],
+...                 default_charges=charges)
+>>> # add walls for the ELC gap
+>>> RE.set_wall_constraints_in_z_direction(0, box_l)
+>>> RE.set_volume(box_l**3)
+>>> system.constraints.add(shape=espressomd.shapes.Wall(dist=0, normal=[0, 0, 1]),
+...                        particle_type=types["wall"])
+>>> system.constraints.add(shape=espressomd.shapes.Wall(dist=-box_l, normal=[0, 0, -1]),
+...                        particle_type=types["wall"])
+
+
+
+ +
+
+get_wall_constraints_in_z_direction()
+

Returns the restrictions of the sampling area in z-direction.

+
+ +
+
+set_volume()
+

Set the volume to be used in the acceptance probability of the reaction +ensemble. This can be useful when using constraints, if the relevant +volume is different from the box volume. If not used the default volume +which is used, is the box volume.

+
+
Parameters
+

volume (float) – Volume of the system in simulation units

+
+
+
+ +
+
+get_volume()
+

Get the volume to be used in the acceptance probability of the reaction +ensemble.

+
+ +
+
+get_acceptance_rate_configurational_moves():
+

Returns the acceptance rate for the configuration moves.

+
+ +
+
+get_acceptance_rate_reaction()
+

Returns the acceptance rate for the given reaction.

+
+
Parameters
+

reaction_id (int) – Reaction id

+
+
+
+ +
+
+set_non_interacting_type()
+

Sets the particle type for non-interacting particles. +Default value: 100. +This is used to temporarily hide particles during a reaction trial +move, if they are to be deleted after the move is accepted. Please +change this value if you intend to use the type 100 for some other +particle types with interactions, or if you need improved performance, +as the default value of 100 causes some overhead. +Please also note that particles +in the current implementation of the Reaction Ensemble are only +hidden with respect to Lennard-Jones and Coulomb interactions. Hiding +of other interactions, for example a magnetic, needs to be implemented +in the code.

+
+
Parameters
+

type (int) – Particle type for the hidden particles

+
+
+
+ +
+
+get_non_interacting_type()
+

Returns the type which is used for hiding particle

+
+ +
+
+reaction()
+

Performs randomly selected reactions.

+
+
Parameters
+

reaction_steps (int, optional) – The number of reactions to be performed at once, defaults to 1.

+
+
+
+ +
+
+displacement_mc_move_for_particles_of_type()
+

Performs displacement Monte Carlo moves for particles of a given type. +New positions of the displaced particles are chosen from the whole box +with a uniform probability distribution and new velocities are +sampled from the Maxwell-Boltzmann distribution.

+

The sequence of moves is only accepted if each individual move in +the sequence was accepted. Particles are sampled without replacement. +Therefore, calling this method once for 10 particles is not equivalent +to calling this method 10 times for 1 particle.

+
+
Parameters
+
    +
  • type_mc (int) – Particle type which should be moved

  • +
  • particle_number_to_be_changed (int) – Number of particles to move, defaults to 1. +Particles are selected without replacement.

  • +
+
+
Returns
+

Whether all moves were accepted.

+
+
Return type
+

bool

+
+
+
+ +
+
+delete_particle()
+

Deletes the particle of the given p_id and makes sure that the particle +range has no holes. This function has some restrictions, as e.g. bonds +are not deleted. Therefore only apply this function to simple ions.

+
+
Parameters
+

p_id (int) – Id of the particle to be deleted.

+
+
+
+ +
+
+change_reaction_constant()
+

Changes the reaction constant of a given reaction +(for both the forward and backward reactions). +The reaction_id which is assigned to a reaction +depends on the order in which add_reaction() was called. +The 0th reaction has reaction_id=0, the next added +reaction needs to be addressed with reaction_id=1, etc.

+
+
Parameters
+
    +
  • reaction_id (int) – Reaction id

  • +
  • gamma (float) – New reaction constant

  • +
+
+
+
+ +
+
+delete_reaction()
+

Delete a reaction from the set of used reactions +(the forward and backward reaction). +The reaction_id which is assigned to a reaction +depends on the order in which add_reaction() was called. +The 0th reaction has reaction_id=0, the next added +reaction needs to be addressed with reaction_id=1, etc. +After the deletion of a reaction subsequent reactions +take the reaction_id of the deleted reaction.

+
+
Parameters
+

reaction_id (int) – Reaction id

+
+
+
+ +
+
+add_reaction(**kwargs)[source]
+

Sets up a reaction in the forward and backward direction.

+
+
Parameters
+
    +
  • gamma (float) – Equilibrium constant \(\Gamma\) of the reaction in simulation +units (see section Reaction ensemble for its definition).

  • +
  • reactant_types (list of int) – List of particle types of reactants in the reaction.

  • +
  • reactant_coefficients (list of int) – List of stoichiometric coefficients of the reactants in the same +order as the list of their types.

  • +
  • product_types (list of int) – List of particle types of products in the reaction.

  • +
  • product_coefficients (list of int) – List of stoichiometric coefficients of products of the reaction in +the same order as the list of their types

  • +
  • default_charges (dict) – A dictionary of default charges for types that occur +in the provided reaction.

  • +
  • check_for_electroneutrality (bool) – Check for electroneutrality of the given reaction. +Default is True.

  • +
+
+
+
+ +
+
+get_status()[source]
+

Returns the status of the reaction ensemble in a dictionary containing +the used reactions, the used kT and the used exclusion radius.

+
+ +
+
+required_keys()[source]
+
+ +
+
+valid_keys()[source]
+
+ +
+ +
+
+class espressomd.reaction_methods.ReactionEnsemble(**kwargs)[source]
+

Bases: espressomd.reaction_methods.ReactionAlgorithm

+

This class implements the Reaction Ensemble.

+
+ +
+
+class espressomd.reaction_methods.SingleReaction(**kwargs)[source]
+

Bases: espressomd.script_interface.ScriptInterfaceHelper

+
+
+make_backward_reaction()[source]
+
+ +
+
+required_keys()[source]
+
+ +
+
+valid_keys()[source]
+
+ +
+ +
+
+class espressomd.reaction_methods.WidomInsertion(**kwargs)[source]
+

Bases: espressomd.reaction_methods.ReactionAlgorithm

+

This class implements the Widom insertion method in the canonical ensemble +for homogeneous systems, where the excess chemical potential is not +depending on the location.

+
+
+add_reaction(**kwargs)[source]
+

Sets up a reaction in the forward and backward direction.

+
+
Parameters
+
    +
  • gamma (float) – Equilibrium constant \(\Gamma\) of the reaction in simulation +units (see section Reaction ensemble for its definition).

  • +
  • reactant_types (list of int) – List of particle types of reactants in the reaction.

  • +
  • reactant_coefficients (list of int) – List of stoichiometric coefficients of the reactants in the same +order as the list of their types.

  • +
  • product_types (list of int) – List of particle types of products in the reaction.

  • +
  • product_coefficients (list of int) – List of stoichiometric coefficients of products of the reaction in +the same order as the list of their types

  • +
  • default_charges (dict) – A dictionary of default charges for types that occur +in the provided reaction.

  • +
  • check_for_electroneutrality (bool) – Check for electroneutrality of the given reaction. +Default is True.

  • +
+
+
+
+ +
+
+calculate_excess_chemical_potential(**kwargs)[source]
+

Given a set of samples of the particle insertion potential energy, +calculates the excess chemical potential and its statistical error.

+
+
Parameters
+
    +
  • particle_insertion_potential_energy_samples (array_like of float) – Samples of the particle insertion potential energy.

  • +
  • N_blocks (int, optional) – Number of bins for binning analysis.

  • +
+
+
Returns
+

    +
  • mean (float) – Mean excess chemical potential.

  • +
  • error (float) – Standard error of the mean.

  • +
+

+
+
+
+ +
+
+calculate_particle_insertion_potential_energy(**kwargs)[source]
+

Measures the potential energy when particles are inserted in the +system following the reaction provided in reaction_id. Please +define the insertion moves first by calling the method +add_reaction() (with only product types +specified).

+

Note that although this function does not provide directly +the chemical potential, it can be used to calculate it. +For an example of such an application please check +/samples/widom_insertion.py.

+
+
Parameters
+

reaction_id (int) – Reaction identifier.

+
+
+
+ +
+
+required_keys()[source]
+
+ +
+
+valid_keys()[source]
+
+ +
+ +
+
+

espressomd.rotation module

+
+
+espressomd.rotation.diagonalized_inertia_tensor(positions, masses)[source]
+

Calculate the diagonalized inertia tensor +with respect to the center of mass +for given point masses at given positions.

+
+
Parameters
+
    +
  • positions ((N,3) array_like of float) – Positions of the masses.

  • +
  • masses ((N,) array_like of float)

  • +
+
+
Returns
+

    +
  • (3,) array_like of float – Principal moments of inertia.

  • +
  • (3,3) array_like of float – Principal axes of inertia. +Note that the second axis is the coordinate axis (same as input).

  • +
+

+
+
+
+ +
+
+espressomd.rotation.inertia_tensor(positions, masses)[source]
+

Calculate the inertia tensor for given point masses +at given positions.

+
+
Parameters
+
    +
  • positions ((N,3) array_like of float) – Point masses’ positions.

  • +
  • masses ((N,) array_like of float)

  • +
+
+
Returns
+

Moment of inertia tensor.

+
+
Return type
+

(3,3) array_like of float

+
+
+

Notes

+

See wikipedia.

+
+ +
+
+espressomd.rotation.matrix_to_quat(m)[source]
+

Convert the (proper) rotation matrix to the corresponding quaternion representation based +on pyquaternion.

+
+
Parameters
+

m ((3,3) array_like of float) – Rotation matrix.

+
+
Returns
+

Quaternion representation of the rotation.

+
+
Return type
+

array_like of float

+
+
Raises
+

ValueError – If the matrix does not a correspond to a proper rotation (det(m) != 1).

+
+
+
+ +
+
+

espressomd.script_interface module

+
+
+class espressomd.script_interface.PObjectRef
+

Bases: object

+
+
+print_sip(self)
+
+ +
+ +
+
+class espressomd.script_interface.PScriptInterface(name=None, policy='GLOBAL', sip=None, **kwargs)
+

Bases: object

+

Python interface to a core ScriptInterface object. The core ScriptInterface +class is itself an interface for other core classes, such as constraints, +shapes, observables, etc.

+

This class can be instantiated in two ways: (1) with the object id of an +existing core ScriptInterface object, or (2) with parameters to construct +a new ScriptInterface object in the core.

+
+
Parameters
+
    +
  • sip (PObjectRef) – Object id of an existing core object (method 1).

  • +
  • name (str) – Name of the core class to instantiate (method 2).

  • +
  • **kwargs – Parameters for the core class constructor (method 2).

  • +
  • policy (str, {‘GLOBAL’, ‘LOCAL’}) – Creation policy. The managed object exists either on all MPI nodes +with ‘GLOBAL’ (default), or only on the head node with ‘LOCAL’.

  • +
+
+
+
+
+sip
+

Pointer to a ScriptInterface object in the core.

+
+
Type
+

PObjectRef

+
+
+
+ +
+
+call_method(self, method, **kwargs)
+

Call a method of the core class.

+
+
Parameters
+
    +
  • method (Creation policy.) – Name of the core method.

  • +
  • **kwargs – Arguments for the method.

  • +
+
+
+
+ +
+
+get_parameter(self, name)
+
+ +
+
+get_params(self)
+
+ +
+
+get_sip(self)
+

Get pointer to the core object.

+
+ +
+
+name(self)
+

Return name of the core class.

+
+ +
+
+set_params(self, **kwargs)
+
+ +
+ +
+
+class espressomd.script_interface.ScriptInterfaceHelper(**kwargs)
+

Bases: espressomd.script_interface.PScriptInterface

+
+
+define_bound_methods(self)
+
+ +
+
+generate_caller(self, method_name)
+
+ +
+ +
+
+class espressomd.script_interface.ScriptObjectList(**kwargs)
+

Bases: espressomd.script_interface.ScriptInterfaceHelper

+

Base class for container-like classes such as +Constraints and +LBBoundaries. Derived classes must +implement an add() method which adds a single item to the container.

+

The core objects must be managed by a container derived from +ScriptInterface::ObjectList.

+
+ +
+
+class espressomd.script_interface.ScriptObjectMap(**kwargs)
+

Bases: espressomd.script_interface.ScriptInterfaceHelper

+

Base class for container-like classes such as +BondedInteractions. Derived classes must +implement an add() method which adds a single item to the container.

+

The core objects must be managed by a container derived from +ScriptInterface::ObjectMap.

+
+
+clear(self)
+

Remove all elements.

+
+ +
+
+items(self)
+
+ +
+
+keys(self)
+
+ +
+
+remove(self, key)
+

Remove the element with the given key. +This is a no-op if the key does not exist.

+
+ +
+ +
+
+espressomd.script_interface.script_interface_register(c)
+

Decorator used to register script interface classes. +This will store a name<->class relationship in a registry, so that +parameters of type object can be instantiated as the correct python class.

+
+ +
+
+

espressomd.shapes module

+
+
+class espressomd.shapes.Cylinder(**kwargs)[source]
+

Bases: espressomd.shapes.Shape, espressomd.script_interface.ScriptInterfaceHelper

+

A cylinder shape.

+
+
+center
+

Coordinates of the center of the cylinder.

+
+
Type
+

(3,) array_like of float

+
+
+
+ +
+
+axis
+

Axis of the cylinder.

+
+
Type
+

(3,) array_like of float

+
+
+
+ +
+
+radius
+

Radius of the cylinder.

+
+
Type
+

float

+
+
+
+ +
+
+length
+

Length of the cylinder.

+
+
Type
+

float

+
+
+
+ +
+
+direction
+

Surface orientation, for +1 the normal points +out of the mantel, for -1 it points inward.

+
+
Type
+

int

+
+
+
+ +
+
+open
+

cylinder is open or has caps.

+
+
Type
+

bool

+
+
+
+ +
+ +
+
+class espressomd.shapes.Ellipsoid(**kwargs)[source]
+

Bases: espressomd.shapes.Shape, espressomd.script_interface.ScriptInterfaceHelper

+

An ellipsoid.

+

For now only ellipsoids of revolution are supported. +The symmetry axis is aligned parallel to the x-direction.

+
+
+center
+

Coordinates of the center of the ellipsoid.

+
+
Type
+

(3,) array_like of float

+
+
+
+ +
+
+a
+

Semiaxis along the axis of rotational symmetry.

+
+
Type
+

float

+
+
+
+ +
+
+b
+

Equatorial semiaxes.

+
+
Type
+

float

+
+
+
+ +
+
+direction
+

Surface orientation, for +1 the normal points +out of the mantel, for -1 it points inward.

+
+
Type
+

int

+
+
+
+ +
+ +
+
+class espressomd.shapes.HollowConicalFrustum(**kwargs)[source]
+

Bases: espressomd.shapes.Shape, espressomd.script_interface.ScriptInterfaceHelper

+

Hollow conical frustum shape.

+
+
+cyl_transform_params
+

Parameters of the spacial orientation of the frustum. Contained must be parameters for center and axis. orientation has no effect, unless central_angle != 0

+
+
Type
+

espressomd.math.CylindricalTransformationParameters,

+
+
+
+ +
+
+r1
+

Radius r1.

+
+
Type
+

float

+
+
+
+ +
+
+r2
+

Radius r2.

+
+
Type
+

float

+
+
+
+ +
+
+length
+

Length of the conical frustum along axis.

+
+
Type
+

float

+
+
+
+ +
+
+thickness
+

The thickness of the frustum. Also determines the rounding radius of the edges

+
+
Type
+

float

+
+
+
+ +
+
+direction
+

Surface orientation, for +1 the normal points +out of the mantel, for -1 it points inside of the shape. Defaults to 1

+
+
Type
+

int, optional

+
+
+
+ +
+
+central_angle
+

A central_angle creates an opening in the frustum along the side, centered symmetrically around the direction of cyl_transform_params. Must be between 0 and 2 pi. Defaults to 0.

+
+
Type
+

float, optional

+
+
+
+ +_images/conical_frustum.png +
+ +
+
+class espressomd.shapes.Rhomboid(**kwargs)[source]
+

Bases: espressomd.shapes.Shape, espressomd.script_interface.ScriptInterfaceHelper

+

A parallelepiped.

+
+
+a
+

First base vector.

+
+
Type
+

(3,) array_like of float

+
+
+
+ +
+
+b
+

Second base vector.

+
+
Type
+

(3,) array_like of float

+
+
+
+ +
+
+c
+

Third base vector.

+
+
Type
+

(3,) array_like of float

+
+
+
+ +
+
+corner
+

Lower left corner of the rhomboid.

+
+
Type
+

(3,) array_like of float

+
+
+
+ +
+
+direction
+

Surface orientation, for +1 the normal points +out of the mantel, for -1 it points inward.

+
+
Type
+

int

+
+
+
+ +
+ +
+
+class espressomd.shapes.Shape[source]
+

Bases: object

+
+ +
+
+class espressomd.shapes.SimplePore(**kwargs)[source]
+

Bases: espressomd.shapes.Shape, espressomd.script_interface.ScriptInterfaceHelper

+

Two parallel infinite planes, and a cylindrical channel connecting them. +The cylinder and the planes are connected by torus segments with an +adjustable radius.

+
+
+radius
+

The radius of the pore.

+
+
Type
+

float

+
+
+
+ +
+
+length
+

The distance between the planes.

+
+
Type
+

float

+
+
+
+ +
+
+smoothing_radius
+

Radius of the torus segments

+
+
Type
+

float

+
+
+
+ +
+
+axis
+

Axis of the cylinder and normal of the planes

+
+
Type
+

(3,) array_like of float

+
+
+
+ +
+
+center
+

Position of the center of the cylinder.

+
+
Type
+

(3,) array_like of float

+
+
+
+ +
+ +
+
+class espressomd.shapes.Slitpore(**kwargs)[source]
+

Bases: espressomd.shapes.Shape, espressomd.script_interface.ScriptInterfaceHelper

+
+Schematic for the Slitpore shape with labeled geometrical parameters. +
+
+
+channel_width
+
+
Type
+

float

+
+
+
+ +
+
+lower_smoothing_radius
+
+
Type
+

float

+
+
+
+ +
+
+pore_length
+
+
Type
+

float

+
+
+
+ +
+
+pore_mouth
+
+
Type
+

float

+
+
+
+ +
+
+pore_width
+
+
Type
+

float

+
+
+
+ +
+
+upper_smoothing_radius
+
+
Type
+

float

+
+
+
+ +
+
+dividing_plane
+
+
Type
+

float

+
+
+
+ +
+ +
+
+class espressomd.shapes.Sphere(**kwargs)[source]
+

Bases: espressomd.shapes.Shape, espressomd.script_interface.ScriptInterfaceHelper

+

A sphere.

+
+
+center
+

Center of the sphere

+
+
Type
+

(3,) array_like of float

+
+
+
+ +
+
+radius
+

Radius of the sphere.

+
+
Type
+

float

+
+
+
+ +
+
+direction
+

Surface orientation, for +1 the normal points +out of the mantel, for -1 it points inward.

+
+
Type
+

int

+
+
+
+ +
+ +
+
+class espressomd.shapes.SpheroCylinder(**kwargs)[source]
+

Bases: espressomd.shapes.Shape, espressomd.script_interface.ScriptInterfaceHelper

+

A cylinder with hemispheres as caps.

+
+
+center
+

Coordinates of the center of the cylinder.

+
+
Type
+

(3,) array_like of float

+
+
+
+ +
+
+axis
+

Axis of the cylinder.

+
+
Type
+

(3,) array_like of float

+
+
+
+ +
+
+radius
+

Radius of the cylinder.

+
+
Type
+

float

+
+
+
+ +
+
+direction
+

Surface orientation, for +1 the normal points +out of the mantel, for -1 it points inward.

+
+
Type
+

int

+
+
+
+ +
+
+length
+

Length of the cylinder (not including the caps).

+
+
Type
+

float

+
+
+
+ +
+ +
+
+class espressomd.shapes.Torus(**kwargs)[source]
+

Bases: espressomd.shapes.Shape, espressomd.script_interface.ScriptInterfaceHelper

+

A torus shape.

+
+
+center
+

Coordinates of the center of the torus.

+
+
Type
+

(3,) array_like of float

+
+
+
+ +
+
+normal
+

Normal axis of the torus.

+
+
Type
+

(3,) array_like of float

+
+
+
+ +
+
+radius
+

Radius of the torus.

+
+
Type
+

float

+
+
+
+ +
+
+tube_radius
+

Radius of the tube.

+
+
Type
+

float

+
+
+
+ +
+
+direction
+

Surface orientation, for +1 the normal points +out of the mantel, for -1 it points inward.

+
+
Type
+

int

+
+
+
+ +
+ +
+
+class espressomd.shapes.Union(**kwargs)[source]
+

Bases: espressomd.shapes.Shape, espressomd.script_interface.ScriptObjectList

+

A union of shapes.

+

This shape represents a union of shapes where the distance to the union +is defined by the smallest distance to any shape contained in the union.

+
+
+size()
+

Number of shapes contained in the union.

+
+ +
+
+clear()
+

Remove all shapes from the union.

+
+ +
+
+add(shape)[source]
+

Add a shape to the union.

+
+
Parameters
+

shape (array_like / instance of espressomd.shapes.Shape) – Shape instance(s) to be added to the union.

+
+
+
+ +
+
+remove(shape)[source]
+

Remove a shape from the union.

+
+
Parameters
+

shape (array_like / instance of espressomd.shapes.Shape) – Shape instance(s) to be removed from the union.

+
+
+
+ +
+ +
+
+class espressomd.shapes.Wall(**kwargs)[source]
+

Bases: espressomd.shapes.Shape, espressomd.script_interface.ScriptInterfaceHelper

+

An infinite plane.

+
+
+dist
+

Distance from the origin.

+
+
Type
+

float

+
+
+
+ +
+
+normal
+

Normal vector of the plane (needs not to be length 1).

+
+
Type
+

(3,) array_like of int

+
+
+
+ +
+ +
+
+

espressomd.system module

+
+
+class espressomd.system.System(**kwargs)
+

Bases: object

+

The ESPResSo system class.

+
+

Note

+

every attribute has to be declared at the class level. +This means that methods cannot define an attribute by using +self.new_attr = somevalue without declaring it inside this +indentation level, either as method, property or reference.

+
+
+
+actors
+

object +espressomd.actors.Actors

+
+
Type
+

actors

+
+
+
+ +
+
+analysis
+

object +espressomd.analyze.Analysis

+
+
Type
+

analysis

+
+
+
+ +
+
+auto_exclusions(self, distance)
+

Automatically adds exclusions between particles +that are bonded.

+

This only considers pair bonds.

+

Requires feature EXCLUSIONS.

+
+
Parameters
+

distance (int) – Bond distance upto which the exclusions should be added.

+
+
+
+ +
+
+auto_update_accumulators
+

object +espressomd.accumulators.AutoUpdateAccumulators

+
+
Type
+

auto_update_accumulators

+
+
+
+ +
+
+bond_breakage
+

object +espressomd.bond_breakage.BreakageSpecs

+
+
Type
+

bond_breakage

+
+
+
+ +
+
+bonded_inter
+

object +espressomd.interactions.BondedInteractions

+
+
Type
+

bonded_inter

+
+
+
+ +
+
+box_l
+

(3,) array_like of float: +Dimensions of the simulation box

+
+ +
+
+cell_system
+

object +espressomd.cell_system.CellSystem

+
+
Type
+

cell_system

+
+
+
+ +
+
+change_volume_and_rescale_particles(self, d_new, dir='xyz')
+

Change box size and rescale particle coordinates.

+
+
Parameters
+
    +
  • d_new (float) – New box length

  • +
  • dir (str, optional) – Coordinate to work on, "x", "y", "z" or "xyz" for isotropic. +Isotropic assumes a cubic box.

  • +
+
+
+
+ +
+
+collision_detection
+

object +espressomd.collision_detection.CollisionDetection

+
+
Type
+

collision_detection

+
+
+
+ +
+
+comfixed
+

object +espressomd.comfixed.ComFixed

+
+
Type
+

comfixed

+
+
+
+ +
+
+constraints
+

object +espressomd.constraints.Constraints

+
+
Type
+

constraints

+
+
+
+ +
+
+cuda_init_handle
+

object +espressomd.cuda_init.CudaInitHandle

+
+
Type
+

cuda_init_handle

+
+
+
+ +
+
+distance(self, p1, p2)
+

Return the scalar distance between particles, between a particle +and a point or between two points, respecting periodic boundaries.

+
+
Parameters
+
    +
  • p1 (ParticleHandle or (3,) array of float) – First particle or position.

  • +
  • p2 (ParticleHandle or (3,) array of float) – Second particle or position.

  • +
+
+
+
+ +
+
+distance_vec(self, p1, p2)
+

Return the distance vector between particles, between a particle +and a point or between two points, respecting periodic boundaries.

+
+
Parameters
+
    +
  • p1 (ParticleHandle or (3,) array of float) – First particle or position.

  • +
  • p2 (ParticleHandle or (3,) array of float) – Second particle or position.

  • +
+
+
+
+ +
+
+ekboundaries
+

object +espressomd.ekboundaries.EKBoundaries

+
+
Type
+

ekboundaries

+
+
+
+ +
+
+force_cap
+

float: +If > 0, the magnitude of the force on the particles +are capped to this value.

+
+ +
+
+galilei
+

object +espressomd.galilei.GalileiTransform

+
+
Type
+

galilei

+
+
+
+ +
+
+integrator
+

object +espressomd.integrate.IntegratorHandle

+
+
Type
+

integrator

+
+
+
+ +
+
+lbboundaries
+

object +espressomd.lbboundaries.LBBoundaries

+
+
Type
+

lbboundaries

+
+
+
+ +
+
+lees_edwards
+

object +espressomd.lees_edwards.LeesEdwards

+
+
Type
+

lees_edwards

+
+
+
+ +
+
+max_cut_bonded
+
+ +
+
+max_cut_nonbonded
+
+ +
+
+max_oif_objects
+

Maximum number of objects as per the object_in_fluid method.

+
+ +
+
+min_global_cut
+
+ +
+
+non_bonded_inter
+

object +espressomd.interactions.NonBondedInteractions

+
+
Type
+

non_bonded_inter

+
+
+
+ +
+
+number_of_particles(self, type=None)
+
+
Parameters
+

type (int (type)) – Particle type to count the number for.

+
+
Returns
+

The number of particles which have the given type.

+
+
Return type
+

int

+
+
Raises
+

RuntimeError – If the particle type is not currently tracked by the system. + To select which particle types are tracked, call setup_type_map().

+
+
+
+ +
+
+part
+

object +espressomd.particle_data.ParticleList

+
+
Type
+

part

+
+
+
+ +
+
+periodicity
+

(3,) array_like of bool: +System periodicity in [x, y, z], False for no periodicity +in this direction, True for periodicity

+
+ +
+
+rotate_system(self, **kwargs)
+

Rotate the particles in the system about the center of mass.

+

If ROTATION is activated, the internal rotation degrees of +freedom are rotated accordingly.

+
+
Parameters
+
    +
  • phi (float) – Angle between the z-axis and the rotation axis.

  • +
  • theta (float) – Rotation of the axis around the y-axis.

  • +
  • alpha (float) – How much to rotate

  • +
+
+
+
+ +
+
+setup_type_map(self, type_list=None)
+

For using ESPResSo conveniently for simulations in the grand canonical +ensemble, or other purposes, when particles of certain types are created +and deleted frequently. Particle ids can be stored in lists for each +individual type and so random ids of particles of a certain type can be +drawn. If you want ESPResSo to keep track of particle ids of a certain type +you have to initialize the method by calling the setup function. After that +ESPResSo will keep track of particle ids of that type.

+
+ +
+
+thermostat
+

object +espressomd.thermostat.Thermostat

+
+
Type
+

thermostat

+
+
+
+ +
+
+time
+

Set the time in the simulation.

+
+ +
+
+time_step
+

Set the time step for the integrator.

+
+ +
+
+velocity_difference(self, p1, p2)
+

Return the velocity difference between two particles, +considering Lees-Edwards boundary conditions, if active.

+
+
Parameters
+
+
+
+
+ +
+
+virtual_sites
+

Set the virtual site implementation.

+

Requires feature VIRTUAL_SITES.

+
+ +
+
+volume(self)
+

Return box volume of the cuboid box.

+
+ +
+ +
+
+

espressomd.thermostat module

+
+
+espressomd.thermostat.AssertThermostatType(*allowedthermostats)
+

Assert that only a certain group of thermostats is active at a time.

+

Decorator class to ensure that only specific combinations of thermostats +can be activated together by the user. Usage:

+
cdef class Thermostat:
+    @AssertThermostatType(THERMO_LANGEVIN, THERMO_DPD)
+    def set_langevin(self, kT=None, gamma=None, gamma_rotation=None,
+             act_on_virtual=False, seed=None):
+        ...
+
+
+

This will prefix an assertion that prevents setting up the Langevin +thermostat if the list of active thermostats contains anything other +than the DPD and Langevin thermostats.

+
+
Parameters
+

allowedthermostats (str) – Allowed list of thermostats which are known to be compatible +with one another.

+
+
+
+ +
+
+class espressomd.thermostat.Thermostat
+

Bases: object

+
+
+get_state(self)
+

Returns the thermostat status.

+
+ +
+
+get_ts(self)
+
+ +
+
+recover(self)
+

Recover a suspended thermostat

+

If the thermostat had been suspended using suspend(), it can +be recovered with this method.

+
+ +
+
+set_brownian(self, kT, gamma, gamma_rotation=None, act_on_virtual=False, seed=None)
+

Sets the Brownian thermostat.

+
+
Parameters
+
    +
  • kT (float) – Thermal energy of the simulated heat bath.

  • +
  • gamma (float) – Contains the friction coefficient of the bath. If the feature +PARTICLE_ANISOTROPY is compiled in, then gamma can be a list +of three positive floats, for the friction coefficient in each +cardinal direction.

  • +
  • gamma_rotation (float, optional) – The same applies to gamma_rotation, which requires the feature +ROTATION to work properly. But also accepts three floats +if PARTICLE_ANISOTROPY is also compiled in.

  • +
  • seed (int) – Initial counter value (or seed) of the philox RNG. +Required on first activation of the Brownian thermostat. +Must be positive.

  • +
+
+
+
+ +
+
+set_dpd(self, kT, seed=None)
+

Sets the DPD thermostat with required parameters ‘kT’. +This also activates the DPD interactions.

+
+
Parameters
+
    +
  • kT (float) – Thermal energy of the heat bath.

  • +
  • seed (int) – Initial counter value (or seed) of the philox RNG. +Required on first activation of the DPD thermostat. +Must be positive.

  • +
+
+
+
+ +
+
+set_langevin(self, kT, gamma, gamma_rotation=None, act_on_virtual=False, seed=None)
+

Sets the Langevin thermostat.

+
+
Parameters
+
    +
  • kT (float) – Thermal energy of the simulated heat bath.

  • +
  • gamma (float) – Contains the friction coefficient of the bath. If the feature +PARTICLE_ANISOTROPY is compiled in, then gamma can be a list +of three positive floats, for the friction coefficient in each +cardinal direction.

  • +
  • gamma_rotation (float, optional) – The same applies to gamma_rotation, which requires the feature +ROTATION to work properly. But also accepts three floats +if PARTICLE_ANISOTROPY is also compiled in.

  • +
  • act_on_virtual (bool, optional) – If True the thermostat will act on virtual sites, default is +False.

  • +
  • seed (int) – Initial counter value (or seed) of the philox RNG. +Required on first activation of the Langevin thermostat. +Must be positive.

  • +
+
+
+
+ +
+
+set_lb(self, seed=None, act_on_virtual=True, LB_fluid=None, gamma=0.0)
+

Sets the LB thermostat.

+

This thermostat requires the feature LBFluid or LBFluidGPU.

+
+
Parameters
+
    +
  • LB_fluid (LBFluid or LBFluidGPU)

  • +
  • seed (int) – Seed for the random number generator, required if kT > 0. +Must be positive.

  • +
  • act_on_virtual (bool, optional) – If True the thermostat will act on virtual sites (default).

  • +
  • gamma (float) – Frictional coupling constant for the MD particle coupling.

  • +
+
+
+
+ +
+
+set_npt(self, kT, gamma0, gammav, seed=None)
+

Sets the NPT thermostat.

+
+
Parameters
+
    +
  • kT (float) – Thermal energy of the heat bath

  • +
  • gamma0 (float) – Friction coefficient of the bath

  • +
  • gammav (float) – Artificial friction coefficient for the volume fluctuations.

  • +
  • seed (int) – Initial counter value (or seed) of the philox RNG. +Required on first activation of the Langevin thermostat. +Must be positive.

  • +
+
+
+
+ +
+
+set_stokesian(self, kT=None, seed=None)
+

Sets the SD thermostat with required parameters.

+

This thermostat requires the feature STOKESIAN_DYNAMICS.

+
+
Parameters
+
    +
  • kT (float, optional) – Temperature.

  • +
  • seed (int, optional) – Seed for the random number generator

  • +
+
+
+
+ +
+
+suspend(self)
+

Suspend the thermostat

+

The thermostat can be suspended, e.g. to perform an energy +minimization.

+
+ +
+
+turn_off(self)
+

Turns off all the thermostat and sets all the thermostat variables to zero.

+
+ +
+ +
+
+

espressomd.utils module

+
+
+class espressomd.utils.array_locked(input_array)
+

Bases: numpy.ndarray

+

Returns a non-writable numpy.ndarray with a special error message upon usage +of __setitem__ or in-place operators. Cast return in __get__ of array +properties to array_locked to prevent these operations.

+
+
+ERR_MSG = 'ESPResSo array properties return non-writable arrays and can only be modified as a whole, not in-place or component-wise. Use numpy.copy(<ESPResSo array property>) to get a writable copy.'
+
+ +
+ +
+
+espressomd.utils.check_array_type_or_throw_except(x, n, t, msg)
+

Check that x is of type t and that n values are given, +otherwise raise a ValueError with message msg. +Integers are accepted when a float was asked for.

+
+ +
+
+espressomd.utils.check_required_keys(required_keys, obtained_keys)
+
+ +
+
+espressomd.utils.check_type_or_throw_except(x, n, t, msg)
+

Check that x is of type t and that n values are given, +otherwise raise a ValueError with message msg. If x is an +array/list/tuple, the type checking is done on the elements, and all +elements are checked. If n is 1, x is assumed to be a scalar. +Integers are accepted when a float was asked for.

+
+ +
+
+espressomd.utils.check_valid_keys(valid_keys, obtained_keys)
+
+ +
+
+espressomd.utils.handle_errors(msg)
+

Gathers runtime errors.

+
+
Parameters
+

msg (str) – Error message that is to be raised.

+
+
+
+ +
+
+espressomd.utils.is_valid_type(value, t)
+

Extended checks for numpy int, float and bool types. +Handles 0-dimensional arrays.

+
+ +
+
+espressomd.utils.nesting_level(obj)
+

Returns the maximal nesting level of an object.

+
+ +
+
+espressomd.utils.to_char_pointer(s)
+

Returns a char pointer which contains the information of the provided python string.

+
+
Parameters
+

s (str)

+
+
+
+ +
+
+espressomd.utils.to_str(s)
+

Returns a python string.

+
+
Parameters
+

s (char*)

+
+
+
+ +
+
+

espressomd.version module

+
+
+espressomd.version.friendly()
+

Dot version of the version.

+
+ +
+
+espressomd.version.git_branch()
+

Git branch of the build if known, otherwise +empty.

+
+ +
+
+espressomd.version.git_commit()
+

Git commit of the build if known, otherwise +empty.

+
+ +
+
+espressomd.version.git_state()
+

Git state of the build if known, otherwise +empty. State is “CLEAN” if the repository +was not changed from git_commit(), +“DIRTY” otherwise.

+
+ +
+
+espressomd.version.major()
+

Prints the major version of ESPResSo.

+
+ +
+
+espressomd.version.minor()
+

Prints the minor version of ESPResSo.

+
+ +
+
+

espressomd.virtual_sites module

+
+
+class espressomd.virtual_sites.ActiveVirtualSitesHandle(**kwargs)[source]
+

Bases: espressomd.script_interface.ScriptInterfaceHelper

+

Handle for the virtual sites implementation active in the core

+

This should not be used directly.

+
+
+have_quaternion
+

Whether the virtual sites has a quaternion (only relevant for +VirtualSitesRelative).

+
+
Type
+

bool

+
+
+
+ +
+
+override_cutoff_check
+

Whether to disable the sanity check that triggers when attempting +to set up a virtual site too far away from the real particle in a +MPI-parallel simulation with more than 1 core. Disabling this +check is not recommended; it is only relevant in rare situations +when using the Hybrid decomposition cell system.

+
+
Type
+

bool

+
+
+
+ +
+ +
+
+class espressomd.virtual_sites.VirtualSitesInertialessTracers(**kwargs)[source]
+

Bases: espressomd.script_interface.ScriptInterfaceHelper

+

Virtual sites which are advected with an LB fluid without inertia. +Forces are on them are transferred to the fluid instantly.

+
+ +
+
+class espressomd.virtual_sites.VirtualSitesOff(**kwargs)[source]
+

Bases: espressomd.script_interface.ScriptInterfaceHelper

+

Virtual sites implementation which does nothing (default)

+
+ +
+
+class espressomd.virtual_sites.VirtualSitesRelative(**kwargs)[source]
+

Bases: espressomd.script_interface.ScriptInterfaceHelper

+

Virtual sites implementation placing virtual sites relative to other +particles. See Rigid arrangements of particles for details.

+
+ +
+
+

espressomd.visualization module

+
+
+class espressomd.visualization.Camera(cam_pos=array([0, 0, 1]), cam_target=array([0, 0, 0]), cam_right=array([1., 0., 0.]), move_speed=0.5, global_rot_speed=3.0, center=array([0, 0, 0]))[source]
+

Bases: object

+
+
+get_camera_rotation_matrix(target_vec, up_vec)[source]
+
+ +
+
+move_backward()[source]
+
+ +
+
+move_down()[source]
+
+ +
+
+move_forward()[source]
+
+ +
+
+move_left()[source]
+
+ +
+
+move_right()[source]
+
+ +
+
+move_up()[source]
+
+ +
+
+rotate_camera(mouse_pos, mouse_pos_old, mouse_button_state)[source]
+
+ +
+
+rotate_system_XL()[source]
+
+ +
+
+rotate_system_XR()[source]
+
+ +
+
+rotate_system_YL()[source]
+
+ +
+
+rotate_system_YR()[source]
+
+ +
+
+rotate_system_ZL()[source]
+
+ +
+
+rotate_system_ZR()[source]
+
+ +
+
+rotate_system_x(angle)[source]
+
+ +
+
+rotate_system_y(angle)[source]
+
+ +
+
+rotate_system_z(angle)[source]
+
+ +
+
+rotate_vector(vector, phi, axis)[source]
+

Rotate vector around (unit vector) axis by angle phi. +Uses Rodrigues’ rotation formula.

+
+ +
+
+update_modelview()[source]
+
+ +
+ +
+
+class espressomd.visualization.Cylinder(shape, particle_type, color, material, quality, box_l, rasterize_resolution, rasterize_pointsize)[source]
+

Bases: espressomd.visualization.Shape

+

Drawable Shape Cylinder.

+
+
+draw()[source]
+

Draw shape via rasterization. Used as a default draw method. +Can and should be overwritten in child classes to implement a better +draw method.

+
+ +
+ +
+
+class espressomd.visualization.Ellipsoid(shape, particle_type, color, material, quality, box_l, rasterize_resolution, rasterize_pointsize)[source]
+

Bases: espressomd.visualization.Shape

+

Drawable Shape Ellipsoid.

+
+
+draw()[source]
+

Draw shape via rasterization. Used as a default draw method. +Can and should be overwritten in child classes to implement a better +draw method.

+
+ +
+ +
+
+class espressomd.visualization.HollowConicalFrustum(shape, particle_type, color, material, quality, box_l, rasterize_resolution, rasterize_pointsize)[source]
+

Bases: espressomd.visualization.Shape

+

Drawable Shape HollowConicalFrustum.

+
+
+draw()[source]
+

Draw using OpenGL Extrusion library, if available. +Use rasterization of base class, otherwise.

+
+ +
+ +
+
+class espressomd.visualization.KeyboardButtonEvent(button, fireEvent, callback, internal=False)[source]
+

Bases: object

+

Keyboard event used for keyboard callbacks. Stores button, event type and callback.

+
+ +
+
+class espressomd.visualization.KeyboardFireEvent[source]
+

Bases: object

+

Event type of button used for keyboard callbacks.

+
+
+Hold = 1
+
+ +
+
+Pressed = 0
+
+ +
+
+Released = 2
+
+ +
+ +
+
+class espressomd.visualization.KeyboardManager[source]
+

Bases: object

+

Handles keyboard callbacks.

+
+
+callback_on_button(be, b)[source]
+
+ +
+
+handle_input()[source]
+
+ +
+
+keyboard_down(button)[source]
+
+ +
+
+keyboard_up(button)[source]
+
+ +
+
+register_button(buttonEvent)[source]
+

Register keyboard input callbacks.

+
+ +
+ +
+
+class espressomd.visualization.MouseButtonEvent(button, fireEvent, callback, positional=False)[source]
+

Bases: object

+

Mouse event used for mouse callbacks. Stores button and callback.

+
+ +
+
+class espressomd.visualization.MouseFireEvent[source]
+

Bases: object

+

Event type of mouse button used for mouse callbacks.

+
+
+ButtonMotion = 2
+
+ +
+
+ButtonPressed = 0
+
+ +
+
+ButtonReleased = 3
+
+ +
+
+DoubleClick = 4
+
+ +
+
+FreeMotion = 1
+
+ +
+ +
+
+class espressomd.visualization.MouseManager[source]
+

Bases: object

+

Handles mouse callbacks.

+
+
+mouse_click(button, state, x, y)[source]
+
+ +
+
+mouse_move(x, y)[source]
+
+ +
+
+register_button(mouseEvent)[source]
+

Register mouse input callbacks.

+
+ +
+ +
+
+class espressomd.visualization.Shape(shape, particle_type, color, material, quality, box_l, rasterize_resolution, rasterize_pointsize)[source]
+

Bases: object

+

Shape base class in the visualizer context.

+
+
+draw()[source]
+

Draw shape via rasterization. Used as a default draw method. +Can and should be overwritten in child classes to implement a better +draw method.

+
+ +
+ +
+
+class espressomd.visualization.SimplePore(shape, particle_type, color, material, quality, box_l, rasterize_resolution, rasterize_pointsize)[source]
+

Bases: espressomd.visualization.Shape

+

Drawable Shape SimplePore.

+
+
+draw()[source]
+

Draw using OpenGL Extrusion library, if available. +Use OpenGL primitives + clip planes, otherwise.

+
+ +
+ +
+
+class espressomd.visualization.Slitpore(shape, particle_type, color, material, quality, box_l, rasterize_resolution, rasterize_pointsize)[source]
+

Bases: espressomd.visualization.Shape

+

Drawable Shape Slitpore.

+
+
+draw()[source]
+

Draw shape via rasterization. Used as a default draw method. +Can and should be overwritten in child classes to implement a better +draw method.

+
+ +
+ +
+
+class espressomd.visualization.Sphere(shape, particle_type, color, material, quality, box_l, rasterize_resolution, rasterize_pointsize)[source]
+

Bases: espressomd.visualization.Shape

+

Drawable Shape Sphere.

+
+
+draw()[source]
+

Draw shape via rasterization. Used as a default draw method. +Can and should be overwritten in child classes to implement a better +draw method.

+
+ +
+ +
+
+class espressomd.visualization.Spherocylinder(shape, particle_type, color, material, quality, box_l, rasterize_resolution, rasterize_pointsize)[source]
+

Bases: espressomd.visualization.Shape

+

Drawable Shape Spherocylinder.

+
+
+draw()[source]
+

Draw shape via rasterization. Used as a default draw method. +Can and should be overwritten in child classes to implement a better +draw method.

+
+ +
+ +
+
+class espressomd.visualization.Wall(shape, particle_type, color, material, quality, box_l, rasterize_resolution, rasterize_pointsize)[source]
+

Bases: espressomd.visualization.Shape

+

Drawable Shape Wall.

+
+
+draw()[source]
+

Draw shape via rasterization. Used as a default draw method. +Can and should be overwritten in child classes to implement a better +draw method.

+
+ +
+ +
+
+espressomd.visualization.draw_arrow(pos, d, radius, color, material, quality)[source]
+
+ +
+
+espressomd.visualization.draw_box(p0, s, color, material, width)[source]
+
+ +
+
+espressomd.visualization.draw_cylinder(posA, posB, radius, color, material, quality, draw_caps=False)[source]
+
+ +
+
+espressomd.visualization.draw_plane(corners, color, material)[source]
+
+ +
+
+espressomd.visualization.get_extra_clip_plane()[source]
+
+ +
+
+class espressomd.visualization.openGLLive(system, **kwargs)[source]
+

Bases: object

+

This class provides live visualization using pyOpenGL. +Use the update method to push your current simulation state after +integrating. Modify the appearance with a list of keywords. +Timed callbacks can be registered via the register_callback() method +and keyboard callbacks via keyboard_manager.register_button().

+
+
Parameters
+
    +
  • system (espressomd.system.System)

  • +
  • window_size ((2,) array_like of int, optional) – Size of the visualizer window in pixels.

  • +
  • name (str, optional) – The name of the visualizer window.

  • +
  • background_color ((3,) array_like of float, optional) – RGB of the background.

  • +
  • periodic_images ((3,) array_like of int, optional) – Periodic repetitions on both sides of the box in xyz-direction.

  • +
  • draw_box (bool, optional) – Draw wireframe boundaries.

  • +
  • draw_axis (bool, optional) – Draw xyz system axes.

  • +
  • draw_nodes (bool, optional) – Draw node boxes.

  • +
  • draw_cells (bool, optional) – Draw cell boxes.

  • +
  • quality_particles (int, optional) – The number of subdivisions for particle spheres.

  • +
  • quality_bonds (int, optional) – The number of subdivisions for cylindrical bonds.

  • +
  • quality_arrows (int, optional) – The number of subdivisions for external force arrows.

  • +
  • quality_constraints (int, optional) – The number of subdivisions for primitive constraints.

  • +
  • close_cut_distance (float, optional) – The distance from the viewer to the near clipping plane.

  • +
  • far_cut_distance (float, optional) – The distance from the viewer to the far clipping plane.

  • +
  • camera_position (str or (3,) array_like of float, optional) – Initial camera position. Use 'auto' (default) for shifted position in z-direction.

  • +
  • camera_target (str or (3,) array_like of float, optional) – Initial camera target. Use 'auto' (default) to look towards the system center.

  • +
  • camera_right ((3,) array_like of float, optional) – Camera right vector in system coordinates. Default is [1, 0, 0]

  • +
  • particle_sizes (str or array_like of float or callable, optional) –

    +
      +
    • 'auto' (default): The Lennard-Jones sigma value of the +self-interaction is used for the particle diameter.

    • +
    • callable: A lambda function with one argument. Internally, +the numerical particle type is passed to the lambda +function to determine the particle radius.

    • +
    • list: A list of particle radii, indexed by the particle type.

    • +
    +
  • +
  • particle_coloring (str, optional) –

    +
      +
    • 'auto' (default): Colors of charged particles are +specified by particle_charge_colors, neutral particles +by particle_type_colors.

    • +
    • 'charge': Minimum and maximum charge of all particles is determined by the +visualizer. All particles are colored by a linear +interpolation of the two colors given by +particle_charge_colors according to their charge.

    • +
    • 'type': Particle colors are specified by particle_type_colors, +indexed by their numerical particle type.

    • +
    • 'node': Color according to the node the particle is on.

    • +
    +
  • +
  • particle_type_colors (array_like of float, optional) – Colors for particle types.

  • +
  • particle_type_materials (array_like of str, optional) – Materials of the particle types.

  • +
  • particle_charge_colors ((2,) array_like of float, optional) – Two colors for min/max charged particles.

  • +
  • draw_constraints (bool, optional) – Enables constraint visualization. For simple constraints +(planes, spheres and cylinders), OpenGL primitives are +used. Otherwise, visualization by rasterization is used.

  • +
  • rasterize_pointsize (float, optional) – Point size for the rasterization dots.

  • +
  • rasterize_resolution (float, optional) – Accuracy of the rasterization.

  • +
  • quality_constraints (int, optional) – The number of subdivisions for primitive constraints.

  • +
  • constraint_type_colors (array_like of float, optional) – Colors of the constraints by type.

  • +
  • constraint_type_materials (array_like of str, optional) – Materials of the constraints by type.

  • +
  • draw_bonds (bool, optional) – Enables bond visualization.

  • +
  • bond_type_radius (array_like of float, optional) – Radii of bonds by type.

  • +
  • bond_type_colors (array_like of float, optional) – Color of bonds by type.

  • +
  • bond_type_materials (array_like of str, optional) – Materials of bonds by type.

  • +
  • ext_force_arrows (bool, optional) – Enables external force visualization.

  • +
  • ext_force_arrows_type_scale (array_like of float, optional) – List of scale factors of external force arrows for different particle types.

  • +
  • ext_force_arrows_type_colors (array_like of float, optional) – Colors of ext_force arrows for different particle types.

  • +
  • ext_force_arrows_type_materials (array_like of str, optional) – Materials of ext_force arrows for different particle types.

  • +
  • ext_force_arrows_type_radii (array_like of float, optional) – List of arrow radii for different particle types.

  • +
  • force_arrows (bool, optional) – Enables particle force visualization.

  • +
  • force_arrows_type_scale (array_like of float, optional) – List of scale factors of particle force arrows for different particle types.

  • +
  • force_arrows_type_colors (array_like of float, optional) – Colors of particle force arrows for different particle types.

  • +
  • force_arrows_type_materials (array_like of str, optional) – Materials of particle force arrows for different particle types.

  • +
  • force_arrows_type_radii (array_like of float, optional) – List of arrow radii for different particle types.

  • +
  • velocity_arrows (bool, optional) – Enables particle velocity visualization.

  • +
  • velocity_arrows_type_scale (array_like of float, optional) – List of scale factors of particle velocity arrows for different particle types.

  • +
  • velocity_arrows_type_colors (array_like of float, optional) – Colors of particle velocity arrows for different particle types.

  • +
  • velocity_arrows_type_materials (array_like of str, optional) – Materials of particle velocity arrows for different particle types.

  • +
  • velocity_arrows_type_radii (array_like of float, optional) – List of arrow radii for different particle types.

  • +
  • director_arrows (bool, optional) – Enables particle director visualization.

  • +
  • director_arrows_type_scale (float, optional) – Scale factor of particle director arrows for different particle types.

  • +
  • director_arrows_type_colors (array_like of float, optional) – Colors of particle director arrows for different particle types.

  • +
  • director_arrows_type_materials (array_like of str, optional) – Materials of particle director arrows for different particle types.

  • +
  • director_arrows_type_radii (array_like of float, optional) – List of arrow radii for different particle types.

  • +
  • drag_enabled (bool, optional) – Enables mouse-controlled particles dragging (Default: False)

  • +
  • drag_force (bool, optional) – Factor for particle dragging

  • +
  • LB_draw_nodes (bool, optional) – Draws a lattice representation of the LB nodes that are no boundaries.

  • +
  • LB_draw_node_boundaries (bool, optional) – Draws a lattice representation of the LB nodes that are boundaries.

  • +
  • LB_draw_boundaries (bool, optional) – Draws the LB shapes.

  • +
  • LB_draw_velocity_plane (bool, optional) – Draws LB node velocity arrows in a plane perpendicular to the axis in +LB_plane_axis, at a distance LB_plane_dist from the origin, +every LB_plane_ngrid grid points.

  • +
  • LB_plane_axis (int, optional) – LB node velocity arrows are drawn in a plane perpendicular to the +x, y, or z axes, which are encoded by values 0, 1, or 2 respectively.

  • +
  • LB_plane_dist (float, optional) – LB node velocity arrows are drawn in a plane perpendicular to the +x, y, or z axes, at a distance LB_plane_dist from the origin.

  • +
  • LB_plane_ngrid (int, optional) – LB node velocity arrows are drawn in a plane perpendicular to the +x, y, or z axes, every LB_plane_ngrid grid points.

  • +
  • LB_vel_scale (float, optional) – Rescale LB node velocity arrow length.

  • +
  • LB_vel_radius_scale (float, optional) – Rescale LB node velocity arrow radii.

  • +
  • LB_arrow_color ((3,) array_like of float, optional) – RGB of the LB velocity arrows.

  • +
  • LB_arrow_material (str, optional) – Material of LB arrows.

  • +
  • quality_constraints (int, optional) – The number of subdivisions for LB arrows.

  • +
  • light_pos ((3,) array_like of float, optional) – If auto (default) is used, the light is placed dynamically in +the particle barycenter of the system. Otherwise, a fixed +coordinate can be set.

  • +
  • light_colors (array_like of float, optional) – Three lists to specify ambient, diffuse and specular light colors.

  • +
  • light_brightness (float, optional) – Brightness (inverse constant attenuation) of the light.

  • +
  • light_size (float, optional) – Size (inverse linear attenuation) of the light. If auto +(default) is used, the light size will be set to a reasonable +value according to the box size at start.

  • +
  • spotlight_enabled (bool, optional) – If set to True (default), it enables a spotlight on the +camera position pointing in look direction.

  • +
  • spotlight_colors (array_like of float, optional) – Three lists to specify ambient, diffuse and specular spotlight colors.

  • +
  • spotlight_angle (float, optional) – The spread angle of the spotlight in degrees (from 0 to 90).

  • +
  • spotlight_brightness (float, optional) – Brightness (inverse constant attenuation) of the spotlight.

  • +
  • spotlight_focus (float, optional) – Focus (spot exponent) for the spotlight from 0 (uniform) to 128.

  • +
+
+
+

Notes

+

The visualization of some constraints is either improved by or even relies +on the presence of an installed OpenGL Extrusion library on your system.

+
+
+materials = {'bright': [0.9, 1.0, 0.8, 0.4, 1.0], 'chrome': [0.25, 0.4, 0.774597, 0.6, 1.0], 'dark': [0.4, 0.5, 0.1, 0.4, 1.0], 'medium': [0.6, 0.8, 0.2, 0.4, 1.0], 'plastic': [0, 0.55, 0.7, 0.25, 1.0], 'rubber': [0, 0.4, 0.7, 0.078125, 1.0], 'steel': [0.25, 0.38, 0, 0.32, 1.0], 'transparent1': [0.6, 0.8, 0.2, 0.5, 0.8], 'transparent2': [0.6, 0.8, 0.2, 0.5, 0.4], 'transparent3': [0.6, 0.8, 0.2, 0.5, 0.2]}
+
+ +
+
+register_callback(cb, interval=1000)[source]
+

Register timed callbacks.

+
+ +
+
+run(integration_steps=1)[source]
+

Convenience method with a simple integration thread.

+
+ +
+
+screenshot(path)[source]
+

Renders the current state into an image file at path with +dimensions of specs['window_size'] in PNG format.

+
+ +
+
+start()[source]
+

The blocking start method.

+
+ +
+
+update()[source]
+

Update method to be called after integration. +Changes of ESPResSo system can only happen here.

+
+ +
+
+update_system_info()[source]
+

Update the information stored in dict self.system_info.

+

The dictionary is used for showing system information, such as particle +or constraint information, in the visualizer window.

+
+ +
+ +
+
+espressomd.visualization.rotation_helper(d)[source]
+
+ +
+
+espressomd.visualization.set_solid_material(color, material=(0.6, 1.0, 0.1, 0.4, 1.0))[source]
+
+ +
+
+

Module contents

+
+
+exception espressomd.FeaturesError(missing_features)[source]
+

Bases: Exception

+
+ +
+
+espressomd.assert_features(*args)[source]
+

Raise an exception when a list of features is not a subset of the +compiled-in features.

+
+ +
+
+espressomd.has_features(*args)[source]
+

Check whether a list of features is a subset of the compiled-in features.

+
+ +
+
+espressomd.missing_features(*args)[source]
+

Return a list of the missing features in the arguments.

+
+ +
+
+ + +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/doc4.2.2/espressomd.io.html b/doc4.2.2/espressomd.io.html new file mode 100644 index 0000000000..631383a5d4 --- /dev/null +++ b/doc4.2.2/espressomd.io.html @@ -0,0 +1,169 @@ + + + + + + + + + espressomd.io package — ESPResSo 4.2.2 documentation + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +
+

espressomd.io package

+
+

Subpackages

+ +
+
+

Submodules

+
+
+

espressomd.io.mpiio module

+
+
+class espressomd.io.mpiio.Mpiio(**kwargs)[source]
+

Bases: espressomd.script_interface.ScriptInterfaceHelper

+

MPI-IO object.

+

Used to output particle data using MPI-IO to binary files.

+
+
+read(prefix=None, positions=False, velocities=False, types=False, bonds=False)[source]
+

MPI-IO read.

+

This function reads data dumped by :meth`write`. See the :meth`write` +documentation for details.

+
+

Note

+

The files must be read on the same number of processes that wrote +the data. The data must be read on a machine with the same +architecture (otherwise, this might silently fail).

+
+
+ +
+
+write(prefix=None, positions=False, velocities=False, types=False, bonds=False)[source]
+

MPI-IO write.

+

Outputs binary data using MPI-IO to several files starting with prefix. +Suffixes are:

+
    +
  • head: Information about fields that are dumped,

  • +
  • pref: Information about processes: 1 int per process,

  • +
  • id: Particle ids: 1 int per particle,

  • +
  • pos: Position information (if dumped): 3 doubles per particle,

  • +
  • vel: Velocity information (if dumped): 3 doubles per particle,

  • +
  • typ: Type information (if dumped): 1 int per particle,

  • +
  • bond: Bond information (if dumped): variable amount of data,

  • +
  • boff: Bond offset information (if bonds are dumped): 1 int per particle.

  • +
+
+

Note

+

Do not read the files on a machine with a different architecture!

+
+
+
Parameters
+
    +
  • prefix (str) – Common prefix for the filenames.

  • +
  • positions (bool, optional) – Indicates if positions should be dumped.

  • +
  • velocities (bool, optional) – Indicates if velocities should be dumped.

  • +
  • types (bool, optional) – Indicates if types should be dumped.

  • +
  • bonds (bool, optional) – Indicates if bonds should be dumped.

  • +
+
+
Raises
+

ValueError – If no prefix was given or none of the output fields are chosen.

+
+
+
+ +
+ +
+
+

Module contents

+
+
+ + +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/doc4.2.2/espressomd.io.writer.html b/doc4.2.2/espressomd.io.writer.html new file mode 100644 index 0000000000..f50c052487 --- /dev/null +++ b/doc4.2.2/espressomd.io.writer.html @@ -0,0 +1,337 @@ + + + + + + + + + espressomd.io.writer package — ESPResSo 4.2.2 documentation + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +
+

espressomd.io.writer package

+
+

Submodules

+
+
+

espressomd.io.writer.h5md module

+
+
+class espressomd.io.writer.h5md.H5md(**kwargs)[source]
+

Bases: espressomd.script_interface.ScriptInterfaceHelper

+

H5md file object.

+
+

Note

+

Bonds will be written to the file if they exist. +The pypresso script will be written in the metadata.

+
+
+
Parameters
+
    +
  • file_path (str) – Path to the trajectory file, or an existing file to append data to +(it must have the same specifications).

  • +
  • unit_system (UnitSystem, optional) – Physical units for the data.

  • +
  • fields (set or str, optional) – List of fields to write to the trajectory file. Defaults to 'all'. +See valid_fields() for the +list of valid fields. This list defines the H5MD specifications. +If the file in file_path already exists but has different +specifications, an exception is raised.

  • +
+
+
+
+
+get_params()
+

Get the parameters from the script interface.

+
+ +
+
+valid_fields()
+

Get the list of valid fields.

+
+ +
+
+write()
+

Call the H5md write method.

+
+ +
+
+flush()
+

Call the H5md flush method.

+
+ +
+
+close()
+

Close the H5md file.

+
+ +
+
+file_path
+

Path to the trajectory file.

+
+
Type
+

str

+
+
+
+ +
+
+script_path
+

Path to the pypresso script, or empty string for interactive sessions.

+
+
Type
+

str

+
+
+
+ +
+
+fields
+

List of fields to write to the trajectory file.

+
+
Type
+

list

+
+
+
+ +
+
+mass_unit
+
+
Type
+

str

+
+
+
+ +
+
+length_unit
+
+
Type
+

str

+
+
+
+ +
+
+time_unit
+
+
Type
+

str

+
+
+
+ +
+
+force_unit
+
+
Type
+

str

+
+
+
+ +
+
+velocity_unit
+
+
Type
+

str

+
+
+
+ +
+
+charge_unit
+
+
Type
+

str

+
+
+
+ +
+
+default_params()[source]
+
+ +
+
+required_keys()[source]
+
+ +
+
+valid_keys()[source]
+
+ +
+
+validate_params(params)[source]
+

Check validity of given parameters.

+
+ +
+ +
+
+class espressomd.io.writer.h5md.UnitSystem(**kwargs)[source]
+

Bases: object

+

Data class for writing H5MD trajectories with +physical units. +There are four settable units: ‘mass’, ‘length’, ‘time’, ‘charge’. +Units should be written as strings following the specifications defined +here, +e.g. UnitSystem(time='ps', mass='u', length='nm', charge='e').

+
+ +
+
+

espressomd.io.writer.vtf module

+
+
+espressomd.io.writer.vtf.vtf_pid_map(system, types='all')[source]
+

Generates a VTF particle index map to ESPResSo id. +This fills the gap for particle ID’s as required by VMD.

+
+
Parameters
+
    +
  • system (espressomd.system.System)

  • +
  • types (str) – Specifies the particle types. The id mapping depends on which +particles are going to be printed. This should be the same as +the one used in writevsf() and writevcf().

  • +
+
+
Returns
+

A dictionary where the values are the VTF indices and the keys +are the ESPresSo particle id.

+
+
Return type
+

dict

+
+
+
+ +
+
+espressomd.io.writer.vtf.writevcf(system, fp, types='all')[source]
+

writes a VCF (VTF Coordinate Format) to a file. +This can be used to write a timestep to a VTF file.

+
+
Parameters
+
    +
  • system (espressomd.system.System)

  • +
  • types (str) – Specifies the particle types. The string ‘all’ will write all particles

  • +
  • fp (file) – File pointer to write to.

  • +
+
+
+
+ +
+
+espressomd.io.writer.vtf.writevsf(system, fp, types='all')[source]
+

writes a VST (VTF Structure Format) to a file. +This can be used to write the header of a VTF file.

+
+
Parameters
+
    +
  • system (espressomd.system.System)

  • +
  • types (str) – Specifies the particle types. The string ‘all’ will write all particles

  • +
  • fp (file) – File pointer to write to.

  • +
+
+
+
+ +
+
+

Module contents

+
+
+ + +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/doc4.2.2/genindex.html b/doc4.2.2/genindex.html new file mode 100644 index 0000000000..6d65c9a311 --- /dev/null +++ b/doc4.2.2/genindex.html @@ -0,0 +1,3209 @@ + + + + + + + + Index — ESPResSo 4.2.2 documentation + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ + +

Index

+ +
+ A + | B + | C + | D + | E + | F + | G + | H + | I + | K + | L + | M + | N + | O + | P + | Q + | R + | S + | T + | U + | V + | W + +
+

A

+ + + +
+ +

B

+ + + +
+ +

C

+ + + +
+ +

D

+ + + +
+ +

E

+ + + +
+ +

F

+ + + +
+ +

G

+ + + +
+ +

H

+ + + +
+ +

I

+ + + +
+ +

K

+ + + +
+ +

L

+ + + +
+ +

M

+ + + +
+ +

N

+ + + +
+ +

O

+ + + +
+ +

P

+ + + +
+ +

Q

+ + + +
+ +

R

+ + + +
+ +

S

+ + + +
+ +

T

+ + + +
+ +

U

+ + + +
+ +

V

+ + + +
+ +

W

+ + + +
+ + + +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/doc4.2.2/index.html b/doc4.2.2/index.html new file mode 100644 index 0000000000..0dbfba2705 --- /dev/null +++ b/doc4.2.2/index.html @@ -0,0 +1,144 @@ + + + + + + + + + ESPResSo documentation — ESPResSo 4.2.2 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/doc4.2.2/installation.html b/doc4.2.2/installation.html new file mode 100644 index 0000000000..86d3e68321 --- /dev/null +++ b/doc4.2.2/installation.html @@ -0,0 +1,921 @@ + + + + + + + + + 2. Installation — ESPResSo 4.2.2 documentation + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +
+

2. Installation

+

This chapter will describe how to get, compile and run the software.

+

ESPResSo releases are available as source code packages from the homepage 1. +This is where new users should get the code. The code within release packages +is tested and known to run on a number of platforms. +Alternatively, people who want to use the newest features of ESPResSo or +start contributing to the software can instead obtain the +current development code via the version control system software 2 +from ESPResSo’s project page at GitHub 3. This code might be not as well +tested and documented as the release code; it is recommended to use this +code only if you have already gained some experience in using ESPResSo.

+

Unlike most other software, no binary distributions of ESPResSo are available, +and the software is usually not installed globally for all users. +Instead, users of ESPResSo should compile the software themselves. The reason for +this is that it is possible to activate and deactivate various features +before compiling the code. Some of these features are not compatible +with each other, and some of the features have a profound impact on the +performance of the code. Therefore it is not possible to build a single +binary that can satisfy all needs. For performance reasons a user +should always activate only those features that are actually needed. +This means, however, that learning how to compile is a necessary evil. +The build system of ESPResSo uses CMake to compile +software easily on a wide range of platforms.

+
+

2.1. Requirements

+

The following tools and libraries, including their header files, +are required to be able to compile and use ESPResSo:

+
+
CMake

The build system is based on CMake version 3 or later 4.

+
+
C++ compiler

The C++ core of ESPResSo needs to be built by a C++14-capable compiler.

+
+
Boost

A number of advanced C++ features used by ESPResSo are provided by Boost. +We strongly recommend to use at least Boost 1.71.

+
+
FFTW

For some algorithms like P\(^3\)M, ESPResSo needs the FFTW library +version 3 or later 5 for Fourier transforms, including header files.

+
+
CUDA

For some algorithms like P\(^3\)M, +ESPResSo provides GPU-accelerated implementations for NVIDIA GPUs. +We strongly recommend CUDA 12.0 or later 6.

+
+
MPI

An MPI library that implements the MPI standard version 1.2 is required +to run simulations in parallel. ESPResSo is currently tested against +Open MPI and +MPICH, with and without +UCX enabled. +Other MPI implementations like Intel MPI should also work, although +they are not actively tested in ESPResSo continuous integration.

+

Open MPI version 4.x is known to not properly support the MCA binding +policy “numa” in singleton mode on a few NUMA architectures. +On affected systems, e.g. AMD Ryzen or AMD EPYC, Open MPI halts with +a fatal error when setting the processor affinity in MPI_Init. +This issue can be resolved by setting the environment variable +OMPI_MCA_hwloc_base_binding_policy to a value other than “numa”, +such as “l3cache” to bind to a NUMA shared memory block, or to +“none” to disable binding (can cause performance loss).

+
+
Python

ESPResSo’s main user interface relies on Python 3.

+

We strongly recommend using Python environments to isolate +packages required by ESPResSo from packages installed system-wide. +This can be achieved using venv 7, conda 8, or any similar tool. +Inside an environment, commands of the form +sudo apt install python3-numpy python3-scipy +can be rewritten as python3 -m pip install numpy scipy, +and thus do not require root privileges.

+

Depending on your needs, you may choose to install all ESPResSo +dependencies inside the environment, or only the subset of +dependencies not already satisfied by your workstation or cluster. +For the exact syntax to create and configure an environment, +please refer to the tool documentation.

+
+
Cython

Cython is used for connecting the C++ core to Python.

+

Python environment tools may allow you to install a Python executable +that is more recent than the system-wide Python executable. +Be aware this might lead to compatibility issues if Cython +accidentally picks up the system-wide Python.h header file. +In that scenario, you will have to manually adapt the C++ compiler +include paths to find the correct Python.h header file.

+
+
+
+

2.1.1. Installing requirements on Ubuntu Linux

+

To compile ESPResSo on Ubuntu 22.04 LTS, install the following dependencies:

+
sudo apt install build-essential cmake cython3 python3-dev openmpi-bin \
+  libboost-all-dev fftw3-dev libfftw3-mpi-dev libhdf5-dev libhdf5-openmpi-dev \
+  python3-pip python3-numpy python3-scipy python3-opengl libgsl-dev freeglut3
+
+
+

Optionally the ccmake utility can be installed for easier configuration:

+
sudo apt install cmake-curses-gui
+
+
+
+

2.1.1.1. Nvidia GPU acceleration

+

If your computer has an Nvidia graphics card, you should also download and install the +CUDA SDK to make use of GPU computation:

+
sudo apt install nvidia-cuda-toolkit
+
+
+

Later in the installation instructions, you will see CMake commands of the +form cmake .. with optional arguments, such as cmake .. -D WITH_CUDA=ON +to activate CUDA. These commands may need to be adapted depending on which +operating system and CUDA version you are using.

+

On Ubuntu 22.04, the default GCC compiler is too recent for nvcc and will fail +to compile sources that rely on std::function. You can either use GCC 10:

+
CC=gcc-10 CXX=g++-10 cmake .. -D WITH_CUDA=ON
+
+
+

or alternatively install Clang 12 as a replacement for nvcc and GCC:

+
CC=clang-12 CXX=clang++-12 cmake .. -D WITH_CUDA=ON -D WITH_CUDA_COMPILER=clang
+
+
+

On Ubuntu 20.04, the default GCC compiler is also too recent for nvcc and will +generate compiler errors. You can either install an older version of GCC and +select it with environment variables CC and CXX when building ESPResSo, +or edit the system header files as shown in the following +patch for Ubuntu 20.04.

+
+
+

2.1.1.2. Requirements for building the documentation

+

To generate the Sphinx documentation, install the following packages:

+
pip3 install --user -c requirements.txt \
+    sphinx sphinxcontrib-bibtex sphinx-toggleprompt
+
+
+

To generate the Doxygen documentation, install the following packages:

+
sudo apt install doxygen graphviz
+
+
+
+
+

2.1.1.3. Setting up a Jupyter environment

+

To run the samples and tutorials, start by installing the following packages:

+
sudo apt install python3-matplotlib python3-pint python3-tqdm ffmpeg
+pip3 install --user 'MDAnalysis>=1.0.0,<2.0.0'
+
+
+

The tutorials are written in the +Notebook Format +version <= 4.4 and can be executed by any of these tools:

+ +

To check whether one of them is installed, run these commands:

+
jupyter notebook --version
+jupyter lab --version
+ipython --version
+code --version
+
+
+

If you don’t have any of these tools installed and aren’t sure which one +to use, we recommend installing the historic Jupyter Notebook, since the +ESPResSo tutorials have been designed with the exercise2 plugin in mind.

+

To use Jupyter Notebook, install the following packages:

+
pip3 install --user 'nbformat==5.1.3' 'nbconvert==6.4.5' 'notebook==6.4.8' 'jupyter_contrib_nbextensions==0.5.1'
+jupyter contrib nbextension install --user
+jupyter nbextension enable rubberband/main
+jupyter nbextension enable exercise2/main
+
+
+

Alternatively, to use JupyterLab, install the following packages:

+
pip3 install --user nbformat notebook jupyterlab
+
+
+

Alternatively, to use VS Code Jupyter, install the following extensions:

+
code --install-extension ms-python.python
+code --install-extension ms-toolsai.jupyter
+code --install-extension ms-toolsai.jupyter-keymap
+code --install-extension ms-toolsai.jupyter-renderers
+
+
+
+
+
+

2.1.2. Installing requirements on other Linux distributions

+

Please refer to the following Dockerfiles to find the minimum set of packages +required to compile ESPResSo on other Linux distributions:

+ +
+
+

2.1.3. Installing requirements on Windows via WSL

+

To run ESPResSo on Windows, use the Linux subsystem. For that you need to

+ +
+
+

2.1.4. Installing requirements on macOS

+

To build ESPResSo on macOS 10.15 or higher, you need to install its dependencies. +There are two possibilities for this, MacPorts and Homebrew. We strongly +recommend Homebrew, but if you already have MacPorts installed, you can use +that too, although we do not provide MacPorts installation instructions.

+

To check whether you already have one or the other installed, run the +following commands:

+
test -e /opt/local/bin/port && echo "MacPorts is installed"
+test -e /usr/local/bin/brew && echo "Homebrew is installed"
+
+
+

If Homebrew is already installed, you should resolve any problems reported by +the command

+
brew doctor
+
+
+

If you want to install Homebrew, follow the installation instructions at +https://docs.brew.sh/Installation, but bear in mind that MacPorts and Homebrew +may conflict with one another.

+

If Anaconda Python or the Python from www.python.org are installed, you +will likely not be able to run ESPResSo. Therefore, please uninstall them +using the following commands:

+
sudo rm -r ~/anaconda[23]
+sudo rm -r /Library/Python
+
+
+
+

2.1.4.1. Installing packages using Homebrew

+

Run the following commands:

+
brew install cmake python cython boost boost-mpi fftw \
+  doxygen gsl numpy scipy ipython jupyter freeglut
+brew install hdf5-mpi
+brew link --force cython
+pip install -c requirements.txt PyOpenGL matplotlib
+
+
+
+
+
+
+

2.2. Quick installation

+

If you have installed the requirements (see section Requirements) in +standard locations, compiling ESPResSo is usually only a matter of creating a build +directory and calling cmake and make in it. See for example the command +lines below (optional steps which modify the build process are commented out):

+
mkdir build
+cd build
+cmake ..
+#ccmake . // in order to add/remove features like ScaFaCoS or CUDA
+make -j
+
+
+

This will build ESPResSo with a default feature set, namely +src/config/myconfig-default.hpp. This file is a C++ header file, +which defines the features that should be compiled in. +You may want to adjust the feature set to your needs. This can be easily +done by copying the myconfig-sample.hpp which has been created in +the build directory to myconfig.hpp and only uncomment +the features you want to use in your simulation.

+

The cmake command looks for libraries and tools needed by ESPResSo. +So ESPResSo can only be built if cmake reports no errors.

+

The command make will compile the source code. Depending on the +options passed to the program, make can also be used for a number of +other things:

+
    +
  • It can install and uninstall the program to some other directories. +However, normally it is not necessary to actually install to run +it: make install

  • +
  • It can invoke code checks: make check

  • +
  • It can build this documentation: make sphinx

  • +
+

When these steps have successfully completed, ESPResSo can be started with the +command:

+
./pypresso script.py
+
+
+

where script.py is a Python script which has to be written by the user. +You can find some examples in the samples folder of the source code +directory. If you want to run in parallel, you should have compiled with an +MPI library, and need to tell MPI to run in parallel. +The actual invocation is implementation-dependent, but in many cases, such as +Open MPI and MPICH, you can use

+
mpirun -n 4 ./pypresso script.py
+
+
+

where 4 is the number of processors to be used.

+
+
+

2.3. Features

+

This chapter describes the features that can be activated in ESPResSo. Even if +possible, it is not recommended to activate all features, because this +will negatively affect ESPResSo’s performance.

+

Features can be activated in the configuration header myconfig.hpp +(see section myconfig.hpp: Activating and deactivating features). +To activate FEATURE, add the following line to the header file:

+
#define FEATURE
+
+
+
+

2.3.1. General features

+
    +
  • ELECTROSTATICS This enables the use of the various electrostatics algorithms, such as P3M.

    +
    +

    See also

    +

    Electrostatics

    +
    +
  • +
  • MMM1D_GPU: This enables MMM1D on GPU. It is faster than the CPU version +by several orders of magnitude, but has float precision instead of double +precision.

  • +
  • MMM1D_MACHINE_PREC: This enables high-precision Bessel functions +for MMM1D on CPU. Comes with a 60% slow-down penalty. The low-precision +functions are enabled by default and are precise enough for most applications.

  • +
  • DIPOLES This activates the dipole-moment property of particles and switches +on various magnetostatics algorithms

    +
    +

    See also

    +

    Magnetostatics

    +
    +
  • +
  • SCAFACOS_DIPOLES This activates magnetostatics methods of ScaFaCoS.

  • +
  • DIPOLAR_DIRECT_SUM This activates the GPU implementation of the dipolar direct sum.

  • +
  • ROTATION Switch on rotational degrees of freedom for the particles, as well as +the corresponding quaternion integrator.

    +
    +

    See also

    +

    Setting up particles

    +
    +
    +

    Note

    +

    When this feature is activated, every particle has three +additional degrees of freedom, which for example means that the +kinetic energy changes at constant temperature is twice as large.

    +
    +
  • +
  • THERMOSTAT_PER_PARTICLE Allows setting a per-particle friction +coefficient for the Langevin and Brownian thermostats.

  • +
  • ROTATIONAL_INERTIA Allows particles to have individual rotational inertia matrix eigenvalues. +When not built in, all eigenvalues are unity in simulation units.

  • +
  • EXTERNAL_FORCES Allows to define an arbitrary constant force for each particle +individually. Also allows to fix individual coordinates of particles, +keep them at a fixed position or within a plane.

  • +
  • MASS Allows particles to have individual masses. +When not built in, all masses are unity in simulation units.

    + +
  • +
  • EXCLUSIONS Allows to exclude specific short ranged interactions within +molecules.

    + +
  • +
  • BOND_CONSTRAINT Turns on the RATTLE integrator which allows for fixed lengths bonds +between particles.

  • +
  • VIRTUAL_SITES_RELATIVE Virtual sites are particles, the position and velocity of which is +not obtained by integrating equations of motion. Rather, they are +placed using the position (and orientation) of other particles. The +feature allows for rigid arrangements of particles.

    +
    +

    See also

    +

    Virtual sites

    +
    +
  • +
  • COLLISION_DETECTION Allows particles to be bound on collision.

  • +
+

In addition, there are switches that enable additional features in the +integrator or thermostat:

+
    +
  • NPT Enables an on-the-fly NpT integration scheme.

    + +
  • +
  • ENGINE

  • +
  • PARTICLE_ANISOTROPY

  • +
+
+
+

2.3.2. Fluid dynamics and fluid structure interaction

+
    +
  • DPD Enables the dissipative particle dynamics thermostat and interaction.

    +
    +

    See also

    +

    DPD interaction

    +
    +
  • +
  • LB_BOUNDARIES

  • +
  • LB_BOUNDARIES_GPU

  • +
  • LB_ELECTROHYDRODYNAMICS Enables the implicit calculation of electro-hydrodynamics for charged +particles and salt ions in an electric field.

  • +
  • ELECTROKINETICS

  • +
  • EK_BOUNDARIES

  • +
  • EK_DEBUG

  • +
+
+
+

2.3.3. Interaction features

+

The following switches turn on various short ranged interactions (see +section Isotropic non-bonded interactions):

+
    +
  • TABULATED Enable support for user-defined non-bonded interaction potentials.

  • +
  • LENNARD_JONES Enable the Lennard-Jones potential.

  • +
  • LENNARD_JONES_GENERIC Enable the generic Lennard-Jones potential with configurable +exponents and individual prefactors for the two terms.

  • +
  • LJCOS Enable the Lennard-Jones potential with a cosine-tail.

  • +
  • LJCOS2 Same as LJCOS, but using a slightly different way of smoothing the +connection to 0.

  • +
  • WCA Enable the Weeks–Chandler–Andersen potential.

  • +
  • GAY_BERNE Enable the Gay–Berne potential.

  • +
  • HERTZIAN Enable the Hertzian potential.

  • +
  • MORSE Enable the Morse potential.

  • +
  • BUCKINGHAM Enable the Buckingham potential.

  • +
  • SOFT_SPHERE Enable the soft sphere potential.

  • +
  • SMOOTH_STEP Enable the smooth step potential, a step potential with +two length scales.

  • +
  • BMHTF_NACL Enable the Born–Meyer–Huggins–Tosi–Fumi potential, +which can be used to model salt melts.

  • +
  • GAUSSIAN Enable the Gaussian potential.

  • +
  • HAT Enable the Hat potential.

  • +
+

Some of the short-range interactions have additional features:

+
    +
  • LJGEN_SOFTCORE This modifies the generic Lennard-Jones potential +(LENNARD_JONES_GENERIC) with tunable parameters.

  • +
  • THOLE See Thole correction

  • +
+
+
+

2.3.4. Debug messages

+

Finally, there is a flag for debugging:

+
    +
  • ADDITIONAL_CHECKS Enables numerous additional checks which can detect +inconsistencies especially in the cell systems. These checks are however +too slow to be enabled in production runs.

    +
    +

    Note

    +

    Because of a bug in OpenMPI versions 2.0-2.1, 3.0.0-3.0.2 and 3.1.0-3.1.2 +that causes a segmentation fault when running the ESPResSo OpenGL visualizer +with feature ADDITIONAL_CHECKS enabled together with either +ELECTROSTATICS or DIPOLES, the subset of additional checks for +those two features are disabled if an unpatched version of OpenMPI is +detected during compilation.

    +
    +
  • +
+
+
+

2.3.5. External features

+

External features cannot be added to the myconfig.hpp file by the user. +They are added by CMake if the corresponding dependency was found on the +system. Some of these external features are optional and must be activated +using a CMake flag (see Options and Variables).

+ +
+
+
+

2.4. Configuring

+
+

2.4.1. myconfig.hpp: Activating and deactivating features

+

ESPResSo has a large number of features that can be compiled into the binary. +However, it is not recommended to actually compile in all possible +features, as this will slow down ESPResSo significantly. Instead, compile in only +the features that are actually required. A strong gain in speed can be +achieved by disabling all non-bonded interactions except for a single +one, e.g. LENNARD_JONES. For developers, it is also possible to turn on or off a +number of debugging messages. The features and debug messages can be +controlled via a configuration header file that contains C-preprocessor +declarations. Subsection Features describes all available features. If a +file named myconfig.hpp is present in the build directory when cmake +is run, all features defined in it will be compiled in. If no such file exists, +the configuration file src/config/myconfig-default.hpp will be used +instead, which turns on the default features.

+

When you distinguish between the build and the source directory, the +configuration header can be put in either of these. Note, however, that +when a configuration header is found in both directories, the one in the +build directory will be used.

+

By default, the configuration header is called myconfig.hpp. +The configuration header can be used to compile different binary +versions of with a different set of features from the same source +directory. Suppose that you have a source directory $srcdir and two +build directories $builddir1 and $builddir2 that contain +different configuration headers:

+
    +
  • $builddir1/myconfig.hpp:

    +
    #define ELECTROSTATICS
    +#define LENNARD_JONES
    +
    +
    +
  • +
  • $builddir2/myconfig.hpp:

    +
    #define LJCOS
    +
    +
    +
  • +
+

Then you can simply compile two different versions of ESPResSo via:

+
cd $builddir1
+cmake ..
+make
+
+cd $builddir2
+cmake ..
+make
+
+
+

To see what features were activated in myconfig.hpp, run:

+
./pypresso
+
+
+

and then in the Python interpreter:

+
import espressomd
+print(espressomd.features())
+
+
+
+
+

2.4.2. cmake

+

In order to build the first step is to create a build directory in which +cmake can be executed. In cmake, the source directory (that contains +all the source files) is completely separated from the build directory +(where the files created by the build process are put). cmake is +designed to not be executed in the source directory. cmake will +determine how to use and where to find the compiler, as well as the +different libraries and tools required by the compilation process. By +having multiple build directories you can build several variants of ESPResSo, +each variant having different activated features, and for as many +platforms as you want.

+

Once you’ve run ccmake, you can list the configured variables with +cmake -LAH -N . | less (uses a pager) or with ccmake .. and pressing +key t to toggle the advanced mode on (uses the curses interface).

+

Example:

+

When the source directory is srcdir (the files where unpacked to this +directory), then the user can create a build directory build below that +path by calling mkdir srcdir/build. In the build directory cmake is to be +executed, followed by a call to make. None of the files in the source directory +are ever modified by the build process.

+
cd build
+cmake ..
+make -j
+
+
+

Afterwards ESPResSo can be run by calling ./pypresso from the command line.

+
+
+

2.4.3. ccmake

+

Optionally and for easier use, the curses interface to cmake can be used +to configure ESPResSo interactively.

+

Example:

+

Alternatively to the previous example, instead of cmake, the ccmake executable +is called in the build directory to configure ESPResSo, followed by a call to make:

+
cd build
+ccmake ..
+make
+
+
+

Fig. ccmake interface shows the interactive ccmake UI.

+
+ccmake interface +
+

ccmake interface

+
+
+
+
+

2.4.4. Options and Variables

+

The behavior of ESPResSo can be controlled by means of options and variables +in the CMakeLists.txt file. Most options are boolean values +(ON or OFF). A few options are strings or semicolon-delimited lists.

+

The following options control features from external libraries:

+
    +
  • WITH_CUDA: Build with GPU support.

  • +
  • WITH_HDF5: Build with HDF5 support.

  • +
  • WITH_SCAFACOS: Build with ScaFaCoS support.

  • +
  • WITH_GSL: Build with GSL support.

  • +
  • WITH_STOKESIAN_DYNAMICS Build with Stokesian Dynamics support.

  • +
  • WITH_PYTHON Build with Stokesian Dynamics support.

  • +
+

The following options control code instrumentation:

+
    +
  • WITH_VALGRIND_INSTRUMENTATION: Build with valgrind instrumentation markers

  • +
  • WITH_PROFILER: Build with Caliper profiler annotations

  • +
  • WITH_MSAN: Compile C++ code with memory sanitizer

  • +
  • WITH_ASAN: Compile C++ code with address sanitizer

  • +
  • WITH_UBSAN: Compile C++ code with undefined behavior sanitizer

  • +
  • WITH_COVERAGE: Generate C++ code coverage reports when running ESPResSo

  • +
  • WITH_COVERAGE_PYTHON: Generate Python code coverage reports when running ESPResSo

  • +
+

The following options control how the project is built and tested:

+
    +
  • WITH_CLANG_TIDY: Run Clang-Tidy during compilation.

  • +
  • WITH_CPPCHECK: Run Cppcheck during compilation.

  • +
  • WITH_CCACHE: Enable compiler cache for faster rebuilds.

  • +
  • WITH_TESTS: Enable C++ and Python tests.

  • +
  • WITH_BENCHMARKS: Enable benchmarks.

  • +
  • WITH_CUDA_COMPILER (string): Select the CUDA compiler.

  • +
  • CTEST_ARGS (string): Arguments passed to the ctest command.

  • +
  • TEST_TIMEOUT: Test timeout.

  • +
  • ESPRESSO_ADD_OMPI_SINGLETON_WARNING: Add a runtime warning in the +pypresso and ipypresso scripts that is triggered in singleton mode +with Open MPI version 4.x on unsupported NUMA environments +(see MPI installation requirements for details).

  • +
  • MYCONFIG_NAME (string): Filename of the user-provided config file

  • +
  • MPIEXEC_PREFLAGS, MPIEXEC_POSTFLAGS (strings): Flags passed to the +mpiexec command in MPI-parallel tests and benchmarks.

  • +
  • CMAKE_CXX_FLAGS (string): Flags passed to the compilers.

  • +
  • CMAKE_BUILD_TYPE (string): Build type. Default is Release.

  • +
  • CUDA_TOOLKIT_ROOT_DIR (string): Path to the CUDA toolkit directory.

  • +
+

Most of these options are opt-in, meaning their default value is set to +OFF in the CMakeLists.txt file. These options can be modified +by calling cmake with the command line argument -D:

+
cmake -D WITH_HDF5=OFF ..
+
+
+

When an option is enabled, additional options may become available. +For example with -D WITH_CUDA=ON, one can choose the CUDA compiler with +-D WITH_CUDA_COMPILER=<compiler_id>, where <compiler_id> can be +nvcc (default) or clang.

+

Environment variables can be passed to CMake. For example, to select Clang, use +CC=clang CXX=clang++ cmake .. -DWITH_CUDA=ON -DWITH_CUDA_COMPILER=clang. +If you have multiple versions of the CUDA library installed, you can select the +correct one with CUDA_BIN_PATH=/usr/local/cuda-10.0 cmake .. -DWITH_CUDA=ON +(with Clang as the CUDA compiler, you also need to override its default CUDA +path with -DCMAKE_CXX_FLAGS=--cuda-path=/usr/local/cuda-10.0).

+
+

2.4.4.1. Build types and compiler flags

+

The build type is controlled by -D CMAKE_BUILD_TYPE=<type> where +<type> can take one of the following values:

+
    +
  • Release: for production use: disables assertions and debug information, +enables -O3 optimization (this is the default)

  • +
  • RelWithAssert: for debugging purposes: enables assertions and +-O3 optimization (use this to track the source of a fatal error)

  • +
  • Debug: for debugging in GDB

  • +
  • Coverage: for code coverage

  • +
+

Cluster users and HPC developers may be interested in manually editing the +Espresso_cpp_flags target in the top-level CMakeLists.txt file for +finer control over compiler flags. The variable declaration is followed +by a series of conditionals to enable or disable compiler-specific flags. +Compiler flags passed to CMake via the -DCMAKE_CXX_FLAGS option +(such as cmake . -DCMAKE_CXX_FLAGS="-ffast-math -fno-finite-math-only") +will appear in the compiler command before the flags in Espresso_cpp_flags, +and will therefore have lower precedence.

+

Be aware that fast-math mode can break ESPResSo. It is incompatible with the +ADDITIONAL_CHECKS feature due to the loss of precision in the LB code +on CPU. The Clang 10 compiler breaks field couplings with -ffast-math. +The Intel compiler enables the -fp-model fast=1 flag by default; +it can be disabled by adding the -fp-model=strict flag.

+

ESPResSo currently doesn’t fully support link-time optimization (LTO).

+
+
+
+

2.4.5. Configuring without a network connection

+

Several external features in ESPResSo rely on +external libraries that are downloaded automatically by CMake. When a +network connection cannot be established due to firewall restrictions, +the CMake logic needs editing:

+
    +
  • WITH_HDF5: when cloning ESPResSo, the libs/h5xx folder will be +a git submodule containing a .git subfolder. To prevent CMake from +updating this submodule with git, delete the corresponding command with:

    +
    sed -i '/execute_process(COMMAND ${GIT_EXECUTABLE} submodule update -- libs\/h5xx/,+1 d' CMakeLists.txt
    +
    +
    +

    When installing a release version of ESPResSo, no network communication +is needed for HDF5.

    +
  • +
  • WITH_STOKESIAN_DYNAMICS: this library is installed using FetchContent. +The repository URL can be found in the GIT_REPOSITORY field of the +corresponding FetchContent_Declare() command. The GIT_TAG field +provides the commit. Clone this repository locally next to the ESPResSo +folder and edit the ESPResSo build system such that GIT_REPOSITORY points +to the absolute path of the Stokesian Dynamics clone, for example with:

    +
    sed -ri 's|GIT_REPOSITORY +.+stokesian-dynamics.git|GIT_REPOSITORY /work/username/stokesian_dynamics|' CMakeLists.txt
    +
    +
    +
  • +
+
+
+
+

2.5. Compiling, testing and installing

+

The command make is mainly used to compile the source code, but it +can do a number of other things. The generic syntax of the make +command is:

+
make [options] [target] [variable=value]
+
+
+

When no target is given, the target all is used. The following +targets are available:

+
+
all

Compiles the complete source code. The variable can be used to +specify the name of the configuration header to be used.

+
+
check

Runs the testsuite. By default, all available tests will be run on +1, 2, 3, 4, 6, or 8 processors.

+
+
test

Do not use this target, it is a broken feature +(see issue #4370). +Use make check instead.

+
+
clean

Deletes all files that were created during the compilation.

+
+
install

Install ESPResSo in the path specified by the CMake variable +CMAKE_INSTALL_PREFIX. The path can be changed by calling CMake +with cmake .. -DCMAKE_INSTALL_PREFIX=/path/to/espresso. Do not use +make DESTDIR=/path/to/espresso install to install to a specific path, +this will cause issues with the runtime path (RPATH) and will conflict +with the CMake variable CMAKE_INSTALL_PREFIX if it has been set.

+
+
doxygen

Creates the Doxygen code documentation in the doc/doxygen +subdirectory.

+
+
sphinx

Creates the sphinx code documentation in the doc/sphinx +subdirectory.

+
+
tutorials

Creates the tutorials in the doc/tutorials subdirectory.

+
+
doc

Creates all documentation in the doc subdirectory (only when +using the development sources).

+
+
+

A number of options are available when calling make. The most +interesting option is probably -j num_jobs, which can be used for +parallel compilation. num_jobs specifies the maximal number of +concurrent jobs that will be run. Setting num_jobs to the number +of available processors speeds up the compilation process significantly.

+
+
+

2.6. Troubleshooting

+

If you encounter issues when building ESPResSo or running it for the first time, +please have a look at the Installation FAQ +on the wiki. If you still didn’t find an answer, see Community support.

+

Many algorithms require parameters that must be provided within valid ranges. +Range checks are implemented to catch invalid input values and generate +meaningful error messages, however these checks cannot always catch errors +arising from an invalid combination of two or more features. If you encounter +issues with a script, you can activate extra runtime checks by enabling C++ +assertions. This is achieved by updating the CMake project and rebuilding +ESPResSo with:

+
cmake . -DCMAKE_BUILD_TYPE=RelWithAssert
+make -j
+
+
+

The resulting build will run slightly slower, but will produce an error +message for common issues, such as divisions by zero, array access out +of bounds, or square roots of negative numbers.

+

If this still doesn’t help, you can activate debug symbols to help with +instrumentation:

+
cmake . -DCMAKE_BUILD_TYPE=Debug
+make -j
+
+
+

The resulting build will be quite slow but will allow many debugging tools +to be used. For details, please refer to chapter Debugging ESPResSo.

+

If you are dealing with a segmentation fault or undefined behavior, and GDB +doesn’t help or is too cumbersome to use (e.g. in MPI-parallel simulations), +you can as a last resort activate sanitizers:

+
cmake . -DWITH_ASAN=ON -DWITH_UBSAN=ON -DCMAKE_BUILD_TYPE=Release
+make -j
+
+
+

The resulting build will be around 5 times slower that a debug build, +but it will generate valuable reports when detecting fatal exceptions. +For more details, please consult the online documentation of +UBSAN and +ASAN.

+
+
+
1
+

https://espressomd.org

+
+
2
+

https://git-scm.com/

+
+
3
+

https://github.com/espressomd/espresso

+
+
4
+

https://cmake.org/

+
+
5
+

https://www.fftw.org/

+
+
6
+

https://docs.nvidia.com/cuda/

+
+
7
+

https://docs.python.org/3/library/venv.html

+
+
8
+

https://conda.io/projects/conda/en/latest/user-guide/tasks/manage-environments.html

+
+
+
+
+ + +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/doc4.2.2/integration.html b/doc4.2.2/integration.html new file mode 100644 index 0000000000..3dd2593dbc --- /dev/null +++ b/doc4.2.2/integration.html @@ -0,0 +1,706 @@ + + + + + + + + + 6. Integrators and thermostats — ESPResSo 4.2.2 documentation + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +
+

6. Integrators and thermostats

+
+

6.1. Particle integration and propagation

+

The main integration scheme of ESPResSo is the velocity Verlet algorithm. +A steepest descent algorithm is used to minimize the system.

+

Additional integration schemes are available, which can be coupled to +thermostats to enable Langevin dynamics, Brownian dynamics, Stokesian dynamics, +dissipative particle dynamics, and simulations in the NpT ensemble.

+
+
+

6.2. Integrators

+

To run the integrator call the method +system.integrate.run():

+
system.integrator.run(number_of_steps, recalc_forces=False, reuse_forces=False)
+
+
+

where number_of_steps is the number of time steps the integrator should perform.

+
+

6.2.1. Velocity Verlet algorithm

+

espressomd.integrate.IntegratorHandle.set_vv()

+

The equations of motion for the trajectory of point-like particles read

+
+\[\begin{split}\dot v_i(t) = F_i(\{x_j\},v_i,t)/m_i \\ \dot x_i(t) = v_i(t),\end{split}\]
+

where \(x_i\), \(v_i\), \(m_i\) are position, velocity and mass of +particle \(i\) and \(F_i(\{x_j\},v_i,t)\) the forces acting on it. +These forces comprise all interactions with other particles and external fields +as well as non-deterministic contributions described in Thermostats.

+

For numerical integration, this equation is discretized to the following steps ([Rapaport, 2004] eqs. 3.5.8 - 3.5.10):

+
    +
  1. Calculate the velocity at the half step

    +
    +\[v(t+dt/2) = v(t) + \frac{F(x(t),v(t-dt/2),t)}{m} dt/2\]
    +
  2. +
  3. Calculate the new position

    +
    +\[x(t+dt) = x(t) + v(t+dt/2) dt\]
    +
  4. +
  5. Calculate the force based on the new position

    +
    +\[F = F(x(t+dt), v(t+dt/2), t+dt)\]
    +
  6. +
  7. Calculate the new velocity

    +
    +\[v(t+dt) = v(t+dt/2) + \frac{F(x(t+dt),t+dt)}{m} dt/2\]
    +
  8. +
+

Note that this implementation of the velocity Verlet algorithm reuses +forces in step 1. That is, they are computed once in step 3, +but used twice, in step 4 and in step 1 of the next iteration. In the first time +step after setting up, there are no forces present yet. Therefore, ESPResSo has +to compute them before the first time step. That has two consequences: +first, random forces are redrawn, resulting in a narrower distribution +of the random forces, which we compensate by stretching. Second, +coupling forces of e.g. the lattice-Boltzmann fluid cannot be computed +and are therefore lacking in the first half time step. In order to +minimize these effects, ESPResSo has a quite conservative heuristics to decide +whether a change makes it necessary to recompute forces before the first +time step. Therefore, calling 100 times +espressomd.integrate.Integrator.run() with steps=1 does the +same as with steps=100, apart from some small calling overhead.

+

However, for checkpointing, there is no way for ESPResSo to tell that the forces +that you read back in actually match the parameters that are set. +Therefore, ESPResSo would recompute the forces before the first time step, which +makes it essentially impossible to checkpoint LB simulations, where it +is vital to keep the coupling forces. To work around this, there is +an additional parameter reuse_forces, which tells integrate to not recalculate +the forces for the first time step, but use that the values still stored +with the particles. Use this only if you are absolutely sure that the +forces stored match your current setup!

+

The opposite problem occurs when timing interactions: In this case, one +would like to recompute the forces, despite the fact that they are +already correctly calculated. To this aim, the option recalc_forces can be used to +enforce force recalculation.

+
+
+

6.2.2. Isotropic NpT integrator

+

espressomd.integrate.IntegratorHandle.set_isotropic_npt()

+

As the NpT thermostat alters the way the equations of motion are integrated, it is +discussed here and only a brief summary is given in Thermostats.

+

To activate the NpT integrator, use set_isotropic_npt() +with parameters:

+
    +
  • ext_pressure: The external pressure

  • +
  • piston: The mass of the applied piston

  • +
  • direction: Flags to enable/disable box dimensions to be subject to fluctuations. By default, all directions are enabled.

  • +
+

Additionally, a NpT thermostat has to be set by set_npt() +with parameters:

+
    +
  • kT: Thermal energy of the heat bath

  • +
  • gamma0: Friction coefficient of the bath

  • +
  • gammav: Artificial friction coefficient for the volume fluctuations.

  • +
+

A code snippet would look like:

+
import espressomd
+
+system = espressomd.System(box_l=[1, 1, 1])
+system.thermostat.set_npt(kT=1.0, gamma0=1.0, gammav=1.0, seed=42)
+system.integrator.set_isotropic_npt(ext_pressure=1.0, piston=1.0)
+
+
+

The physical meaning of these parameters is described below:

+

The relaxation towards a desired pressure \(P\) (parameter ext_pressure) +is enabled by treating the box +volume \(V\) as a degree of freedom with corresponding momentum \(\Pi = Q\dot{V}\), +where \(Q\) (parameter piston) is an artificial piston mass. +Which box dimensions are affected to change the volume can be controlled by a list of +boolean flags for parameter direction. +An additional energy \(H_V = 1/(2Q)\Pi + PV\) +associated with the volume is postulated. This results in a “force” on the box such that

+
+\[\dot{\Pi} = \mathcal{P} - P\]
+

where

+
+\[\mathcal{P} = \frac{1}{Vd} \sum_{i,j} f_{ij}x_{ij} + \frac{1}{Vd} \sum_i m_i v_i^2\]
+

Here \(\mathcal{P}\) is the instantaneous pressure, \(d\) the dimension +of the system (number of flags set by direction), \(f_{ij}\) the +short range interaction force between particles \(i\) and \(j\) and +\(x_{ij}= x_j - x_i\).

+

In addition to this deterministic force, a friction \(-\frac{\gamma^V}{Q}\Pi(t)\) +and noise \(\sqrt{k_B T \gamma^V} \eta(t)\) are added for the box +volume dynamics and the particle dynamics. This introduces three new parameters: +The friction coefficient for the box \(\gamma^V\) (parameter gammav), +the friction coefficient of the particles \(\gamma^0\) (parameter gamma0) +and the thermal energy \(k_BT\) (parameter kT). +For a discussion of these terms and their discretisation, see Langevin thermostat, +which uses the same approach, but only for particles. +As a result of box geometry changes, the particle positions and velocities have to be rescaled +during integration.

+

The discretisation consists of the following steps (see [Kolb and Dünweg, 1999] for a full derivation of the algorithm):

+
    +
  1. Calculate the particle velocities at the half step

    +
    +\[v'(t+dt/2) = v(t) + \frac{F(x(t),v(t-dt/2),t)}{m} dt/2\]
    +
  2. +
  3. Calculate the instantaneous pressure and “volume momentum”

    +
    +\[\mathcal{P} = \mathcal{P}(x(t),V(t),f(x(t)), v'(t+dt/2))\]
    +
    +\[\Pi(t+dt/2) = \Pi(t) + (\mathcal{P}-P) dt/2 -\frac{\gamma^V}{Q}\Pi(t) dt/2 + \sqrt{k_B T \gamma^V dt} \overline{\eta}\]
    +
  4. +
  5. Calculate box volume and scaling parameter \(L\) at half step and full step, scale the simulation box accordingly

    +
    +\[V(t+dt/2) = V(t) + \frac{\Pi(t+dt/2)}{Q} dt/2\]
    +
    +\[L(t+dt/2) = V(t+dt/2)^{1/d}\]
    +
    +\[V(t+dt) = V(t+dt/2) + \frac{\Pi(t+dt/2)}{Q} dt/2\]
    +
    +\[L(t+dt) = V(t+dt)^{1/d}\]
    +
  6. +
  7. Update particle positions and scale velocities

    +
    +\[x(t+dt) = \frac{L(t+dt)}{L(t)} \left[ x(t) + \frac{L^2(t)}{L^2(t+dt/2)} v(t+dt/2) dt \right]\]
    +
    +\[v(t+dt/2) = \frac{L(t)}{L(t+dt)} v'(t+dt/2)\]
    +
  8. +
  9. Calculate forces, instantaneous pressure and “volume momentum”

    +
    +\[F = F(x(t+dt),v(t+dt/2),t)\]
    +
    +\[\mathcal{P} = \mathcal{P}(x(t+dt),V(t+dt),f(x(t+dt)), v(t+dt/2))\]
    +
    +\[\Pi(t+dt) = \Pi(t+dt/2) + (\mathcal{P}-P) dt/2 -\frac{\gamma^V}{Q}\Pi(t+dt/2) dt/2 + \sqrt{k_B T \gamma^V dt} \overline{\eta}\]
    +

    with uncorrelated numbers \(\overline{\eta}\) drawn from a random uniform process \(\eta(t)\)

    +
  10. +
  11. Update the velocities

    +
    +\[v(t+dt) = v(t+dt/2) + \frac{F(t+dt)}{m} dt/2\]
    +
  12. +
+

Notes:

+
    +
  • The NpT algorithm is only tested for all 3 directions enabled for scaling. Usage of direction is considered an experimental feature.

  • +
  • In step 4, only those coordinates are scaled for which direction is set.

  • +
  • For the instantaneous pressure, the same limitations of applicability hold as described in Pressure.

  • +
  • The particle forces \(F\) include interactions as well as a friction (\(\gamma^0\)) and noise term (\(\sqrt{k_B T \gamma^0 dt} \overline{\eta}\)) analogous to the terms in the Langevin thermostat.

  • +
  • The particle forces are only calculated in step 5 and then reused in step 1 of the next iteration. See Velocity Verlet algorithm for the implications of that.

  • +
  • The NpT algorithm doesn’t support Lees–Edwards boundary conditions.

  • +
  • The NpT algorithm doesn’t support propagation of angular velocities.

  • +
+
+
+

6.2.3. Steepest descent

+

espressomd.integrate.IntegratorHandle.set_steepest_descent()

+

This feature is used to propagate each particle by a small distance parallel to the force acting on it. +When only conservative forces for which a potential exists are in use, this is equivalent to a steepest descent energy minimization. +A common application is removing overlap between randomly placed particles.

+

Please note that the behavior is undefined if a thermostat is activated, +in which case the integrator will generate an error. The integrator runs +the following steepest descent algorithm:

+
+\[\vec{r}_{i+1} = \vec{r}_i + \min(\gamma \vec{F}_i, \vec{r}_{\text{max_displacement}}),\]
+

while the maximal force/torque is bigger than f_max or for at most steps times. The energy +is relaxed by gamma, while the change per coordinate per step is limited to max_displacement. +The combination of gamma and max_displacement can be used to get a poor man’s adaptive update. +Rotational degrees of freedom are treated similarly: each particle is +rotated around an axis parallel to the torque acting on the particle, +with max_displacement interpreted as the maximal rotation angle. +Please be aware of the fact that this needs not to converge to a local +minimum in periodic boundary conditions. Translational and rotational +coordinates that are fixed using the fix and rotation attribute of particles are not altered.

+

Usage example:

+
system.integrator.set_steepest_descent(
+    f_max=0, gamma=0.1, max_displacement=0.1)
+system.integrator.run(20)   # maximal number of steps
+system.integrator.set_vv()  # to switch back to velocity Verlet
+
+
+
+

6.2.3.1. Using a custom convergence criterion

+

The f_max parameter can be set to zero to prevent the integrator from +halting when a specific force/torque is reached. The integration can then +be carried out in a loop with a custom convergence criterion:

+
min_sigma = 1  # size of the smallest particle
+max_sigma = 5  # size of the largest particle
+min_dist = 0.0
+system.integrator.set_steepest_descent(f_max=0, gamma=10,
+                                       max_displacement=min_sigma * 0.01)
+# gradient descent until particles are separated by at least max_sigma
+while min_dist < max_sigma:
+    min_dist = system.analysis.min_dist()
+    system.integrator.run(10)
+system.integrator.set_vv()
+
+
+

When writing a custom convergence criterion based on forces or torques, keep +in mind that particles whose motion and rotation are fixed in space along +some or all axes with fix or rotation need to be filtered from the +force/torque observable used in the custom convergence criterion. Since these +two properties can be cast to boolean values, they can be used as masks to +remove forces/torques that are ignored by the integrator:

+
particles = system.part.all()
+max_force = np.max(np.linalg.norm(particles.f * np.logical_not(particles.fix), axis=1))
+max_torque = np.max(np.linalg.norm(particles.torque_lab * np.logical_not(particles.rotation), axis=1))
+
+
+

Virtual sites can also be an issue since the force on the virtual site is +transferred to the target particle at the beginning of the integration loop. +The correct forces need to be re-calculated after running the integration:

+
def convergence_criterion(forces):
+    '''Function that decides when the gradient descent has converged'''
+    return ...
+p1 = system.part.add(pos=[0, 0, 0], type=1)
+p2 = system.part.add(pos=[0, 0, 0.1], type=1)
+p2.vs_auto_relate_to(p1)
+system.integrator.set_steepest_descent(f_max=800, gamma=1.0, max_displacement=0.01)
+while convergence_criterion(system.part.all().f):
+    system.integrator.run(10)
+    system.integrator.run(0, recalc_forces=True)  # re-calculate forces from virtual sites
+system.integrator.set_vv()
+
+
+

The algorithm can also be used for energy minimization:

+
# minimize until energy difference < 5% or energy < 1e-3
+system.integrator.set_steepest_descent(f_max=0, gamma=1.0, max_displacement=0.01)
+relative_energy_change = float('inf')
+relative_energy_change_threshold = 0.05
+energy_threshold = 1e-3
+energy_old = system.analysis.energy()['total']
+print(f'Energy: {energy_old:.2e}')
+for i in range(20):
+    system.integrator.run(50)
+    energy = system.analysis.energy()['total']
+    print(f'Energy: {energy:.2e}')
+    relative_energy_change = (energy_old - energy) / energy_old
+    if relative_energy_change < relative_energy_change_threshold or energy < energy_threshold:
+        break
+    energy_old = energy
+else:
+    print(f'Energy minimization did not converge in {i + 1} cycles')
+system.integrator.set_vv()
+
+
+

Please note that not all features support energy calculation. +For example IBM +and OIF do not implement energy calculation for +mesh surface deformation.

+
+
+
+

6.2.4. Brownian Dynamics

+

Brownian Dynamics integrator [Schlick, 2010]. +See details in Brownian thermostat.

+
+
+

6.2.5. Stokesian Dynamics

+
+

Note

+

Requires STOKESIAN_DYNAMICS external feature, enabled with +-DWITH_STOKESIAN_DYNAMICS=ON.

+
+

espressomd.integrate.IntegratorHandle.set_stokesian_dynamics()

+

The Stokesian Dynamics method is used to model the behavior of spherical +particles in a viscous fluid. It is targeted at systems with very low Reynolds +numbers. In such systems, particles come to a rest almost immediately as soon as +any force on them is removed. In other words, motion has no memory of the past.

+

The integration scheme is relatively simple. Only the particles’ positions, +radii and forces (including torques) are needed to compute the momentary +velocities (including angular velocities). The particle positions are +integrated by the simple Euler scheme.

+

The computation of the velocities is an approximation with good results +in the far field. +The Stokesian Dynamics method is only available for open systems, +i.e. no periodic boundary conditions are supported. The box size has +no effect either.

+

The Stokesian Dynamics method is outlined in [Durlofsky et al., 1987].

+

The following minimal example illustrates how to use the SDM in ESPResSo:

+
import espressomd
+system = espressomd.System(box_l=[1.0, 1.0, 1.0])
+system.periodicity = [False, False, False]
+system.time_step = 0.01
+system.cell_system.skin = 0.4
+system.part.add(pos=[0, 0, 0], rotation=[1, 0, 0])
+system.integrator.set_stokesian_dynamics(viscosity=1.0, radii={0: 1.0})
+system.integrator.run(100)
+
+
+

Because there is no force on the particle yet, nothing will move. You will need +to add your own actors to the system. The parameter radii is a dictionary +that maps particle types to different radii. viscosity is the dynamic +viscosity of the ambient infinite fluid. There are additional optional +parameters for set_stokesian_dynamics(). For more information, see +espressomd.integrate.IntegratorHandle.set_stokesian_dynamics().

+

Note that this setup represents a system at zero temperature. In order to +thermalize the system, the SD thermostat needs to be activated (see +Stokesian thermostat).

+
+

6.2.5.1. Important

+

The particles must be prevented from overlapping. It is mathematically allowed +for the particles to overlap to a certain degree. However, once the distance +of the sphere centers is less than 2/3 of the sphere diameter, the mobility +matrix is no longer positive definite and the Stokesian Dynamics integrator +will fail. Therefore, the particle centers must be kept apart from each +other by a strongly repulsive potential, for example the WCA potential +that is set to the appropriate particle radius (for more information about +the available interaction types see Non-bonded interactions).

+

The current implementation of SD only includes the far field approximation. +The near field (so-called lubrication) correction is planned. For now, +Stokesian Dynamics provides a good approximation of the hydrodynamics +in dilute systems where the average distance between particles is several +sphere diameters.

+
+
+
+
+

6.3. Thermostats

+

To add a thermostat, call the appropriate setter:

+
system.thermostat.set_langevin(kT=1.0, gamma=1.0, seed=41)
+
+
+

The different thermostats available in ESPResSo will be described in the following +subsections.

+

You may combine different thermostats at your own risk by turning them on +one by one. The list of active thermostats can be cleared at any time with +system.thermostat.turn_off(). +Not all combinations of thermostats are allowed, though (see +espressomd.thermostat.AssertThermostatType() for details). +Some integrators only work with a specific thermostat and throw an +error otherwise. Note that there is only one temperature for all +thermostats, although for some thermostats like the Langevin thermostat, +particles can be assigned individual temperatures.

+

Since ESPResSo does not enforce a particular unit system, it cannot know about +the current value of the Boltzmann constant. Therefore, when specifying +the temperature of a thermostat, you actually do not define the +temperature, but the value of the thermal energy \(k_B T\) in the +current unit system (see the discussion on units, Section On units).

+

All thermostats have a seed argument that controls the state of the random +number generator (Philox Counter-based RNG). This seed is required on first +activation of a thermostat, unless stated otherwise. It can be omitted in +subsequent calls of the method that activates the same thermostat. The random +sequence also depends on the thermostats counters that are +incremented after each integration step.

+
+

6.3.1. Langevin thermostat

+

In order to activate the Langevin thermostat the member function +set_langevin() of the thermostat +class espressomd.thermostat.Thermostat has to be invoked. +Best explained in an example:

+
import espressomd
+system = espressomd.System(box_l=[1, 1, 1])
+system.thermostat.set_langevin(kT=1.0, gamma=1.0, seed=41)
+
+
+

As explained before the temperature is set as thermal energy \(k_\mathrm{B} T\).

+

The Langevin thermostat is based on an extension of Newton’s equation of motion to

+
+\[m_i \dot{v}_i(t) = f_i(\{x_j\},v_i,t) - \gamma v_i(t) + \sqrt{2\gamma k_B T} \eta_i(t).\]
+

Here, \(f_i\) are all deterministic forces from interactions, +\(\gamma\) the bare friction coefficient and \(\eta\) a random, “thermal” force. +The friction term accounts for dissipation in a surrounding fluid whereas +the random force mimics collisions of the particle with solvent molecules +at temperature \(T\) and satisfies

+
+\[<\eta(t)> = 0 , <\eta^\alpha_i(t)\eta^\beta_j(t')> = \delta_{\alpha\beta} \delta_{ij}\delta(t-t')\]
+

(\(<\cdot>\) denotes the ensemble average and \(\alpha,\beta\) are spatial coordinates).

+

In the ESPResSo implementation of the Langevin thermostat, +the additional terms only enter in the force calculation. +This reduces the accuracy of the velocity Verlet integrator +by one order in \(dt\) because forces are now velocity-dependent.

+

The random process \(\eta(t)\) is discretized by drawing an uncorrelated random number +\(\overline{\eta}\) for each component of all the particle forces. +The distribution of \(\overline{\eta}\) is uniform and satisfies

+
+\[<\overline{\eta}> = 0 , <\overline{\eta}\overline{\eta}> = 1/dt\]
+

If the feature ROTATION is compiled in, the rotational degrees of freedom are +also coupled to the thermostat. If only the first two arguments are +specified then the friction coefficient for the rotation is set to the +same value as that for the translation. +A separate rotational friction coefficient can be set by inputting +gamma_rotate. The two options allow one to switch the translational and rotational +thermalization on or off separately, maintaining the frictional behavior. This +can be useful, for instance, in high Péclet number active matter systems, where +one wants to thermalize only the rotational degrees of freedom while +translational degrees of freedom are affected by the self-propulsion.

+

The keywords gamma and gamma_rotate can be specified as a scalar, +or, with feature PARTICLE_ANISOTROPY compiled in, as the three eigenvalues +of the respective friction coefficient tensor. This is enables the simulation of +the anisotropic diffusion of anisotropic colloids (rods, etc.).

+

Using the Langevin thermostat, it is possible to set a temperature and a +friction coefficient for every particle individually via the feature +THERMOSTAT_PER_PARTICLE. Consult the reference of the part command +(chapter Setting up particles) for information on how to achieve this.

+
+
+

6.3.2. Brownian thermostat

+

Brownian thermostat is a formal name of a thermostat enabling the +Brownian Dynamics feature (see [Schlick, 2010]) which implies +a propagation scheme involving systematic and thermal parts of the +classical Ermak-McCammom’s (see [Ermak and McCammon, 1978]) +Brownian Dynamics. Currently it is implemented without +hydrodynamic interactions, i.e. +with a diagonal diffusion tensor. +The hydrodynamic interactions feature will be available later +as a part of the present Brownian Dynamics or +implemented separately within the Stokesian Dynamics.

+

In order to activate the Brownian thermostat, the member function +set_brownian of the thermostat +class espressomd.thermostat.Thermostat has to be invoked. +The system integrator should be also changed. +Best explained in an example:

+
import espressomd
+system = espressomd.System(box_l=[1, 1, 1])
+system.thermostat.set_brownian(kT=1.0, gamma=1.0, seed=41)
+system.integrator.set_brownian_dynamics()
+
+
+

where gamma (hereinafter \(\gamma\)) is a viscous friction coefficient. +In terms of the Python interface and setup, the Brownian thermostat is very +similar to the Langevin thermostat. The feature +THERMOSTAT_PER_PARTICLE is used to control the per-particle +temperature and the friction coefficient setup. The major differences are +its internal integrator implementation and other temporal constraints. +The integrator is still a symplectic velocity Verlet-like one. +It is implemented via a viscous drag part and a random walk of both the position and +velocity. Due to a nature of the Brownian Dynamics method, its time step \(\Delta t\) +should be large enough compared to the relaxation time +\(m/\gamma\) where \(m\) is the particle mass. +This requirement is just a conceptual one +without specific implementation technical restrictions. +Note that with all similarities of +Langevin and Brownian Dynamics, the Langevin thermostat temporal constraint +is opposite. A velocity is restarting from zero at every step. +Formally, the previous step velocity at the beginning of the the \(\Delta t\) interval +is dissipated further +and does not contribute to the end one as well as to the positional random walk. +Another temporal constraint +which is valid for both Langevin and Brownian Dynamics: conservative forces +should not change significantly over the \(\Delta t\) interval.

+

The viscous terminal velocity \(\Delta v\) and corresponding positional +step \(\Delta r\) are fully driven by conservative forces \(F\):

+
+\[\Delta r = \frac{F \cdot \Delta t}{\gamma}\]
+
+\[\Delta v = \frac{F}{\gamma}\]
+

A positional random walk variance of each coordinate \(\sigma_p^2\) +corresponds to a diffusion within the Wiener process:

+
+\[\sigma_p^2 = 2 \frac{kT}{\gamma} \cdot \Delta t\]
+

Each velocity component random walk variance \(\sigma_v^2\) is defined by the heat +component:

+
+\[\sigma_v^2 = \frac{kT}{m}\]
+

Note: the velocity random walk is propagated from zero at each step.

+

A rotational motion is implemented similarly. +Note: the rotational Brownian dynamics implementation is compatible with particles which have +the isotropic moment of inertia tensor only. Otherwise, the viscous terminal angular velocity +is not defined, i.e. it has no constant direction over the time.

+
+
+

6.3.3. Isotropic NpT thermostat

+

This feature allows to simulate an (on average) homogeneous and isotropic system in the NpT ensemble. +In order to use this feature, NPT has to be defined in the myconfig.hpp. +Activate the NpT thermostat with the command set_npt() +and setup the integrator for the NpT ensemble with set_isotropic_npt().

+

For example:

+
import espressomd
+
+system = espressomd.System(box_l=[1, 1, 1])
+system.thermostat.set_npt(kT=1.0, gamma0=1.0, gammav=1.0, seed=41)
+system.integrator.set_isotropic_npt(ext_pressure=1.0, piston=1.0)
+
+
+

For an explanation of the algorithm involved, see Isotropic NpT integrator.

+

Be aware that this feature is neither properly examined for all systems +nor is it maintained regularly. If you use it and notice strange +behavior, please contribute to solving the problem.

+
+
+

6.3.4. Dissipative Particle Dynamics (DPD)

+

The DPD thermostat adds friction and noise to the particle +dynamics like the Langevin thermostat, but these +are not applied to every particle individually but instead +encoded in a dissipative interaction between particles [Soddemann et al., 2003].

+

To realize a complete DPD fluid model in ESPResSo, three parts are needed: +the DPD thermostat, which controls the temperate, a dissipative interaction +between the particles that make up the fluid, see DPD interaction, +and a repulsive conservative force, see Hat interaction.

+

The temperature is set via +espressomd.thermostat.Thermostat.set_dpd() +which takes kT and seed as arguments.

+

The friction coefficients and cutoff are controlled via the +DPD interaction on a per type-pair basis.

+

The friction (dissipative) and noise (random) term are coupled via the +fluctuation-dissipation theorem. The friction term is a function of the +relative velocity of particle pairs. The DPD thermostat is better for +dynamics than the Langevin thermostat, since it mimics hydrodynamics in +the system.

+

As a conservative force any interaction potential can be used, +see Isotropic non-bonded interactions. A common choice is +a force ramp which is implemented as Hat interaction.

+

A complete example of setting up a DPD fluid and running it +to sample the equation of state can be found in /samples/dpd.py.

+

When using a Lennard-Jones interaction, \({r_\mathrm{cut}} = +2^{\frac{1}{6}} \sigma\) is a good value to choose, so that the +thermostat acts on the relative velocities between nearest neighbor +particles. Larger cutoffs including next nearest neighbors or even more +are unphysical.

+

Boundary conditions for DPD can be introduced by adding the boundary +as a particle constraint, and setting a velocity and a type on it, see +espressomd.constraints.Constraint. Then a +DPD interaction with the type can be defined, which acts as a +boundary condition.

+
+
+

6.3.5. Lattice-Boltzmann thermostat

+

The Lattice-Boltzmann thermostat acts similar to the Langevin thermostat in that the governing equation for particles is

+
+\[m_i \dot{v}_i(t) = f_i(\{x_j\},v_i,t) - \gamma (v_i(t)-u(x_i(t),t)) + \sqrt{2\gamma k_B T} \eta_i(t).\]
+

where \(u(x,t)\) is the fluid velocity at position \(x\) and time \(t\). +To preserve momentum, an equal and opposite friction force and random force act on the fluid.

+

Numerically the fluid velocity is determined from the lattice-Boltzmann node velocities +by interpolating as described in Interpolating velocities. +The backcoupling of friction forces and noise to the fluid is also done by distributing those forces amongst the nearest LB nodes. +Details for both the interpolation and the force distribution can be found in [Ahlrichs and Dünweg, 1999] and [Dünweg and Ladd, 2009].

+

The LB fluid can be used to thermalize particles, while also including their hydrodynamic interactions. +The LB thermostat expects an instance of either espressomd.lb.LBFluid or espressomd.lb.LBFluidGPU. +Temperature is set via the kT argument of the LB fluid.

+

The magnitude of the frictional coupling can be adjusted by the +parameter gamma. To enable the LB thermostat, use:

+
import espressomd
+import espressomd.lb
+system = espressomd.System(box_l=[1, 1, 1])
+lbf = espressomd.lb.LBFluid(agrid=1, dens=1, visc=1, tau=0.01)
+system.actors.add(lbf)
+system.thermostat.set_lb(LB_fluid=lbf, seed=123, gamma=1.5)
+
+
+

No other thermostatting mechanism is necessary +then. Please switch off any other thermostat before starting the LB +thermostatting mechanism.

+

The LBM implementation provides a fully thermalized LB fluid, all +nonconserved modes, including the pressure tensor, fluctuate correctly +according to the given temperature and the relaxation parameters. All +fluctuations can be switched off by setting the temperature to 0.

+
+

Note

+

Coupling between LB and MD only happens if the LB thermostat is set with a \(\gamma \ge 0.0\).

+
+
+
+

6.3.6. Stokesian thermostat

+
+

Note

+

Requires STOKESIAN_DYNAMICS external feature, enabled with +-DWITH_STOKESIAN_DYNAMICS=ON.

+
+

In order to thermalize a Stokesian Dynamics simulation, the SD thermostat +needs to be activated via:

+
import espressomd
+system = espressomd.System(box_l=[1.0, 1.0, 1.0])
+system.periodicity = [False, False, False]
+system.time_step = 0.01
+system.cell_system.skin = 0.4
+system.part.add(pos=[0, 0, 0], rotation=[1, 0, 0], ext_force=[0, 0, -1])
+system.thermostat.set_stokesian(kT=1.0, seed=43)
+system.integrator.set_stokesian_dynamics(viscosity=1.0, radii={0: 1.0})
+system.integrator.run(100)
+
+
+

where kT denotes the desired temperature of the system, and seed the +seed for the random number generator.

+
+
+
+ + +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/doc4.2.2/inter_bonded.html b/doc4.2.2/inter_bonded.html new file mode 100644 index 0000000000..7b4607dc6f --- /dev/null +++ b/doc4.2.2/inter_bonded.html @@ -0,0 +1,681 @@ + + + + + + + + + 8. Bonded interactions — ESPResSo 4.2.2 documentation + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +
+

8. Bonded interactions

+

Bonded interactions are configured by the +espressomd.interactions.BondedInteractions class, which is +a member of espressomd.system.System. Generally, one may use +the following syntax to activate and assign a bonded interaction:

+
system.bonded_inter.add(bond)
+p1.add_bond((bond, p2, ...))
+
+
+

In general, one instantiates an interaction object bond and subsequently passes it +to espressomd.interactions.BondedInteractions.add(). This will enable the +bonded interaction and allows the user to assign bonds between particles p1 +and p2. +Bonded interactions are identified by either their bondid or their appropriate object.

+

Defining a bond between two particles always involves three steps: +defining the interaction, adding it to the system and applying it to the particles. +To illustrate this, assume that two particles p1 and p2 already exist. +One could for example create a FENE bond (more information about the FENE bond +is provided in subsection FENE bond) between them using:

+
fene = FeneBond(k=1, d_r_max=1)
+system.bonded_inter.add(fene)
+p1.add_bond((fene, p2))
+
+
+

Note that the fene object specifies the type of bond and its parameters, +while the information of the bond between p1 and its bonded partners +is stored on p1. This means that to remove a bond, one has to remember +on which particle the bond was added. You can find more +information regarding particle properties in Setting up particles.

+

To delete the FENE bond between particles p1 and p2:

+
p1.delete_bond((fene, p2))
+
+
+

Note that alternatively to particle handles, the particle’s ids can be +used to setup bonded interactions. For example, to create a bond between the +particles with the ids 12 and 43:

+
system.part.by_id(12).add_bond((fene, 43))
+
+
+
+

8.1. Distance-dependent bonds

+
+

8.1.1. FENE bond

+

A FENE (finite extension nonlinear elastic) bond can be instantiated via +espressomd.interactions.FeneBond:

+
import espressomd.interactions
+fene = espressomd.interactions.FeneBond(k=<float>, d_r_max=<float>, r_0=<float>)
+
+
+

This command creates a bond type identifier with a FENE +interaction. The FENE potential

+
+\[V(r) = -\frac{1}{2} K \Delta r_\mathrm{max}^2\ln \left[ 1 - \left( + \frac{r-r_0}{\Delta r_\mathrm{max}} \right)^2 \right]\]
+

models a rubber-band-like, symmetric interaction between two particles with magnitude +\(K\), maximal stretching length \(\Delta r_0\) and equilibrium bond length +\(r_0\). The bond potential diverges at a particle distance +\(r=r_0-\Delta r_\mathrm{max}\) and \(r=r_0+\Delta r_\mathrm{max}\).

+
+
+

8.1.2. Harmonic bond

+

A harmonic bond can be instantiated via +espressomd.interactions.HarmonicBond:

+
import espressomd.interactions
+hb = espressomd.interactions.HarmonicBond(k=<float>, r_0=<float>, r_cut=<float>)
+
+
+

This creates a bond type identifier with a classical harmonic +potential. It is a symmetric interaction between two particles. With the +equilibrium length \(r_0\) and the magnitude \(k\). It is given by

+
+\[V(r) = \frac{1}{2} k \left( r - r_0 \right)^2\]
+

The third, optional parameter defines a cutoff radius. Whenever a +harmonic bond gets longer than \(r_\mathrm{cut}\), the bond will be reported as broken, +and a background error will be raised.

+
+
+

8.1.3. Quartic bond

+

A quartic bond can be instantiated via +espressomd.interactions.QuarticBond.

+

The potential is minimal at particle distance \(r=R\). It is given by

+
+\[V(r) = \frac{1}{2} K_0 \left( r - R \right)^2 + \frac{1}{4} K_1 \left( r - R \right)^4\]
+

The fourth, optional, parameter defines a cutoff radius. Whenever a +quartic bond gets longer than r_cut, the bond will be reported as broken, and +a background error will be raised.

+
+
+

8.1.4. Bonded Coulomb

+
+

Note

+

Requires ELECTROSTATICS feature.

+
+

A pairwise Coulomb interaction can be instantiated via +espressomd.interactions.BondedCoulomb:

+
import espressomd.interactions
+bonded_coulomb = espressomd.interactions.BondedCoulomb(prefactor=1.0)
+system.bonded_inter.add(bonded_coulomb)
+p1.add_bond((bonded_coulomb, p2))
+
+
+

This creates a bond with a Coulomb pair potential between particles p1 and p2. +It is given by

+
+\[V(r) = \alpha \frac{q_1 q_2}{r},\]
+

where \(q_1\) and \(q_2\) are the charges of the bound particles and \(\alpha\) is the +Coulomb prefactor. This interaction has no cutoff and acts independently of other +Coulomb interactions.

+
+
+

8.1.5. Subtract P3M short-range bond

+
+

Note

+

Requires the P3M feature.

+
+

This bond can be instantiated via +espressomd.interactions.BondedCoulombSRBond:

+
import espressomd.interactions
+subtr_p3m_sr = espressomd.interactions.BondedCoulombSRBond(q1q2=<float>)
+
+
+

The parameter q1q2 sets the charge factor of the short-range P3M interaction. +It can differ from the actual particle charges. This specialized bond can be +used to cancel or add only the short-range electrostatic part +of the P3M solver. A use case is described in Particle polarizability with thermalized cold Drude oscillators.

+
+
+

8.1.6. Rigid bonds

+
+

Note

+

Requires BOND_CONSTRAINT feature.

+
+

A rigid bond can be instantiated via +espressomd.interactions.RigidBond:

+
import espressomd.interactions
+rig = espressomd.interactions.RigidBond(r=<float>, ptol=<float>, vtol=<float> )
+
+
+

To simulate rigid bonds, ESPResSo uses the Rattle Shake algorithm which satisfies +internal constraints for molecular models with internal constraints, +using Lagrange multipliers.[Andersen, 1983] The constrained bond distance +is named r, the positional tolerance is named ptol and the velocity tolerance +is named vtol.

+
+
+

8.1.7. Thermalized distance bond

+

A thermalized bond can be instantiated via +espressomd.interactions.ThermalizedBond:

+
import espressomd.interactions
+thermalized_bond = espressomd.interactions.ThermalizedBond(
+    temp_com=<float>, gamma_com=<float>,
+    temp_distance=<float>, gamma_distance=<float>,
+    r_cut=<float>, seed=<int>)
+system.bonded_inter.add(thermalized_bond)
+
+
+

This bond can be used to apply Langevin thermalization on the centre of mass +and the distance of a particle pair. Each thermostat can have its own +temperature and friction coefficient.

+

The bond is closely related to simulating Particle polarizability with thermalized cold Drude oscillators.

+
+
+

8.1.8. Tabulated distance

+

A tabulated bond length can be instantiated via +espressomd.interactions.TabulatedDistance:

+
import espressomd.interactions
+tab_dist = espressomd.interactions.TabulatedDistance(
+    min=<min>, max=<max>, energy=<energy>, force=<force>)
+system.bonded_inter.add(tab_dist)
+p1.add_bond((tab_dist, p2))
+
+
+

This creates a bond type identifier with a tabulated potential. The force acts +in the direction of the connecting vector between the particles. The bond breaks +above the tabulated range, but for distances smaller than the tabulated range, +a linear extrapolation based on the first two tabulated force values is used. +For details of the interpolation, see Tabulated interaction.

+
+
+

8.1.9. Virtual bonds

+

A virtual bond can be instantiated via +espressomd.interactions.Virtual:

+
import espressomd.interactions
+vb = espressomd.interactions.Virtual()
+
+
+

This creates a virtual bond type identifier for a pair bond +without associated potential or force. It can be used to specify topologies +and for some analysis that rely on bonds, or for bonds that should be +displayed in the visualizer.

+
+
+
+

8.2. Bond-angle interactions

+

Bond-angle interactions involve three particles forming the angle \(\phi\), as shown in the schematic below.

+
+Bond-angle interactions +
+

This allows for a bond type having an angle-dependent potential. This potential +is defined between three particles and depends on the angle \(\phi\) +between the vectors from the central particle to the two other particles.

+

Similar to other bonded interactions, these are defined for every particle triplet and must be added to a particle (see property bonds), in this case the central one. +For example, for the schematic with particles p0, p1 (central particle) and p2 the bond was defined using

+
p1.add_bond((bond_angle, p0, p2))
+
+
+

The parameter bond_angle is an instance of one of four possible bond-angle +classes, described below.

+
+

8.2.1. Harmonic angle potential

+

espressomd.interactions.AngleHarmonic

+

Equation:

+
+\[V(\phi) = \frac{K}{2} \left(\phi - \phi_0\right)^2.\]
+

\(K\) is the bending constant and \(\phi_0\) is the equilibrium bond +angle in radians ranging from 0 to \(\pi\).

+

Example:

+
import espressomd.interactions
+angle_harmonic = espressomd.interactions.AngleHarmonic(bend=1.0, phi0=2 * np.pi / 3)
+system.bonded_inter.add(angle_harmonic)
+p1.add_bond((angle_harmonic, p0, p2))
+
+
+
+
+

8.2.2. Cosine angle potential

+

espressomd.interactions.AngleCosine

+

Equation:

+
+\[V(\phi) = K \left[1 - \cos(\phi - \phi_0)\right]\]
+

\(K\) is the bending constant and \(\phi_0\) is the equilibrium bond +angle in radians ranging from 0 to \(\pi\).

+

Around \(\phi_0\), this potential is close to a harmonic one +(both are \(1/2(\phi-\phi_0)^2\) in leading order), but it is +periodic and smooth for all angles \(\phi\).

+

Example:

+
import espressomd.interactions
+angle_cosine = espressomd.interactions.AngleCosine(bend=1.0, phi0=2 * np.pi / 3)
+system.bonded_inter.add(angle_cosine)
+p1.add_bond((angle_cosine, p0, p2))
+
+
+
+
+

8.2.3. Harmonic cosine potential

+

espressomd.interactions.AngleCossquare

+

Equation:

+
+\[V(\phi) = \frac{K}{2} \left[\cos(\phi) - \cos(\phi_0)\right]^2\]
+

\(K\) is the bending constant and \(\phi_0\) is the equilibrium bond +angle in radians ranging from 0 to \(\pi\).

+

This form is used for example in the GROMOS96 force field. The +potential is \(1/8(\phi-\phi_0)^4\) around \(\phi_0\), and +therefore much flatter than the two aforementioned potentials.

+

Example:

+
import espressomd.interactions
+angle_cossquare = espressomd.interactions.AngleCossquare(bend=1.0, phi0=2 * np.pi / 3)
+system.bonded_inter.add(angle_cossquare)
+p1.add_bond((angle_cossquare, p0, p2))
+
+
+
+
+

8.2.4. Tabulated angle potential

+

A tabulated bond angle can be instantiated via +espressomd.interactions.TabulatedAngle:

+
import espressomd.interactions
+theta = np.linspace(0, np.pi, num=91, endpoint=True)
+angle_tab =  espressomd.interactions.TabulatedAngle(
+    energy=10 * (theta - 2 * np.pi / 3)**2,
+    force=10 * (theta - 2 * np.pi / 3) / 2)
+system.bonded_inter.add(angle_tab)
+p1.add_bond((angle_tab, p0, p2))
+
+
+

The energy and force tables must be sampled from \(0\) to \(\pi\), +where \(\pi\) corresponds to a flat angle. The forces are scaled with the +inverse length of the connecting vectors. The force on the extremities acts +perpendicular to the connecting vector between the corresponding particle and +the center particle, in the plane defined by the three particles. The force on +the center particle balances the other two forces. +For details of the interpolation, see Tabulated interaction.

+
+
+
+

8.3. Dihedral interactions

+
+

8.3.1. Dihedral potential with phase shift

+

Dihedral interactions are available through the espressomd.interactions.Dihedral class:

+
import espressomd.interactions
+dihedral = espressomd.interactions.Dihedral(bend=<K>, mult=<n>, phase=<phi_0>)
+system.bonded_inter.add(dihedral)
+p2.add_bond((dihedral, p1, p3, p4))
+
+
+

This creates a bond type identifier with a dihedral potential, a +four-body-potential. In the following, let the particle for which the +bond is created be particle \(p_2\), and the other bond partners +\(p_1\), \(p_3\), \(p_4\), in this order. Then, the +dihedral potential is given by

+
+\[V(\phi) = K\left[1 - \cos(n\phi - \phi_0)\right],\]
+

where \(n\) is the multiplicity of the potential (number of minima) and can +take any integer value (typically from 1 to 6), \(\phi_0\) is a phase +parameter and \(K\) is the bending constant of the potential. \(\phi\) is +the dihedral angle between the particles defined by the particle +quadruple \(p_1\), \(p_2\), \(p_3\) and \(p_4\), the +angle between the planes defined by the particle triples \(p_1\), +\(p_2\) and \(p_3\) and \(p_2\), \(p_3\) and +\(p_4\):

+
+Dihedral interaction +
+

Together with appropriate Lennard-Jones interactions, this potential can +mimic a large number of atomic torsion potentials.

+

Note that there is a singularity in the forces, but not in the energy, when +\(\phi = 0\) and \(\phi = \pi\).

+
+
+

8.3.2. Tabulated dihedral potential

+

A tabulated dihedral interaction can be instantiated via +espressomd.interactions.TabulatedDihedral:

+
import espressomd.interactions
+dihedral_tab = espressomd.interactions.TabulatedDihedral(energy=<energy>, force=<force>)
+system.bonded_inter.add(dihedral_tab)
+p2.add_bond((dihedral_tab, p1, p3, p4))
+
+
+

The energy and force tables must be sampled from \(0\) to \(2\pi\). +For details of the interpolation, see Tabulated interaction.

+

Note that there is a singularity in the forces, but not in the energy, when +\(\phi = 0\) and \(\phi = \pi\).

+
+
+
+

8.4. Immersed Boundary Method interactions

+

Elastic forces for the Immersed Boundary Method (IBM). With the IBM, soft +particles are modelled as a triangulated surface. Each vertex has an +associated particle, and neighboring particles have bonded interactions. +When the surface is deformed by external forces, elastic forces restore +the original geometry [Krüger, 2012].

+
+

8.4.1. IBM local forces

+
+

8.4.1.1. Shear

+

espressomd.interactions.IBM_Triel

+

Compute elastic shear forces. To setup an interaction, use:

+
tri1 = IBM_Triel(ind1=0, ind2=1, ind3=2, elasticLaw="Skalak", k1=0.1, k2=0, maxDist=2.4)
+
+
+

where ind1, ind2 and ind3 represent the indices of the three +marker points making up the triangle. The parameter maxDist specifies +the maximum stretch above which the bond is considered broken. The parameter +elasticLaw can be either "NeoHookean" or "Skalak". +The parameters k1 and k2 are the elastic moduli.

+
+
+

8.4.1.2. Bending

+

espressomd.interactions.IBM_Tribend

+

Compute out-of-plane bending forces. To setup an interaction, use:

+
tribend = IBM_Tribend(ind1=0, ind2=1, ind3=2, ind4=3, kb=1, refShape="Initial")
+
+
+

where ind1, ind2, ind3 and ind4 are four marker points +corresponding to two neighboring triangles. The indices ind1 and ind3 +contain the shared edge. Note that the marker points within a triangle must +be labelled such that the normal vector +\(\vec{n} = (\vec{r}_\text{ind2} - \vec{r}_\text{ind1}) \times (\vec{r}_\text{ind3} - \vec{r}_\text{ind1})\) +points outward of the elastic object. The reference (zero energy) shape +can be either "Flat" or the initial curvature "Initial". +The bending modulus is kb.

+
+
+
+

8.4.2. IBM global forces

+
+

8.4.2.1. Volume conservation

+

espressomd.interactions.IBM_VolCons

+

Compute the volume-conservation force. Without this correction, the volume +of the soft object tends to shrink over time due to numerical inaccuracies. +Therefore, this implements an artificial force intended to keep the volume +constant. If volume conservation is to be used for a given soft particle, +the interaction must be added to every marker point belonging to that object:

+
volCons = IBM_VolCons(softID=1, kappaV=kV)
+
+
+

where softID identifies the soft particle and kappaV is a volumetric +spring constant. Note that this volCons bond does not have a bond partner. +It is added to a particle as follows:

+
system.part.by_id(0).add_bond((volCons,))
+
+
+

The comma is needed to create a tuple containing a single item.

+
+
+
+
+

8.5. Object-in-fluid interactions

+

Please cite [Cimrák et al., 2014] when using the interactions in this section in +order to simulate extended objects embedded in a LB fluid. For more details +please consult the dedicated OIF documentation available at +http://cell-in-fluid.fri.uniza.sk/en/content/oif-espresso.

+

The following interactions are implemented in order to mimic the +mechanics of elastic or rigid objects immersed in the LB fluid flow. +Their mathematical formulations were inspired by +[Dupin et al., 2007]. Details on how the bonds can be used for +modeling objects are described in section Object-in-fluid.

+
+

8.5.1. OIF local forces

+

OIF local forces are available through the espressomd.interactions.OifLocalForces class.

+

This type of interaction is available for closed 3D immersed objects flowing in the LB flow.

+

This interaction comprises three different concepts. The local +elasticity of biological membranes can be captured by three different +elastic moduli. Stretching of the membrane, bending of the membrane and +local preservation of the surface area. Parameters +\({L^0_{AB}},\ {k_s},\ {k_{s,\mathrm{lin}}}\) define the stretching, +parameters \(\phi,\ k_b\) define the bending, and +\(A_1,\ A_2,\ k_{al}\) define the preservation of local area. The +stretching force is applied first, followed by the bending force and +finally the local area force. They can be used all together, or, by setting +any of \(k_s, k_{s,\mathrm{lin}}, k_b, k_{al}\) to zero, the corresponding modulus +can be turned off.

+

OIF local forces are asymmetric. After creating the interaction

+
local_inter = OifLocalForces(r0=1.0, ks=0.5, kslin=0.0, phi0=1.7, kb=0.6,
+                             A01=0.2, A02=0.3, kal=1.1, kvisc=0.7)
+
+
+

it is important how the bond is created. Particles need to be mentioned +in the correct order. Command

+
p1.add_bond((local_inter, p0.part_id, p2.part_id, p3.part_id))
+
+
+

creates a bond related to the triangles 012 and 123. The particle 0 +corresponds to point A1, particle 1 to C, particle 2 to B and particle 3 +to A2. There are two rules that need to be fulfilled:

+
    +
  • there has to be an edge between particles 1 and 2

  • +
  • orientation of the triangle 012, that is the normal vector defined as +a vector product \(01 \times 02\) must point to the inside of +the immersed object.

  • +
+

Then the stretching force is applied to particles 1 and 2, with the +relaxed length being 1.0. The bending force is applied to preserve the +angle between triangles 012 and 123 with relaxed angle 1.7 and finally, +local area force is applied to both triangles 012 and 123 with relaxed +area of triangle 012 being 0.2 and relaxed area of triangle 123 being +0.3.

+
+

8.5.1.1. Stretching

+

For each edge of the mesh, \(L_{AB}\) is the current distance between point \(A\) and +point \(B\). \(L^0_{AB}\) is the distance between these points in the relaxed state, that +is if the current edge has this length exactly, then no forces are +added. \(\Delta L_{AB}\) is the deviation from the relaxed +state, that is \(\Delta L_{AB} = L_{AB} - L_{AB}^0\). The +stretching force between \(A\) and \(B\) is calculated using

+
+\[F_s(A,B) = (k_s\kappa(\lambda_{AB}) + k_{s,\mathrm{lin}})\Delta L_{AB}n_{AB}.\]
+

Here, \(n_{AB}\) is the unit vector pointing from \(A\) to \(B\), \(k_s\) is the +constant for nonlinear stretching, \(k_{s,\mathrm{lin}}\) is the constant for +linear stretching, \(\lambda_{AB} = L_{AB}/L_{AB}^0\), and \(\kappa\) +is a nonlinear function that resembles neo-Hookean behavior

+
+\[\kappa(\lambda_{AB}) = \frac{\lambda_{AB}^{0.5} + \lambda_{AB}^{-2.5}} +{\lambda_{AB} + \lambda_{AB}^{-3}}.\]
+

Typically, one wants either nonlinear or linear behavior and therefore one of +\(k_s, k_{s,\mathrm{lin}}\) is zero. Nonetheless the interaction will work +if both constants are non-zero.

+
+_images/oif-stretching.png +
+
+
+

8.5.1.2. Bending

+

The tendency of an elastic object to maintain the resting shape is +achieved by prescribing the preferred angles between neighboring +triangles of the mesh.

+

Denote the angle between two triangles in the resting shape by +\(\theta^0\). For closed immersed objects, one always has to set the +inner angle. The deviation of this angle +\(\Delta \theta = \theta - \theta^0\) defines two bending forces for +two triangles \(A_1BC\) and \(A_2BC\)

+
+\[F_{bi}(A_iBC) = k_b \Delta \theta n_{A_iBC}\]
+

Here, \(n_{A_iBC}\) is the unit normal vector to the triangle \(A_iBC\). +The force \(F_{bi}(A_iBC)\) is assigned +to the vertex not belonging to the common edge. The opposite force +divided by two is assigned to the two vertices lying on the common edge. +This procedure is done twice, for \(i=1\) and for \(i=2\).

+

Notice that concave objects can be created with \(\theta^0 > \pi\).

+
+_images/oif-bending.png +
+
+
+

8.5.1.3. Local area conservation

+

This interaction conserves the area of the triangles in the triangulation. +The area constraint assigns the following shrinking/expanding force to +vertex \(A\):

+
+\[F_{AT} = k_{al} \vec{AT}\frac{\Delta S_\triangle}{t_a^2 + t_b^2 + t_c^2}\]
+

where \(\Delta S_\triangle\) is the difference between current \(S_\triangle\) +and area \(S^0\) of the triangle in relaxed state, \(T\) is the centroid of +the triangle, and \(t_a, t_b, t_c\) are the lengths of segments \(AT, BT, CT\), +respectively. Similarly the analogue forces are assigned to \(B\) and \(C\).

+
+_images/oif-arealocal.png +
+
+
+
+

8.5.2. OIF global forces

+

OIF global forces are available through the +espressomd.interactions.OifGlobalForces class.

+

This type of interaction is available solely for closed 3D immersed objects.

+

It comprises two concepts: preservation of global surface +and of volume of the object. The parameters \(S^0, k_{ag}\) +define preservation of the surface while parameters +\(V^0, k_{v}\) define volume preservation. They can be +used together, or, by setting either \(k_{ag}\) or \(k_{v}\) to +zero, the corresponding modulus can be turned off.

+

These interactions are symmetric. After the definition of the interaction by

+
global_force_interaction = OifGlobalForces(A0_g=65.3, ka_g=3.0, V0=57.0, kv=2.0)
+
+
+

the order of vertices is crucial. By the following command the bonds are +defined

+
p0.add_bond((global_force_interaction, p1.part_id, p2.part_id))
+
+
+

Triangle 012 must have correct orientation, that is the normal vector +defined by a vector product \(01\times02\) must point to the inside of +the immersed object.

+
+

8.5.2.1. Global area conservation

+

The global area conservation force is defined as

+
+\[F_{ag}(A) = k_{ag} \frac{S^{c} - S^{c}_0}{S^{c}_0} \cdot S_{ABC} \cdot \frac{t_{a}}{|t_a|^2 + |t_b|^2 + |t_c|^2},\]
+

where \(S^c\) denotes the current surface of the immersed object, \(S^c_0\) the surface in +the relaxed state, \(S_{ABC}\) is the surface of the triangle, \(T\) is the centroid of the triangle, and \(t_a, t_b, t_c\) are the lengths of segments \(AT, BT, CT\), respectively.

+
+
+

8.5.2.2. Volume conservation

+

The deviation of the objects volume \(V\) is computed from the volume +in the resting shape \(\Delta V = V - V^0\). For each triangle, the +following force is computed:

+
+\[F_v(ABC) = -k_v\frac{\Delta V}{V^0} S_{ABC} n_{ABC}\]
+

where \(S_{ABC}\) is the area of triangle \(ABC\), \(n_{ABC}\) is +the normal unit vector of the plane spanned by \(ABC\), and \(k_v\) +is the volume constraint coefficient. The volume of one immersed object +is computed from

+
+\[V = \sum_{ABC}S_{ABC}\ n_{ABC}\cdot h_{ABC},\]
+

where the sum is computed over all triangles of the mesh and \(h_{ABC}\) is the +normal vector from the centroid of triangle \(ABC\) to any plane which does not +cross the cell. The force \(F_v(ABC)\) is equally distributed to all three vertices +\(A, B, C.\)

+
+_images/oif-volcons.png +
+
+
+
+
+ + +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/doc4.2.2/inter_non-bonded.html b/doc4.2.2/inter_non-bonded.html new file mode 100644 index 0000000000..dca9e50b10 --- /dev/null +++ b/doc4.2.2/inter_non-bonded.html @@ -0,0 +1,755 @@ + + + + + + + + + 7. Non-bonded interactions — ESPResSo 4.2.2 documentation + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +
+

7. Non-bonded interactions

+

In ESPResSo, interactions are set up and investigated by the espressomd.interactions module. There are +mainly two types of interactions: non-bonded and bonded interactions.

+

Non-bonded interactions only depend on the type of the two particles +involved. This also applies to the electrostatic interaction; however, +due to its long-ranged nature, it requires special care and ESPResSo handles it +separately with a number of state-of-the-art algorithms. To specify particle +type and charge see Setting up particles.

+

A bonded interaction defines an interaction between a number of specific +particles; it only applies to the set of particles for which it has been +explicitly set. A bonded interaction between a set of particles has to +be specified explicitly by the command, while the command is used to +define the interaction parameters.

+
+

7.1. Isotropic non-bonded interactions

+

Non-bonded interaction are configured via the espressomd.interactions.NonBondedInteraction class, which is a member of espressomd.system.System:

+
system.non_bonded_inter[type1, type2]
+
+
+

This command defines an interaction between all particles of type type1 and +type2. Possible interaction types and their parameters are +listed below.

+

For many non-bonded interactions, it is possible to artificially cap the +forces, which often allows to equilibrate the system much faster. See +the subsection Capping the force during warmup for more details.

+
+

7.1.1. Tabulated interaction

+
+

Note

+

Feature TABULATED required.

+
+

The interface for tabulated interactions are implemented in the +TabulatedNonBonded class. They can be configured +via the following syntax:

+
system.non_bonded_inter[type1, type2].tabulated.set_params(
+    min='min', max='max', energy='energy', force='force')
+
+
+

This defines an interaction between particles of the types type1 and +type2 according to an arbitrary tabulated pair potential by linear interpolation. +force specifies the tabulated forces and energy the energies as a function of the +separation distance. force and energy have to have the same length \(N_\mathrm{points}\). +Take care when choosing the number of points, since a copy of each lookup +table is kept on each node and must be referenced very frequently. +The maximal tabulated separation distance also acts as the effective cutoff +value for the potential.

+

The values of \(r\) are assumed to be equally distributed between +\(r_\mathrm{min}\) and \(r_\mathrm{max}\) with a fixed distance +of \((r_\mathrm{max}-r_\mathrm{min})/(N_\mathrm{points}-1)\).

+
+
+

7.1.2. Lennard-Jones interaction

+
+

Note

+

Feature LENNARD_JONES required.

+
+

The interface for the Lennard-Jones interaction is implemented in +LennardJonesInteraction. The Lennard-Jones parameters +can be set via:

+
system.non_bonded_inter[type1, type2].lennard_jones.set_params(**kwargs)
+
+
+

This command defines the traditional (12-6)-Lennard-Jones interaction +between particles of the types type1 and type2. For a description of the input arguments +see LennardJonesInteraction. The potential is defined by

+
+\[\begin{split}\label{eq:lj} + V_\mathrm{LJ}(r) = + \begin{cases} + 4 \epsilon \left[ \left(\frac{\sigma}{r-r_\mathrm{off}}\right)^{12} + - \left(\frac{\sigma}{r-r_\mathrm{off}}\right)^6+c_\mathrm{shift}\right] + & \mathrm{if~} r_\mathrm{min}+r_\mathrm{off} < r < r_\mathrm{cut}+r_\mathrm{off}\\ + 0 + & \mathrm{otherwise} + \end{cases}.\end{split}\]
+

The traditional Lennard-Jones potential is the “work-horse” potential of +particle–particle interactions in coarse-grained simulations. It is a +simple model for the van-der-Waals interaction, and is attractive at +large distance, but strongly repulsive at short distances. +\(r_\mathrm{off} + \sigma\) corresponds to the sum of +the radii of the interaction particles. At this distance, the potential is +\(V_\mathrm{LJ}(r_\mathrm{off} + \sigma) = 4 \epsilon c_\mathrm{shift}\). +The minimum of the potential is at +\(V_\mathrm{LJ}(r_\mathrm{off} + +2^\frac{1}{6}\sigma) = +-\epsilon + 4 \epsilon c_\mathrm{shift}\). Beyond this value the interaction is attractive. +Beyond the distance \(r_\mathrm{cut}\) the potential is cut off and the interaction force is zero.

+

If \(c_\mathrm{shift}\) is set to the string 'auto', the shift will be +automatically computed such that the potential is continuous at the +cutoff radius.

+

The net force on a particle can be capped by using force capping, see +section Capping the force during warmup

+

An optional additional parameter can be used to restrict the interaction +from a minimal distance \(r_\mathrm{min}\). This is an +optional parameter, set to \(0\) by default.

+

A special case of the Lennard-Jones potential is the +Weeks–Chandler–Andersen (WCA) potential, which one obtains by putting +the cutoff into the minimum and shifting the potential to be continuous, choosing +\(r_\mathrm{cut}=2^\frac{1}{6}\sigma\) and \(c_\mathrm{shift}=\) 'auto'. The WCA +potential is purely repulsive, and is often used to mimic hard sphere repulsion.

+
+
+

7.1.3. Generic Lennard-Jones interaction

+
+

Note

+

Feature LENNARD_JONES_GENERIC required.

+
+

The interface for the generic Lennard-Jones interactions is implemented in +espressomd.interactions.GenericLennardJonesInteraction. They +are configured via the syntax:

+
system.non_bonded_inter[type1, type2].generic_lennard_jones.set_params(**kwargs)
+
+
+

This command defines a generalized version of the Lennard-Jones +interaction (see Lennard-Jones interaction) between particles of the +types type1 and type2. The potential is defined by

+
+\[\begin{split}\label{eq:lj-generic} + V_\mathrm{LJ}(r) = + \begin{cases} + \epsilon\left[b_1\left(\frac{\sigma}{r-r_\mathrm{off}}\right)^{e_1} + -b_2\left(\frac{\sigma}{r-r_\mathrm{off}}\right)^{e_2}+c_\mathrm{shift}\right] + & \mathrm{if~} r_\mathrm{min}+r_\mathrm{off} < r < r_\mathrm{cut}+r_\mathrm{off}\\ + 0 + & \mathrm{otherwise} + \end{cases}\ .\end{split}\]
+

Note that the prefactor 4 of the standard LJ potential is missing, so +the normal LJ potential is recovered for \(b_1=b_2=4\), +\(e_1=12\) and \(e_2=6\).

+

The optional LJGEN_SOFTCORE feature activates a softcore version of +the potential, where the following transformations apply: +\(\epsilon \rightarrow \lambda \epsilon\) and +\(r-r_\mathrm{off} \rightarrow \sqrt{(r-r_\mathrm{off})^2 + +(1-\lambda) \delta \sigma^2}\). \(\lambda\) allows to tune the strength of the +interaction, while \(\delta\) varies how smoothly the potential goes to zero as +\(\lambda\rightarrow 0\). Such a feature allows one to perform +alchemical transformations, where a group of atoms can be slowly turned +on/off during a simulation.

+
+
+

7.1.4. Weeks–Chandler–Andersen interaction

+
+

Note

+

Feature WCA required.

+
+

The interface for the Weeks–Chandler–Andersen interactions is implemented in +espressomd.interactions.WCAInteraction. They +are configured via the syntax:

+
system.non_bonded_inter[type1, type2].wca.set_params(**kwargs)
+
+
+

This command defines a Weeks-Chandler-Andersen interaction between particles of the +types type1 and type2. The potential is defined by

+
+\[\begin{split}\label{eq:wca} + V_\mathrm{WCA}(r) = + \begin{cases} + 4 \epsilon \left[ \left(\frac{\sigma}{r}\right)^{12} + - \left(\frac{\sigma}{r}\right)^6 + \frac{1}{4} \right] + & \mathrm{if~} r < \sigma 2^{\frac{1}{6}}\\ + 0 + & \mathrm{otherwise} + \end{cases}.\end{split}\]
+
+
+

7.1.5. Lennard-Jones cosine interaction

+
+

Note

+

Feature LJCOS and/or LJCOS2 required.

+
+

espressomd.interactions.LennardJonesCosInteraction and +espressomd.interactions.LennardJonesCos2Interaction specify +a Lennard-Jones interaction with cosine tail [Soddemann et al., 2001] +between particles of the types type1 and type2. They +are configured via the syntax:

+
system.non_bonded_inter[type1, type2].lennard_jones_cos.set_params(**kwargs)
+system.non_bonded_inter[type1, type2].lennard_jones_cos2.set_params(**kwargs)
+
+
+

The first variant behaves as follows: until the minimum of the Lennard-Jones +potential at \(r_\mathrm{min} = r_\mathrm{off} + 2^{\frac{1}{6}}\sigma\), it +behaves identical to the unshifted Lennard-Jones potential +(\(c_\mathrm{shift}=0\)). Between \(r_\mathrm{min}\) and \(r_\mathrm{cut}\), a cosine is used to +smoothly connect the potential to 0, i.e.,

+
+\[V(r)=\frac{1}{2}\epsilon\left(\cos\left[\alpha(r - r_\mathrm{off})^2 + \beta\right]-1\right),\]
+

where \(\alpha = \pi\left[(r_\mathrm{cut} - +r_\mathrm{off})^2-(r_\mathrm{min} - r_\mathrm{off})^2\right]^{-1}\) and +\(\beta = \pi - \left(r_\mathrm{min} - +r_\mathrm{off}\right)^2\alpha\).

+

In the second variant, the cutoff radius is +\(r_\mathrm{cut}=r_\mathrm{min} + \omega\), where +\(r_\mathrm{min} = r_\mathrm{off} + 2^{\frac{1}{6}}\sigma\) as in +the first variant. The potential between \(r_\mathrm{min}\) and +\(r_\mathrm{cut}\) is given by

+
+\[V(r)=-\epsilon\cos^2\left[\frac{\pi}{2\omega}(r - r_\mathrm{min})\right].\]
+

For \(r < r_\mathrm{min}\), \(V(r)\) is implemented as normal +Lennard-Jones interaction with \(c_\mathrm{shift} = 0\).

+

The net force on a particle can be capped by using force capping, see +section Capping the force during warmup

+
+
+

7.1.6. Smooth step interaction

+
+

Note

+

Feature SMOOTH_STEP required.

+
+

The interface for the smooth-step interaction is implemented in +espressomd.interactions.SmoothStepInteraction. The smooth-step parameters +can be set via:

+
system.non_bonded_inter[type1, type2].smooth_step.set_params(**kwargs)
+
+
+

This defines a smooth step interaction between particles of the types type1 +and type2, for which the potential is

+
+\[V(r)= \left(d/r\right)^n + \epsilon/(1 + \exp\left[2k_0 (r - \sigma)\right])\]
+

for \(r<r_\mathrm{cut}\), and \(V(r)=0\) elsewhere. With +\(n\) around 10, the first term creates a short range repulsion +similar to the Lennard-Jones potential, while the second term provides a +much softer repulsion. This potential therefore introduces two length +scales, the range of the first term, \(d\), and the range of +the second one, \(\sigma\), where in general \(d<\sigma\).

+
+
+

7.1.7. BMHTF potential

+
+

Note

+

Feature BMHTF_NACL required.

+
+

The interface for the smooth-step interaction is implemented in +espressomd.interactions.BMHTFInteraction. The parameters of the BMHTF potential +can be set via:

+
system.non_bonded_inter[type1, type2].bmhtf.set_params(**kwargs)
+
+
+

This defines an interaction with the short-ranged part of the +Born–Meyer–Huggins–Tosi–Fumi potential between particles of the types type1 +and type2, which is often used to simulate NaCl crystals. The potential is +defined by:

+
+\[V(r)= A\exp\left[B(\sigma - r)\right] - + C r^{-6} - D r^{-8} + \epsilon_\mathrm{shift},\]
+

where \(\epsilon_\mathrm{shift}\) is automatically chosen such that +\(V(r_\mathrm{cut})=0\). For +\(r\ge r_\mathrm{cut}\), the \(V(r)=0\).

+

For NaCl, the parameters should be chosen as follows:

+ ++++++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

types

\(A\) \(\left(\mathrm{kJ}/\mathrm{mol}\right)\)

\(B\) \(\left(\mathring{\mathrm{A}}^{-1}\right)\)

\(C\) \(\left(\mathring{\mathrm{A}}^6 \mathrm{kJ}/\mathrm{mol})\right)\)

\(D\) \(\left(\mathring{\mathrm{A}}^8 \mathrm{kJ}/\mathrm{mol}\right)\)

\(\sigma\) \(\left(\mathring{\mathrm{A}}\right)\)

Na-Na

25.4435

3.1546

101.1719

48.1771

2.34

Na-Cl

20.3548

3.1546

674.4793

837.0770

2.755

Cl-Cl

15.2661

3.1546

6985.6786

14031.5785

3.170

+

The cutoff can be chosen relatively freely because the potential decays +fast; a value around 10 seems reasonable.

+

In addition to this short ranged interaction, one needs to add a +Coulombic, long-ranged part. If one uses elementary charges, a charge of +\(q=+1\) for the Na-particles, and \(q=-1\) for the +Cl-particles, the corresponding prefactor of the Coulomb interaction is +\(\approx 1389.3549\,\mathrm{kJ}/\mathrm{mol}\).

+
+
+

7.1.8. Morse interaction

+
+

Note

+

Feature MORSE required.

+
+

The interface for the Morse interaction is implemented in +espressomd.interactions.MorseInteraction. The Morse interaction parameters +can be set via:

+
system.non_bonded_inter[type1, type2].morse.set_params(**kwargs)
+
+
+

This defines an interaction using the Morse potential between particles +of the types type1 and type2. It serves similar purposes as the Lennard-Jones +potential, but has a deeper minimum, around which it is harmonic. This +models the potential energy in a diatomic molecule.

+

For \(r < r_\mathrm{cut}\), this potential is given by

+
+\[V(r)=\epsilon\left(\exp\left[-2 \alpha \left(r - r_\mathrm{min}\right)\right] + - 2\exp\left[-\alpha\left(r - r_\mathrm{min}\right)\right]\right) - + \epsilon_\mathrm{shift},\]
+

where is again chosen such that \(V(r_\mathrm{cut})=0\). For +\(r\ge r_\mathrm{cut}\), the \(V(r)=0\).

+
+
+

7.1.9. Buckingham interaction

+
+

Note

+

Feature BUCKINGHAM required.

+
+

The interface for the Buckingham interaction is implemented in +espressomd.interactions.BuckinghamInteraction. The Buckingham interaction parameters +can be set via:

+
system.non_bonded_inter[type1, type2].morse.set_params(**kwargs)
+
+
+

This defines a Buckingham interaction between particles of the types type1 and type2, +for which the potential is given by

+
+\[V(r)= A \exp(-B r) - C r^{-6} - D r^{-4} + \epsilon_\mathrm{shift}\]
+

for \(r_\mathrm{discont} < r < r_\mathrm{cut}\). Below \(r_\mathrm{discont}\), +the potential is linearly continued towards \(r=0\), similarly to +force capping, see below. Above \(r=r_\mathrm{cut}\), the +potential is \(0\).

+
+
+

7.1.10. Soft-sphere interaction

+
+

Note

+

Feature SOFT_SPHERE required.

+
+

The interface for the soft-sphere interaction is implemented in +espressomd.interactions.SoftSphereInteraction. The Soft-sphere parameters +can be set via:

+
system.non_bonded_inter[type1, type2].soft_sphere.set_params(**kwargs)
+
+
+

This defines a soft-sphere interaction between particles of the types type1 +and type2, which is defined by a single power law:

+
+\[V(r)=a\left(r-r_\mathrm{offset}\right)^{-n}\]
+

for \(r<r_\mathrm{cut}\), and \(V(r)=0\) above. There is +no shift implemented currently, which means that the potential is +discontinuous at \(r=r_\mathrm{cut}\). Therefore energy +calculations should be used with great caution.

+
+
+

7.1.11. Hat interaction

+
+

Note

+

Feature HAT required.

+
+

The interface for the hat interaction is implemented in +espressomd.interactions.HatInteraction. The hat parameters +can be set via:

+
system.non_bonded_inter[type1, type2].hat.set_params(**kwargs)
+
+
+

This defines a simple force ramp between particles of two types. +The maximal force acts at zero distance and zero force is applied at +distances \(r_c\) and bigger. For distances smaller than \(r_c\), +the force is given by

+
+\[F(r)=F_{\text{max}} \cdot \left( 1 - \frac{r}{r_c} \right),\]
+

for distances exceeding \(r_c\), the force is zero.

+

The potential energy is given by

+
+\[V(r)=F_{\text{max}} \cdot (r-r_c) \cdot \left( \frac{r+r_c}{2r_c} - 1 \right),\]
+

which is zero for distances bigger than \(r_c\) and continuous at distance \(0\).

+

This is the standard conservative DPD potential and can be used in +combination with Dissipative Particle Dynamics (DPD).

+
+
+

7.1.12. Hertzian interaction

+
+

Note

+

Feature HERTZIAN required.

+
+

The interface for the Hertzian interaction is implemented in +espressomd.interactions.HertzianInteraction. The Hertzian interaction parameters +can be set via:

+
system.non_bonded_inter[type1, type2].hertzian.set_params(**kwargs)
+
+
+

This defines an interaction according to the Hertzian potential between +particles of the types type1 and type2. The Hertzian potential is defined by

+
+\[\begin{split}V(r)= + \begin{cases} \epsilon\left(1-\frac{r}{\sigma}\right)^{5/2} & r < \sigma\\ + 0 & r \ge \sigma. + \end{cases}\end{split}\]
+

The potential has no singularity and is defined everywhere; the +potential has a non-differentiable maximum at \(r=0\), where the force +is undefined.

+
+
+

7.1.13. Gaussian interaction

+
+

Note

+

Feature GAUSSIAN required.

+
+

The interface for the Gaussian interaction is implemented in +espressomd.interactions.GaussianInteraction. The Gaussian interaction parameters +can be set via:

+
system.non_bonded_inter[type1, type2].gaussian.set_params(**kwargs)
+
+
+

This defines an interaction according to the Gaussian potential between +particles of the types type1 and type2. The Gaussian potential is defined by

+
+\[\begin{split}V(r) = + \begin{cases} \epsilon\,e^{-\frac{1}{2}\left(\frac{r}{\sigma}\right)^{2}} + & r < r_\mathrm{cut}\\ + 0 & r \ge r_\mathrm{cut} + \end{cases}\end{split}\]
+

The Gaussian potential is smooth except at the cutoff, and has a finite +overlap energy of \(\epsilon\). It can be used to model overlapping +polymer coils.

+

Currently, there is no shift implemented, which means that the potential +is discontinuous at \(r=r_\mathrm{cut}\). Therefore use +caution when performing energy calculations. However, you can often +choose the cutoff such that the energy difference at the cutoff is less +than a desired accuracy, since the potential decays very rapidly.

+
+
+

7.1.14. DPD interaction

+
+

Note

+

Feature DPD required.

+
+

This is a special interaction that is to be used in conjunction with the +Dissipative Particle Dynamics (DPD) thermostat. +The parameters can be set via:

+
system.non_bonded_inter[type1, type2].dpd.set_params(**kwargs)
+
+
+

This command defines an interaction between particles of the types type1 and type2 +that contains velocity-dependent friction and noise according +to a temperature set by espressomd.thermostat.Thermostat.set_dpd(). +The parameters for the interaction are

+
    +
  • gamma

  • +
  • weight_function

  • +
  • k

  • +
  • r_cut

  • +
  • trans_gamma

  • +
  • trans_weight_function

  • +
  • trans_r_cut

  • +
+

which will be explained below. The interaction +only has an effect if the DPD thermostat is activated.

+

The interaction consists of a friction force \(\vec{F}_{ij}^{D}\) and +a random force \(\vec{F}_{ij}^R\) added to the other interactions +between particles \(i\) and \(j\). It is decomposed into a component +parallel and perpendicular to the distance vector \(\vec{r}_{ij}\) of the particle pair. +The friction force contributions of the parallel part are

+
+\[\vec{F}_{ij}^{D} = -\gamma_\parallel w_\parallel (r_{ij}) (\hat{r}_{ij} \cdot \vec{v}_{ij}) \hat{r}_{ij}\]
+

for the dissipative force and

+
+\[\vec{F}_{ij}^R = \sqrt{2 k_B T \gamma_\parallel w_\parallel (r_{ij}) } \eta_{ij}(t) \hat{r}_{ij}\]
+

for the random force. This introduces the friction coefficient \(\gamma_\parallel\) (parameter gamma) and the weight function +\(w_\parallel\). The thermal energy \(k_B T\) is not set by the interaction, +but by the DPD thermostat (espressomd.thermostat.Thermostat.set_dpd()) +to be equal for all particles. The weight function can be specified via the weight_function switch. +The possible values for weight_function are 0 and 1, corresponding to the +order of \(w_\parallel\):

+
+\[\begin{split}w_\parallel (r_{ij}) = \left\{ +\begin{array}{clcr} + 1 & , \; \text{weight_function} = 0 \\ + {( 1 - (\frac{r_{ij}}{r^\text{cut}_\parallel})^k} )^2 & , \; \text{weight_function} = 1 + \end{array} + \right.\end{split}\]
+

Both weight functions are set to zero for \(r_{ij}>r^\text{cut}_\parallel\) (parameter r_cut).

+

In case the weight_function 1 is selected the parameter k can be chosen. \(k = 1\) is the +default and recovers the linear ramp. \(k > 1\) enhances the dissipative nature of the interaction +and thus yields higher Schmidt numbers [Yaghoubi et al., 2015].

+

The random force has the properties

+
+\[<\eta_{ij}(t)> = 0 , <\eta_{ij}^\alpha(t)\eta_{kl}^\beta(t')> = \delta_{\alpha\beta} \delta_{ik}\delta_{jl}\delta(t-t')\]
+

and is numerically discretized to a random number \(\overline{\eta}\) for each spatial +component for each particle pair drawn from a uniform distribution +with properties

+
+\[<\overline{\eta}> = 0 , <\overline{\eta}\overline{\eta}> = 1/dt\]
+

For the perpendicular part, the dissipative and random force are calculated analogously

+
+\[\vec{F}_{ij}^{D} = -\gamma_\bot w^D (r_{ij}) (I-\hat{r}_{ij}\otimes\hat{r}_{ij}) \cdot \vec{v}_{ij}\]
+
+\[\vec{F}_{ij}^R = \sqrt{2 k_B T \gamma_\bot w_\bot (r_{ij})} (I-\hat{r}_{ij}\otimes\hat{r}_{ij}) \cdot \vec{\eta}_{ij}\]
+

and introduce the second set of parameters prefixed with trans_. +For \(w_\bot (r_{ij})\) (parameter trans_weight_function) +the same options are available as for \(w_\parallel (r_{ij})\).

+

Note: This interaction does not conserve angular momentum.

+

A more detailed description of the interaction can be found in [Soddemann et al., 2003].

+
+
+

7.1.15. Thole correction

+
+

Note

+

Requires features THOLE and ELECTROSTATICS.

+
+
+

Note

+

THOLE is only implemented for the P3M electrostatics solver.

+
+

The Thole correction is closely related to simulations involving +Particle polarizability with thermalized cold Drude oscillators. +In this context, it is used to correct for overestimation of +induced dipoles at short distances. Ultimately, it alters the short-range +electrostatics of P3M to result in a damped Coulomb interaction potential +\(V(r) = \frac{q_1 q_2}{r} \cdot (1- e^{-s r} (1 + \frac{s r}{2}) )\). The +Thole scaling coefficient \(s\) is related to the polarizabilities +\(\alpha\) and Thole damping parameters \(a\) of the interacting +species via \(s = \frac{ (a_i + a_j) / 2 }{ (\alpha_i \alpha_j)^{1/6} }\). +Note that for the Drude oscillators, the Thole correction should be applied +only for the dipole part \(\pm q_d\) added by the Drude charge and not on +the total core charge, which can be different for polarizable ions. Also note +that the Thole correction acts between all dipoles, intra- and intermolecular. +Again, the accuracy is related to the P3M accuracy and the split between +short-range and long-range electrostatics interaction. It is configured by:

+
system = espressomd.System(box_l=[1, 1, 1])
+system.non_bonded_inter[type_1,type_2].thole.set_params(scaling_coeff=<float>, q1q2=<float>)
+
+
+
+
with parameters:
    +
  • scaling_coeff: The scaling coefficient \(s\).

  • +
  • q1q2: The charge factor of the involved charges.

  • +
+
+
+

Because the scaling coefficient depends on the mixed polarizabilities and the +nonbonded interaction is controlled by particle types, each Drude charge with a +unique polarizability has to have a unique type. Each Drude charge type has +a Thole correction interaction with all other Drude charges and all Drude +cores, except the one it’s connected to. This exception is handled internally +by disabling Thole interaction between particles connected via Drude bonds. +Also, each Drude core has a Thole correction interaction with all other Drude +cores and Drude charges. To assist with the bookkeeping of mixed scaling +coefficients, the helper method add_drude_particle_to_core() (see +Particle polarizability with thermalized cold Drude oscillators) +collects all core types, Drude types and relevant parameters when a Drude +particle is created. The user already provided all the information when +setting up the Drude particles, so the simple call:

+
add_all_thole(<system>, <verbose>)
+
+
+

given the espressomd.System() object, uses this information to create all +necessary Thole interactions. The method calculates the mixed scaling +coefficient s and creates the non-bonded Thole interactions between the +collected types to cover all the Drude-Drude, Drude-core and core-core +combinations. No further calls of add_drude_particle_to_core() should +follow. Set verbose to True to print out the coefficients, charge factors +and involved types.

+

The samples folder contains the script /samples/drude_bmimpf6.py with a +fully polarizable, coarse grained ionic liquid where this approach is applied.

+
+
+
+

7.2. Anisotropic non-bonded interactions

+
+

7.2.1. Gay–Berne interaction

+
+

Note

+

Feature GAY_BERNE required.

+
+

The interface for a Gay–Berne interaction is provided by the +espressomd.interactions.GayBerneInteraction class. Interaction +parameters can be set via:

+
system.non_bonded_inter[type1, type2].gay_berne.set_params(**kwargs)
+
+
+

This defines a Gay–Berne potential for prolate and oblate particles +between particles types type1 and type2. The Gay–Berne potential is an +anisotropic version of the classic Lennard-Jones potential, with +orientational dependence of the range \(\sigma_0\) and the well-depth +\(\varepsilon_0\).

+

Assume two particles with orientations given by the unit vectors +\(\mathbf{\hat{u}}_i\) and \(\mathbf{\hat{u}}_j\) and +intermolecular vector \(\mathbf{r} = r\mathbf{\hat{r}}\). If +\(r<r_\mathrm{cut}\), then the interaction between these two +particles is given by

+
+\[V(\mathbf{r}_{ij}, \mathbf{\hat{u}}_i, \mathbf{\hat{u}}_j) = 4 + \varepsilon(\mathbf{\hat{r}}_{ij}, \mathbf{\hat{u}}_i, + \mathbf{\hat{u}}_j) \left( \tilde{r}_{ij}^{-12}-\tilde{r}_{ij}^{-6} + \right),\]
+

otherwise \(V(r)=0\). The reduced radius is

+
+\[\tilde{r}=\frac{r - \sigma(\mathbf{\hat{r}}, + \mathbf{\hat{u}}_i, \mathbf{\hat{u}}_j)+\sigma_0}{\sigma_0},\]
+

where

+
+\[\sigma( \mathbf{\hat{r}}, \mathbf{\hat{u}}_i, + \mathbf{\hat{u}}_j) = \sigma_{0} \left\{ 1 - \frac{1}{2} \chi \left[ + \frac{ \left( \mathbf{\hat{r}} \cdot \mathbf{\hat{u}}_i + + \mathbf{\hat{r}} \cdot \mathbf{\hat{u}}_j \right)^{2} } + {1 + \chi \mathbf{\hat{u}}_i \cdot \mathbf{\hat{u}}_j } + + \frac{ \left( \mathbf{\hat{r}} \cdot \mathbf{\hat{u}}_i - + \mathbf{\hat{r}} \cdot \mathbf{\hat{u}}_j \right)^{2} } + {1 - \chi \mathbf{\hat{u}}_i \cdot \mathbf{\hat{u}}_j} + \right] \right\}^{-\frac{1}{2}}\]
+

and

+
+\[\begin{split}\begin{gathered} + \varepsilon(\mathbf{\hat{r}}, \mathbf{\hat{u}}_i, + \mathbf{\hat{u}}_j) = \\ + \varepsilon_0 \left( 1- \chi^{2}(\mathbf{\hat{u}}_i + \cdot \mathbf{\hat{u}}_j)^{2} \right)^{-\frac {\nu}{2}} \left[1-\frac + {\chi'}{2} \left( \frac { (\mathbf{\hat{r}} \cdot + \mathbf{\hat{u}}_i+ \mathbf{\hat{r}} \cdot + \mathbf{\hat{u}}_j)^{2}} {1+\chi' \, \mathbf{\hat{u}}_i \cdot + \mathbf{\hat{u}}_j }+ \frac {(\mathbf{\hat{r}} \cdot + \mathbf{\hat{u}}_i-\mathbf{\hat{r}} \cdot + \mathbf{\hat{u}}_j)^{2}} {1-\chi' \, \mathbf{\hat{u}}_i \cdot + \mathbf{\hat{u}}_j } \right) \right]^{\mu}.\end{gathered}\end{split}\]
+

Note that contrary to the original paper [Gay and Berne, 1981], here +\(\varepsilon_0\) is not raised to the power of \(\nu\), +in agreement with the convention used in the Gay–Berne literature.

+

The parameters \(\chi = \left(k_1^{2} - 1\right)/\left(k_1^{2} + 1\right)\) +and \(\chi' = \left(k_2^{1/\mu} - 1\right)/\left(k_2^{1/\mu} + 1\right)\) +are responsible for the degree of anisotropy of the molecular properties. \(k_1\) is +the molecular elongation, and \(k_2\) is the ratio of the potential well depths for the +side-by-side and end-to-end configurations. The exponents and are adjustable +parameters of the potential. Several Gay–Berne parametrizations exist, the +original one being \(k_1 = 3\), \(k_2 = 5\), +\(\mu = 2\) and \(\nu = 1\).

+
+
+
+ + +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/doc4.2.2/introduction.html b/doc4.2.2/introduction.html new file mode 100644 index 0000000000..342105e2f9 --- /dev/null +++ b/doc4.2.2/introduction.html @@ -0,0 +1,1063 @@ + + + + + + + + + 1. Introduction — ESPResSo 4.2.2 documentation + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +
+

1. Introduction

+

ESPResSo is a simulation package designed to perform Molecular Dynamics (MD) and +Monte Carlo (MC) simulations. It is meant to be a universal tool for +simulations of a variety of soft matter systems. It features a +broad range of interaction potentials which opens up possibilities for +performing simulations using models with different levels of coarse-graining. +It also includes modern and efficient algorithms for treatment of +Electrostatics (P3M, MMM-type algorithms, constant potential +simulations, dielectric interfaces, …), hydrodynamic interactions +(DPD, Lattice-Boltzmann), +and magnetic interactions, only +to name a few. It is designed to exploit the capabilities of parallel +computational environments. The program is being continuously extended to keep +the pace with current developments both in the algorithms and software.

+

The kernel of ESPResSo is written in C++ with computational efficiency in mind. +Interaction between the user and the simulation engine is provided via a +Python scripting interface. This enables setup of arbitrarily complex +systems, with simulation parameters that can be modified at runtime.

+
+

1.1. Guiding principles

+

ESPResSo is a tool for performing computer simulation and this user guide describes +how to use this tool. However, it should be borne in mind that being able to +operate a tool is not sufficient to obtain physically meaningful results. It is +always the responsibility of the user to understand the principles behind the +model, simulation and analysis methods he or she is using.

+

It is expected that the users of ESPResSo and readers of this user guide have a +thorough understanding of simulation methods and algorithms they are planning +to use. They should have passed a basic course on molecular simulations or read +one of the renown textbooks, e.g. [Frenkel and Smit, 2002]. It is not necessary to +understand everything that is contained in ESPResSo, but it is inevitable to +understand all methods that you want to use. Using the program as a black box +without proper understanding of the background will most probably result in +wasted user and computer time with no useful output.

+

To enable future extensions, the functionality of the program is kept as +general as possible. It is modularized, so that extensions to some parts +of the program (e.g. implementing a new potential) can be done by modifying +or adding only a few files, leaving most of the code untouched.

+

Much emphasis is put on readability of the code. To cite a few examples, +hard-coded C-style for loops are generally avoided in favor of modern C++ +range-based for loops or STL accumulators and algorithms, and output +parameters are often avoided by returning a std::tuple. In addition, +vector algebra can be expressed in few lines of code thanks to the +Utils::Vector class that provides overloads for elementary operations, +the dot product, the cross product and operations with matrices.

+

Hand-in-hand with the extensibility and readability of the code comes the +flexibility of the whole program. On the one hand, it is provided by the +generalized functionality of its parts, avoiding highly specialized functions. +An example can be the implementation of the Generic Lennard-Jones potential +described in section Generic Lennard-Jones interaction where the user +can change all available parameters. Where possible, default values are +avoided, providing the user with the possibility of choice. ESPResSo cannot be +aware whether your particles are representing atoms or billiard balls, so it +cannot check if the chosen parameters make sense and it is the user’s +responsibility to make sure they do. In fact, ESPResSo can be used to play +billiard (see sample script samples/billiard.py)!

+

On the other hand, flexibility of ESPResSo stems from the employment of a scripting +language at the steering level. Apart from the ability to modify the simulation +and system parameters at runtime, many simple tasks which are not +computationally critical can be implemented at this level, without even +touching the C++ kernel. For example, simple problem-specific analysis routines +can be implemented in this way and made to interact with the simulation core. +Another example of the program’s flexibility is the possibility to integrate +system setup, simulation and analysis in one single control script. ESPResSo +provides commands to create particles and set up interactions between them. +Capping of forces helps prevent system blow-up when initially some particles +are placed on top of each other. Using the Python interface, one can simulate +the randomly set-up system with capped forces, interactively check whether it +is safe to remove the cap and switch on the full interactions and then perform +the actual productive simulation.

+
+
+

1.2. Basic program structure

+

As already mentioned, ESPResSo consists of two components. The simulation engine is +written in C++ for the sake of computational efficiency. The steering or +control level is interfaced to the kernel via an interpreter of Python +scripting languages.

+

The kernel performs all computationally demanding tasks. Before all, +integration of Newton’s equations of motion, including calculation of energies +and forces. It also takes care of internal organization of data, storing the +data about particles, communication between different processors or cells of +the cell-system. The kernel is modularized so that basic functions are accessed +via a set of well-defined lean interfaces, hiding the details of the complex +numerical algorithms.

+

The scripting interface (Python) is used to setup the system (particles, +boundary conditions, interactions, …), control the simulation, run analysis, +and store and load results. The user has at hand the full readability and +functionality of the scripting language. For instance, it is possible to use +the SciPy package for analysis and PyPlot for plotting. With a certain overhead +in efficiency, it can also be used to reject/accept new configurations in +combined MD/MC schemes. In principle, any parameter which is accessible from +the scripting level can be changed at any moment of runtime. In this way +methods like thermodynamic integration become readily accessible.

+

The focus of the user guide is documenting the scripting interface, its +behavior and use in the simulation. It only describes certain technical details +of implementation which are necessary for understanding how the script +interface works. Technical documentation of the code and program structure is +contained in the online wiki.

+
+
+

1.3. Basic python simulation script

+

In this section, a brief overview is given over the most important components +of the Python interface. Their usage is illustrated by short examples, which +can be put together to a demo script.

+

Imports

+

As usual, the Python script starts by importing the necessary modules. The +ESPResSo interface is contained in the espressomd Python module, which needs to be +imported, before anything related can be done.

+
import espressomd
+
+
+

This should be followed by further necessary imports of the example at hand:

+
import espressomd.interactions
+import espressomd.electrostatics
+
+
+

espressomd.System

+

Access to the simulation system is provided via the System class. As a +first step, an instance of this class needs to be created.

+
system = espressomd.System(box_l=[10, 10, 10])
+
+
+

Note that only one instance of the System class can be created due to +limitations in the simulation core. Properties of the System +class are used to access the parameters +concerning the simulation system such as box geometry, time step or +cell-system:

+
print(f"The box dimensions are {system.box_l}")
+system.time_step = 0.01
+system.cell_system.skin = 0.4
+
+
+

Particles

+

The particles in the simulation are accessed via system.part, an instance of the +ParticleList class. Use the add method to +create new particles:

+
part1 = system.part.add(pos=[1.0, 1.0, 1.0], type=0)
+part2 = system.part.add(pos=[1.0, 1.0, 2.0], type=0)
+
+
+

The individual particles are represented by instances of ParticleHandle which, as +demonstrated in the example above, can be stored as Python variables (part1 and part2). +The properties of the particle are implemented as Python properties and can be accessed and/or modified using +the respective ParticleHandle:

+
>>> print(part2.pos)
+[1.0, 1.0, 2.0]
+>>> part2.pos = [0.2, 2.0, 0.0]
+>>> print(part2.pos)
+[0.2, 2.0, 0.0]
+
+
+

It is also possible to loop over all particles:

+
for p in system.part:
+    print(f"Particle pos {p.pos}, type {p.type}")
+
+
+

Internally, each particle is automatically assigned a unique numerical id by ESPResSo. +Note that in principle it is possible to explicitly set this particle id (if not in use already) on particle creation. +Using the id, the respective particle can be accessed from the particle list:

+
>>> system.part.add(id=3, pos=[2.1, 1.2, 3.3], type=0)
+>>> system.part.by_id(3).pos = [1.0, 1.0, 2.0]
+>>> print(system.part.by_id(3).pos)
+[1.0, 1.0, 2.0]
+
+
+

For larger simulation setups, explicit handling of numerical ids can quickly +become confusing and is thus error-prone. We therefore highly recommend using +ParticleHandle instead wherever possible.

+

Properties of all particles +can be accessed via:

+
positions = system.part.all().pos
+
+
+

Interactions

+

In ESPResSo, interactions between particles usually fall in three categories:

+
    +
  • Non-bonded interactions are short-ranged interactions between all +pairs of particles of specified types. An example is the +Lennard-Jones interaction mimicking overlap repulsion and van-der-Waals attraction.

  • +
  • Bonded interactions act only between two specific particles. An +example is the harmonic bond between adjacent particles in a polymer +chain.

  • +
  • Long-range interactions act between all particles with specific +properties in the entire system. An example is the Coulomb +interaction.

  • +
+

Non-bonded interaction

+

Non-bonded interactions are represented as subclasses of +NonBondedInteraction, e.g. +LennardJonesInteraction. +Instances of these classes for a given pair of particle types are accessed via +the non_bonded_inter attribute of the System class. This sets up a Lennard-Jones +interaction between all particles of type 0 with the given parameters:

+
system.non_bonded_inter[0, 0].lennard_jones.set_params(
+    epsilon=1, sigma=1, cutoff=5.0, shift="auto")
+
+
+

Bonded interaction

+

Next, we add a pair of particles with a different type to later add +a harmonic bond between them:

+
part1 = system.part.add(pos=[7.0, 7.0, 7.0], type=1)
+part2 = system.part.add(pos=[7.0, 7.0, 8.0], type=1)
+
+
+

To set up a bonded interaction, first an instance of the appropriate +class is created with the desired parameters:

+
harmonic = espressomd.interactions.HarmonicBond(k=1.0, r_0=0.5)
+
+
+

Then, the bonded interaction is registered in the simulation core +by adding the instance to bonded_inter:

+
system.bonded_inter.add(harmonic)
+
+
+

Finally, the bond can be added to particles using the add_bond() +method of ParticleHandle with the instance of the bond class and the +instance of the partner particle:

+
part1.add_bond((harmonic, part2))
+
+
+

Charges

+

Now we demonstrate how to setup a pair of charged particles treated by the P3M +electrostatics solver. We start by adding the particles:

+
cation = system.part.add(pos=[4.0, 1.0, 1.0], type=2, q=1.0)
+anion = system.part.add(pos=[6.0, 1.0, 1.0], type=2, q=-1.0)
+
+
+

Long-range interactions and other methods that might be mutually exclusive +are treated as so-called actors. They are used by first creating an instance +of the desired actor:

+
p3m = espressomd.electrostatics.P3M(accuracy=1e-3, prefactor=1.0)
+
+
+

and then adding it to the system:

+
print("Tuning p3m ...")
+system.actors.add(p3m)
+
+
+

Integration

+

So far we just added particles and interactions, but did not propagate the +system. This is done by the integrator. It uses by default the velocity +Verlet algorithm and is already created by the system class. To perform an +integration step, just execute:

+
system.integrator.run(1)
+
+
+

Usually, the system is propagated for a number of steps in a loop alongside +with some analysis. In this last snippet, the different energy contributions +of the system are printed:

+
num_configs = 10
+num_steps = 1000
+
+for i in range(num_configs):
+    system.integrator.run(num_steps)
+    energy = system.analysis.energy()
+    print(f"System time: {system.time}")
+    print(f"Energy of the LJ interaction: {energy['non_bonded']}")
+    print(f"Energy of the harmonic bond: {energy['bonded']}")
+    print(f"Energy of the Coulomb interaction: {energy['coulomb']}")
+
+
+
+
+

1.4. Tutorials

+

There are a number of tutorials that introduce the use of ESPResSo for different +physical systems. You can also find the tutorials and related scripts in the +directory /doc/tutorials. +They are executed with the ipypresso script.

+

The following tutorials are available:

+
    +
  • lennard_jones: Modelling of a single-component and a two-component Lennard-Jones liquid.

  • +
  • visualization: Using the online visualizers of ESPResSo.

  • +
  • error_analysis: Statistical analysis of simulation results.

  • +
  • charged_system: Modelling of ion condensation around a charged rod.

  • +
  • ferrofluid: Modelling a colloidal suspension of magnetic particles.

  • +
  • lattice_boltzmann: Simulations including hydrodynamic interactions using the lattice-Boltzmann method.

  • +
  • raspberry_electrophoresis: Extended objects in a lattice-Boltzmann fluid, raspberry particles.

  • +
  • active_matter: Modelling of self-propelling particles.

  • +
  • electrokinetics: Modelling electrokinetics together with hydrodynamic interactions.

  • +
  • constant_pH: Modelling the titration of a weak acid using the constant pH method

  • +
+

The executed notebooks with solutions and plots are periodically deployed +online to the GitHub Pages.

+
+
+

1.5. Sample scripts

+

Several scripts that can serve as usage examples can be found in the +directory /samples. +They are executed with the pypresso script.

+

The following samples are available:

+
    +
  • +
    billiard.py

    ESPResSo 8Ball billiards game.

    +
    +
    +
  • +
  • +
    chamber_game.py

    Game based on Maxwell’s demon, a thought experiment used to teach statistical +thermodynamics. The user has to scoop particles from a chamber and guide them +to another chamber through a channel with the help of a snake controlled by a +gamepad or the keyboard. The particle imbalance between chambers creates +a pressure gradient that makes it harder to move particles to the chamber +with an excess of particles.

    +
    +
    +
  • +
  • +
    constraints.py

    Confine a polymer between two slabs and check that it cannot escape +them during the entire simulation.

    +
    +
    +
  • +
  • +
    dancing.py

    Stokesian Dynamics simulation of particle sedimentation. +Reproduce the trajectory in Figure 5b from [Durlofsky et al., 1987].

    +
    +
    +
  • +
  • +
    diffusion_coefficient.py

    Compare the diffusion coefficient of a single thermalized particle obtained +from the particle’s mean square displacement and the auto correlation +function of its velocity to the expected value. Uses the +Observables/Correlators framework.

    +
    +
    +
  • +
  • +
    dpd.py

    Set up a DPD fluid and calculate pressure as a function of the +varying density. The fluid is thermalized using a DPD thermostat.

    +
    +
    +
  • +
  • +
    drude_bmimpf6.py

    Particle polarization with cold Drude oscillators on a coarse-grained +simulation of the ionic liquid BMIM PF6.

    +
    +
    +
  • +
  • +
    ekboundaries.py

    Set up an electrokinetics (LB) fluid confined between charged walls.

    +
    +
    +
  • +
  • +
    electrophoresis.py

    Simulate electrophoresis of a linear polymer using the P3M electrostatics solver.

    +
    +
    +
  • +
  • +
    espresso_logo.py

    Build the ESPResSo logo with particles.

    +
    +
    +
  • +
  • +
    grand_canonical.py

    Perform a grand canonical simulation of a system in contact +with a salt reservoir while maintaining a constant chemical potential.

    +
    +
    +
  • +
  • +
    h5md.py

    Write ESPResSo trajectories in the H5MD format. See Writing H5MD-files.

    +
    +
    +
  • +
  • +
    h5md_trajectory.py

    Write ESPResSo trajectories in the H5MD format with a Lees-Edwards offset, +aperiodic boundaries and a fluctuating box size. Read the trajectory and +reconstruct the unfolded positions. See Writing H5MD-files for details.

    +
    +
    +
  • +
  • +
    immersed_boundary/sampleImmersedBoundary.py

    Simulate the motion of a spherical red blood cell-like particle advected +in a planar Poiseuille flow, with or without volume conservation. For more +details, see Immersed Boundary Method for soft elastic objects.

    +
    +
    +
  • +
  • +
    lb_profile.py

    Simulate the flow of a lattice-Boltzmann fluid past a cylinder, +obtain the velocity profile in polar coordinates and compare it +to the analytical solution.

    +
    +
    +
  • +
  • +
    lbf.py

    Set up a lattice-Boltzmann fluid and apply an external force density on it.

    +
    +
    +
  • +
  • +
    lj_liquid.py

    Simulate a Lennard-Jones fluid maintained at a fixed temperature +by a Langevin thermostat. Shows the basic features of how to:

    +
      +
    • set up system parameters, particles and interactions.

    • +
    • warm up and integrate.

    • +
    • write parameters, configurations and observables to files.

    • +
    +

    The particles in the system are of two types: type 0 and type 1. +Type 0 particles interact with each other via a repulsive WCA +interaction. Type 1 particles neither interact with themselves +nor with type 0 particles.

    +
    +
    +
  • +
  • +
    lj_liquid_distribution.py

    Set up a Lennard-Jones fluid maintained at a fixed temperature by a +Langevin thermostat. The particles in the system are of two types: +type 0 and type 1. Type 0 particles interact with each other via a +repulsive WCA interaction. Type 1 particles neither interact with +themselves nor with type 0 particles. The distribution of minimum +distances between particles of type 0 and type 1 is recorded with +distribution(). +See Particle distribution.

    +
    +
    +
  • +
  • +
    lj_liquid_structurefactor.py

    Set up a Lennard-Jones fluid maintained at a fixed temperature by a +Langevin thermostat. The particles in the system are of two types: +type 0 and type 1. Type 0 particles interact with each other via a +repulsive WCA interaction. Type 1 particles neither interact with +themselves nor with type 0 particles. The spherically averaged +structure factor of particles of type 0 and type 1 is calculated +with structure_factor(). +See Structure factor.

    +
    +
    +
  • +
  • +
    load_checkpoint.py

    Basic usage of the checkpointing feature. Show how to load the state of:

    +
      +
    • custom user variables.

    • +
    • non-bonded interactions.

    • +
    • particles.

    • +
    • P3M parameters.

    • +
    • thermostat.

    • +
    +
    +
    +
  • +
  • +
    MDAnalysisIntegration.py

    Show how to expose configuration to MDAnalysis at run time. The +functions of MDAnalysis can be used to perform some analysis or +convert the frame to other formats (CHARMM, GROMACS, …). For more +details, see Writing various formats using MDAnalysis.

    +
    +
    +
  • +
  • +
    minimal-charged-particles.py

    Simulate an equal number of positively and negatively charged particles +using the P3M solver. The system is maintained at a constant temperature +using a Langevin thermostat.

    +
    +
    +
  • +
  • +
    minimal-diamond.py

    Set up a diamond-structured polymer network.

    +
    +
    +
  • +
  • +
    minimal-polymer.py

    Set up a linear polymer.

    +
    +
    +
  • +
  • +
    object_in_fluid/motivation.py

    Simulate the motion of flexible red blood cells in a lattice-Boltzmann fluid +with solid obstacles. For more details, see Object-in-fluid.

    +
    +
    +
  • +
  • +
    observables_correlators.py

    Measure mean square displacements using the Observables/Correlators framework.

    +
    +
    +
  • +
  • +
    p3m.py

    Simulate a Lennard-Jones liquid with charges. The P3M method is used to +calculate electrostatic interactions.

    +
    +
    +
  • +
  • +
    reaction_ensemble_complex_reaction.py

    Guide for the reaction ensemble. The modeled reaction is +\(2\mathrm{A} + 3\mathrm{B} \leftrightarrow 4\mathrm{C} + 1\mathrm{D} + 3\mathrm{E}\).

    +
    +
    +
  • +
  • +
    reaction_methods.py

    Guide for the reaction ensemble and the constant pH ensemble. The modeled +reaction is \(\mathrm{AH} \leftrightarrow \mathrm{A}^- + \mathrm{H}^+\).

    +
    +
    +
  • +
  • +
    rigid_body.py

    Demonstrates the construction of a rigid object by means of the +VIRTUAL_SITES_RELATIVE feature.

    +
    +
    +
  • +
  • +
    save_checkpoint.py

    Basic usage of the checkpointing feature. Show how to write the state of:

    +
      +
    • custom user variables.

    • +
    • non-bonded interactions.

    • +
    • particles.

    • +
    • P3M parameters.

    • +
    • thermostat.

    • +
    +
    +
    +
  • +
  • +
    slice_input.py

    Illustrate how particles of interest can be accessed via slicing.

    +
    +
    +
  • +
  • +
    visualization_bonded.py

    Visualize the simulation of a linear polymer.

    +
    +
    +
  • +
  • +
    visualization_cellsystem.py

    Visualize the system cells and MPI domains. Run ESPResSo in parallel +to color particles by node. With OpenMPI, this can be achieved using +mpiexec -n 4 ./pypresso ../samples/visualization_cellsystem.py. +Set property system.cell_system.node_grid = [i, j, k] (with i * j * k +equal to the number of MPI ranks) to change the way the cellsystem is +partitioned. Only the domain of MPI rank 0 will be shown in wireframe.

    +
    +
    +
  • +
  • +
    visualization_charged.py

    Visualize a simulation with a pool of particles with various charges, +LJ parameters and masses.

    +
    +
    +
  • +
  • +
    visualization_constraints.py

    Visualize shape-based constraints interacting with a Lennard-Jones gas.

    +
    +
    +
  • +
  • +
    visualization_elc.py

    Visualize charged particles confined between two plates of a capacitor with +a potential difference. The system is periodic in the xy-plane but has a gap +in the z-direction. The ELC method subtracts the electrostatic contribution +from the periodic images in the z-direction. The system total charge is zero. +For more details, see Electrostatic Layer Correction (ELC).

    +
    +
    +
  • +
  • +
    visualization_interactive.py

    Visualize a simulation box where the particles can be repositioned via the +mouse and timed callbacks, and the temperature of the thermostat can be +changed via the keyboard.

    +
    +
    +
  • +
  • +
    visualization_lbboundaries.py

    Visualize lattice-Boltzmann boundary nodes.

    +
    +
    +
  • +
  • +
    visualization_ljliquid.py

    Visualize a Lennard-Jones liquid with live plotting via matplotlib.

    +
    +
    +
  • +
  • +
    visualization_npt.py

    Visualize particle dumbbells in the NpT ensemble (constant temperature, +constant pressure, variable volume).

    +
    +
    +
  • +
  • +
    visualization_poiseuille.py

    Visualize the Poiseuille flow in a lattice-Boltzmann fluid with an +external force applied.

    +
    +
    +
  • +
  • +
    widom_insertion.py

    Measure the excess chemical potential of a charged WCA fluid via Widom’s +insertion method.

    +
    +
    +
  • +
+
+
+

1.6. On units

+

What is probably one of the most confusing subjects for beginners of ESPResSo is, +that ESPResSo does not predefine any units. While most MD programs specify a set +of units, like, for example, that all lengths are measured in Ångström +or nanometers, times are measured in nano- or picoseconds and energies +are measured in \(\mathrm{kJ/mol}\), ESPResSo does not do so.

+

Instead, the length-, time- and energy scales can be freely chosen by +the user. Once these three scales are fixed, all remaining units are +derived from these three basic choices.

+

The probably most important choice is the length scale. A length of +\(1.0\) can mean a nanometer, an Ångström, or a kilometer - +depending on the physical system, that the user has in mind when he +writes his ESPResSo-script. When creating particles that are intended to +represent a specific type of atoms, one will probably use a length scale +of Ångström. This would mean, that the parameter \(\sigma\) of the +Lennard-Jones interaction between two atoms would be set to twice the +van-der-Waals radius of the atom in Ångström. Alternatively, one could +set \(\sigma\) to \(2.0\) and measure all lengths in multiples +of the van-der-Waals radius. When simulation colloidal particles, which +are usually of micrometer size, one will choose their diameter (or +radius) as basic length scale, which is much larger than the Ångström +scale used in atomistic simulations.

+

The second choice to be made is the energy scale. One can for example +choose to set the Lennard-Jones parameter \(\epsilon\) to the energy +in \(\mathrm{kJ/mol}\). Then all energies will be measured in that +unit. Alternatively, one can choose to set it to \(1.0\) and measure +everything in multiples of the van-der-Waals binding energy of the +respective particles.

+

The final choice is the time (or mass) scale. By default, ESPResSo uses a reduced +mass of 1 for all particles, so that the mass unit is simply the mass of one particle. +Combined with the energy and length scale, this is sufficient to derive +the resulting time scale:

+
+\[[\mathrm{time}] = [\mathrm{length}]\sqrt{\frac{[\mathrm{mass}]}{[\mathrm{energy}]}}\]
+

This means, that if you measure lengths in Ångström, energies in +\(k_B T\) at 300K and masses in 39.95u, then your time scale is +\(\mathring{A} \sqrt{39.95u / k_B T} = 0.40\,\mathrm{ps}\).

+

On the other hand, if you want a particular time scale, then the mass +scale can be derived from the time, energy and length scales as

+
+\[[\mathrm{mass}] = [\mathrm{energy}]\frac{[\mathrm{time}]^2}{[\mathrm{length}]^2}.\]
+

By activating the feature MASS, you can specify particle masses in +the chosen unit system.

+

A special note is due regarding the temperature, which is coupled to the +energy scale by Boltzmann’s constant. However, since ESPResSo does not enforce a +particular unit system, we also don’t know the numerical value of the +Boltzmann constant in the current unit system. Therefore, when +specifying the temperature of a thermostat, you actually do not define +the temperature, but the value of the thermal energy \(k_B T\) in +the current unit system. For example, if you measure energy in units of +\(\mathrm{kJ/mol}\) and your real temperature should be 300K, then +you need to set the thermostat’s effective temperature to +\(k_B 300\, K \mathrm{mol / kJ} = 2.494\).

+

As long as one remains within the same unit system throughout the whole +ESPResSo-script, there should be no problems.

+
+
+

1.7. Available simulation methods

+

ESPResSo provides a number of useful methods. The following table shows the +various methods as well as their status. The table distinguishes between +the state of the development of a certain feature and the state of its +use. We distinguish between five levels:

+
+
Core

means that the method is part of the core of ESPResSo, and that it is +extensively developed and used by many people.

+
+
Good

means that the method is developed and used by independent people +from different groups.

+
+
Group

means that the method is developed and used in one group.

+
+
Single

means that the method is developed and used by one person only.

+
+
None

means that the method is developed and used by nobody.

+
+
Experimental

means that the method might have side effects.

+
+
+

In the “Tested” column, we note whether there is an integration test for the method.

+

If you believe that the status of a certain method is wrong, please +report so to the developers using the instructions in Contributing.

+ ++++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Feature

Development Status

Usage Status

Tested

Integrators, Thermostats, Barostats

Velocity-Verlet Integrator

Core

Core

Yes

Langevin Thermostat

Core

Core

Yes

Isotropic NpT

Experimental

None

Yes

Quaternion Integrator

Core

Good

Yes

Stokesian Dynamics

Single

None

Yes

Interactions

Short-range Interactions

Core

Core

Yes

Constraints

Core

Core

Yes

Relative Virtual Sites

Good

Good

Yes

RATTLE Rigid Bonds

Single

Group

Yes

Gay–Berne Interaction

Experimental

Experimental

Yes

Coulomb Interaction

P3M

Core

Core

Yes

P3M on GPU

Single

Single

Yes

Dipolar P3M

Group

Good

Yes

MMM1D

Single

Good

No

MMM1D on GPU

Single

Single

No

ELC

Good

Good

Yes

ICC*

Group

Group

Yes

Hydrodynamic Interaction

Lattice-Boltzmann

Core

Core

Yes

Lattice-Boltzmann on GPU

Group

Core

Yes

Input/Output

VTF output

Core

Core

Yes

VTK output

Group

Group

No

Checkpointing

Experimental

Experimental

Yes

Visualization

OpenGL visualizer

Good

Good

No

Miscellaneous

Electrokinetics

Group

Group

Yes

Collision Detection

Group

Group

Yes

Reaction Ensemble

Group

Group

Yes

Constant pH Method

Group

Group

Yes

Object-in-fluid

Group

Group

Yes

Immersed boundary method

Group

Group

Yes

DPD

Single

Good

Yes

DPD Thermostat

Single

Good

Yes

+
+
+

1.8. Software releases

+

ESPResSo releases use the following versioning scheme: major.minor.patch_level. +New features are introduced in major and minor releases, while bugfix releases +only patch bugs without adding or removing features. Since the patch_level +doesn’t affect the capabilities of the software, it’s common to refer to +releases simply as major.minor.

+

New users should always choose the latest release. When opting for an +older release, we recommend using the latest bugfix release from that +line (for example 4.0.2 instead of 4.0), unless you need to capture the +behavior of bugs for reproducibility reasons. When filing bug reports +or citing ESPResSo, the version should always be mentioned. See +our policies on bug reports and +citing the software for more details.

+

Releases from 4.0 onward can be found on +GitHub. +Older releases from 2.1 to 3.3 can be found in +GNU Savannah. +See our policy on API backward compatibility +if you need more details.

+
+

1.8.1. Release workflow

+

Major and minor releases are branched from the development branch python. +When a version X.Y.0 is released, the python branch is copied +to a new branch named X.Y, at which point the python branch is ready +to accept contributions for the X.Y+1.0 release. The X.Y branch +still gets bugfix releases X.Y.1, X.Y.2, …, for several months.

+

GitHub milestones +track the progress of each release. They can give you an idea of the changes +in future releases, although it’s more convenient to follow the live release +notes in the wiki (listed +under “Planned releases” in the side bar). These notes are updated monthly. +Most users will only be interested in the live release notes of the +planned bugfix release for the version of ESPResSo they’re using.

+

If you’re actively developing code for ESPResSo, you might also be interested in +the summaries of the ESPResSo meetings, +where the core team discusses plans for future releases and feature freezes.

+
+
+

1.8.2. Intended interface compatibility between ESPResSo versions

+

With regards to the stability of the Python interface, we have the following +guidelines:

+
    +
  • patch_level: The Python interface will not change if only the +patch_level number is different. Example: 4.0.0 \(\to\) 4.0.1.

  • +
  • minor: There will be no silent interface changes between two versions +with different minor numbers, i.e. a simulation script will not silently +produce different results with the new version. The interface can, however, +be extended. In important cases, the interface can change in such a way +that using the old interface produces a clear error message and the +simulation is terminated. Example: 4.0.2 \(\to\) 4.1.0.

  • +
  • major: No guarantees are made for a transition between major versions. +Example: 4.1.2 \(\to\) 5.0.

  • +
  • No guarantees are made with regards to the development branch on GitHub.

  • +
  • No guarantees are made with respect to the C++ bindings in the simulation core.

  • +
+
+
+

1.8.3. How to cite ESPResSo

+

Please cite Weik et al. [2019] (BibTeX key weik19a in doc/bibliography.bib) +for ESPResSo 4.0 and later, or both Arnold et al. [2013] and Limbach et al. [2006] +(BibTeX keys arnold13a and limbach06a in doc/bibliography.bib) +for ESPResSo 2.0 to 3.3. To find the version number, use the following command:

+
./pypresso -c "import espressomd.version;print(espressomd.version.friendly())"
+
+
+

A number of algorithms in ESPResSo are fairly advanced and unique to ESPResSo. +The authors of these contributions kindly ask you to cite the relevant +publications, using the BibTeX entries indicated in this user guide.

+

A complete citation would look like this:

+
+

Simulations were carried out with ESPResSo 4.2[24] using the ICC* +algorithm[25].

+
+
____________
+
+
+
[24] F. Weik, R. Weeber, K. Szuttor et al. ESPResSo 4.0 – an +extensible software package for simulating soft matter systems. +Eur. Phys. J. Spec. Top. 227, 1789–1816 (2019). +doi:10.1140/epjst/e2019-800186-9.
+
[25] C. Tyagi, M. Süzen, M. Sega et al. An iterative, fast, +linear-scaling method for computing induced charges on arbitrary +dielectric boundaries. J. Chem. Phys. 132, 154112 (2010). +doi:10.1063/1.3376011.
+
+
+

You may also provide the patch level, when relevant. If you developed code +for ESPResSo and made it available in a publicly accessible repository, you +should consider providing the corresponding URL, for example in a footnote:

+
+

The method was implemented for ESPResSo 4.2.2[24] and the source code is +available onlinenote 1.

+
+
____________
+
+ +
+
[24] F. Weik, R. Weeber, K. Szuttor et al. ESPResSo 4.0 – an +extensible software package for simulating soft matter systems. +Eur. Phys. J. Spec. Top. 227, 1789–1816 (2019). +doi:10.1140/epjst/e2019-800186-9.
+
+
+
+
+
+ + +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/doc4.2.2/io.html b/doc4.2.2/io.html new file mode 100644 index 0000000000..396ab62c54 --- /dev/null +++ b/doc4.2.2/io.html @@ -0,0 +1,555 @@ + + + + + + + + + 16. Input and Output — ESPResSo 4.2.2 documentation + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +
+

16. Input and Output

+
+

16.1. Checkpointing and restoring a simulation

+

One of the most asked-for feature that seems to be missing is +checkpointing, a simple way to store and restore the current +state of the simulation, and to be able to write this state to or read +it from a file. This would be most useful to be able to restart a +simulation from a specific point in time.

+

Unfortunately, it is impossible to provide a simple command +(checkpoint), out of two reasons. The main reason is that it has no +way to determine what information constitutes the actual state of the +simulation. Scripts sometimes use variables that +contain essential information about a simulation: the stored values of +an observable that was computed in previous time steps, counters, etc. +These would have to be contained in a checkpoint. However, not all +variables are of interest.

+

Another problem with a generic checkpoint would be the control flow of +the script. In principle, the checkpoint would have to store where in +the script the checkpointing function was called to be able to return +there. All this is even further complicated by the fact that ESPResSo is +running in parallel.

+

Having said that, ESPResSo does provide functionality which aims to store the state of the simulation engine. +In addition, variables declared in the simulation script can be added to the checkpoint. +The checkpoint data can then later be restored by calling one +load function that will automatically process the checkpoint data by +setting the user variables and restore the components of the simulation. +Furthermore, the checkpointing can be triggered by system signals that +are invoked for example when the simulation is aborted by the user or by +a timeout.

+

The checkpointing functionality is difficult to test for all possible simulation setups. Therefore, it is to be used with care. +It is strongly recommended to keep track of the times in the simulation run where a checkpoint was written and restored and manually verify that the observables of interest do not jump or drift after restoring the checkpoint. +Moreover, please carefully read the limitations mentioned below.

+

Checkpointing is implemented by the espressomd.checkpointing.Checkpoint class. It is instanced as follows:

+
import espressomd
+import espressomd.checkpointing
+checkpoint = espressomd.checkpointing.Checkpoint(checkpoint_id="mycheckpoint", checkpoint_path=".")
+
+
+

Here, checkpoint_id denotes the identifier for a checkpoint. Legal characters for an id +are “0-9”, “a-zA-Z”, “-”, “_”. +The parameter checkpoint_path, specifies the relative or absolute path where the checkpoints are +stored. The current working directory is assumed, when this parameter is skipped.

+

After the simulation system and user variables are set up, they can be +registered for checkpointing. +Name the string of the object or user variable that should be registered for +checkpointing.

+

To give an example:

+
my_var = "some variable value"
+system = espressomd.System(box_l=[100.0, 100.0, 100.0])
+# ... set system properties like time_step here ...
+checkpoint.register("system")
+checkpoint.register("my_var")
+# ...
+
+
+

will register the user variable my_var and the instance of the simulation system. The checkpoint can be saved via:

+
checkpoint.save()
+
+
+

To trigger the checkpoint when Ctrl+C is pressed during a running simulation, the corresponding signal has to be registered:

+
import signal
+# signal.SIGINT: signal 2, is sent when ctrl+c is pressed
+checkpoint.register_signal(signal.SIGINT)
+
+
+

In the above example checkpointing is triggered, when the user interrupts by +pressing Ctrl+C. In this case a new checkpoint is written and the simulation +quits.

+

An existing checkpoint can be loaded with:

+
import espressomd
+import espressomd.checkpointing
+import signal
+
+checkpoint = espressomd.checkpointing.Checkpoint(checkpoint_id="mycheckpoint")
+checkpoint.load()
+
+
+

This will restore the state of the objects registered for checkpointing. +The checkpointing instance itself will also be restored. I.e., the same +variables will be registered for the next checkpoint and the same system +signals will be caught as in the initial setup of the checkpointing.

+

Be aware of the following limitations:

+
    +
  • Checkpointing makes use of the pickle python package. Objects will only +be restored as far as they support pickling. This is the case for Python’s +basic data types, numpy arrays and many other objects. Still, pickling +support cannot be taken for granted.

  • +
  • Pickling of the espressomd.system.System instance and +contained objects such as bonded and non-bonded interactions and +electrostatics methods is covered by basic tests. However, not all +combinations of algorithms can be tested. If you encounter an issue +for a specific combination of features, please share your findings +with the ESPResSo community.

  • +
  • The active actors, i.e., the content of system.actors, are checkpointed. +For lattice-Boltzmann fluids, this only includes the parameters such as the +lattice constant (agrid). The actual flow field has to be saved +separately with the lattice-Boltzmann specific methods +espressomd.lb.HydrodynamicInteraction.save_checkpoint() +and loaded via espressomd.lb.HydrodynamicInteraction.load_checkpoint() +after restoring the checkpoint. See LB checkpointing +for more details.

  • +
  • References between Python objects are not maintained during checkpointing. +For example, if an instance of a shape and an instance of a constraint +containing the shape are checkpointed, these two objects are equal before +checkpointing but independent copies which have the same parameters after +restoring the checkpoint. Changing one will no longer affect the other.

  • +
  • The state of the cell system as well as the MPI node grid are checkpointed. +Therefore, checkpoints can only be loaded, when the script runs on the same +number of MPI ranks.

  • +
  • Checkpoints are not compatible between different ESPResSo versions.

  • +
  • Checkpoints may depend on the presence of other Python modules at specific +versions. It may therefore not be possible to load a checkpoint in a +different environment than where it was written.

  • +
  • To be fully deterministic when loading from a checkpoint with an active +thermostat, the first step of the integration should be called with the flag +reuse_forces=True, e.g. system.integrator.run(2, reuse_forces=True). +This is because loading a checkpoint reinitializes the system and enforces +a recalculation of the forces. However, this computes the forces from the +velocities at the current time step and not at the previous half time step. +Please note that long-range actors can make trajectories non-reproducible. +For example, lattice-Boltzmann introduces errors of the order of 1e-15 with +binary checkpoint files, or 1e-7 with ASCII checkpoint files. In addition, +several electrostatic and magnetostatic actors automatically introduce +a deviation of the order of 1e-7, either due to floating-point rounding +errors (P3MGPU), or due to re-tuning +using the most recent system state (MMM1D, +MMM1DGPU). +When in doubt, you can easily verify the absence of a “force jump” when +loading from a checkpoint by replacing the electrostatics actor with your +combination of features in files samples/save_checkpoint.py and +samples/load_checkpoint.py and running them sequentially.

  • +
+

For additional methods of the checkpointing class, see +espressomd.checkpointing.Checkpoint.

+
+
+

16.2. Writing H5MD-files

+
+

Note

+

Requires H5MD external feature, enabled with -DWITH_HDF5=ON. Also +requires a parallel version of HDF5. On Ubuntu, this can be installed via +either libhdf5-openmpi-dev for OpenMPI or libhdf5-mpich-dev for +MPICH, but not libhdf5-dev which is the serial version.

+
+

For long simulations, it’s a good idea to store data in the hdf5 file format +(see https://www.hdfgroup.org for details, H5MD is based on hdf5). +Currently ESPResSo supports some basic functions for writing simulation +data to H5MD files. The implementation is MPI-parallelized and is capable +of dealing with a varying number of particles.

+

To write data in a hdf5-file according to the H5MD proposal +(https://nongnu.org/h5md), first an object of the class +espressomd.io.writer.h5md.H5md has to be created and linked to the +respective hdf5-file. This may, for example, look like:

+
import espressomd.io.writer.h5md
+system = espressomd.System(box_l=[100.0, 100.0, 100.0])
+# ... add particles here
+h5 = espressomd.io.writer.h5md.H5md(file_path="trajectory.h5")
+
+
+

An optional argument to the constructor of espressomd.io.writer.h5md.H5md is +an instance of espressomd.io.writer.h5md.UnitSystem which encapsulates +physical units for time, mass, length and electrical charge.

+

If a file at the given filepath exists and has a valid H5MD structure, +it will be backed up to a file with suffix “.bak” and loaded into +a new file. Therefore H5MD can be used together with checkpointing. +The backup file will be deleted when the new file is closed at the end of the +simulation with close(). The backup +file is not be erased if the simulation terminates unexpectedly.

+

To write data to the HDF5 file, simply call the method +write() without any arguments. +After the last write, call flush() +and then close() +to close the datasets and remove the backup file.

+

The current implementation writes the following properties by default: folded +positions, periodic image count, velocities, forces, species (ESPResSo types), +charges and masses of the particles. While folded positions are written +to disk, the unfolded coordinates can be reconstructed from the image count. +The time-dependent box size and Lees-Edwards parameters are also stored. +Some of these properties can be opted out by specifying in argument +fields the subset of fields to write to the trajectory file; +call method valid_fields() +to find out which string corresponds to which field.

+

In simulations with a varying number of particles (Monte-Carlo reactions), the +size of the dataset will be adapted if the maximum number of particles +increases but will not be decreased. Instead a negative fill value will +be written to the trajectory for the id.

+

If you have a parallel +simulation, please keep in mind that the sequence of particles in general +changes from timestep to timestep. Therefore you have to always use the +dataset for the ids to track which position/velocity/force/type/mass +entry belongs to which particle.

+

For an example involving physical units, see /samples/h5md.py.

+
+
+

16.3. Reading H5MD-files

+

H5MD files can be read and sometimes modified by many tools. If the data was +stored with physical units, +they can be accessed by reading the group attributes. Since the data is +written in parallel, the particles are unsorted; if particles were created +with increasing particle id and no particle deletion occurred during the +simulation, the coordinates can be sorted with a simply numpy operation.

+

To read with the python module h5py (documentation: +HDF5 for Python):

+
import h5py
+with h5py.File("sample.h5", mode='r') as h5file:
+    positions = h5file['particles/atoms/position/value']
+    positions.attrs['unit']
+    forces = h5file['particles/atoms/force/value']
+    forces_unit = forces.attrs['unit']
+    sim_time = h5file['particles/atoms/id/time']
+    print(f"last frame: {sim_time[-2]:.3f} {sim_time.attrs['unit'].decode('utf8')}")
+
+
+

To read with the python module pandas (documentation: HDFStore: PyTables):

+
import pandas
+with pandas.HDFStore("sample.h5", mode='r') as h5file:
+    positions = h5file.root.particles.atoms.position.value
+    positions.attrs['unit']
+    forces = h5file.root.particles.atoms.force.value
+    forces_unit = forces.attrs['unit']
+    sim_time = h5file.root.particles.atoms.id.time
+    print(f"last frame: {sim_time[-2]:.3f} {sim_time.attrs['unit'].decode('utf8')}")
+
+
+

To read from the command line with +h5dump +(Ubuntu package hdf5-tools):

+
# show metadata only
+h5dump --header sample.h5 | less
+# show metadata + data
+h5dump sample.h5 | less
+
+
+

H5MD files can also be inspected with the GUI tool +HDFView (Ubuntu package +hdfview) or visually with the H5MD VMD plugin (GitHub project +h5md/VMD-h5mdplugin).

+

For an example involving h5py, coordinates resorting and reconstruction +of the unfolded coordinates, see /samples/h5md_trajectory.py.

+
+
+

16.4. Writing MPI-IO binary files

+

This method outputs binary data in parallel and is, thus, also suitable for +large-scale simulations. Generally, H5MD is the preferred method because the +data is easily accessible. In contrast to H5MD, the MPI-IO functionality +outputs data in a machine-dependent format, but has write and read +capabilities. The usage is quite simple:

+
import espressomd
+import espressomd.io
+system = espressomd.System(box_l=[1, 1, 1])
+# ... add particles here
+mpiio = espressomd.io.mpiio.Mpiio()
+mpiio.write("/tmp/mydata", positions=True, velocities=True, types=True, bonds=True)
+
+
+

Here, /tmp/mydata is the prefix used to generate several files. +The call will output particle positions, velocities, types and their bonds +to the following files in folder /tmp:

+
    +
  • mydata.head

  • +
  • mydata.id

  • +
  • mydata.pos

  • +
  • mydata.pref

  • +
  • mydata.type

  • +
  • mydata.vel

  • +
  • mydata.boff

  • +
  • mydata.bond

  • +
+

Depending on the chosen output, not all of these files might be created. +To read these in again, simply call espressomd.io.mpiio.Mpiio.read(). +It has the same signature as espressomd.io.mpiio.Mpiio.write(). +When writing files, make sure the prefix hasn’t been used before +(e.g. by a different simulation script), otherwise the write operation +will fail to avoid accidentally overwriting pre-existing data. Likewise, +reading incomplete data (or complete data but with the wrong number of MPI +ranks) will throw an error.

+

WARNING: Do not attempt to read these binary files on a machine +with a different architecture! This will read malformed data without +necessarily throwing an error.

+

In case of read failure or write failure, the simulation will halt. +On 1 MPI rank, the simulation will halt with a python runtime error. +This exception can be recovered from; in case of a write operation, +any written file must be deleted before attempting to write again +(since the prefix argument must be unique). On more than 1 MPI rank, +the simulation will halt with a call to MPI_Abort and will send +the SIGABRT signal.

+
+
+

16.5. Writing VTF files

+

The formats VTF (VTF Trajectory Format), VSF +(VTF Structure Format) and VCF (VTF +Coordinate Format) are formats for the visualization +software VMD: [Humphrey et al., 1996]. They are intended to +be human-readable and easy to produce automatically and modify.

+

The format distinguishes between structure blocks that contain the +topological information of the system (the system size, particle names, +types, radii and bonding information, amongst others), while coordinate +blocks (a.k.a. as timestep blocks) contain the coordinates for the +particles at a single timestep. For a visualization with VMD, one +structure block and at least one coordinate block is required.

+

Files in the VSF format contain a single structure block, files in the +VCF format contain at least one coordinate block, while files in the VTF +format contain a single structure block (usually as a header) and an arbitrary number of +coordinate blocks (time frames) afterwards, thus allowing to store all information for +a whole simulation in a single file. For more details on the format, +refer to the VTF homepage (https://github.com/olenz/vtfplugin/wiki).

+

Creating files in these formats from within is supported by the commands espressomd.io.writer.vtf.writevsf() +and espressomd.io.writer.vtf.writevcf(), that write a structure and coordinate block (respectively) to the +given file. To create a standalone VTF file, first use writevsf at the beginning of +the simulation to write the particle definitions as a header, and then writevcf +to generate a timeframe of the simulation state. For example:

+

A standalone VTF file can simply be

+
import espressomd
+import espressomd.io.writer.vtf
+system = espressomd.System(box_l=[100.0, 100.0, 100.0])
+fp = open('trajectory.vtf', mode='w+t')
+
+# ... add particles here
+
+# write structure block as header
+espressomd.io.writer.vtf.writevsf(system, fp)
+# write initial positions as coordinate block
+espressomd.io.writer.vtf.writevcf(system, fp)
+
+# integrate and write the frame
+for n in num_steps:
+    system.integrator.run(100)
+    espressomd.io.writer.vtf.writevcf(system, fp)
+fp.close()
+
+
+

The structure definitions in the VTF/VSF formats are incremental, the user +can easily add further structure lines to the VTF/VSF file after a +structure block has been written to specify further particle properties +for visualization.

+

Note that the ids of the particles in ESPResSo and VMD may differ. VMD requires +the particle ids to be enumerated continuously without any holes, while +this is not required in ESPResSo. When using writevsf +and writevcf, the particle ids are +automatically translated into VMD particle ids. The function allows the +user to get the VMD particle id for a given ESPResSo particle id.

+

One can specify the coordinates of which particles should be written using types. +If types='all' is used, all coordinates will be written (in the ordered timestep format). +Otherwise, has to be a list specifying the pids of the particles.

+

Also note, that these formats can not be used to write trajectories +where the number of particles or their types varies between the +timesteps. This is a restriction of VMD itself, not of the format.

+
+

16.5.1. writevsf: Writing the topology

+

espressomd.io.writer.vtf.writevsf()

+

Writes a structure block describing the system’s structure to the given channel, for example:

+
import espressomd
+import espressomd.io.writer.vtf
+system = espressomd.System(box_l=[100.0, 100.0, 100.0])
+# ... add particles here
+fp = open('trajectory.vsf', mode='w+t')
+espressomd.io.writer.vtf.writevsf(system, fp, types='all')
+
+
+

The output of this command can be +used for a standalone VSF file, or at the beginning of a VTF file that +contains a trajectory of a whole simulation.

+
+
+

16.5.2. writevcf: Writing the coordinates

+

espressomd.io.writer.vtf.writevcf()

+

Writes a coordinate (or timestep) block that contains all coordinates of +the system’s particles.

+
import espressomd
+import espressomd.io.writer.vtf
+system = espressomd.System(box_l=[100.0, 100.0, 100.0])
+# ... add particles here
+fp = open('trajectory.vcf', mode='w+t')
+espressomd.io.writer.vtf.writevcf(system, fp, types='all')
+
+
+
+
+

16.5.3. vtf_pid_map: Going back and forth between ESPResSo and VTF indexing

+

espressomd.io.writer.vtf.vtf_pid_map()

+

Generates a dictionary which maps ESPResSo particle id to VTF indices. +This is motivated by the fact that the list of ESPResSo particle id is allowed to contain holes but VMD +requires increasing and continuous indexing. The ESPResSo id can be used as key to obtain the VTF index as the value, for example:

+
import espressomd
+import espressomd.io.writer.vtf
+system = espressomd.System(box_l=[100.0, 100.0, 100.0])
+system.part.add(id=5, pos=[0, 0, 0])
+system.part.add(id=3, pos=[0, 0, 0])
+vtf_index = espressomd.io.writer.vtf.vtf_pid_map(system)
+vtf_index[3]
+
+
+

Note that the ESPResSo particles are ordered in increasing order, thus id=3 corresponds to the zeroth VTF index.

+
+
+
+

16.6. Writing various formats using MDAnalysis

+

If the MDAnalysis package (https://mdanalysis.org) is installed, it +is possible to use it to convert frames to any of the supported +configuration/trajectory formats, including PDB, GROMACS, GROMOS, +CHARMM/NAMD, AMBER, LAMMPS, …

+

To use MDAnalysis to write in any of these formats, one has first to prepare a stream from +the ESPResSo particle data using the class espressomd.MDA_ESP, and then read from it +using MDAnalysis. A simple example is the following:

+
import espressomd
+import MDAnalysis as mda
+import espressomd.MDA_ESP
+system = espressomd.System(box_l=[100.0, 100.0, 100.0])
+# ... add particles here
+eos = espressomd.MDA_ESP.Stream(system)  # create the stream
+u = mda.Universe(eos.topology, eos.trajectory)  # create the MDA universe
+
+# example: write a single frame to PDB
+u.atoms.write("system.pdb")
+
+# example: save the trajectory to GROMACS format
+from MDAnalysis.coordinates.TRR import TRRWriter
+W = TRRWriter("traj.trr", n_atoms=len(system.part))  # open the trajectory file
+for i in range(100):
+    system.integrator.run(1)
+    u.load_new(eos.trajectory)  # load the frame to the MDA universe
+    W.write_next_timestep(u.trajectory.ts)  # append it to the trajectory
+
+
+

For other examples, see /samples/MDAnalysisIntegration.py

+
+
+

16.7. Reading various formats using MDAnalysis

+

MDAnalysis can read various formats, including MD topologies and trajectories. +To read a PDB file containing a single frame:

+
import MDAnalysis
+import numpy as np
+import espressomd
+import espressomd.interactions
+
+# parse protein structure
+universe = MDAnalysis.Universe("protein.pdb")
+# extract only the C-alpha atoms of chain A
+chainA = universe.select_atoms("name CA and segid A")
+# use the unit cell as box
+box_l = np.ceil(universe.dimensions[0:3])
+# setup system
+system = espressomd.System(box_l=box_l)
+system.time_step = 0.001
+system.cell_system.skin = 0.4
+# configure sphere size sigma and create a harmonic bond
+system.non_bonded_inter[0, 0].lennard_jones.set_params(
+    epsilon=1, sigma=1.5, cutoff=2, shift="auto")
+system.bonded_inter[0] = espressomd.interactions.HarmonicBond(k=0.5, r_0=1.5)
+# create particles and add bonds between them
+system.part.add(pos=np.array(chainA.positions, dtype=float))
+for i in range(0, len(chainA) - 1):
+    system.part.by_id(i).add_bond((system.bonded_inter[0], i + 1))
+# visualize protein in 3D
+import espressomd.visualization
+visualizer = espressomd.visualization.openGLLive(system, bond_type_radius=[0.2])
+visualizer.run(0)
+
+
+
+
+ + +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/doc4.2.2/lb.html b/doc4.2.2/lb.html new file mode 100644 index 0000000000..850882e218 --- /dev/null +++ b/doc4.2.2/lb.html @@ -0,0 +1,486 @@ + + + + + + + + + 13. Lattice-Boltzmann — ESPResSo 4.2.2 documentation + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +
+

13. Lattice-Boltzmann

+

For an implicit treatment of a solvent, ESPResSo can couple the molecular +dynamics simulation to a lattice-Boltzmann fluid. The lattice-Boltzmann +method (LBM) is a fast, lattice-based method that, in its “pure” form, +allows to calculate fluid flow in different boundary conditions of +arbitrarily complex geometries. Coupled to molecular dynamics, +it allows for the computationally efficient inclusion of hydrodynamic +interactions into the simulation. The focus of the ESPResSo implementation +of the LBM is, of course, the coupling to MD and therefore available +geometries and boundary conditions are somewhat limited in comparison to +“pure” LB codes.

+

Here we restrict the documentation to the interface. For a more detailed +description of the method, please refer to the literature.

+
+

Note

+

Please cite [Arnold et al., 2013] (BibTeX key arnold13a in +doc/bibliography.bib) if you use the LB fluid and [Roehm and Arnold, 2012] +(BibTeX key rohm12a in doc/bibliography.bib) if you use +the GPU implementation.

+
+
+

13.1. Setting up a LB fluid

+

The following minimal example illustrates how to use the LBM in ESPResSo:

+
import espressomd
+import espressomd.lb
+system = espressomd.System(box_l=[10, 20, 30])
+system.time_step = 0.01
+system.cell_system.skin = 0.4
+lb = espressomd.lb.LBFluid(agrid=1.0, dens=1.0, visc=1.0, tau=0.01)
+system.actors.add(lb)
+system.integrator.run(100)
+
+
+

To use the GPU-accelerated variant, replace line 6 in the example above by:

+
lb = espressomd.lb.LBFluidGPU(agrid=1.0, dens=1.0, visc=1.0, tau=0.01)
+
+
+
+

Note

+

Feature CUDA required for the GPU-accelerated variant

+
+

To use the (much faster) GPU implementation of the LBM, use +LBFluidGPU in place of LBFluid. +Please note that the GPU implementation uses single precision floating point operations. +This decreases the accuracy of calculations compared to the CPU implementation. +In particular, due to rounding errors, the fluid density decreases over time, +when external forces, coupling to particles, or thermalization is used. +The loss of density is on the order of \(10^{-12}\) per time step.

+

The command initializes the fluid with a given set of parameters. It is +also possible to change parameters on the fly, but this will only rarely +be done in practice. Before being able to use the LBM, it is necessary +to set up a box of a desired size. The parameter is used to set the +lattice constant of the fluid, so the size of the box in every direction +must be a multiple of agrid.

+

In the following, we discuss the parameters that can be supplied to the LBM in ESPResSo. +The detailed interface definition is available at LBFluid.

+

The LB scheme and the MD scheme are not synchronized: In one LB time +step typically several MD steps are performed. This allows to speed up +the simulations and is adjusted with the parameter tau, the LB time step. +The parameters dens and visc set up the density and (kinematic) viscosity of the +LB fluid in (usual) MD units. Internally the LB implementation works +with a different set of units: all lengths are expressed in agrid, all times +in tau and so on. +LB nodes are located at 0.5, 1.5, 2.5, etc. +(in terms of agrid). This has important implications for the location of +hydrodynamic boundaries which are generally considered to be halfway +between two nodes for flat, axis-aligned walls. For more complex boundary geometries, +the hydrodynamic boundary location deviates from this midpoint and the deviation +decays to first order in agrid. The LBM should +not be used as a black box, but only after a careful check of all +parameters that were applied.

+

In the following, we describe a number of optional parameters. +Thermalization of the fluid (and particle coupling later on) can be activated by +providing a non-zero value for the parameter kT. Then, a seed has to be provided for +the fluid thermalization:

+
lbfluid = espressomd.lb.LBFluid(kT=1.0, seed=134, ...)
+
+
+

The parameter ext_force_density takes a three dimensional vector as an +array_like of float, representing a homogeneous external body force density in MD +units to be applied to the fluid. The parameter bulk_visc allows one to +tune the bulk viscosity of the fluid and is given in MD units. In the limit of +low Mach number, the flow does not compress the fluid and the resulting flow +field is therefore independent of the bulk viscosity. It is however known that +the value of the viscosity does affect the quality of the implemented +link-bounce-back method. gamma_even and gamma_odd are the relaxation +parameters for the kinetic modes. These fluid parameters do not correspond to +any macroscopic fluid properties, but do influence numerical properties of the +algorithm, such as the magnitude of the error at boundaries. Unless you are an +expert, leave their defaults unchanged. If you do change them, note that they +are to be given in LB units.

+

Before running a simulation at least the following parameters must be +set up: agrid, tau, visc, dens. For the other parameters, +the following are taken: bulk_visc=0, gamma_odd=0, gamma_even=0, +ext_force_density=[0, 0, 0].

+
+
+

13.2. Checkpointing

+
lb.save_checkpoint(path, binary)
+lb.load_checkpoint(path, binary)
+
+
+

The first command saves all of the LB fluid nodes’ populations to an ASCII +(binary=False) or binary (binary=True) format respectively. +The second command loads the LB fluid nodes’ populations. +In both cases path specifies the location of the +checkpoint file. This is useful for restarting a simulation either on the same +machine or a different machine. Some care should be taken when using the binary +format as the format of doubles can depend on both the computer being used as +well as the compiler. One thing that one needs to be aware of is that loading +the checkpoint also requires the user to reuse the old forces. This is +necessary since the coupling force between the particles and the fluid has +already been applied to the fluid. Failing to reuse the old forces breaks +momentum conservation, which is in general a problem. It is particularly +problematic for bulk simulations as the system as a whole acquires a drift of +the center of mass, causing errors in the calculation of velocities and +diffusion coefficients. The correct way to restart an LB simulation is to first +load in the particles with the correct forces, and use:

+
system.integrator.run(steps=number_of_steps, reuse_forces=True)
+
+
+

upon the first call integrator.run. This causes the +old forces to be reused and thus conserves momentum.

+
+
+

13.3. Interpolating velocities

+

To get interpolated velocity values between lattice nodes, the function:

+
lb.get_interpolated_velocity(pos=[1.1, 1.2, 1.3])
+
+
+

with a single position pos as an argument can be used. +For the GPU fluid espressomd.lb.LBFluidGPU, a method +get_interpolated_fluid_velocity_at_positions() +is also available, which expects a numpy array of positions as an argument.

+

By default, the interpolation is done linearly between the nearest 8 LB nodes, +but for the GPU implementation also a quadratic scheme involving 27 nodes is implemented +(see eqs. 297 and 301 in [Dünweg and Ladd, 2009]). +You can choose by calling +one of:

+
lb.set_interpolation_order('linear')
+lb.set_interpolation_order('quadratic')
+
+
+

A note on boundaries: +both interpolation schemes don’t take into account the physical location of the boundaries +(e.g. in the middle between two nodes for a planar wall) but will use the boundary node slip velocity +at the node position. This means that every interpolation involving at least one +boundary node will introduce an error.

+
+
+

13.4. Coupling LB to a MD simulation

+

MD particles can be coupled to a LB fluid through frictional coupling. The friction force

+
+\[F_{i,\text{frict}} = - \gamma (v_i(t)-u(x_i(t),t))\]
+

depends on the particle velocity \(v\) and the fluid velocity \(u\). It acts both +on the particle and the fluid (in opposite direction). Because the fluid is also affected, +multiple particles can interact via hydrodynamic interactions. As friction in molecular systems is +accompanied by fluctuations, the particle-fluid coupling has to be activated through +the Lattice-Boltzmann thermostat (see more detailed description there). A short example is:

+
system.thermostat.set_lb(LB_fluid=lbf, seed=123, gamma=1.5)
+
+
+

where lbf is an instance of either LBFluid or +LBFluidGPU, gamma the friction coefficient and +seed the seed for the random number generator involved +in the thermalization.

+
+
+

13.5. Reading and setting properties of single lattice nodes

+

Appending three indices to the lb object returns an object that represents +the selected LB grid node and allows one to access all of its properties:

+
lb[x, y, z].density              # fluid density (one scalar for LB and CUDA)
+lb[x, y, z].velocity             # fluid velocity (a numpy array of three floats)
+lb[x, y, z].pressure_tensor      # fluid pressure tensor (a symmetric 3x3 numpy array of floats)
+lb[x, y, z].pressure_tensor_neq  # nonequilibrium part of the pressure tensor (as above)
+lb[x, y, z].boundary             # flag indicating whether the node is fluid or boundary (fluid: boundary=0, boundary: boundary != 0)
+lb[x, y, z].population           # 19 LB populations (a numpy array of 19 floats, check order from the source code)
+
+
+

All of these properties can be read and used in further calculations. +Only the property population can be modified. The indices x, y, z +are integers and enumerate the LB nodes in the three Cartesian directions, +starting at 0. To modify boundary, refer to Setting up boundary conditions.

+

Example:

+
print(lb[0, 0, 0].velocity)
+lb[0, 0, 0].density = 1.2
+
+
+

The first line prints the fluid velocity at node (0 0 0) to the screen. +The second line sets this fluid node’s density to the value 1.2.

+

The nodes can be read and modified using slices. Example:

+
print(lb[0:4:2, 0:2, 0].velocity)
+lb[0:4:2, 0:2, 0].density = [[[1.1], [1.2]], [[1.3], [1.4]]]
+
+
+

The first line prints an array of shape (2, 2, 1, 3) with the velocities +of nodes (0 0 0), (0 1 0), (2 0 0), (2 1 0). The second line updates +these nodes with densities ranging from 1.1 to 1.4. You can set either +a value that matches the length of the slice (which sets each node +individually), or a single value that will be copied to every node +(e.g. a scalar for density, or an array of length 3 for the velocity).

+
+
+

13.6. Output for visualization

+

ESPResSo implements a number of commands to output fluid field data of the whole fluid into a file at once.

+
lb.write_vtk_velocity(path)
+lb.write_vtk_boundary(path)
+lb.write_velocity(path)
+lb.write_boundary(path)
+
+
+

Currently supported fluid properties are the velocity, and boundary flag in ASCII VTK as well as Gnuplot compatible ASCII output.

+

The VTK format is readable by visualization software such as ParaView 1 +or Mayavi2 2. If you plan to use ParaView for visualization, note that also the particle +positions can be exported using the VTK format (see writevtk()).

+

The variant

+
lb.write_vtk_velocity(path, bb1, bb2)
+
+
+

allows you to only output part of the flow field by specifying an axis aligned +bounding box through the coordinates bb1 and bb1 (lists of three ints) of two of its corners. This +bounding box can be used to output a slice of the flow field. As an +example, executing

+
lb.write_vtk_velocity(path, [0, 0, 5], [10, 10, 5])
+
+
+

will output the cross-section of the velocity field in a plane +perpendicular to the \(z\)-axis at \(z = 5\) (assuming the box +size is 10 in the \(x\)- and \(y\)-direction).

+
+
+

13.7. Choosing between the GPU and CPU implementations

+

ESPResSo contains an implementation of the LBM for NVIDIA +GPUs using the CUDA framework. On CUDA-supporting machines this can be +activated by compiling with the feature CUDA. Within the +Python script, the LBFluid object can be substituted +with the LBFluidGPU object to switch from CPU based +to GPU based execution. For further +information on CUDA support see section CUDA acceleration.

+

The following minimal example demonstrates how to use the GPU implementation +of the LBM in analogy to the example for the CPU given in section +Setting up a LB fluid:

+
import espressomd
+system = espressomd.System(box_l=[10, 20, 30])
+system.time_step = 0.01
+system.cell_system.skin = 0.4
+lb = espressomd.lb.LBFluidGPU(agrid=1.0, dens=1.0, visc=1.0, tau=0.01)
+system.actors.add(lb)
+system.integrator.run(100)
+
+
+

For boundary conditions analogous to the CPU +implementation, the feature LB_BOUNDARIES_GPU has to be activated. +Lees–Edwards boundary conditions are not supported by either +LB implementation.

+
+
+

13.8. Electrohydrodynamics

+
+

Note

+

This needs the feature LB_ELECTROHYDRODYNAMICS.

+
+

If the feature is activated, the lattice-Boltzmann code can be +used to implicitly model surrounding salt ions in an external electric +field by having the charged particles create flow.

+

For that to work, you need to set the electrophoretic mobility +(multiplied by the external \(E\)-field) \(\mu E\) on the +particles that should be subject to the field. This effectively acts +as a velocity offset between the particle and the LB fluid.

+

For more information on this method and how it works, read the +publication [Hickey et al., 2010].

+
+
+

13.9. Using shapes as lattice-Boltzmann boundary

+
+

Note

+

Feature LB_BOUNDARIES required

+
+

Lattice-Boltzmann boundaries are implemented in the module +espressomd.lbboundaries. You might want to take a look +at the classes LBBoundary +and LBBoundaries for more information.

+

Adding a shape-based boundary is straightforward:

+
lbb = espressomd.lbboundaries.LBBoundary(shape=my_shape, velocity=[0, 0, 0])
+system.lbboundaries.add(lbb)
+
+
+

or:

+
lbb = espressomd.lbboundaries.LBBoundary()
+lbb.shape = my_shape
+lbb.velocity = [0, 0, 0]
+system.lbboundaries.add(lbb)
+
+
+
+

13.9.1. Minimal usage example

+
+

Note

+

Feature LB_BOUNDARIES or LB_BOUNDARIES_GPU required

+
+

In order to add a wall as boundary for a lattice-Boltzmann fluid +you could do the following:

+
wall = espressomd.shapes.Wall(dist=5, normal=[1, 0, 0])
+lbb = espressomd.lbboundaries.LBBoundary(shape=wall, velocity=[0, 0, 0])
+system.lbboundaries.add(lbb)
+
+
+
+
+

13.9.2. Setting up boundary conditions

+

The following example sets up a system consisting of a spherical boundary +in the center of the simulation box acting as a no-slip boundary for the +LB fluid that is driven by 4 walls with a slip velocity:

+
import espressomd
+import espressomd.lb
+import espressomd.lbboundaries
+import espressomd.shapes
+
+system = espressomd.System(box_l=[64, 64, 64])
+system.time_step = 0.01
+system.cell_system.skin = 0.4
+
+lb = espressomd.lb.LBFluid(agrid=1.0, dens=1.0, visc=1.0, tau=0.01)
+system.actors.add(lb)
+
+v = [0, 0, 0.01]  # the boundary slip
+walls = [None] * 4
+
+wall_shape = espressomd.shapes.Wall(normal=[1, 0, 0], dist=1)
+walls[0] = espressomd.lbboundaries.LBBoundary(shape=wall_shape, velocity=v)
+
+wall_shape = espressomd.shapes.Wall(normal=[-1, 0, 0], dist=-63)
+walls[1] = espressomd.lbboundaries.LBBoundary(shape=wall_shape, velocity=v)
+
+wall_shape = espressomd.shapes.Wall(normal=[0, 1, 0], dist=1)
+walls[2] = espressomd.lbboundaries.LBBoundary(shape=wall_shape, velocity=v)
+
+wall_shape = espressomd.shapes.Wall(normal=[0, -1, 0], dist=-63)
+walls[3] = espressomd.lbboundaries.LBBoundary(shape=wall_shape, velocity=v)
+
+for wall in walls:
+    system.lbboundaries.add(wall)
+
+sphere_shape = espressomd.shapes.Sphere(radius=5.5, center=[33, 33, 33], direction=1)
+sphere = espressomd.lbboundaries.LBBoundary(shape=sphere_shape)
+system.lbboundaries.add(sphere)
+
+system.integrator.run(4000)
+
+print(sphere.get_force())
+
+
+

After integrating the system for a sufficient time to reach the steady state, +the hydrodynamic drag force exerted on the sphere is evaluated.

+

The LB boundaries use the same shapes objects to specify +their geometry as constraints do for particles. +This allows the user to quickly set up a system with boundary conditions +that simultaneously act on the fluid and particles. For a complete +description of all available shapes, refer to espressomd.shapes.

+

Intersecting boundaries are in principle possible but must be treated +with care. In the current implementation, all nodes that are +within at least one boundary are treated as boundary nodes.

+

Currently, only the so-called “link-bounce-back” algorithm for wall +nodes is available. This creates a boundary that is located +approximately midway between the lattice nodes, so in the above example wall[0] +corresponds to a boundary at \(x=1.5\). Note that the +location of the boundary is unfortunately not entirely independent of +the viscosity. This can be seen when using the sample script with a high +viscosity.

+

The bounce back boundary conditions permit it to set the velocity at the boundary +to a non-zero value via the v property of an LBBoundary object. +This allows to create shear flow and boundaries +moving relative to each other. The velocity boundary conditions are +implemented according to [Succi, 2001] eq. 12.58. Using +this implementation as a blueprint for the boundary treatment, an +implementation of the Ladd-Coupling should be relatively +straightforward. The LBBoundary object furthermore possesses +a property force, which keeps track of the hydrodynamic drag +force exerted onto the boundary by the moving fluid.

+
+
1
+

https://www.paraview.org/

+
+
2
+

http://code.enthought.com/projects/mayavi/

+
+
+
+
+
+ + +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/doc4.2.2/magnetostatics.html b/doc4.2.2/magnetostatics.html new file mode 100644 index 0000000000..dc28a116bd --- /dev/null +++ b/doc4.2.2/magnetostatics.html @@ -0,0 +1,253 @@ + + + + + + + + + 10. Magnetostatics — ESPResSo 4.2.2 documentation + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +
+

10. Magnetostatics

+
+

10.1. Dipolar interaction

+

ESPResSo contains methods to calculate the interactions between point dipoles

+
+\[U^{Dip}(\vec{r}) = D \cdot \left( \frac{(\vec{\mu}_i \cdot \vec{\mu}_j)}{r^3} + - \frac{3 (\vec{\mu}_i \cdot \vec{r}) (\vec{\mu}_j \cdot \vec{r}) }{r^5} \right)\]
+

where \(r=|\vec{r}|\). +The prefactor \(D\) is can be set by the user and is given by

+
+(1)\[D =\frac{\mu_0 \mu}{4\pi}\]
+

where \(\mu_0\) and \(\mu\) are the vacuum permittivity and the +relative permittivity of the background material, respectively.

+

Magnetostatic interactions are activated via the actor framework:

+
import espressomd
+import espressomd.magnetostatics
+
+system = espressomd.System(box_l=[10, 10, 10])
+system.time_step = 0.01
+system.part.add(pos=[[0, 0, 0], [1, 1, 1]],
+                rotation=2 * [(1, 1, 1)], dip=2 * [(1, 0, 0)])
+
+actor = espressomd.magnetostatics.DipolarDirectSumCpu(prefactor=1.)
+system.actors.add(actor)
+
+
+

The list of actors can be cleared with +system.actors.clear() and +system.actors.remove(actor).

+
+

10.1.1. Dipolar P3M

+

espressomd.magnetostatics.DipolarP3M

+

This is the dipolar version of the P3M algorithm, described in [Cerdà et al., 2008].

+

Make sure that you know the relevance of the P3M parameters before using +P3M! If you are not sure, read the following references: +[Cerdà et al., 2008, Deserno, 2000, Deserno and Holm, 1998, Deserno and Holm, 1998, Deserno et al., 2000, Ewald, 1921, Hockney and Eastwood, 1988, Kolafa and Perram, 1992].

+

Note that dipolar P3M does not work with non-cubic boxes.

+

The parameters of the dipolar P3M method can be tuned automatically, by +providing accuracy=<TARGET_ACCURACY> to the method. It is also possible to +pass a subset of the method parameters such as mesh. In that case, only +the omitted parameters are tuned:

+
import espressomd.magnetostatics as magnetostatics
+p3m = magnetostatics.DipolarP3M(prefactor=1, mesh=32, accuracy=1E-4)
+system.actors.add(p3m)
+
+
+

It is important to note that the error estimates given in [Cerdà et al., 2008] +used in the tuning contain assumptions about the system. In particular, a +homogeneous system is assumed. If this is no longer the case during the +simulation, actual force and torque errors can be significantly larger.

+
+
+

10.1.2. Dipolar Layer Correction (DLC)

+

espressomd.magnetostatics.DLC

+

The dipolar layer correction (DLC) is used in conjunction with the dipolar P3M +method to calculate dipolar interactions in a 2D-periodic system. +It is based on [Bródka, 2004] and the dipolar version of +Electrostatic Layer Correction (ELC).

+

Usage notes:

+
    +
  • The non-periodic direction is always the z-direction.

  • +
  • The method relies on a slab of the simulation box perpendicular to the +z-direction not to contain particles. The size in z-direction of this slab +is controlled by the gap_size parameter. The user has to ensure that +no particles enter this region by means of constraints or by fixing the +particles’ z-coordinate. When particles enter the slab of the specified +size, an error will be thrown.

  • +
  • The method can be tuned using the accuracy parameter. In contrast to +the electrostatic method, it refers to the energy. Furthermore, it is +assumed that all dipole moment are as large as the largest of the dipoles +in the system.

  • +
  • When the base solver is not a P3M method, metallic epsilon is assumed.

  • +
+

The method is used as follows:

+
import espressomd.magnetostatics
+dp3m = espressomd.magnetostatics.DipolarP3M(prefactor=1, accuracy=1E-4)
+mdlc = espressomd.magnetostatics.DLC(actor=dp3m, maxPWerror=1E-5, gap_size=2.)
+system.actors.add(mdlc)
+
+
+
+
+
+

10.2. Dipolar direct sum

+

This interaction calculates energies and forces between dipoles by +explicitly summing over all pairs. For the directions in which the +system is periodic (as defined by system.periodicity), it applies the +minimum image convention, i.e. the interaction is effectively cut off at +half a box length.

+

The direct summation methods are mainly intended for non-periodic systems which cannot be solved using the dipolar P3M method. +Due to the long-range nature of dipolar interactions, Direct summation with minimum image convention does not yield good accuracy with periodic systems.

+

Two methods are available:

+
    +
  • DipolarDirectSumCpu +performs the calculation in double precision on the Cpu.

  • +
  • DipolarDirectSumGpu +performs the calculations in single precision on a Cuda-capable graphics card. +The implementation is optimized for large systems of several thousand +particles. It makes use of one thread per particle. When there are fewer +particles than the number of threads the gpu can execute simultaneously, +the rest of the gpu remains idle. Hence, the method will perform poorly +for small systems.

  • +
+

To use the methods, create an instance of either +DipolarDirectSumCpu or +DipolarDirectSumGpu and add it to the +system’s list of active actors. The only required parameter is the Prefactor +(1):

+
import espressomd.magnetostatics
+dds = espressomd.magnetostatics.DipolarDirectSumGpu(prefactor=1)
+system.actors.add(dds)
+
+
+

For testing purposes, a variant of the dipolar direct sum is available which +adds periodic copies to the system in periodic directions: +DipolarDirectSumWithReplicaCpu. +As it is very slow, this method is not intended to do simulations, but +rather to check the results you get from more efficient methods like P3M.

+

DipolarDirectSumCpu and +DipolarDirectSumWithReplicaCpu +do not support MPI parallelization.

+
+
+

10.3. Barnes-Hut octree sum on GPU

+

espressomd.magnetostatics.DipolarBarnesHutGpu

+

This interaction calculates energies and forces between dipoles by +summing over the spatial octree cells (aka leaves). +Far enough cells are considered as a single dipole with a cumulative +vector in the cell center of mass. Parameters which determine that the +cell is far enough are \(I_{\mathrm{tol}}^2\) and +\(\varepsilon^2\) which define a fraction of the cell and +an additive distance respectively. For the detailed description of the +Barnes-Hut method application to the dipole-dipole interactions, please +refer to [Polyakov et al., 2013].

+

To use the method, create an instance of DipolarBarnesHutGpu +and add it to the system’s list of active actors:

+
import espressomd.magnetostatics
+bh = espressomd.magnetostatics.DipolarBarnesHutGpu(prefactor=1., epssq=200.0, itolsq=8.0)
+system.actors.add(bh)
+
+
+
+
+

10.4. ScaFaCoS magnetostatics

+

espressomd.magnetostatics.Scafacos

+

ESPResSo can use the methods from the ScaFaCoS Scalable fast Coulomb solvers +library for dipoles, if the methods support dipolar calculations. The feature +SCAFACOS_DIPOLES has to be added to myconfig.hpp to activate this +feature. Dipolar calculations are only included in the dipoles branch of +the ScaFaCoS code. The specific methods available can be queried with +espressomd.electrostatics.Scafacos.get_available_methods().

+

To use ScaFaCoS, create an instance of Scafacos +and add it to the list of active actors. Three parameters have to be specified: +prefactor, method_name, method_params. The method-specific +parameters are described in the ScaFaCoS manual. In addition, methods +supporting tuning have a parameter tolerance_field which sets the desired +root mean square accuracy for the magnetic field.

+

For details of the various methods and their parameters please refer to +the ScaFaCoS manual. To use this feature, ScaFaCoS has to be built as a +shared library.

+
+
+ + +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/doc4.2.2/modules.html b/doc4.2.2/modules.html new file mode 100644 index 0000000000..4809e05e25 --- /dev/null +++ b/doc4.2.2/modules.html @@ -0,0 +1,140 @@ + + + + + + + + + espressomd — ESPResSo 4.2.2 documentation + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/doc4.2.2/objects.inv b/doc4.2.2/objects.inv new file mode 100644 index 0000000000..56ab322812 Binary files /dev/null and b/doc4.2.2/objects.inv differ diff --git a/doc4.2.2/particles.html b/doc4.2.2/particles.html new file mode 100644 index 0000000000..5a69835c90 --- /dev/null +++ b/doc4.2.2/particles.html @@ -0,0 +1,711 @@ + + + + + + + + + 5. Setting up particles — ESPResSo 4.2.2 documentation + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +
+

5. Setting up particles

+
+

5.1. Overview of the relevant Python classes

+

For understanding this chapter, it is helpful to be aware of the Python classes provided by ESPResSo to interact with particles:

+
    +
  • ParticleHandle provides access to a single particle in the simulation.

  • +
  • ParticleList provides access to all particles in the simulation

  • +
  • ParticleSlice provides access to a subset of particles in the simulation identified by a list of ids or an instance of slice or range.

  • +
+

In almost no case have these classes to be instantiated explicitly by the user. +Rather, access is provided via the system part attribute. +The details are explained in the following sections.

+
+
+

5.2. Adding particles

+

In order to add particles to the system, call +ParticleList.add():

+
import espressomd
+system = espressomd.System(box_l=[10., 10., 10.])
+p = system.part.add(pos=[1., 1., 1.], type=0)
+
+
+

This command adds a single particle to the system with properties given +as arguments, and it returns an instance of +ParticleHandle, which will be used to access +properties of the newly created particle. The pos property is required, all +other properties are optional. +All available particle properties are members of ParticleHandle.

+

Note that the instances of ParticleHandle returned by +ParticleList.add() are handles for the live particles in the +simulation, rather than offline copies. Changing their properties will affect the simulation.

+

It is also possible to add several particles at once:

+
import numpy as np
+new_parts = system.part.add(pos=np.random.random((10, 3)) * box_length)
+
+
+

If several particles are added at once, an instance of +ParticleSlice is returned.

+

Particles are identified via their id property. A unique id is given to them +automatically. Alternatively, you can assign an id manually when adding them to the system:

+
system.part.add(pos=[1., 2., 3.], id=system.part.highest_particle_id + 1)
+
+
+

The id provides an alternative way to access particles in the system. To +retrieve the handle of the particle with id 5, call:

+
p = system.part.by_id(5)
+
+
+
+
+

5.3. Accessing particle properties

+

Particle properties can be accessed like any class member.

+

For example, to print the particle’s current position, call:

+
print(p.pos)
+
+
+
+
+

5.4. Modifying particle properties

+

Similarly, the position can be set:

+
p.pos = [1., 2.5, 3.]
+
+
+

Not all properties are writeable. For example, properties that are +automatically derived from other properties are read-only attributes.

+

Please note that changing a particle property will not affect the ghost +particles until after the next integration loop. This can be an issue for +certain methods like espressomd.system.System.distance() which use +the old ghost information, while other methods like particle-based analysis +tools and espressomd.cell_system.CellSystem.get_neighbors() update the +ghost information before calculating the observable.

+
+

5.4.1. Vectorial properties

+

For vectorial particle properties, component-wise manipulation like +p.pos[0] = 1 or in-place operators like += or *= +are not allowed and raise an exception. +This behavior is inherited, so the same applies to pos after +pos = p.pos. If you want to use a vectorial property for further +calculations, you should explicitly make a copy e.g. via +pos = numpy.copy(p.pos).

+
+
+
+

5.5. Deleting particles

+

Particles can be easily deleted in Python using particle ids or ranges of particle ids. +For example, to delete all particles of type 1, run:

+
system.part.select(type=1).remove()
+
+
+

To delete all particles, use:

+
system.part.clear()
+
+
+
+
+

5.6. Iterating over particles and pairs of particles

+

You can iterate over all particles or over a subset of particles +(see Interacting with groups of particles) as follows:

+
for p in system.part:
+    print(p.pos)
+
+for p in system.part.select(type=1):
+    print(p.pos)
+
+
+

You can iterate over all pairs of particles using:

+
for pair in system.part.pairs():
+    print(pair[0].id, pair[1].id)
+
+
+
+
+

5.7. Exclusions

+

Particles can have an exclusion list of all other particles where non-bonded interactions are ignored. +This is typically used in atomistic simulations, +where nearest and next nearest neighbor interactions along a chain of bonded +particles have to be omitted since they are included in the bonding potentials. +Exclusions do not apply to the short range part of electrostatics and magnetostatics methods, e.g. to P3M.

+

To create exclusions for particles pairs 0 and 1:

+
system.part.by_id(0).add_exclusion(1)
+
+
+

To delete the exclusion:

+
system.part.by_id(0).delete_exclusion(1)
+
+
+

The current list of exclusions is accessible in the +exclusions property.

+
+
+

5.8. Rotational degrees of freedom and particle anisotropy

+

When the feature ROTATION is compiled in, particles not only have a position, +but also an orientation that changes with an angular velocity. +A torque on a particle leads to a change in angular velocity depending on the +particles rotational inertia. +The property rinertia has to +be specified as the three eigenvalues of the particles rotational inertia tensor. +Even if the particle rotational inertia is isotropic, the rotation state can be +important if, e.g., the particle carries a dipole or is an active particle.

+

The rotational degrees of freedom are integrated using a velocity Verlet scheme. +The implementation is based on a quaternion representation of the particle +orientation and described in [Omelyan, 1998] with quaternion components +indexing made according to the formalism +\(q = a + b\mathbf{i} + c\mathbf{j} + d\mathbf{k}\) [Allen and Tildesley, 2017].

+

When the Langevin thermostat is enabled, the rotational degrees of freedom are also thermalized.

+

Whether or not rotational degrees of freedom are propagated, +is controlled on a per-particle and per-axis level, where the axes +are the Cartesian axes of the particle in its body-fixed frame. +It is important to note that starting from version 4.0 and unlike +in earlier versions of ESPResSo, the particles’ rotation is disabled by default. +In this way, just compiling in the ROTATION feature no longer changes the physics of the system.

+

The rotation of a particle is controlled via the +rotation property. +E.g., the following code adds a particle with rotation enabled around the x-axis of its body frame:

+
import espressomd
+system = espressomd.System(box_l=[1, 1, 1])
+system.part.add(pos=(0, 0, 0), rotation=(True, False, False))
+
+
+

The rotational state of a particle is stored as a quaternion in the +quat property. +For a value of (1,0,0,0), the body and space frames coincide. +When setting up a particle, its orientation state is by default aligned with the space frame of the box. +If your particles have a rotational symmetry, you can set up the particle direction +(the symmetry axis) using the director property. +Note that then you have no control over the initial rotation angle around the symmetry axis. +If your particles are anisotropic in all three directions, you can either set +the quat attribute directly, +or (recommended) set up all particle properties in the box frame and then use +rotate to rotate the particle +to the desired state before starting the simulation.

+

Notes:

+
    +
  • The space-frame direction of the particle’s z-axis in its body frame is accessible +through the director property.

  • +
  • Any other vector can be converted from body to space fixed frame using the +ParticleHandle.convert_vector_body_to_space() method.

  • +
  • When DIPOLES are compiled in, the particles dipole moment is always +co-aligned with the z-axis in the body-fixed frame.

  • +
  • Changing the particles dipole moment and director will re-orient the particle +such that its z-axis in space frame is aligned parallel to the given vector. +No guarantees are made for the other two axes after setting the director or the dipole moment.

  • +
+

The following particle properties are related to rotation:

+ +
+
+

5.9. Virtual sites

+

Virtual sites are particles, the positions and velocities of which are +not obtained by integrating an equation of motion. Rather, their +coordinates are obtained from the position (and orientation) of one or +more other particles. In this way, rigid arrangements of particles can +be constructed and a particle can be placed in the center of mass of a +set of other particles. Virtual sites can interact with other particles +in the system by means of interactions. Forces are added to them +according to their respective particle type. Before the next integration +step, the forces accumulated on a virtual site are distributed back to +those particles, from which the virtual site was derived.

+

There are different schemes for virtual sites, described in the +following sections. To switch the active scheme, the system +virtual_sites property can be used:

+
import espressomd
+import espressomd.virtual_sites
+
+system = espressomd.System(box_l=[1, 1, 1])
+system.virtual_sites = espressomd.virtual_sites.VirtualSitesRelative(have_quaternion=False)
+# or
+system.virtual_sites = espressomd.virtual_sites.VirtualSitesOff()
+
+
+

By default, espressomd.virtual_sites.VirtualSitesOff is selected. +This means that virtual particles are not touched during integration. +The have_quaternion parameter determines whether the quaternion of +the virtual particle is updated (useful in combination with the +vs_quat property of the +virtual particle which defines the orientation of the virtual particle +in the body fixed frame of the related real particle).

+
+

5.9.1. Rigid arrangements of particles

+

The relative implementation of virtual sites allows for the simulation +of rigid arrangements of particles. It can be used, for extended +dipoles and raspberry-particles, but also for more complex +configurations. Position and velocity of a virtual site are obtained +from the position and orientation of exactly one non-virtual particle, +which has to be placed in the center of mass of the rigid body. Several +virtual sites can be related to one and the same non-virtual particle. +The position of the virtual site is given by

+
+\[\vec{x_v} =\vec{x_n} +O_n (O_v \vec{E_z}) d,\]
+

where \(\vec{x_n}\) is the position of the non-virtual particle, +\(O_n\) is the orientation of the non-virtual particle, \(O_v\) +denotes the orientation of the vector \(\vec{x_v}-\vec{x_n}\) with +respect to the non-virtual particles body fixed frame and \(d\) the +distance between virtual and non-virtual particle. In words: The virtual +site is placed at a fixed distance from the non-virtual particle. When +the non-virtual particle rotates, the virtual sites rotates on an orbit +around the non-virtual particles center.

+

To use this implementation of virtual sites, activate the feature +VIRTUAL_SITES_RELATIVE. Furthermore, an instance of +VirtualSitesRelative has to be set as the +active virtual sites scheme (see above). To set up a virtual site:

+
    +
  1. Place the particle to which the virtual site should be related. +It needs to be in the center of mass of the rigid arrangement of +particles you create:

    +
    import espressomd
    +import espressomd.virtual_sites
    +
    +system = espressomd.System(box_l=[10., 10., 10.])
    +system.virtual_sites = espressomd.virtual_sites.VirtualSitesRelative()
    +p1 = system.part.add(pos=[1., 2., 3.])
    +
    +
    +
  2. +
  3. Place a particle at the desired relative position, make it virtual +and relate it to the first particle:

    +
    rel_offset = [1., 0., 0.]
    +p2 = system.part.add(pos=p1.pos + rel_offset)
    +p2.vs_auto_relate_to(p1)
    +
    +
    +

    This will set the virtual +attribute on particle p2 to True.

    +
  4. +
  5. Repeat the previous step with more virtual sites, if desired.

  6. +
  7. To update the positions of all virtual sites, call:

    +
    system.integrator.run(0, recalc_forces=True)
    +
    +
    +
  8. +
+

Please note:

+
    +
  • The relative position of the virtual site is defined by its distance +from the non-virtual particle, the id of the non-virtual particle and +a quaternion which defines the vector from non-virtual particle to +virtual site in the non-virtual particles body-fixed frame. This +information is saved in the virtual site’s +vs_relative attribute. +Take care, not to overwrite it after using vs_auto_relate.

  • +
  • Virtual sites can not be placed relative to other virtual sites, as +the order in which the positions of virtual sites are updated is not +guaranteed. Always relate a virtual site to a non-virtual particle +placed in the center of mass of the rigid arrangement of particles.

  • +
  • In case you know the correct quaternions, you can also setup a virtual +site using its vs_relative +and virtual attributes.

  • +
  • In a simulation on more than one CPU, the effective cell size needs +to be larger than the largest distance between a non-virtual particle +and its associated virtual sites. To this aim, when running on more than one core, +you need to set the system’s min_global_cut +attribute to this largest distance. +An error is generated when this requirement is not met. +Under very specific circumstances it may be desirable to disable this check, +e.g. when using certain setups with the hybrid decomposition scheme. +You can do so by setting the virtual sites property override_cutoff_check = True. +However, only consider this if you are absolutely sure of what you are doing.

  • +
  • If the virtual sites represent actual particles carrying a mass, the +inertia tensor of the non-virtual particle in the center of mass +needs to be adapted.

  • +
  • The presence of rigid bodies constructed by means of virtual sites +adds a contribution to the scalar pressure and pressure tensor.

  • +
+
+
+

5.9.2. Inertialess lattice-Boltzmann tracers

+

espressomd.virtual_sites.VirtualSitesInertialessTracers

+

When this implementation is selected, the virtual sites follow the motion of a +lattice-Boltzmann fluid (both, CPU and GPU). This is achieved by integrating +their position using the fluid velocity at the virtual sites’ position. +Forces acting on the virtual sites are directly transferred as force density +onto the lattice-Boltzmann fluid, making the coupling free of inertia. +The feature stems from the implementation of the +Immersed Boundary Method for soft elastic objects, but can be used independently.

+

For correct results, the LB thermostat has to be deactivated for virtual sites:

+
system.thermostat.set_lb(kT=0, act_on_virtual=False)
+
+
+

Please note that the velocity attribute of the virtual particles does not carry valid information for this virtual sites scheme. +With the LB GPU implementation, inertialess tracers only work on 1 MPI rank.

+
+
+
+

5.10. Interacting with groups of particles

+

Groups of particles are addressed using ParticleSlice objects. +Usually, these objects do not have to be instantiated by the user. There are several ways +to retrieve a particle slice:

+
    +
  • By calling ParticleList.add()

    +

    When adding several particles at once, a particle slice is returned instead +of a particle handle.

    +
  • +
  • By calling ParticleList.by_ids()

    +

    It is also possible to get a slice containing particles of specific ids, e.g.:

    +
    system.part.by_ids([1, 4, 3])
    +
    +
    +

    would contain the particles with ids 1, 4, and 3 in that specific order.

    +
  • +
  • By calling ParticleList.all()

    +

    You can get a slice containing all particles using:

    +
    system.part.all()
    +
    +
    +
  • +
  • By calling ParticleList.select()

    +

    This is useful to filter out particles with distinct properties, e.g.:

    +
    slice1 = system.part.select(type=0, q=1)
    +slice2 = system.part.select(lambda p: p.pos[0] < 0.5)
    +
    +
    +
  • +
+

Properties of particle slices can be accessed just like with single particles. +A list of all values is returned:

+
print(system.part.all().q)
+
+
+

A particle slice can be iterated over, see Iterating over particles and pairs of particles.

+

Setting properties of slices can be done by

+
    +
  • supplying a single value that is assigned to each entry of the slice, e.g.:

    +
    system.part.by_ids(range(10)).ext_force = [1, 0, 0]
    +
    +
    +
  • +
  • supplying an array of values that matches the length of the slice which sets each entry individually, e.g.:

    +
    system.part.by_ids(range(3)).ext_force = [[1, 0, 0], [2, 0, 0], [3, 0, 0]]
    +
    +
    +
  • +
+

For list properties that have no fixed length like exclusions or bonds, some care has to be taken. +There, single value assignment also accepts lists/tuples just like setting the property of an individual particle. For example:

+
system.part.by_id(0).exclusions = [1, 2]
+
+
+

would both exclude short-range interactions of the particle pairs 0 <-> 1 and 0 <-> 2. +Similarly, a list can also be assigned to each entry of the slice:

+
system.part.by_ids(range(2,4)).exclusions = [0, 1]
+
+
+

This would exclude interactions between 2 <-> 0, 2 <-> 1, 3 <-> 0 and 3 <-> 1. +Now when it is desired to supply an array of values with individual values for each slice entry, the distinction can no longer be done +by the length of the input, as slice length and input length can be equal. Here, the nesting level of the input is the distinctive criterion:

+
system.part.by_ids(range(2,4)).exclusions = [[0, 1], [0, 1]]
+
+
+

The above code snippet would lead to the same exclusions as the one before. +The same accounts for the bonds property by interchanging the integer entries of the exclusion list with +the tuple (bond, partners).

+

You can select a subset of particles via using the select method. For example you can obtain a list of particles with charge -1 via using

+
system.part.select(q=-1)
+
+
+

For further information on how to use selections see espressomd.particle_data.ParticleList.select().

+
+
+

5.11. Create particular particle configurations

+
+

5.11.1. Setting up polymer chains

+

If you want to have polymers in your system, you can use the function +espressomd.polymer.linear_polymer_positions() to determine suitable positions.

+

Required arguments are the desired number of polymers n_polymers, the +number of monomers per polymer chain beads_per_chain, and the parameter +bond_length, which determines the distance between adjacent monomers +within the polymer chains. +Determining suitable particle positions pseudo-randomly requires the use of +a pseudo-random number generator, which has to be seeded. This seed +is therefore also a mandatory parameter.

+

The function espressomd.polymer.linear_polymer_positions() returns a +three-dimensional numpy array, namely a list of polymers containing the +positions of monomers (x, y, z). A quick example of how to set up polymers:

+
import espressomd
+import espressomd.polymer
+import espressomd.interactions
+
+system = espressomd.System([50, 50, 50])
+fene = espressomd.interactions.FeneBond(k=10, d_r_max=2)
+system.bonded_inter.add(fene)
+polymer_positions = espressomd.polymer.linear_polymer_positions(
+    n_polymers=10, beads_per_chain=25, bond_length=0.9, seed=23)
+
+for positions in polymer_positions:
+    monomers = system.part.add(pos=positions)
+    previous_part = None
+    for part in monomers:
+        if not previous_part is None:
+            part.add_bond((fene, previous_part))
+        previous_part = part
+
+
+

If there are constraints present in your system which you want to be taken +into account when creating the polymer positions, you can set the optional +boolean parameter respect_constraint=True. +To simulate excluded volume while drawing the polymer positions, a minimum +distance between all particles can be set via min_distance. This will +also respect already existing particles in the system. +Both when setting respect_constraints and choosing a min_distance +trial positions are pseudo-randomly chosen and only accepted if the +requested requirement is fulfilled. Otherwise, a new attempt will be made, +up to max_tries times per monomer and if this fails max_tries per +polymer. The default value is max_tries=1000. Depending on the total +number of beads and constraints, this value may need to be adapted. If +determining suitable polymer positions within this limit fails, a runtime +error is thrown.

+

Note that the distance between adjacent monomers +during the course of the simulation depends on the applied potentials. +For fixed bond length please refer to the Rattle Shake +algorithm[Andersen, 1983]. The algorithm is based on +Verlet algorithm and satisfy internal constraints for molecular models +with internal constraints, using Lagrange multipliers.

+
+
+

5.11.2. Setting up diamond polymer networks

+

espressomd.polymer.setup_diamond_polymer() creates a diamond-structured +polymer network with 8 tetra-functional nodes +connected by \(2 \times 8\) polymer chains of length MPC with the system box as +the unit cell. The box therefore has to be cubic. +The diamond command creates 16*MPC+8 many particles +which are connected via the provided bond type (the term plus 8 stems from adding 8 nodes which are connecting the chains). +Chain monomers are placed at constant distance to each other +along the vector connecting network nodes. The distance between monomers is +system.box_l[0]*(0.25 * sqrt(3))/(MPC + 1), which should be taken into account +when choosing the connecting bond. +The starting particle id, the charges of monomers, the frequency +of charged monomers in the chains as well as the types of the node particles, +the charged and the uncharged chain particles can be set via keyword arguments, see espressomd.polymer.setup_diamond_polymer().

+
+Diamond-like polymer network with MPC=15. +
+

Diamond-like polymer network with MPC=15.

+
+
+

For simulating compressed or stretched gels, the function +espressomd.system.System.change_volume_and_rescale_particles() may be used.

+
+
+
+

5.12. Particle number counting feature

+
+

Note

+

Do not use these methods with the espressomd.collision_detection +module since the collision detection may create or delete particles +without the particle number counting feature being aware of this. +Therefore the espressomd.reaction_methods module may not +be used with the collision detection.

+
+

Knowing the number of particles of a certain type in simulations where +particle numbers can fluctuate is of interest. +Particle ids can be stored in a map for each individual type:

+
import espressomd
+system = espressomd.System(box_l=[1, 1, 1])
+system.setup_type_map([_type])
+system.number_of_particles(_type)
+
+
+

If you want to keep track of particle ids of a certain type you have to +initialize the method by calling

+
system.setup_type_map([_type])
+
+
+

After that the system will keep track of particle ids of that type. Keeping +track of particles of a given type is not enabled by default since it requires +memory. The keyword number_of_particles as argument will return the number +of particles which have the given type. For counting the number of particles +of a given type you could also use +ParticleList.select()

+
import espressomd
+system = espressomd.System(box_l=[1, 1, 1])
+system.part.add(pos=[1, 0, 0], type=0)
+system.part.add(pos=[0, 1, 0], type=0)
+system.part.add(pos=[0, 0, 1], type=2)
+print(len(system.part.select(type=0)))
+print(len(system.part.select(type=2)))
+
+
+

However calling select(type=type) results in looping over all particles, +which is slow. In contrast, the system +number_of_particles() method can return the +number of particles with that type.

+
+
+

5.13. Self-propelled swimmers

+
+

Note

+

If you are using this feature, please cite [de Graaf et al., 2016].

+
+
+

See also

+

swimming

+
+
+

5.13.1. Langevin swimmers

+
import espressomd
+system = espressomd.System(box_l=[1, 1, 1])
+system.part.add(pos=[1, 0, 0], swimming={'f_swim': 0.03})
+
+
+

This enables the particle to be self-propelled in the direction determined by +its quaternion. For setting the particle’s quaternion see +quat. The self-propulsion +speed will relax to a constant velocity, that is specified by v_swim. +Alternatively it is possible to achieve a constant velocity by imposing a +constant force term f_swim that is balanced by friction of a (Langevin) +thermostat. The way the velocity of the particle decays to the constant +terminal velocity in either of these methods is completely determined by the +friction coefficient. You may only set one of the possibilities v_swim or +f_swim as you cannot relax to constant force and constant velocity at the +same time. Note that there is no real difference between v_swim and +f_swim, since the latter may always be chosen such that the same terminal +velocity is achieved for a given friction coefficient.

+
+
+

5.13.2. Lattice-Boltzmann swimmers

+
import espressomd
+system = espressomd.System(box_l=[1, 1, 1])
+system.part.add(pos=[2, 0, 0], rotation=[1, 1, 1], swimming={
+    'f_swim': 0.01, 'mode': 'pusher', 'dipole_length': 2.0})
+
+
+

For an explanation of the parameters v_swim and f_swim see the previous +item. In lattice-Boltzmann self-propulsion is less trivial than for regular MD, +because the self-propulsion is achieved by a force-free mechanism, which has +strong implications for the far-field hydrodynamic flow field induced by the +self-propelled particle. In ESPResSo only the dipolar component of the flow field +of an active particle is taken into account. This flow field can be generated +by a pushing or a pulling mechanism, leading to change in the sign of the +dipolar flow field with respect to the direction of motion. You can specify the +nature of the particle’s flow field by using one of the modes: pusher or +puller. You will also need to specify a dipole_length which determines +the distance of the source of propulsion from the particle’s center. Note that +you should not put this distance to zero; ESPResSo (currently) does not support +mathematical dipole flow fields.

+

You may ask: “Why are there two methods v_swim and f_swim for the +self-propulsion using the lattice-Boltzmann algorithm?” The answer is +straightforward. When a particle is accelerating, it has a monopolar flow-field +contribution which vanishes when it reaches its terminal velocity (for which +there will only be a dipolar flow field). The major difference between the +above two methods is that with v_swim the flow field only has a monopolar +moment and only while the particle is accelerating. As soon as the particle +reaches a constant speed (given by v_swim) this monopolar moment is gone +and the flow field is zero! In contrast, f_swim always, i.e., while +accelerating and while swimming at constant force possesses a dipolar flow +field.

+
+
+
+ + +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/doc4.2.2/py-modindex.html b/doc4.2.2/py-modindex.html new file mode 100644 index 0000000000..12a6410914 --- /dev/null +++ b/doc4.2.2/py-modindex.html @@ -0,0 +1,322 @@ + + + + + + + + Python Module Index — ESPResSo 4.2.2 documentation + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ + +

Python Module Index

+ +
+ e +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
 
+ e
+ espressomd +
    + espressomd.accumulators +
    + espressomd.actors +
    + espressomd.analyze +
    + espressomd.bond_breakage +
    + espressomd.cell_system +
    + espressomd.checkpointing +
    + espressomd.cluster_analysis +
    + espressomd.collision_detection +
    + espressomd.comfixed +
    + espressomd.constraints +
    + espressomd.cuda_init +
    + espressomd.drude_helpers +
    + espressomd.ekboundaries +
    + espressomd.electrokinetics +
    + espressomd.electrostatic_extensions +
    + espressomd.electrostatics +
    + espressomd.galilei +
    + espressomd.highlander +
    + espressomd.integrate +
    + espressomd.interactions +
    + espressomd.io +
    + espressomd.io.mpiio +
    + espressomd.io.writer +
    + espressomd.io.writer.h5md +
    + espressomd.io.writer.vtf +
    + espressomd.lb +
    + espressomd.lbboundaries +
    + espressomd.lees_edwards +
    + espressomd.magnetostatics +
    + espressomd.math +
    + espressomd.MDA_ESP +
    + espressomd.observables +
    + espressomd.pair_criteria +
    + espressomd.particle_data +
    + espressomd.polymer +
    + espressomd.profiler +
    + espressomd.reaction_methods +
    + espressomd.rotation +
    + espressomd.script_interface +
    + espressomd.shapes +
    + espressomd.system +
    + espressomd.thermostat +
    + espressomd.utils +
    + espressomd.version +
    + espressomd.virtual_sites +
    + espressomd.visualization +
+ + +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/doc4.2.2/reaction_methods.html b/doc4.2.2/reaction_methods.html new file mode 100644 index 0000000000..6f38ca4fa2 --- /dev/null +++ b/doc4.2.2/reaction_methods.html @@ -0,0 +1,360 @@ + + + + + + + + + 19. Reaction methods — ESPResSo 4.2.2 documentation + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +
+

19. Reaction methods

+

This chapter describes methods for simulating chemical reaction equilibria +using reactive particles. Chemical species are referred to by an integer value +stored in the particle type +property. Chemical reactions take place by changing the value in the +type property via Monte Carlo +moves using the potential energy of the system before and after the reaction +[Turner et al., 2008].

+

Please keep in mind the following remarks:

+
    +
  • All reaction methods uses Monte Carlo moves which require potential energies. +Therefore reaction methods require support for energy calculations for all +active interactions in the simulation. Some algorithms do not support energy +calculation, e.g. OIF and +IBM.

  • +
  • When modeling reactions that do not conserve the number of particles, the +method has to create or delete particles from the system. This process can +invalidate particle ids, in which case the particles are no longer numbered +contiguously. Particle slices returned by system.part are still iterable, +but the indices no longer match the particle ids.

  • +
  • Checkpointing is not supported, since the state of the Mersenne Twister +random number generator cannot be serialized.

  • +
  • For improved performance, you can set the type of invalidated particles with +set_non_interacting_type() +in all reaction method classes.

  • +
  • Some of the functionality requires particle book-keeping. If your simulation +script raises runtime errors about “provided particle type X is currently not +tracked by the system”, use system.setup_type_map(type_list=[X]) where X is the particle +type to track.

  • +
+
+

19.1. Thermodynamic ensembles

+
+

19.1.1. Reaction ensemble

+

The reaction ensemble [Johnson et al., 1994, Smith and Triska, 1994, Turner et al., 2008] allows to simulate +chemical reactions which can be represented by the general equation:

+
+\[\mathrm{\nu_1 S_1 +\ \dots\ \nu_l S_l\ \rightleftharpoons\ \nu_m S_m +\ \dots\ \nu_z S_z } + \label{general-eq}\]
+

where \(\nu_i\) is the stoichiometric coefficient of species +\(S_i\). By convention, stoichiometric coefficients of the +species on the left-hand side of the reaction (reactants) attain +negative values, and those on the right-hand side (products) attain +positive values, so that the reaction can be equivalently written as

+
+\[\mathrm{\sum_i \nu_i S_i = 0} \,. + \label{general-eq-sum}\]
+

The equilibrium constant of the reaction is then given as

+
+\[K = \exp(-\Delta_{\mathrm{r}}G^{\ominus} / k_B T) + \quad\text{with}\quad + \Delta_{\mathrm{r}}G^{\ominus} = \sum_i \nu_i \mu_i^{\ominus}\,. + \label{Keq}\]
+

Here \(k_B\) is the Boltzmann constant, \(T\) is temperature, +\(\Delta_{\mathrm{r}}G^{\ominus}\) standard Gibbs free energy change +of the reaction, and \(\mu_i^{\ominus}\) the standard chemical +potential (per particle) of species \(i\). Note that thermodynamic equilibrium is +independent of the direction in which we write the reaction. If it is +written with left and right-hand side swapped, +both \(\Delta_{\mathrm{r}}G^{\ominus}\) and the stoichiometric +coefficients attain opposite signs, and the equilibrium constant attains the inverse value. +Further, note that the equilibrium constant \(K\) is the +dimensionless thermodynamic, concentration-based equilibrium constant, +defined as

+
+\[K(c^{\ominus}) = (c^{\ominus})^{-\bar\nu} \prod_i (c_i)^{\nu_i}\]
+

where \(\bar\nu=\sum_i \nu_i\), and \(c^{\ominus}\) is the reference concentration, +at which the standard chemical potential \(\Delta_{\mathrm{r}}G^{\ominus}\) was determined. +In practice, this constant is often used with the dimension of \((c^{\ominus})^{\bar\nu}\)

+
+\[K_c(c^{\ominus}) = K(c^{\ominus})\times (c^{\ominus})^{\bar\nu}\]
+

A simulation in +the reaction ensemble consists of two types of moves: the reaction move +and the configuration move. The configuration move changes the configuration +of the system. +In the forward reaction, the appropriate number of reactants (given by +\(\nu_i\)) is removed from the system, and the concomitant number of +products is inserted into the system. In the backward reaction, +reactants and products exchange their roles. The acceptance probability +\(P^{\xi}\) for a move from state \(o\) to \(n\) in the reaction +ensemble is given by the criterion [Smith and Triska, 1994]

+
+\[P^{\xi} = \text{min}\biggl(1,V^{\bar\nu\xi}\Gamma^{\xi}e^{-\beta\Delta E}\prod_{i=1}\frac{N_i^0!}{(N_i^0+\nu_{i}\xi)!} + \label{eq:Pacc} + \biggr),\]
+

where \(\Delta E=E_\mathrm{new}-E_\mathrm{old}\) is the change in potential energy, +\(V\) is the simulation box volume, +\(\beta=1/k_\mathrm{B}T\) is the Boltzmann factor, and +\(\xi\) is the extent of reaction, with \(\xi=1\) for the forward and +\(\xi=-1\) for the backward direction.

+

\(\Gamma\) is proportional to the reaction constant. It is defined as

+
+\[\Gamma = \prod_i \Bigl(\frac{\left<N_i\right>}{V} \Bigr)^{\bar\nu} = V^{-\bar\nu} \prod_i \left<N_i\right>^{\nu_i} = K_c(c^{\ominus}=1/\sigma^3)\]
+

where \(\left<N_i\right>/V\) is the average number density of particles of type \(i\). +Note that the dimension of \(\Gamma\) is \(V^{\bar\nu}\), therefore its +units must be consistent with the units in which ESPResSo measures the box volume, +i.e. \(\sigma^3\).

+

It is often convenient, and in some cases even necessary, that some particles +representing reactants are not removed from or placed at randomly in the system +but their identity is changed to that of the products, or vice versa in the +backward direction. A typical example is the ionization reaction of weak +polyelectrolytes, where the ionizable groups on the polymer have to remain on +the polymer chain after the reaction. The replacement rule is that the identity of a given reactant type is +changed to the corresponding product type as long as the corresponding +coefficients allow for it. Corresponding means having the same position (index) in +the python lists of reactants and products which are used to set up the +reaction.

+

Multiple reactions can be added to the same instance of the reaction ensemble.

+

An example script can be found here:

+ +

For a description of the available methods, see espressomd.reaction_methods.ReactionEnsemble.

+
+
+

19.1.2. Grand canonical ensemble

+

As a special case, all stoichiometric coefficients on one side of the chemical +reaction can be set to zero. Such a reaction creates particles ex nihilo, and +is equivalent to exchanging particles with a reservoir. This type of simulation +in the reaction ensemble is equivalent to the grand canonical simulation. +Formally, this can be expressed by the reaction

+
+\[\mathrm{\emptyset \rightleftharpoons\ \nu_A A } \,,\]
+

where, if \(\nu_A=1\), the reaction constant \(\Gamma\) defines the chemical potential of species A. +However, if \(\nu_A\neq 1\), the statistics of the reaction ensemble becomes +equivalent to the grand canonical only in the limit of large average number of species A in the box. +If the reaction contains more than one product, then the reaction constant +\(\Gamma\) defines only the sum of their chemical potentials but not the +chemical potential of each product alone.

+

Since the Reaction Ensemble acceptance transition probability can be +derived from the grand canonical acceptance transition probability, we +can use the reaction ensemble to implement grand canonical simulation +moves. This is done by adding reactions that only have reactants (for the +deletion of particles) or only have products (for the creation of +particles). There exists a one-to-one mapping of the expressions in the +grand canonical transition probabilities and the expressions in the +reaction ensemble transition probabilities.

+
+
+

19.1.3. Constant pH

+

As before in the reaction ensemble, one can define multiple reactions (e.g. for an ampholytic system which contains an acid and a base) in one ConstantpHEnsemble instance:

+
cpH=reaction_methods.ConstantpHEnsemble(
+    temperature=1, exclusion_range=1, seed=77)
+cpH.add_reaction(gamma=K_diss, reactant_types=[0], reactant_coefficients=[1],
+                product_types=[1, 2], product_coefficients=[1, 1],
+                default_charges={0: 0, 1: -1, 2: +1})
+cpH.add_reaction(gamma=1/(10**-14/K_diss), reactant_types=[3], reactant_coefficients=[1], product_types=[0, 2], product_coefficients=[1, 1], default_charges={0:0, 2:1, 3:1} )
+
+
+

An example script can be found here:

+ +

In the constant pH method due to Reed and Reed +[Reed and Reed, 1992] it is possible to set the chemical potential +of \(H^{+}\) ions, assuming that the simulated system is coupled to an +infinite reservoir. This value is the used to simulate dissociation +equilibrium of acids and bases. Under certain conditions, the constant +pH method can yield equivalent results as the reaction ensemble [Landsgesell et al., 2017]. However, it +treats the chemical potential of \(H^{+}\) ions and their actual +number in the simulation box as independent variables, which can lead to +serious artifacts. +The constant pH method can be used within the reaction ensemble module by +initializing the reactions with the standard commands of the reaction ensemble.

+

The dissociation constant, which is the input of the constant pH method, is the equilibrium +constant \(K_c\) for the following reaction:

+
+\[\mathrm{HA \rightleftharpoons\ H^+ + A^- } \,,\]
+

For a description of the available methods, see espressomd.reaction_methods.ConstantpHEnsemble.

+
+
+

19.1.4. Widom Insertion (for homogeneous systems)

+

The Widom insertion method [Widom, 1963] measures the change in excess free energy, i.e. the excess chemical potential due to the insertion of a new particle, or a group of particles:

+
+\[\begin{split}\mu^\mathrm{ex}_B & :=\Delta F^\mathrm{ex} =F^\mathrm{ex}(N_B+1,V,T)-F^\mathrm{ex}(N_B,V,T)\\ +&=-kT \ln \left(\frac{1}{V} \int_V d^3r_{N_B+1} \langle \exp(-\beta \Delta E_\mathrm{pot}) \rangle_{N_B} \right)\end{split}\]
+

For this one has to provide the following reaction to the Widom method:

+
type_B=1
+widom = reaction_methods.WidomInsertion(
+    temperature=temperature, seed=77)
+widom.add_reaction(reactant_types=[],
+reactant_coefficients=[], product_types=[type_B],
+product_coefficients=[1], default_charges={1: 0})
+widom.calculate_particle_insertion_potential_energy(reaction_id=0)
+
+
+

The call of add_reaction define the insertion \(\mathrm{\emptyset \to type_B}\) (which is the 0th defined reaction). +Multiple reactions for the insertions of different types can be added to the same WidomInsertion instance. +Measuring the excess chemical potential using the insertion method is done by +calling widom.calculate_particle_insertion_potential_energy(reaction_id=0) +multiple times and providing the accumulated sample to +widom.calculate_excess_chemical_potential(particle_insertion_potential_energy_samples=samples). +If another particle insertion is defined, then the excess chemical potential +for this insertion can be measured in a similar fashion by sampling +widom.calculate_particle_insertion_potential_energy(reaction_id=1). +Be aware that the implemented method only works for the canonical ensemble. If the numbers of particles fluctuate (i.e. in a semi grand canonical simulation) one has to adapt the formulas from which the excess chemical potential is calculated! This is not implemented. Also in a isobaric-isothermal simulation (NpT) the corresponding formulas for the excess chemical potentials need to be adapted. This is not implemented.

+

The implementation can also deal with the simultaneous insertion of multiple particles and can therefore measure the change of excess free energy of multiple particles like e.g.:

+
+\[\begin{split}\mu^\mathrm{ex, pair}&:=\Delta F^\mathrm{ex, pair}:= F^\mathrm{ex}(N_1+1, N_2+1,V,T)-F^\mathrm{ex}(N_1, N_2 ,V,T)\\ +&=-kT \ln \left(\frac{1}{V^2} \int_V \int_V d^3r_{N_1+1} d^3 r_{N_2+1} \langle \exp(-\beta \Delta E_\mathrm{pot}) \rangle_{N_1, N_2} \right)\end{split}\]
+

Note that the measurement involves three averages: the canonical ensemble average \(\langle \cdot \rangle_{N_1, N_2}\) and the two averages over the position of particles \(N_1+1\) and \(N_2+1\). +Since the averages over the position of the inserted particles are obtained via brute force sampling of the insertion positions it can be beneficial to have multiple insertion tries on the same configuration of the other particles.

+

One can measure the change in excess free energy due to the simultaneous insertions of particles of type 1 and 2 and the simultaneous removal of a particle of type 3:

+
+\[\mu^\mathrm{ex}:=\Delta F^\mathrm{ex, }:= F^\mathrm{ex}(N_1+1, N_2+1, N_3-1,V,T)-F^\mathrm{ex}(N_1, N_2, N_3 ,V,T)\]
+

For this one has to provide the following reaction to the Widom method:

+
widom.add_reaction(reactant_types=[type_3],
+reactant_coefficients=[1], product_types=[type_1, type_2],
+product_coefficients=[1,1], default_charges={1: 0})
+widom.calculate_particle_insertion_potential_energy(reaction_id=0)
+
+
+

Be aware that in the current implementation, for MC moves which add +and remove particles, the insertion of the new particle always takes +place at the position where the last particle was removed. Be sure +that this is the behavior you want to have. Otherwise implement a new +function WidomInsertion::make_reaction_attempt in the core.

+

An example script which demonstrates how to measure the pair excess +chemical potential for inserting an ion pair into a salt solution +can be found here:

+ +

For a description of the available methods, see espressomd.reaction_methods.WidomInsertion.

+
+
+
+

19.2. Practical considerations

+
+

19.2.1. Converting tabulated reaction constants to internal units in ESPResSo

+

The implementation in ESPResSo requires that the dimension of \(\Gamma\) +is consistent with the internal unit of volume, \(\sigma^3\). The tabulated +values of equilibrium constants for reactions in solution, \(K_c\), typically use +\(c^{\ominus} = 1\,\mathrm{moldm^{-3}}\) as the reference concentration, +and have the dimension of \((c^{\ominus})^{\bar\nu}\). To be used with ESPResSo, the +value of \(K_c\) has to be converted as

+
+\[\Gamma = K_c(c^{\ominus} = 1/\sigma^3) = K_c(c^{\ominus} = 1\,\mathrm{moldm^{-3}}) +\Bigl( N_{\mathrm{A}}\bigl(\frac{\sigma}{\mathrm{dm}}\bigr)^3\Bigr)^{\bar\nu}\]
+

where \(N_{\mathrm{A}}\) is the Avogadro number. For gas-phase reactions, +the pressure-based reaction constant, \(K_p\) is often used, which can +be converted to \(K_c\) as

+
+\[K_p(p^{\ominus}=1\,\mathrm{atm}) = K_c(c^{\ominus} = 1\,\mathrm{moldm^{-3}}) \biggl(\frac{c^{\ominus}RT}{p^{\ominus}}\biggr)^{\bar\nu},\]
+

where \(p^{\ominus}=1\,\mathrm{atm}\) is the standard pressure. +Consider using the python module pint for unit conversion.

+
+
+

19.2.2. Coupling reaction methods to molecular dynamics

+

The Monte Carlo (MC) sampling of the reaction can be coupled with a configurational sampling using Molecular Dynamics (MD). +For non-interacting systems this coupling is not an issue, but for interacting systems the insertion of new particles +can lead to instabilities in the MD integration ultimately leading to a crash of the simulation.

+

This integration instabilities can be avoided by defining a distance around the particles which already exist in the system +where new particles will not be inserted, which is defined by the required keyword exclusion_range. +This prevents big overlaps with the newly inserted particles, avoiding too big forces between particles, which prevents the MD integration from crashing. +The value of the exclusion range does not affect the limiting result and it only affects the convergence and the stability of the integration. For interacting systems, +it is usually a good practice to choose the exclusion range such that it is comparable to the diameter of the particles.

+

If particles with significantly different sizes are present, it is desired to define a different exclusion range for each pair of particle types. This can be done by +defining an exclusion radius per particle type by using the optional argument exclusion_radius_per_type. Then, their exclusion range is calculated using +the Lorentz-Berthelot combination rule, i.e. exclusion_range = exclusion_radius_per_type[particle_type_1] + exclusion_radius_per_type[particle_type_2]. +If the exclusion radius of one particle type is not defined, the value of the parameter provided in exclusion_range is used by default. +If the value in exclusion_radius_per_type is equal to 0, then the exclusion range of that particle type with any other particle is 0.

+
+
+
+ + +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/doc4.2.2/running.html b/doc4.2.2/running.html new file mode 100644 index 0000000000..939f232b64 --- /dev/null +++ b/doc4.2.2/running.html @@ -0,0 +1,515 @@ + + + + + + + + + 3. Running a simulation — ESPResSo 4.2.2 documentation + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +
+

3. Running a simulation

+

ESPResSo is implemented as a Python module. This means that you need to write a +python script for any task you want to perform with ESPResSo. In this chapter, +the basic structure of the interface will be explained. For a practical +introduction, see the tutorials, which are also part of the +distribution.

+
+

3.1. Running ESPResSo

+
+

3.1.1. Running a script

+

To use ESPResSo, you need to import the espressomd module in your +Python script. To this end, the folder containing the python module +needs to be in the Python search path. The module is located in the +src/python folder under the build directory.

+

A convenient way to run Python with the correct path is to use the +pypresso script located in the build directory:

+
./pypresso simulation.py
+
+
+

The pypresso script is just a wrapper in order to expose the ESPResSo python +module to the system’s Python interpreter by modifying the $PYTHONPATH. +If you have installed ESPResSo from a Linux package manager that doesn’t provide +the pypresso script, you will need to modify the $PYTHONPATH and +possibly the $LD_LIBRARY_PATH too, depending on which symbols are missing.

+

The next chapter, Setting up the system, will explain in more details +how to write a simulation script for ESPResSo. If you don’t have any script, +simply call one of the files listed in section Sample scripts.

+
+
+

3.1.2. Using the console

+

Since ESPResSo can be manipulated like any other Python module, it is possible +to interact with it in a Python interpreter. Simply run the pypresso +script without arguments to start a Python session:

+
./pypresso
+
+
+

Likewise, a Jupyter console can be started with the ipypresso script, +which is also located in the build directory:

+
./ipypresso console
+
+
+

The name comes from the IPython interpreter, today known as Jupyter.

+
+
+

3.1.3. Interactive notebooks

+

Tutorials are available as notebooks, i.e. they consist of a .ipynb +file which contains both the source code and the corresponding explanations. +They can be viewed, changed and run interactively. To generate the tutorials +in the build folder, do:

+
make tutorials
+
+
+

The tutorials contain solutions hidden with the exercise2 NB extension. +Since this extension is only available for Jupyter Notebook, JupyterLab +users need to convert the tutorials:

+
for f in doc/tutorials/*/*.ipynb; do
+  ./pypresso doc/tutorials/convert.py exercise2 --to-jupyterlab ${f}
+done
+
+
+

Likewise, VS Code Jupyter users need to convert the tutorials:

+
for f in doc/tutorials/*/*.ipynb; do
+  ./pypresso doc/tutorials/convert.py exercise2 --to-vscode-jupyter ${f}
+done
+
+
+

To interact with notebooks, move to the directory containing the tutorials +and call the ipypresso script to start a local Jupyter session.

+

For Jupyter Notebook and IPython users:

+
cd doc/tutorials
+../../ipypresso notebook
+
+
+

For JupyterLab users:

+
cd doc/tutorials
+../../ipypresso lab
+
+
+

For VS Code Jupyter users, no action is needed if pypresso was set as +the interpreter path (see details in Running inside an IDE).

+

You may then browse through the different tutorial folders. Files whose name +ends with extension .ipynb can be opened in the browser. Click on the Run +button to execute the current block, or use the keyboard shortcut Shift+Enter. +If the current block is a code block, the In [ ] label to the left will +change to In [*] while the code is being executed, and become In [1] +once the execution has completed. The number increments itself every time a +code cell is executed. This bookkeeping is extremely useful when modifying +previous code cells, as it shows which cells are out-of-date. It’s also +possible to run all cells by clicking on the “Run” drop-down menu, then on +“Run All Below”. This will change all labels to In [*] to show that the +first one is running, while the subsequent ones are awaiting execution.

+

You’ll also see that many cells generate an output. When the output becomes +very long, Jupyter will automatically put it in a box with a vertical scrollbar. +The output may also contain static plots, dynamic plots and videos. It is also +possible to start a 3D visualizer in a new window, however closing the window +will exit the Python interpreter and Jupyter will notify you that the current +Python kernel stopped. If a cell takes too long to execute, you may interrupt +it with the stop button.

+

Solutions cells are created using the exercise2 plugin from nbextensions. +To prevent solution code cells from running when clicking on “Run All”, these +code cells need to be converted to Markdown cells and fenced with ```python +and ```.

+

To close the Jupyter session, go to the terminal where it was started and use +the keyboard shortcut Ctrl+C twice.

+

When starting a Jupyter session, you may see the following warning in the +terminal:

+
[TerminalIPythonApp] WARNING | Subcommand `ipython notebook` is deprecated and will be removed in future versions.
+[TerminalIPythonApp] WARNING | You likely want to use `jupyter notebook` in the future
+
+
+

This only means ESPResSo was compiled with IPython instead of Jupyter. If Jupyter +is installed on your system, the notebook will automatically close IPython and +start Jupyter. To recompile ESPResSo with Jupyter, provide cmake with the flag +-DIPYTHON_EXECUTABLE=$(which jupyter).

+

You can find the official Jupyter documentation at +https://jupyter.readthedocs.io/en/latest/running.html

+
+
+

3.1.4. Running inside an IDE

+

You can use an integrated development environment (IDE) to develop and run ESPResSo +scripts. Suitable IDEs are e.g. Visual Studio Code and Spyder. They can +provide a workflow superior to that of a standard text editor as they offer +useful features such as advanced code completion, debugging and analysis tools +etc. The following example shows how to setup ESPResSo in Visual Studio Code on +Linux (tested with version 1.46.1). The process should be similar for every +Python IDE, namely the Python interpreter needs to be replaced.

+

The pypresso executable can be set as a custom Python interpreter inside VS +Code. ESPResSo scripts can then be executed just like any other python script. +Inside VS Code, the Python extension needs to be installed. Next, click the +gear at the bottom left and choose Settings. Search for +Default Interpreter Path and change the setting to the path to your +pypresso executable, e.g.

+
~/espresso/build/pypresso
+
+
+

After that, you can open scripts and execute them with the keyboard shortcut +Ctrl+F5.

+

Fig. Visual Studio Code interface shows the VS Code interface with the interpreter +path set to pypresso.

+
+

Note

+

You may need to set the path relative to your home directory, i.e. ~/path/to/pypresso.

+
+
+Visual Studio Code interface with the default interpreter path set to the ``pypresso`` executable +
+

Visual Studio Code interface

+
+
+
+
+
+

3.2. Debugging ESPResSo

+

Exceptional situations occur in every program. If ESPResSo crashes with a +segmentation fault, that means that there was a memory fault in the +simulation core which requires running the program in a debugger. The +pypresso executable file is actually not a program but a script +which sets the Python path appropriately and starts the Python +interpreter with your arguments. Thus it is not possible to directly +run pypresso in a debugger. However, we provide some useful +command line options for the most common tools.

+
./pypresso --tool <args>
+
+
+

where --tool can be any tool from the table below. +Only one tool can be used at a time. Some tools benefit from specific build +options, as outlined in the installation section Troubleshooting. +ESPResSo can be debugged in MPI environments, as outlined in section +Debugging parallel code.

+ + ++++ + + + + + + + + + + + + + + + + + + + + + + +
Tools for the Python wrapper to ESPResSo.

Tool

Effect

--gdb

gdb --args python <args>

--lldb

lldb -- python <args>

--valgrind

valgrind --leak-check=full python <args>

--cuda-gdb

cuda-gdb --args python <args>

--cuda-memcheck

cuda-memcheck python <args>

+
+
+

3.3. Parallel computing

+

Many algorithms in ESPResSo are designed to work with multiple MPI ranks. +However, not all algorithms benefit from MPI parallelization equally. +Several algorithms only use MPI rank 0 (e.g. Reaction methods). +ESPResSo should work with most MPI implementations on the market; +see the MPI installation requirements for details.

+
+

3.3.1. General syntax

+

To run a simulation on several MPI ranks, for example 4, simply invoke +the pypresso script with the following syntax:

+
mpiexec -n 4 ./pypresso simulation.py
+
+
+

The cell system is automatically split among the MPI ranks, and data +is automatically gathered on the main rank, which means a regular ESPResSo +script can be executed in an MPI environment out-of-the-box. The number +of MPI ranks can be accessed via the system n_nodes state property. +The simulation box partition is controlled by the cell system +node_grid property. +By default, MPI ranks are assigned in decreasing order, e.g. on 6 MPI ranks +node_grid is [3, 2, 1]. It is possible to re-assign the ranks by +changing the value of the node_grid property, however a few algorithms +(such as FFT-based electrostatic methods) only work for the default +partitioning scheme where values must be arranged in decreasing order.

+
# get the number of ranks
+print(system.cell_system.get_state()["n_nodes"])
+# re-assign the ranks
+system.cell_system.node_grid = [2, 1, 3]
+system.cell_system.node_grid = [6, 1, 1]
+
+
+

There are alternative ways to invoke MPI on pypresso, but they share +similar options. The number after the -n option is the number of ranks, +which needs to be inferior or equal to the number of physical cores on the +workstation. Command nproc displays the number of logical cores on the +workstation. For architectures that support hyperthreading, the number of +logical cores is an integer multiple of the number of physical cores, +usually 2. Therefore on a hyperthreaded workstation with 32 cores, +at most 16 cores can be used without major performance loss, unless +extra arguments are passed to the mpiexec program.

+

On cluster computers, it might be necessary to load the MPI library with +module load openmpi or similar.

+
+
+

3.3.2. Performance gain

+

Simulations executed in parallel with run faster, however the runtime +won’t decrease linearly with the number of MPI ranks. MPI-parallel +simulations introduce several sources of overhead and latency:

+
    +
  • overhead of serializing, communicating and deserializing data structures

  • +
  • extra calculations in the LB halo

  • +
  • extra calculations in the ghost shell +(see section Internal particle organization for more details)

  • +
  • latency due to blocking communication (i.e. a node remains idle +while waiting for a message from another node)

  • +
  • latency due to blocking data collection for GPU +(only relevant for GPU methods)

  • +
  • latency due to context switching

  • +
  • latency due to memory bandwidth

  • +
+

While good performance can be achieved up to 32 MPI ranks, allocating more +than 32 ranks to a simulation will not always lead to significantly improved +run times. The performance gain is highly sensitive to the algorithms used +by the simulation, for example GPU methods rarely benefit from more than +8 MPI ranks. Performance is also affected by the number of features enabled +at compile time, even when these features are not used by the simulation; +do not hesitate to remove all features not required by the +simulation script and rebuild ESPResSo for optimal performance.

+

Benchmarking is often the best way to determine the optimal number of MPI +ranks for a given simulation setup. Please refer to the wiki chapter on +benchmarking +for more details.

+

Runtime speed-up is not the only appeal of MPI parallelization. Another +benefit is the possibility to distribute a calculation over multiple +compute nodes in clusters and high-performance environments, and therefore +split the data structures over multiple machines. This becomes necessary +when running simulations with millions of particles, as the memory +available on a single compute node would otherwise saturate.

+
+
+

3.3.3. Communication model

+

ESPResSo was originally designed for the “flat” model of communication: +each MPI rank binds to a logical CPU core. This communication model +doesn’t fully leverage shared memory on recent CPUs, such as NUMA +architectures, +and ESPResSo currently doesn’t support the hybrid +MPI+OpenMP programming model.

+

The MPI+CUDA programming model is supported, although only one GPU can be +used for the entire simulation. As a result, a blocking gather operation +is carried out to collect data from all ranks to the main rank, and a +blocking scatter operation is carried out to transfer the result of the +GPU calculation from the main rank back to all ranks. This latency limits +GPU-acceleration to simulations running on fewer than 8 MPI ranks. +For more details, see section GPU acceleration.

+
+

3.3.3.1. The MPI callbacks framework

+

When starting a simulation with \(n\) MPI ranks, ESPResSo will internally +use MPI rank \(0\) as the head node (also referred to as the “main rank”) +and MPI ranks \(1\) to \(n-1\) as worker nodes. The Python interface +interacts only with the head node, and the head node forwards the information +to the worker nodes.

+

To put it another way, all worker nodes are idle until the user calls +a function that is designed to run in parallel, +in which case the head node calls the corresponding core function +and sends a request on the worker nodes to call the same core function. +The request can be a simple collective call, or a collective call with a +reduction if the function returns a value. The reduction can either:

+
    +
  • combine the \(n\) results via a mathematical operation +(usually a summation or a multiplication)

  • +
  • discard the result of the \(n-1\) worker nodes; this is done when +all ranks return the same value, or when the calculation can only be +carried out on the main rank but requires data from the other ranks

  • +
  • return the result of one rank when the calculation can only be carried out +by a specific rank; this is achieved by returning an optional, which +contains a value on the rank that has access to the information necessary +to carry out the calculation, while the other \(n-1\) ranks return +an empty optional

  • +
+

For more details on this framework, please refer to the Doxygen documentation +of the the C++ core file MpiCallbacks.hpp.

+
+
+
+

3.3.4. Debugging parallel code

+

It is possible to debug an MPI-parallel simulation script with GDB. +Keep in mind that contrary to a textbook example MPI application, where +all ranks execute the main function, in ESPResSo the worker nodes are idle +until the head node on MPI rank 0 delegates work to them. This means that +on MPI rank > 1, break points will only have an effect in code that can be +reached from a callback function whose pointer has been registered in the +MPI callbacks framework.

+

The following command runs a script with 2 MPI ranks and binds a terminal +to each rank:

+
mpiexec -np 2 xterm -fa 'Monospace' -fs 12 -e ./pypresso --gdb simulation.py
+
+
+

It can also be done via ssh with X-window forwarding:

+
ssh -X username@hostname
+mpiexec -n 2 -x DISPLAY="${DISPLAY}" xterm -fa 'Monospace' -fs 12 \
+    -e ./pypresso --gdb simulation.py
+
+
+

The same syntax is used for C++ unit tests:

+
mpiexec -np 2 xterm -fa 'Monospace' -fs 12 \
+    -e gdb src/core/unit_tests/EspressoSystemStandAlone_test
+
+
+
+
+
+

3.4. GPU acceleration

+
+

3.4.1. CUDA acceleration

+
+

Note

+

Feature CUDA required

+
+

ESPResSo is capable of delegating work to the GPU to speed up simulations. +Not every simulation method profits from GPU acceleration. +Refer to Available simulation methods +to check whether your desired method can be used on the GPU. +In order to use GPU acceleration you need a NVIDIA GPU +and it needs to have at least compute capability 2.0. +For more details, please refer to the installation section +Nvidia GPU acceleration.

+

For more information please check espressomd.cuda_init.CudaInitHandle.

+
+

3.4.1.1. List available devices

+

To list available CUDA devices, call +espressomd.cuda_init.CudaInitHandle.list_devices():

+
>>> import espressomd
+>>> system = espressomd.System(box_l=[1, 1, 1])
+>>> print(system.cuda_init_handle.list_devices())
+{0: 'GeForce RTX 2080', 1: 'GeForce GT 730'}
+
+
+

This method returns a dictionary containing +the device id as key and the device name as its value.

+

To get more details on the CUDA devices for each MPI node, call +espressomd.cuda_init.CudaInitHandle.list_devices_properties():

+
>>> import pprint
+>>> import espressomd
+>>> system = espressomd.System(box_l=[1, 1, 1])
+>>> pprint.pprint(system.cuda_init_handle.list_devices_properties())
+{'seraue': {0: {'name': 'GeForce RTX 2080',
+                'compute_capability': (7, 5),
+                'cores': 46,
+                'total_memory': 8370061312},
+            1: {'name': 'GeForce GT 730',
+                'compute_capability': (3, 5),
+                'cores': 2,
+                'total_memory': 1014104064}}}
+
+
+
+
+

3.4.1.2. Select a device

+

When you start pypresso, the first GPU should be selected. +If you wanted to use the second GPU, this can be done +by setting espressomd.cuda_init.CudaInitHandle.device as follows:

+
>>> import espressomd
+>>> system = espressomd.System(box_l=[1, 1, 1])
+>>> system.cuda_init_handle.device = 1
+
+
+

Setting a device id outside the valid range or a device +which does not meet the minimum requirements will raise +an exception.

+
+
+
+
+ + +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/doc4.2.2/search.html b/doc4.2.2/search.html new file mode 100644 index 0000000000..edeb9faa45 --- /dev/null +++ b/doc4.2.2/search.html @@ -0,0 +1,96 @@ + + + + + + + + Search — ESPResSo 4.2.2 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Search

+ + + + +

+ Searching for multiple words only shows matches that contain + all words. +

+ + +
+ + + +
+ + + +
+ +
+ + +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/doc4.2.2/searchindex.js b/doc4.2.2/searchindex.js new file mode 100644 index 0000000000..3b153f1692 --- /dev/null +++ b/doc4.2.2/searchindex.js @@ -0,0 +1 @@ +Search.setIndex({docnames:["advanced_methods","analysis","appendix","bibliography","community","constraints","contributing","ek","electrostatics","espressomd","espressomd.MDA_ESP","espressomd.io","espressomd.io.writer","index","installation","integration","inter_bonded","inter_non-bonded","introduction","io","lb","magnetostatics","modules","particles","reaction_methods","running","system_manipulation","system_setup","under_the_hood","visualization"],envversion:{"sphinx.domains.c":2,"sphinx.domains.changeset":1,"sphinx.domains.citation":1,"sphinx.domains.cpp":4,"sphinx.domains.index":1,"sphinx.domains.javascript":2,"sphinx.domains.math":2,"sphinx.domains.python":3,"sphinx.domains.rst":2,"sphinx.domains.std":2,"sphinx.ext.todo":2,"sphinx.ext.viewcode":1,"sphinxcontrib.bibtex":9,sphinx:56},filenames:["advanced_methods.rst","analysis.rst","appendix.rst","bibliography.rst","community.rst","constraints.rst","contributing.rst","ek.rst","electrostatics.rst","espressomd.rst","espressomd.MDA_ESP.rst","espressomd.io.rst","espressomd.io.writer.rst","index.rst","installation.rst","integration.rst","inter_bonded.rst","inter_non-bonded.rst","introduction.rst","io.rst","lb.rst","magnetostatics.rst","modules.rst","particles.rst","reaction_methods.rst","running.rst","system_manipulation.rst","system_setup.rst","under_the_hood.rst","visualization.rst"],objects:{"":{espressomd:[9,0,0,"-"]},"espressomd.MDA_ESP":{ESPParser:[10,2,1,""],ESPReader:[10,2,1,""],Stream:[10,2,1,""],Timestep:[10,2,1,""]},"espressomd.MDA_ESP.ESPParser":{format:[10,3,1,""],parse:[10,4,1,""]},"espressomd.MDA_ESP.ESPReader":{format:[10,3,1,""],units:[10,3,1,""]},"espressomd.MDA_ESP.Stream":{trajectory:[10,5,1,""]},"espressomd.MDA_ESP.Timestep":{dimensions:[10,5,1,""]},"espressomd.accumulators":{AutoUpdateAccumulators:[9,2,1,""],Correlator:[9,2,1,""],MeanVarianceCalculator:[9,2,1,""],TimeSeries:[9,2,1,""]},"espressomd.accumulators.AutoUpdateAccumulators":{add:[9,4,1,""],clear:[9,4,1,""],remove:[9,4,1,""]},"espressomd.accumulators.Correlator":{lag_times:[9,4,1,""],result:[9,4,1,""],sample_sizes:[9,4,1,""]},"espressomd.accumulators.MeanVarianceCalculator":{mean:[9,4,1,""],std_error:[9,4,1,""],update:[9,4,1,""],variance:[9,4,1,""]},"espressomd.accumulators.TimeSeries":{clear:[9,4,1,""],time_series:[9,4,1,""],update:[9,4,1,""]},"espressomd.actors":{Actors:[9,2,1,""]},"espressomd.actors.Actors":{active_actors:[9,3,1,""],add:[9,4,1,""],clear:[9,4,1,""],remove:[9,4,1,""]},"espressomd.analyze":{Analysis:[9,2,1,""],autocorrelation:[9,6,1,""]},"espressomd.analyze.Analysis":{angular_momentum:[9,4,1,""],calc_re:[9,4,1,""],calc_rg:[9,4,1,""],calc_rh:[9,4,1,""],center_of_mass:[9,4,1,""],check_topology:[9,4,1,""],distribution:[9,4,1,""],dpd_stress:[9,4,1,""],energy:[9,4,1,""],gyration_tensor:[9,4,1,""],linear_momentum:[9,4,1,""],min_dist:[9,4,1,""],moment_of_inertia_matrix:[9,4,1,""],nbhood:[9,4,1,""],particle_energy:[9,4,1,""],pressure:[9,4,1,""],pressure_tensor:[9,4,1,""],structure_factor:[9,4,1,""]},"espressomd.bond_breakage":{BreakageSpec:[9,2,1,""],BreakageSpecs:[9,2,1,""]},"espressomd.cell_system":{CellSystem:[9,2,1,""]},"espressomd.cell_system.CellSystem":{decomposition_type:[9,3,1,""],get_neighbors:[9,4,1,""],get_pairs:[9,4,1,""],get_state:[9,4,1,""],interaction_range:[9,3,1,""],max_cut_bonded:[9,3,1,""],max_cut_nonbonded:[9,3,1,""],node_grid:[9,3,1,""],non_bonded_loop_trace:[9,4,1,""],resort:[9,4,1,""],set_hybrid_decomposition:[9,4,1,""],set_n_square:[9,4,1,""],set_regular_decomposition:[9,4,1,""],skin:[9,3,1,""],tune_skin:[9,4,1,""],use_verlet_lists:[9,3,1,""]},"espressomd.checkpointing":{Checkpoint:[9,2,1,""]},"espressomd.checkpointing.Checkpoint":{get_last_checkpoint_index:[9,4,1,""],get_registered_objects:[9,4,1,""],has_checkpoints:[9,4,1,""],load:[9,4,1,""],read_signals:[9,4,1,""],register:[9,4,1,""],register_signal:[9,4,1,""],save:[9,4,1,""],unregister:[9,4,1,""]},"espressomd.cluster_analysis":{Cluster:[9,2,1,""],ClusterStructure:[9,2,1,""],Clusters:[9,2,1,""]},"espressomd.cluster_analysis.Cluster":{center_of_mass:[9,4,1,""],fractal_dimension:[9,4,1,""],longest_distance:[9,4,1,""],particle_ids:[9,4,1,""],particles:[9,4,1,""],size:[9,4,1,""]},"espressomd.cluster_analysis.ClusterStructure":{cid_for_particle:[9,4,1,""],clear:[9,4,1,""],cluster_ids:[9,4,1,""],clusters:[9,5,1,""],run_for_all_pairs:[9,4,1,""],run_for_bonded_particles:[9,4,1,""]},"espressomd.collision_detection":{CollisionDetection:[9,2,1,""]},"espressomd.collision_detection.CollisionDetection":{get_parameter:[9,4,1,""],get_params:[9,4,1,""],set_params:[9,4,1,""]},"espressomd.comfixed":{ComFixed:[9,2,1,""]},"espressomd.constraints":{Constraint:[9,2,1,""],Constraints:[9,2,1,""],ElectricPlaneWave:[9,2,1,""],ElectricPotential:[9,2,1,""],FlowField:[9,2,1,""],ForceField:[9,2,1,""],Gravity:[9,2,1,""],HomogeneousFlowField:[9,2,1,""],HomogeneousMagneticField:[9,2,1,""],LinearElectricPotential:[9,2,1,""],PotentialField:[9,2,1,""],ShapeBasedConstraint:[9,2,1,""]},"espressomd.constraints.Constraints":{add:[9,4,1,""],clear:[9,4,1,""],remove:[9,4,1,""]},"espressomd.constraints.ElectricPlaneWave":{E0:[9,5,1,""],k:[9,5,1,""],omega:[9,5,1,""],phi:[9,5,1,""]},"espressomd.constraints.Gravity":{g:[9,5,1,""]},"espressomd.constraints.HomogeneousFlowField":{gamma:[9,3,1,""],u:[9,5,1,""]},"espressomd.constraints.HomogeneousMagneticField":{H:[9,3,1,""]},"espressomd.constraints.LinearElectricPotential":{E:[9,5,1,""],phi0:[9,5,1,""]},"espressomd.constraints.ShapeBasedConstraint":{min_dist:[9,4,1,""],only_positive:[9,3,1,""],particle_type:[9,3,1,""],particle_velocity:[9,3,1,""],penetrable:[9,3,1,""],shape:[9,3,1,""],total_force:[9,4,1,""],total_normal_force:[9,4,1,""]},"espressomd.cuda_init":{CudaInitHandle:[9,2,1,""],gpu_available:[9,6,1,""]},"espressomd.cuda_init.CudaInitHandle":{device:[9,3,1,""],list_devices:[9,4,1,""],list_devices_properties:[9,4,1,""]},"espressomd.drude_helpers":{DrudeHelpers:[9,2,1,""]},"espressomd.drude_helpers.DrudeHelpers":{add_all_thole:[9,4,1,""],add_drude_particle_to_core:[9,4,1,""],add_intramol_exclusion_bonds:[9,4,1,""],add_thole_pair_damping:[9,4,1,""],setup_and_add_drude_exclusion_bonds:[9,4,1,""],setup_intramol_exclusion_bonds:[9,4,1,""]},"espressomd.ekboundaries":{EKBoundaries:[9,2,1,""],EKBoundary:[9,2,1,""]},"espressomd.electrokinetics":{Electrokinetics:[9,2,1,""],ElectrokineticsRoutines:[9,2,1,""],SpecieRoutines:[9,2,1,""],Species:[9,2,1,""]},"espressomd.electrokinetics.Electrokinetics":{add_boundary:[9,4,1,""],add_reaction:[9,4,1,""],add_species:[9,4,1,""],default_params:[9,4,1,""],ek_init:[9,4,1,""],get_params:[9,4,1,""],load_checkpoint:[9,4,1,""],neutralize_system:[9,4,1,""],required_keys:[9,4,1,""],save_checkpoint:[9,4,1,""],set_density:[9,4,1,""],valid_keys:[9,4,1,""],validate_params:[9,4,1,""],write_vtk_boundary:[9,4,1,""],write_vtk_density:[9,4,1,""],write_vtk_lbforce:[9,4,1,""],write_vtk_particle_potential:[9,4,1,""],write_vtk_potential:[9,4,1,""],write_vtk_velocity:[9,4,1,""]},"espressomd.electrokinetics.ElectrokineticsRoutines":{potential:[9,3,1,""]},"espressomd.electrokinetics.SpecieRoutines":{density:[9,3,1,""],flux:[9,3,1,""]},"espressomd.electrokinetics.Species":{default_params:[9,4,1,""],get_params:[9,4,1,""],id:[9,3,1,""],py_number_of_species:[9,3,1,""],required_keys:[9,4,1,""],valid_keys:[9,4,1,""],write_vtk_density:[9,4,1,""],write_vtk_flux:[9,4,1,""],write_vtk_flux_fluc:[9,4,1,""],write_vtk_flux_link:[9,4,1,""]},"espressomd.electrostatic_extensions":{ElectrostaticExtensions:[9,2,1,""],ICC:[9,2,1,""]},"espressomd.electrostatic_extensions.ElectrostaticExtensions":{default_params:[9,4,1,""],required_keys:[9,4,1,""],valid_keys:[9,4,1,""],validate_params:[9,4,1,""]},"espressomd.electrostatic_extensions.ICC":{default_params:[9,4,1,""],last_iterations:[9,4,1,""],required_keys:[9,4,1,""],valid_keys:[9,4,1,""],validate_params:[9,4,1,""]},"espressomd.electrostatics":{DH:[9,2,1,""],ELC:[9,2,1,""],ElectrostaticInteraction:[9,2,1,""],MMM1D:[9,2,1,""],MMM1DGPU:[9,2,1,""],P3M:[9,2,1,""],P3MGPU:[9,2,1,""],ReactionField:[9,2,1,""],Scafacos:[9,2,1,""]},"espressomd.electrostatics.DH":{default_params:[9,4,1,""],required_keys:[9,4,1,""],valid_keys:[9,4,1,""]},"espressomd.electrostatics.ELC":{default_params:[9,4,1,""],required_keys:[9,4,1,""],valid_keys:[9,4,1,""],validate_params:[9,4,1,""]},"espressomd.electrostatics.ElectrostaticInteraction":{default_params:[9,4,1,""],required_keys:[9,4,1,""],valid_keys:[9,4,1,""],validate_params:[9,4,1,""]},"espressomd.electrostatics.MMM1D":{default_params:[9,4,1,""],required_keys:[9,4,1,""],valid_keys:[9,4,1,""],validate_params:[9,4,1,""]},"espressomd.electrostatics.MMM1DGPU":{default_params:[9,4,1,""],required_keys:[9,4,1,""],valid_keys:[9,4,1,""],validate_params:[9,4,1,""]},"espressomd.electrostatics.ReactionField":{default_params:[9,4,1,""],required_keys:[9,4,1,""],valid_keys:[9,4,1,""]},"espressomd.electrostatics.Scafacos":{default_params:[9,4,1,""],get_available_methods:[9,4,1,""],get_near_field_delegation:[9,4,1,""],required_keys:[9,4,1,""],set_near_field_delegation:[9,4,1,""],valid_keys:[9,4,1,""],validate_params:[9,4,1,""]},"espressomd.galilei":{GalileiTransform:[9,2,1,""]},"espressomd.galilei.GalileiTransform":{galilei_transform:[9,4,1,""],kill_particle_forces:[9,4,1,""],kill_particle_motion:[9,4,1,""],system_CMS:[9,4,1,""],system_CMS_velocity:[9,4,1,""]},"espressomd.highlander":{ThereCanOnlyBeOne:[9,1,1,""],highlander:[9,6,1,""]},"espressomd.integrate":{BrownianDynamics:[9,2,1,""],Integrator:[9,2,1,""],IntegratorHandle:[9,2,1,""],SteepestDescent:[9,2,1,""],StokesianDynamics:[9,2,1,""],VelocityVerlet:[9,2,1,""],VelocityVerletIsotropicNPT:[9,2,1,""]},"espressomd.integrate.BrownianDynamics":{default_params:[9,4,1,""],required_keys:[9,4,1,""],valid_keys:[9,4,1,""],validate_params:[9,4,1,""]},"espressomd.integrate.Integrator":{default_params:[9,4,1,""],get_params:[9,4,1,""],required_keys:[9,4,1,""],run:[9,4,1,""],valid_keys:[9,4,1,""],validate_params:[9,4,1,""]},"espressomd.integrate.IntegratorHandle":{force_cap:[9,3,1,""],get_state:[9,4,1,""],run:[9,4,1,""],set_brownian_dynamics:[9,4,1,""],set_isotropic_npt:[9,4,1,""],set_nvt:[9,4,1,""],set_steepest_descent:[9,4,1,""],set_stokesian_dynamics:[9,4,1,""],set_vv:[9,4,1,""],time:[9,3,1,""],time_step:[9,3,1,""]},"espressomd.integrate.SteepestDescent":{default_params:[9,4,1,""],required_keys:[9,4,1,""],run:[9,4,1,""],valid_keys:[9,4,1,""],validate_params:[9,4,1,""]},"espressomd.integrate.StokesianDynamics":{default_params:[9,4,1,""],required_keys:[9,4,1,""],valid_keys:[9,4,1,""],validate_params:[9,4,1,""]},"espressomd.integrate.VelocityVerlet":{default_params:[9,4,1,""],required_keys:[9,4,1,""],valid_keys:[9,4,1,""],validate_params:[9,4,1,""]},"espressomd.integrate.VelocityVerletIsotropicNPT":{default_params:[9,4,1,""],required_keys:[9,4,1,""],valid_keys:[9,4,1,""],validate_params:[9,4,1,""]},"espressomd.interactions":{AngleCosine:[9,2,1,""],AngleCossquare:[9,2,1,""],AngleHarmonic:[9,2,1,""],BMHTFInteraction:[9,2,1,""],BondedCoulomb:[9,2,1,""],BondedCoulombSRBond:[9,2,1,""],BondedInteraction:[9,2,1,""],BondedInteractionNotDefined:[9,2,1,""],BondedInteractions:[9,2,1,""],BuckinghamInteraction:[9,2,1,""],DPDInteraction:[9,2,1,""],Dihedral:[9,2,1,""],FeneBond:[9,2,1,""],GaussianInteraction:[9,2,1,""],GayBerneInteraction:[9,2,1,""],GenericLennardJonesInteraction:[9,2,1,""],HarmonicBond:[9,2,1,""],HatInteraction:[9,2,1,""],HertzianInteraction:[9,2,1,""],IBM_Tribend:[9,2,1,""],IBM_Triel:[9,2,1,""],IBM_VolCons:[9,2,1,""],LennardJonesCos2Interaction:[9,2,1,""],LennardJonesCosInteraction:[9,2,1,""],LennardJonesInteraction:[9,2,1,""],MorseInteraction:[9,2,1,""],NonBondedInteraction:[9,2,1,""],NonBondedInteractionHandle:[9,2,1,""],NonBondedInteractions:[9,2,1,""],OifGlobalForces:[9,2,1,""],OifLocalForces:[9,2,1,""],QuarticBond:[9,2,1,""],RigidBond:[9,2,1,""],SmoothStepInteraction:[9,2,1,""],SoftSphereInteraction:[9,2,1,""],TabulatedAngle:[9,2,1,""],TabulatedDihedral:[9,2,1,""],TabulatedDistance:[9,2,1,""],TabulatedNonBonded:[9,2,1,""],ThermalizedBond:[9,2,1,""],Virtual:[9,2,1,""],WCAInteraction:[9,2,1,""],get_bonded_interaction_type_from_es_core:[9,6,1,""]},"espressomd.interactions.AngleCosine":{get_default_params:[9,4,1,""],type_name:[9,4,1,""],type_number:[9,4,1,""]},"espressomd.interactions.AngleCossquare":{get_default_params:[9,4,1,""],type_name:[9,4,1,""],type_number:[9,4,1,""]},"espressomd.interactions.AngleHarmonic":{get_default_params:[9,4,1,""],type_name:[9,4,1,""],type_number:[9,4,1,""]},"espressomd.interactions.BMHTFInteraction":{default_params:[9,4,1,""],is_active:[9,4,1,""],required_keys:[9,4,1,""],set_params:[9,4,1,""],type_name:[9,4,1,""],valid_keys:[9,4,1,""],validate_params:[9,4,1,""]},"espressomd.interactions.BondedCoulomb":{get_default_params:[9,4,1,""],type_name:[9,4,1,""],type_number:[9,4,1,""]},"espressomd.interactions.BondedCoulombSRBond":{get_default_params:[9,4,1,""],type_name:[9,4,1,""],type_number:[9,4,1,""]},"espressomd.interactions.BondedInteraction":{get_default_params:[9,4,1,""],params:[9,5,1,""],required_keys:[9,4,1,""],type_name:[9,4,1,""],type_number:[9,4,1,""],valid_keys:[9,4,1,""],validate_params:[9,4,1,""]},"espressomd.interactions.BondedInteractionNotDefined":{get_default_params:[9,4,1,""],required_keys:[9,4,1,""],type_name:[9,4,1,""],type_number:[9,4,1,""],valid_keys:[9,4,1,""]},"espressomd.interactions.BondedInteractions":{add:[9,4,1,""],clear:[9,4,1,""]},"espressomd.interactions.BuckinghamInteraction":{default_params:[9,4,1,""],is_active:[9,4,1,""],required_keys:[9,4,1,""],set_params:[9,4,1,""],type_name:[9,4,1,""],valid_keys:[9,4,1,""],validate_params:[9,4,1,""]},"espressomd.interactions.DPDInteraction":{default_params:[9,4,1,""],is_active:[9,4,1,""],required_keys:[9,4,1,""],set_params:[9,4,1,""],type_name:[9,4,1,""],valid_keys:[9,4,1,""],validate_params:[9,4,1,""]},"espressomd.interactions.Dihedral":{get_default_params:[9,4,1,""],type_name:[9,4,1,""],type_number:[9,4,1,""],validate_params:[9,4,1,""]},"espressomd.interactions.FeneBond":{get_default_params:[9,4,1,""],type_name:[9,4,1,""],type_number:[9,4,1,""]},"espressomd.interactions.GaussianInteraction":{default_params:[9,4,1,""],is_active:[9,4,1,""],required_keys:[9,4,1,""],set_params:[9,4,1,""],type_name:[9,4,1,""],valid_keys:[9,4,1,""],validate_params:[9,4,1,""]},"espressomd.interactions.GayBerneInteraction":{default_params:[9,4,1,""],is_active:[9,4,1,""],required_keys:[9,4,1,""],set_params:[9,4,1,""],type_name:[9,4,1,""],valid_keys:[9,4,1,""],validate_params:[9,4,1,""]},"espressomd.interactions.GenericLennardJonesInteraction":{default_params:[9,4,1,""],is_active:[9,4,1,""],required_keys:[9,4,1,""],set_params:[9,4,1,""],type_name:[9,4,1,""],valid_keys:[9,4,1,""],validate_params:[9,4,1,""]},"espressomd.interactions.HarmonicBond":{get_default_params:[9,4,1,""],type_name:[9,4,1,""],type_number:[9,4,1,""]},"espressomd.interactions.HatInteraction":{default_params:[9,4,1,""],is_active:[9,4,1,""],required_keys:[9,4,1,""],set_params:[9,4,1,""],type_name:[9,4,1,""],valid_keys:[9,4,1,""],validate_params:[9,4,1,""]},"espressomd.interactions.HertzianInteraction":{default_params:[9,4,1,""],is_active:[9,4,1,""],required_keys:[9,4,1,""],set_params:[9,4,1,""],type_name:[9,4,1,""],valid_keys:[9,4,1,""],validate_params:[9,4,1,""]},"espressomd.interactions.IBM_Tribend":{get_default_params:[9,4,1,""],type_name:[9,4,1,""],type_number:[9,4,1,""],valid_keys:[9,4,1,""],validate_params:[9,4,1,""]},"espressomd.interactions.IBM_Triel":{get_default_params:[9,4,1,""],type_name:[9,4,1,""],type_number:[9,4,1,""],valid_keys:[9,4,1,""],validate_params:[9,4,1,""]},"espressomd.interactions.IBM_VolCons":{current_volume:[9,4,1,""],get_default_params:[9,4,1,""],type_name:[9,4,1,""],type_number:[9,4,1,""]},"espressomd.interactions.LennardJonesCos2Interaction":{default_params:[9,4,1,""],is_active:[9,4,1,""],required_keys:[9,4,1,""],set_params:[9,4,1,""],type_name:[9,4,1,""],valid_keys:[9,4,1,""],validate_params:[9,4,1,""]},"espressomd.interactions.LennardJonesCosInteraction":{default_params:[9,4,1,""],is_active:[9,4,1,""],required_keys:[9,4,1,""],set_params:[9,4,1,""],type_name:[9,4,1,""],valid_keys:[9,4,1,""],validate_params:[9,4,1,""]},"espressomd.interactions.LennardJonesInteraction":{default_params:[9,4,1,""],is_active:[9,4,1,""],required_keys:[9,4,1,""],set_params:[9,4,1,""],type_name:[9,4,1,""],valid_keys:[9,4,1,""],validate_params:[9,4,1,""]},"espressomd.interactions.MorseInteraction":{default_params:[9,4,1,""],is_active:[9,4,1,""],required_keys:[9,4,1,""],set_params:[9,4,1,""],type_name:[9,4,1,""],valid_keys:[9,4,1,""],validate_params:[9,4,1,""]},"espressomd.interactions.NonBondedInteraction":{default_params:[9,4,1,""],get_params:[9,4,1,""],is_active:[9,4,1,""],is_valid:[9,4,1,""],required_keys:[9,4,1,""],set_params:[9,4,1,""],type_name:[9,4,1,""],user_interactions:[9,3,1,""],valid_keys:[9,4,1,""],validate_params:[9,4,1,""]},"espressomd.interactions.NonBondedInteractionHandle":{bmhtf:[9,3,1,""],buckingham:[9,3,1,""],dpd:[9,3,1,""],gaussian:[9,3,1,""],gay_berne:[9,3,1,""],generic_lennard_jones:[9,3,1,""],hat:[9,3,1,""],hertzian:[9,3,1,""],lennard_jones:[9,3,1,""],lennard_jones_cos2:[9,3,1,""],lennard_jones_cos:[9,3,1,""],morse:[9,3,1,""],smooth_step:[9,3,1,""],soft_sphere:[9,3,1,""],tabulated:[9,3,1,""],thole:[9,3,1,""],type1:[9,3,1,""],type2:[9,3,1,""]},"espressomd.interactions.NonBondedInteractions":{reset:[9,4,1,""]},"espressomd.interactions.OifGlobalForces":{get_default_params:[9,4,1,""],type_name:[9,4,1,""],type_number:[9,4,1,""]},"espressomd.interactions.OifLocalForces":{get_default_params:[9,4,1,""],type_name:[9,4,1,""],type_number:[9,4,1,""]},"espressomd.interactions.QuarticBond":{get_default_params:[9,4,1,""],type_name:[9,4,1,""],type_number:[9,4,1,""]},"espressomd.interactions.RigidBond":{get_default_params:[9,4,1,""],type_name:[9,4,1,""],type_number:[9,4,1,""]},"espressomd.interactions.SmoothStepInteraction":{default_params:[9,4,1,""],is_active:[9,4,1,""],required_keys:[9,4,1,""],set_params:[9,4,1,""],type_name:[9,4,1,""],valid_keys:[9,4,1,""],validate_params:[9,4,1,""]},"espressomd.interactions.SoftSphereInteraction":{default_params:[9,4,1,""],is_active:[9,4,1,""],required_keys:[9,4,1,""],set_params:[9,4,1,""],type_name:[9,4,1,""],valid_keys:[9,4,1,""],validate_params:[9,4,1,""]},"espressomd.interactions.TabulatedAngle":{pi:[9,3,1,""],type_name:[9,4,1,""],type_number:[9,4,1,""],validate_params:[9,4,1,""]},"espressomd.interactions.TabulatedDihedral":{pi:[9,3,1,""],type_name:[9,4,1,""],type_number:[9,4,1,""],validate_params:[9,4,1,""]},"espressomd.interactions.TabulatedDistance":{type_name:[9,4,1,""],type_number:[9,4,1,""]},"espressomd.interactions.TabulatedNonBonded":{is_active:[9,4,1,""],required_keys:[9,4,1,""],set_default_params:[9,4,1,""],set_params:[9,4,1,""],type_name:[9,4,1,""],type_number:[9,4,1,""],valid_keys:[9,4,1,""]},"espressomd.interactions.ThermalizedBond":{get_default_params:[9,4,1,""],type_name:[9,4,1,""],type_number:[9,4,1,""],validate_params:[9,4,1,""]},"espressomd.interactions.Virtual":{get_default_params:[9,4,1,""],type_name:[9,4,1,""],type_number:[9,4,1,""]},"espressomd.interactions.WCAInteraction":{default_params:[9,4,1,""],is_active:[9,4,1,""],required_keys:[9,4,1,""],set_params:[9,4,1,""],type_name:[9,4,1,""],valid_keys:[9,4,1,""],validate_params:[9,4,1,""]},"espressomd.io":{mpiio:[11,0,0,"-"],writer:[12,0,0,"-"]},"espressomd.io.mpiio":{Mpiio:[11,2,1,""]},"espressomd.io.mpiio.Mpiio":{read:[11,4,1,""],write:[11,4,1,""]},"espressomd.io.writer":{h5md:[12,0,0,"-"],vtf:[12,0,0,"-"]},"espressomd.io.writer.h5md":{H5md:[12,2,1,""],UnitSystem:[12,2,1,""]},"espressomd.io.writer.h5md.H5md":{charge_unit:[12,3,1,""],close:[12,4,1,""],default_params:[12,4,1,""],fields:[12,3,1,""],file_path:[12,3,1,""],flush:[12,4,1,""],force_unit:[12,3,1,""],get_params:[12,4,1,""],length_unit:[12,3,1,""],mass_unit:[12,3,1,""],required_keys:[12,4,1,""],script_path:[12,3,1,""],time_unit:[12,3,1,""],valid_fields:[12,4,1,""],valid_keys:[12,4,1,""],validate_params:[12,4,1,""],velocity_unit:[12,3,1,""],write:[12,4,1,""]},"espressomd.io.writer.vtf":{vtf_pid_map:[12,6,1,""],writevcf:[12,6,1,""],writevsf:[12,6,1,""]},"espressomd.lb":{FluidActor:[9,2,1,""],HydrodynamicInteraction:[9,2,1,""],LBFluid:[9,2,1,""],LBFluidGPU:[9,2,1,""],LBFluidRoutines:[9,2,1,""],LBSlice:[9,2,1,""]},"espressomd.lb.FluidActor":{active_list:[9,3,1,""],class_lookup:[9,4,1,""],default_params:[9,4,1,""],get_params:[9,4,1,""],is_active:[9,4,1,""],is_valid:[9,4,1,""],required_keys:[9,4,1,""],set_params:[9,4,1,""],system:[9,3,1,""],valid_keys:[9,4,1,""],validate_params:[9,4,1,""]},"espressomd.lb.HydrodynamicInteraction":{agrid:[9,3,1,""],bulk_viscosity:[9,3,1,""],default_params:[9,4,1,""],density:[9,3,1,""],ext_force_density:[9,3,1,""],get_interpolated_velocity:[9,4,1,""],kT:[9,3,1,""],load_checkpoint:[9,4,1,""],nodes:[9,4,1,""],pressure_tensor:[9,3,1,""],required_keys:[9,4,1,""],save_checkpoint:[9,4,1,""],seed:[9,3,1,""],set_interpolation_order:[9,4,1,""],shape:[9,3,1,""],tau:[9,3,1,""],valid_keys:[9,4,1,""],validate_params:[9,4,1,""],viscosity:[9,3,1,""],write_boundary:[9,4,1,""],write_velocity:[9,4,1,""],write_vtk_boundary:[9,4,1,""],write_vtk_velocity:[9,4,1,""]},"espressomd.lb.LBFluidGPU":{get_interpolated_fluid_velocity_at_positions:[9,4,1,""]},"espressomd.lb.LBFluidRoutines":{boundary:[9,3,1,""],density:[9,3,1,""],index:[9,3,1,""],population:[9,3,1,""],pressure_tensor:[9,3,1,""],pressure_tensor_neq:[9,3,1,""],velocity:[9,3,1,""]},"espressomd.lb.LBSlice":{boundary:[9,5,1,""],density:[9,5,1,""],get_indices:[9,4,1,""],get_values:[9,4,1,""],index:[9,5,1,""],population:[9,5,1,""],pressure_tensor:[9,5,1,""],pressure_tensor_neq:[9,5,1,""],set_values:[9,4,1,""],velocity:[9,5,1,""]},"espressomd.lbboundaries":{LBBoundaries:[9,2,1,""],LBBoundary:[9,2,1,""]},"espressomd.lbboundaries.LBBoundaries":{add:[9,4,1,""],clear:[9,4,1,""],empty:[9,4,1,""],remove:[9,4,1,""],size:[9,4,1,""]},"espressomd.lees_edwards":{LeesEdwards:[9,2,1,""],LinearShear:[9,2,1,""],Off:[9,2,1,""],OscillatoryShear:[9,2,1,""]},"espressomd.lees_edwards.LeesEdwards":{pos_offset:[9,3,1,""],protocol:[9,3,1,""],set_boundary_conditions:[9,4,1,""],shear_direction:[9,3,1,""],shear_plane_normal:[9,3,1,""],shear_velocity:[9,3,1,""]},"espressomd.magnetostatics":{DLC:[9,2,1,""],DipolarBarnesHutGpu:[9,2,1,""],DipolarDirectSumCpu:[9,2,1,""],DipolarDirectSumGpu:[9,2,1,""],DipolarDirectSumWithReplicaCpu:[9,2,1,""],DipolarP3M:[9,2,1,""],MagnetostaticInteraction:[9,2,1,""],Scafacos:[9,2,1,""]},"espressomd.magnetostatics.DLC":{default_params:[9,4,1,""],required_keys:[9,4,1,""],valid_keys:[9,4,1,""],validate_params:[9,4,1,""]},"espressomd.magnetostatics.DipolarBarnesHutGpu":{default_params:[9,4,1,""],required_keys:[9,4,1,""],valid_keys:[9,4,1,""]},"espressomd.magnetostatics.DipolarDirectSumCpu":{default_params:[9,4,1,""],required_keys:[9,4,1,""],valid_keys:[9,4,1,""]},"espressomd.magnetostatics.DipolarDirectSumGpu":{default_params:[9,4,1,""],required_keys:[9,4,1,""],valid_keys:[9,4,1,""]},"espressomd.magnetostatics.DipolarDirectSumWithReplicaCpu":{default_params:[9,4,1,""],required_keys:[9,4,1,""],valid_keys:[9,4,1,""]},"espressomd.magnetostatics.DipolarP3M":{default_params:[9,4,1,""],required_keys:[9,4,1,""],valid_keys:[9,4,1,""],validate_params:[9,4,1,""]},"espressomd.magnetostatics.MagnetostaticInteraction":{default_params:[9,4,1,""],get_magnetostatics_prefactor:[9,4,1,""],required_keys:[9,4,1,""],valid_keys:[9,4,1,""],validate_params:[9,4,1,""]},"espressomd.magnetostatics.Scafacos":{default_params:[9,4,1,""],get_available_methods:[9,4,1,""],required_keys:[9,4,1,""],valid_keys:[9,4,1,""],validate_params:[9,4,1,""]},"espressomd.math":{CylindricalTransformationParameters:[9,2,1,""]},"espressomd.observables":{BondAngles:[9,2,1,""],BondDihedrals:[9,2,1,""],ComPosition:[9,2,1,""],ComVelocity:[9,2,1,""],CosPersistenceAngles:[9,2,1,""],CylindricalDensityProfile:[9,2,1,""],CylindricalFluxDensityProfile:[9,2,1,""],CylindricalLBFluxDensityProfileAtParticlePositions:[9,2,1,""],CylindricalLBVelocityProfile:[9,2,1,""],CylindricalLBVelocityProfileAtParticlePositions:[9,2,1,""],CylindricalProfileObservable:[9,2,1,""],CylindricalVelocityProfile:[9,2,1,""],DPDStress:[9,2,1,""],DensityProfile:[9,2,1,""],DipoleMoment:[9,2,1,""],Energy:[9,2,1,""],FluxDensityProfile:[9,2,1,""],ForceDensityProfile:[9,2,1,""],LBFluidPressureTensor:[9,2,1,""],LBVelocityProfile:[9,2,1,""],MagneticDipoleMoment:[9,2,1,""],Observable:[9,2,1,""],ParticleAngularVelocities:[9,2,1,""],ParticleBodyAngularVelocities:[9,2,1,""],ParticleBodyVelocities:[9,2,1,""],ParticleDistances:[9,2,1,""],ParticleForces:[9,2,1,""],ParticlePositions:[9,2,1,""],ParticleVelocities:[9,2,1,""],Pressure:[9,2,1,""],PressureTensor:[9,2,1,""],ProfileObservable:[9,2,1,""],RDF:[9,2,1,""],TotalForce:[9,2,1,""]},"espressomd.observables.BondAngles":{calculate:[9,4,1,""]},"espressomd.observables.BondDihedrals":{calculate:[9,4,1,""]},"espressomd.observables.ComPosition":{calculate:[9,4,1,""]},"espressomd.observables.ComVelocity":{calculate:[9,4,1,""]},"espressomd.observables.CosPersistenceAngles":{calculate:[9,4,1,""]},"espressomd.observables.CylindricalDensityProfile":{calculate:[9,4,1,""]},"espressomd.observables.CylindricalFluxDensityProfile":{calculate:[9,4,1,""]},"espressomd.observables.CylindricalLBFluxDensityProfileAtParticlePositions":{calculate:[9,4,1,""]},"espressomd.observables.CylindricalLBVelocityProfile":{calculate:[9,4,1,""]},"espressomd.observables.CylindricalLBVelocityProfileAtParticlePositions":{calculate:[9,4,1,""]},"espressomd.observables.CylindricalVelocityProfile":{calculate:[9,4,1,""]},"espressomd.observables.DPDStress":{calculate:[9,4,1,""]},"espressomd.observables.DensityProfile":{calculate:[9,4,1,""]},"espressomd.observables.DipoleMoment":{calculate:[9,4,1,""]},"espressomd.observables.Energy":{calculate:[9,4,1,""]},"espressomd.observables.FluxDensityProfile":{calculate:[9,4,1,""]},"espressomd.observables.ForceDensityProfile":{calculate:[9,4,1,""]},"espressomd.observables.LBFluidPressureTensor":{calculate:[9,4,1,""]},"espressomd.observables.LBVelocityProfile":{calculate:[9,4,1,""]},"espressomd.observables.MagneticDipoleMoment":{calculate:[9,4,1,""]},"espressomd.observables.Observable":{calculate:[9,4,1,""],shape:[9,4,1,""]},"espressomd.observables.ParticleAngularVelocities":{calculate:[9,4,1,""]},"espressomd.observables.ParticleBodyAngularVelocities":{calculate:[9,4,1,""]},"espressomd.observables.ParticleBodyVelocities":{calculate:[9,4,1,""]},"espressomd.observables.ParticleDistances":{calculate:[9,4,1,""]},"espressomd.observables.ParticleForces":{calculate:[9,4,1,""]},"espressomd.observables.ParticlePositions":{calculate:[9,4,1,""]},"espressomd.observables.ParticleVelocities":{calculate:[9,4,1,""]},"espressomd.observables.Pressure":{calculate:[9,4,1,""]},"espressomd.observables.PressureTensor":{calculate:[9,4,1,""]},"espressomd.observables.ProfileObservable":{bin_centers:[9,4,1,""],bin_edges:[9,4,1,""]},"espressomd.observables.RDF":{bin_centers:[9,4,1,""],calculate:[9,4,1,""]},"espressomd.observables.TotalForce":{calculate:[9,4,1,""]},"espressomd.pair_criteria":{BondCriterion:[9,2,1,""],DistanceCriterion:[9,2,1,""],EnergyCriterion:[9,2,1,""]},"espressomd.particle_data":{ParticleHandle:[9,2,1,""],ParticleList:[9,2,1,""],ParticleSlice:[9,2,1,""],set_slice_one_for_all:[9,6,1,""],set_slice_one_for_each:[9,6,1,""]},"espressomd.particle_data.ParticleHandle":{add_bond:[9,4,1,""],add_exclusion:[9,4,1,""],add_verified_bond:[9,4,1,""],bonds:[9,3,1,""],convert_vector_body_to_space:[9,4,1,""],convert_vector_space_to_body:[9,4,1,""],delete_all_bonds:[9,4,1,""],delete_bond:[9,4,1,""],delete_exclusion:[9,4,1,""],delete_verified_bond:[9,4,1,""],dip:[9,3,1,""],dipm:[9,3,1,""],director:[9,3,1,""],exclusions:[9,3,1,""],ext_force:[9,3,1,""],ext_torque:[9,3,1,""],f:[9,3,1,""],fix:[9,3,1,""],gamma:[9,3,1,""],gamma_rot:[9,3,1,""],id:[9,3,1,""],image_box:[9,3,1,""],lees_edwards_flag:[9,3,1,""],lees_edwards_offset:[9,3,1,""],mass:[9,3,1,""],mol_id:[9,3,1,""],mu_E:[9,3,1,""],node:[9,3,1,""],normalize_and_check_bond_or_throw_exception:[9,4,1,""],omega_body:[9,3,1,""],omega_lab:[9,3,1,""],pos:[9,3,1,""],pos_folded:[9,3,1,""],q:[9,3,1,""],quat:[9,3,1,""],remove:[9,4,1,""],rinertia:[9,3,1,""],rotate:[9,4,1,""],rotation:[9,3,1,""],swimming:[9,3,1,""],to_dict:[9,4,1,""],torque_lab:[9,3,1,""],type:[9,3,1,""],update:[9,4,1,""],v:[9,3,1,""],virtual:[9,3,1,""],vs_auto_relate_to:[9,4,1,""],vs_quat:[9,3,1,""],vs_relative:[9,3,1,""]},"espressomd.particle_data.ParticleList":{add:[9,4,1,""],all:[9,4,1,""],by_id:[9,4,1,""],by_ids:[9,4,1,""],clear:[9,4,1,""],exists:[9,4,1,""],highest_particle_id:[9,3,1,""],n_part_types:[9,3,1,""],n_rigidbonds:[9,3,1,""],pairs:[9,4,1,""],select:[9,4,1,""],writevtk:[9,4,1,""]},"espressomd.particle_data.ParticleSlice":{bonds:[9,5,1,""],dip:[9,5,1,""],dipm:[9,5,1,""],director:[9,5,1,""],exclusions:[9,5,1,""],ext_force:[9,5,1,""],ext_torque:[9,5,1,""],f:[9,5,1,""],fix:[9,5,1,""],gamma:[9,5,1,""],gamma_rot:[9,5,1,""],id:[9,5,1,""],image_box:[9,5,1,""],lees_edwards_flag:[9,5,1,""],lees_edwards_offset:[9,5,1,""],mass:[9,5,1,""],mol_id:[9,5,1,""],mu_E:[9,5,1,""],node:[9,5,1,""],omega_body:[9,5,1,""],omega_lab:[9,5,1,""],pos:[9,5,1,""],q:[9,5,1,""],quat:[9,5,1,""],rinertia:[9,5,1,""],rotation:[9,5,1,""],swimming:[9,5,1,""],to_dict:[9,4,1,""],torque_lab:[9,5,1,""],type:[9,5,1,""],v:[9,5,1,""],virtual:[9,5,1,""],vs_quat:[9,5,1,""],vs_relative:[9,5,1,""]},"espressomd.polymer":{linear_polymer_positions:[9,6,1,""],setup_diamond_polymer:[9,6,1,""],validate_params:[9,6,1,""]},"espressomd.profiler":{begin_section:[9,6,1,""],end_section:[9,6,1,""]},"espressomd.reaction_methods":{ConstantpHEnsemble:[9,2,1,""],ReactionAlgorithm:[9,2,1,""],ReactionEnsemble:[9,2,1,""],SingleReaction:[9,2,1,""],WidomInsertion:[9,2,1,""]},"espressomd.reaction_methods.ConstantpHEnsemble":{add_reaction:[9,4,1,""],constant_pH:[9,3,1,""],required_keys:[9,4,1,""],valid_keys:[9,4,1,""]},"espressomd.reaction_methods.ReactionAlgorithm":{add_reaction:[9,4,1,""],change_reaction_constant:[9,4,1,""],delete_particle:[9,4,1,""],delete_reaction:[9,4,1,""],displacement_mc_move_for_particles_of_type:[9,4,1,""],get_acceptance_rate_reaction:[9,4,1,""],get_non_interacting_type:[9,4,1,""],get_status:[9,4,1,""],get_volume:[9,4,1,""],get_wall_constraints_in_z_direction:[9,4,1,""],reaction:[9,4,1,""],remove_constraint:[9,4,1,""],required_keys:[9,4,1,""],set_cylindrical_constraint_in_z_direction:[9,4,1,""],set_non_interacting_type:[9,4,1,""],set_volume:[9,4,1,""],set_wall_constraints_in_z_direction:[9,4,1,""],valid_keys:[9,4,1,""]},"espressomd.reaction_methods.SingleReaction":{make_backward_reaction:[9,4,1,""],required_keys:[9,4,1,""],valid_keys:[9,4,1,""]},"espressomd.reaction_methods.WidomInsertion":{add_reaction:[9,4,1,""],calculate_excess_chemical_potential:[9,4,1,""],calculate_particle_insertion_potential_energy:[9,4,1,""],required_keys:[9,4,1,""],valid_keys:[9,4,1,""]},"espressomd.rotation":{diagonalized_inertia_tensor:[9,6,1,""],inertia_tensor:[9,6,1,""],matrix_to_quat:[9,6,1,""]},"espressomd.script_interface":{PObjectRef:[9,2,1,""],PScriptInterface:[9,2,1,""],ScriptInterfaceHelper:[9,2,1,""],ScriptObjectList:[9,2,1,""],ScriptObjectMap:[9,2,1,""],script_interface_register:[9,6,1,""]},"espressomd.script_interface.PObjectRef":{print_sip:[9,4,1,""]},"espressomd.script_interface.PScriptInterface":{call_method:[9,4,1,""],get_parameter:[9,4,1,""],get_params:[9,4,1,""],get_sip:[9,4,1,""],name:[9,4,1,""],set_params:[9,4,1,""],sip:[9,3,1,""]},"espressomd.script_interface.ScriptInterfaceHelper":{define_bound_methods:[9,4,1,""],generate_caller:[9,4,1,""]},"espressomd.script_interface.ScriptObjectMap":{clear:[9,4,1,""],items:[9,4,1,""],keys:[9,4,1,""],remove:[9,4,1,""]},"espressomd.shapes":{Cylinder:[9,2,1,""],Ellipsoid:[9,2,1,""],HollowConicalFrustum:[9,2,1,""],Rhomboid:[9,2,1,""],Shape:[9,2,1,""],SimplePore:[9,2,1,""],Slitpore:[9,2,1,""],Sphere:[9,2,1,""],SpheroCylinder:[9,2,1,""],Torus:[9,2,1,""],Union:[9,2,1,""],Wall:[9,2,1,""]},"espressomd.shapes.Cylinder":{axis:[9,3,1,""],center:[9,3,1,""],direction:[9,3,1,""],length:[9,3,1,""],open:[9,3,1,""],radius:[9,3,1,""]},"espressomd.shapes.Ellipsoid":{a:[9,3,1,""],b:[9,3,1,""],center:[9,3,1,""],direction:[9,3,1,""]},"espressomd.shapes.HollowConicalFrustum":{central_angle:[9,3,1,""],cyl_transform_params:[9,3,1,""],direction:[9,3,1,""],length:[9,3,1,""],r1:[9,3,1,""],r2:[9,3,1,""],thickness:[9,3,1,""]},"espressomd.shapes.Rhomboid":{a:[9,3,1,""],b:[9,3,1,""],c:[9,3,1,""],corner:[9,3,1,""],direction:[9,3,1,""]},"espressomd.shapes.SimplePore":{axis:[9,3,1,""],center:[9,3,1,""],length:[9,3,1,""],radius:[9,3,1,""],smoothing_radius:[9,3,1,""]},"espressomd.shapes.Slitpore":{channel_width:[9,3,1,""],dividing_plane:[9,3,1,""],lower_smoothing_radius:[9,3,1,""],pore_length:[9,3,1,""],pore_mouth:[9,3,1,""],pore_width:[9,3,1,""],upper_smoothing_radius:[9,3,1,""]},"espressomd.shapes.Sphere":{center:[9,3,1,""],direction:[9,3,1,""],radius:[9,3,1,""]},"espressomd.shapes.SpheroCylinder":{axis:[9,3,1,""],center:[9,3,1,""],direction:[9,3,1,""],length:[9,3,1,""],radius:[9,3,1,""]},"espressomd.shapes.Torus":{center:[9,3,1,""],direction:[9,3,1,""],normal:[9,3,1,""],radius:[9,3,1,""],tube_radius:[9,3,1,""]},"espressomd.shapes.Union":{add:[9,4,1,""],clear:[9,4,1,""],remove:[9,4,1,""],size:[9,4,1,""]},"espressomd.shapes.Wall":{dist:[9,3,1,""],normal:[9,3,1,""]},"espressomd.system":{System:[9,2,1,""]},"espressomd.system.System":{actors:[9,3,1,""],analysis:[9,3,1,""],auto_exclusions:[9,4,1,""],auto_update_accumulators:[9,3,1,""],bond_breakage:[9,3,1,""],bonded_inter:[9,3,1,""],box_l:[9,3,1,""],cell_system:[9,3,1,""],change_volume_and_rescale_particles:[9,4,1,""],collision_detection:[9,3,1,""],comfixed:[9,3,1,""],constraints:[9,3,1,""],cuda_init_handle:[9,3,1,""],distance:[9,4,1,""],distance_vec:[9,4,1,""],ekboundaries:[9,3,1,""],force_cap:[9,3,1,""],galilei:[9,3,1,""],integrator:[9,3,1,""],lbboundaries:[9,3,1,""],lees_edwards:[9,3,1,""],max_cut_bonded:[9,3,1,""],max_cut_nonbonded:[9,3,1,""],max_oif_objects:[9,3,1,""],min_global_cut:[9,3,1,""],non_bonded_inter:[9,3,1,""],number_of_particles:[9,4,1,""],part:[9,3,1,""],periodicity:[9,3,1,""],rotate_system:[9,4,1,""],setup_type_map:[9,4,1,""],thermostat:[9,3,1,""],time:[9,3,1,""],time_step:[9,3,1,""],velocity_difference:[9,4,1,""],virtual_sites:[9,3,1,""],volume:[9,4,1,""]},"espressomd.thermostat":{AssertThermostatType:[9,6,1,""],Thermostat:[9,2,1,""]},"espressomd.thermostat.Thermostat":{get_state:[9,4,1,""],get_ts:[9,4,1,""],recover:[9,4,1,""],set_brownian:[9,4,1,""],set_dpd:[9,4,1,""],set_langevin:[9,4,1,""],set_lb:[9,4,1,""],set_npt:[9,4,1,""],set_stokesian:[9,4,1,""],suspend:[9,4,1,""],turn_off:[9,4,1,""]},"espressomd.utils":{array_locked:[9,2,1,""],check_array_type_or_throw_except:[9,6,1,""],check_required_keys:[9,6,1,""],check_type_or_throw_except:[9,6,1,""],check_valid_keys:[9,6,1,""],handle_errors:[9,6,1,""],is_valid_type:[9,6,1,""],nesting_level:[9,6,1,""],to_char_pointer:[9,6,1,""],to_str:[9,6,1,""]},"espressomd.utils.array_locked":{ERR_MSG:[9,3,1,""]},"espressomd.version":{friendly:[9,6,1,""],git_branch:[9,6,1,""],git_commit:[9,6,1,""],git_state:[9,6,1,""],major:[9,6,1,""],minor:[9,6,1,""]},"espressomd.virtual_sites":{ActiveVirtualSitesHandle:[9,2,1,""],VirtualSitesInertialessTracers:[9,2,1,""],VirtualSitesOff:[9,2,1,""],VirtualSitesRelative:[9,2,1,""]},"espressomd.virtual_sites.ActiveVirtualSitesHandle":{have_quaternion:[9,3,1,""],override_cutoff_check:[9,3,1,""]},"espressomd.visualization":{Camera:[9,2,1,""],Cylinder:[9,2,1,""],Ellipsoid:[9,2,1,""],HollowConicalFrustum:[9,2,1,""],KeyboardButtonEvent:[9,2,1,""],KeyboardFireEvent:[9,2,1,""],KeyboardManager:[9,2,1,""],MouseButtonEvent:[9,2,1,""],MouseFireEvent:[9,2,1,""],MouseManager:[9,2,1,""],Shape:[9,2,1,""],SimplePore:[9,2,1,""],Slitpore:[9,2,1,""],Sphere:[9,2,1,""],Spherocylinder:[9,2,1,""],Wall:[9,2,1,""],draw_arrow:[9,6,1,""],draw_box:[9,6,1,""],draw_cylinder:[9,6,1,""],draw_plane:[9,6,1,""],get_extra_clip_plane:[9,6,1,""],openGLLive:[9,2,1,""],rotation_helper:[9,6,1,""],set_solid_material:[9,6,1,""]},"espressomd.visualization.Camera":{get_camera_rotation_matrix:[9,4,1,""],move_backward:[9,4,1,""],move_down:[9,4,1,""],move_forward:[9,4,1,""],move_left:[9,4,1,""],move_right:[9,4,1,""],move_up:[9,4,1,""],rotate_camera:[9,4,1,""],rotate_system_XL:[9,4,1,""],rotate_system_XR:[9,4,1,""],rotate_system_YL:[9,4,1,""],rotate_system_YR:[9,4,1,""],rotate_system_ZL:[9,4,1,""],rotate_system_ZR:[9,4,1,""],rotate_system_x:[9,4,1,""],rotate_system_y:[9,4,1,""],rotate_system_z:[9,4,1,""],rotate_vector:[9,4,1,""],update_modelview:[9,4,1,""]},"espressomd.visualization.Cylinder":{draw:[9,4,1,""]},"espressomd.visualization.Ellipsoid":{draw:[9,4,1,""]},"espressomd.visualization.HollowConicalFrustum":{draw:[9,4,1,""]},"espressomd.visualization.KeyboardFireEvent":{Hold:[9,3,1,""],Pressed:[9,3,1,""],Released:[9,3,1,""]},"espressomd.visualization.KeyboardManager":{callback_on_button:[9,4,1,""],handle_input:[9,4,1,""],keyboard_down:[9,4,1,""],keyboard_up:[9,4,1,""],register_button:[9,4,1,""]},"espressomd.visualization.MouseFireEvent":{ButtonMotion:[9,3,1,""],ButtonPressed:[9,3,1,""],ButtonReleased:[9,3,1,""],DoubleClick:[9,3,1,""],FreeMotion:[9,3,1,""]},"espressomd.visualization.MouseManager":{mouse_click:[9,4,1,""],mouse_move:[9,4,1,""],register_button:[9,4,1,""]},"espressomd.visualization.Shape":{draw:[9,4,1,""]},"espressomd.visualization.SimplePore":{draw:[9,4,1,""]},"espressomd.visualization.Slitpore":{draw:[9,4,1,""]},"espressomd.visualization.Sphere":{draw:[9,4,1,""]},"espressomd.visualization.Spherocylinder":{draw:[9,4,1,""]},"espressomd.visualization.Wall":{draw:[9,4,1,""]},"espressomd.visualization.openGLLive":{materials:[9,3,1,""],register_callback:[9,4,1,""],run:[9,4,1,""],screenshot:[9,4,1,""],start:[9,4,1,""],update:[9,4,1,""],update_system_info:[9,4,1,""]},espressomd:{FeaturesError:[9,1,1,""],MDA_ESP:[10,0,0,"-"],accumulators:[9,0,0,"-"],actors:[9,0,0,"-"],analyze:[9,0,0,"-"],assert_features:[9,6,1,""],bond_breakage:[9,0,0,"-"],cell_system:[9,0,0,"-"],checkpointing:[9,0,0,"-"],cluster_analysis:[9,0,0,"-"],collision_detection:[9,0,0,"-"],comfixed:[9,0,0,"-"],constraints:[9,0,0,"-"],cuda_init:[9,0,0,"-"],drude_helpers:[9,0,0,"-"],ekboundaries:[9,0,0,"-"],electrokinetics:[9,0,0,"-"],electrostatic_extensions:[9,0,0,"-"],electrostatics:[9,0,0,"-"],galilei:[9,0,0,"-"],has_features:[9,6,1,""],highlander:[9,0,0,"-"],integrate:[9,0,0,"-"],interactions:[9,0,0,"-"],io:[11,0,0,"-"],lb:[9,0,0,"-"],lbboundaries:[9,0,0,"-"],lees_edwards:[9,0,0,"-"],magnetostatics:[9,0,0,"-"],math:[9,0,0,"-"],missing_features:[9,6,1,""],observables:[9,0,0,"-"],pair_criteria:[9,0,0,"-"],particle_data:[9,0,0,"-"],polymer:[9,0,0,"-"],profiler:[9,0,0,"-"],reaction_methods:[9,0,0,"-"],rotation:[9,0,0,"-"],script_interface:[9,0,0,"-"],shapes:[9,0,0,"-"],system:[9,0,0,"-"],thermostat:[9,0,0,"-"],utils:[9,0,0,"-"],version:[9,0,0,"-"],virtual_sites:[9,0,0,"-"],visualization:[9,0,0,"-"]}},objnames:{"0":["py","module","Python module"],"1":["py","exception","Python exception"],"2":["py","class","Python class"],"3":["py","attribute","Python attribute"],"4":["py","method","Python method"],"5":["py","property","Python property"],"6":["py","function","Python function"]},objtypes:{"0":"py:module","1":"py:exception","2":"py:class","3":"py:attribute","4":"py:method","5":"py:property","6":"py:function"},terms:{"0":[0,1,2,3,5,7,8,9,14,15,16,17,18,19,20,21,23,24,25,26,27,28,29],"00":0,"00001":29,"0001":[0,3,8,29],"00018":3,"001":[3,9,19],"00131":3,"002":0,"0021":3,"0022":3,"00268979400100481":3,"00268979500100371":3,"003856704":3,"004011":3,"005":3,"0055396":3,"00586":3,"006":3,"0064":3,"00877":3,"0088":9,"01":[0,1,3,8,9,15,16,18,20,21,23,27],"012":16,"013":3,"014":3,"016":[0,3],"01639":3,"02":[0,3,16],"0263":3,"0295":3,"03":[9,23],"04":[0,14],"046702":3,"05":[15,28],"05d":29,"062":3,"066707":3,"0770":17,"078125":9,"08":3,"083615":3,"086":3,"08927020801986564":3,"08927029208049126":3,"094107":3,"09500348814550731":3,"0_":16,"0th":[9,24],"1":[0,1,2,3,5,7,8,9,10,11,14,15,16,17,18,19,20,21,23,24,25,26,27,28,29],"10":[0,1,2,3,5,7,8,9,10,14,15,16,17,18,20,21,23,24,27,28,29],"100":[0,1,3,8,9,15,19,20,29],"1000":[0,9,18,23,29],"10000":28,"100000":8,"1002":3,"1007":3,"101":[0,17],"1014104064":25,"1016":3,"1017":3,"102":[3,9],"103":3,"1039":3,"105":3,"1063":[3,18],"1080":3,"1088":3,"109":3,"1093":3,"1098":3,"10n":28,"11":[0,1,3],"110":3,"1103":3,"111":[1,3],"1140":[3,18],"1142":3,"117":3,"119":3,"12":[0,3,5,8,14,16,17,20,25,27,28],"1209":3,"123":[3,15,16,20],"127":3,"1274":3,"128":9,"128kb":28,"129":3,"13":3,"131":3,"132":[3,18],"133":3,"134":20,"134106":3,"1352":3,"1358":3,"1360":3,"1361":3,"1364":3,"1389":17,"14":[0,3,14,24,28],"14031":17,"1411":3,"14159265358979":9,"144":3,"144103":3,"146":3,"148":3,"1483":3,"148301":3,"1489":3,"1491954":3,"1491955":3,"15":[0,3,5,14,17,19,23],"154103":3,"154107":3,"154112":[3,18],"1546":17,"154723":3,"1568":28,"16":[1,3,9,23,25],"1609":3,"1620":3,"166":3,"168642":3,"17":[3,9],"170":17,"1719":17,"1734110":3,"174":3,"1771":17,"1789":[3,18],"18":3,"180":[0,3,9],"181":0,"1816":[3,18],"182":3,"184":3,"185":3,"19":[3,20],"192":28,"1921":[3,8,21],"19213690304":3,"1963":[3,24],"1972":[3,27],"1978":[3,15],"1981":[2,3,17],"1983":[3,16,23],"1986":[3,9],"1987":[3,15,18],"1988":[1,3,8,21],"1992":[3,8,21,24],"1994":[3,24],"1995":[1,3,8,9],"1996":[3,19],"1998":[3,8,21,23],"1999":[2,3,15],"1_1":3,"1d":1,"1e":[8,9,15,18,19,21],"1f":29,"1ghz":28,"1mb":28,"2":[0,1,2,3,5,8,9,10,14,15,16,17,18,19,20,21,23,24,25,27,28,29],"20":[0,1,3,5,9,14,15,17,20,27,28],"200":[21,28],"2000":[3,8,21],"2001":[1,3,9,17,20],"2002":[0,1,2,3,8,18],"2003":[3,9,15,17],"2004":[3,9,15,21],"2005":[2,3,8],"2006":[3,18],"2007":[2,3,16],"2008":[3,8,21,24],"2009":[1,3,9,15,20],"200mhz":28,"2010":[0,1,3,8,9,15,18,20],"2011":[0,3,8,9],"2012":[0,3,9,16,20],"2013":[0,3,8,18,20,21],"2014":[0,3,16],"2015":[0,3,17],"2016":[3,23],"2017":[0,3,9,23,24],"2018":[3,9],"2019":[3,18],"2021":[3,27],"203001":3,"204102":3,"2052647":3,"2080":25,"21":3,"210":3,"21105":3,"22":[0,3,14],"221":3,"226":3,"227":[3,18],"23":[3,14,23],"234104":3,"2376":3,"24":[3,18],"24002":3,"2496":3,"25":[3,5,9,17,18,23,28],"2502":3,"2503":3,"2512":3,"253":3,"25358":3,"26":3,"2614":3,"2661":17,"267351":3,"27":[3,20],"272":9,"278":3,"2790428":3,"28":3,"2802":3,"2812":3,"287":3,"288":3,"29":3,"297":20,"2d":[1,3,8,21],"2e":15,"2e_":1,"2f":0,"2gb":28,"2k_0":17,"2n":2,"2nd":3,"2p":1,"2q":15,"2r_":8,"2r_c":17,"2u_x":2,"2u_xu_i":2,"2u_z":2,"2v":1,"2x":9,"2y":9,"2z":9,"3":[0,1,2,3,7,8,9,10,11,14,15,16,17,18,19,20,21,23,24,25,27,28,29],"30":[3,5,9,20,29],"300":18,"3000389":3,"300k":18,"301":20,"3019":3,"3021064":3,"3027":3,"31":3,"319":3,"32":[3,9,21,25,27],"320":3,"3216473":3,"324":3,"3245303":3,"327":3,"32979":3,"33":[3,20],"330":3,"3316":3,"3319":3,"3376011":[3,18],"34":[3,17],"348":3,"3491098":3,"35":[3,9],"351":3,"354":3,"3548":17,"3549":17,"36":3,"368":3,"369":3,"37":3,"3719":3,"375":3,"38":[3,9],"39":[3,18],"3929":3,"393":0,"3d":[0,8,9,16,19,25,27,29],"3f":19,"3r_":24,"3v":[1,9],"3x3":[1,9,20],"4":[0,1,2,3,7,8,9,14,15,16,17,18,19,20,21,23,25,27,28,29],"40":[3,18],"400":[2,3],"4000":20,"4011":3,"4021":3,"409":3,"41":[3,15],"419":3,"42":[3,15,29],"43":[3,15,16],"436761":3,"4370":14,"44":3,"441483":3,"4419":3,"4435":17,"4453":3,"44649":3,"45":3,"46":[0,3,25],"462145":3,"4655":3,"466443":3,"467":28,"469273":3,"47":3,"470117":3,"471":3,"475":3,"477414":3,"477415":3,"479":3,"479208":3,"4793":17,"48":[0,3,17],"480156":3,"487":3,"49":3,"494":18,"4944962":3,"4u_x":2,"4u_xu_i":2,"5":[0,1,2,3,4,5,7,8,9,14,15,16,17,18,19,20,21,23,25,27,29],"50":[0,3,9,15,23],"500":[0,29],"505":3,"5075":3,"50n":28,"51":[3,9],"517":3,"52":[0,3],"53":3,"54":3,"540":3,"5451":3,"5459":3,"54734631":9,"54988961":9,"55":[3,9],"56":3,"57":[3,16],"577":3,"5785":17,"58":[3,20],"59":3,"595":3,"5b":18,"6":[0,1,2,3,5,7,9,14,15,16,17,18,20,25,28],"60":[3,14],"60324":3,"61":3,"62":3,"63":[3,20],"6350":3,"6351":3,"64":[3,20,27],"642":3,"648x":3,"65":[3,16],"66":3,"663":9,"67":3,"674":17,"6786":17,"68":3,"69":3,"6985":17,"6_2":3,"7":[0,1,3,9,14,16,18,19,25],"70":3,"704":3,"71":[3,14],"711":3,"717":3,"718":3,"71834061":9,"72":3,"725":3,"727":3,"73":3,"730":25,"733":3,"736":3,"74":3,"75":[3,8],"755":17,"7678":3,"7694":3,"77":[9,24],"774597":9,"7855":3,"8":[1,2,3,9,14,15,16,17,18,20,21,23,25,28],"800":15,"800186":[3,18],"800mb":28,"8054":3,"81":3,"8225":3,"8239":3,"83":3,"8348":3,"837":17,"8370061312":25,"84":3,"8577":3,"8593":3,"864":28,"877":3,"87706":3,"89":3,"8ball":18,"8kb":28,"8u_x":2,"9":[0,1,3,8,9,18,19,23,27,29],"90":9,"900":3,"90014":3,"907":3,"91":16,"95u":18,"96":3,"97":3,"978":3,"9780080545585":3,"9780198519768":3,"9780198803195":3,"9780511816581":3,"9780852743928":3,"9789812793768_0023":3,"9991":3,"\u00e0":[3,8,21],"\u00e1":[0,3,16],"\u00e4":[1,3],"\u00e5":10,"\u00e5ngstr\u00f6m":18,"\u00e9":3,"\u00ed":3,"\u00f3":[3,9,21],"\u00f6":[3,9],"\u00fc":[0,3,9,15,16,20],"\u010d":3,"\u0161":3,"abstract":9,"boolean":[14,15,23],"break":[2,5,9,14,15,16,20,25],"byte":28,"case":[0,1,2,5,7,8,9,14,15,16,17,18,19,20,21,23,24,25,27,28],"catch":14,"char":9,"class":[1,5,7,8,9,10,11,12,15,16,17,18,19,20,24,26,27],"default":[0,1,7,9,12,14,15,17,18,19,20,23,24,25,27,29],"do":[0,1,2,4,5,9,11,14,15,18,19,20,21,23,24,25,27],"export":[7,20],"final":[0,1,14,16,18,29],"float":[0,9,14,15,16,17,19,20],"function":[0,2,3,5,7,8,9,11,14,15,16,17,18,19,20,23,24,25,26,29],"h\u00f6fling":9,"h\u00fcckel":9,"import":[0,1,2,5,7,8,9,10,14,16,18,19,20,21,23,25,27,28,29],"int":[9,11,16,20],"long":[0,1,2,3,7,8,9,17,18,19,21,24,25],"new":[0,3,4,6,7,8,9,14,15,18,19,23,24,25,26,28],"null":9,"p\u00e9clet":15,"public":[18,20],"return":[0,1,5,9,10,12,15,18,19,20,23,24,25,26],"s\u00fczen":18,"short":[1,2,8,9,14,15,17,18,20,23,27,28],"static":25,"switch":[0,7,8,9,14,15,17,18,20,23,25,26],"throw":[5,9,15,19],"true":[0,1,5,7,8,9,10,15,16,17,19,20,23,27,29],"while":[0,1,2,6,7,15,16,17,18,19,23,25,26,27,29],A:[0,1,2,3,5,7,9,10,12,14,15,16,17,18,19,20,23,24,25,27,28,29],AT:16,And:0,As:[0,1,2,5,7,9,15,18,20,21,23,24,25,27],At:[0,7,9,17],Be:[0,9,14,15,19,24,27],But:[2,9,27,28],By:[0,2,7,9,14,15,16,18,20,23,24,25,26,27],For:[0,1,2,5,6,7,8,9,14,15,16,17,18,19,20,21,23,24,25,26,27,28],If:[0,1,2,4,5,6,7,8,9,11,12,14,15,16,17,18,19,20,21,23,24,25,27,28,29],In:[0,1,2,3,5,7,8,9,14,15,16,17,18,19,20,21,23,24,25,27,28],It:[0,1,4,5,6,7,8,9,14,15,16,17,18,19,20,21,23,24,25,26,27,29],No:[0,15,17,18,23],Not:[15,23,25],ON:[9,14,15,19],Of:27,On:[0,1,3,7,14,15,19,20,25,29],One:[0,2,5,7,9,16,18,19,20,24,28],Or:9,Such:[17,24],That:[1,15],The:[0,1,3,4,5,6,7,8,9,10,11,12,14,15,16,17,18,19,20,21,23,24,26,27,28,29],Their:[0,16,18],Then:[0,14,15,16,18,20,24,28,29],There:[0,4,5,12,14,15,16,17,18,23,24,25,27],These:[0,2,5,7,9,10,14,15,16,18,19,20,26,29],To:[0,1,2,5,6,7,8,9,14,15,16,17,18,19,20,21,23,24,25,26,27,28,29],Will:9,With:[0,8,16,17,18,23,27,29],_0:16,_1:[0,2],_2:0,_3:[0,2],_4:0,_:[1,2,7,9,15,16,17,19],____________:18,__get__:9,__setitem__:9,_a:0,_b:[0,24],_c:0,_d:0,_i:[1,9,15,17,21],_interpol:9,_j:[1,2,17,21],_k:[1,7],_l:1,_n:29,_p3mbase:9,_paircriterion:9,_param:9,_particlesliceimpl:9,_s:[0,2],_t:2,_tabulatedbas:9,_type1:9,_type2:9,_type:23,_z:2,a01:[9,16],a02:[9,16],a0_g:[9,16],a1:16,a2:16,a_0:0,a_1:16,a_1bc:16,a_2:16,a_2bc:16,a_:[0,1],a_g:0,a_i:[1,9,17],a_ibc:16,a_j:17,aa6313:3,aaron:3,ab:16,abc:[0,16],abil:18,abl:[6,14,18,19,20,27,28],abort:[9,19],about:[0,1,6,7,9,11,15,16,18,19,21,24,27,28],abov:[0,1,2,7,9,16,17,18,19,20,23,28],absenc:[9,19],absolut:[2,14,15,19,23],abxac:0,ac:9,academ:3,acceler:[20,23],accept:[0,9,18,23,24],access:[1,5,6,7,9,10,14,18,19,20,25,28],accident:[14,19],accommod:[9,27],accompani:20,accomplish:26,accord:[1,8,9,15,17,19,20,23],accordingli:[9,15],account:[0,1,6,7,8,9,15,20,23],accumul:[18,22,23,24],accur:[3,9],accuraci:[1,2,3,8,9,15,17,18,20,21],acf:9,achiev:[0,2,7,8,9,14,15,16,18,23,25,28],achim:3,acid:[9,18,24],acquir:20,acronym:2,across:[9,27,28],act:[0,5,7,9,15,16,17,18,20,23,26,29],act_on_virtu:[9,23],acta:3,action:[0,7,9,25],action_typ:[0,9],activ:[0,3,7,8,9,15,16,17,18,19,20,21,23,24,26,29],active_actor:9,active_list:9,active_matt:18,activevirtualsiteshandl:9,actor:[0,7,8,15,18,19,20,21,22],actual:[0,1,14,15,16,18,19,21,23,24,25,28],acylindr:[1,9],ad:[0,1,2,7,8,9,14,15,16,17,18,19,20,21,24,27,28,29],adapt:[8,9,14,15,19,23,24],add:[0,1,2,5,7,8,9,10,14,15,16,17,18,19,20,21,23,24,27,28,29],add_all_thol:[9,17],add_bond:[0,9,16,18,19,23],add_boundari:9,add_drude_particle_to_cor:[0,9,17],add_exclus:[9,14,23],add_intramol_exclusion_bond:[0,9],add_react:[9,24],add_speci:[7,9],add_subplot:1,add_thole_pair_damp:9,add_verified_bond:9,addit:[0,1,2,5,6,8,9,14,15,17,18,19,21,27,28,29],addition:[0,2,7,8,15],additional_check:14,address:[9,14,23],adhes:0,adjac:[5,9,18,23,27],adjust:[0,1,5,9,14,15,17,20,26,29],adjust_max_skin:9,adsso:29,advanc:[3,13,14,18,25],advantag:[0,2,7,28],advect:[0,7,9,18],affect:[0,9,14,15,18,19,20,23,24,25,26],affin:14,aforement:16,afshar:3,after:[0,1,2,5,9,15,16,19,20,23,24,25,27,29],afterward:[0,14,19],ag:[0,16],again:[0,17,19,29],against:[1,9,14],agglomer:0,agreement:17,agrid:[0,7,9,15,19,20],ah:18,ahlrich:[3,15],aim:[0,15,19,23],aka:21,al:[0,1,2,8,9,15,16,17,18,19,20,21,23,24,27],alboul:3,alchem:17,alexandr:3,alexei:3,algebra:18,algorithm:[0,3,7,9,14,16,17,18,19,20,21,23,24,25,26,27,28],align:[5,7,9,20,23],all:[0,1,2,4,5,6,7,8,9,12,14,15,16,17,18,19,20,21,23,24,25,26,27,28],allen:[3,23],alloc:[25,27,28],allow:[0,2,7,8,9,14,15,16,17,19,20,23,24,27,28],allow_empty_bin:9,allowedthermostat:9,almost:[0,1,8,15,23],alon:[24,27],along:[0,1,2,5,9,15,23,27,28],alongsid:18,alpha:[0,9,10,15,16,17,19],alpha_i:[15,17],alpha_j:17,alphabet:0,alreadi:[0,6,8,9,12,14,15,16,17,18,20,23,24,27],also:[0,1,2,4,5,6,7,8,9,14,15,17,18,19,20,21,23,24,25,26,27,28,29],alter:[0,15,17],altern:[0,1,2,9,14,16,18,23,25],although:[2,8,9,14,15,18,25],alwai:[0,1,2,8,9,14,16,18,19,21,23,24,25,27,28],amber:19,ambient:[9,15,29],ambigu:9,amd:14,among:[25,27],amongst:[15,19,27],amount:[11,28],amphiphil:3,ampholyt:24,amplitud:[7,9],an:[0,1,2,3,4,5,6,7,8,9,10,12,14,15,16,17,18,19,20,21,23,24,26,27,28,29],anaconda:14,analog:[1,15,17,20],analogu:[0,16],analysi:[0,9,13,15,16,18,23,25],analyt:[8,18],analyz:[1,22],andersen:[3,14,16,23],andp:3,andrew:3,angl:[0,1,9,10,15,23],angle_btw_triangl:0,angle_cosin:16,angle_cossquar:16,angle_harmon:16,angle_tab:16,anglecosin:[9,16],anglecossquar:[9,16],angleharmon:[0,9,16],angular:[0,1,9,15,17,23,26],angular_momentum:9,ani:[0,1,2,4,5,6,7,8,9,10,14,15,16,18,19,20,23,24,25],anim:0,anion:[0,18],anisotrop:[3,9,15,23],anisotropi:[1,9,17],annalen:3,annot:14,anomal:3,anoth:[0,1,5,7,9,14,15,18,19,24,25,28],answer:[4,14,23],anthoni:3,anyth:[9,18],ao:3,apart:[2,9,15,18],aperiod:[9,18],api:18,appeal:25,appear:[0,9,14,27,29],append:[12,19,20],append_point_data_to_vtk:0,appendix:[8,13],appli:[0,1,3,5,7,8,9,15,16,17,18,20,21,23,26,27],applic:[0,1,3,7,9,14,15,21,25,27],approach:[0,2,3,9,15,17,28],appropri:[9,15,16,18,24,25],approx:[1,9,17],approxim:[0,2,8,9,15,20],approximation_method:9,apt:14,ar:[1,2,4,5,6,7,8,9,10,11,12,14,15,16,17,18,19,20,21,23,24,25,26,27,28,29],arbitrari:[1,3,14,17,18,19,28],arbitrarili:[2,8,18,20],architectur:[11,14,19,25,28],archiv:[4,6],area:[0,5,8,9],area_triangl:0,aren:14,arg:[9,25],argument:[0,1,2,5,8,9,14,15,17,19,20,23,24,25,29],aris:[1,9,14],arlo:3,arnold13a:[18,20],arnold:[0,2,3,8,18,20],around:[0,1,9,14,15,16,17,18,23,24,27,28],arrai:[1,2,9,14,17,19,20,23,28,29],arrang:[0,9,14,25,28],array_lik:[9,20],array_lock:9,arrow:[9,29],art:[3,8,17],articl:[3,8],artifact:[5,24],artifici:[2,9,15,16,17,26],asan:14,ascii:[0,9,19,20],ask:[9,18,19,23],aspect:[2,28],aspher:[1,9],assert:[9,14],assert_featur:9,assertionerror:9,assertthermostattyp:[9,15],assign:[0,8,9,15,16,18,23,25,27,28,29],assist:[0,9,17],associ:[0,3,7,9,15,16,23,29],assum:[0,1,2,7,9,16,17,19,20,21,24,27,28],assumpt:[2,9,21],asterisk:1,asymmetr:[0,16],athanassio:3,atm:24,atom:[10,16,17,18,19],atomist:[18,23],attach:[0,27,28],attain:24,attempt:[9,19,23],attenu:9,attr:19,attract:[9,17,18],attribut:[0,9,10,15,18,19,23,27],author:[2,18],auto:[1,9,17,18,19],auto_exclus:9,auto_update_accumul:[1,9],autocorrel:[1,9],automat:[1,8,9,14,17,18,19,21,23,25,27],autoupdateaccumul:9,avail:[7,8,9,14,15,16,17,20,21,23,24,27,29],averag:[0,1,9,15,18,24,27],avogadro:24,avoid:[1,5,18,19,24,26],awai:[2,9],await:25,awar:[0,5,9,14,15,18,19,20,23,24,27],ax:[1,9,15,23],axel:3,axi:[0,1,2,5,9,15,20,23,27],axial:9,azimuth:9,b1:9,b2:9,b978:3,b:[0,1,3,5,7,8,9,10,15,16,17,18,23,24],b_1:17,b_2:17,b_:[1,2],b_i:9,b_j:9,bac:0,back:[1,15,20,23,25,27],backcoupl:15,background:[9,16,18,21],background_color:[9,29],backup:19,backward:[9,18,24,29],bak:19,balanc:[9,16,23,27],ball:18,ballenegg:[3,9],bamberg:3,band:16,bandwidth:25,bar:[18,24],barbosa:3,bare:15,barn:9,barostat:18,bart:3,barycent:9,base:[0,1,8,9,10,11,12,14,15,16,18,19,20,21,23,24,25,27,29],baseexcept:9,basi:15,basic:[0,2,3,19,25,28],bath:[9,15],batteri:8,bayreuth:0,bb1:[9,20],bb2:[9,20],bc:8,bcd:0,bd:9,bead:[9,23],beads_per_chain:[9,23],beam:9,bear:14,becaus:[0,1,2,8,9,14,15,17,19,20,23,27,28],becom:[1,2,7,8,9,14,18,24,25,26],been:[0,1,2,7,8,9,14,17,19,20,25,26,27,28,29],befor:[0,2,6,7,8,9,14,15,18,19,20,21,23,24],begin:[0,2,7,9,15,17,19],begin_sect:9,beginn:18,behav:[0,17],behavior:[1,5,7,14,15,16,18,23,24,27],behind:18,being:[0,1,2,9,16,17,18,20,23,25,27],believ:18,belong:[9,16,19,27],below:[0,2,5,9,14,15,16,17,19,25,26,27],benchmark:[14,25],bend:[0,3,9],benefici:24,benefit:[6,25],berend:3,berkowitz:3,berlin:3,bern:[3,9,14,18],berthelot:24,bessel:[2,8,14],bessel_cutoff:[8,9],best:[9,15,25],beta:[1,2,10,15,17,24],beta_j:15,better:[2,9,15],between:[0,2,3,5,7,8,9,14,15,16,17,21,23,24,26,27,28],beyond:[1,2,3,9,17],bh:21,bi:16,bib:[0,18,20],bibliographi:[0,13,18,20],bibtex:[0,14,18,20],big:[0,24],bigger:[15,17],biggl:24,biggr:24,bigl:[1,2,24],bigr:[1,2,24],billiard:[18,29],bin:[1,9,14],bin_cent:[1,9],bin_edg:[1,9],binari:[9,11,14,20],bind:[0,9,14,18,25],bind_at_point_of_collis:[0,9],bind_cent:[0,9],bind_three_particl:[0,9],bindgen:[3,27],biofluid:0,biolog:16,biomed:3,bisect:9,bit:28,bjerrum:[7,8],bla:14,black:[18,20],block:[0,2,9,14,19,25,29],blood:[0,3,18],blow:18,blue:[0,29],blueprint:20,bmhtf:9,bmhtf_nacl:[14,17],bmhtfinteract:[9,17],bmim:18,bochum:3,bodi:[1,3,9,16,20,23],boff:[11,19],boltzmann:[0,1,3,5,7,9,13,18,19,24,26,29],bond:[1,5,8,9,11,12,13,14,15,18,19,23,26,27,29],bond_angl:[9,16],bond_breakag:[0,22],bond_cent:[0,9],bond_constraint:[14,16],bond_id:9,bond_length:[0,9,23],bond_three_particl:[0,9],bond_typ:9,bond_type_color:9,bond_type_materi:9,bond_type_radiu:[9,19],bond_v:[0,9],bondangl:[1,9],bondcriterion:9,bonddihedr:[1,9],bonded_coulomb:16,bonded_int:[0,9,16,18,19,23],bondedcoulomb:[9,16],bondedcoulombsrbond:[9,16],bondedinteract:[9,16],bondedinteractionnotdefin:9,bondid:16,bondtyp:9,book:[1,9,24],bookkeep:[17,25],bool:[0,9,11],boost:14,border:2,born:[14,17,18],bossi:3,bot:17,both:[0,2,5,6,8,9,14,15,16,17,18,20,23,24,25,26,27],bottom:[2,5,8,9,25],bounc:20,bound:[0,2,9,14,16,20],boundari:[2,3,5,8,9,15,18,23,26,28],boundary1:0,boundary2:0,box:[0,1,2,5,8,9,10,15,18,19,20,21,23,24,25,28],box_l:[0,1,7,8,9,10,15,17,18,19,20,21,23,25,26,27,29],box_length:23,boxi:0,boxx:0,br:[3,9,21],bradi:3,branch:[6,9,18,21],breakabl:0,breakag:[0,9],breakage_length:[0,9],breakagespec:[0,9],breitsprech:3,brennan:3,brew:14,brief:[15,18],briefli:[1,7],bright:[9,29],broad:18,broken:[9,14,16],brown:[3,9],brownian:[3,9,14],browniandynam:9,brows:25,browser:25,brute:24,bt:16,buckingham:[9,14],buckinghaminteract:[9,17],buffer:1,bug:[14,18],bugfix:18,build:[0,9,18,25],builddir1:14,builddir2:14,built:[8,14,21,28],bulk:[7,9,20],bulk_visc:[9,20],bulk_viscos:9,bunch:9,burkhard:3,button:[0,9,25,29],buttonev:9,buttonmot:9,buttonpress:9,buttonreleas:9,buyl:[3,9],by_id:[9,16,18,19,23],c0sm00718h:3,c:[0,1,2,3,5,8,9,10,14,16,17,18,19,23,24,25],c_0:16,c_:[9,17],c_i:[9,24],c_po:1,c_vel:1,ca:19,cach:[14,28],cal:1,calc_bending_forc:0,calc_global_area_forc:0,calc_linear_stretching_forc:0,calc_local_area_forc:0,calc_r:[1,9],calc_rg:[1,9],calc_rh:[1,9],calc_stretching_forc:0,calc_volume_forc:0,calcul:[0,2,3,5,7,8,9,14,15,16,17,18,20,21,23,24,25,26,27,28],calculate_excess_chemical_potenti:[9,24],calculate_particle_insertion_potential_energi:[9,24],calip:14,call:[0,1,2,5,8,9,12,14,15,17,18,19,20,23,24,25,27,28,29],call_method:9,callabl:9,callback:[9,18,29],callback_on_button:9,cam_po:9,cam_right:9,cam_target:9,cambridg:3,camera:[9,29],camera_posit:9,camera_right:9,camera_target:9,camwa:3,can:[0,1,2,4,5,6,7,8,9,10,12,14,15,16,17,18,19,20,21,23,24,25,26,27,28,29],cancel:[1,8,16],cannot:[0,1,2,4,5,7,9,14,15,18,19,21,23,24,27],canon:[3,9,18],cao:[8,9],cap:[5,9,17,18],capabl:[7,9,14,18,19,21,25],capacitor:[8,9,18],capsul:5,captur:[16,18],card:[14,21],cardin:9,care:[3,7,9,17,18,19,20,23],carefulli:[0,19],carlo:[9,18,19,24],carri:[1,9,15,18,23,25],cartesian:[1,9,20,23],cast:[9,15],categori:18,cation:[0,18],caught:19,caus:[0,1,5,7,9,14,20],caution:17,caveat:27,caviti:8,cb:9,cbo9780511816581:3,cc:14,cd:[14,25],cdef:9,cdot:[0,1,7,8,9,15,16,17,21,24,27],cecam:4,ceil:[9,19],cell:[0,2,3,8,9,14,16,18,19,21,23,25,28,29],cell_:0,cell_data:0,cell_grid:27,cell_siz:27,cell_system:[0,1,7,10,15,18,19,20,22,23,25,27,29],cell_typ:0,cellplist:28,cellsystem:[9,18,23,27,28],celltyp:0,center:[0,2,5,9,15,16,20,21,23,28],center_i:9,center_of_mass:[1,9],center_x:9,centr:[0,5,16],central:[0,1,2,5,9,16],central_angl:9,centroid:16,cerd:[3,8,21],cerda:3,certain:[1,8,9,15,18,23,24],chain:[0,3,9,18,19,24],chain_length:9,chain_start:9,chaina:19,chamber:18,chamber_gam:18,chandler:14,chang:[0,1,2,6,7,8,9,14,15,18,19,20,23,24,25,27],change_reaction_const:9,change_volume_and_rescale_particl:[9,23,26,27],channel:[0,4,5,9,18,19],channel_width:[5,9],chapter:[7,9,14,15,23,24,25,27],charact:[9,19],character:9,charg:[0,1,2,3,4,7,8,9,12,14,16,17,18,19,20,23,28,29],charge_dens:7,charge_unit:12,charged_system:18,charl:3,charmm:[18,19],cheap:2,chebychev:2,check:[0,8,9,12,14,18,20,21,23,25],check_array_type_or_throw_except:9,check_for_electroneutr:9,check_neutr:9,check_orient:0,check_required_kei:9,check_topolog:9,check_type_or_throw_except:9,check_valid_kei:9,checkpoint:[5,7,15,18,22,24],checkpoint_id:[9,19],checkpoint_index:9,checkpoint_path:[9,19],chem:18,chemic:[0,3,9,18,24],chi:17,child:9,chlorid:7,chmidt:3,choic:[0,1,5,7,9,15,18],choos:[0,1,2,7,8,9,14,15,17,18,23,24,25,28],chosen:[0,9,11,17,18,19,23,27,28],chri:3,christian:3,christoph:3,chrome:9,ci:6,cid_for_particl:9,cimr:[0,3,16],cimrak12a:0,cimrak14a:0,cimrak:0,circl:5,circularli:29,circumst:[9,23],circumv:7,citat:18,cite:[0,1,8,16,20,23],cl:[9,17],clang:14,clarendon:3,class_lookup:9,classic:[2,15,16,17,28],clcr:17,clean:[9,14],clear:[0,5,8,9,15,18,21,23],click:[0,25,29],clip:9,clock:28,clockwis:0,clone:[6,14],close:[0,1,2,5,7,12,16,17,19,25,28],close_cut_dist:9,closer:[0,1,9],closest:5,cloud:0,cluster:[9,14,25],cluster_analysi:[1,14,22],cluster_id:9,cluster_structur:9,clusterstructur:[1,9],cm:9,cmake:25,cmake_build_typ:14,cmake_cxx_flag:14,cmake_install_prefix:14,cmakelist:14,cms_vel:9,cnm:3,co:[2,9,16,17,23],coars:[0,1,3,7,17,18],code:[1,2,7,9,14,15,18,20,21,23,27,28,29],coeffici:[0,7,9,14,15,16,17,18,20,23,24],cohen:3,coil:17,coincid:23,colbi:[3,9],cold:[16,17,18],collect:[0,1,3,8,9,17,25],collid:9,collis:[0,9,14,15,18,23],collision_detect:[0,14,22,23],collisiondetect:[0,9],colloid:[15,18],color:[9,18],column:[9,18],com:[7,9,14,18,19,20],combin:[0,1,3,7,8,9,14,15,17,18,19,23,24,25,26],come:[0,2,7,9,14,15,18,25],comfix:[22,26],comma:16,command:[0,1,5,7,14,15,16,17,18,19,20,23,24,25,26,27],comment:14,commit:[9,14],common:[0,1,2,5,8,9,11,14,15,16,18,25,28],commonli:8,commun:[2,3,6,13,14,18,19,27,28],compar:[0,1,2,15,18,20,24],comparison:[3,20],compart:27,compat:[1,9,14,15,19,20],compens:15,compil:[6,7,8,9,15,20,23,25,26,28],compiler_id:14,complet:[0,2,7,8,9,14,15,18,19,20,23,25,27],complex:[0,1,18,20,23],complic:[2,19],compon:[0,1,2,9,15,17,18,19,23,27,29],componentwis:9,componentwise_product:9,composit:[1,9],compress1:[1,9],compress2:9,compress:[1,9,20,23],compris:[9,15,16],comput:[0,1,2,3,7,8,9,14,15,16,17,18,19,20,27,28],computation:[0,2,8,18,20],compute_cap:25,comveloc:[1,9],concav:[5,16],concentr:[7,9,24],concept:[1,16],conceptu:15,concern:[1,4,18],concomit:24,concurr:14,conda:14,condens:[3,7,18],condit:[0,2,3,7,9,14,15,18,24,26],condition:2,cone:5,config:14,configur:[0,1,5,8,9,16,17,18,19,24,26,27],confin:[1,18],conflict:14,confus:18,conic:[7,9],conjunct:[0,17,21],connect:[0,1,5,8,9,16,17,23],consecut:[0,1,9],consequ:[2,15],conserv:[0,5,9,15,17,18,20,24],consid:[0,1,2,4,5,9,15,16,18,20,21,23,24,27,29],consider:[0,27],consist:[0,1,15,17,18,20,24,25,28],const_pot:[8,9],constant:[0,1,3,7,8,9,14,15,16,18,19,20,23,27],constant_ph:[9,18],constantphensembl:[9,24],constitut:[2,9,19],constrain:[9,16],constraint:[0,1,8,13,15,16,18,19,20,21,22,23,26,27,29],constraint_type_color:9,constraint_type_materi:9,construct:[2,9,18,23],constructor:[1,5,9,19],consult:[14,15,16],consum:[0,28],contact:[0,4,6,18],contain:[0,1,5,7,8,9,14,16,17,18,19,20,21,23,24,25,27,28,29],content:[0,16,19,22],context:[5,9,17,25],contigu:[1,9,24,28],continu:[1,2,5,6,7,8,9,14,17,18,19],contrari:[17,25],contrast:[8,9,19,21,23,28],contrib:14,contribut:[1,2,5,7,8,9,13,14,15,17,18,23],control:[0,1,5,6,7,8,9,14,15,17,18,19,21,23,25,27],conveni:[0,2,9,18,24,25,26,29],convent:[0,9,17,21,24],convention:7,converg:[2,8,9,24],convergence_criterion:15,convers:[5,9,24],convert:[8,9,18,19,23,25],convert_unit:10,convert_vector_body_to_spac:[9,23],convert_vector_space_to_bodi:9,convex:[0,5],coordin:[0,1,2,5,8,9,10,12,14,15,18,20,21,23,26,27,28],copi:[0,1,9,14,17,18,19,20,21,23,27],core:[0,1,6,8,9,10,14,17,18,23,24,25,26,28],core_part:9,corner:[0,5,9,20],corr:1,corr_oper:[1,9],correct:[0,1,2,3,9,14,15,16,18,20,23,25],correctli:[1,8,15],correl:[3,7,9,18],correspond:[0,1,5,7,8,9,14,15,16,17,18,19,20,24,25,26,27],cosh:2,cosin:[1,2,9,14],cospersistenceangl:[1,9],cost:[1,9,27],could:[5,6,16,18,20,23],coulomb:[0,1,2,7,9,17,18,21,27],coulomb_prefactor:[0,9],count:[1,8,9,19],counter:[1,7,8,9,15,19,27],counterion:3,counterpart:[1,8],coupl:[0,1,5,7,9,14,15,18,23,27],cours:[1,18,20,23],coval:0,cover:[0,1,7,9,17,19],coverag:14,cpc:3,cph:24,cpickl:9,cplett:3,cppcheck:14,cpu:[7,8,9,14,21,23,25,27],crash:[0,5,24,25],crc:3,creat:[5,7,8,9,10,14,16,17,18,19,20,21,24,25,26,27,29],creation:[0,9,18,24],criteria:[1,9],criterion:[1,9,23,24],critic:[0,18],cross:[0,5,7,9,16,18,20,27],crowl:[0,3],crucial:[16,28],crystal:[3,17],cs:1,ct:16,ctest:14,ctest_arg:14,ctrl:[19,25],cubic:[8,9,21,23,26,27,28],cubic_box:9,cuboid:[9,27],cuda:[7,8,9,14,20,21],cuda_bin_path:14,cuda_init:[22,25],cuda_init_handl:[9,25],cuda_toolkit_root_dir:14,cudainithandl:[9,25],cumbersom:14,cumul:21,current:[0,1,7,9,10,14,15,16,17,18,19,20,23,24,25,26,27,28,29],current_volum:9,curs:14,cursor:29,curv:8,curvatur:16,custom:[9,18,25],cut:[8,9,15,16,17,21,27],cut_off:[1,9],cutoff:[0,2,3,5,8,9,15,16,17,18,19,27],cutoff_regular:[9,27],cxx:14,cycl:[0,15,29],cyl_transform_param:[1,9],cylind:[0,7,9,18],cylindr:[1,5,9],cylindricaldensityprofil:[1,9],cylindricalfluxdensityprofil:[1,9],cylindricallbfluxdensityprofileatparticleposit:[1,9],cylindricallbvelocityprofil:[1,9],cylindricallbvelocityprofileatparticleposit:[1,9],cylindricalprofileobserv:9,cylindricaltransformationparamet:[1,9],cylindricalvelocityprofil:[1,9],cython3:14,cython:14,d3q19:9,d:[0,1,3,7,9,14,15,17,18,20,21,23,24],d_k:7,d_new:[9,26],d_r_max:[9,16,23],daan:3,daemon:29,dai:4,dalk:3,damp:[0,9,17],dampen:9,danc:18,darden:3,dark:9,dat:0,data:[1,5,9,10,11,12,14,18,19,20,25,27,28],datafil:0,datanam:0,dataset:[0,19],date:[6,25],david:3,dc:1,dcmake_build_typ:14,dcmake_cxx_flag:14,dcmake_install_prefix:14,dd:21,ddr:28,de:[3,9,23],deactiv:[9,23],deal:[2,8,14,19,24,27],debian:14,debug:29,debugg:25,deby:9,decad:[1,7],decai:[9,17,20,23],decid:[9,15],declar:[9,14,19],decod:19,decompos:[2,17],decomposit:[2,9,23,28],decomposition_typ:9,decor:9,decoupl:[2,7],decreas:[1,2,7,19,20,25,27],decreasetemp:29,dedic:16,deduc:7,deeper:[2,17],def:[9,15,29],default_charg:[9,24],default_param:[9,12],default_scal:9,defin:[0,1,2,7,8,9,12,14,15,16,17,18,21,23,24,28],define_bound_method:9,definit:[9,15,16,19,20],deform:[0,3,9,15,16,26],degre:[0,1,9,10,14,15,17],deleg:[9,25],delet:[9,14,16,19,24],delete_all_bond:9,delete_bond:[0,9,16],delete_exclus:[9,23],delete_particl:9,delete_react:9,delete_verified_bond:9,delimit:14,deliv:28,delta:[0,1,2,7,9,15,16,17,24],delta_:[1,15,17,24],delta_b:[8,9],delta_mid_bot:[8,9],delta_mid_bottom:9,delta_mid_top:[8,9],delta_n:[1,9],delta_t:[8,9],demand:[2,18,28],demo:18,demon:18,demonstr:[5,18,20,24,29],den:[0,9,15,20],denisov:3,denomin:9,denot:[0,1,2,8,9,15,16,19,23],dens:[3,26],densiti:[0,1,2,7,8,9,18,20,23,24,26,27],density_profil:1,densityprofil:[1,9],depend:[0,1,2,5,6,8,9,12,14,15,17,18,19,20,23,25,27,28],depict:5,deploi:18,deprec:25,depth:[0,9,17,28],der:[3,17,18],deriv:[1,2,9,15,18,23,24,27],descend:[1,9],descent:[8,9,26],describ:[0,1,2,5,7,8,9,14,15,16,18,19,20,21,23,24,28],descript:[1,5,7,10,17,20,21,24],descriptor:[1,9],deseri:25,deserno:[3,8,21],design:[0,9,14,18,25],desir:[0,1,5,8,15,17,18,20,21,23,24,25],despit:15,destdir:14,det:9,detail:[0,2,5,6,7,8,9,11,14,15,16,17,18,19,20,21,23,25,27],detect:[0,9,14,18,23],determin:[0,1,5,7,8,9,14,15,19,21,23,24,25,27,28,29],determinist:[15,19],dev:[14,19,29],develop:[0,4,14,18,25],deviat:[9,16,19,20],devic:[0,3,6,9],dh:[0,8,9],diagon:[9,15],diagonalized_inertia_tensor:9,diamet:[0,9,15,18,24],diamond:[9,18],diatom:17,dict:[9,10,12],dictionari:[1,9,12,15,19,25],did:[15,18],didn:[4,14],die:3,diego:3,dielectr:[3,7,9,18],differ:[0,1,2,4,5,7,8,9,11,12,14,15,16,17,18,19,20,23,24,25,27,28],differenti:[3,9,17],difficult:[19,26],diffus:[9,15,18,20,29],diffusion_coeffici:[1,18],dihedr:[1,9],dihedral_tab:16,dilut:[1,15],dimens:[0,2,3,9,10,15,18,19,24,27],dimension:[2,3,9,20,23],dimensionless:24,dip:[1,9,21,23],dipm:9,dipol:[0,1,2,3,8,9,14,17,21,23],dipolar:[0,3,9,14,18,23],dipolar_barnes_hut:9,dipolar_direct_sum:[9,14],dipolarbarneshutgpu:[9,21],dipolardirectsumcpu:[9,21],dipolardirectsumgpu:[9,21],dipolardirectsumwithreplicacpu:[9,21],dipolarp3m:[9,21],dipole_length:[9,23],dipolemo:[1,9],dipython_execut:25,dir:[1,9,26],direct:[0,2,5,8,9,14,15,16,18,20,23,24,26,27,28,29],directli:[0,1,2,7,9,23,25,27,28],director:[9,23,29],director_arrow:[9,29],director_arrows_type_color:[9,29],director_arrows_type_materi:9,director_arrows_type_radii:[9,29],director_arrows_type_scal:[9,29],directori:[0,6,9,14,18,19,25],dirti:9,disabl:[9,14,15,17,23,27],disastr:9,discard1:[1,9],discard2:9,discard:[0,1,9,25],discard_epsilon:0,discont:[9,17],discontinu:[5,8,17],discret:[0,2,9,15,17],discretis:[0,15],discuss:[1,2,4,5,13,15,18,20,28],disk:19,displac:[1,5,9,18,26],displacement_mc_move_for_particles_of_typ:9,displai:[0,16,25],displaystyl:9,disregard:[1,9],dissert:3,dissip:[3,14,17],dissoci:24,dist0:0,dist:[0,5,9,20],dist_cm:9,distanc:[0,2,8,9,15,17,18,21,23,24,26,29],distance_criterion:1,distance_glued_particle_to_v:[0,9],distance_vec:[0,9],distancecriterion:[1,9],distinct:[0,23],distinguish:[0,14,18,19,29],distribut:[2,6,7,8,9,15,16,17,18,23,25,28],diverg:[8,16],divid:[1,7,16,26,27],dividing_plan:[5,9],divis:[9,14],dka:[3,9,21],dlc:9,dm:24,dna:3,doc:[0,14,18,20,25],dockerfil:14,doctor:14,document:[0,1,4,5,6,7,11,16,18,19,20,25],doe:[0,2,5,7,8,9,15,16,17,18,19,20,21,23,24,25,26,27],doesn:[8,9,14,15,18,25],doi:[3,9,18],domain:[9,18,27],domin:3,don:[7,14,18,20,25],donald:3,done:[0,1,2,8,9,14,15,16,18,20,23,24,25],dot:[2,5,9,15,18,24],doubl:[1,9,11,14,20,21,28,29],doubleclick:9,doubt:19,down:[0,2,8,14,25],download:[0,14],downsid:0,doxygen:[6,14,25],dp3m:21,dpd:[3,9,14,18,26],dpd_stress:9,dpdinteract:9,dpdstress:[1,9],dr:9,drag:[9,15,20],drag_en:[9,29],drag_forc:[9,29],draw:[9,15,23],draw_arrow:9,draw_axi:9,draw_bond:9,draw_box:9,draw_cap:9,draw_cel:9,draw_constraint:9,draw_cylind:9,draw_nod:9,draw_plan:9,drawabl:9,drawn:[9,15,17],drewel:3,drift:[19,20,26],drive:0,driven:[15,20],drop:[0,1,9,25],drude:[9,16,17,18],drude_bmimpf6:[17,18],drude_help:[0,22],drude_part:[0,9],drudehelp:[0,9],dt:[9,15,17],dtype:19,due:[0,1,2,5,7,9,14,15,16,17,18,19,20,21,24,25,26,27],dumbbel:18,dump:11,dupin:[3,16],dure:[0,1,2,7,8,9,14,15,17,18,19,21,23,27,29],durlofski:[3,15,18],dwith_asan:14,dwith_cuda:14,dwith_cuda_compil:14,dwith_gsl:9,dwith_hdf5:19,dwith_stokesian_dynam:15,dwith_ubsan:14,dynam:[0,1,3,7,8,9,17,18,20,25,27,28],e0:9,e1:9,e2012:3,e2016:3,e2019:[3,18],e2:9,e:[0,1,2,3,5,8,9,12,14,15,17,18,19,20,21,23,24,25,27,28],e_0:9,e_1:17,e_2:17,e_:[1,2,8,24],e_c:2,e_z:23,each:[0,1,2,5,8,9,14,15,16,17,18,20,23,24,25,27,28],earlier:[0,23],easi:[1,2,6,8,19],easier:14,easili:[0,2,14,19,23,27],eastwood:[3,8,21],echo:14,edg:[0,1,5,9,16,28],edit:[3,14],editor:[3,25],edward:[3,9,15,18,19,20],effect:[5,7,9,15,17,18,20,21,23,25,27,28],effici:[1,2,3,8,18,20,21,27,28],effort:1,eigenvalu:[1,9,14,15,23],eigenvector:[1,9],eight:2,eighth:9,einstein:7,either:[0,1,2,4,5,9,14,15,16,19,20,21,23,25,26,29],ek:9,ek_boundari:[7,14],ek_debug:14,ek_init:9,ekboundari:[7,18,22],elabor:28,elast:[3,9,16,18,23],elastic_forc:0,elasticforc:0,elasticlaw:[9,16],elc:[9,18,21],elc_gap:9,electr:[1,7,8,9,14,19,20],electricplanewav:[5,9],electricpotenti:[5,9],electro:[7,14],electrod:8,electrodynam:7,electrohydrodynam:3,electrokinet:[0,13,14,18,22],electrokineticsroutin:9,electrolyt:7,electron:0,electroneutr:9,electrophoresi:18,electrophoret:[9,20],electrostat:[1,2,3,7,13,14,16,17,18,19,21,22,23,25],electrostatic_extens:[8,22],electrostaticextens:9,electrostaticinteract:9,elektrostatisch:3,element:[0,9],elementari:[17,18],elfrich:3,ellipsoid:[7,9],elong:[0,9,17],els:[5,6,15,29],elsevi:3,elsewher:[0,17],email:4,embed:[16,28],emphasi:18,emploi:8,employ:18,empti:[2,9,12,25,29],emptyset:24,en:[0,14,16,25],enabl:[0,1,7,9,14,15,16,18,19,23,25],encapsul:19,encod:[9,15],encount:[14,19],end:[0,1,2,5,7,9,15,17,19,25],end_sect:9,endow:7,endpoint:16,energet:[0,1],energi:[0,2,3,5,7,8,9,14,15,16,17,18,21,24,26,28],energy_old:15,energy_threshold:15,energycriterion:9,enforc:[15,18,19],engin:[3,9,14,18,19,29],enhanc:17,enough:[0,1,2,7,14,15,21],ensembl:[1,3,9,15,18],ensur:[0,8,9,21,28],enter:[0,1,8,9,15,21,25,29],enthought:[7,20],entir:[1,9,18,20,25],entri:[2,9,18,19,23,29],entropi:7,enumer:[19,20],environ:[18,19,25,27],eo:[10,19],ep:9,epjst:[3,18],epl:3,eps_out:[8,9],epsilon1:9,epsilon2:9,epsilon:[8,9,17,18,19,21],epsilon_:17,epssq:21,epyc:14,eq:[1,7,15,17,20,24],eqn:8,equal:[0,1,2,8,9,15,16,17,18,19,23,24,25,26,27,28],equat:[1,3,9,14,15,16,18,23,24,27],equatori:[5,9],equidist:9,equilater:0,equilibr:[17,26,29],equilibria:[3,24],equilibrium:[0,1,3,7,9,16,24],equival:[9,15,24],eras:19,erechnung:3,erfc:1,erin:3,erlend:3,ermak:[3,15],err:8,err_msg:9,error:[0,1,3,5,8,9,14,15,16,18,19,20,21,23,24,27],error_analysi:18,es_coupl:[7,9],escap:18,esh:3,esp:10,especi:[0,2,14],esppars:10,espread:10,espresso:[0,1,2,3,4,5,6,7,8,9,10,11,12,14,15,16,17,20,21,22,23,26,27,28,29],espresso_add_ompi_singleton_warn:14,espresso_cpp_flag:14,espresso_logo:18,espressomd:[0,1,4,5,6,7,8,13,14,15,16,17,18,19,20,21,23,24,25,26,27,29],espressosystemstandalone_test:25,essenti:[0,6,14,15,19],esser:3,essmann:[1,3],establish:14,estat:7,estim:[1,2,3,8,9,21,27],et:[0,1,2,8,9,15,16,17,18,19,20,21,23,24,27],eta:[7,15,17],eta_:[7,17],eta_i:15,etc:[0,2,9,15,19,20,25,29],eth:3,ethz:3,euler:[0,15],eur:18,european:3,europhys:3,eva0:9,eva1:9,eva2:9,evalu:[1,2,9,20,28],even:[0,1,2,7,9,14,15,18,19,23,24,25,27,29],event:[4,9,29],ever:14,everi:[0,1,2,4,9,14,15,16,20,25,26,28,29],everyth:18,everywher:[9,17],evil:14,ewald:[2,3,7,8,9,21],ewald_r_cut:8,ex:24,exact:14,exactli:[0,16,23],examin:15,exampl:[0,2,3,5,7,8,9,10,14,15,16,18,19,23,24,25,26,27,28],exce:0,exceed:17,excel:2,except:[1,2,5,9,12,14,17,19,23,25,27],excess:[2,9,18,24],exchang:[9,24],excit:9,exclud:[0,7,9,14,23],exclus:[0,9,14,18,24],exclusion_radius_per_typ:[9,24],exclusion_rang:[9,24],execut:[0,14,18,20,21,25,28],execute_process:14,exercise2:[14,25],exert:[20,29],exhibit:3,exist:[0,1,2,9,12,14,15,16,17,19,23,24],exit:[5,25],exp:[1,8,9,17,24],expand:[2,16],expect:[0,9,15,18,20],expens:[0,1,8],experi:[14,18,28],experienc:9,experiment:[7,15,18,27],expert:20,explain:[7,15,17,23,25,27,28],explan:[1,7,15,23,25],explicit:[7,8,9,18],explicitli:[8,9,17,18,21,23,27],exploit:18,expon:[9,14,17],exponenti:[2,5,9],expos:[10,18,25],express:[2,8,18,20,24],ext_field:[8,9],ext_forc:[5,7,9,15,23,29],ext_force_arrow:[9,29],ext_force_arrows_type_color:9,ext_force_arrows_type_materi:9,ext_force_arrows_type_radii:9,ext_force_arrows_type_scal:9,ext_force_dens:[0,7,9,20],ext_pressur:[9,15],ext_torqu:[9,23,29],extend:[5,8,9,16,18,23],extens:[0,3,6,8,9,14,15,16,18,25,26,29],extent:[1,24],exterior:9,extern:[0,6,7,9,15,16,18,19,20,29],external_field:9,external_forc:[0,9,14],extra:[1,2,5,14,25],extract:[1,7,19],extrapol:16,extrem:[0,3,16,25],extrus:[5,9,29],ey:0,f5:25,f:[0,1,2,3,9,15,17,18,19,24,25,27,29],f_:[1,2,15,16,17,20,26],f_i:15,f_max:[9,15,26],f_p:2,f_q:2,f_swim:[9,23],f_v:16,f_x:0,f_y:0,f_z:[0,2],fa:25,fabritiu:3,face:0,facilit:1,fact:[0,1,2,5,9,15,18,19,27],factor:[2,9,16,17,18,24,26],fahrenberg:3,fail:[9,11,14,15,19,20,23],failur:19,fairli:[18,27,28],fall:[1,9,18],fals:[0,5,7,8,9,11,15,20,23,27],famili:8,familiar:0,faq:[4,14],far:[2,7,8,9,15,18,19,21,23],far_cut:9,far_cut_dist:9,far_switch_radiu:[8,9],fashion:[5,7,9,24,28],fast:[1,2,3,8,14,17,18,20,21,28],faster:[7,9,14,17,20,25,28],fastest:8,fatal:14,fault:[14,25],favor:[2,18],fc:[1,9],fcs_acf:9,feasibl:[1,8],featur:[0,1,6,7,8,9,15,16,17,18,19,20,21,25,26,27,28,29],featureserror:9,februari:3,fedora:[14,29],feed:10,felix:3,fenc:25,fene:[9,23],fenebond:[9,16,23],ferri:[1,3],ferrofluid:[3,18],fetch:28,fetchcont:14,fetchcontent_declar:14,few:[0,1,2,5,9,14,18,25,27],fewer:[21,25,28],ffast:14,ffect:3,ffmpeg:[14,29],fft:[9,25],fftw3:[8,14],fftw:[8,14],field:[0,3,9,11,12,14,15,16,19,20,21,23],fig:[0,1,5,14,25],figur:[1,2,5,9,18],file:[7,9,10,11,12,14,18,20,25,29],file_path:[12,19],filenam:[0,9,10,11,14,29],filepath:19,fill:[0,12,19],filter:[0,9,15,23],find:[1,4,5,6,8,9,14,16,18,19,25],fine:[5,27],finer:14,finit:[2,7,9,14,16,17],fireev:9,firewal:14,first:[0,1,5,6,7,8,9,14,15,16,17,18,19,20,23,25,28],first_id:[8,9],firstappend:0,fit:[9,28],five:18,fix:[1,8,9,14,15,17,18,21,23],fixedpoint:0,fl:7,flag:[5,7,9,15,19,20,25],flat:[9,16,20,25],flatter:16,flexibl:[0,1,18,27],fling:[3,9],flip:0,floor:9,florian:3,flow:[0,3,9,16,18,19,20,23],flowfield:[5,9],fluctuat:[0,7,8,9,15,18,20,23,24,26],fluctuation_amplitud:7,fluid:[1,3,5,7,9,15,18,19,23,26],fluid_coupl:[7,9],fluidactor:9,fluoresc:[1,3,9],fluorophor:9,flush:[12,19],flux:[7,9],fluxdensityprofil:[1,9],fly:[1,3,14,20],fmetric:0,fname:9,fno:14,focu:[9,18,20],fogelson:[0,3],fold:[0,1,9,19,27],folder:[0,14,17,19,25],follow:[0,1,5,7,8,9,10,12,14,15,16,17,18,19,20,21,23,24,25,26,29],foo:29,footnot:18,forc:[0,1,2,3,7,8,9,10,13,14,15,17,18,19,20,21,23,24,28,29],force_arrow:[9,29],force_arrows_type_color:9,force_arrows_type_materi:9,force_arrows_type_radii:9,force_arrows_type_scal:9,force_cap:[9,26],force_unit:12,forcedensityprofil:[1,9],forcefield:[5,9],forces_unit:19,fork:6,form:[0,1,2,8,9,14,16,20,27],formal:[7,9,15,23,24],format:[9,10,12,14,18,20,29],former:[0,5,7],formul:[3,16],formula:[1,2,3,8,9,24],forum:4,forward:[2,9,24,25,29],found:[0,1,4,5,6,9,14,15,17,18,24,29],four:[1,12,16],fourier:[1,2,9,14],fourth:[1,9,16],fp:[12,14,19],fr:8,frac:[1,2,7,8,9,15,16,17,18,21,24,27],fractal:9,fractal_dimens:[9,14],fraction:[9,21,28],frame:[1,9,10,18,19,23,26],framer:29,framework:[0,9,18,20,21],franosch:3,frederick:3,free:[0,4,7,23,24,26],freedom:[0,1,7,9,14,15],freeglut3:14,freeglut:14,freeli:[17,18],freemot:9,freez:18,frenkel:[1,3,18],frequenc:[0,7,9,23,28],frequent:[1,9,17],fri:[0,16],fric:0,frict:20,friction:[0,7,9,14,15,16,17,20,23],friendli:[9,18],from:[0,1,2,4,5,6,7,8,9,12,14,15,16,17,18,19,20,21,23,24,25,26,27,28,29],frustrat:0,frustum:[7,9],fs:25,ft:9,fulfil:[7,16,23],full:[1,8,9,15,18,25,28],fulli:[0,1,8,14,15,17,19,25,27],fumi:[14,17],further:[0,1,2,7,15,17,18,19,20,23,24,27,29],furthermor:[8,19,20,21,23],futur:[0,18,25],g0:0,g:[0,1,3,8,9,12,14,15,18,19,20,23,24,25,27,28],g_i:9,ga:[7,18,24],gai:[3,9,14,18],gain:[1,14],galilei:22,galilei_transform:[9,26],galileitransform:[9,26],game:18,gamepad:18,gamma0:[9,15],gamma:[2,9,10,15,17,20,24,27,29],gamma_:[9,17],gamma_com:[9,16],gamma_dist:[9,16],gamma_even:[9,20],gamma_odd:[9,20],gamma_rot:[9,15,23,27],gammav:[9,15],gap:[2,8,9,12,18],gap_siz:[8,9,21],gari:3,gather:[9,17,25],gaussian:[9,14],gaussianinteract:[9,17],gay_bern:[9,14,17],gayberneinteract:[9,17],gcc:14,gdb:[14,25],ge:[2,15,17],gear:25,geforc:25,gekl:[0,3],gel:23,gener:[0,1,2,3,5,6,8,9,12,15,16,18,19,20,23,24],generate_cal:9,generic_lennard_jon:[9,17],genericlennardjonesinteract:[9,17],geometr:5,geometri:[0,3,5,9,15,16,18,20,27],ger:[0,3,9,16],germani:4,get:[0,1,4,7,9,12,14,15,16,18,19,20,21,23,25],get_acceptance_rate_configurational_mov:9,get_acceptance_rate_react:9,get_approx_origin:0,get_available_method:[8,9,21],get_bonded_interaction_type_from_es_cor:9,get_camera_rotation_matrix:9,get_default_param:9,get_extra_clip_plan:9,get_forc:20,get_indic:9,get_interpolated_fluid_velocity_at_posit:[9,20],get_interpolated_veloc:[9,20],get_last_checkpoint_index:9,get_magnetostatics_prefactor:9,get_n_nod:0,get_n_triangl:0,get_near_field_deleg:9,get_neighbor:[9,23],get_non_interacting_typ:9,get_origin:0,get_origin_fold:0,get_pair:9,get_param:[9,12],get_paramet:9,get_registered_object:9,get_sip:9,get_stat:[9,25,27,29],get_statu:9,get_t:9,get_valu:9,get_veloc:0,get_volum:9,get_wall_constraints_in_z_direct:9,gg:1,ghost:[9,23,25,28],gibb:24,git:[6,9,14],git_branch:9,git_commit:9,git_execut:14,git_repositori:14,git_stat:9,git_tag:14,github:[4,6,13,14,18,19,27],give:[0,1,7,9,18,19,27],given:[0,1,2,5,7,8,9,11,12,14,15,16,17,18,19,20,21,23,24,25,26,27],global:[0,1,9,14,29],global_flag:9,global_force_interact:16,global_rot_spe:9,glue_to_surfac:[0,9],glyph:0,gmsh:0,gnu:[14,18],gnuplot:20,go:[5,7,9,12,25],goe:[17,28],gold:29,goncalo:3,gone:23,good:[0,6,9,15,18,19,21,24,25],govern:15,gpu:[3,7,9,18,23],gpu_avail:9,graaf:[3,23],gradient:[15,18],gradual:26,grain:[0,1,3,17,18],grand:[9,18],grand_canon:18,grant:19,graphic:[3,6,14,21],graphviz:14,grassberg:3,gravit:9,graviti:[5,9],great:17,greater:[7,9],greatli:0,green:1,grid:[0,7,8,9,19,20,27,28],grid_spac:9,griebel:3,gromac:[18,19],gromo:19,gromos96:16,grotendorst:3,group:[0,1,9,17,18,19,24,29],grow:[1,2,9,28],gsl:[9,14],gt:[25,26],guarante:[0,18,23],gubbin:3,guckenberg:[0,3],gui:[14,19],guid:[0,3,9,14],guidelin:18,gunsteren:3,gusenbau:3,gyrat:9,gyration_tensor:[1,9],h1:0,h2:0,h5:19,h5dump:19,h5file:19,h5md:[9,11,14,18],h5md_trajectori:[18,19],h5mdplugin:19,h5py:19,h5xx:14,h:[2,3,8,9,14,18,24,29],h_:16,h_v:15,ha:[0,1,2,5,6,7,8,9,12,14,15,16,17,18,19,20,21,23,24,25,26,27,28,29],had:9,half:[0,1,9,15,19,21],halfwai:20,halim:3,hallidai:3,halo:25,halt:[14,15,19,26],han:3,hand:[1,2,6,18,24],handl:[0,8,9,16,17,18,23,29],handle_error:9,handle_input:9,handler:9,happen:[5,9,15,27],hard:[1,17,18,26],hardcod:7,harden:3,harder:18,harm_bond:9,harmless:9,harmon:[0,9,17,18,19],harmonic_bond1:0,harmonic_bond2:0,harmonic_bond:[0,9],harmonicbond:[0,9,16,18,19],has_checkpoint:9,has_featur:9,hasn:19,hat:[9,14,15],hatinteract:[9,17],have:[0,1,2,4,5,6,7,8,9,12,14,15,16,17,18,19,20,21,23,24,25,27,28,29],have_quaternion:[9,23],hb:16,hdf5:[14,19],hdfgroup:19,hdfstore:19,hdfview:19,he:18,head:[1,9,11,19,25],header:[12,14,19],hear:0,heart:0,heat:[0,9,15],heath:3,heavili:28,heavisid:7,heidelberg:3,height:[2,9],held:[0,9],help:[0,5,14,18,23],helper:[9,17],hemispher:[5,9],henc:[1,2,21],henri:3,heori:3,here:[0,1,2,5,7,9,12,15,16,17,19,20,23,24,27,28],hereinaft:15,hertzian:[9,14],hertzianinteract:[9,17],hesit:25,heurist:15,hi:18,hickei:[3,20],hidden:[9,25],hide:[9,18],hierarch:[1,2],high:[0,1,7,14,15,20,25,27,29],higher:[1,4,7,14,17],highest:9,highest_particle_id:[9,23],highland:22,highli:[2,7,8,18,25,27],hinder:27,histogram:[1,9],histor:14,histori:1,hit:28,hm:3,hocknei:[3,8,21],hold:[0,2,9,15,29],hole:[9,19],hollow:[5,7,9],hollowconicalfrustum:[9,29],holm:[2,3,8,21],home:25,homepag:[14,19],homogen:[1,2,8,9,15,20,21],homogeneousflowfield:[5,9],homogeneousmagneticfield:[5,9],hood:13,hookean:[0,9,16],hookian:0,horizont:5,hors:17,host:9,hostnam:25,hot:0,how:[0,1,3,4,5,8,9,14,15,16,17,20,23,24,25,27,28],howard:3,howev:[0,1,2,5,7,9,14,15,17,18,19,20,23,24,25,26,27,28],hpc:14,hpp:[0,2,15,21,25],hsing:3,html:[14,25],http:[0,6,7,14,16,18,19,20,25],hu:3,hueckel:9,huge:9,huggin:[14,17],human:19,humphrei:[3,19],hut:9,hybrid:[9,23,25],hydrodynam:[1,3,7,9,14,15,18,20,23],hydrodynamicinteract:[9,19],hyperthread:25,i:[0,1,2,3,5,9,14,15,16,17,18,19,20,21,23,24,25,27,28,29],i_0:9,i_:[2,21],ian:3,ibm:[0,9,15,24],ibm_tribend:[9,16],ibm_triel:[9,16],ibm_volcon:[9,16],icc:[3,9,18],icc_typ:8,iccarea:8,iccepsilon:8,iccnorm:8,iccsigma:8,icmmm2d:3,icon:0,id:[0,1,9,11,12,16,18,19,23,24],idea:[0,2,6,18,19],ideal:7,ident:[0,17,24],identifi:[1,5,9,16,19,23,26],idl:[21,25,27],ids1:9,ids2:9,idx:9,iff:9,ignor:[1,2,5,9,15,23],igor:3,igov:3,ii:3,iii:3,ij:[1,2,15,17],ik:17,ilario:3,illumin:9,illustr:[15,16,18,20],imag:[1,2,3,5,8,9,18,19,21,27,29],image2:29,image_box:[1,9,27],imbal:18,immedi:[9,15,28],immers:[3,18,23],immersed_boundari:[0,18],immobil:5,immut:7,impact:[5,9,14],imper:7,implement:[0,1,2,3,7,8,9,14,15,16,17,18,19,21,23,24,25,26,28],impli:15,implic:[15,20,23],implicit:[3,9,14,20],implicitli:[0,20],impos:[9,23],imposs:[15,19],improv:[3,8,9,24,25,29],imsav:29,imshow:1,inaccuraci:16,inact:9,incid:0,includ:[0,1,2,3,5,7,9,14,15,18,19,21,23,26],include_lbfluid:9,include_particl:9,inclus:[9,20],incompat:14,incomplet:19,incompress:9,inconsist:[0,14],increas:[0,1,2,3,5,8,19,27,28],increasetemp:29,increment:[9,15,19,25,27,29],ind1:[9,16],ind2:[9,16],ind3:[9,16],ind4:[9,16],indent:9,independ:[0,7,9,16,18,19,20,23,24],index:[1,2,9,12,13,23,24,29],indic:[0,9,11,12,16,18,19,20,24],individu:[0,1,4,7,9,14,15,18,20,23,29],induc:[0,3,8,9,17,18,23],induct:[8,9],inert:0,inerti:9,inertia:[9,14,15,23],inertia_tensor:9,inertialess:0,inevit:18,inf:15,infer:5,inferior:25,infin:9,infinit:[0,2,5,9,15,24],influenc:[1,8,20],info:[0,9],inform:[0,1,2,5,6,7,9,10,11,14,15,16,17,19,20,23,25,28,29],infti:9,ingredi:0,inherit:[23,27],inhomogen:[1,8,9],initi:[0,5,8,9,10,16,18,19,20,23,24,26,29],initial_pos_offset:[9,27],inner:[0,16,27],input:[0,7,9,13,14,15,17,18,23,24,29],input_arrai:9,insert:[1,9,18,27],insid:[0,5,7,8,9,14,16,26,28],inspect:[0,19],inspir:16,instabl:24,instal:[4,6,8,9,13,19,25,29],instanc:[0,1,8,9,15,16,18,19,20,21,23,24,26],instantan:[1,7,9,15],instanti:[1,5,8,9,16,23,29],instantli:9,instead:[0,1,2,7,8,9,14,15,18,19,23,25,26,27,28],instruct:[4,9,14,18,27,28],instrument:14,int_flag:9,int_step:9,int_v:24,integ:[0,9,16,20,23,24,25],integr:[1,3,5,6,8,13,14,18,19,20,22,23,24,25,26,27,28,29],integration_step:9,integratorhandl:[9,15],intel:14,intend:[0,9,16,19,21],intens:9,inter:1,interact:[1,2,3,5,7,8,12,13,15,18,19,20,22,24,26,27,28,29],interaction_rang:9,interchang:23,interdisciplinari:3,interest:[1,14,18,19,23],interfac:[1,3,7,9,12,14,15,17,20,25,27],interior:9,intermolecular:17,intern:[0,3,7,8,9,15,16,17,18,20,23,25,27,29],interpol:[7,9,15,16,17],interpolation_ord:9,interpret:[1,2,5,14,15,18,25],interrupt:[1,19,25],intersect:[0,20],interv:[1,9,15,29],intra:17,intramolecular:9,introduc:[0,8,15,17,18,19,20,25],introduct:[7,13,25],intuit:1,invalid:[14,24],invari:[3,5],invers:[0,8,9,16,24],investig:17,invoc:14,invok:[5,14,15,19,25,27],involv:[9,15,16,17,19,20,24],inward:[5,9],io:[9,14,22,25],ion:[7,9,14,17,18,20,24],ionic:[0,3,17,18],ioniz:24,ipynb:25,ipypresso:[14,18,25],ipython:[14,25],ira:3,irrevers:0,is_act:9,is_valid:9,is_valid_typ:9,isbn:3,isn:[0,9],isobar:24,isol:14,isotherm:24,isotrop:[1,9,14,18,23,26],issu:[4,8,14,15,19,23,24,28],item:[9,16,23],iter:[0,3,5,8,9,15,18,24],itiner:26,itolsq:21,its:[0,1,2,5,8,9,14,15,16,17,18,20,23,24,25,26,28],itself:[0,9,19,25,28],itterpotential:3,ivan:0,iveta:0,iy:2,j:[1,2,3,7,9,14,15,17,18,23],jame:3,jan:3,jancigova:0,jen:3,jiri:3,jl:17,joanni:3,job:14,john:3,johnson:[3,24],join:0,jona:3,jone:[9,14,15,16,18],joost:3,jorg:3,joss:3,journal:3,juan:3,jump:[8,9,19],jupyt:[6,25],jupyter_contrib_nbextens:14,jupyterlab:[14,25],just:[0,1,2,5,8,9,15,18,23,25,29],k0:9,k1:[9,16],k2:[9,16],k:[0,1,2,3,7,8,9,16,17,18,19,23,24],k_0:[2,16],k_1:[2,16,17],k_2:17,k_:[0,7,15,16,24],k_b:[0,8,15,16,17,18,24],k_bt:15,k_c:24,k_diss:24,k_n:2,k_p:24,k_v:[0,16],ka_g:[9,16],kag:0,kai:3,kal:[0,9,16],kantorovich:3,kappa:[8,9,16],kappav:[9,16],karl:3,kb:[0,9,16],kbyte:28,keep:[9,14,15,16,18,19,20,23,24,25,27],kei:[0,9,12,14,18,19,20,25,29],keith:3,kept:[0,15,17,18,28],keq:24,kernel:[8,9,18,25],kesselheim:[3,8],keyboard:[9,18,25,29],keyboard_down:9,keyboard_manag:[9,29],keyboard_up:9,keyboardbuttonev:[9,29],keyboardfireev:[9,29],keyboardmanag:9,keymap:14,keyword:[0,1,9,15,23,24,29],kill:9,kill_mot:0,kill_particle_forc:[9,26],kill_particle_mot:[9,26],kilomet:18,kind:[0,1],kindli:18,kinemat:[9,20],kinet:[1,9,14,20],kj:[17,18],kl:17,klass:9,klm:2,know:[0,8,9,15,18,21,23,27,28],knowledg:[6,8,28],known:[7,8,9,14,20,25],ko:3,kolafa:[3,8,21],kolb:[3,15],konrad:3,koo:3,kr:[0,3,9,16],kremer:3,ks:[0,9,16],kslin:[0,9,16],kt:[9,15,20,23,24,27,29],kubo:1,kundu:[3,9],kuron:3,kurt:3,kusumaatmaja:3,kuzmin:3,kv:[0,9,16],kvisc:[0,9,16],kwarg:[9,10,11,12,17,29],l1:28,l2:28,l3cach:14,l:[0,1,2,3,8,9,15,16],l_:[7,16,27],l_b:[8,9],l_z:[8,9],lab:[9,14,25],label:[1,7,16,17,24,25],laboratori:9,lack:15,ladd:[3,15,20],lag:[1,3,9],lag_tim:9,lagrang:[16,23],lah:14,lalith:3,lam:9,lambda:[0,9,17,23],lambda_:[2,16],lambda_i:2,lambda_x:2,lambda_z:2,lammp:[1,19],lanc:3,landsgesel:[3,24],langevin:[0,9,14,16,18],langl:[1,24],languag:18,lapack:14,larg:[1,2,3,9,14,15,16,17,19,21,24,26,27,29],larger:[0,1,9,15,18,21,23,27,28],largest:[0,2,9,15,21,23],laser:9,last:[1,9,14,18,19,24],last_iter:9,latenc:[25,28],later:[0,1,3,9,14,15,18,19,20],latest:[1,6,14,18,25],latter:[0,7,9,23],lattic:[0,1,3,5,7,9,13,18,19,26,29],lattice_boltzmann:18,law:[9,17],layer:[2,3,7,9,18,28],lb:[0,1,5,7,14,15,16,18,19,22,23,25],lb_arrow_color:9,lb_arrow_materi:9,lb_boundari:[0,14,20],lb_boundaries_gpu:[14,20],lb_densiti:7,lb_draw_boundari:9,lb_draw_nod:9,lb_draw_node_boundari:9,lb_draw_velocity_plan:9,lb_electrohydrodynam:[9,14,20],lb_fluid:[9,15,20],lb_plane_axi:9,lb_plane_dist:9,lb_plane_ngrid:9,lb_profil:18,lb_vel_radius_scal:9,lb_vel_scal:9,lbb:20,lbboundari:[0,7,20,22],lbf:[0,15,18,20],lbfluid:[0,9,15,20],lbfluidgpu:[9,15,20],lbfluidpressuretensor:9,lbfluidroutin:9,lbm:[15,20],lbslice:9,lbvelocityprofil:[1,9],lc:2,ld:9,ld_library_path:25,ldot:2,le_protocol:27,lead:[0,1,2,5,7,8,9,14,16,23,24,25,26,27],leak:25,lean:18,learn:14,least:[0,1,7,9,14,15,19,20,25,27,28],leav:[2,18,20,21,27],lebc:27,lectur:[3,4],lee:[3,9,15,18,19,20],lees_edward:[22,27],lees_edwards_flag:9,lees_edwards_offset:9,leesedward:9,left:[0,1,2,5,7,8,9,15,16,17,21,24,25,27,29],leftrightarrow:18,legal:19,lekner:2,len:[9,19,23,27],length:[0,1,2,5,7,8,9,10,12,14,16,17,18,19,20,21,23,26,27],length_unit:12,lennard:[9,14,15,16,18],lennard_jon:[9,14,17,18,19],lennard_jones_co:[9,17],lennard_jones_cos2:[9,17],lennard_jones_gener:[14,17],lennardjonescos2interact:[9,17],lennardjonescosinteract:[9,17],lennardjonesinteract:[9,17,18],lenz:3,leq:1,less:[0,2,5,9,14,15,17,19,23],let:[1,2,16,27,28],letter:3,level:[0,1,6,7,9,14,18,23,28],leverag:25,lewerenz:3,lfloor:27,lib:[10,14],libboost:14,libfftw3:14,libgl:29,libgle3:29,libgsl:14,libhdf5:[14,19],librari:[5,8,9,14,21,25,29],light:[1,3,9],light_bright:9,light_color:9,light_po:9,light_siz:9,like:[0,2,5,7,9,14,15,16,18,19,21,23,24,25,27,29],likewis:[19,25],likhtman:3,lim_:2,limbach06a:18,limbach:[3,18],limit:[0,2,8,9,15,18,19,20,23,24,25,26,27],limits_:[2,9],lin:16,linalg:[0,15],lindsai:3,line:[0,7,8,14,18,19,20,25],linear:[0,1,2,3,5,8,9,16,17,18,20,28],linear_momentum:[1,9],linear_polymer_posit:[9,23],linearelectricpotenti:[5,9],linearli:[9,17,20,25],linearshear:[9,27],link:[2,7,14,19,20,28],linkcent:7,linspac:16,linux:25,liquid:[0,3,9,17,18],list:[0,1,4,5,6,7,8,9,12,14,15,17,18,19,20,21,23,24,27,28,29],list_devic:[9,25],list_devices_properti:[9,25],list_of_types_to_fix:26,literatur:[0,1,17,20],littl:[2,28],live:[9,18,23,29],lj:[9,17,18,27],lj_liquid:18,lj_liquid_distribut:18,lj_liquid_structurefactor:18,ljco:[14,17],ljcos2:[14,17],ljgen_softcor:[9,14,17],ll:[9,25],lldb:25,ln:[16,24],load:[9,18,19,20,25,27],load_checkpoint:[9,18,19,20],load_new:19,local:[0,1,9,14,15,25],local_int:16,locat:[0,1,2,5,7,9,14,20,25,28],log:[1,2,9],log_flag:9,logarithm:[2,9],logic:[14,25],logical_not:15,logo:18,london:3,longer:[0,1,9,15,16,19,21,23,24,27],longest:[1,9],longest_dist:9,look:[0,2,9,14,15,18,19,20],lookup:[0,17],lookup_t:0,loop:[0,2,9,15,18,23,26,27,28,29],lorentz:24,loss:[1,14,20,25],lost:9,lot:[8,28],low:[0,9,14,15,20,28],lower:[1,2,5,9,14],lower_smoothing_radiu:[5,9],lowest:2,lt:14,lto:14,lub:9,lubric:15,ly:16,lyuba:3,lyutyi:3,m:[0,1,2,3,9,14,15,18,27],m_:1,m_i:[9,15],m_z:2,mach:[9,20],machin:[9,11,19,20,25],macport:14,macroscop:20,made:[0,8,18,23],magatti:[1,3],magnet:[1,7,9,18,21],magneticdipolemo:[1,9],magnetostat:[13,14,19,22,23],magnetostaticinteract:9,magnitud:[0,1,7,9,14,15,16,20,26],magnu:3,mai:[1,4,5,7,9,14,15,16,18,19,23,25,26,27,29],mail:[4,6,27],main:[10,14,15,19,25,28],main_thread:29,mainli:[8,14,17,21],maintain:[0,7,8,15,16,18,19],mainz:3,major:[2,6,7,9,15,18,23,25,28],make:[0,1,2,5,6,8,9,14,15,16,18,19,21,23,25,27],make_backward_react:9,make_reaction_attempt:24,malform:19,man:15,manag:[4,9,14,25,29],mandatori:[0,9,23],mani:[0,1,3,9,14,17,18,19,23,25,27],manipul:[1,13,23,25,27],mann:3,manner:1,mantel:9,manual:[0,1,8,9,14,19,21,23,27],map:[0,9,12,15,19,23,24],marc:3,marcello:3,marcia:3,markdown:25,marker:[0,14,16],market:25,marku:3,martin:3,masao:3,mask:15,mass:[0,7,9,12,14,15,16,18,19,20,21,23],mass_drud:9,mass_unit:12,match:[0,7,9,15,20,23,24],materi:[4,9,21],math:[1,14,22],mathbf:[0,1,17,23],mathcal:[7,9,15],mathemat:[1,3,9,15,16,23,25],mathijssen:3,mathr:[17,18],mathrm:[1,7,8,9,15,16,17,18,21,24,26,27],matplotlib:[1,14,18,29],matric:18,matrix:[9,14,15],matrix_to_quat:9,matter:[3,14,15,18],mattson:3,max:[0,1,3,9,15,16,17,26],max_cut_bond:[9,27],max_cut_nonbond:[9,27],max_displac:[9,15],max_forc:15,max_i:[1,9],max_iter:[8,9],max_oif_object:9,max_phi:[1,9],max_r:[1,9],max_sigma:15,max_skin:9,max_torqu:15,max_tri:[9,23],max_x:[1,9],max_z:[1,9],maxdist:[9,16],maxim:[0,2,8,9,14,15,16,17,27,28],maximum:[8,9,16,17,19,26,27],maxpwerror:[8,9,21],maxwel:[9,18],maxwperror:9,mayavi2:[7,20],mayavi:[7,20],mc:[18,24],mca:14,mccammom:15,mccammon:[3,15],md:[1,7,9,15,18,19,23,24,27,28],mda:[10,19],mda_esp:[9,19,22],mdanalysi:[10,14,18],mdanalysisintegr:[18,19],mdlc:21,mean:[0,2,5,7,8,9,14,15,16,17,18,20,21,23,24,25,27],meaning:[9,14,18],meaningless:9,meant:[18,29],meanvariancecalcul:[1,9],measur:[0,1,3,5,8,9,18,24],mechan:[1,3,9,15,16,23],medium:[7,9],meet:[6,9,18,25],mehmet:3,melt:[1,14],member:[15,16,17,23],membran:[0,16],memcheck:25,memori:[14,15,23,25,27,28],menk:3,mention:[1,7,16,18,19],menu:[0,25],mersenn:[9,24],mesh:[0,3,8,9,15,16,21],mesh_off:9,meshfre:3,meshnod:0,messag:[0,4,9,18,25],met:[9,23],meta:5,metadata:[12,19],metal:[8,9,21],meth:11,method:[1,2,3,5,7,9,12,13,14,15,17,19,20,21,23,25,27,28,29],method_nam:[8,9,21],method_param:[8,9,21],metric:0,meyer:[14,17],mhz:28,michael:3,microfluid:[0,3],micromet:[0,18],microscal:7,microsecond:0,mid:0,middl:[8,20,29],midpoint:[1,9,20],midwai:20,might:[0,1,6,8,11,14,18,19,20,25],mileston:18,million:25,millisecond:[8,29],mimic:[0,3,8,15,16,17],mimick:18,min:[0,1,9,15,16,17,24],min_dist:[1,5,9,15,23],min_global_cut:[0,9,23,27],min_i:[1,9],min_phi:[1,9],min_r:[1,9],min_sigma:15,min_skin:9,min_x:[1,9],min_z:[1,9],mind:[0,14,15,18,19,24,25],minim:[0,8,9,10,15,16,17,18,27,28,29],minima:[7,9,16],minimum:[0,5,9,14,15,17,18,21,23,25,27],minor:[9,18],minu:9,minut:0,mirror:0,miscellan:18,miss:[0,9,17,19,25,28],misshap:5,missing_featur:9,mistak:6,mix:[9,17],mkdir:14,mmm1d:[3,9,14,18,19,27],mmm1d_gpu:[8,14],mmm1d_machine_prec:14,mmm1dgpu:[8,9,19],mmm2d:3,mmm:[8,18],mobil:[7,9,15,20],mode:[0,9,14,15,19,20,23],model:[3,7,9,14,15,16,17,18,20,23,24,26,27,28],moder:7,modern:[3,18,28],modif:[2,3],modifi:[0,1,3,7,9,14,18,19,20,25,27],modul:[0,1,5,7,17,18,19,20,22,23,24,25,26,29],modular:18,moduli:[0,16],modulu:[0,9,16],mol:[17,18],mol_core_partial_charg:9,mol_core_typ:9,mol_drude_typ:9,mol_id:9,moldm:24,molecul:[0,1,9,14,15,17],molecular:[0,1,3,9,16,17,18,20,23],moment:[0,2,8,9,14,15,18,21,23],moment_of_inertia_matrix:[1,9],momentari:15,momentum:[0,9,15,17,20,26],monom:[9,23],monopolar:23,monospac:25,monoton:[1,7],monoval:7,mont:[9,18,19,24],month:18,monthli:18,more:[0,1,2,6,7,8,9,14,15,16,17,18,19,20,21,23,24,25,26,27,28,29],moreov:[2,7,19,27,28],mors:[9,14],morseinteract:[9,17],most:[0,1,5,6,7,8,14,15,18,19,25,26,27,28,29],mostli:0,motion:[3,7,9,14,15,18,23,26],motiv:[0,1,18,19],mous:[9,18,29],mouse_button_st:9,mouse_click:9,mouse_mov:9,mouse_po:9,mouse_pos_old:9,mousebuttonev:9,mouseev:9,mousefireev:9,mousemanag:9,move:[0,5,9,15,18,20,24,25,28,29],move_backward:9,move_down:9,move_forward:9,move_left:9,move_right:9,move_spe:9,move_up:9,mp4:29,mpc:[9,23],mpi:[5,9,11,14,18,21,23,27],mpi_abort:19,mpi_init:14,mpicallback:25,mpich:[14,19],mpiexec:[14,18,25],mpiexec_postflag:14,mpiexec_preflag:14,mpiio:[9,19,22],mpirun:14,ms:14,msg:9,mu:[9,17,20,21,24],mu_0:[9,21],mu_e:9,mu_i:24,much:[1,2,7,9,16,17,18,20,27,28],mult:[9,16],multi:[3,9],multipl:[2,5,8,9,14,16,18,20,24,25,27],multipli:[2,16,20,23],multipol:2,munn:3,must:[0,1,7,8,9,11,12,14,15,16,17,19,20,24,25,27],mutat:8,mutual:[9,18],my_shap:[5,7,20],my_var:19,mycheckpoint:19,myconfig:[0,15,21],myconfig_nam:14,myconstraint:5,mydata:19,myshap:5,n:[0,1,2,3,8,9,14,16,17,18,19,24,25,28,29],n_1:24,n_2:24,n_3:24,n_:[2,16,17,24],n_angle_bond:0,n_atom:[10,19],n_b:24,n_block:9,n_bonded_ia:9,n_i:24,n_icc:[8,9],n_k:7,n_node:[25,27],n_part:27,n_part_typ:9,n_phi_bin:[1,9],n_polym:[9,23],n_r_bin:[1,9],n_replica:9,n_rigidbond:9,n_square_typ:[9,27],n_x_bin:[1,9],n_y_bin:[1,9],n_z_bin:[1,9],na:17,nabla:[7,9],nacl:17,naiv:[0,1,2],namd:19,name:[0,2,7,9,14,15,16,18,19,23,25,29],namedstream:10,nano:18,nanomet:18,narrow:15,nativ:10,natur:[8,9,15,17,21,23,27],navier:7,nb:25,nbconvert:14,nbextens:[14,25],nbformat:14,nbhood:[1,9],ndarrai:9,nearest:[5,15,20,23],nearli:[0,27,28],necessari:[0,2,9,14,15,17,18,20,24,25,27],necessarili:[2,19],need:[0,1,2,5,6,8,9,10,14,15,16,17,18,20,23,24,25,27,28,29],neg:[0,5,7,9,14,18,19,24],neglect:7,neglig:1,neighbor:[0,1,5,9,15,16,23,28],neighborhood:9,neighbour:9,neither:[2,15,18],neo:[0,9,16],neohookean:[9,16],neq:[1,2,24],nest:[9,23],nesting_level:9,net:[9,17],network:18,neutral:[2,3,9],neutralize_system:9,never:0,nevertheless:28,new_attr:9,new_le_protocol:27,new_part:23,new_properti:9,newest:14,newli:[0,9,23,24],newton:[5,15,18],next:[0,2,5,6,7,9,14,15,18,19,23,25,26],neyertz:[3,9],nggi:3,nicc:8,nicc_per_electrod:8,nicc_tot:8,nihilo:24,nm:[10,12],no_bond:9,nobodi:18,node:[0,1,5,7,9,15,17,18,19,23,25,27,28],node_grid:[9,18,25,27],nodesfil:0,nois:[7,15,17],non:[0,1,2,3,5,7,8,9,13,14,15,16,18,19,20,21,23,24,26,27,29],non_bond:[1,9,18],non_bonded_int:[0,9,17,18,19],non_bonded_intra:9,non_bonded_loop_trac:9,nonbond:[1,9,17],nonbondedinteract:[5,9,17,18],nonbondedinteractionhandl:9,nonconserv:15,none:[0,9,10,11,14,18,20,23,27],nonequilibrium:[3,20],nonetheless:16,nongnu:19,nonlinear:[0,16],nonumb:7,nor:[0,2,15,18],norm:[0,15],normal:[0,1,5,8,9,14,16,17,20,27],normalize_and_check_bond_or_throw_except:9,notat:[0,1],note:[0,1,2,3,5,6,7,8,9,14,15,16,17,18,19,20,21,23,24,27],notebook:[14,18],noth:[9,15],notic:[5,6,15,16,27],notifi:25,notion:7,novel:3,now:[0,2,5,6,9,15,18,23,27],np:[0,1,9,15,16,19,23,25,29],nproc:25,npt:[9,14,18,24],nq_iq_j:2,nu:[9,17,24],nu_1:24,nu_:24,nu_a:24,nu_i:24,nu_k:7,nu_l:24,nu_m:24,nu_z:24,num:16,num_config:18,num_job:14,num_step:[18,19],num_triang:0,numa:[14,25],number:[0,1,2,3,7,8,9,11,14,15,16,17,18,19,20,21,24,25,27,28,29],number_of_chain:9,number_of_particl:[9,23],number_of_step:[15,20],numer:[0,3,9,14,15,16,17,18,20,29],numerica:3,numpi:[0,1,9,14,19,20,23,27,29],nvcc:14,nvidia:[20,25],nvt:9,nweg:[3,15,20],nxn:2,ny:3,o3:14,o:[0,1,2,3,9,24],o_n:23,o_v:23,ob:[1,9],obei:9,obj:9,object:[1,3,5,7,8,9,10,11,12,17,18,19,20,23,27,29],object_in_fluid:[9,18],objectlist:9,objectmap:9,oblat:17,obs1:[1,9],obs2:9,obs_bin:1,obs_data:1,observ:[0,7,15,18,19,22,23],observables_correl:[1,18],obstacl:[0,18],obtain:[0,1,2,5,6,7,8,9,14,17,18,19,23,24,26,27],obtained_kei:9,obviou:2,obvious:[0,7],occur:[0,1,2,7,9,15,19,25,27,28],octob:4,octre:9,odd:[9,27],off:[0,5,7,9,14,15,16,17,21,26,27],offer:[0,25,29],offici:[4,6,13,25],offlin:[23,29],offset:[0,2,9,11,17,18,20,26,27],often:[0,1,5,9,17,18,24,25,26,27],oif:[15,24],oif_empl:0,oif_neo_hookean_nonlin:0,oif_nod:0,oif_triangl:0,oifglobalforc:[9,16],oiflocalforc:[9,16],olaf:3,old:[0,18,20,23,24],older:[6,14,18],olenz:19,oltzmann:3,omega:[2,9,17],omega_bodi:[9,23],omega_lab:[9,23],omega_p:2,omega_q:2,omelyan:[3,23],ominu:24,omit:[1,2,9,15,21,23],ompi_mca_hwloc_base_binding_polici:14,onc:[0,9,14,15,18,20,23,25,27,28,29],one:[1,2,3,5,7,8,9,12,14,15,16,17,18,19,20,21,23,24,25,26,27,28],ones:[0,25],onli:[0,1,2,5,7,8,9,14,15,16,17,18,19,20,21,23,24,25,27,28],onlin:[1,4,14,18],only_posit:[5,9],ont:3,onto:[0,9,20,23,28],onward:18,oordin:19,op:9,opac:29,open:[0,3,4,5,9,14,15,18,19,25],opengl:[5,9,14,18,19,29],openmp:25,openmpi:[14,18,19,25],opensci:3,oper:[1,6,9,14,18,19,20,23,25,27,28,29],oppos:7,opposit:[7,15,16,20,24,26,27],opt:[14,18,19],optic:3,optim:[2,3,14,21,25,27,28],option:[0,1,6,7,8,9,11,12,15,16,17,19,20,23,24,25,26,27,29],optisch:3,orbit:23,order:[0,1,2,5,7,8,9,14,15,16,17,19,20,23,25,27,28],order_n:9,ordin:9,orest:3,org:[0,6,7,14,19,20],organ:[4,18,25,27],orient:[0,1,5,9,14,16,17,23,29],orific:5,origin:[0,1,2,5,9,16,17,25],ormat:19,orthogon:9,oscil:[9,16,17,18],oscillatori:9,oscillatoryshear:[9,27],oso:3,other:[0,1,2,4,5,6,7,8,9,15,16,17,18,19,20,23,24,25,26,27,28],otherwis:[2,5,8,9,11,15,17,19,23,24,25,27,28],otim:[1,17],oulomb:3,our:[0,5,6,7,18,28],out:[1,8,9,14,15,16,17,18,19,23,25,27],out_fil:0,outdat:1,outer:[0,9],outfil:0,outlin:[15,25],output:[0,1,8,9,11,13,18,25,27,29],output_mesh_point:0,output_mesh_triangl:0,output_raw_data:0,output_vtk_cylind:0,output_vtk_lin:0,output_vtk_po:0,output_vtk_pos_fold:0,output_vtk_rhomboid:0,outputmeshtriangl:0,outsid:[0,2,5,8,25,27,28],outward:[0,5,16],ovan:3,over:[0,1,2,9,14,15,16,18,20,21,24,25,27],overcharg:7,overestim:[7,17],overhead:[1,9,15,18,25],overlap:[3,9,15,17,18,24,26],overlin:[15,17],overload:18,overrid:14,overridden:9,override_cutoff_check:[9,23],overview:18,overwrit:[9,19,23],overwritten:9,owen:3,own:[0,9,15,16],oxford:3,p0:[0,9,16],p0x:0,p0y:0,p0z:0,p1:[0,1,9,15,16,23],p1x:0,p1y:0,p1z:0,p2:[0,1,9,15,16,23],p390:0,p391:0,p391x:0,p391y:0,p391z:0,p392:0,p392x:0,p392y:0,p392z:0,p3:[0,16],p3m:[0,1,2,3,7,9,14,17,18,23],p3mgpu:[8,9,19],p4:16,p5:0,p:[0,1,2,3,5,9,14,15,18,23,24,27],p_1:16,p_2:16,p_3:16,p_4:16,p_:[1,2],p_core:9,p_i:[1,2],p_id:9,p_j:2,p_type:[5,9],pacc:24,pace:18,packag:[0,3,4,6,18,19,22,25,29],pad:9,page:[0,3,9,13,14,18,28],pager:14,paid:4,pair:[0,1,2,8,9,15,16,17,18,21,24,27,29],pair_criteria:[1,22],pair_criterion:9,pair_mobl:9,pairwis:[2,8,9,16],panagiotopoulo:3,panda:19,paper:[8,9,17],parabol:9,paragraph:7,parallel:[1,3,5,8,9,14,15,17,18,19,21,23,27],parallelepip:[5,9],param:[9,12],paramet:[0,1,2,5,7,8,9,10,11,12,14,15,16,17,18,19,20,21,23,24,26,27,29],parametr:[0,17],paraview:[7,20],pars:[10,19],part1:18,part2:18,part:[0,1,2,5,8,9,10,15,16,17,18,19,20,21,23,24,25,27,28,29],part_al:9,part_id:[9,16],part_po:1,part_typ:[0,1],part_type_0_1:9,part_type_2:9,part_type_after_glu:[0,9],part_type_to_attach_vs_to:[0,9],part_type_to_be_glu:[0,9],part_type_v:[0,9],partial:[0,3,7,9],particl:[2,3,7,8,9,10,11,12,13,14,16,17,18,19,20,21,24,25,27],particle_anisotropi:[9,14,15],particle_attribut:9,particle_charge_color:9,particle_color:[9,29],particle_data:[0,14,22,23],particle_dict:9,particle_energi:9,particle_id:9,particle_insertion_potential_energy_sampl:[9,24],particle_number_to_be_chang:9,particle_s:9,particle_scal:9,particle_slic:9,particle_typ:[0,5,9],particle_type_1:24,particle_type_2:24,particle_type_color:[9,29],particle_type_materi:[9,29],particle_veloc:9,particleangularveloc:[1,9],particlebodyangularveloc:[1,9],particlebodyveloc:[1,9],particledist:[1,9],particleforc:[1,9,28],particlehandl:[0,9,14,18,23],particlelist:[9,18,23],particleposit:[1,9,28],particleproperti:28,particleslic:[9,23],particleveloc:[1,9],particular:[0,7,15,18,20,21],particularli:20,partit:[18,25,27],partner:[0,9,16,18,23],partpoint:0,parttyp:0,pass:[0,1,5,9,14,16,18,21,25,29],past:[4,15,18],patch:[14,18],patch_level:18,path:[0,1,7,9,12,14,19,20,25,29],patrick:3,paul:3,paus:29,pcolormesh:1,pdb:19,pdf:0,pedersen:3,penalti:[14,28],penetr:[5,9],penultim:1,peopl:[4,14,18],per:[0,1,5,9,11,14,15,20,21,23,24,27,28],perera:3,perform:[0,1,8,9,14,15,17,18,20,21,24,26],period:[0,1,2,3,5,8,9,15,16,18,19,21,26],periodic_imag:9,permiss:9,permit:[9,20],permitt:[9,21],perpendicular:[8,9,16,17,20,21],perram:[3,8,21],persist:1,person:18,peskin:[0,3],pf6:18,ph:[9,18],phantom:2,phase:[3,9,24],phd:3,phenomena:3,phi0:[0,9,16],phi:[0,1,2,7,9,16],phi_0:[0,9,16],phi_:2,philox:[9,15],photon:3,phy:18,physic:[0,2,3,9,12,15,18,19,20,23,25,28],physik:3,physrev:3,physrevlett:3,pi:[0,1,2,7,8,9,15,16,17,21],pick:14,pickl:[9,19],picosecond:18,pictur:5,pid:[9,19],piec:[3,6],pierr:3,pijush:3,pill:5,pint:[14,24],pip2:6,pip3:[6,14],pip:[6,14],pishevar:3,piston:[9,15],pixel:9,pk_0:2,place:[0,5,8,9,14,15,18,20,23,24,27],placement:0,plai:[7,18],plain:[8,27],plan:[0,6,15,18,20],planar:[3,5,8,18,20],plane:[1,2,5,8,9,14,16,18,20],plastic:9,plate:[8,9,18],plateau:5,platelet:3,platform:14,pleas:[0,1,4,5,6,8,9,14,15,16,18,19,20,21,23,24,25,27],plimpton:3,plot:[1,5,18,25,29],plt:1,plu:[1,23,27],plugin:[14,19,25],pm:[2,8,17],png:[9,29],po:[0,1,5,8,9,10,11,15,18,19,20,21,23,27,29],pobjectref:9,point:[1,2,3,5,8,9,14,15,16,17,18,19,20,21,25],point_data:0,pointer:[9,12,25,28],pointwis:0,poiseuil:18,poisson:7,polar:[1,9,18],polariz:[9,16,17],polici:[9,14,18],polyakov:[3,21],polyatom:3,polydata:0,polyelectrolyt:[3,24],polygamma:2,polym:[1,3,17,18,22,24,27],polymer_posit:23,pool:18,poor:[9,15],poorli:21,popul:[9,10,20],pore:[5,9],pore_constraint:5,pore_length:[5,9],pore_mouth:[5,9],pore_width:[5,9],port:14,portion:[0,28],pos_bound:0,pos_fold:[9,27],pos_ob:1,pos_offset:9,posa:9,posb:9,posit:[0,1,2,5,9,11,14,15,16,18,19,20,23,24,27,28],position_observ:1,possess:[0,20,23],possibl:[0,1,7,8,9,14,15,16,17,18,19,20,21,23,24,25,26,27,28,29],post:4,postul:15,pot:24,pot_diff:[8,9],potassium:7,potenti:[0,1,2,3,7,9,14,15,18,23,24,26],potentialfield:[5,9],power:[9,17],pprint:25,pq:2,practic:[5,20,25],pre:19,preced:[0,14],precis:[0,2,8,9,14,20,21],predefin:18,pref:[11,19],prefactor:[0,2,7,8,9,14,16,17,18,21],prefer:[16,19],prefix:[9,11,17,19],prepar:[14,19],preprocessor:14,prerequisit:1,prescrib:16,presenc:[9,19,23,29],present:[0,1,9,14,15,23,24,28],preserv:[0,1,15,16],press:[0,3,9,14,19,29],pressur:[3,5,9,15,18,20,23,24,28],pressure_tensor:[1,9,20],pressure_tensor_neq:[9,20],pressuretensor:[1,9],prevent:[0,5,9,14,15,18,24,25],previou:[5,9,14,15,19,23,25],previous:[0,5,9],previous_part:23,primari:2,primarili:0,primit:[9,27],princip:9,principl:[1,19,20],print:[0,1,5,7,9,10,12,14,15,17,18,19,20,23,25,27,29],print_info:0,print_sip:9,prior:0,privileg:14,probabl:[0,1,4,9,14,18,24],probe:5,problem:[3,4,6,14,15,18,19,20,26],problemat:[8,20],procedur:[1,8,16,28],proceed:[3,6],process:[0,1,3,6,7,11,14,15,19,24,25,29],processor:[1,2,14,18,27,28],prod_:24,prod_i:24,produc:[1,7,9,14,18,19,29],product:[0,1,2,5,7,9,14,16,18,24],product_coeffici:[9,24],product_typ:[9,24],profil:[1,14,18,22],profileobserv:9,profit:25,profound:14,program:[5,14,25],progress:[1,18],project:[6,7,14,19,20],prolat:17,prolong:0,promin:1,prompt:9,prone:18,prop_nam:9,propag:[0,7,18,23],propel:[9,18],proper:[0,7,9,18],properli:[1,7,8,9,14,15],properti:[0,1,3,5,7,8,9,10,14,15,16,17,18,19,24,25,28],proport:24,propos:19,propuls:[9,15,23],protein:19,protocol:[9,27],provid:[0,1,5,6,8,9,10,14,15,16,17,18,19,20,21,23,24,25],proxim:1,ps:[10,12,18],pscriptinterfac:9,pseudo:[2,23],psi:2,ptol:[9,16],publicli:18,publish:3,pull:[9,23],puller:[9,23],pure:[1,5,17,20],purpos:[0,1,9,14,17,21,29],push:[1,5,9,23],pusher:[9,23],put:[2,14,17,18,23,25,27],pv:15,py:[0,1,9,14,15,17,18,19,25,27,29],py_number_of_speci:9,pyopengl:[9,14,29],pyplot:[1,18,29],pypresso:[0,12,14,18,25],pyquaternion:9,pytabl:19,python2:6,python3:[6,14],python:[0,1,5,6,9,14,15,19,20,24,26,27,29],pythonpath:25,q1q2:[9,16,17],q:[1,2,8,9,15,17,18,23],q_1:[8,16,17],q_2:[8,16,17],q_:0,q_d:[0,17],q_i:[1,2,9],q_iq_j:2,q_j:[1,2],q_je:2,q_k:7,qe:29,quad:[2,8,24],quadrat:[9,20],quadrupl:16,qualiti:[9,20,29],quality_arrow:9,quality_bond:9,quality_constraint:9,quality_particl:9,quantiti:[1,29],quartic:9,quarticbond:[9,16],quasi:9,quat:[9,23],quaternion:[1,3,9,14,18,23],queri:[8,9,21],question:4,quick:23,quickli:[18,20],quit:[1,2,5,14,15,19],r0:[9,16],r1:9,r2:9,r:[0,1,2,3,6,8,9,14,15,16,17,18,19,21,24,26],r_0:[0,9,16,18,19],r_:[1,2,8,9,15,16,17,24],r_bin:[1,9],r_c:17,r_catch:[1,9],r_cut:[0,8,9,16,17],r_g:9,r_i:9,r_j:9,r_k:2,r_max:[1,9],r_min:[1,9],radial:[1,5,9],radian:[0,9,16],radii:[8,9,15,17,19,29],radiu:[0,1,5,8,9,15,16,17,18,20,24],radius_of_cylind:9,rais:[9,11,12,16,17,23,24,25,26],rajectori:19,ralph:3,ram:28,ramirez:[1,3,9],ramp:[15,17],random:[1,9,15,17,20,23,24,26,28,29],randomli:[9,15,18,23,24],rang:[0,1,2,3,8,9,14,15,17,18,19,20,21,23,24,25,27,28,29],rangl:1,rangle_:24,rank:[5,9,18,19,23,25,27],rapaport:[3,15],rapidli:17,rare:[9,20,25],raspberri:[18,23],raspberry_electrophoresi:18,raster:9,rasterize_points:9,rasterize_resolut:9,rate:[9,28],rather:[0,2,4,14,21,23,29],ratio:[9,17],rattl:[3,14,16,18,23],raw:1,rawdata:0,rawdatafil:0,rbc374node:0,rbc374triangl:0,rdf:[1,9],re:[0,2,6,9,15,18,19,23,25,27],reach:[2,9,15,20,23,25],react:3,reactant:[9,24],reactant_coeffici:[9,24],reactant_typ:[9,24],reaction:[0,3,9,13,18,19,25],reaction_ensemble_complex_react:18,reaction_id:[9,24],reaction_method:[18,22,23,24],reaction_step:9,reactionalgorithm:9,reactionensembl:[9,24],reactionfield:[8,9],reactiv:[3,24],read:[0,1,6,8,9,11,15,18,21,23,27,28],read_sign:9,readabl:[7,18,19,20],reader:[7,10,18],readi:18,readili:18,readthedoc:25,real:[0,3,8,9,18,23,27],realiz:[7,15],realli:[0,2,9],realtim:29,reason:[2,4,5,9,14,17,18,19],rebuild:[14,25],rec:1,recalc_forc:[9,15,23],recalcul:[0,9,15,19],recent:[14,19,25,27],recip:0,recommend:[0,4,8,9,14,18,19,23,27,29],recompil:25,recomput:[9,15],reconstruct:[9,18,19],record:[0,9,18],recov:[9,17,19,27],rectangular:0,recycl:[0,8],red:[0,3,18,29],redrawn:15,reduc:[1,9,15,17,18],reduct:[1,25],reed:[3,24],ref:[1,9],refer:[0,1,2,5,6,7,8,9,14,15,16,18,19,20,21,23,24,25,26,27],referenc:17,reflect:0,refshap:[9,16],regard:[0,16,18],regardless:9,region:[5,8,9,21],regist:[1,4,6,9,18,19,25,29],register_button:[9,29],register_callback:[9,29],register_sign:[9,19],registr:4,registri:9,regular:[8,9,23,25,28],regularli:15,reiniti:[19,27],reject:18,rel:[0,1,2,9,15,17,18,19,20,21,23,25,26,27],rel_offset:23,rel_to:9,relat:[0,1,7,9,16,17,18,23],relationship:9,relative_energy_chang:15,relative_energy_change_threshold:15,relax:[0,7,8,9,15,16,20,23],releas:[0,6,9,14],relev:[0,1,8,9,17,18,21,25],reli:[1,7,8,9,14,16,21,29],reload:0,relwithassert:14,remain:[0,1,2,9,18,21,24,25,26,27],remark:24,remedi:28,rememb:[4,16],remov:[0,5,6,8,9,14,15,16,18,19,21,23,24,25],remove_constraint:9,ren:3,render:[5,9,14,29],renown:18,repartit:9,repeat:23,repeatedli:0,repetit:9,replac:[0,1,2,5,9,14,19,20,24,25],replica:[2,8,9],report:[8,14,16,18,26],reposit:18,repositori:[6,9,13,14,18],repres:[0,1,2,5,8,9,15,16,18,20,23,24,28],represent:[1,2,9,23],reproduc:[18,19],repuls:[0,5,9,15,17,18,26],request:[0,8,9,23,25],requir:[0,1,2,7,8,9,12,15,16,17,19,20,21,23,24,25,27,28,29],required_kei:[9,12],rescal:[9,15],research:[0,3],resembl:16,reservoir:[18,24],reset:9,reshap:1,resid:[0,28],residu:9,resist:9,resiz:0,resolut:9,resolv:[0,3,4,14],resort:[9,14,19],resp:[1,5],respect:[0,1,2,5,7,9,15,16,18,19,20,21,23,26,27],respect_constraint:[9,23],respond:0,respons:[17,18,28],rest:[15,16,21,28],restart:[15,19,20],restor:[0,16],restrict:[7,9,14,15,17,19,20],result:[0,1,2,7,8,9,14,15,17,18,20,21,23,24,25,27,28],retain:8,retri:9,retriev:[9,23,28],reus:[9,15,20],reusabl:9,reuse_forc:[9,15,19,20],reva:3,revert_bind_at_point_of_collis:[0,9],review:3,revolut:9,rewritten:14,reynold:15,rf:[8,29],rfloor:27,rg:[3,9],rgb:[9,29],rgba:29,rho:2,rho_:[2,7],rho_l:2,rhomboid:[0,7,9],ri:14,rich:3,rig:16,right:[0,1,2,5,7,8,9,15,16,17,21,24,27,29],rightarrow:[2,9,17],rightleftharpoon:24,rigid:[0,3,9,14,18],rigid_bodi:18,rigidbond:[9,16],rigidli:0,rinertia:[9,23],risk:15,rl:2,rm:14,rmin:9,rng:[9,15],robust:1,rod:[5,15,18],rodrigu:9,roehm:[3,20],rohm12a:20,role:[7,24],roll:29,rom:3,root:[8,14,19,21],rotat:[0,1,5,14,15,21,22,26,29],rotate_camera:9,rotate_system:9,rotate_system_i:9,rotate_system_x:9,rotate_system_xl:9,rotate_system_xr:9,rotate_system_yl:9,rotate_system_yr:9,rotate_system_z:9,rotate_system_zl:9,rotate_system_zr:9,rotate_vector:9,rotation_help:9,rotational_inertia:[9,14],roughli:28,round:[5,9,19,20,27],routin:[3,18],row:[0,28],royal:3,rpath:14,rsp:[2,28],rspa:3,rt:24,rtx:25,rubber:[9,16],rubberband:14,rubinstein:[3,9],rudolf:3,rule:[1,16,24,27],run:[1,8,9,13,14,15,18,19,20,23,27,28],run_for_all_pair:[1,9],run_for_bonded_particl:[1,9],runtim:[9,14,18,19,23,24,25,27],runtimeerror:9,ryzen:14,s0009:3,s0010:3,s002211208700171x:3,s0962492902000077:3,s10189:3,s:[0,2,3,5,7,9,10,12,14,15,16,17,18,19,20,21,23,25,26,28],s_1:24,s_:[2,16],s_i:[2,24],s_l:24,s_m:24,s_z:24,safe:[1,5,6,9,18,28],safer:8,sai:0,said:[2,19],sake:18,sal:3,salom:0,salt:[7,14,18,20,24],same:[0,1,2,5,7,8,9,11,12,14,15,17,18,19,20,23,24,25,27,28],sampl:[1,9,14,15,16,17,19,20,24,25,27,29],sample_s:9,sample_scalar:0,sampleimmersedboundari:18,sampling_:9,sampling_delta_i:9,sampling_delta_x:9,sampling_delta_z:9,sampling_dens:9,sampling_offset_i:9,sampling_offset_x:9,sampling_offset_z:9,samuel:3,san:3,sandeep:3,sanit:14,saniti:9,sathish:3,satisfi:[9,14,15,16,23],satur:25,savannah:18,save:[0,9,10,19,20,23,29],save_checkpoint:[9,18,19,20],scafaco:[9,14],scafacos_dipol:[14,21],scalabl:[8,21],scalar:[1,7,9,15,20,23],scalar_product:[1,9],scalars1:0,scalars2:0,scale:[0,1,2,3,7,8,9,14,15,16,17,18,19,27,29],scaling_coeff:17,scatter:[1,3,25],scenario:[0,14],scf:0,sch:[1,3],schemat:[1,5,16],scheme:[0,9,14,15,18,20,23,25,27,28],schlick:[3,15],schmidt:17,schrefl:3,schulten:3,schweitzer:3,scienc:[3,9],scientif:[3,14],scipi:[9,14,18],scm:14,scoop:18,scope:1,screen:[2,8,9,20],screenshot:9,screenshot_:29,script:[1,9,12,14,17,19,20,24],script_interfac:[11,12,22],script_interface_regist:9,script_path:12,scriptinterfac:9,scriptinterfacehelp:[9,11,12],scriptnam:29,scriptobjectlist:9,scriptobjectmap:9,scrollbar:25,sd:[9,15],sdk:14,sdm:15,sean:3,search:[0,4,9,13,25],search_algorithm:9,sebastian:3,second:[0,1,8,9,15,17,18,20,25,28],section:[0,1,4,5,6,8,9,14,15,16,17,18,20,23,25,26,27],sed:14,sediment:18,see:[0,1,2,5,6,7,8,9,11,12,14,15,16,17,18,19,20,23,24,25,27,29],seed:[9,15,16,20,23,24,29],seem:[1,17,19],seen:[2,20],sega:[3,18],segid:19,segment:[0,5,9,14,16,25],select:[0,9,14,17,20,23,27],select_atom:19,self:[0,2,9,15,18],self_mobl:9,semi:24,semiax:[5,9],semiaxi:[5,9],semicolon:14,send:[2,4,19,25],sens:[1,2,5,18],sensibl:9,sensit:25,sent:19,separ:[0,1,2,9,14,15,17,19,28,29],sequenc:[9,15,19],sequenti:19,serau:25,seri:[2,9,14],serial:[19,24,25],seriou:24,serv:[0,7,17,18],session:[12,25],set:[0,1,5,7,8,9,10,12,13,15,16,17,18,19,21,24,25,26,28],set_boundary_condit:[9,27],set_brownian:[9,15],set_brownian_dynam:[9,15],set_cylindrical_constraint_in_z_direct:9,set_default_param:9,set_dens:9,set_dpd:[9,15,17],set_forc:0,set_hybrid_decomposit:[9,27],set_interpolation_ord:[9,20],set_isotropic_npt:[9,15],set_langevin:[9,15,29],set_lb:[9,15,20,23],set_mesh_point:0,set_n_squar:[9,27],set_near_field_deleg:9,set_non_interacting_typ:[9,24],set_npt:[9,15],set_nvt:9,set_origin:0,set_param:[0,9,17,18,19],set_regular_decomposit:[9,27],set_slice_one_for_al:9,set_slice_one_for_each:9,set_solid_materi:9,set_steepest_desc:[9,15],set_stokesian:[9,15],set_stokesian_dynam:[9,15],set_valu:9,set_veloc:0,set_volum:9,set_vv:[9,15],set_wall_constraints_in_z_direct:9,settabl:12,setter:15,setup:[0,8,9,10,15,16,18,19,23,25,27,29],setup_and_add_drude_exclusion_bond:[0,9],setup_diamond_polym:[9,23],setup_intramol_exclusion_bond:[0,9],setup_type_map:[9,23,24],sever:[0,4,6,8,9,11,14,15,17,18,19,20,21,23,25,27,28,29],sextupl:0,sf_order:[1,9],sf_type:[1,9],sh:14,shake:[3,16,23],shape:[0,1,7,8,16,18,19,22,27,29],shape_constraint:5,shape_i:9,shape_x:9,shape_z:9,shapebasedconstraint:[5,9],shardt:3,share:[0,8,9,14,16,19,21,25],she:18,shear:[0,3,9,20,27],shear_direct:[9,27],shear_plane_norm:[9,27],shear_veloc:[9,27],sheet:2,shell:[0,1,9,25,28],shendruk:3,shift:[0,1,9,17,18,19,25,27],shini:29,shirani:3,shortcut:25,shortest:8,shortrang:0,should:[0,1,2,5,6,7,8,9,11,12,14,15,16,17,18,19,20,23,25,27,29],show:[0,1,2,5,7,8,9,14,18,19,25,29],shown:[0,1,2,6,14,16,18],shrink:16,side:[0,2,5,8,9,17,18,24,27],sideward:29,sig:9,sigabrt:19,sigint:19,sigma:[8,9,15,17,18,19,24],sigma_0:17,sigma_:17,sigma_j:2,sigma_p:15,sigma_v:15,sign:[0,1,2,5,9,23,24],signal:[9,19,28],signatur:19,signific:[1,8],significantli:[0,14,15,21,24,25],signum:9,silent:[11,18],silva:3,sim1:0,sim_tim:19,similar:[2,5,7,9,14,15,16,17,24,25],similarli:[0,2,5,15,16,17,23],simpl:[0,2,5,9,15,17,18,19,25,26,27,28],simplepor:[9,29],simpli:[0,2,7,14,18,19,25,26,29],simplifi:[1,8],simul:[1,2,3,4,5,7,8,9,13,14,15,16,17,21,23,24,26,28,29],simultan:[0,2,20,21,24,28],sin:[2,9],sinc:[0,1,2,5,7,9,14,15,17,18,19,20,23,24,25,26,27,28],sine:2,singapor:3,singl:[0,1,2,3,7,8,9,10,13,14,16,17,18,19,21,23,25,27,28],singleframereaderbas:10,singlereact:9,singleton:14,singular:[2,7,16,17,26],sip:9,site:[0,3,9,14,15,18,27],situat:[7,9,25,27],six:[0,5],sixth:9,size:[0,1,2,8,9,15,18,19,20,21,23,24,26,27,28,29],sk:[0,16],skalak:[9,16],skin:[0,1,7,9,10,15,18,19,20,27,28,29],skip:[0,19],slab:[2,3,8,9,18,21],slab_end_z:9,slab_start_z:9,slater:3,slice1:23,slice2:23,slice:[0,1,2,5,9,18,20,23,24],slice_input:18,slide:0,slightli:[0,14],slip:[9,20],slitpor:9,slow:[0,8,14,21,23],slower:[0,14],slowli:17,small:[0,1,2,8,9,15,21,27,28],smaller:[0,2,16,17,27],smallest:[5,9,15],smiatek:3,smit:[1,3,18],smith:[2,3,24],smoluchowski:7,smooth:[2,3,5,7,9,14,16],smooth_step:[9,14,17],smoothing_radiu:[5,9],smoothli:[9,17],smoothstepinteract:[9,17],snake:18,snapshot:[1,29],snippet:[15,18,23,29],so:[0,1,2,5,8,9,14,15,17,18,20,23,24,26,27,29],societi:3,soddemann:[3,15,17],sodium:7,sofia:3,soft:[3,9,14,16,18,23],soft_a:0,soft_cut:0,soft_n:0,soft_offset:0,soft_spher:[0,9,14,17],softcor:17,softer:17,softid:[9,16],softsphereinteract:[9,17],softwar:[0,3,6,7,14,19,20],sole:16,solid:[3,18],solut:[0,1,3,4,6,7,18,24,25,27],solv:[7,8,15,21,27],solvent:[15,20],solver:[0,8,9,16,17,18,21],some:[0,1,2,3,5,6,8,9,14,15,16,18,19,20,23,24,25,27,28,29],someon:6,sometim:[0,1,9,19],somevalu:9,somewhat:[2,20],soon:[4,15,23],sor:9,sort:[1,9,19],sound:[5,9],sourc:[1,2,3,6,9,10,11,12,14,18,20,23,25],space:[0,1,3,5,8,9,15,23,27,29],spacial:9,span:[1,9,16],spatial:[0,1,8,15,17,21,27],spec:[9,18],speci:[9,17,19,24],special:[0,1,2,3,8,9,16,17,18,24,27],specieroutin:9,specif:[5,7,8,9,12,14,15,17,18,19,21,23,25,27],specifi:[0,1,5,7,8,9,12,14,15,16,17,18,19,20,21,23,26,27,29],spectra:7,spectroscopi:[1,3,9],specular:[9,29],speed:[0,8,9,14,20,23,25,27,28],speedup:1,sperb:3,sphere:[0,7,9,14,15,19,20],sphere_shap:20,spheric:[1,2,5,9,15,18,20],spherical_cav:9,spherical_constraint:9,spherocylind:9,sphinx:[6,14],sphinxcontrib:14,split:[0,1,2,17,25],spot:9,spotlight:9,spotlight_angl:9,spotlight_bright:9,spotlight_color:9,spotlight_en:9,spotlight_focu:9,spread:9,spring:[0,16],springer:3,spyder:25,sqrt:[0,2,7,9,15,17,18,23],squar:[1,2,8,9,14,18,21],square_distance_componentwis:[1,9],src:[14,25],srcdir:14,ssh:25,stabil:[18,24],stabl:[0,6,7],stage:0,stai:[0,27],stand:[0,2],standalon:19,standard:[1,2,9,14,17,24,25],star:9,start:[0,2,6,9,11,14,15,18,20,23,25,27,29],start_id:9,start_posit:9,state:[1,3,8,9,15,16,17,18,19,20,23,24,25],statist:[1,3,9,18,24],statu:[9,18],std:[14,18],std_error:9,steadi:20,steel:[9,29],steepest:[8,9,26],steepestdesc:9,steer:18,stefan:3,stem:[18,23],stencil:[7,9],step:[0,1,7,8,9,14,15,16,18,19,20,23,27,29],stephan:3,stiff:[0,9],still:[0,2,4,5,9,14,15,18,19,24],stimac:3,stl:18,stochast:3,stoichiometr:[9,24],stoke:7,stokesian:[9,14,18,27],stokesian_dynam:[9,14,15],stokesiandynam:9,stop:[0,5,9,25],storag:[1,28],store:[0,1,2,9,15,16,18,19,23,24,28,29],str:[0,9,11,12],straight:2,straightforward:[20,23],strain:0,strang:15,stream:[10,19],strebel:[2,3],strength:[9,17],stress:[3,9,27],stretch:[0,9,15,23],strict:14,strictli:[0,6],string:[0,9,12,14,17,19],strong:[0,7,14,23],strongli:[9,14,15,17,19],structur:[0,9,12,19,23,25,28],structure_factor:[1,9,18],studi:3,studio:25,stuttgart:4,style:18,subclass:18,subcommand:25,subdirectori:14,subdivis:9,subfold:14,subject:[5,15,18,20],submodul:[14,22],subpackag:22,subsect:[14,15,16,17],subsequ:[7,9,15,16,25,27],subset:[9,14,19,21,23],substitut:20,substructur:28,subsystem:14,subtr_p3m_sr:16,subtract:[0,9,18,26],successfulli:14,succi:[3,20],sudo:14,suffici:[0,2,18,20],suffix:[11,19],suggest:[0,4],suit:27,suitabl:[0,9,19,23,25,29],sukumaran:3,sum:[0,1,2,3,5,7,9,14,16,17,24,26],sum_:[1,2,9,15,16],sum_i:[9,15,24],sum_k:7,summand:[1,2],summari:[15,18],summat:[2,3,9,21,25],superior:[9,25],superpos:8,superscript:1,suppli:[0,9,20,23],support:[1,7,8,9,10,14,15,19,20,21,23,24,25,29],suppos:[1,14],sure:[0,1,5,8,9,14,15,18,19,21,23,24],surfac:[5,7,8,9,15,16],surround:[0,9,15,20],suspend:9,suspens:[3,18],swap:24,swim:[9,23],swimmer:9,sylvi:3,symbol:[14,25],symmetr:[8,9,16,20],symmetri:[1,2,5,9,23],symplect:[5,15],synchron:[20,29],syntax:[5,14,16,17],system:[2,3,6,7,8,10,12,13,14,15,16,17,18,19,20,21,22,23,25,28,29],system_cm:[9,26],system_cms_veloc:[9,26],system_info:9,systemat:[1,9,15],szuttor:[3,18],t1:9,t2:9,t:[0,1,2,3,4,5,7,8,9,14,15,16,17,18,19,20,24,25,29],t_:16,t_a:16,t_b:16,t_c:16,tab:14,tab_dist:16,tabl:[0,5,9,16,17,18,25],tabul:[9,14],tabulatedangl:[9,16],tabulateddihedr:[9,16],tabulateddist:[9,16],tabulatednonbond:[9,17],tackl:2,tail:[1,9,14,17],tailor:26,take:[0,1,8,9,14,15,16,17,18,20,23,24,25],taken:[0,1,7,9,19,20,23],tamar:3,target:[1,9,14,15,29],target_accuraci:21,target_vec:9,task:[14,18,25],tau:[0,3,9,15,20],tau_:1,tau_lin:[1,9],tau_max:[1,9],taylor:2,tcl:0,teach:[4,18],team:18,technic:[0,2,8,15,18,28],techniqu:3,tell:[0,14,15],temp_com:[9,16],temp_dist:[9,16],temper:15,temperatur:[0,7,9,14,15,16,17,18,24,26,27,29],templat:0,tempor:15,temporarili:[9,27],tend:16,tendenc:16,tensor:[3,9,15,20,23],tensor_product:9,term:[1,2,7,8,9,14,15,17,20,23],termin:[0,9,14,15,18,19,23,25],terminalipythonapp:25,test:[1,8,9,15,18,19,21,25],test_timeout:14,testsuit:14,tetra:23,teubner:3,text:[0,1,7,9,15,16,17,20,24,25],textbook:[18,25],textrm:[0,8,9],tf:19,tg:29,th:[1,2,9],than:[0,1,2,4,5,7,9,14,15,16,17,18,19,21,23,24,25,27,28],thank:18,thei:[0,1,4,5,7,8,9,12,14,15,16,17,18,19,20,23,25,27,28],them:[0,1,2,5,8,9,14,15,16,18,19,20,23,25,28],themselv:[14,18],theorem:[2,15],theoret:3,theori:[3,7,8],therebi:26,therecanonlybeon:9,therefor:[0,1,2,5,7,8,9,14,15,16,17,18,19,20,23,24,25,26,27,28],therein:9,thermal:[2,7,8,9,15,17,18,20,23],thermalized_bond:[0,9,16],thermalizedbond:[9,16],thermo_dpd:9,thermo_langevin:9,thermodynam:18,thermostat:[0,3,7,13,14,16,17,18,19,20,22,23,26,27,29],thermostat_per_particl:[0,9,14,15],thesi:3,theta:[9,16],thi:[0,1,2,4,5,6,7,8,9,10,11,12,14,15,16,17,18,19,20,21,23,24,25,26,27,28,29],thick:9,thin:0,thing:[0,2,14,20],think:0,third:[0,9,16],thole:[0,9,14],thole_damp:9,thoma:3,thompson:[1,3],thorough:18,those:[0,1,2,7,14,15,23,24],though:[0,15,27],thought:18,thousand:[0,21],thread:[9,21,29],three:[0,1,2,3,5,8,9,14,15,16,18,20,21,23,24,27],three_particle_binding_angle_resolut:[0,9],three_point:9,threeneigbor:0,threeneighbor:0,threshold:9,through:[0,2,5,7,16,18,20,23,25,28,29],throughout:[1,7,18,27],thrown:[8,21,23],thu:[0,1,5,9,14,17,18,19,20,25,27],thumb:[1,27],tick:28,tidi:14,tidynam:3,tild:[2,17],tildeslei:[3,23],time:[0,2,3,4,7,8,9,10,12,14,15,16,18,19,20,23,24,25,27,28,29],time_0:[9,27],time_seri:[1,9],time_step:[0,1,7,8,9,10,15,18,19,20,21,27,29],time_unit:12,timefram:19,timeout:[14,19],timer:29,times02:16,timeseri:[1,9],timestep:[9,10,12,19],timm:3,tini:3,tironi:[3,8],titrat:[3,18],tmp:19,to_char_point:9,to_dict:9,to_str:9,todai:25,togeth:[0,2,5,9,14,16,18,19],toggl:[5,8,14,29],toggleprompt:14,tol:[9,21],toler:[9,16],tolerance_field:[8,21],tom:3,too:[1,2,5,7,8,9,14,24,25],tool:[0,14,18,19,23],toolbar:0,toolbox:1,toolkit:14,toolsai:14,top:[2,5,6,8,9,10,14,18],topic:3,topmost:2,topolog:[1,9,10,16],topologyreaderbas:10,torqu:[9,15,21,23,26],torque_lab:[9,15,23],torsion:16,toru:9,tosi:[14,17],total:[0,1,2,5,8,9,15,17,18,23,27],total_forc:[5,9],total_memori:25,total_normal_forc:9,totalforc:[1,9],touch:[18,23],toward:[0,9,15,17],tqdm:14,trace:[0,9],tracer:0,track:[0,9,14,18,19,20,23,24],tracker:4,tradit:17,traj:19,trajectori:[9,10,12,15,18,19],trans_:17,trans_gamma:[9,17],trans_r_cut:[9,17],trans_weight_funct:[9,17],transfer:[0,9,15,23,25,28],transform:[1,2,9,14,17],transform_param:[1,9],transit:[18,24],translat:[1,3,9,15,19,29],translation:5,transloc:3,transmit:0,transpar:28,transparent1:9,transparent2:9,transparent3:9,transport:3,trap:9,treat:[2,3,8,9,15,18,20,24,27],treatment:[0,2,18,20],tree:18,tremend:27,tri1:16,tri:[0,8,9,24],trial:[9,23],triangl:[1,9,16],triangle_1:0,triangle_2:0,triangle_strip:0,trianglesfil:0,triangul:16,tribend:[9,16],trick:2,triel:9,trigger:[0,1,9,14,19,27,29],trilinear:9,tripl:[1,16],triplet:[0,16],triska:[3,24],trivial:[1,9,23],troubleshoot:25,trr:19,trrwriter:19,tructur:19,truncat:5,ts:19,tube:[5,9],tube_radiu:[5,9],tunabl:[0,14],tune:[0,1,5,9,17,18,19,20,21],tune_skin:9,tupl:[9,16,18,23,27],turn:[0,1,2,5,7,9,14,15,16,17,28],turn_off:[9,15,29],turner:[3,24],tutori:[0,4,6,14,25,29],tweak:0,twice:[14,15,16,18,25,27],twister:[9,24],two:[0,1,2,3,5,7,8,9,14,15,16,17,18,19,20,21,23,24,26,27,28,29],txt:[6,14],tyagi:[2,3,8,18],tyler:3,typ:11,type1:[9,17],type2:[9,17],type:[0,1,5,7,8,9,10,11,12,15,16,17,18,19,23,24,26,27,29],type_1:[17,24],type_2:[17,24],type_3:24,type_b:24,type_cm:9,type_drud:9,type_i:9,type_j:9,type_list:[9,24],type_list_a:[1,9],type_list_b:[1,9],type_mc:9,type_nam:9,type_nm:9,type_nod:9,type_numb:9,typic:[0,5,7,9,16,20,23,24,27,28,29],tzel:[1,3],u:[8,9,10,12,15,17,19,20,21],u_c:8,u_i:2,u_x:2,u_xx:2,u_z:2,ubiquit:1,ubsan:14,ubuntu:[19,29],ucx:14,ui:14,uk:3,ulrich:3,ultim:[0,17,24],un:9,unbias:0,unchang:[0,20,27],uncharg:23,unclear:9,uncom:14,uncorrel:[9,15],und:3,undefin:[14,15,17],under:[0,3,4,9,13,18,23,24,25,26,27],underli:10,understand:[3,18,23,28],undocu:6,uneduc:8,unexpect:[5,27],unexpectedli:19,unfavor:[26,27,28],unfold:[1,18,19,26,27],unfortun:[19,20],uniform:[0,9,15,17],uninstal:14,uninterest:2,union:9,uniqu:[0,4,17,18,19,23],unit:[0,3,5,8,9,10,12,14,15,16,17,19,20,23,25,27],unit_system:12,unit_test:25,unitcel:10,uniti:14,unitsystem:[12,19],univers:[0,1,3,4,10,18,19],universit:3,unix:6,uniza:[0,16],unkill_mot:0,unknown:0,unless:[9,15,18,20,25],unlik:[8,9,14,23],unnorm:9,unpack:14,unpatch:14,unphys:[8,15],unproblemat:2,unregist:9,unscreen:2,unset:27,unshift:17,unsort:19,unsupport:14,untherm:9,until:[8,9,15,17,23,25],untouch:18,unverifi:9,unwant:[0,5],unwrap:9,up:[0,1,2,3,5,6,7,8,9,10,13,15,16,17,18,19,24,25,28],up_vec:9,updat:[1,9,14,15,18,20,23,27,28,29],update_modelview:9,update_system_info:9,upgrad:6,upload:0,upon:[9,20],upper:[2,5,9],upper_smoothing_radiu:[5,9],upto:9,url:[14,18],us:[0,2,3,4,5,6,7,8,9,10,11,12,16,17,18,21,23,24,26,27,28,29],usa:3,usag:[0,1,8,9,15,18,19,21],use_verlet_list:[9,27],user:[0,1,4,5,7,8,9,14,16,17,18,19,20,21,23,25,29],user_interact:9,usernam:[14,18,25],usr:14,usual:[0,5,14,18,19,20,23,24,25,26],utf8:19,util:[10,14,18,22],v0:[9,16],v1:0,v2:0,v3:0,v:[0,1,3,7,9,15,16,17,19,20,24,27,29],v_0:0,v_:[1,9,17],v_i:[15,20],v_swim:[9,23],v_x:0,v_y:0,v_z:0,vacuum:21,val_cm:9,val_nod:9,valenc:[7,9],valgrind:[14,25],valid:[7,9,12,14,15,19,23,25,27],valid_field:[12,19],valid_kei:[9,12],validate_param:[9,12],valu:[0,1,5,7,8,9,12,14,15,16,17,18,19,20,23,24,25,26,27,29],valuabl:14,value1:0,value2:0,valueerror:[9,11],van:[3,17,18],vanish:[2,23],varepsilon:[17,21],varepsilon_0:[1,8,9,17],varepsilon_1:8,varepsilon_2:8,varepsilon_b:8,varepsilon_m:8,varepsilon_r:[1,8,9],varepsilon_t:8,vari:[0,17,18,19],variabl:[0,7,9,11,18,19,24],varianc:[9,15],variant:[2,14,17,20,21],varieti:[5,18],variou:[0,1,3,8,14,18,21,29],vb:16,vcf:[12,19],vd:15,ve:14,vec:[1,7,9,15,16,17,21,23],vector:[1,5,8,9,16,17,18,20,21,23,29],vector_field:0,vectordata:0,vectori:27,vel:[11,19],vel_ob:1,veloc:[0,1,3,7,9,10,11,14,16,17,18,19,23,27,29],velocity_arrow:[9,29],velocity_arrows_type_color:9,velocity_arrows_type_materi:9,velocity_arrows_type_radii:9,velocity_arrows_type_scal:9,velocity_differ:9,velocity_unit:12,velocityverlet:9,velocityverletisotropicnpt:9,venv:14,verbos:[0,9,17],veri:[0,1,2,6,7,8,15,17,21,23,25,26,27],verifi:[9,19],verlag:3,verlet:[0,9,18,23,27],verlet_reus:27,versa:[0,9,24],version:[0,3,6,7,8,14,17,19,21,22,23,25],versu:5,vertex:16,vertic:[5,9,16,25],vf:1,vi:3,via:[0,1,3,5,6,7,8,9,15,16,17,18,19,20,21,23,24,25,26,27,29],vice:[0,9,24],video:[25,29],view:[2,25],vieweg:3,viewer:9,viggen:3,vincent:3,violat:5,virial:1,virtual:[0,9,14,15,18,27,28],virtual_sit:[0,22,23],virtual_sites_rel:[0,1,9,14,18,23],virtualsitesinertialesstrac:[9,23],virtualsitesoff:[9,23],virtualsitesrel:[0,9,23],visc:[0,9,15,20],viscos:[0,7,9,15,20],viscou:[9,15],visit:27,visual:[3,5,7,13,14,16,18,19,22,25,27],visualis:0,visualization_:29,visualization_bond:18,visualization_cellsystem:[18,27],visualization_charg:18,visualization_constraint:18,visualization_elc:18,visualization_interact:[18,29],visualization_lbboundari:18,visualization_ljliquid:[18,29],visualization_npt:18,visualization_poiseuil:18,vital:15,vmd:[3,12,19],volcon:16,voltag:[8,9],volum:[0,1,3,5,7,9,15,18,23,24],volumetr:16,vorselaar:3,vphantom:7,vs:[14,25],vs_auto_rel:23,vs_auto_relate_to:[9,15,23],vs_placement:0,vs_quat:[9,23],vs_rel:[9,23],vscode:25,vsf:19,vst:12,vtf:[9,11,18],vtf_index:19,vtf_pid_map:12,vtfplugin:19,vtk:[7,9,18,20],vtkfile:0,vtol:16,vtop:9,vx:9,vy:9,vz:9,w:[3,7,9,17,19],w_:17,w_x:9,w_y:9,w_z:9,wa:[0,1,5,9,11,14,16,18,19,23,24,25,28],waal:[17,18],wai:[0,1,2,5,7,9,14,15,18,19,20,23,25,27,28],waist:9,wait:25,wald:3,walk:15,wall:[0,7,9,18,20],wall_shap:20,wallback:0,want:[0,1,5,9,14,15,16,18,20,23,24,25,27],warm:18,warmup:17,warn:[0,9,14,19,25],wasd:29,wast:18,wave:[1,9],wavevector:9,wayn:3,wca:[9,14,15,17,18],wcainteract:[9,17],we:[0,1,2,5,7,9,14,15,18,20,24,25,28],weak:[3,18,24],websit:[0,4,6,13],weeber:[3,18],week:14,weight:[3,9,17],weight_funct:[9,17],weik19a:18,weik:[3,18],welcom:6,well:[1,2,8,9,14,15,17,18,19,20,23,26,28],went:0,were:[0,1,9,14,16,18,19,20],what:[0,2,5,9,14,18,19,23,27],wheel:29,when:[1,2,5,7,8,9,14,15,16,17,18,19,20,21,23,24,25,27,28],whenev:[5,16,29],where:[0,1,2,5,7,8,9,12,14,15,16,17,18,19,20,21,23,24,25],wherea:[9,15],wherev:18,whether:[0,1,2,7,9,14,15,18,20,23,25],which:[0,1,2,4,5,6,7,8,9,10,12,14,15,16,17,18,19,20,21,23,24,25,26,27,28,29],white:7,who:[0,4,14],whole:[0,3,9,18,19,20,26],whose:[0,5,15,25],why:23,wide:[0,1,14],widom:[3,9,18],widom_insert:[9,18],widominsert:[9,24],width:9,wiener:15,wiesbaden:3,wiki:[6,13,14,18,19,25],wikipedia:9,wilfr:3,william:3,window:[0,9,25,29],window_s:[9,29],wirefram:[9,18],wise:[2,9,23,27],wish:[0,5],with_asan:14,with_benchmark:14,with_ccach:14,with_clang_tidi:14,with_coverag:14,with_coverage_python:14,with_cppcheck:14,with_cuda:14,with_cuda_compil:14,with_gsl:14,with_hdf5:14,with_msan:14,with_profil:14,with_python:14,with_scafaco:14,with_stokesian_dynam:14,with_test:14,with_ubsan:14,with_valgrind_instrument:14,within:[0,1,5,9,14,15,16,18,19,20,23,24,27,28],without:[0,1,9,10,15,16,18,19,23,25,26,28,29],wobbl:0,won:25,wonder:0,word:[5,15,23],work:[0,1,6,8,9,10,14,15,16,17,18,19,20,21,23,24,25,26],worker:25,workflow:25,workload:27,workshop:4,workstat:[14,25],world:3,worst:28,would:[0,1,5,8,9,15,18,19,23,25,28],wp:0,wrap:[9,26,27],writabl:9,write:[9,11,12,14,15,18,24,25,26,29],write_boundari:[9,20],write_next_timestep:19,write_veloc:[9,20],write_vtk_boundari:[7,9,20],write_vtk_dens:[7,9],write_vtk_flux:[7,9],write_vtk_flux_fluc:9,write_vtk_flux_link:9,write_vtk_lbforc:9,write_vtk_particle_potenti:9,write_vtk_potenti:[7,9],write_vtk_veloc:[7,9,20],writeabl:23,writer:[9,11,19],writevcf:12,writevsf:12,writevtk:[9,20],written:[0,9,12,14,18,19,24],wrong:[18,19],wrote:11,ws:29,www:[0,7,14,19,20],x5000:3,x:[0,1,2,5,9,14,15,18,20,23,24,25,26,27],x_1:9,x_2:9,x_:[0,2,9,15],x_i:[2,9,15,20],x_indic:9,x_j:[2,15],x_n:[9,23],x_v:23,xi:[2,8,24],xterm:25,xx:9,xy:[2,8,18],xyz:[9,26],y:[0,2,3,5,9,18,20,23,26,27,29],y_1:9,y_2:9,y_:[0,2],y_i:[2,9],y_indic:9,y_j:2,y_n:9,yaghoubi:[3,17],ye:18,year:[1,4],yet:15,yi:8,yield:[5,8,9,17,21,24],york:3,you:[0,1,4,5,6,8,9,14,15,16,17,18,19,20,21,23,24,25,26,27,29],your:[0,4,5,7,8,9,14,15,18,19,23,24,25,29],yourself:4,youtub:4,yu:3,z:[0,1,2,3,5,8,9,18,19,20,21,23,26,27],z_1:9,z_2:9,z_:[0,2],z_i:[2,9],z_indic:9,z_j:2,z_n:9,za:19,zc:29,zen:3,zero:[0,8,9,14,15,16,17,18,20,23,24,26,27],zeroth:19,zilina:0,zoom:29},titles:["18. Advanced methods","15. Analysis","23. Appendix","24. Bibliography","21. Community","12. Single particle forces (constraints)","22. Contributing","14. Electrokinetics","9. Electrostatics","espressomd package","espressomd.MDA_ESP package","espressomd.io package","espressomd.io.writer package","ESPResSo documentation","2. Installation","6. Integrators and thermostats","8. Bonded interactions","7. Non-bonded interactions","1. Introduction","16. Input and Output","13. Lattice-Boltzmann","10. Magnetostatics","espressomd","5. Setting up particles","19. Reaction methods","3. Running a simulation","11. System manipulation","4. Setting up the system","20. Under the hood","17. Online-visualization"],titleterms:{"class":[0,23],"function":1,"h\u00fcckel":8,"import":15,"short":[0,16],On:18,The:[2,25],acceler:[14,25],access:[23,27],accumul:[1,9],activ:14,actor:9,ad:[5,23],advanc:0,algorithm:[1,2,8,15],an:25,analysi:1,analyz:9,andersen:17,angl:16,anisotrop:17,anisotropi:23,apart:0,appendix:2,ar:0,area:16,arrang:23,automat:0,avail:[0,1,5,18,25],back:19,barn:21,base:5,basic:18,bend:16,bern:17,between:[1,18,19,20],bibliographi:3,binari:19,bmhtf:17,boltzmann:[15,20,23],bond:[0,16,17],bond_breakag:9,boundari:[0,7,16,20,27],box:[26,27],brownian:15,buckingham:17,build:[6,14],calcul:1,callback:25,cancel:0,canon:24,cap:26,ccmake:14,cell:27,cell_system:9,center:[1,26],chain:[1,23],chandler:17,chang:26,checkpoint:[9,19,20],choos:20,cite:18,cluster:1,cluster_analysi:9,cmake:14,code:[0,6,25],coeffici:1,cold:0,collid:0,collision_detect:9,color:[0,29],comfix:9,commun:[4,25],compat:18,compil:14,comput:25,condit:[20,27],configur:[14,23],connect:14,conserv:16,consider:24,consol:25,constant:[5,24],constraint:[5,9],content:[9,10,11,12],contrast:2,contribut:6,control:29,converg:15,convert:24,coordin:19,correct:[8,17,21],correl:1,cosin:[16,17],coulomb:[8,16],count:23,coupl:[20,24],cpu:20,creat:[0,1,23],criterion:15,cuda:25,cuda_init:9,current:5,custom:15,cylind:5,data:0,deactiv:14,debug:[14,25],deby:8,decomposit:27,defin:5,degre:23,delet:[0,5,23],depend:16,descent:15,descript:0,detail:1,develop:6,devic:25,diamond:23,dielectr:[2,8],diffus:[1,7],dihedr:16,dipolar:21,direct:[1,21],dissip:15,distanc:[1,5,16],distribut:[1,14],dlc:21,document:[13,14],dpd:[15,17],drag:29,drude:0,drude_help:9,dure:26,dynam:[14,15,24],edward:27,ek:7,ekboundari:9,elast:0,elc:[2,8],electrohydrodynam:20,electrokinet:[7,9],electrostat:[0,8,9],electrostatic_extens:9,ellipsoid:5,energi:1,ensembl:24,environ:14,equat:7,error:2,espresso:[13,18,19,24,25],espressomd:[9,10,11,12,22],exampl:[1,20,29],exclus:23,extern:[5,14],factor:1,famili:2,featur:[14,23],fene:16,field:[5,7,8],file:[0,19],fix:26,flag:14,fluid:[0,14,16,20],forc:[5,16,26],format:[0,19],forth:19,framework:[1,25],freedom:23,gai:17,gain:25,galilei:[9,26],gaussian:17,gener:[14,17,25,29],get:5,global:[16,27],go:19,gpu:[8,14,20,21,25],grand:24,group:23,guid:[6,13,18],gyrat:1,h5md:[12,19],harmon:16,hat:17,helper:0,hertzian:17,highland:9,hollowconicalfrustum:5,homebrew:14,homogen:24,hood:28,how:18,hpp:14,hut:21,hybrid:27,ibm:16,icc:8,id:25,immers:[0,16],implement:20,index:19,indic:13,inertia:1,inertialess:23,initi:7,input:19,insert:24,insid:25,instal:14,integr:[0,9,15],intend:18,interact:[0,9,14,16,17,21,23,25],interfac:[8,18],intern:[24,28],interpol:[5,20],intramolecular:0,introduct:[2,18],io:[11,12,19],isotrop:[15,17],iter:23,jone:17,jupyt:14,langevin:[15,23],lattic:[15,20,23],layer:[8,21],lb:[9,20],lbboundari:9,lee:27,lees_edward:9,lennard:17,linux:14,list:25,load:0,local:[7,16],maco:14,magnetostat:[9,21],manipul:26,mass:[1,26],materi:29,math:9,matrix:1,md:20,mda_esp:10,mdanalysi:19,mean:1,messag:14,method:[0,8,16,18,24],minim:[1,5,20],mmm1d:[2,8],mmm2d:2,mmm:2,model:[0,25],modifi:23,modul:[9,10,11,12,13,27],molecular:24,moment:1,momentum:1,mors:17,movement:0,mpi:[19,25],mpiio:11,multipl:[0,1],myconfig:14,n:27,neighborhood:1,network:[14,23],node:20,non:17,notebook:25,npt:15,number:23,nvidia:14,object:[0,16],observ:[1,9],octre:21,oif:[0,16],oifcel:0,oifcelltyp:0,one:0,onlin:[13,29],open:27,option:[5,14],organ:28,oscil:0,other:14,out:0,output:[7,19,20],over:23,overview:23,own:6,p3m:[8,16,21],packag:[9,10,11,12,14],pair:23,pair_criteria:9,parallel:25,paraview:0,particl:[0,1,5,15,23,26,28,29],particle_data:9,particular:23,perform:25,period:27,ph:24,phase:16,point:0,polariz:0,polym:[9,23],potenti:[5,8,16,17],practic:24,pressur:1,principl:18,procedur:0,profil:9,program:18,propag:15,propel:23,properti:[20,23,27,29],pull:0,python:[13,18,23,25],quantiti:7,quartic:16,quick:14,rang:16,reaction:[8,24],reaction_method:9,read:[19,20],regular:27,releas:18,relev:23,requir:[6,14],resourc:13,restor:19,revers:0,rhomboid:5,rigid:[16,23],rotat:[9,23],routin:1,run:[0,25,29],s:[1,6,13],sampl:[0,18],scafaco:[8,21],scalar:0,school:4,screenshot:29,script:[0,18,25,29],script_interfac:9,select:25,self:23,seri:1,set:[14,20,23,27,29],setup:7,shape:[5,9,20],shear:16,shift:16,simplepor:5,simul:[0,18,19,20,25,27],singl:[5,20],site:23,slitpor:5,smooth:17,soft:[0,17],softwar:18,speci:7,specif:0,sphere:[5,17],spherocylind:5,squar:27,star:8,state:27,steepest:15,step:17,stokesian:15,stop:26,stretch:16,structur:[1,14,18],submodul:[9,11,12],subpackag:[9,11],subtract:16,sum:21,summer:4,support:4,surfac:0,swimmer:23,syntax:25,system:[0,1,5,9,24,26,27],tabl:13,tabul:[16,17,24],tau:1,tensor:1,test:14,theori:2,thermal:[0,16],thermodynam:24,thermostat:[9,15],thole:17,time:1,todo:9,tool:[6,25],topolog:19,toru:5,tracer:23,transform:26,triangl:0,triangul:0,troubleshoot:14,tune:8,tutori:18,type:14,ubuntu:14,under:28,union:5,unit:[18,24],up:[14,20,23,27,29],us:[1,14,15,19,20,25],usag:[20,29],user:[6,13],util:[0,9],variabl:[14,27],varianc:1,variou:19,vector:0,vectori:[23,29],veloc:[15,20,26],verlet:15,version:[9,18],via:14,virtual:[16,23],virtual_sit:9,visual:[0,9,20,29],volum:[16,26],vtf:[12,19],vtf_pid_map:19,vtk:0,wall:5,warmup:26,week:17,when:0,widom:24,window:14,without:14,workflow:18,wrapper:25,write:[0,19],writer:12,writevcf:19,writevsf:19,wsl:14,your:6}}) \ No newline at end of file diff --git a/doc4.2.2/system_manipulation.html b/doc4.2.2/system_manipulation.html new file mode 100644 index 0000000000..1ed59fb51a --- /dev/null +++ b/doc4.2.2/system_manipulation.html @@ -0,0 +1,218 @@ + + + + + + + + + 11. System manipulation — ESPResSo 4.2.2 documentation + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +
+

11. System manipulation

+
+

11.1. Changing the box volume

+

This is implemented in +espressomd.system.System.change_volume_and_rescale_particles() +with the parameters d_new for the new length and dir for the +coordinates to work on and "xyz" for isotropic.

+

Changes the volume of either a cubic simulation box to the new volume or +its given x-/y-/z-/xyz-extension to the new box-length, and +isotropically adjusts the particles coordinates as well. The function +returns the new volume of the deformed simulation box.

+
+
+

11.2. Stopping particles

+

To stop particles you can use the functionality implemented in the +espressomd.galilei module. The corresponding class +espressomd.galilei.GalileiTransform which is wrapped inside +the espressomd.system.System instance as +espressomd.system.System.galilei has two functions:

+ +
+
+

11.3. Fixing the center of mass

+

This interaction type applies a constraint on particles of the specified +types such that during the integration the center of mass of these particles is +fixed. This is accomplished as follows: The sum of all the forces acting +on particles of type are calculated. These include all the forces due to +other interaction types and also the thermostat. Next a force equal in +magnitude, but in the opposite direction is applied to all the +particles. This force is divided on the particles of type relative to +their respective mass. Under periodic boundary conditions, this fixes +the itinerant center of mass, that is, the one obtained from the +unfolded coordinates.

+

Center of mass fixing can be activated via espressomd.system.System:

+
system.comfixed.types = list_of_types_to_fix
+
+
+
+
+

11.4. Capping the force during warmup

+

Non-bonded interactions are often used to model the hard core repulsion +between particles. Most of the potentials in the section are therefore +singular at zero distance, and forces usually become very large for +distances below the particle size. This is not a problem during the +simulation, as particles will simply avoid overlapping. However, +creating an initial dense random configuration without overlap is often +difficult. By artificially capping the forces, it is possible to simulate a system +with overlaps. By gradually raising the cap value, possible overlaps +become unfavorable, and the system equilibrates to an overlap-free +configuration.

+

Force capping can be activated via espressomd.system.System:

+
system.force_cap = F_max
+
+
+

This command will limit the magnitude of the force to \(r F_\mathrm{max}\). +Energies are not affected by the capping, so the energy can be used to +identify the remaining overlap. Torques are also not affected by the +capping. Force capping is switched off by setting \(F_\mathrm{max}=0\).

+

For simple systems, it is often more convenient to use the +Steepest descent algorithm instead of writing a tailored warmup +loop in Python. The steepest descent algorithm will integrate the system +while capping both the maximum displacement and maximum rotation.

+
+
+

11.5. Galilei Transform and Particle Velocity Manipulation

+

The following class espressomd.galilei.GalileiTransform may be useful +in affecting the velocity of the system.

+
system = espressomd.System(box_l=[1, 1, 1])
+gt = system.galilei
+
+
+
    +
  • Particle motion and rotation

    +
    gt.kill_particle_motion()
    +
    +
    +

    This command halts all particles in the current simulation, setting +their velocities to zero, as well as their angular momentum if the +option rotation is specified and the feature ROTATION has been +compiled in.

    +
  • +
  • Forces and torques acting on the particles

    +
    gt.kill_particle_forces()
    +
    +
    +

    This command sets all forces on the particles to zero, as well as all +torques if the option torque is specified and the feature ROTATION +has been compiled in.

    +
  • +
  • The center of mass of the system

    +
    gt.system_CMS()
    +
    +
    +

    Returns the center of mass of the whole system. It currently does not +factor in the density fluctuations of the lattice-Boltzmann fluid.

    +
  • +
  • The center-of-mass velocity

    +
    gt.system_CMS_velocity()
    +
    +
    +

    Returns the velocity of the center of mass of the whole system.

    +
  • +
  • The Galilei transform

    +
    gt.galilei_transform()
    +
    +
    +

    Subtracts the velocity of the center of mass of the whole system from +every particle’s velocity, thereby performing a Galilei transform into +the reference frame of the center of mass of the system. This +transformation is useful for example in combination with the DPD +thermostat, since there, a drift in the velocity of the whole system +leads to an offset in the reported temperature.

    +
  • +
+
+
+ + +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/doc4.2.2/system_setup.html b/doc4.2.2/system_setup.html new file mode 100644 index 0000000000..4cb57ad33b --- /dev/null +++ b/doc4.2.2/system_setup.html @@ -0,0 +1,441 @@ + + + + + + + + + 4. Setting up the system — ESPResSo 4.2.2 documentation + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +
+

4. Setting up the system

+
+

4.1. Setting global variables

+

The global system variables are controlled via the Python +espressomd.system.System class:

+
import espressomd
+system = espressomd.System(box_l=[10., 10., 10.])
+system.time_step = 0.01
+system.cell_system.skin = 0.4
+system.periodicity = [True, True, True]
+
+
+

This code creates a system with a cubic unit cell of length 10 in simulation +units, and sets the skin to 0.4 simulation units and the time step to 0.01 +simulation units.

+

Some variables belong to the System class and will be explained in the list +below, while other variables such as the skin belong to objects that are +attached to the class, and will be explain in subsequent sections and chapters. +Note that for many vectorial properties, e.g. box_l and periodicity, +component-wise manipulation +like system.box_l[0] = 1 or in-place operators like += or *= are not +allowed and result in an error. This behavior is inherited, so the same applies +to a after a = system.box_l. If you want to use a vectorial property +for further calculations, you should explicitly make a copy e.g. via +a = numpy.copy(system.box_l).

+
    +
  • box_l

    +

    Simulation box lengths of the cuboid box used by ESPResSo. +Note that if you change the box length during the simulation, the folded +particle coordinates will remain the same, i.e., the particle stay in +the same image box, but at the same relative position in their image +box. If you want to scale the positions, use the command +change_volume_and_rescale_particles().

    +
  • +
  • periodicity

    +

    Specifies periodicity for the three directions. ESPResSo can be instructed +to treat some dimensions as non-periodic. By default ESPResSo assumes periodicity in +all directions which equals setting this variable to [True, True, True]. +A dimension is specified as non-periodic via setting the periodicity +variable for this dimension to False. E.g. Periodicity only in z-direction +is obtained by [False, False, True]. Caveat: Be aware of the fact that making a +dimension non-periodic does not hinder particles from leaving the box in +this direction; in this case, shape-based constraints can be used to keep +particles in the simulation box. For more details, see Boundary conditions.

    +
  • +
  • time_step

    +

    Time step for MD integration.

    +
  • +
  • time

    +

    The simulation time.

    +
  • +
  • min_global_cut

    +

    Minimal total cutoff for real space. Effectively, this plus the +skin is the minimally possible +cell size. ESPResSo typically determines this value automatically, but some +algorithms, virtual sites, require you to specify it manually.

    +
  • +
  • max_cut_bonded

    +

    read-only Maximal cutoff of bonded interactions.

    +
  • +
  • max_cut_nonbonded

    +

    read-only Maximal cutoff of non-bonded interactions.

    +
  • +
+
+

4.1.1. Accessing module states

+

Some variables like or are no longer directly available as attributes. +In these cases they can be easily derived from the corresponding Python +objects like:

+
n_part = len(system.part)
+
+
+

or by calling the corresponding get_state() methods like:

+
temperature = system.thermostat.get_state()[0]['kT']
+gamma = system.thermostat.get_state()[0]['gamma']
+gamma_rot = system.thermostat.get_state()[0]['gamma_rotation']
+
+
+
+
+
+

4.2. Simulation box

+
+

4.2.1. Boundary conditions

+
+

4.2.1.1. Periodic boundaries

+

With periodic boundary conditions, particles interact with periodic +images of all particles in the system. This is the default behavior. +When particles cross a box boundary, their position are folded and +their image box counter are incremented.

+

From the Python interface, the folded position is accessed with +pos_folded and the image +box counter with image_box. +Note that pos gives the +unfolded particle position.

+

Example:

+
import espressomd
+system = espressomd.System(box_l=[5.0, 5.0, 5.0], periodicity=[True, True, True])
+system.time_step = 0.1
+system.cell_system.skin = 0.0
+p = system.part.add(pos=[4.9, 0.0, 0.0], v=[0.1, 0.0, 0.0])
+system.integrator.run(20)
+print(f"pos        = {p.pos}")
+print(f"pos_folded = {p.pos_folded}")
+print(f"image_box  = {p.image_box}")
+
+
+

Output:

+
pos        = [5.1 0.  0. ]
+pos_folded = [0.1 0.  0. ]
+image_box  = [1 0 0]
+
+
+
+
+

4.2.1.2. Open boundaries

+

With open boundaries, particles can leave the simulation box. +What happens in this case depends on which algorithm is used. +Some algorithms may require open boundaries, +such as Stokesian Dynamics.

+

Example:

+
import espressomd
+system = espressomd.System(box_l=[5.0, 5.0, 5.0], periodicity=[False, False, False])
+system.time_step = 0.1
+system.cell_system.skin = 0.0
+p = system.part.add(pos=[4.9, 0.0, 0.0], v=[0.1, 0.0, 0.0])
+system.integrator.run(20)
+print(f"pos        = {p.pos}")
+print(f"pos_folded = {p.pos_folded}")
+print(f"image_box  = {p.image_box}")
+
+
+

Output:

+
pos        = [5.1 0.  0. ]
+pos_folded = [5.1 0.  0. ]
+image_box  = [0 0 0]
+
+
+
+
+

4.2.1.3. Lees–Edwards boundary conditions

+

Lees–Edwards boundary conditions (LEbc) are special periodic boundary +conditions to simulate systems under shear stress [Lees and Edwards, 1972]. +Periodic images of particles across the shear boundary appear with a +time-dependent position offset. When a particle crosses the shear boundary, +it appears to the opposite side of the simulation box with a position offset +and a shear velocity [Bindgen et al., 2021].

+

LEbc require a fully periodic system and are configured with +LinearShear and +OscillatoryShear. +To temporarily disable LEbc, use Off. +To completely disable LEbc and reinitialize the box geometry, do +system.lees_edwards.protocol = None.

+

Example:

+
import espressomd
+import espressomd.lees_edwards
+system = espressomd.System(box_l=[5.0, 5.0, 5.0])
+system.time_step = 0.1
+system.cell_system.skin = 0.0
+system.cell_system.set_n_square(use_verlet_lists=True)
+le_protocol = espressomd.lees_edwards.LinearShear(
+    shear_velocity=-0.1, initial_pos_offset=0.0, time_0=-0.1)
+system.lees_edwards.set_boundary_conditions(
+    shear_direction="y", # shear along y-axis
+    shear_plane_normal="x", # shift when crossing the x-boundary
+    protocol=le_protocol)
+p = system.part.add(pos=[4.9, 0.0, 0.0], v=[0.1, 0.0, 0.0])
+system.integrator.run(20)
+print(f"pos        = {p.pos}")
+print(f"pos_folded = {p.pos_folded}")
+print(f"image_box  = {p.image_box}")
+print(f"velocity   = {p.v}")
+
+
+

Output:

+
pos        = [5.1 0.2 0. ]
+pos_folded = [0.1 0.2 0. ]
+image_box  = [1 0 0]
+velocity   = [0.1 0.1 0. ]
+
+
+

Particles inserted outside the box boundaries will be wrapped around +using the normal periodic boundary rules, i.e. they will not be sheared, +even though their image_box +is not zero.

+

Once a valid tuple (shear_direction, shear_plane_normal, protocol) has been +set via set_boundary_conditions(), +one can update the protocol via a simple assignment of the form +system.lees_edwards.protocol = new_le_protocol, in which case +the shear direction and shear normal are left unchanged. The method +set_boundary_conditions() +is the only way to modify the shear direction and shear normal.

+
+
+
+

4.2.2. Cell systems

+

This section deals with the flexible particle data organization of ESPResSo. +ESPResSo is able to change the organization of the particles in the computer +memory to accommodate for the needs of the algorithms being used. +For details on the internal organization, +refer to section Internal particle organization.

+
+

4.2.2.1. Global properties

+

The properties of the cell system can be accessed via the system +cell_system attribute:

+
    +
  • node_grid

    +

    3D node grid for real space domain decomposition (optional, if +unset an optimal partition is chosen automatically). The domain decomposition +can be visualized with samples/visualization_cellsystem.py.

    +
  • +
  • skin

    +

    Skin for the Verlet list. This value has to be set, otherwise the simulation will not start.

    +
  • +
+

Details about the cell system can be obtained by +get_state():

+
    +
  • cell_grid Dimension of the inner cell grid (only for regular decomposition).

  • +
  • cell_size Box-length of a cell (only for regular decomposition).

  • +
  • n_nodes Number of MPI nodes.

  • +
  • node_grid MPI domain partition.

  • +
  • type The current type of the cell system.

  • +
  • skin Verlet list skin.

  • +
  • verlet_reuse Average number of integration steps the Verlet list is re-used.

  • +
+
+
+

4.2.2.2. Regular decomposition

+

Invoking set_regular_decomposition() +selects the regular decomposition cell scheme, using Verlet lists for the +calculation of the interactions. If you specify use_verlet_lists=False, +only the regular decomposition is used, but not the Verlet lists.

+
import espressomd
+system = espressomd.System(box_l=[1, 1, 1])
+system.cell_system.set_regular_decomposition(use_verlet_lists=True)
+
+
+

The regular decomposition cellsystem is the default system and suits most +applications with short ranged interactions. The particles are divided +up spatially into small compartments, the cells, such that the cell size +is larger than the maximal interaction range. In this case interactions +only occur between particles in adjacent cells. Since the interaction +range should be much smaller than the total system size, leaving out all +interactions between non-adjacent cells can mean a tremendous speed-up. +Moreover, since for constant interaction range, the number of particles +in a cell depends only on the density. The number of interactions is +therefore of the order \(N\) instead of order \(N^2\) if one has to +calculate all pair interactions.

+

With this scheme, there must be at least two cells per direction, +and at most 32 cells per direction for a cubic box geometry. +The number of cells per direction depends on the interaction range cutoff +\(l_{\mathrm{cut}}\), the Verlet list skin \(l_{\mathrm{skin}}\) +and the box length \(l_{\mathrm{box}}\), and is determined automatically +by solving several equations. It can be useful to know how to estimate the +number of cells per direction, because it limits the number of MPI ranks +that can be allocated to an MPI-parallel simulation. As a rule of thumb, +for a cubic box geometry the number of cells per direction is often:

+
+\[\left\lfloor \frac{l_{\mathrm{box}}}{l_{\mathrm{cut}} + l_{\mathrm{skin}}} \right\rfloor\]
+

For example, in a system with box length 12, LJ cutoff 2.5 and Verlet +skin 0.4, the number of cells cannot be more than 4 in each direction. +A runtime error will be triggered during integration when running a +simulation with such a system and allocating more than 64 MPI ranks +in total, or more than 4 MPI ranks per direction. In this situation, +consider increasing the box size or decreasing the interaction cutoff +or Verlet list skin.

+
+
+

4.2.2.3. N-squared

+

Invoking set_n_square() +selects the very primitive N-squared cellsystem, which calculates +the interactions for all particle pairs. Therefore it loops over all +particles, giving an unfavorable computation time scaling of +\(N^2\). However, algorithms like MMM1D or the plain Coulomb +interaction in the cell model require the calculation of all pair +interactions.

+
import espressomd
+system = espressomd.System(box_l=[1, 1, 1])
+system.cell_system.set_n_square()
+
+
+

In a multiple processor environment, the N-squared cellsystem uses a +simple particle balancing scheme to have a nearly equal number of +particles per CPU, \(n\) nodes have \(m\) particles, and +\(p-n\) nodes have \(m+1\) particles, such that +\(n \cdot m + (p - n) \cdot (m + 1) = N\), the total number of particles. Therefore the +computational load should be balanced fairly equal among the nodes, with +one exception: This code always uses one CPU for the interaction between +two different nodes. For an odd number of nodes, this is fine, because +the total number of interactions to calculate is a multiple of the +number of nodes, but for an even number of nodes, for each of the +\(p-1\) communication rounds, one processor is idle.

+

E.g. for 2 processors, there are 3 interactions: 0-0, 1-1, 0-1. +Naturally, 0-0 and 1-1 are treated by processor 0 and 1, respectively. +But the 0-1 interaction is treated by node 1 alone, so the workload for +this node is twice as high. For 3 processors, the interactions are 0-0, +1-1, 2-2, 0-1, 1-2, 0-2. Of these interactions, node 0 treats 0-0 and +0-2, node 1 treats 1-1 and 0-1, and node 2 treats 2-2 and 1-2.

+

Therefore it is highly recommended that you use N-squared only with an +odd number of nodes, if with multiple processors at all.

+
+
+

4.2.2.4. Hybrid decomposition

+

If for a simulation setup the interaction range is much smaller than the +system size, use of a Regular decomposition leads to efficient +scaling behavior (order \(N\) instead of order \(N^2\)). +Consider a system with many small particles, e.g. a polymer solution. +There, already the addition of one single large particle increases the maximum +interaction range and thus the minimum cell size of the decomposition. +Due to this larger cell size, throughout the simulation box a large number +of non-interacting pairs of small particles is visited during the short +range calculation. This can considerably increase the computational cost of +the simulation.

+

For such simulation setups, i.e. systems with a few large particles and much +more small particles, the hybrid decomposition can be used. This hybrid +decomposition is backed by two coupled particle decompositions which can +be used to efficiently deal with the differently sized particles. +Specifically that means putting the small particles into a +Regular decomposition. There, the minimum cell size is limited only +by the maximum interaction range of all particles within this decomposition. +The few large particles are put into a N-squared cellsystem. Particles +within this decomposition interact both, amongst each other and with all small +particles in the Regular decomposition. The hybrid decomposition can therefore +effectively recover the computational efficiency of the regular decomposition, +given that only a few large particles have been added.

+

Invoking set_hybrid_decomposition() +selects the hybrid decomposition.

+
system = espressomd.System(box_l=[10, 10, 10])
+system.cell_system.set_hybrid_decomposition(n_square_types={1, 3}, cutoff_regular=1.2)
+
+
+

Here, n_square_types is a python set containing the types of particles to +put into the N-squared cellsystem, i.e. the particle types of the +large particles. Particles with other types will by default be put into the +Regular decomposition. Note that for now it is also necessary to manually set +the maximum cutoff to consider for interactions within the +Regular decomposition, i.e. the maximum interaction range among all +small particle types. Set this via the cutoff_regular parameter.

+
+

Note

+

The hybrid particle decomposition has been added to ESPResSo only recently and +for now should be considered an experimental feature. If you notice some unexpected +behavior please let us know via github or the mailing list.

+
+
+
+
+
+ + +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/doc4.2.2/under_the_hood.html b/doc4.2.2/under_the_hood.html new file mode 100644 index 0000000000..b54ede695f --- /dev/null +++ b/doc4.2.2/under_the_hood.html @@ -0,0 +1,183 @@ + + + + + + + + + 20. Under the hood — ESPResSo 4.2.2 documentation + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +
+

20. Under the hood

+
+

20.1. Internal particle organization

+

Since basically all major parts of the main MD integration have to +access the particle data, efficient access to the particle data is +crucial for a fast MD code. Therefore the particle data needs some more +elaborate organization, which will be presented here. A particle itself +is represented by a structure (Particle) consisting of several +substructures (e.g. ParticlePosition, ParticleForce or +ParticleProperties), which in turn represent basic physical properties +such as position, force or charge. The particles are organized in one or +more particle lists on each node, called CellPList. The cells are +arranged by several possible systems, as described in Cell systems. +A cell system defines a way the particles are stored in ESPResSo, i.e. +how they are distributed onto the processor nodes and how they are +organized on each of them. Moreover a cell system also defines +procedures to efficiently calculate the force, energy and pressure for +the short ranged interactions, since these can be heavily optimized +depending on the cell system. For example, the regular decomposition +cellsystem allows an order N interactions evaluation.

+

Technically, a cell is organized as a dynamically growing array, not as +a list. This ensures that the data of all particles in a cell is stored +contiguously in the memory. The particle data is accessed transparently +through a set of methods common to all cell systems, which allocate the +cells, add new particles, retrieve particle information and are +responsible for communicating the particle data between the nodes. +Therefore most portions of the code can access the particle data safely +without direct knowledge of the currently used cell system. Only the +force, energy and pressure loops are implemented separately for each +cell model as explained above.

+

The regular decomposition or link cell algorithm is implemented such +that the cells equal the cells, i.e. each cell is a separate particle +list. For an example let us assume that the simulation box has size +\(20\times 20\times 20\) and that we assign 2 processors to the +simulation. Then each processor is responsible for the particles inside +a \(10\times 20\times 20\) box. If the maximal interaction range is +1.2, the minimal possible cell size is 1.25 for 8 cells along the first +coordinate, allowing for a small skin of 0.05. If one chooses only 6 +boxes in the first coordinate, the skin depth increases to 0.467. In +this example we assume that the number of cells in the first coordinate +was chosen to be 6 and that the cells are cubic. One would then organize +the cells on each node in a \(6 \times 12 \times 12\) cell grid +embedded at the center of a \(8 \times 14 \times 14\) grid. +The additional cells around the cells containing the particles +represent the ghost shell in which the information of the ghost +particles from the neighboring nodes is stored. Therefore the particle +information stored on each node resides in 1568 particle lists of which +864 cells contain particles assigned to the node, the rest contain +information of particles from other nodes.

+

Classically, the link cell algorithm is implemented differently. Instead +of having separate particle lists for each cell, there is only one +particle list per node, and the cells actually only contain pointers +to this particle list. This has the advantage that when particles are +moved from one cell to another on the same processor, only the pointers +have to be updated, which is much fewer data (4 rsp. 8 bytes) than the +full particle structure (around 192 bytes, depending on the features +compiled in). The data storage scheme of however requires to always move +the full particle data. Nevertheless, from our experience, the second +approach is 2-3 times faster than the classical one.

+

To understand this, one has to know a little bit about the architecture +of modern computers. Most modern processors have a clock frequency above +1GHz and are able to execute nearly one instruction per clock tick. In +contrast, the memory runs at a clock speed around 200MHz. Modern +double data rate (DDR) RAM transfers up to 3.2GB/s at this clock speed +(at each edge of the clock signal 8 bytes are transferred). But in +addition to the data transfer speed, DDR RAM has some latency for +fetching the data, which can be up to 50ns in the worst case. Memory is +organized internally in pages or rows of typically 8KB size. The full +\(2\times 200\) MHz data rate can only be achieved if the access is +within the same memory page (page hit), otherwise some latency has to be +added (page miss). The actual latency depends on some other aspects of +the memory organization which will not be discussed here, but the +penalty is at least 10ns, resulting in an effective memory transfer rate +of only 800MB/s. To remedy this, modern processors have a small amount +of low latency memory directly attached to the processor, the cache.

+

The processor cache is organized in different levels. The level 1 (L1) +cache is built directly into the processor core, has no latency and +delivers the data immediately on demand, but has only a small size of +around 128KB. This is important since modern processors can issue +several simple operations such as additions simultaneously. The L2 cache +is larger, typically around 1MB, but is located outside the processor +core and delivers data at the processor clock rate or some fraction of +it.

+

In a typical implementation of the link cell scheme, the order of the +particles is fairly random, determined e.g. by the order in which the +particles are set up or have been communicated across the processor +boundaries. The force loop therefore accesses the particle array in +arbitrary order, resulting in a lot of unfavorable page misses. In the +memory organization of ESPResSo, the particles are accessed in a virtually +linear order. Because the force calculation goes through the cells in a +linear fashion, all accesses to a single cell occur close in time, for +the force calculation of the cell itself as well as for its neighbors. +Using the regular decomposition cell scheme, two cell layers have to be +kept in the processor cache. For 10000 particles and a typical cell grid +size of 20, these two cell layers consume roughly 200 KBytes, which +nearly fits into the L2 cache. Therefore every cell has to be read from +the main memory only once per force calculation.

+
+
+ + +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/doc4.2.2/visualization.html b/doc4.2.2/visualization.html new file mode 100644 index 0000000000..2fcc1afe84 --- /dev/null +++ b/doc4.2.2/visualization.html @@ -0,0 +1,355 @@ + + + + + + + + + 17. Online-visualization — ESPResSo 4.2.2 documentation + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +
+

17. Online-visualization

+

ESPResSo offers a direct rendering engine based on pyopengl. +It supports several features like shape-based constraints, +particle properties, the cell system, lattice-Boltzmann and more. +It can be adjusted with a large number of parameters to set colors, +materials, camera and interactive features like assigning callbacks +to user input. It requires the Python module PyOpenGL. +It is not meant to produce high quality renderings, but rather to +debug the simulation setup and equilibration process.

+
+

17.1. General usage

+

The recommended usage is to instantiate the visualizer and pass it the +espressomd.System() object. Then write +your integration loop in a separate function, which is started in a +non-blocking thread. Whenever needed, call update() to synchronize +the renderer with your system. Finally start the blocking visualization +window with start(). See the following minimal code example:

+
import espressomd
+import espressomd.visualization
+import threading
+
+system = espressomd.System(box_l=[10, 10, 10])
+system.cell_system.skin = 0.4
+system.time_step = 0.00001
+
+system.part.add(pos=[1, 1, 1], v=[1, 0, 0])
+system.part.add(pos=[9, 9, 9], v=[0, 1, 0])
+
+visualizer = espressomd.visualization.openGLLive(system)
+
+def main_thread():
+    while True:
+        system.integrator.run(1)
+        visualizer.update()
+
+t = threading.Thread(target=main_thread)
+t.daemon = True
+t.start()
+visualizer.start()
+
+
+
+
+

17.2. Setting up the visualizer

+

espressomd.visualization.openGLLive()

+

The required parameter system is the System object. +The optional keywords in **kwargs are used to adjust the appearance of the visualization. +These parameters have suitable default values for most simulations.

+

espressomd.visualization.openGLLive.update()

+

update() synchronizes system and visualizer, handles keyboard events for +openGLLive.

+

espressomd.visualization.openGLLive.start()

+

start() starts the blocking visualizer window. +Should be called after a separate thread containing update() has been started.

+

espressomd.visualization.openGLLive.register_callback()

+

Registers the method callback(), which is called every interval milliseconds. Useful for +live plotting (see sample script /samples/visualization_ljliquid.py).

+
+

Note

+

The visualization of some constraints is either improved by (espressomd.shapes.SimplePore) +or even relies on (espressomd.shapes.HollowConicalFrustum) the presence of an installed +OpenGL Extrusion library on your system. Typically, the library will be available through the +default package manager of your operating system. On Ubuntu the required package is called libgle3-dev, +on Fedora libgle – just to name two examples.

+
+
+

17.2.1. Running the visualizer

+

espressomd.visualization.openGLLive.run()

+

To visually debug your simulation, run(n) can be used to conveniently start +an integration loop with n integration steps in a separate thread once the +visualizer is initialized:

+
import espressomd
+import espressomd.visualization
+
+system = espressomd.System(box_l=[10, 10, 10])
+system.cell_system.skin = 0.4
+system.time_step = 0.0001
+
+system.part.add(pos=[1, 1, 1], v=[1, 0, 0])
+system.part.add(pos=[9, 9, 9], v=[0, 1, 0])
+
+visualizer = espressomd.visualization.openGLLive(system, background_color=[1, 1, 1])
+visualizer.run(1)
+
+
+
+
+

17.2.2. Screenshots

+ +

The OpenGL visualizer can also be used for offline rendering. +After creating the visualizer object, call screenshot(path) +to save an image of your simulation to path. Internally, the image is saved +with matplotlib.pyplot.imsave, so the file format is specified by the +extension of the filename. The image size is determined by the keyword +argument window_size of the visualizer. This method can be used to create +screenshots without blocking the simulation script:

+
import espressomd
+import espressomd.visualization
+
+system = espressomd.System(box_l=[10, 10, 10])
+system.cell_system.skin = 1.0
+system.time_step = 0.1
+
+for i in range(1000):
+    system.part.add(pos=[5, 5, 5])
+
+system.thermostat.set_langevin(kT=1, gamma=1, seed=42)
+
+visualizer = espressomd.visualization.openGLLive(system, window_size=[500, 500])
+
+for i in range(100):
+    system.integrator.run(1)
+    visualizer.screenshot(f'screenshot_{i:0>5}.png')
+
+# You may consider creating a video with ffmpeg:
+# ffmpeg -f image2 -framerate 30 -i 'screenshot_%05d.png' output.mp4
+
+
+

It is also possible to create a snapshot during online visualization. +Simply press the enter key to create a snapshot of the current window, +which saves it to <scriptname>_n.png (with incrementing n).

+
+
+

17.2.3. Colors and Materials

+

Colors for particles, bonds and constraints are specified by RGB arrays. +Materials by an array for the ambient, diffuse, specular and shininess and opacity (ADSSO) +components. To distinguish particle groups, arrays of RGBA or ADSSO entries are +used, which are indexed circularly by the numerical particle type:

+
# Particle type 0 is red, type 1 is blue (type 2 is red etc)..
+visualizer = espressomd.visualization.openGLLive(system,
+                                                 particle_coloring='type',
+                                                 particle_type_colors=[[1, 0, 0], [0, 0, 1]])
+
+
+

particle_type_materials lists the materials by type:

+
# Particle type 0 is gold, type 1 is blue (type 2 is gold again etc).
+visualizer = espressomd.visualization.openGLLive(system,
+                                                 particle_coloring='type',
+                                                 particle_type_colors=[[1, 1, 1], [0, 0, 1]],
+                                                 particle_type_materials=["steel", "bright"])
+
+
+

Materials are stored in espressomd.visualization.openGLLive.materials.

+
+
+

17.2.4. Visualize vectorial properties

+

Most vectorial particle properties can be visualized by 3D-arrows on the +particles:

+
    +
  • ext_force: An external force. Activate with the keyword ext_force_arrows = True.

  • +
  • f: The force acting on the particle. Activate with the keyword force_arrows = True.

  • +
  • v: The velocity of the particle. Activate with the keyword velocity_arrows = True.

  • +
  • director: A vector associated with the orientation of the particle. Activate with the keyword director_arrows = True.

  • +
+

Arrow colors, scales and radii can be adjusted. Again, the lists specifying +these quantities are indexed circularly by the numerical particle type. The +following code snippet demonstrates the visualization of the director property +and individual settings for two particle types (requires the ROTATION +feature):

+
import numpy as np
+import espressomd
+from espressomd.visualization import openGLLive, KeyboardButtonEvent, KeyboardFireEvent
+
+box_l = 10
+system = espressomd.System(box_l=[box_l, box_l, box_l])
+system.cell_system.skin = 0.4
+
+system.time_step = 0.00001
+
+visualizer = openGLLive(system,
+                        director_arrows=True,
+                        director_arrows_type_scale=[1.5, 1.0],
+                        director_arrows_type_radii=[0.1, 0.4],
+                        director_arrows_type_colors=[[1.0, 0, 0], [0, 1.0, 0]])
+
+for i in range(10):
+    system.part.add(pos=np.random.random(3) * box_l,
+                    rotation=[1, 1, 1],
+                    ext_torque=[5, 0, 0],
+                    v=[10, 0, 0],
+                    type=0)
+    system.part.add(pos=np.random.random(3) * box_l,
+                    rotation=[1, 1, 1],
+                    ext_torque=[0, 5, 0],
+                    v=[-10, 0, 0],
+                    type=1)
+
+visualizer.run(1)
+
+
+
+
+

17.2.5. Controls

+

The camera can be controlled via mouse and keyboard:

+
    +
  • hold left button: rotate the system

  • +
  • hold right button: translate the system

  • +
  • hold middle button: zoom / roll

  • +
  • mouse wheel / key pair TG: zoom

  • +
  • WASD-Keyboard control (WS: move forwards/backwards, AD: move sidewards)

  • +
  • Key pairs QE, RF, ZC: rotate the system

  • +
  • Double click on a particle: Show particle information

  • +
  • Double click in empty space: Toggle system information

  • +
  • Left/Right arrows: Cycle through particles

  • +
  • Space: If started with run(n), this pauses the simulation

  • +
  • Enter: Creates a snapshot of the current window and saves it to <scriptname>_n.png (with incrementing n)

  • +
+

Additional input functionality for mouse and keyboard is possible by assigning +callbacks to specified keyboard or mouse buttons. This may be useful for +realtime adjustment of system parameters (temperature, interactions, particle +properties, etc.) or for demonstration purposes. The callbacks can be triggered +by a timer or keyboard input:

+
def foo():
+    print("foo")
+
+# Registers timed calls of foo()
+visualizer.register_callback(foo, interval=500)
+
+# Callbacks to control temperature
+temperature = 1.0
+system.thermostat.set_langevin(kT=temperature, seed=42, gamma=1.0)
+def increaseTemp():
+    global temperature
+    temperature += 0.5
+    system.thermostat.set_langevin(kT=temperature, gamma=1.0)
+    print(f"T = {system.thermostat.get_state()[0]['kT']:.1f}")
+
+def decreaseTemp():
+    global temperature
+    temperature -= 0.5
+    if temperature > 0:
+        system.thermostat.set_langevin(kT=temperature, gamma=1.0)
+        print(f"T = {system.thermostat.get_state()[0]['kT']:.1f}")
+    else:
+        temperature = 0
+        system.thermostat.turn_off()
+        print("T = 0")
+
+# Registers input-based calls with keys Y and H
+visualizer.keyboard_manager.register_button(KeyboardButtonEvent('y', KeyboardFireEvent.Hold, increaseTemp))
+visualizer.keyboard_manager.register_button(KeyboardButtonEvent('h', KeyboardFireEvent.Hold, decreaseTemp))
+
+visualizer.run(1)
+
+
+

Further examples can be found in /samples/billiard.py or /samples/visualization_interactive.py.

+
+
+

17.2.6. Dragging particles

+

With the keyword drag_enabled set to True, the mouse can be used to +exert a force on particles in drag direction (scaled by drag_force and the +distance of particle and mouse cursor).

+
+
+
+

17.3. Visualization example scripts

+

Various Sample scripts can be found in /samples/visualization_*.py +or in the Tutorials “Visualization” and “Charged Systems”.

+
+
+ + +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/tutorials4.2.2.md b/tutorials4.2.2.md new file mode 100644 index 0000000000..7d6fa2bfcd --- /dev/null +++ b/tutorials4.2.2.md @@ -0,0 +1,58 @@ +# Tutorials + +All tutorials are available as Jupyter notebooks and can be found in `doc/tutorials/` in the +source code and [on GitHub](https://github.com/espressomd/espresso/tree/python/doc/tutorials). + + +### Introductory tutorials + +* **Simulate a simple Lennard-Jones liquid** + Modelling of a single-component and a two-component Lennard-Jones liquid. + [Guide](tutorials4.2.2/lennard_jones/lennard_jones.html) +* **Error analysis** + Statistical analysis of simulation results + Guide + [Part 1](tutorials4.2.2/error_analysis/error_analysis_part1.html) | + [Part 2](tutorials4.2.2/error_analysis/error_analysis_part2.html) +* **Visualization** + Using the online visualizers of ESPResSo. + [Guide](tutorials4.2.2/visualization/visualization.html) + +### Intermediate tutorials + +* **Charged systems** + Modelling of ion condensation around a charged rod. + [Guide](tutorials4.2.2/charged_system/charged_system.html) +* **Langevin dynamics** + Modelling of Brownian motion and measurement of diffusion coefficients. + [Guide](tutorials4.2.2/langevin_dynamics/langevin_dynamics.html) +* **Ferrofluid** + Modelling of a monolayer ferrofluid system. + Guide + [Part 1](tutorials4.2.2/ferrofluid/ferrofluid_part1.html) | + [Part 2](tutorials4.2.2/ferrofluid/ferrofluid_part2.html) | + [Part 3](tutorials4.2.2/ferrofluid/ferrofluid_part3.html) +* **Lattice-Boltzmann** + Simulations including hydrodynamic interactions using the Lattice-Boltzmann method. + Guide + [Part 1](tutorials4.2.2/lattice_boltzmann/lattice_boltzmann_theory.html) | + [Part 2](tutorials4.2.2/lattice_boltzmann/lattice_boltzmann_poiseuille_flow.html) +* **Polymers** + Modelling polymers with hydrodynamic interactions. + [Guide](tutorials4.2.2/polymers/polymers.html) +* **Raspberry electrophoresis** + Extended objects in a Lattice-Boltzmann fluid, raspberry particles. + [Guide](tutorials4.2.2/raspberry_electrophoresis/raspberry_electrophoresis.html) + +### Advanced tutorials + +* **Active matter** + Modelling of self-propelling particles. + [Guide](tutorials4.2.2/active_matter/active_matter.html) +* **Electrokinetics** + Modelling electrokinetics together with hydrodynamic interactions. + [Guide](tutorials4.2.2/electrokinetics/electrokinetics.html) +* **Constant pH method** + Modelling an acid dissociation curve using the constant pH method. + [Guide](tutorials4.2.2/constant_pH/constant_pH.html) + diff --git a/tutorials4.2.2/active_matter/active_matter.html b/tutorials4.2.2/active_matter/active_matter.html new file mode 100644 index 0000000000..ff6bf2cb08 --- /dev/null +++ b/tutorials4.2.2/active_matter/active_matter.html @@ -0,0 +1,8865 @@ + + + + + +active_matter.run + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + diff --git a/tutorials4.2.2/active_matter/figures/friction.svg b/tutorials4.2.2/active_matter/figures/friction.svg new file mode 100644 index 0000000000..c1cc98ff17 --- /dev/null +++ b/tutorials4.2.2/active_matter/figures/friction.svg @@ -0,0 +1,109 @@ + +image/svg+xmldirector +drivingforce +friction + \ No newline at end of file diff --git a/tutorials4.2.2/active_matter/figures/geometry.svg b/tutorials4.2.2/active_matter/figures/geometry.svg new file mode 100644 index 0000000000..97c0df079e --- /dev/null +++ b/tutorials4.2.2/active_matter/figures/geometry.svg @@ -0,0 +1,126 @@ + +image/svg+xml \ No newline at end of file diff --git a/tutorials4.2.2/active_matter/figures/pusher-puller.svg b/tutorials4.2.2/active_matter/figures/pusher-puller.svg new file mode 100644 index 0000000000..555ff4dacd --- /dev/null +++ b/tutorials4.2.2/active_matter/figures/pusher-puller.svg @@ -0,0 +1,477 @@ + +image/svg+xml(a) +(b) +(c) +(d) +` +` + \ No newline at end of file diff --git a/tutorials4.2.2/charged_system/charged_system.html b/tutorials4.2.2/charged_system/charged_system.html new file mode 100644 index 0000000000..04cd1e8c6f --- /dev/null +++ b/tutorials4.2.2/charged_system/charged_system.html @@ -0,0 +1,9004 @@ + + + + + +charged_system.run + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + diff --git a/tutorials4.2.2/constant_pH/constant_pH.html b/tutorials4.2.2/constant_pH/constant_pH.html new file mode 100644 index 0000000000..aad27a8f9d --- /dev/null +++ b/tutorials4.2.2/constant_pH/constant_pH.html @@ -0,0 +1,8938 @@ + + + + + +constant_pH.run + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + diff --git a/tutorials4.2.2/electrokinetics/electrokinetics.html b/tutorials4.2.2/electrokinetics/electrokinetics.html new file mode 100644 index 0000000000..beb683cb32 --- /dev/null +++ b/tutorials4.2.2/electrokinetics/electrokinetics.html @@ -0,0 +1,8280 @@ + + + + + +electrokinetics.run + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + +
+ + diff --git a/tutorials4.2.2/electrokinetics/figures/schlitzpore_3d.png b/tutorials4.2.2/electrokinetics/figures/schlitzpore_3d.png new file mode 100644 index 0000000000..1c94a31a56 Binary files /dev/null and b/tutorials4.2.2/electrokinetics/figures/schlitzpore_3d.png differ diff --git a/tutorials4.2.2/error_analysis/error_analysis_part1.html b/tutorials4.2.2/error_analysis/error_analysis_part1.html new file mode 100644 index 0000000000..d2b6ea222f --- /dev/null +++ b/tutorials4.2.2/error_analysis/error_analysis_part1.html @@ -0,0 +1,8140 @@ + + + + + +error_analysis_part1.run + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + +
+ + diff --git a/tutorials4.2.2/error_analysis/error_analysis_part2.html b/tutorials4.2.2/error_analysis/error_analysis_part2.html new file mode 100644 index 0000000000..d91d4deabf --- /dev/null +++ b/tutorials4.2.2/error_analysis/error_analysis_part2.html @@ -0,0 +1,8244 @@ + + + + + +error_analysis_part2.run + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + +
+ + diff --git a/tutorials4.2.2/ferrofluid/ferrofluid_part1.html b/tutorials4.2.2/ferrofluid/ferrofluid_part1.html new file mode 100644 index 0000000000..0f9e496f72 --- /dev/null +++ b/tutorials4.2.2/ferrofluid/ferrofluid_part1.html @@ -0,0 +1,8875 @@ + + + + + +ferrofluid_part1.run + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + diff --git a/tutorials4.2.2/ferrofluid/figures/Electro-Steric_Stabilization.jpg b/tutorials4.2.2/ferrofluid/figures/Electro-Steric_Stabilization.jpg new file mode 100644 index 0000000000..1c19ccca08 Binary files /dev/null and b/tutorials4.2.2/ferrofluid/figures/Electro-Steric_Stabilization.jpg differ diff --git a/tutorials4.2.2/ferrofluid/figures/Ferrofluid_Magnet_under_glass_edit.jpg b/tutorials4.2.2/ferrofluid/figures/Ferrofluid_Magnet_under_glass_edit.jpg new file mode 100644 index 0000000000..2d75ed4713 Binary files /dev/null and b/tutorials4.2.2/ferrofluid/figures/Ferrofluid_Magnet_under_glass_edit.jpg differ diff --git a/tutorials4.2.2/ferrofluid/figures/headtotailconf.png b/tutorials4.2.2/ferrofluid/figures/headtotailconf.png new file mode 100644 index 0000000000..39f48cdc57 Binary files /dev/null and b/tutorials4.2.2/ferrofluid/figures/headtotailconf.png differ diff --git a/tutorials4.2.2/langevin_dynamics/langevin_dynamics.html b/tutorials4.2.2/langevin_dynamics/langevin_dynamics.html new file mode 100644 index 0000000000..7b667c8c31 --- /dev/null +++ b/tutorials4.2.2/langevin_dynamics/langevin_dynamics.html @@ -0,0 +1,8109 @@ + + + + + +langevin_dynamics.run + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + +
+ + diff --git a/tutorials4.2.2/lattice_boltzmann/figures/latticeboltzmann-grid.png b/tutorials4.2.2/lattice_boltzmann/figures/latticeboltzmann-grid.png new file mode 100644 index 0000000000..5f8b65b671 Binary files /dev/null and b/tutorials4.2.2/lattice_boltzmann/figures/latticeboltzmann-grid.png differ diff --git a/tutorials4.2.2/lattice_boltzmann/figures/latticeboltzmann-momentumexchange.png b/tutorials4.2.2/lattice_boltzmann/figures/latticeboltzmann-momentumexchange.png new file mode 100644 index 0000000000..0035c5cc68 Binary files /dev/null and b/tutorials4.2.2/lattice_boltzmann/figures/latticeboltzmann-momentumexchange.png differ diff --git a/tutorials4.2.2/lattice_boltzmann/lattice_boltzmann_poiseuille_flow.html b/tutorials4.2.2/lattice_boltzmann/lattice_boltzmann_poiseuille_flow.html new file mode 100644 index 0000000000..2b94a764cd --- /dev/null +++ b/tutorials4.2.2/lattice_boltzmann/lattice_boltzmann_poiseuille_flow.html @@ -0,0 +1,7825 @@ + + + + + +lattice_boltzmann_poiseuille_flow.run + + + + + + + + + + + + +
+ + + + + + + +
+ + diff --git a/tutorials4.2.2/lattice_boltzmann/lattice_boltzmann_theory.html b/tutorials4.2.2/lattice_boltzmann/lattice_boltzmann_theory.html new file mode 100644 index 0000000000..e3c49fd7c9 --- /dev/null +++ b/tutorials4.2.2/lattice_boltzmann/lattice_boltzmann_theory.html @@ -0,0 +1,7804 @@ + + + + + +lattice_boltzmann_theory.run + + + + + + + + + + + + +
+ + + + + + + + + + + +
+ + diff --git a/tutorials4.2.2/lennard_jones/lennard_jones.html b/tutorials4.2.2/lennard_jones/lennard_jones.html new file mode 100644 index 0000000000..04140e8091 --- /dev/null +++ b/tutorials4.2.2/lennard_jones/lennard_jones.html @@ -0,0 +1,9073 @@ + + + + + +lennard_jones.run + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + diff --git a/tutorials4.2.2/polymers/polymers.html b/tutorials4.2.2/polymers/polymers.html new file mode 100644 index 0000000000..f741d168b5 --- /dev/null +++ b/tutorials4.2.2/polymers/polymers.html @@ -0,0 +1,8756 @@ + + + + + +polymers.run + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + diff --git a/tutorials4.2.2/raspberry_electrophoresis/figures/raspberry_snapshot.png b/tutorials4.2.2/raspberry_electrophoresis/figures/raspberry_snapshot.png new file mode 100644 index 0000000000..815a4e295f Binary files /dev/null and b/tutorials4.2.2/raspberry_electrophoresis/figures/raspberry_snapshot.png differ diff --git a/tutorials4.2.2/raspberry_electrophoresis/raspberry_electrophoresis.html b/tutorials4.2.2/raspberry_electrophoresis/raspberry_electrophoresis.html new file mode 100644 index 0000000000..c4e30500db --- /dev/null +++ b/tutorials4.2.2/raspberry_electrophoresis/raspberry_electrophoresis.html @@ -0,0 +1,8577 @@ + + + + + +raspberry_electrophoresis.run + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + diff --git a/tutorials4.2.2/visualization/visualization.html b/tutorials4.2.2/visualization/visualization.html new file mode 100644 index 0000000000..5d61c0416b --- /dev/null +++ b/tutorials4.2.2/visualization/visualization.html @@ -0,0 +1,7975 @@ + + + + + +visualization.run + + + + + + + + + + + + +
+ + + + + + + + + + + +
+ +