1 /* Copyright (C) 2015 Atsushi Togo */
2 /* All rights reserved. */
3
4 /* This file is part of phonopy. */
5
6 /* Redistribution and use in source and binary forms, with or without */
7 /* modification, are permitted provided that the following conditions */
8 /* are met: */
9
10 /* * Redistributions of source code must retain the above copyright */
11 /* notice, this list of conditions and the following disclaimer. */
12
13 /* * Redistributions in binary form must reproduce the above copyright */
14 /* notice, this list of conditions and the following disclaimer in */
15 /* the documentation and/or other materials provided with the */
16 /* distribution. */
17
18 /* * Neither the name of the phonopy project nor the names of its */
19 /* contributors may be used to endorse or promote products derived */
20 /* from this software without specific prior written permission. */
21
22 /* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */
23 /* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT */
24 /* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS */
25 /* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE */
26 /* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, */
27 /* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, */
28 /* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; */
29 /* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER */
30 /* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT */
31 /* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN */
32 /* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE */
33 /* POSSIBILITY OF SUCH DAMAGE. */
34
35 #include <math.h>
36 #include <stdlib.h>
37 #include "dynmat.h"
38 #define PI 3.14159265358979323846
39
40 static void get_dynmat_ij(double *dynamical_matrix,
41 const long num_patom,
42 const long num_satom,
43 const double *fc,
44 const double q[3],
45 const double (*svecs)[3],
46 const long (*multi)[2],
47 const double *mass,
48 const long *s2p_map,
49 const long *p2s_map,
50 const double (*charge_sum)[3][3],
51 const long i,
52 const long j);
53 static void get_dm(double dm_real[3][3],
54 double dm_imag[3][3],
55 const long num_patom,
56 const long num_satom,
57 const double *fc,
58 const double q[3],
59 const double (*svecs)[3],
60 const long (*multi)[2],
61 const long *p2s_map,
62 const double (*charge_sum)[3][3],
63 const long i,
64 const long j,
65 const long k);
66 static double get_dielectric_part(const double q_cart[3],
67 const double dielectric[3][3]);
68 static void get_KK(double *dd_part, /* [natom, 3, natom, 3, (real,imag)] */
69 const double (*G_list)[3], /* [num_G, 3] */
70 const long num_G,
71 const long num_patom,
72 const double q_cart[3],
73 const double *q_direction_cart,
74 const double dielectric[3][3],
75 const double (*pos)[3], /* [num_patom, 3] */
76 const double lambda,
77 const double tolerance);
78 static void make_Hermitian(double *mat, const long num_band);
79 static void multiply_borns(double *dd,
80 const double *dd_in,
81 const long num_patom,
82 const double (*born)[3][3]);
83
dym_get_dynamical_matrix_at_q(double * dynamical_matrix,const long num_patom,const long num_satom,const double * fc,const double q[3],const double (* svecs)[3],const long (* multi)[2],const double * mass,const long * s2p_map,const long * p2s_map,const double (* charge_sum)[3][3],const long with_openmp)84 long dym_get_dynamical_matrix_at_q(double *dynamical_matrix,
85 const long num_patom,
86 const long num_satom,
87 const double *fc,
88 const double q[3],
89 const double (*svecs)[3],
90 const long (*multi)[2],
91 const double *mass,
92 const long *s2p_map,
93 const long *p2s_map,
94 const double (*charge_sum)[3][3],
95 const long with_openmp)
96 {
97 long i, j, ij;
98
99 if (with_openmp) {
100 #ifdef PHPYOPENMP
101 #pragma omp parallel for
102 #endif
103 for (ij = 0; ij < num_patom * num_patom ; ij++) {
104 get_dynmat_ij(dynamical_matrix,
105 num_patom,
106 num_satom,
107 fc,
108 q,
109 svecs,
110 multi,
111 mass,
112 s2p_map,
113 p2s_map,
114 charge_sum,
115 ij / num_patom, /* i */
116 ij % num_patom); /* j */
117 }
118 } else {
119 for (i = 0; i < num_patom; i++) {
120 for (j = 0; j < num_patom; j++) {
121 get_dynmat_ij(dynamical_matrix,
122 num_patom,
123 num_satom,
124 fc,
125 q,
126 svecs,
127 multi,
128 mass,
129 s2p_map,
130 p2s_map,
131 charge_sum,
132 i,
133 j);
134 }
135 }
136 }
137
138 make_Hermitian(dynamical_matrix, num_patom * 3);
139
140 return 0;
141 }
142
dym_get_recip_dipole_dipole(double * dd,const double * dd_q0,const double (* G_list)[3],const long num_G,const long num_patom,const double q_cart[3],const double * q_direction_cart,const double (* born)[3][3],const double dielectric[3][3],const double (* pos)[3],const double factor,const double lambda,const double tolerance)143 void dym_get_recip_dipole_dipole(double *dd, /* [natom, 3, natom, 3, (real,imag)] */
144 const double *dd_q0, /* [natom, 3, 3, (real,imag)] */
145 const double (*G_list)[3], /* [num_G, 3] */
146 const long num_G,
147 const long num_patom,
148 const double q_cart[3],
149 const double *q_direction_cart, /* must be pointer */
150 const double (*born)[3][3],
151 const double dielectric[3][3],
152 const double (*pos)[3], /* [num_patom, 3] */
153 const double factor, /* 4pi/V*unit-conv */
154 const double lambda,
155 const double tolerance)
156 {
157 long i, k, l, adrs, adrs_sum;
158 double *dd_tmp;
159
160 dd_tmp = NULL;
161 dd_tmp = (double*) malloc(sizeof(double) * num_patom * num_patom * 18);
162
163 for (i = 0; i < num_patom * num_patom * 18; i++) {
164 dd[i] = 0;
165 dd_tmp[i] = 0;
166 }
167
168 get_KK(dd_tmp,
169 G_list,
170 num_G,
171 num_patom,
172 q_cart,
173 q_direction_cart,
174 dielectric,
175 pos,
176 lambda,
177 tolerance);
178
179 multiply_borns(dd, dd_tmp, num_patom, born);
180
181 for (i = 0; i < num_patom; i++) {
182 for (k = 0; k < 3; k++) { /* alpha */
183 for (l = 0; l < 3; l++) { /* beta */
184 adrs = i * num_patom * 9 + k * num_patom * 3 + i * 3 + l;
185 adrs_sum = i * 9 + k * 3 + l;
186 dd[adrs * 2] -= dd_q0[adrs_sum * 2];
187 dd[adrs * 2 + 1] -= dd_q0[adrs_sum * 2 + 1];
188 }
189 }
190 }
191
192 for (i = 0; i < num_patom * num_patom * 18; i++) {
193 dd[i] *= factor;
194 }
195
196 /* This may not be necessary. */
197 /* make_Hermitian(dd, num_patom * 3); */
198
199 free(dd_tmp);
200 dd_tmp = NULL;
201 }
202
dym_get_recip_dipole_dipole_q0(double * dd_q0,const double (* G_list)[3],const long num_G,const long num_patom,const double (* born)[3][3],const double dielectric[3][3],const double (* pos)[3],const double lambda,const double tolerance)203 void dym_get_recip_dipole_dipole_q0(double *dd_q0, /* [natom, 3, 3, (real,imag)] */
204 const double (*G_list)[3], /* [num_G, 3] */
205 const long num_G,
206 const long num_patom,
207 const double (*born)[3][3],
208 const double dielectric[3][3],
209 const double (*pos)[3], /* [num_patom, 3] */
210 const double lambda,
211 const double tolerance)
212 {
213 long i, j, k, l, adrs_tmp, adrs, adrsT;
214 double zero_vec[3];
215 double *dd_tmp1, *dd_tmp2;
216
217 dd_tmp1 = NULL;
218 dd_tmp1 = (double*) malloc(sizeof(double) * num_patom * num_patom * 18);
219 dd_tmp2 = NULL;
220 dd_tmp2 = (double*) malloc(sizeof(double) * num_patom * num_patom * 18);
221
222 for (i = 0; i < num_patom * num_patom * 18; i++) {
223 dd_tmp1[i] = 0;
224 dd_tmp2[i] = 0;
225 }
226
227 zero_vec[0] = 0;
228 zero_vec[1] = 0;
229 zero_vec[2] = 0;
230
231 get_KK(dd_tmp1,
232 G_list,
233 num_G,
234 num_patom,
235 zero_vec,
236 NULL,
237 dielectric,
238 pos,
239 lambda,
240 tolerance);
241
242 multiply_borns(dd_tmp2, dd_tmp1, num_patom, born);
243
244 for (i = 0; i < num_patom * 18; i++) {
245 dd_q0[i] = 0;
246 }
247
248 for (i = 0; i < num_patom; i++) {
249 for (k = 0; k < 3; k++) { /* alpha */
250 for (l = 0; l < 3; l++) { /* beta */
251 adrs = i * 9 + k * 3 + l;
252 for (j = 0; j < num_patom; j++) {
253 adrs_tmp = i * num_patom * 9 + k * num_patom * 3 + j * 3 + l ;
254 dd_q0[adrs * 2] += dd_tmp2[adrs_tmp * 2];
255 dd_q0[adrs * 2 + 1] += dd_tmp2[adrs_tmp * 2 + 1];
256 }
257 }
258 }
259 }
260
261 /* Summation over another atomic index */
262 /* for (j = 0; j < num_patom; j++) { */
263 /* for (k = 0; k < 3; k++) { /\* alpha *\/ */
264 /* for (l = 0; l < 3; l++) { /\* beta *\/ */
265 /* adrs = j * 9 + k * 3 + l; */
266 /* for (i = 0; i < num_patom; i++) { */
267 /* adrs_tmp = i * num_patom * 9 + k * num_patom * 3 + j * 3 + l ; */
268 /* dd_q0[adrs * 2] += dd_tmp2[adrs_tmp * 2]; */
269 /* dd_q0[adrs * 2 + 1] += dd_tmp2[adrs_tmp * 2 + 1]; */
270 /* } */
271 /* } */
272 /* } */
273 /* } */
274
275 for (i = 0; i < num_patom; i++) {
276 for (k = 0; k < 3; k++) { /* alpha */
277 for (l = 0; l < 3; l++) { /* beta */
278 adrs = i * 9 + k * 3 + l;
279 adrsT = i * 9 + l * 3 + k;
280 dd_q0[adrs * 2] += dd_q0[adrsT * 2];
281 dd_q0[adrs * 2] /= 2;
282 dd_q0[adrsT * 2] = dd_q0[adrs * 2];
283 dd_q0[adrs * 2 + 1] -= dd_q0[adrsT * 2 + 1];
284 dd_q0[adrs * 2 + 1] /= 2;
285 dd_q0[adrsT * 2 + 1] = -dd_q0[adrs * 2 + 1];
286 }
287 }
288 }
289
290 free(dd_tmp1);
291 dd_tmp1 = NULL;
292 free(dd_tmp2);
293 dd_tmp2 = NULL;
294 }
295
dym_get_charge_sum(double (* charge_sum)[3][3],const long num_patom,const double factor,const double q_cart[3],const double (* born)[3][3])296 void dym_get_charge_sum(double (*charge_sum)[3][3],
297 const long num_patom,
298 const double factor, /* 4pi/V*unit-conv and denominator */
299 const double q_cart[3],
300 const double (*born)[3][3])
301 {
302 long i, j, k, a, b;
303 double (*q_born)[3];
304
305 q_born = (double (*)[3]) malloc(sizeof(double[3]) * num_patom);
306 for (i = 0; i < num_patom; i++) {
307 for (j = 0; j < 3; j++) {
308 q_born[i][j] = 0;
309 }
310 }
311
312 for (i = 0; i < num_patom; i++) {
313 for (j = 0; j < 3; j++) {
314 for (k = 0; k < 3; k++) {
315 q_born[i][j] += q_cart[k] * born[i][k][j];
316 }
317 }
318 }
319
320 for (i = 0; i < num_patom; i++) {
321 for (j = 0; j < num_patom; j++) {
322 for (a = 0; a < 3; a++) {
323 for (b = 0; b < 3; b++) {
324 charge_sum[i * num_patom + j][a][b] =
325 q_born[i][a] * q_born[j][b] * factor;
326 }
327 }
328 }
329 }
330
331 free(q_born);
332 q_born = NULL;
333 }
334
335 /* fc[num_patom, num_satom, 3, 3] */
336 /* dm[num_comm_points, num_patom * 3, num_patom *3] */
337 /* comm_points[num_satom / num_patom, 3] */
338 /* shortest_vectors[:, 3] */
339 /* multiplicities[num_satom, num_patom, 2] */
dym_transform_dynmat_to_fc(double * fc,const double * dm,const double (* comm_points)[3],const double (* svecs)[3],const long (* multi)[2],const double * masses,const long * s2pp_map,const long * fc_index_map,const long num_patom,const long num_satom)340 void dym_transform_dynmat_to_fc(double *fc,
341 const double *dm,
342 const double (*comm_points)[3],
343 const double (*svecs)[3],
344 const long (*multi)[2],
345 const double *masses,
346 const long *s2pp_map,
347 const long *fc_index_map,
348 const long num_patom,
349 const long num_satom)
350 {
351 long i, j, k, l, m, N, adrs, m_pair, i_pair, svecs_adrs;
352 double coef, phase, cos_phase, sin_phase;
353
354 N = num_satom / num_patom;
355 for (i = 0; i < num_patom * num_satom * 9; i++) {
356 fc[i] = 0;
357 }
358
359 for (i = 0; i < num_patom; i++) {
360 for (j = 0; j < num_satom; j++) {
361 i_pair = j * num_patom + i;
362 m_pair = multi[i_pair][0];
363 svecs_adrs = multi[i_pair][1];
364 coef = sqrt(masses[i] * masses[s2pp_map[j]]) / N;
365 for (k = 0; k < N; k++) {
366 cos_phase = 0;
367 sin_phase = 0;
368 for (l = 0; l < m_pair; l++) {
369 phase = 0;
370 for (m = 0; m < 3; m++) {
371 phase -= comm_points[k][m] * svecs[svecs_adrs + l][m];
372 }
373 cos_phase += cos(phase * 2 * PI);
374 sin_phase += sin(phase * 2 * PI);
375 }
376 cos_phase /= m_pair;
377 sin_phase /= m_pair;
378 for (l = 0; l < 3; l++) {
379 for (m = 0; m < 3; m++) {
380 adrs = k * num_patom * num_patom * 18 + i * num_patom * 18 +
381 l * num_patom * 6 + s2pp_map[j] * 6 + m * 2;
382 fc[fc_index_map[i] * num_satom * 9 + j * 9 + l * 3 + m] +=
383 (dm[adrs] * cos_phase - dm[adrs + 1] * sin_phase) * coef;
384 }
385 }
386 }
387 }
388 }
389 }
390
391
get_dynmat_ij(double * dynamical_matrix,const long num_patom,const long num_satom,const double * fc,const double q[3],const double (* svecs)[3],const long (* multi)[2],const double * mass,const long * s2p_map,const long * p2s_map,const double (* charge_sum)[3][3],const long i,const long j)392 static void get_dynmat_ij(double *dynamical_matrix,
393 const long num_patom,
394 const long num_satom,
395 const double *fc,
396 const double q[3],
397 const double (*svecs)[3],
398 const long (*multi)[2],
399 const double *mass,
400 const long *s2p_map,
401 const long *p2s_map,
402 const double (*charge_sum)[3][3],
403 const long i,
404 const long j)
405 {
406 long k, l, adrs;
407 double mass_sqrt;
408 double dm_real[3][3], dm_imag[3][3];
409
410 mass_sqrt = sqrt(mass[i] * mass[j]);
411
412 for (k = 0; k < 3; k++) {
413 for (l = 0; l < 3; l++) {
414 dm_real[k][l] = 0;
415 dm_imag[k][l] = 0;
416 }
417 }
418
419 for (k = 0; k < num_satom; k++) { /* Lattice points of right index of fc */
420 if (s2p_map[k] != p2s_map[j]) {
421 continue;
422 }
423 get_dm(dm_real,
424 dm_imag,
425 num_patom,
426 num_satom,
427 fc,
428 q,
429 svecs,
430 multi,
431 p2s_map,
432 charge_sum,
433 i,
434 j,
435 k);
436 }
437
438 for (k = 0; k < 3; k++) {
439 for (l = 0; l < 3; l++) {
440 adrs = (i * 3 + k) * num_patom * 3 + j * 3 + l;
441 dynamical_matrix[adrs * 2] = dm_real[k][l] / mass_sqrt;
442 dynamical_matrix[adrs * 2 + 1] = dm_imag[k][l] / mass_sqrt;
443 }
444 }
445 }
446
get_dm(double dm_real[3][3],double dm_imag[3][3],const long num_patom,const long num_satom,const double * fc,const double q[3],const double (* svecs)[3],const long (* multi)[2],const long * p2s_map,const double (* charge_sum)[3][3],const long i,const long j,const long k)447 static void get_dm(double dm_real[3][3],
448 double dm_imag[3][3],
449 const long num_patom,
450 const long num_satom,
451 const double *fc,
452 const double q[3],
453 const double (*svecs)[3],
454 const long (*multi)[2],
455 const long *p2s_map,
456 const double (*charge_sum)[3][3],
457 const long i,
458 const long j,
459 const long k)
460 {
461 long l, m, i_pair, m_pair, adrs;
462 double phase, cos_phase, sin_phase, fc_elem;
463
464 cos_phase = 0;
465 sin_phase = 0;
466
467 i_pair = k * num_patom + i;
468 m_pair = multi[i_pair][0];
469 adrs = multi[i_pair][1];
470
471 for (l = 0; l < m_pair; l++) {
472 phase = 0;
473 for (m = 0; m < 3; m++) {
474 phase += q[m] * svecs[adrs + l][m];
475 }
476 cos_phase += cos(phase * 2 * PI) / m_pair;
477 sin_phase += sin(phase * 2 * PI) / m_pair;
478 }
479
480 for (l = 0; l < 3; l++) {
481 for (m = 0; m < 3; m++) {
482 if (charge_sum) {
483 fc_elem = (fc[p2s_map[i] * num_satom * 9 + k * 9 + l * 3 + m] +
484 charge_sum[i * num_patom + j][l][m]);
485 } else {
486 fc_elem = fc[p2s_map[i] * num_satom * 9 + k * 9 + l * 3 + m];
487 }
488 dm_real[l][m] += fc_elem * cos_phase;
489 dm_imag[l][m] += fc_elem * sin_phase;
490 }
491 }
492 }
493
get_dielectric_part(const double q_cart[3],const double dielectric[3][3])494 static double get_dielectric_part(const double q_cart[3],
495 const double dielectric[3][3])
496 {
497 long i, j;
498 double x[3];
499 double sum;
500
501 for (i = 0; i < 3; i++) {
502 x[i] = 0;
503 for (j = 0; j < 3; j++) {
504 x[i] += dielectric[i][j] * q_cart[j];
505 }
506 }
507
508 sum = 0;
509 for (i = 0; i < 3; i++) {
510 sum += q_cart[i] * x[i];
511 }
512
513 return sum;
514 }
515
get_KK(double * dd_part,const double (* G_list)[3],const long num_G,const long num_patom,const double q_cart[3],const double * q_direction_cart,const double dielectric[3][3],const double (* pos)[3],const double lambda,const double tolerance)516 static void get_KK(double *dd_part, /* [natom, 3, natom, 3, (real,imag)] */
517 const double (*G_list)[3], /* [num_G, 3] */
518 const long num_G,
519 const long num_patom,
520 const double q_cart[3],
521 const double *q_direction_cart,
522 const double dielectric[3][3],
523 const double (*pos)[3], /* [num_patom, 3] */
524 const double lambda,
525 const double tolerance)
526 {
527 long i, j, k, l, g, adrs;
528 double q_K[3];
529 double norm, cos_phase, sin_phase, phase, dielectric_part, exp_damp, L2;
530 double KK[3][3];
531
532 L2 = 4 * lambda * lambda;
533
534 /* sum over K = G + q and over G (i.e. q=0) */
535 /* q_direction has values for summation over K at Gamma point. */
536 /* q_direction is NULL for summation over G */
537 for (g = 0; g < num_G; g++) {
538 norm = 0;
539 for (i = 0; i < 3; i++) {
540 q_K[i] = G_list[g][i] + q_cart[i];
541 norm += q_K[i] * q_K[i];
542 }
543
544 if (sqrt(norm) < tolerance) {
545 if (!q_direction_cart) {
546 continue;
547 } else {
548 dielectric_part = get_dielectric_part(q_direction_cart, dielectric);
549 for (i = 0; i < 3; i++) {
550 for (j = 0; j < 3; j++) {
551 KK[i][j] =
552 q_direction_cart[i] * q_direction_cart[j] / dielectric_part;
553 }
554 }
555 }
556 } else {
557 dielectric_part = get_dielectric_part(q_K, dielectric);
558 exp_damp = exp(-dielectric_part / L2);
559 for (i = 0; i < 3; i++) {
560 for (j = 0; j < 3; j++) {
561 KK[i][j] = q_K[i] * q_K[j] / dielectric_part * exp_damp;
562 }
563 }
564 }
565
566 for (i = 0; i < num_patom; i++) {
567 for (j = 0; j < num_patom; j++) {
568 phase = 0;
569 for (k = 0; k < 3; k++) {
570 /* For D-type dynamical matrix */
571 /* phase += (pos[i][k] - pos[j][k]) * q_K[k]; */
572 /* For C-type dynamical matrix */
573 phase += (pos[i][k] - pos[j][k]) * G_list[g][k];
574 }
575 phase *= 2 * PI;
576 cos_phase = cos(phase);
577 sin_phase = sin(phase);
578 for (k = 0; k < 3; k++) {
579 for (l = 0; l < 3; l++) {
580 adrs = i * num_patom * 9 + k * num_patom * 3 + j * 3 + l;
581 dd_part[adrs * 2] += KK[k][l] * cos_phase;
582 dd_part[adrs * 2 + 1] += KK[k][l] * sin_phase;
583 }
584 }
585 }
586 }
587 }
588 }
589
make_Hermitian(double * mat,const long num_band)590 static void make_Hermitian(double *mat, const long num_band)
591 {
592 long i, j, adrs, adrsT;
593
594 for (i = 0; i < num_band; i++) {
595 for (j = i; j < num_band; j++) {
596 adrs = i * num_band + j * 1;
597 adrs *= 2;
598 adrsT = j * num_band + i * 1;
599 adrsT *= 2;
600 /* real part */
601 mat[adrs] += mat[adrsT];
602 mat[adrs] /= 2;
603 /* imaginary part */
604 mat[adrs + 1] -= mat[adrsT+ 1];
605 mat[adrs + 1] /= 2;
606 /* store */
607 mat[adrsT] = mat[adrs];
608 mat[adrsT + 1] = -mat[adrs + 1];
609 }
610 }
611 }
612
multiply_borns(double * dd,const double * dd_in,const long num_patom,const double (* born)[3][3])613 static void multiply_borns(double *dd,
614 const double *dd_in,
615 const long num_patom,
616 const double (*born)[3][3])
617 {
618 long i, j, k, l, m, n, adrs, adrs_in;
619 double zz;
620
621 for (i = 0; i < num_patom; i++) {
622 for (j = 0; j < num_patom; j++) {
623 for (k = 0; k < 3; k++) { /* alpha */
624 for (l = 0; l < 3; l++) { /* beta */
625 adrs = i * num_patom * 9 + k * num_patom * 3 + j * 3 + l;
626 for (m = 0; m < 3; m++) { /* alpha' */
627 for (n = 0; n < 3; n++) { /* beta' */
628 adrs_in = i * num_patom * 9 + m * num_patom * 3 + j * 3 + n ;
629 zz = born[i][m][k] * born[j][n][l];
630 dd[adrs * 2] += dd_in[adrs_in * 2] * zz;
631 dd[adrs * 2 + 1] += dd_in[adrs_in * 2 + 1] * zz;
632 }
633 }
634 }
635 }
636 }
637 }
638 }
639