1#ifndef COLVAR_ROTATION_DERIVATIVE
2#define COLVAR_ROTATION_DERIVATIVE
4#include "colvartypes.h"
9template <typename T, typename std::enable_if<std::is_same<T, cvm::atom_pos>::value,
bool>::type =
true>
10inline void read_atom_coord(
11 size_t ia,
const std::vector<T>& pos,
18template <typename T, typename std::enable_if<std::is_same<T, cvm::atom>::value,
bool>::type =
true>
19inline void read_atom_coord(
20 size_t ia,
const std::vector<T>& pos,
28enum class rotation_derivative_dldq {
35inline constexpr rotation_derivative_dldq operator|(rotation_derivative_dldq Lhs, rotation_derivative_dldq Rhs) {
36 return static_cast<rotation_derivative_dldq
>(
37 static_cast<std::underlying_type<rotation_derivative_dldq>::type
>(Lhs) |
38 static_cast<std::underlying_type<rotation_derivative_dldq>::type
>(Rhs));
41inline constexpr bool operator&(rotation_derivative_dldq Lhs, rotation_derivative_dldq Rhs)
43 return (
static_cast<std::underlying_type<rotation_derivative_dldq>::type
>(Lhs) &
44 static_cast<std::underlying_type<rotation_derivative_dldq>::type
>(Rhs));
48template <
typename T1,
typename T2>
50 static_assert(std::is_same<T1, cvm::atom_pos>::value || std::is_same<T1, cvm::atom>::value,
51 "class template rotation_derivative only supports cvm::atom_pos or cvm::atom types.");
52 static_assert(std::is_same<T2, cvm::atom_pos>::value || std::is_same<T2, cvm::atom>::value,
53 "class template rotation_derivative only supports cvm::atom_pos or cvm::atom types.");
73 const std::vector<T1> &pos1,
74 const std::vector<T2> &pos2):
83 if (require_dl_dq & rotation_derivative_dldq::use_dl) {
102 if (require_dl_dq & rotation_derivative_dldq::use_dq) {
112 tmp_Q0Q0_L[0][0][0] = (Q1[0] * Q0[0]) / (L0-L1) * Q1[0] +
113 (Q2[0] * Q0[0]) / (L0-L2) * Q2[0] +
114 (Q3[0] * Q0[0]) / (L0-L3) * Q3[0];
115 tmp_Q0Q0_L[1][0][0] = (Q1[0] * Q0[0]) / (L0-L1) * Q1[1] +
116 (Q2[0] * Q0[0]) / (L0-L2) * Q2[1] +
117 (Q3[0] * Q0[0]) / (L0-L3) * Q3[1];
118 tmp_Q0Q0_L[2][0][0] = (Q1[0] * Q0[0]) / (L0-L1) * Q1[2] +
119 (Q2[0] * Q0[0]) / (L0-L2) * Q2[2] +
120 (Q3[0] * Q0[0]) / (L0-L3) * Q3[2];
121 tmp_Q0Q0_L[3][0][0] = (Q1[0] * Q0[0]) / (L0-L1) * Q1[3] +
122 (Q2[0] * Q0[0]) / (L0-L2) * Q2[3] +
123 (Q3[0] * Q0[0]) / (L0-L3) * Q3[3];
125 tmp_Q0Q0_L[0][0][1] = (Q1[0] * Q0[1]) / (L0-L1) * Q1[0] +
126 (Q2[0] * Q0[1]) / (L0-L2) * Q2[0] +
127 (Q3[0] * Q0[1]) / (L0-L3) * Q3[0];
128 tmp_Q0Q0_L[1][0][1] = (Q1[0] * Q0[1]) / (L0-L1) * Q1[1] +
129 (Q2[0] * Q0[1]) / (L0-L2) * Q2[1] +
130 (Q3[0] * Q0[1]) / (L0-L3) * Q3[1];
131 tmp_Q0Q0_L[2][0][1] = (Q1[0] * Q0[1]) / (L0-L1) * Q1[2] +
132 (Q2[0] * Q0[1]) / (L0-L2) * Q2[2] +
133 (Q3[0] * Q0[1]) / (L0-L3) * Q3[2];
134 tmp_Q0Q0_L[3][0][1] = (Q1[0] * Q0[1]) / (L0-L1) * Q1[3] +
135 (Q2[0] * Q0[1]) / (L0-L2) * Q2[3] +
136 (Q3[0] * Q0[1]) / (L0-L3) * Q3[3];
139 tmp_Q0Q0_L[0][0][2] = (Q1[0] * Q0[2]) / (L0-L1) * Q1[0] +
140 (Q2[0] * Q0[2]) / (L0-L2) * Q2[0] +
141 (Q3[0] * Q0[2]) / (L0-L3) * Q3[0];
142 tmp_Q0Q0_L[1][0][2] = (Q1[0] * Q0[2]) / (L0-L1) * Q1[1] +
143 (Q2[0] * Q0[2]) / (L0-L2) * Q2[1] +
144 (Q3[0] * Q0[2]) / (L0-L3) * Q3[1];
145 tmp_Q0Q0_L[2][0][2] = (Q1[0] * Q0[2]) / (L0-L1) * Q1[2] +
146 (Q2[0] * Q0[2]) / (L0-L2) * Q2[2] +
147 (Q3[0] * Q0[2]) / (L0-L3) * Q3[2];
148 tmp_Q0Q0_L[3][0][2] = (Q1[0] * Q0[2]) / (L0-L1) * Q1[3] +
149 (Q2[0] * Q0[2]) / (L0-L2) * Q2[3] +
150 (Q3[0] * Q0[2]) / (L0-L3) * Q3[3];
152 tmp_Q0Q0_L[0][0][3] = (Q1[0] * Q0[3]) / (L0-L1) * Q1[0] +
153 (Q2[0] * Q0[3]) / (L0-L2) * Q2[0] +
154 (Q3[0] * Q0[3]) / (L0-L3) * Q3[0];
155 tmp_Q0Q0_L[1][0][3] = (Q1[0] * Q0[3]) / (L0-L1) * Q1[1] +
156 (Q2[0] * Q0[3]) / (L0-L2) * Q2[1] +
157 (Q3[0] * Q0[3]) / (L0-L3) * Q3[1];
158 tmp_Q0Q0_L[2][0][3] = (Q1[0] * Q0[3]) / (L0-L1) * Q1[2] +
159 (Q2[0] * Q0[3]) / (L0-L2) * Q2[2] +
160 (Q3[0] * Q0[3]) / (L0-L3) * Q3[2];
161 tmp_Q0Q0_L[3][0][3] = (Q1[0] * Q0[3]) / (L0-L1) * Q1[3] +
162 (Q2[0] * Q0[3]) / (L0-L2) * Q2[3] +
163 (Q3[0] * Q0[3]) / (L0-L3) * Q3[3];
165 tmp_Q0Q0_L[0][1][0] = (Q1[1] * Q0[0]) / (L0-L1) * Q1[0] +
166 (Q2[1] * Q0[0]) / (L0-L2) * Q2[0] +
167 (Q3[1] * Q0[0]) / (L0-L3) * Q3[0];
168 tmp_Q0Q0_L[1][1][0] = (Q1[1] * Q0[0]) / (L0-L1) * Q1[1] +
169 (Q2[1] * Q0[0]) / (L0-L2) * Q2[1] +
170 (Q3[1] * Q0[0]) / (L0-L3) * Q3[1];
171 tmp_Q0Q0_L[2][1][0] = (Q1[1] * Q0[0]) / (L0-L1) * Q1[2] +
172 (Q2[1] * Q0[0]) / (L0-L2) * Q2[2] +
173 (Q3[1] * Q0[0]) / (L0-L3) * Q3[2];
174 tmp_Q0Q0_L[3][1][0] = (Q1[1] * Q0[0]) / (L0-L1) * Q1[3] +
175 (Q2[1] * Q0[0]) / (L0-L2) * Q2[3] +
176 (Q3[1] * Q0[0]) / (L0-L3) * Q3[3];
178 tmp_Q0Q0_L[0][1][1] = (Q1[1] * Q0[1]) / (L0-L1) * Q1[0] +
179 (Q2[1] * Q0[1]) / (L0-L2) * Q2[0] +
180 (Q3[1] * Q0[1]) / (L0-L3) * Q3[0];
181 tmp_Q0Q0_L[1][1][1] = (Q1[1] * Q0[1]) / (L0-L1) * Q1[1] +
182 (Q2[1] * Q0[1]) / (L0-L2) * Q2[1] +
183 (Q3[1] * Q0[1]) / (L0-L3) * Q3[1];
184 tmp_Q0Q0_L[2][1][1] = (Q1[1] * Q0[1]) / (L0-L1) * Q1[2] +
185 (Q2[1] * Q0[1]) / (L0-L2) * Q2[2] +
186 (Q3[1] * Q0[1]) / (L0-L3) * Q3[2];
187 tmp_Q0Q0_L[3][1][1] = (Q1[1] * Q0[1]) / (L0-L1) * Q1[3] +
188 (Q2[1] * Q0[1]) / (L0-L2) * Q2[3] +
189 (Q3[1] * Q0[1]) / (L0-L3) * Q3[3];
191 tmp_Q0Q0_L[0][1][2] = (Q1[1] * Q0[2]) / (L0-L1) * Q1[0] +
192 (Q2[1] * Q0[2]) / (L0-L2) * Q2[0] +
193 (Q3[1] * Q0[2]) / (L0-L3) * Q3[0];
194 tmp_Q0Q0_L[1][1][2] = (Q1[1] * Q0[2]) / (L0-L1) * Q1[1] +
195 (Q2[1] * Q0[2]) / (L0-L2) * Q2[1] +
196 (Q3[1] * Q0[2]) / (L0-L3) * Q3[1];
197 tmp_Q0Q0_L[2][1][2] = (Q1[1] * Q0[2]) / (L0-L1) * Q1[2] +
198 (Q2[1] * Q0[2]) / (L0-L2) * Q2[2] +
199 (Q3[1] * Q0[2]) / (L0-L3) * Q3[2];
200 tmp_Q0Q0_L[3][1][2] = (Q1[1] * Q0[2]) / (L0-L1) * Q1[3] +
201 (Q2[1] * Q0[2]) / (L0-L2) * Q2[3] +
202 (Q3[1] * Q0[2]) / (L0-L3) * Q3[3];
204 tmp_Q0Q0_L[0][1][3] = (Q1[1] * Q0[3]) / (L0-L1) * Q1[0] +
205 (Q2[1] * Q0[3]) / (L0-L2) * Q2[0] +
206 (Q3[1] * Q0[3]) / (L0-L3) * Q3[0];
207 tmp_Q0Q0_L[1][1][3] = (Q1[1] * Q0[3]) / (L0-L1) * Q1[1] +
208 (Q2[1] * Q0[3]) / (L0-L2) * Q2[1] +
209 (Q3[1] * Q0[3]) / (L0-L3) * Q3[1];
210 tmp_Q0Q0_L[2][1][3] = (Q1[1] * Q0[3]) / (L0-L1) * Q1[2] +
211 (Q2[1] * Q0[3]) / (L0-L2) * Q2[2] +
212 (Q3[1] * Q0[3]) / (L0-L3) * Q3[2];
213 tmp_Q0Q0_L[3][1][3] = (Q1[1] * Q0[3]) / (L0-L1) * Q1[3] +
214 (Q2[1] * Q0[3]) / (L0-L2) * Q2[3] +
215 (Q3[1] * Q0[3]) / (L0-L3) * Q3[3];
218 tmp_Q0Q0_L[0][2][0] = (Q1[2] * Q0[0]) / (L0-L1) * Q1[0] +
219 (Q2[2] * Q0[0]) / (L0-L2) * Q2[0] +
220 (Q3[2] * Q0[0]) / (L0-L3) * Q3[0];
221 tmp_Q0Q0_L[1][2][0] = (Q1[2] * Q0[0]) / (L0-L1) * Q1[1] +
222 (Q2[2] * Q0[0]) / (L0-L2) * Q2[1] +
223 (Q3[2] * Q0[0]) / (L0-L3) * Q3[1];
224 tmp_Q0Q0_L[2][2][0] = (Q1[2] * Q0[0]) / (L0-L1) * Q1[2] +
225 (Q2[2] * Q0[0]) / (L0-L2) * Q2[2] +
226 (Q3[2] * Q0[0]) / (L0-L3) * Q3[2];
227 tmp_Q0Q0_L[3][2][0] = (Q1[2] * Q0[0]) / (L0-L1) * Q1[3] +
228 (Q2[2] * Q0[0]) / (L0-L2) * Q2[3] +
229 (Q3[2] * Q0[0]) / (L0-L3) * Q3[3];
231 tmp_Q0Q0_L[0][2][1] = (Q1[2] * Q0[1]) / (L0-L1) * Q1[0] +
232 (Q2[2] * Q0[1]) / (L0-L2) * Q2[0] +
233 (Q3[2] * Q0[1]) / (L0-L3) * Q3[0];
234 tmp_Q0Q0_L[1][2][1] = (Q1[2] * Q0[1]) / (L0-L1) * Q1[1] +
235 (Q2[2] * Q0[1]) / (L0-L2) * Q2[1] +
236 (Q3[2] * Q0[1]) / (L0-L3) * Q3[1];
237 tmp_Q0Q0_L[2][2][1] = (Q1[2] * Q0[1]) / (L0-L1) * Q1[2] +
238 (Q2[2] * Q0[1]) / (L0-L2) * Q2[2] +
239 (Q3[2] * Q0[1]) / (L0-L3) * Q3[2];
240 tmp_Q0Q0_L[3][2][1] = (Q1[2] * Q0[1]) / (L0-L1) * Q1[3] +
241 (Q2[2] * Q0[1]) / (L0-L2) * Q2[3] +
242 (Q3[2] * Q0[1]) / (L0-L3) * Q3[3];
244 tmp_Q0Q0_L[0][2][2] = (Q1[2] * Q0[2]) / (L0-L1) * Q1[0] +
245 (Q2[2] * Q0[2]) / (L0-L2) * Q2[0] +
246 (Q3[2] * Q0[2]) / (L0-L3) * Q3[0];
247 tmp_Q0Q0_L[1][2][2] = (Q1[2] * Q0[2]) / (L0-L1) * Q1[1] +
248 (Q2[2] * Q0[2]) / (L0-L2) * Q2[1] +
249 (Q3[2] * Q0[2]) / (L0-L3) * Q3[1];
250 tmp_Q0Q0_L[2][2][2] = (Q1[2] * Q0[2]) / (L0-L1) * Q1[2] +
251 (Q2[2] * Q0[2]) / (L0-L2) * Q2[2] +
252 (Q3[2] * Q0[2]) / (L0-L3) * Q3[2];
253 tmp_Q0Q0_L[3][2][2] = (Q1[2] * Q0[2]) / (L0-L1) * Q1[3] +
254 (Q2[2] * Q0[2]) / (L0-L2) * Q2[3] +
255 (Q3[2] * Q0[2]) / (L0-L3) * Q3[3];
257 tmp_Q0Q0_L[0][2][3] = (Q1[2] * Q0[3]) / (L0-L1) * Q1[0] +
258 (Q2[2] * Q0[3]) / (L0-L2) * Q2[0] +
259 (Q3[2] * Q0[3]) / (L0-L3) * Q3[0];
260 tmp_Q0Q0_L[1][2][3] = (Q1[2] * Q0[3]) / (L0-L1) * Q1[1] +
261 (Q2[2] * Q0[3]) / (L0-L2) * Q2[1] +
262 (Q3[2] * Q0[3]) / (L0-L3) * Q3[1];
263 tmp_Q0Q0_L[2][2][3] = (Q1[2] * Q0[3]) / (L0-L1) * Q1[2] +
264 (Q2[2] * Q0[3]) / (L0-L2) * Q2[2] +
265 (Q3[2] * Q0[3]) / (L0-L3) * Q3[2];
266 tmp_Q0Q0_L[3][2][3] = (Q1[2] * Q0[3]) / (L0-L1) * Q1[3] +
267 (Q2[2] * Q0[3]) / (L0-L2) * Q2[3] +
268 (Q3[2] * Q0[3]) / (L0-L3) * Q3[3];
270 tmp_Q0Q0_L[0][3][0] = (Q1[3] * Q0[0]) / (L0-L1) * Q1[0] +
271 (Q2[3] * Q0[0]) / (L0-L2) * Q2[0] +
272 (Q3[3] * Q0[0]) / (L0-L3) * Q3[0];
273 tmp_Q0Q0_L[1][3][0] = (Q1[3] * Q0[0]) / (L0-L1) * Q1[1] +
274 (Q2[3] * Q0[0]) / (L0-L2) * Q2[1] +
275 (Q3[3] * Q0[0]) / (L0-L3) * Q3[1];
276 tmp_Q0Q0_L[2][3][0] = (Q1[3] * Q0[0]) / (L0-L1) * Q1[2] +
277 (Q2[3] * Q0[0]) / (L0-L2) * Q2[2] +
278 (Q3[3] * Q0[0]) / (L0-L3) * Q3[2];
279 tmp_Q0Q0_L[3][3][0] = (Q1[3] * Q0[0]) / (L0-L1) * Q1[3] +
280 (Q2[3] * Q0[0]) / (L0-L2) * Q2[3] +
281 (Q3[3] * Q0[0]) / (L0-L3) * Q3[3];
283 tmp_Q0Q0_L[0][3][1] = (Q1[3] * Q0[1]) / (L0-L1) * Q1[0] +
284 (Q2[3] * Q0[1]) / (L0-L2) * Q2[0] +
285 (Q3[3] * Q0[1]) / (L0-L3) * Q3[0];
286 tmp_Q0Q0_L[1][3][1] = (Q1[3] * Q0[1]) / (L0-L1) * Q1[1] +
287 (Q2[3] * Q0[1]) / (L0-L2) * Q2[1] +
288 (Q3[3] * Q0[1]) / (L0-L3) * Q3[1];
289 tmp_Q0Q0_L[2][3][1] = (Q1[3] * Q0[1]) / (L0-L1) * Q1[2] +
290 (Q2[3] * Q0[1]) / (L0-L2) * Q2[2] +
291 (Q3[3] * Q0[1]) / (L0-L3) * Q3[2];
292 tmp_Q0Q0_L[3][3][1] = (Q1[3] * Q0[1]) / (L0-L1) * Q1[3] +
293 (Q2[3] * Q0[1]) / (L0-L2) * Q2[3] +
294 (Q3[3] * Q0[1]) / (L0-L3) * Q3[3];
296 tmp_Q0Q0_L[0][3][2] = (Q1[3] * Q0[2]) / (L0-L1) * Q1[0] +
297 (Q2[3] * Q0[2]) / (L0-L2) * Q2[0] +
298 (Q3[3] * Q0[2]) / (L0-L3) * Q3[0];
299 tmp_Q0Q0_L[1][3][2] = (Q1[3] * Q0[2]) / (L0-L1) * Q1[1] +
300 (Q2[3] * Q0[2]) / (L0-L2) * Q2[1] +
301 (Q3[3] * Q0[2]) / (L0-L3) * Q3[1];
302 tmp_Q0Q0_L[2][3][2] = (Q1[3] * Q0[2]) / (L0-L1) * Q1[2] +
303 (Q2[3] * Q0[2]) / (L0-L2) * Q2[2] +
304 (Q3[3] * Q0[2]) / (L0-L3) * Q3[2];
305 tmp_Q0Q0_L[3][3][2] = (Q1[3] * Q0[2]) / (L0-L1) * Q1[3] +
306 (Q2[3] * Q0[2]) / (L0-L2) * Q2[3] +
307 (Q3[3] * Q0[2]) / (L0-L3) * Q3[3];
309 tmp_Q0Q0_L[0][3][3] = (Q1[3] * Q0[3]) / (L0-L1) * Q1[0] +
310 (Q2[3] * Q0[3]) / (L0-L2) * Q2[0] +
311 (Q3[3] * Q0[3]) / (L0-L3) * Q3[0];
312 tmp_Q0Q0_L[1][3][3] = (Q1[3] * Q0[3]) / (L0-L1) * Q1[1] +
313 (Q2[3] * Q0[3]) / (L0-L2) * Q2[1] +
314 (Q3[3] * Q0[3]) / (L0-L3) * Q3[1];
315 tmp_Q0Q0_L[2][3][3] = (Q1[3] * Q0[3]) / (L0-L1) * Q1[2] +
316 (Q2[3] * Q0[3]) / (L0-L2) * Q2[2] +
317 (Q3[3] * Q0[3]) / (L0-L3) * Q3[2];
318 tmp_Q0Q0_L[3][3][3] = (Q1[3] * Q0[3]) / (L0-L1) * Q1[3] +
319 (Q2[3] * Q0[3]) / (L0-L2) * Q2[3] +
320 (Q3[3] * Q0[3]) / (L0-L3) * Q3[3];
335 if (ds_out !=
nullptr) {
338 for (
int i = 0; i < 4; ++i) {
339 for (
int j = 0; j < 4; ++j) {
340 (*ds_out)[i][j] = ds[i][j];
344 if (dl0_out !=
nullptr) {
353 *dl0_out =
tmp_Q0Q0[0][0] * ds[0][0] +
370 if (dq0_out !=
nullptr) {
372 if (dq0_out->size() != 4) dq0_out->resize(4);
386 (*dq0_out)[0] = tmp_Q0Q0_L[0][0][0] * ds[0][0] +
387 tmp_Q0Q0_L[0][0][1] * ds[0][1] +
388 tmp_Q0Q0_L[0][0][2] * ds[0][2] +
389 tmp_Q0Q0_L[0][0][3] * ds[0][3] +
390 tmp_Q0Q0_L[0][1][0] * ds[1][0] +
391 tmp_Q0Q0_L[0][1][1] * ds[1][1] +
392 tmp_Q0Q0_L[0][1][2] * ds[1][2] +
393 tmp_Q0Q0_L[0][1][3] * ds[1][3] +
394 tmp_Q0Q0_L[0][2][0] * ds[2][0] +
395 tmp_Q0Q0_L[0][2][1] * ds[2][1] +
396 tmp_Q0Q0_L[0][2][2] * ds[2][2] +
397 tmp_Q0Q0_L[0][2][3] * ds[2][3] +
398 tmp_Q0Q0_L[0][3][0] * ds[3][0] +
399 tmp_Q0Q0_L[0][3][1] * ds[3][1] +
400 tmp_Q0Q0_L[0][3][2] * ds[3][2] +
401 tmp_Q0Q0_L[0][3][3] * ds[3][3];
403 (*dq0_out)[1] = tmp_Q0Q0_L[1][0][0] * ds[0][0] +
404 tmp_Q0Q0_L[1][0][1] * ds[0][1] +
405 tmp_Q0Q0_L[1][0][2] * ds[0][2] +
406 tmp_Q0Q0_L[1][0][3] * ds[0][3] +
407 tmp_Q0Q0_L[1][1][0] * ds[1][0] +
408 tmp_Q0Q0_L[1][1][1] * ds[1][1] +
409 tmp_Q0Q0_L[1][1][2] * ds[1][2] +
410 tmp_Q0Q0_L[1][1][3] * ds[1][3] +
411 tmp_Q0Q0_L[1][2][0] * ds[2][0] +
412 tmp_Q0Q0_L[1][2][1] * ds[2][1] +
413 tmp_Q0Q0_L[1][2][2] * ds[2][2] +
414 tmp_Q0Q0_L[1][2][3] * ds[2][3] +
415 tmp_Q0Q0_L[1][3][0] * ds[3][0] +
416 tmp_Q0Q0_L[1][3][1] * ds[3][1] +
417 tmp_Q0Q0_L[1][3][2] * ds[3][2] +
418 tmp_Q0Q0_L[1][3][3] * ds[3][3];
420 (*dq0_out)[2] = tmp_Q0Q0_L[2][0][0] * ds[0][0] +
421 tmp_Q0Q0_L[2][0][1] * ds[0][1] +
422 tmp_Q0Q0_L[2][0][2] * ds[0][2] +
423 tmp_Q0Q0_L[2][0][3] * ds[0][3] +
424 tmp_Q0Q0_L[2][1][0] * ds[1][0] +
425 tmp_Q0Q0_L[2][1][1] * ds[1][1] +
426 tmp_Q0Q0_L[2][1][2] * ds[1][2] +
427 tmp_Q0Q0_L[2][1][3] * ds[1][3] +
428 tmp_Q0Q0_L[2][2][0] * ds[2][0] +
429 tmp_Q0Q0_L[2][2][1] * ds[2][1] +
430 tmp_Q0Q0_L[2][2][2] * ds[2][2] +
431 tmp_Q0Q0_L[2][2][3] * ds[2][3] +
432 tmp_Q0Q0_L[2][3][0] * ds[3][0] +
433 tmp_Q0Q0_L[2][3][1] * ds[3][1] +
434 tmp_Q0Q0_L[2][3][2] * ds[3][2] +
435 tmp_Q0Q0_L[2][3][3] * ds[3][3];
437 (*dq0_out)[3] = tmp_Q0Q0_L[3][0][0] * ds[0][0] +
438 tmp_Q0Q0_L[3][0][1] * ds[0][1] +
439 tmp_Q0Q0_L[3][0][2] * ds[0][2] +
440 tmp_Q0Q0_L[3][0][3] * ds[0][3] +
441 tmp_Q0Q0_L[3][1][0] * ds[1][0] +
442 tmp_Q0Q0_L[3][1][1] * ds[1][1] +
443 tmp_Q0Q0_L[3][1][2] * ds[1][2] +
444 tmp_Q0Q0_L[3][1][3] * ds[1][3] +
445 tmp_Q0Q0_L[3][2][0] * ds[2][0] +
446 tmp_Q0Q0_L[3][2][1] * ds[2][1] +
447 tmp_Q0Q0_L[3][2][2] * ds[2][2] +
448 tmp_Q0Q0_L[3][2][3] * ds[2][3] +
449 tmp_Q0Q0_L[3][3][0] * ds[3][0] +
450 tmp_Q0Q0_L[3][3][1] * ds[3][1] +
451 tmp_Q0Q0_L[3][3][2] * ds[3][2] +
452 tmp_Q0Q0_L[3][3][3] * ds[3][3];
469 if (dl0_1_out ==
nullptr && dq0_1_out ==
nullptr)
return;
472 read_atom_coord(ia,
m_pos2, &a2x, &a2y, &a2z);
474 ds_1[0][0].
set( a2x, a2y, a2z);
475 ds_1[1][0].
set( 0.0, a2z, -a2y);
476 ds_1[0][1] = ds_1[1][0];
477 ds_1[2][0].
set(-a2z, 0.0, a2x);
478 ds_1[0][2] = ds_1[2][0];
479 ds_1[3][0].
set( a2y, -a2x, 0.0);
480 ds_1[0][3] = ds_1[3][0];
481 ds_1[1][1].
set( a2x, -a2y, -a2z);
482 ds_1[2][1].
set( a2y, a2x, 0.0);
483 ds_1[1][2] = ds_1[2][1];
484 ds_1[3][1].
set( a2z, 0.0, a2x);
485 ds_1[1][3] = ds_1[3][1];
486 ds_1[2][2].
set(-a2x, a2y, -a2z);
487 ds_1[3][2].
set( 0.0, a2z, a2y);
488 ds_1[2][3] = ds_1[3][2];
489 ds_1[3][3].
set(-a2x, -a2y, a2z);
506 if (dl0_2_out ==
nullptr && dq0_2_out ==
nullptr)
return;
509 read_atom_coord(ia,
m_pos1, &a1x, &a1y, &a1z);
511 ds_2[0][0].
set( a1x, a1y, a1z);
512 ds_2[1][0].
set( 0.0, -a1z, a1y);
513 ds_2[0][1] = ds_2[1][0];
514 ds_2[2][0].
set( a1z, 0.0, -a1x);
515 ds_2[0][2] = ds_2[2][0];
516 ds_2[3][0].
set(-a1y, a1x, 0.0);
517 ds_2[0][3] = ds_2[3][0];
518 ds_2[1][1].
set( a1x, -a1y, -a1z);
519 ds_2[2][1].
set( a1y, a1x, 0.0);
520 ds_2[1][2] = ds_2[2][1];
521 ds_2[3][1].
set( a1z, 0.0, a1x);
522 ds_2[1][3] = ds_2[3][1];
523 ds_2[2][2].
set(-a1x, a1y, -a1z);
524 ds_2[3][2].
set( 0.0, a1z, a1y);
525 ds_2[2][3] = ds_2[3][2];
526 ds_2[3][3].
set(-a1x, -a1y, a1z);
537template<
typename T1,
typename T2>
540 const std::vector<T1> &pos1,
541 const std::vector<T2> &pos2) {
542 static_assert(std::is_same<T1, cvm::atom_pos>::value || std::is_same<T1, cvm::atom>::value,
"");
543 static_assert(std::is_same<T2, cvm::atom_pos>::value || std::is_same<T2, cvm::atom>::value,
"");
579 reinterpret_cast<MathEigen::Jacobi<
cvm::real,
583 deriv.
prepare_derivative(rotation_derivative_dldq::use_dl | rotation_derivative_dldq::use_dq);
587 for (
size_t ia = 0; ia < pos2.size(); ++ia) {
594 for (
size_t comp = 0; comp < 3; comp++) {
596 std::memset(S_new_eigval, 0,
sizeof(
cvm::real) * 4);
597 std::memset(S_new_eigvec, 0,
sizeof(
cvm::real) * 4 * 4);
598 for (
size_t i = 0; i < 4; i++) {
599 for (
size_t j = 0; j < 4; j++) {
605 ecalc->Diagonalize(S_new, S_new_eigval, S_new_eigvec);
607 NR::diagonalize_matrix(S_new, S_new_eigval, S_new_eigvec);
609 cvm::real const &L0_new = S_new_eigval[0];
618 cvm::log(
"|(l_0+dl_0) - l_0^new|/l_0 = "+
620 ", |(q_0+dq_0) - q_0^new| = "+
Arbitrary size array (two dimensions) suitable for linear algebra operations (i.e....
Definition: colvartypes.h:376
1-dimensional vector of real numbers with four components and a quaternion algebra
Definition: colvartypes.h:958
cvm::real inner(cvm::quaternion const &Q2) const
Inner product (as a 4-d vector) with Q2; requires match() if the largest overlap is looked for.
Definition: colvartypes.h:1292
A rotation between two sets of coordinates (for the moment a wrapper for colvarmodule::quaternion)
Definition: colvartypes.h:1314
cvm::real S_eigval[4]
Eigenvalues of S.
Definition: colvartypes.h:1323
cvm::real S_backup[4][4]
Used for debugging gradients.
Definition: colvartypes.h:1329
cvm::real S_eigvec[4][4]
Eigenvectors of S.
Definition: colvartypes.h:1326
void * jacobi
Pointer to instance of Jacobi solver.
Definition: colvartypes.h:1505
vector of real numbers with three components
Definition: colvartypes.h:727
void set(cvm::real value)
Set all components to a scalar.
Definition: colvartypes.h:760
Arbitrary size array (one dimensions) suitable for linear algebra operations (i.e....
Definition: colvartypes.h:37
double real
Defining an abstract real number allows to switch precision.
Definition: colvarmodule.h:95
static void log(std::string const &message, int min_log_level=10)
Definition: colvarmodule.cpp:1970
static size_t const cv_prec
Number of digits to represent a collective variables value(s)
Definition: colvarmodule.h:664
static size_t const cv_width
Number of characters to represent a collective variables value(s)
Definition: colvarmodule.h:666
static real fabs(real const &x)
Reimplemented to work around MS compiler issues.
Definition: colvarmodule.h:127
static std::string to_str(char const *s)
Convert to string for output purposes.
Definition: colvarmodule.cpp:2393
static real debug_gradients_step_size
Finite difference step size (if there is no dynamics, or if gradients need to be tested independently...
Definition: colvarmodule.h:250
Helper class for calculating the derivative of rotation.
Definition: colvar_rotation_derivative.h:49
void calc_derivative_impl(const cvm::rvector(&ds)[4][4], cvm::rvector *const dl0_out, cvm::vector1d< cvm::rvector > *const dq0_out, cvm::matrix2d< cvm::rvector > *const ds_out) const
Actual implementation of the derivative calculation.
Definition: colvar_rotation_derivative.h:330
void prepare_derivative(rotation_derivative_dldq require_dl_dq)
This function must be called before calc_derivative_wrt_group1 and calc_derivative_wrt_group2 in orde...
Definition: colvar_rotation_derivative.h:82
const std::vector< T1 > & m_pos1
Reference to the atom positions of group 1.
Definition: colvar_rotation_derivative.h:57
void calc_derivative_wrt_group2(size_t ia, cvm::rvector *const dl0_2_out=nullptr, cvm::vector1d< cvm::rvector > *const dq0_2_out=nullptr, cvm::matrix2d< cvm::rvector > *const ds_2_out=nullptr) const
Calculate the derivatives of S, the leading eigenvalue L and the leading eigenvector Q with respect t...
Definition: colvar_rotation_derivative.h:502
const cvm::rotation & m_rot
Reference to the rotation.
Definition: colvar_rotation_derivative.h:55
cvm::real tmp_Q0Q0[4][4]
Temporary variable that will be updated if prepare_derivative called.
Definition: colvar_rotation_derivative.h:61
rotation_derivative(const cvm::rotation &rot, const std::vector< T1 > &pos1, const std::vector< T2 > &pos2)
Constructor of the cvm::rotation::derivative class.
Definition: colvar_rotation_derivative.h:71
void calc_derivative_wrt_group1(size_t ia, cvm::rvector *const dl0_1_out=nullptr, cvm::vector1d< cvm::rvector > *const dq0_1_out=nullptr, cvm::matrix2d< cvm::rvector > *const ds_1_out=nullptr) const
Calculate the derivatives of S, the leading eigenvalue L and the leading eigenvector Q with respect t...
Definition: colvar_rotation_derivative.h:465
const std::vector< T2 > & m_pos2
Reference to the atom positions of group 2.
Definition: colvar_rotation_derivative.h:59