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 "rotation.hpp"
35
36#ifdef ROTATION
37
38#include <utils/Vector.hpp>
39#include <utils/mask.hpp>
40
41#include <cassert>
42#include <cmath>
43
44/** @brief Calculate the derivatives of the quaternion and angular
45 * acceleration for a given particle.
46 * See @cite sonnenschein85a. Please note that ESPResSo uses scalar-first
47 * notation for quaternions, while @cite sonnenschein85a uses scalar-last
48 * notation.
49 * @param[in] p Particle
50 * @param[out] Qd First derivative of the particle quaternion
51 * @param[out] Qdd Second derivative of the particle quaternion
52 * @param[out] S Function of @p Qd and @p Qdd, used to evaluate the
53 * Lagrange parameter lambda
54 * @param[out] Wd Angular acceleration of the particle
55 */
58 Utils::Vector3d &Wd) {
59 /* calculate the first derivative of the quaternion */
60 /* Eq. (4) @cite sonnenschein85a */
61 Qd[0] = 0.5 * (-p.quat()[1] * p.omega()[0] - p.quat()[2] * p.omega()[1] -
62 p.quat()[3] * p.omega()[2]);
63
64 Qd[1] = 0.5 * (p.quat()[0] * p.omega()[0] - p.quat()[3] * p.omega()[1] +
65 p.quat()[2] * p.omega()[2]);
66
67 Qd[2] = 0.5 * (p.quat()[3] * p.omega()[0] + p.quat()[0] * p.omega()[1] -
68 p.quat()[1] * p.omega()[2]);
69
70 Qd[3] = 0.5 * (-p.quat()[2] * p.omega()[0] + p.quat()[1] * p.omega()[1] +
71 p.quat()[0] * p.omega()[2]);
72
73 /* Calculate the angular acceleration. */
74 /* Eq. (5) @cite sonnenschein85a */
75 if (p.can_rotate_around(0))
76 Wd[0] = (p.torque()[0] + p.omega()[1] * p.omega()[2] *
77 (p.rinertia()[1] - p.rinertia()[2])) /
78 p.rinertia()[0];
79 if (p.can_rotate_around(1))
80 Wd[1] = (p.torque()[1] + p.omega()[2] * p.omega()[0] *
81 (p.rinertia()[2] - p.rinertia()[0])) /
82 p.rinertia()[1];
83 if (p.can_rotate_around(2))
84 Wd[2] = (p.torque()[2] + p.omega()[0] * p.omega()[1] *
85 (p.rinertia()[0] - p.rinertia()[1])) /
86 p.rinertia()[2];
87
88 auto const S1 = Qd.norm2();
89
90 /* Calculate the second derivative of the quaternion. */
91 /* Eq. (8) @cite sonnenschein85a */
92 Qdd[0] =
93 0.5 * (-p.quat()[1] * Wd[0] - p.quat()[2] * Wd[1] - p.quat()[3] * Wd[2]) -
94 p.quat()[0] * S1;
95
96 Qdd[1] =
97 0.5 * (p.quat()[0] * Wd[0] - p.quat()[3] * Wd[1] + p.quat()[2] * Wd[2]) -
98 p.quat()[1] * S1;
99
100 Qdd[2] =
101 0.5 * (p.quat()[3] * Wd[0] + p.quat()[0] * Wd[1] - p.quat()[1] * Wd[2]) -
102 p.quat()[2] * S1;
103
104 Qdd[3] =
105 0.5 * (-p.quat()[2] * Wd[0] + p.quat()[1] * Wd[1] + p.quat()[0] * Wd[2]) -
106 p.quat()[3] * S1;
107
108 S[0] = S1;
109 S[1] = Utils::dot(Qd, Qdd);
110 S[2] = Qdd.norm2();
111}
112
113/**
114 * See @cite omelyan98a. Please note that ESPResSo uses scalar-first
115 * notation for quaternions, while @cite omelyan98a uses scalar-last
116 * notation.
117 *
118 * For very high angular velocities (e.g. if the product of @p time_step
119 * with the largest component of @ref ParticleMomentum::omega "p.omega()"
120 * is superior to ~2.0) and for @p time_step superior or equal to unity,
121 * the calculation might fail.
122 *
123 * \todo implement for fixed_coord_flag
124 */
125void propagate_omega_quat_particle(Particle &p, double time_step) {
126 assert(p.can_rotate());
127
128 Utils::Quaternion<double> Qd{}, Qdd{};
129 Utils::Vector3d S{}, Wd{};
130
131 // Clear rotational velocity for blocked rotation axes.
132 p.omega() = Utils::mask(p.rotation(), p.omega());
133
134 define_Qdd(p, Qd, Qdd, S, Wd);
135
136 auto const time_step_squared = time_step * time_step;
137 auto const time_step_half = 0.5 * time_step;
138
139 /* Eq. (12) @cite omelyan98a. */
140 auto const square =
141 1 - time_step_squared *
142 (S[0] +
143 time_step * (S[1] + time_step_half / 2. * (S[2] - S[0] * S[0])));
144 assert(square >= 0.);
145 auto const lambda = 1 - S[0] * 0.5 * time_step_squared - sqrt(square);
146
147 p.omega() += time_step_half * Wd;
148 p.quat() += time_step * (Qd + time_step_half * Qdd) - lambda * p.quat();
149
150 /* and rescale quaternion, so it is exactly of unit length */
151 auto const scale = p.quat().norm();
152 if (scale == 0) {
154 } else {
155 p.quat() /= scale;
156 }
157}
158
159void convert_torque_propagate_omega(Particle &p, double time_step) {
160 assert(p.can_rotate());
162
163 // Propagation of angular velocities
164 p.omega() += hadamard_division(0.5 * time_step * p.torque(), p.rinertia());
165
166 // zeroth estimate of omega
167 Utils::Vector3d omega_0 = p.omega();
168
169 /* if the tensor of inertia is isotropic, the following refinement is not
170 needed.
171 Otherwise repeat this loop 2-3 times depending on the required accuracy
172 */
173
174 const double rinertia_diff_01 = p.rinertia()[0] - p.rinertia()[1];
175 const double rinertia_diff_12 = p.rinertia()[1] - p.rinertia()[2];
176 const double rinertia_diff_20 = p.rinertia()[2] - p.rinertia()[0];
177 for (int times = 0; times <= 5; times++) {
179
180 Wd[0] = p.omega()[1] * p.omega()[2] * rinertia_diff_12 / p.rinertia()[0];
181 Wd[1] = p.omega()[2] * p.omega()[0] * rinertia_diff_20 / p.rinertia()[1];
182 Wd[2] = p.omega()[0] * p.omega()[1] * rinertia_diff_01 / p.rinertia()[2];
183
184 p.omega() = omega_0 + (0.5 * time_step) * Wd;
185 }
186}
187
189 for (auto &p : particles) {
190 if (!p.can_rotate())
191 continue;
193 }
194}
195
196#endif // ROTATION
Vector implementation and trait types for boost qvm interoperability.
A range of particles.
auto mask(Integral mask, T t) -> std::enable_if_t< std::is_unsigned_v< Integral > &&(size_in_bits< Integral >::value >=tuple_size< T >::value), T >
Pick elements of a tuple-like by a bit mask.
Definition mask.hpp:57
void convert_initial_torques(const ParticleRange &particles)
Convert torques to the body-fixed frame before the integration loop.
Definition rotation.cpp:188
void propagate_omega_quat_particle(Particle &p, double time_step)
See .
Definition rotation.cpp:125
void convert_torque_propagate_omega(Particle &p, double time_step)
Definition rotation.cpp:159
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:56
This file contains all subroutines required to process rotational motion.
void convert_torque_to_body_frame_apply_fix(Particle &p)
Definition rotation.hpp:143
Struct holding all information for one particle.
Definition Particle.hpp:393
bool can_rotate() const
Definition Particle.hpp:458
auto const & rinertia() const
Definition Particle.hpp:500
auto const & quat() const
Definition Particle.hpp:475
auto const & rotation() const
Definition Particle.hpp:456
bool can_rotate_around(unsigned int const axis) const
Definition Particle.hpp:459
auto const & torque() const
Definition Particle.hpp:477
auto const & omega() const
Definition Particle.hpp:479
Quaternion representation.
static Quaternion< T > identity()
Construct an identity quaternion.
value_type norm2() const
Retrieve the square of the norm of the quaternion.