4 * Created by Toshi Nagata on 2005/06/07.
5 * Copyright 2005 Toshi Nagata. All rights reserved.
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation version 2 of the License.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
18 #include "MDGraphite.h"
23 extern int do_custom_bond_callback(MDArena *arena, Double r, void *procObj, Double *energy, Double *force);
26 s_custom_bond_force(MDArena *arena, Double r, MDCustomBondPar *cp, Double *energy, Double *force)
31 s = exp(-cp->u.morse.a * (r - cp->u.morse.r0));
32 *energy = cp->u.morse.D * (1.0 + s * (s - 2.0));
33 *force = -2.0 * cp->u.morse.a * cp->u.morse.D * s * (1.0 - s);
36 /* retval = do_custom_bond_callback(arena, r, cp->u.proc, energy, force);
38 md_panic(arena, NULL); */
41 *energy = *force = 0.0;
47 s_calc_bond_force(MDArena *arena)
49 Atom *ap = arena->mol->atoms;
50 Int nbonds = arena->mol->nbonds;
51 Int *bonds = arena->mol->bonds;
52 Int *bond_par_i = arena->bond_par_i;
53 Int *custom_bond_par_i = arena->custom_bond_par_i;
54 BondPar *bond_pars = arena->par->bondPars;
55 Double *anbond_r0 = arena->anbond_r0;
56 Double *energies = &arena->energies[kBondIndex];
57 Vector *forces = &arena->forces[kBondIndex * arena->mol->natoms];
59 for (i = 0; i < nbonds; i++, bonds += 2, bond_par_i++) {
61 Double k0, k1, w1, w2, r0;
65 continue; /* Ignore this entry */
66 /* if (bond_uniq != NULL && bond_uniq[i] >= 0)
67 continue; *//* Non-unique bond */
68 if (ap[bonds[0]].mm_exclude || ap[bonds[1]].mm_exclude)
69 continue; /* Skip non-occupied atoms */
70 VecSub(r12, ap[bonds[1]].r, ap[bonds[0]].r);
72 if (custom_bond_par_i != NULL && (idx = custom_bond_par_i[i]) > 0 && idx <= arena->ncustom_bond_pars) {
74 s_custom_bond_force(arena, w1, arena->custom_bond_pars + (idx - 1), &energy, &force);
77 r0 = 0.0; /* To keep complier happy */
79 bp = bond_pars + *bond_par_i;
81 if (anbond_r0 != NULL) {
82 if (anbond_r0[i] > 0.0)
86 k0 = bp->k * w2 * w2; /* Energy */
87 k1 = -2.0 * bp->k * w2 / w1; /* Force / r */
89 VecScaleSelf(r12, k1);
91 VecDec(forces[bonds[0]], r12);
92 VecInc(forces[bonds[1]], r12);
93 if (arena->debug_result && arena->debug_output_level > 1) {
94 fprintf(arena->debug_result, "bond force %d-%d: r=%f, r0=%f, k1=%f, {%f %f %f}\n", bonds[0]+1, bonds[1]+1, w1, r0, k1, r12.x, r12.y, r12.z);
100 s_calc_angle_force_one(const Vector *r1, const Vector *r2, const Vector *r3, const AnglePar *anp, Double *angle, Double *energy, Double *k1out, Vector *force1, Vector *force2, Vector *force3)
102 Vector r21, r23, f1, f2, v1;
103 Double w1, w2, w3, cost, sint, t, k0, k1;
104 VecSub(r21, *r1, *r2);
105 VecSub(r23, *r3, *r2);
106 w1 = 1.0 / VecLength(r21);
107 w2 = 1.0 / VecLength(r23);
108 VecScaleSelf(r21, w1);
109 VecScaleSelf(r23, w2);
110 cost = VecDot(r21, r23);
111 if (cost > 0.999999 || cost < -0.999999) {
112 /* printf("Cannot handle linear angle %d-%d-%d: skipped.\n", angles[0]+1, angles[1]+1, angles[2]+1); */
113 return -1; /* Cannot handle linear angle */
115 sint = sqrt(1.0 - cost * cost);
116 /* if (sint < 1e-5 && sint > -1e-5)
117 continue; *//* Cannot handle linear angle */
118 t = atan2(sint, cost) - anp->a0;
121 if (sint < 0.1 && sint > -0.1) {
122 /* ---- Method 1 ---- */
123 /* This is slower than method 2, but it is safer when sint is close to 0 */
124 k1 = -2 * anp->k * t;
125 VecCross(v1, r21, r23);
126 VecCross(f1, r21, v1);
127 w3 = w1 * k1 / VecLength(f1);
130 VecScaleSelf(f1, w3);
131 VecCross(f2, v1, r23);
132 w3 = w2 * k1 / VecLength(f2);
135 VecScaleSelf(f2, w3);
137 /* ---- Method 2 ---- */
138 k1 = -2 * anp->k * t / sint;
139 VecScale(f1, r21, cost);
142 VecScaleSelf(f1, w3);
143 VecScale(f2, r23, cost);
146 VecScaleSelf(f2, w3);
152 *angle = t + anp->a0;
155 VecScale(*force2, f1, -1);
160 s_calc_angle_force(MDArena *arena)
162 Atom *ap = arena->mol->atoms;
163 Int nangles = arena->mol->nangles;
164 Int *angles = arena->mol->angles;
165 Int *angle_par_i = arena->angle_par_i;
166 AnglePar *angle_pars = arena->par->anglePars;
167 /* Int *angle_uniq = (arena->nsyms > 0 ? arena->sym_angle_uniq : NULL); */
168 Double *energies = &arena->energies[kAngleIndex];
169 Vector *forces = &arena->forces[kAngleIndex * arena->mol->natoms];
171 for (i = 0; i < nangles; i++, angles += 3, angle_par_i++) {
172 Atom *ap1, *ap2, *ap3;
176 if (*angle_par_i < 0)
177 continue; /* Ignore this entry */
178 ap1 = ATOM_AT_INDEX(ap, angles[0]);
179 ap2 = ATOM_AT_INDEX(ap, angles[1]);
180 ap3 = ATOM_AT_INDEX(ap, angles[2]);
181 /* if (angle_uniq != NULL && angle_uniq[i] >= 0)
182 continue; */ /* Non-unique angle */
183 if (ap1->mm_exclude || ap2->mm_exclude || ap3->mm_exclude)
184 continue; /* Skip non-occupied atoms */
185 if (arena->nalchem_flags > 0) {
186 if (angles[0] < arena->nalchem_flags && angles[1] < arena->nalchem_flags
187 && angles[2] < arena->nalchem_flags
188 && (arena->alchem_flags[angles[0]] | arena->alchem_flags[angles[1]] | arena->alchem_flags[angles[2]]) == 3)
189 continue; /* Interaction between vanishing and appearing groups is ignored */
191 anp = angle_pars + *angle_par_i;
192 if (s_calc_angle_force_one(&(ap1->r), &(ap2->r), &(ap3->r), angle_pars + *angle_par_i, &ang, &en, &k1, &f1, &f2, &f3) != 0)
195 VecInc(forces[angles[0]], f1);
196 VecInc(forces[angles[1]], f2);
197 VecInc(forces[angles[2]], f3);
198 if (arena->debug_result && arena->debug_output_level > 1) {
199 fprintf(arena->debug_result, "angle force %d-%d-%d: a=%f, a0=%f, k1=%f, {%f %f %f}, {%f %f %f}\n", angles[0]+1, angles[1]+1, angles[2]+1, ang*180/PI, anp->a0*180/PI, k1, -f2.x, -f2.y, -f2.z, f3.x, f3.y, f3.z);
205 s_calc_dihedral_force_one(const Vector *r1, const Vector *r2, const Vector *r3, const Vector *r4, const TorsionPar *tp, Double *phi, Double *energy, Double *k1out, Vector *force1, Vector *force2, Vector *force3, Vector *force4)
207 Vector r21, r32, r43;
209 Double w1, w2, w3, k0, k1;
210 Double cosphi, sinphi;
213 VecSub(r21, *r1, *r2);
214 VecSub(r32, *r2, *r3);
215 VecSub(r43, *r3, *r4);
216 VecCross(v1, r21, r32);
217 VecCross(v2, r32, r43);
218 VecCross(v3, r32, v1);
222 if (w1 < 1e-5 || w2 < 1e-5 || w3 < 1e-5)
223 return -1; /* The dihedral cannot be defined */
227 VecScaleSelf(v1, w1);
228 VecScaleSelf(v2, w2);
229 VecScaleSelf(v3, w3);
231 /* The dihedral angle value */
232 cosphi = VecDot(v1, v2);
233 sinphi = VecDot(v3, v2);
234 *phi = -atan2(sinphi, cosphi);
236 /* Repeat for multiple dihedral terms */
238 for (n = 0; n < tp->mult; n++) {
240 Double phi0 = tp->phi0[n];
241 Int period = tp->period[n];
243 k0 += k * (1 + cos(period * *phi + phi0));
244 k1 -= period * k * sin(period * *phi + phi0);
246 /* A simple quadratic term */
252 k0 += k * phi0 * phi0;
257 if (sinphi < -0.1 || sinphi > 0.1) {
260 VecScale(v4, v1, cosphi);
262 VecScaleSelf(v4, w1);
263 VecScale(v5, v2, cosphi);
265 VecScaleSelf(v5, w2);
267 VecCross(f1, r32, v4);
268 VecCross(f3, v5, r32);
269 VecCross(f2, v4, r21);
270 VecCross(vw0, r43, v5);
272 VecScaleSelf(f1, k1);
273 VecScaleSelf(f2, k1);
274 VecScaleSelf(f3, k1);
277 Vector v6, v7, vw1, vw2;
278 VecScale(v6, v3, sinphi);
280 VecScaleSelf(v6, w3);
281 VecScale(v7, v2, sinphi);
283 VecScaleSelf(v7, w2);
285 VecCross(vw1, v6, r32);
286 VecCross(f1, r32, vw1);
287 VecCross(f3, v7, r32);
288 VecCross(f2, r43, v7);
289 VecCross(vw1, r32, r21);
290 VecCross(vw2, v6, vw1);
292 VecCross(vw1, r32, v6);
293 VecCross(vw2, r21, vw1);
295 VecScaleSelf(f1, k1);
296 VecScaleSelf(f2, k1);
297 VecScaleSelf(f3, k1);
299 /* if (dihedral_uniq != NULL)
300 k0 *= -dihedral_uniq[i]; */
305 VecScale(*force2, f1, -1);
307 VecScale(*force3, f2, -1);
308 VecScale(*force4, f3, -1);
313 s_calc_dihedral_force_sub(MDArena *arena, Atom *ap, Int ndihedrals, Int *dihedrals, Int *dihedral_par_i, TorsionPar *dihedral_pars, Int *dihedral_uniq, Double *energies, Vector *forces)
316 if (arena->mol->nsyms == 0)
317 dihedral_uniq = NULL; /* Ignore the symmetry info */
318 for (i = 0; i < ndihedrals; i++, dihedrals += 4, dihedral_par_i++) {
319 Atom *ap1, *ap2, *ap3, *ap4;
321 Vector f1, f2, f3, f4;
324 if (*dihedral_par_i < 0)
325 continue; /* Ignore this entry */
326 /* if (dihedral_uniq != NULL && dihedral_uniq[i] >= 0)
327 continue; *//* Non-unique dihedral */
328 ap1 = ATOM_AT_INDEX(ap, dihedrals[0]);
329 ap2 = ATOM_AT_INDEX(ap, dihedrals[1]);
330 ap3 = ATOM_AT_INDEX(ap, dihedrals[2]);
331 ap4 = ATOM_AT_INDEX(ap, dihedrals[3]);
332 if (ap1->mm_exclude || ap2->mm_exclude || ap3->mm_exclude || ap4->mm_exclude)
333 continue; /* Skip non-occupied atoms */
334 if (arena->nalchem_flags > 0) {
335 if (dihedrals[0] < arena->nalchem_flags && dihedrals[1] < arena->nalchem_flags
336 && dihedrals[2] < arena->nalchem_flags && dihedrals[3] < arena->nalchem_flags
337 && (arena->alchem_flags[dihedrals[0]] | arena->alchem_flags[dihedrals[1]]
338 | arena->alchem_flags[dihedrals[2]] | arena->alchem_flags[dihedrals[3]]) == 3)
339 continue; /* Interaction between vanishing and appearing groups is ignored */
341 tp = dihedral_pars + *dihedral_par_i;
342 if (s_calc_dihedral_force_one(&(ap1->r), &(ap2->r), &(ap3->r), &(ap4->r), tp, &phi, &en, &k1, &f1, &f2, &f3, &f4) != 0)
346 VecSub(r21, ap[dihedrals[0]].r, ap[dihedrals[1]].r);
347 VecSub(r32, ap[dihedrals[1]].r, ap[dihedrals[2]].r);
348 VecSub(r43, ap[dihedrals[2]].r, ap[dihedrals[3]].r);
349 VecCross(v1, r21, r32);
350 VecCross(v2, r32, r43);
351 VecCross(v3, r32, v1);
355 if (w1 < 1e-5 || w2 < 1e-5 || w3 < 1e-5)
356 continue; // The dihedral cannot be defined
360 VecScaleSelf(v1, w1);
361 VecScaleSelf(v2, w2);
362 VecScaleSelf(v3, w3);
364 // The dihedral angle value
365 cosphi = VecDot(v1, v2);
366 sinphi = VecDot(v3, v2);
367 phi = -atan2(sinphi, cosphi);
369 // Repeat for multiple dihedral terms
371 for (n = 0; n < tp->mult; n++) {
373 Double phi0 = tp->phi0[n];
374 Int period = tp->period[n];
376 k0 += k * (1 + cos(period * phi + phi0));
377 k1 -= period * k * sin(period * phi + phi0);
379 // A simple quadratic term
390 if (sinphi < -0.1 || sinphi > 0.1) {
393 VecScale(v4, v1, cosphi);
395 VecScaleSelf(v4, w1);
396 VecScale(v5, v2, cosphi);
398 VecScaleSelf(v5, w2);
400 VecCross(f1, r32, v4);
401 VecCross(f3, v5, r32);
402 VecCross(f2, v4, r21);
403 VecCross(vw0, r43, v5);
405 VecScaleSelf(f1, k1);
406 VecScaleSelf(f2, k1);
407 VecScaleSelf(f3, k1);
410 Vector v6, v7, vw1, vw2;
411 VecScale(v6, v3, sinphi);
413 VecScaleSelf(v6, w3);
414 VecScale(v7, v2, sinphi);
416 VecScaleSelf(v7, w2);
418 VecCross(vw1, v6, r32);
419 VecCross(f1, r32, vw1);
420 VecCross(f3, v7, r32);
421 VecCross(f2, r43, v7);
422 VecCross(vw1, r32, r21);
423 VecCross(vw2, v6, vw1);
425 VecCross(vw1, r32, v6);
426 VecCross(vw2, r21, vw1);
428 VecScaleSelf(f1, k1);
429 VecScaleSelf(f2, k1);
430 VecScaleSelf(f3, k1);
433 VecInc(forces[dihedrals[0]], f1);
435 VecDec(forces[dihedrals[1]], f1);
437 VecDec(forces[dihedrals[2]], f2);
438 VecDec(forces[dihedrals[3]], f3);
441 VecInc(forces[dihedrals[0]], f1);
442 VecInc(forces[dihedrals[1]], f2);
443 VecInc(forces[dihedrals[2]], f3);
444 VecInc(forces[dihedrals[3]], f4);
445 if (arena->debug_result && arena->debug_output_level > 1) {
446 fprintf(arena->debug_result, "dihedral(improper) force %d-%d-%d-%d: phi=%f, k1=%f, {%f %f %f}, {%f %f %f}, {%f %f %f}\n", dihedrals[0]+1, dihedrals[1]+1, dihedrals[2]+1, dihedrals[3]+1, phi*180/PI, k1, f1.x, f1.y, f1.z, f2.x, f2.y, f2.z, f3.x, f3.y, f3.z);
452 s_calc_dihedral_force(MDArena *arena)
454 Molecule *mol = arena->mol;
455 Parameter *par = arena->par;
456 Double *energies = &arena->energies[kDihedralIndex];
457 Vector *forces = &arena->forces[kDihedralIndex * arena->mol->natoms];
458 s_calc_dihedral_force_sub(arena, mol->atoms, mol->ndihedrals, mol->dihedrals, arena->dihedral_par_i, par->dihedralPars, NULL/*arena->sym_dihedral_uniq*/, energies, forces);
462 s_calc_improper_force(MDArena *arena)
464 Molecule *mol = arena->mol;
465 Parameter *par = arena->par;
466 Double *energies = &arena->energies[kImproperIndex];
467 Vector *forces = &arena->forces[kImproperIndex * arena->mol->natoms];
468 s_calc_dihedral_force_sub(arena, mol->atoms, mol->nimpropers, mol->impropers, arena->improper_par_i, par->improperPars, NULL/*arena->sym_improper_uniq*/, energies, forces);
472 s_calc_pibond_force(MDArena *arena)
474 Atom *ap = arena->mol->atoms;
475 Int npibonds = arena->mol->npibonds;
476 Int *pibonds = arena->mol->pibonds;
477 UnionPar *pars = arena->pi_pars;
478 Double energy, val, valk1;
480 // Double *energies = &arena->energies[kAngleIndex];
481 // Vector *forces = &arena->forces[kAngleIndex * arena->mol->natoms];
483 for (i = 0; i < arena->mol->npiatoms; i++) {
484 MoleculeCalculatePiAtomPosition(arena->mol, i);
486 for (i = 0; i < npibonds; i++, pibonds += 4, pars++) {
488 Vector f[4], *forces;
491 for (j = 0; j < 4; j++) {
495 else if (n < ATOMS_MAX_NUMBER) {
496 r[j] = ATOM_AT_INDEX(ap, n)->r;
499 n -= ATOMS_MAX_NUMBER;
500 pp[j] = arena->mol->piatoms + n;
504 if (j == 2) { /* Bond */
506 Double w1, w2, k0, k1;
507 VecSub(r12, r[1], r[0]);
509 w2 = w1 - pars->bond.r0;
510 k0 = pars->bond.k * w2 * w2; /* Energy */
511 k1 = -2.0 * pars->bond.k * w2 / w1; /* Force / r */
512 VecScaleSelf(r12, k1);
514 VecScale(f[0], r12, -1);
516 if (arena->debug_result && arena->debug_output_level > 1) {
517 fprintf(arena->debug_result, "pi bond force %d-%d: r=%f, r0=%f, k1=%f, {%f %f %f}\n", pibonds[0]+1, pibonds[1]+1, w1, pars->bond.r0, k1, r12.x, r12.y, r12.z);
520 } else if (j == 3) { /* Angle */
521 if (s_calc_angle_force_one(&r[0], &r[1], &r[2], &pars->angle, &val, &energy, &valk1, &f[0], &f[1], &f[2]) != 0)
523 if (arena->debug_result && arena->debug_output_level > 1) {
524 fprintf(arena->debug_result, "pi angle force %d-%d-%d: a=%f, a0=%f, k1=%f, {%f %f %f}, {%f %f %f}\n", pibonds[0]+1, pibonds[1]+1, pibonds[2]+1, val*180/PI, pars->angle.a0*180/PI, energy, f[0].x, f[0].y, f[0].z, f[1].x, f[1].y, f[1].z);
527 } else if (j == 4) { /* Dihedral */
528 if (s_calc_dihedral_force_one(&r[0], &r[1], &r[2], &r[3], &pars->torsion, &val, &energy, &valk1, &f[0], &f[1], &f[2], &f[3]) != 0)
530 if (arena->debug_result && arena->debug_output_level > 1) {
531 fprintf(arena->debug_result, "pi dihedral force %d-%d-%d-%d: phi=%f, k1=%f, {%f %f %f}, {%f %f %f}, {%f %f %f}\n", pibonds[0]+1, pibonds[1]+1, pibonds[2]+1, pibonds[3]+1, val*180/PI, energy, f[0].x, f[0].y, f[0].z, f[1].x, f[1].y, f[1].z, f[2].x, f[2].y, f[2].z);
533 idx = kDihedralIndex;
534 } else continue; /* j == 0 or 1? (Cannot happen) */
535 arena->energies[idx] += energy;
536 forces = &arena->forces[idx * arena->mol->natoms];
537 for (k = 0; k < j; k++) {
540 break; /* Cannot happen */
541 else if (n < ATOMS_MAX_NUMBER) {
542 VecInc(forces[n], f[k]);
544 Int *ip = AtomConnectData(&pp[k]->connect);
546 for (kk = pp[k]->connect.count - 1; kk >= 0; kk--) {
547 Int an = ip[kk]; /* Index of the ring atom */
548 Double co = pp[k]->coeffs[kk];
549 VecScaleInc(forces[an], f[k], co);
556 /* ==================================================================== */
557 /* md_check_verlet_list: only for debugging the verlet list generation */
558 /* ==================================================================== */
560 typedef struct md_check_record {
566 s_md_check_verlet_comparator(const void *ap, const void *bp)
568 Double d = ((const md_check_record *)ap)->len - ((const md_check_record *)bp)->len;
569 return (d < 0 ? -1 : (d > 0 ? 1 : 0));
573 md_check_verlet_list(MDArena *arena)
579 Vector cell_offsets[27];
580 XtalCell *cell = arena->mol->cell;
584 ndx = (arena->periodic_a ? 1 : 0);
585 ndy = (arena->periodic_b ? 1 : 0);
586 ndz = (arena->periodic_c ? 1 : 0);
587 if (cell != NULL && (ndx != 0 || ndy != 0 || ndz != 0)) {
589 for (i = -1; i <= 1; i++) {
590 for (j = -1; j <= 1; j++) {
591 for (k = -1; k <= 1; k++) {
592 VecZero(cell_offsets[nn]);
593 VecScaleInc(cell_offsets[nn], cell->axes[0], i);
594 VecScaleInc(cell_offsets[nn], cell->axes[1], j);
595 VecScaleInc(cell_offsets[nn], cell->axes[2], k);
601 /* Debugging is done with x-y 2-dimensional system */
602 ncr = arena->mol->natoms * (arena->mol->natoms - 1) / 2 * 9;
603 cr = (md_check_record *)malloc(sizeof(md_check_record) * ncr);
605 for (i = 0, api = arena->mol->atoms; i < arena->mol->natoms; i++, api = ATOM_NEXT(api)) {
606 for (j = i + 1, apj = ATOM_AT_INDEX(arena->mol->atoms, j); j < arena->mol->natoms; j++, apj = ATOM_NEXT(apj)) {
608 VecSub(dr, apj->r, api->r);
609 for (dx = -1; dx <= 1; dx++) {
610 for (dy = -1; dy <= 1; dy++) {
612 nn = dx * 9 + dy * 3 + 13;
613 VecInc(dr2, cell_offsets[nn]);
619 cr[k].len = VecLength(dr2);
625 for (k = 0; k < arena->nverlets; k++) {
626 i = arena->verlets[k].n1;
627 j = arena->verlets[k].n2;
630 i = arena->verlets[k].n2;
632 dx = arena->verlets[k].symop.dx;
633 dy = arena->verlets[k].symop.dy;
634 nn = (i * arena->mol->natoms - i * (i + 1) / 2 + (j - i) - 1) * 9 + (dx + 1) * 3 + dy + 1;
635 if (cr[nn].i != i || cr[nn].j != j || cr[nn].dx != dx || cr[nn].dy != dy)
636 fprintf(arena->log_result, "Debug: internal inconsistency\n");
640 mergesort(cr, ncr, sizeof(md_check_record), s_md_check_verlet_comparator);
641 for (i = 0; i < ncr; i++) {
645 len2 = arena->verlets[cr[i].n].length;
646 fprintf(arena->log_result, "Debug: %5d (i=%4d,j=%4d) [dx=%4d, dy=%4d] n=%4d %f %f\n", i, cr[i].i, cr[i].j, cr[i].dx, cr[i].dy, cr[i].n, cr[i].len, len2);
647 if (cr[i].len > arena->pairlist_distance)
652 fprintf(arena->log_result, "Debug: %5d (i=%4d,j=%4d) [dx=%4d, dy=%4d] n=%4d %f %f\n", i, cr[i].i, cr[i].j, cr[i].dx, cr[i].dy, cr[i].n, cr[i].len, arena->verlets[cr[i].n].length);
656 fflush(arena->log_result);
660 /* ==================================================================== */
662 /* Count all lattice points within distance d from point v */
663 /* Ref. "Algorithms for the Shortest and Closest Lattice Vector Problems"
664 Guillaume Hanrot, Xavier Pujol, Damien Stehle
665 Coding and Cryptology; Lecture Notes in Computer Science, 2011 vol. 6639/2011 pp. 159-190
666 DOI: 10.1007/978-3-642-20901-7_10 */
668 s_enum_neighbors(MDArena *arena, Vector v, Double d)
670 Vector bn[3]; /* Base vectors for the cell axes */
671 Double bl[3]; /* Square of the length of base vectors */
672 Double mu[3]; /* Non-diagonal terms for Gram-Schmidt orthogonalization */
673 XtalCell *cell = arena->mol->cell;
674 Int dim; /* Number of periodic axes */
675 Int ijk[3]; /* Renumber the indices. For 1-dimensional case, axes[ijk[0]] is the periodic axis.
676 For 2-dimensional case, axes[ijk[0]] and axes[ijk[1]] are the periodic axes.
677 Only uses exchange of two elements, so that ijk[ijk[i]] == i for i=0,1,2 */
678 Vector axes[3]; /* Renumbered cell axes */
679 Double t[3]; /* Projected vector v on bn[] */
680 Int count; /* Number of results */
681 Int x[3]; /* Lattice point candidate */
686 dim = (arena->periodic_a != 0) + (arena->periodic_b != 0) + (arena->periodic_c != 0);
687 ijk[0] = 0; ijk[1] = 1; ijk[2] = 2;
689 /* Non-periodic case: check whether (0,0,0) is within d or not */
690 if (VecLength(v) < d) {
691 x[0] = x[1] = x[2] = 0;
692 AssignArray(&arena->lattice_offsets, &arena->nlattice_offsets, sizeof(Int) * 3, 0, x);
698 if (arena->periodic_b) {
699 ijk[0] = 1; ijk[1] = 0;
700 } else if (arena->periodic_c) {
701 ijk[0] = 2; ijk[2] = 0;
703 } else if (dim == 2) {
704 if (!arena->periodic_a) {
705 ijk[2] = 0; ijk[0] = 2;
706 } else if (!arena->periodic_b) {
707 ijk[1] = 0; ijk[0] = 1;
710 axes[0] = cell->axes[ijk[0]];
711 axes[1] = cell->axes[ijk[1]];
712 axes[2] = cell->axes[ijk[2]];
714 /* Gram-Schmidt orthogonalization */
716 bl[0] = VecLength2(bn[0]);
717 mu[0] = VecDot(axes[1], bn[0]) / bl[0]; /* bl[0] should be non-zero */
725 VecScaleInc(bn[1], bn[0], -mu[0]);
726 bl[1] = VecLength2(bn[1]);
727 mu[1] = VecDot(axes[2], bn[0]) / bl[0];
728 if (dim == 2 || bl[1] < 1e-10) {
735 mu[2] = VecDot(axes[3], bn[1]) / bl[1];
737 VecScaleInc(bn[2], bn[0], -mu[1]);
738 VecScaleInc(bn[2], bn[1], -mu[2]);
739 bl[2] = VecLength2(bn[2]);
746 /* Project the target vector */
747 t[0] = t[1] = t[2] = 0.0;
748 t[0] = VecDot(v, bn[0]) / bl[0];
750 t[1] = VecDot(v, bn[1]) / bl[1];
752 t[2] = VecDot(v, bn[2]) / bl[2];
758 x[0] = x[1] = x[2] = 0;
759 r[0] = r[1] = r[2] = 0.0;
762 x[i] = ceil(t[i] - d / sqrt(bl[i]));
768 for (j = i + 1; j < dim; j++) {
769 w += x[j] * mu[j + i - 1];
772 w2 = x[i] - t[i] + w;
773 r[i] = w2 * w2 * bl[i];
775 for (j = i; j < dim; j++) {
786 AssignArray(&arena->lattice_offsets, &arena->nlattice_offsets, sizeof(Int) * 3, count, xx);
794 for (j = i + 1; j < dim; j++) {
795 w += x[j] * mu[j + i - 1];
797 x[i] = ceil(t[i] - w - sqrt(w2 / bl[i]));
810 /* Update the Verlet list (for non-bonding interaction) */
812 s_make_verlet_list(MDArena *arena)
814 int i, j, k, n, nn, natoms;
815 int dx, dy, dz, ndx, ndy, ndz;
816 Molecule *mol = arena->mol;
817 Atom *atoms = mol->atoms;
819 MDVerlet *vl = arena->verlets;
820 Vector *vdr = arena->verlets_dr;
823 XtalCell *cell = mol->cell;
824 Parameter *par = arena->par;
827 natoms = mol->natoms;
828 for (i = 0; i < natoms; i++)
831 ndx = (arena->periodic_a ? 1 : 0);
832 ndy = (arena->periodic_b ? 1 : 0);
833 ndz = (arena->periodic_c ? 1 : 0);
834 limit = arena->pairlist_distance * arena->pairlist_distance;
836 use_sym = (arena->mol->nsyms > 0);
837 for (i = 0, api = atoms; i < natoms; i++, api++) {
838 MDExclusion *exinfo = arena->exinfo + i;
839 Int index4 = (exinfo + 1)->index0;
840 Int vdw_idx1 = arena->vdw_par_i[i];
841 Int vdw_idx, vdw_idx2;
842 arena->verlet_i[i] = n;
844 for (j = i, apj = atoms + j; j < natoms; j++, apj++) {
850 /* int dxbase, dybase, dzbase; */
854 if (api->fix_force < 0 && apj->fix_force < 0)
857 /* Non-occupied atoms */
858 if (api->mm_exclude || apj->mm_exclude)
861 /* If no symmetry expansion, then no interaction with self */
862 if (ndx + ndy + ndz == 0 && i == j)
865 VecSub(rij, apj->r, api->r);
867 /* Calculate the cell offset for the nearest neighbor */
868 if (ndx + ndy + ndz != 0 && apj->periodic_exclude == 0 && cell != NULL) {
869 count = s_enum_neighbors(arena, rij, limit);
871 static Int sZeros[3] = {0, 0, 0};
872 AssignArray(&arena->lattice_offsets, &arena->nlattice_offsets, sizeof(Int) * 3, 0, sZeros);
875 /* Check the specific cutoff table for (i, j) pair */
876 vdw_idx2 = arena->vdw_par_i[j];
877 if (vdw_idx1 < 0 || vdw_idx2 < 0)
878 vdw_idx = par->nvdwPars * par->nvdwPars; /* A null record */
879 else if (vdw_idx1 < vdw_idx2)
880 vdw_idx = vdw_idx1 * par->nvdwPars + vdw_idx2;
882 vdw_idx = vdw_idx2 * par->nvdwPars + vdw_idx1;
883 vdw_cutoff = arena->cutoff;
884 for (k = par->nvdwCutoffPars - 1; k >= 0; k--) {
885 VdwCutoffPar *cr = par->vdwCutoffPars + k;
886 if (((cr->type1 == kAtomTypeWildcard || cr->type1 == api->type) && (cr->type2 == kAtomTypeWildcard || cr->type2 == apj->type)) ||
887 ((cr->type1 == kAtomTypeWildcard || cr->type1 == apj->type) && (cr->type2 == kAtomTypeWildcard || cr->type2 == api->type))) {
888 vdw_cutoff = cr->cutoff;
891 if ((cr->type1 == i && cr->type2 == j) || (cr->type1 == j && cr->type2 == i)) {
892 vdw_cutoff = cr->cutoff;
896 if (vdw_cutoff < 0) {
897 /* A negative value of specific cutoff means "cutoff at r_eq * (-specific_cutoff) */
898 MDVdwCache *cp = &(arena->vdw_cache[vdw_idx]);
899 Double r_eq = pow(cp->par.A / cp->par.B * 2.0, 1.0/6.0);
900 vdw_cutoff = r_eq * (-vdw_cutoff);
903 /* Search for pairs */
904 for (nn = 0; nn < count; nn++) {
906 dx = arena->lattice_offsets[nn * 3];
907 dy = arena->lattice_offsets[nn * 3 + 1];
908 dz = arena->lattice_offsets[nn * 3 + 2];
909 if (dx == 0 && dy == 0 && dz == 0) {
910 /* Pair within the unit cell */
912 continue; /* No interaction with self */
913 /* Is this pair to be excluded? */
914 for (index0 = exinfo->index0, ip = arena->exlist + index0; index0 < index4; index0++, ip++) {
918 if (index0 < exinfo->index3)
919 continue; /* Special exclusion, 1-2, 1-3 */
921 exflag = 1; /* 1-4 interaction */
922 } else if (apj->periodic_exclude) {
925 VecScaleInc(rij0, cell->axes[0], dx);
926 VecScaleInc(rij0, cell->axes[1], dy);
927 VecScaleInc(rij0, cell->axes[2], dz);
928 /* VecInc(rij0, cell_offsets[nn]); */
932 lenij2 = VecLength2(rij0);
933 if (lenij2 <= limit) {
935 if (n >= arena->max_nverlets) {
936 arena->max_nverlets += 32;
937 vl = (MDVerlet *)realloc(vl, sizeof(MDVerlet) * arena->max_nverlets);
939 md_panic(arena, "Low memory");
942 vlp->vdw_type = (exflag ? 1 : 0);
948 vlp->symop.alive = (vlp->symop.dx != 0 || vlp->symop.dy != 0 || vlp->symop.dz != 0);
949 vlp->index = vdw_idx;
952 vlp->vdw_cutoff = vdw_cutoff;
953 vlp->length = sqrt(lenij2);
955 } /* end if lenij2 <= limit */
960 arena->verlet_i[natoms] = n;
963 arena->last_verlet_step = arena->step;
965 if (arena->debug_result && arena->debug_output_level > 2) {
966 fprintf(arena->debug_result, "\n Verlet list at step %d\n", arena->step);
967 fprintf(arena->debug_result, " {atom1 atom2 vdw_type (=1 if 1-4 bonded) vdw_index cell_translation}\n");
968 for (i = 0; i < arena->nverlets; i++) {
969 fprintf(arena->debug_result, "{%d %d %d %d %06d}%c", vl[i].n1+1, vl[i].n2+1, vl[i].vdw_type, vl[i].index, (vl[i].symop.dx + 50) * 10000 + (vl[i].symop.dy + 50) * 100 + (vl[i].symop.dz + 50), (i % 4 == 3 ? '\n' : ' '));
972 fprintf(arena->debug_result, "\n");
976 /* Calculate the nonbonded force */
977 /* group_flags[] is used for calculation of pair-specific interaction between
978 two groups of atoms */
980 s_calc_nonbonded_force_sub(MDArena *arena, Double *energies, Double *eenergies, Vector *forces, Vector *eforces, const MDGroupFlags *group_flags_1, const MDGroupFlags *group_flags_2)
984 Double limit, elimit, dielec_r;
985 Double lambda, dlambda;
988 /* MDVdwCache *vdw_cache = arena->vdw_cache; */
989 Atom *atoms = arena->mol->atoms;
990 XtalCell *cell = arena->mol->cell;
993 memset(arena->cell_forces, 0, sizeof(Double) * 12);
996 /* Check whether the Verlet list needs update */
997 if (arena->last_verlet_step >= 0) {
998 i = arena->mol->natoms - 1;
999 vdr = arena->verlets_dr + i;
1000 if (arena->cutoff > arena->electro_cutoff)
1001 limit = (arena->pairlist_distance - arena->cutoff) * 0.5;
1003 limit = (arena->pairlist_distance - arena->electro_cutoff) * 0.5;
1004 limit = limit * limit;
1005 for ( ; i >= 0; i--, vdr--) {
1006 if (VecLength2(*vdr) >= limit)
1011 s_make_verlet_list(arena);
1013 /* Calculate the non-bonded interaction for each pair in the Verlet list */
1014 /* limit = arena->cutoff * arena->cutoff; */
1015 elimit = arena->electro_cutoff * arena->electro_cutoff;
1016 dielec_r = COULOMBIC / arena->dielectric;
1017 for (i = arena->nverlets - 1, vl = arena->verlets + i; i >= 0; i--, vl--) {
1018 Double A, B, vofs, k0, k1;
1019 MDVdwCache *vp = arena->vdw_cache + vl->index;
1021 Vector rij, fij, rij2, fij2;
1022 Double r2, w2, w6, w12;
1023 if (group_flags_1 != NULL && group_flags_2 != NULL) {
1024 if (!(get_group_flag(group_flags_1, vl->n1) && get_group_flag(group_flags_2, vl->n2))
1025 && !(get_group_flag(group_flags_1, vl->n2) && get_group_flag(group_flags_2, vl->n1)))
1029 if (arena->nalchem_flags > 0) {
1031 if (vl->n1 < arena->nalchem_flags)
1032 c1 = arena->alchem_flags[vl->n1];
1034 if (vl->n2 < arena->nalchem_flags)
1035 c2 = arena->alchem_flags[vl->n2];
1037 if ((c1 == 1 && c2 == 2) || (c1 == 2 && c2 == 1))
1039 if (c1 == 1 || c2 == 1) {
1040 lambda = (1.0 - arena->alchem_lambda);
1041 dlambda = -arena->alchem_dlambda;
1042 } else if (c1 == 2 || c2 == 2) {
1043 lambda = arena->alchem_lambda;
1044 dlambda = arena->alchem_dlambda;
1054 if (vl->vdw_type == 1) {
1057 /* vofs = vp->vcut14; */
1061 /* vofs = vp->vcut; */
1063 ap1 = &atoms[vl->n1];
1064 ap2 = &atoms[vl->n2];
1066 if (vl->symop.alive) {
1067 VecScaleInc(rij, cell->axes[0], vl->symop.dx);
1068 VecScaleInc(rij, cell->axes[1], vl->symop.dy);
1069 VecScaleInc(rij, cell->axes[2], vl->symop.dz);
1071 VecDec(rij, ap1->r);
1072 r2 = VecLength2(rij);
1075 limit = vl->vdw_cutoff * vl->vdw_cutoff;
1079 fij.x = fij.y = fij.z = 0.0;
1082 /* Coulombic force */
1083 w12 = ap1->charge * ap2->charge * dielec_r;
1085 if (arena->use_xplor_shift) {
1086 w2 = 1.0 / sqrt(r2);
1087 k0 = r2 / elimit - 1.0;
1090 k1 = (3.0 * r2 / elimit - 2.0) / elimit - 1.0 / r2;
1091 k1 = -w12 * k1 * w2;
1093 w2 = 1.0 / sqrt(r2);
1097 vofs = -w12 / arena->electro_cutoff;
1100 if (vl->vdw_type == 1) {
1101 k0 *= arena->scale14_elect;
1102 k1 *= arena->scale14_elect;
1104 VecScale(fij, rij, k1);
1105 *eenergies += k0 / vl->mult;
1106 if (eforces != NULL) {
1107 VecDec(eforces[vl->n1], fij);
1108 VecInc(eforces[vl->n2], fij);
1111 if (arena->debug_result && arena->debug_output_level > 1) {
1112 fprintf(arena->debug_result, "nonbonded(electrostatic) force %d-%d: r=%f, k0=%f, k1=%f, {%f %f %f}\n", vl->n1+1, vl->n2+1, sqrt(r2), k0/KCAL2INTERNAL, k1*sqrt(r2)/KCAL2INTERNAL, fij.x/KCAL2INTERNAL, fij.y/KCAL2INTERNAL, fij.z/KCAL2INTERNAL);
1116 /* van der Waals force */
1120 k0 = A * w12 - B * w6;
1121 k1 = 6 * w2 * (2.0 * A * w12 - B * w6);
1125 vofs = -A * w12 + B * w6;
1127 if (vl->vdw_type == 1) {
1128 k0 *= arena->scale14_vdw;
1129 k1 *= arena->scale14_vdw;
1133 VecScale(fij, rij, k1);
1134 *energies += k0 * lambda;
1135 if (forces != NULL) {
1136 VecDec(forces[vl->n1], fij);
1137 VecInc(forces[vl->n2], fij);
1141 arena->alchem_energy += k0 * dlambda;
1143 if (arena->debug_result && arena->debug_output_level > 1) {
1144 fprintf(arena->debug_result, "nonbonded(vdw) force %d-%d: r=%f, k0=%f, k1=%f, {%f %f %f}\n", vl->n1+1, vl->n2+1, sqrt(r2), k0/KCAL2INTERNAL, k1*sqrt(r2)/KCAL2INTERNAL, fij.x/KCAL2INTERNAL, fij.y/KCAL2INTERNAL, fij.z/KCAL2INTERNAL);
1148 if (arena->is_minimizing && arena->minimize_cell && (ap2->symop.alive || vl->symop.alive)) {
1149 /* Force for changing cell parameters */
1152 Transform da, tr, symtr, symtr2;
1153 if (ap2->symop.alive)
1154 rij2 = ATOM_AT_INDEX(arena->mol->atoms, ap2->symbase)->r;
1156 TransformVec(&rr, cell->rtr, &rij2);
1157 memmove(symtr, SYMMETRY_AT_INDEX(arena->mol->syms, ap2->symop.sym), sizeof(Transform));
1158 symtr[9] += ap2->symop.dx + vl->symop.dx;
1159 symtr[10] += ap2->symop.dy + vl->symop.dy;
1160 symtr[11] += ap2->symop.dz + vl->symop.dz;
1161 TransformMul(symtr2, symtr, cell->rtr);
1162 TransformMul(symtr2, cell->tr, symtr2);
1163 for (j = 0; j < 12; j++) {
1165 if (arena->periodic_a == 0 && (j == 0 || j == 1 || j == 2 || j == 3 || j == 6 || j == 9))
1167 if (arena->periodic_b == 0 && (j == 1 || j == 3 || j == 4 || j == 5 || j == 7 || j == 10))
1169 if (arena->periodic_c == 0 && (j == 2 || j == 5 || j == 6 || j == 7 || j == 8 || j == 11))
1171 memset(da, 0, sizeof(Transform));
1173 TransformMul(tr, symtr2, da);
1174 /* The translation part should be adjusted, because the derivative matrix
1175 has the (3,3) element as 0.0 (instead of 1.0). Thus,
1176 | R v | | R' v' | = | R*R' R*v' | (instead of R*v'+v)
1177 | 0 1 | | 0 0 | | 0 0 |
1178 da * symtr does not have this problem, because the derivative matrix is
1179 multipled from the left. */
1181 tr[10] -= symtr2[10];
1182 tr[11] -= symtr2[11];
1183 TransformMul(da, da, symtr);
1184 for (k = 0; k < 12; k++)
1186 TransformVec(&rrr, da, &rr);
1187 arena->cell_forces[j] += VecDot(fij2, rrr);
1196 s_calc_nonbonded_force(MDArena *arena)
1198 Double *energies = &arena->energies[kVDWIndex];
1199 Double *eenergies = &arena->energies[kElectrostaticIndex];
1200 Vector *forces = &arena->forces[kVDWIndex * arena->mol->natoms];
1201 Vector *eforces = &arena->forces[kElectrostaticIndex * arena->mol->natoms];
1202 s_calc_nonbonded_force_sub(arena, energies, eenergies, forces, eforces, NULL, NULL);
1206 s_calc_auxiliary_force(MDArena *arena)
1208 Double *energies = &arena->energies[kAuxiliaryIndex];
1209 Vector *forces = &arena->forces[kAuxiliaryIndex * arena->mol->natoms];
1210 Atom *atoms = arena->mol->atoms;
1211 int natoms = arena->mol->natoms;
1214 /* Centric force - OBSOLETE */
1215 /* if (arena->centric_potential_force > 0) {
1216 Vector center = arena->mol->atoms[arena->centric_potential_center].r;
1217 Double rin = arena->centric_potential_inner_limit;
1218 Double rout = arena->centric_potential_outer_limit;
1219 Double k = arena->centric_potential_force;
1220 for (i = 0; i < natoms; i++) {
1222 Double w1, w2, k0, k1;
1223 VecSub(r21, atoms[i].r, center);
1224 w2 = VecLength2(r21);
1228 } else if (rout > 0 && w1 > rout) {
1229 k0 = k * (rout - rin) * (w1 + w1 - rout + rin);
1230 k1 = -2.0 * k * (rout - rin) / w1;
1232 k0 = k * (w1 - rin) * (w1 - rin);
1233 k1 = -2.0 * k * (1 - rin / w1);
1236 VecScaleSelf(r21, k1);
1237 VecInc(forces[i], r21);
1239 if (arena->debug_result && arena->debug_output_level > 1) {
1240 fprintf(arena->debug_result, "auxiliary(centric) force %d: r=%f, k1=%f, {%f %f %f}\n", i, w1, k1*w1, r21.x, r21.y, r21.z);
1247 /* Spherical boundary conditions */
1248 if (arena->spherical_bc_force > 0) {
1249 Vector center = arena->spherical_bc_center;
1250 Double rin = arena->spherical_bc_inner_limit;
1251 Double rout = arena->spherical_bc_outer_limit;
1252 Double k = arena->spherical_bc_force;
1253 for (i = 0; i < natoms; i++) {
1255 Double w1, w2, k0, k1;
1256 VecSub(r21, atoms[i].r, center);
1257 w2 = VecLength2(r21);
1261 } else if (rout > 0 && w1 > rout) {
1262 k0 = k * (rout - rin) * (w1 + w1 - rout + rin);
1263 k1 = -2.0 * k * (rout - rin) / w1;
1265 k0 = k * (w1 - rin) * (w1 - rin);
1266 k1 = -2.0 * k * (1 - rin / w1);
1269 VecScaleSelf(r21, k1);
1270 VecInc(forces[i], r21);
1271 if (arena->debug_result && arena->debug_output_level > 1) {
1272 fprintf(arena->debug_result, "auxiliary(spherical BC) force %d: r=%f, k1=%f, {%f %f %f}\n", i, w1, k1*w1, r21.x, r21.y, r21.z);
1278 if (arena->box_potential_force > 0) {
1279 Double xsize = arena->box_potential_xsize;
1280 Double ysize = arena->box_potential_ysize;
1281 Double zsize = arena->box_potential_zsize;
1282 Double k = arena->box_potential_force;
1283 for (i = 0; i < natoms; i++) {
1284 Vector r = atoms[i].r;
1287 else if (r.x < -xsize)
1292 else if (r.y < -ysize)
1297 else if (r.z < -zsize)
1300 *energies += k * (r.x * r.x + r.y * r.y + r.z * r.z);
1301 VecScaleInc(forces[i], r, -2);
1302 if (arena->debug_result && arena->debug_output_level > 1) {
1303 fprintf(arena->debug_result, "auxiliary(box) force %d: {%f %f %f}\n", i, -2*r.x, -2*r.y, -2*r.z);
1309 for (i = j = 0; i < natoms; i++) {
1310 Atom *ap = &atoms[i];
1312 Double w1, w2, k0, k1;
1313 if (ap->fix_force <= 0.0)
1315 VecSub(r21, ap->r, ap->fix_pos);
1316 w2 = VecLength2(r21);
1318 k0 = ap->fix_force * w2;
1319 k1 = -2.0 * ap->fix_force * w1;
1321 VecScaleSelf(r21, k1);
1322 VecInc(forces[i], r21);
1324 if (arena->debug_result && arena->debug_output_level > 1) {
1325 fprintf(arena->debug_result, "auxiliary(fix) force %d: r=%f, k1=%f, {%f %f %f}\n", i, w1, k1*w1, r21.x, r21.y, r21.z);
1329 /* External forces (used for artificial deformation of the structure) */
1330 if (arena->nexforces > 0) {
1331 for (i = 0; i < arena->nexforces; i++) {
1332 VecInc(forces[i], arena->exforces[i]);
1337 if (arena->graphite != NULL && arena->use_graphite) {
1338 graphite_force(arena->graphite, arena, energies, forces);
1343 s_md_debug_output_positions(MDArena *arena)
1346 if (arena->debug_result == NULL || arena->debug_output_level == 0)
1348 fprintf(arena->debug_result, "\n Atom positions, velocities, and forces at step %d\n", arena->step);
1349 fprintf(arena->debug_result, "%5s %7s %7s %7s %7s %7s %7s %7s %7s %7s\n", "No.", "x", "y", "z", "vx", "vy", "vz", "fx", "fy", "fz");
1350 for (i = 0; i < arena->mol->natoms; i++) {
1351 Atom *ap = &arena->mol->atoms[i];
1352 fprintf(arena->debug_result, "%5d %7.3f %7.3f %7.3f %7.3f %7.3f %7.3f %7.3f %7.3f %7.3f\n", i+1, ap->r.x, ap->r.y, ap->r.z, ap->v.x, ap->v.y, ap->v.z, ap->f.x, ap->f.y, ap->f.z);
1357 calc_force(MDArena *arena)
1361 Molecule *mol = arena->mol;
1364 natoms = mol->natoms;
1366 /* Clear the energy/force storage */
1367 for (i = 0; i < natoms; i++)
1368 VecZero(mol->atoms[i].f);
1370 memset(arena->energies, 0, sizeof(Double) * kSlowIndex);
1371 memset(arena->forces, 0, sizeof(Vector) * kSlowIndex * natoms);
1372 arena->total_energy = 0.0;
1373 arena->alchem_energy = 0.0;
1375 if (arena->step == arena->start_step || arena->step % arena->surface_potential_freq == 0) {
1377 arena->energies[kSurfaceIndex] = 0.0;
1378 memset(arena->forces + kSurfaceIndex * natoms, 0, sizeof(Vector) * natoms);
1381 s_calc_bond_force(arena);
1382 s_calc_angle_force(arena);
1383 s_calc_dihedral_force(arena);
1384 s_calc_improper_force(arena);
1385 s_calc_pibond_force(arena);
1386 s_calc_nonbonded_force(arena);
1387 s_calc_auxiliary_force(arena);
1389 if (doSurface && arena->probe_radius > 0.0) {
1390 /* if (arena->sphere_points == 0)
1391 calc_surface_force(arena);
1393 calc_surface_force_2(arena); */
1394 calc_surface_force(arena);
1397 /* Sum up all partial forces and energies */
1398 arena->total_energy = 0.0;
1399 for (i = 0; i < kKineticIndex; i++)
1400 arena->total_energy += arena->energies[i];
1402 for (i = 0; i < natoms; i++) {
1403 if (mol->atoms[i].mm_exclude)
1405 fa = &mol->atoms[i].f;
1406 ff = &arena->forces[i];
1407 for (j = 0; j < kKineticIndex; j++) {
1413 /* The total (internal) force must be zero */
1418 for (i = 0; i < natoms; i++) {
1419 Vector *fp = &(mol->atoms[i].f);
1422 w = (natoms > 0 ? 1.0 / natoms : 0.0);
1424 for (i = 0; i < natoms; i++) {
1425 Vector *fp = &(mol->atoms[i].f);
1430 s_md_debug_output_positions(arena);
1434 calc_pair_interaction(MDArena *arena, const MDGroupFlags *group_flags_1, const MDGroupFlags *group_flags_2)
1436 Vector *forces, *eforces;
1437 if (arena->pair_forces != NULL) {
1438 forces = arena->pair_forces;
1439 eforces = forces + arena->mol->natoms;
1440 memset(forces, 0, sizeof(Vector) * arena->mol->natoms * 2);
1441 } else forces = eforces = NULL;
1442 arena->pair_energies[0] = arena->pair_energies[1] = 0.0;
1443 s_calc_nonbonded_force_sub(arena, &arena->pair_energies[0], &arena->pair_energies[1], forces, eforces, group_flags_1, group_flags_2);