ESPResSo
Extensible Simulation Package for Research on Soft Matter Systems
Loading...
Searching...
No Matches
rotation.cpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2010-2022 The ESPResSo project
3 * Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010
4 * Max-Planck-Institute for Polymer Research, Theory Group
5 *
6 * This file is part of ESPResSo.
7 *
8 * ESPResSo is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * ESPResSo is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 */
21/** \file
22 * Molecular dynamics integrator for rotational motion.
23 *
24 * A velocity Verlet algorithm using quaternions is implemented to tackle
25 * rotational motion. See @cite martys99a for the method and
26 * @cite allen17a for the quaternion components indexing used here.
27 * A random torque and a friction
28 * term are added to provide the constant NVT conditions. Due to this feature
29 * all particles are
30 * treated as 3D objects with 3 translational and 3 rotational degrees of
31 * freedom if ROTATION is compiled in.
32 */
33
34#include <config/config.hpp>
35
36#ifdef ESPRESSO_ROTATION
37
38#include "rotation.hpp"
39
40#include "ParticleRange.hpp"
41
42#include <utils/Vector.hpp>
43#include <utils/mask.hpp>
44
45#include <cassert>
46#include <cmath>
47
48/** @brief Calculate the derivatives of the quaternion and angular
49 * acceleration for a given particle.
50 * See @cite sonnenschein85a. Please note that ESPResSo uses scalar-first
51 * notation for quaternions, while @cite sonnenschein85a uses scalar-last
52 * notation.
53 * @param[in] p Particle
54 * @param[out] Qd First derivative of the particle quaternion
55 * @param[out] Qdd Second derivative of the particle quaternion
56 * @param[out] S Function of @p Qd and @p Qdd, used to evaluate the
57 * Lagrange parameter lambda
58 * @param[out] Wd Angular acceleration of the particle
59 */
62 Utils::Vector3d &Wd) {
63 /* calculate the first derivative of the quaternion */
64 /* Eq. (4) @cite sonnenschein85a */
65 Qd[0] = 0.5 * (-p.quat()[1] * p.omega()[0] - p.quat()[2] * p.omega()[1] -
66 p.quat()[3] * p.omega()[2]);
67
68 Qd[1] = 0.5 * (p.quat()[0] * p.omega()[0] - p.quat()[3] * p.omega()[1] +
69 p.quat()[2] * p.omega()[2]);
70
71 Qd[2] = 0.5 * (p.quat()[3] * p.omega()[0] + p.quat()[0] * p.omega()[1] -
72 p.quat()[1] * p.omega()[2]);
73
74 Qd[3] = 0.5 * (-p.quat()[2] * p.omega()[0] + p.quat()[1] * p.omega()[1] +
75 p.quat()[0] * p.omega()[2]);
76
77 /* Calculate the angular acceleration. */
78 /* Eq. (5) @cite sonnenschein85a */
79 if (p.can_rotate_around(0))
80 Wd[0] = (p.torque()[0] + p.omega()[1] * p.omega()[2] *
81 (p.rinertia()[1] - p.rinertia()[2])) /
82 p.rinertia()[0];
83 if (p.can_rotate_around(1))
84 Wd[1] = (p.torque()[1] + p.omega()[2] * p.omega()[0] *
85 (p.rinertia()[2] - p.rinertia()[0])) /
86 p.rinertia()[1];
87 if (p.can_rotate_around(2))
88 Wd[2] = (p.torque()[2] + p.omega()[0] * p.omega()[1] *
89 (p.rinertia()[0] - p.rinertia()[1])) /
90 p.rinertia()[2];
91
92 auto const S1 = Qd.norm2();
93
94 /* Calculate the second derivative of the quaternion. */
95 /* Eq. (8) @cite sonnenschein85a */
96 Qdd[0] =
97 0.5 * (-p.quat()[1] * Wd[0] - p.quat()[2] * Wd[1] - p.quat()[3] * Wd[2]) -
98 p.quat()[0] * S1;
99
100 Qdd[1] =
101 0.5 * (p.quat()[0] * Wd[0] - p.quat()[3] * Wd[1] + p.quat()[2] * Wd[2]) -
102 p.quat()[1] * S1;
103
104 Qdd[2] =
105 0.5 * (p.quat()[3] * Wd[0] + p.quat()[0] * Wd[1] - p.quat()[1] * Wd[2]) -
106 p.quat()[2] * S1;
107
108 Qdd[3] =
109 0.5 * (-p.quat()[2] * Wd[0] + p.quat()[1] * Wd[1] + p.quat()[0] * Wd[2]) -
110 p.quat()[3] * S1;
111
112 S[0] = S1;
113 S[1] = Utils::dot(Qd, Qdd);
114 S[2] = Qdd.norm2();
115}
116
117/**
118 * See @cite omelyan98a. Please note that ESPResSo uses scalar-first
119 * notation for quaternions, while @cite omelyan98a uses scalar-last
120 * notation.
121 *
122 * For very high angular velocities (e.g. if the product of @p time_step
123 * with the largest component of @ref ParticleMomentum::omega "p.omega()"
124 * is superior to ~2.0) and for @p time_step superior or equal to unity,
125 * the calculation might fail.
126 *
127 * \todo implement for fixed_coord_flag
128 */
129void propagate_omega_quat_particle(Particle &p, double time_step) {
130 assert(p.can_rotate());
131
132 Utils::Quaternion<double> Qd{}, Qdd{};
133 Utils::Vector3d S{}, Wd{};
134
135 // Clear rotational velocity for blocked rotation axes.
136 p.omega() = Utils::mask(p.rotation(), p.omega());
137
138 define_Qdd(p, Qd, Qdd, S, Wd);
139
140 auto const time_step_squared = time_step * time_step;
141 auto const time_step_half = 0.5 * time_step;
142
143 /* Eq. (12) @cite omelyan98a. */
144 auto const square =
145 1 - time_step_squared *
146 (S[0] +
147 time_step * (S[1] + time_step_half / 2. * (S[2] - S[0] * S[0])));
148 assert(square >= 0.);
149 auto const lambda = 1 - S[0] * 0.5 * time_step_squared - sqrt(square);
150
151 p.omega() += time_step_half * Wd;
152 p.quat() += time_step * (Qd + time_step_half * Qdd) - lambda * p.quat();
153
154 /* and rescale quaternion, so it is exactly of unit length */
155 auto const scale = p.quat().norm();
156 if (scale == 0) {
158 } else {
159 p.quat() /= scale;
160 }
161}
162
163void convert_torque_propagate_omega(Particle &p, double time_step) {
164 assert(p.can_rotate());
166
167 // Propagation of angular velocities
168 p.omega() += hadamard_division(0.5 * time_step * p.torque(), p.rinertia());
169
170 // zeroth estimate of omega
171 Utils::Vector3d omega_0 = p.omega();
172
173 /* if the tensor of inertia is isotropic, the following refinement is not
174 needed.
175 Otherwise repeat this loop 2-3 times depending on the required accuracy
176 */
177
178 auto const rinertia_diff_01 = p.rinertia()[0] - p.rinertia()[1];
179 auto const rinertia_diff_12 = p.rinertia()[1] - p.rinertia()[2];
180 auto const rinertia_diff_20 = p.rinertia()[2] - p.rinertia()[0];
181 for (int times = 0; times <= 5; times++) {
183
184 Wd[0] = p.omega()[1] * p.omega()[2] * rinertia_diff_12 / p.rinertia()[0];
185 Wd[1] = p.omega()[2] * p.omega()[0] * rinertia_diff_20 / p.rinertia()[1];
186 Wd[2] = p.omega()[0] * p.omega()[1] * rinertia_diff_01 / p.rinertia()[2];
187
188 p.omega() = omega_0 + (0.5 * time_step) * Wd;
189 }
190}
191
193 for (auto &p : particles) {
194 if (!p.can_rotate())
195 continue;
197 }
198}
199
200#endif // ESPRESSO_ROTATION
Vector implementation and trait types for boost qvm interoperability.
A range of particles.
T mask(std::unsigned_integral auto mask, T const &t)
Pick elements of a tuple-like by a bit mask.
Definition mask.hpp:54
void convert_initial_torques(const ParticleRange &particles)
Convert torques to the body-fixed frame before the integration loop.
Definition rotation.cpp:192
void propagate_omega_quat_particle(Particle &p, double time_step)
See .
Definition rotation.cpp:129
void convert_torque_propagate_omega(Particle &p, double time_step)
Definition rotation.cpp:163
static void define_Qdd(Particle const &p, Utils::Quaternion< double > &Qd, Utils::Quaternion< double > &Qdd, Utils::Vector3d &S, Utils::Vector3d &Wd)
Calculate the derivatives of the quaternion and angular acceleration for a given particle.
Definition rotation.cpp:60
This file contains all subroutines required to process rotational motion.
void convert_torque_to_body_frame_apply_fix(Particle &p)
Definition rotation.hpp:144
Struct holding all information for one particle.
Definition Particle.hpp:450
bool can_rotate() const
Definition Particle.hpp:515
auto const & rinertia() const
Definition Particle.hpp:587
auto const & quat() const
Definition Particle.hpp:532
auto const & rotation() const
Definition Particle.hpp:513
bool can_rotate_around(unsigned int const axis) const
Definition Particle.hpp:516
auto const & torque() const
Definition Particle.hpp:534
auto const & omega() const
Definition Particle.hpp:536
Quaternion representation.
static Quaternion< T > identity()
Construct an identity quaternion.
value_type norm2() const
Retrieve the square of the norm of the quaternion.