4 * Created by Toshi Nagata on 2005/06/06.
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"
19 #include "MDPressure.h"
28 #define ftello(x) ftell(x)
31 static char sErrBuf[256];
34 md_panic(MDArena *arena, const char *fmt,...)
39 /* Clean up the running simulation */
40 md_flush_output_files(arena);
41 arena->is_running = 0;
42 arena->mol->needsMDRebuild = 1;
45 vsnprintf(arena->errmsg, sizeof(arena->errmsg), fmt, ap);
48 envp = arena->setjmp_buf;
49 arena->setjmp_buf = NULL;
50 if (arena->md_panic_func != NULL)
51 (*(arena->md_panic_func))(arena, arena->errmsg);
55 fprintf(stderr, "%s\n", sErrBuf);
61 extern int MyAppCallback_showScriptMessage(const char *fmt, ...);
64 md_warning(MDArena *arena, const char *fmt, ...)
69 vsnprintf(buf, sizeof buf, fmt, ap);
71 MyAppCallback_showScriptMessage("%s", buf);
72 if (arena->log_result != NULL)
73 fputs(buf, arena->log_result);
78 md_log(MDArena *arena, const char *fmt, ...)
82 if (arena->log_result == NULL)
85 fflush(arena->log_result);
89 vsnprintf(buf, sizeof buf, fmt, ap);
91 fputs(buf, arena->log_result);
96 md_debug(MDArena *arena, const char *fmt,...)
99 if (arena->debug_result == NULL || arena->debug_output_level == 0)
102 vfprintf(arena->debug_result, fmt, ap);
104 fflush(arena->debug_result);
108 #define DEBUG_FIT_COORDINATES 0 /* set to 1 while debugging md_fit_coordinates */
111 /* Calculate the transform that moves the current coordinates to the reference
112 coordinates with least displacements. The reference coordinates are given
113 as one of the snapshots (refno = zero-based) */
115 md_fit_coordinates(MDArena *arena, Int refno, Double *weights, Transform trans)
127 if (arena == NULL || arena->mol == NULL || arena->mol->natoms == 0)
128 return 1; /* Molecule is empty */
129 if (refno < 0 || refno >= arena->nsnapshots)
130 return 2; /* No such snapshot */
131 natoms = arena->mol->natoms;
132 ap = arena->mol->atoms;
133 rvf = arena->snapshots[refno]->rvf;
135 /* Calculate the weighted center */
136 for (j = 0; j < 2; j++) {
137 Vector *op = (j == 0 ? &org1 : &org2);
140 for (i = 0; i < natoms; i++) {
141 w1 = (weights != NULL ? weights[i] : ap[i].weight);
145 VecScaleInc(*op, ap[i].r, w1);
147 VecScaleInc(*op, rvf[i * 3], w1);
151 VecScaleSelf(*op, w);
154 /* R = sum(weight[n] * x[n] * t(y[n])); */
155 /* Matrix to diagonalize = R * tR */
156 memset(r, 0, sizeof(Mat33));
157 memset(q, 0, sizeof(Mat33));
158 memset(u, 0, sizeof(Mat33));
160 for (i = 0; i < natoms; i++) {
162 w1 = (weights != NULL ? weights[i] : ap[i].weight);
165 VecSub(v1, ap[i].r, org1);
166 VecSub(v2, rvf[3 * i], org2);
167 r[0] += w1 * v2.x * v1.x;
168 r[1] += w1 * v2.y * v1.x;
169 r[2] += w1 * v2.z * v1.x;
170 r[3] += w1 * v2.x * v1.y;
171 r[4] += w1 * v2.y * v1.y;
172 r[5] += w1 * v2.z * v1.y;
173 r[6] += w1 * v2.x * v1.z;
174 r[7] += w1 * v2.y * v1.z;
175 r[8] += w1 * v2.z * v1.z;
176 /* for (j = 0; j < 3; j++) {
177 for (k = 0; k < 3; k++) {
178 r[3*j+k] += w1 * VecIndex(&v2, j) * VecIndex(&v1, k);
179 #if DEBUG_FIT_COORDINATES
180 printf("r(%d,%d) += %.6g * %.6g * %.6g (%.6g)\n", j, k, w1, VecIndex(&v2, j), VecIndex(&v1, k), r[3*j+k]);
187 for (i = 0; i < 9; i++)
189 for (i = 0; i < 3; i++) {
190 for (j = 0; j < 3; j++) {
191 for (k = 0; k < 3; k++) {
192 q[j*3+i] += r[k*3+i] * r[k*3+j];
197 #if DEBUG_FIT_COORDINATES
198 printf("Matrix to diagonalize:\n");
199 for (i = 0; i < 3; i++) {
200 printf("%10.6g %10.6g %10.6g\n", q[i*3], q[i*3+1], q[i*3+2]);
204 if (MatrixSymDiagonalize(q, eigen_val, eigen_vec) != 0)
205 return 3; /* Cannot determine the eigenvector */
207 #if DEBUG_FIT_COORDINATES
208 for (i = 0; i < 3; i++) {
209 printf("Eigenvalue %d = %.6g\n", i+1, eigen_val[i]);
210 printf("Eigenvector %d: %.6g %.6g %.6g\n", i+1, eigen_vec[i].x, eigen_vec[i].y, eigen_vec[i].z);
214 /* s[i] = normalize(tR * v[i]) */
215 /* U = s0*t(v0) + s1*t(v1) + s2*t(v2) */
216 MatrixTranspose(r, r);
217 for (i = 0; i < 3; i++) {
218 MatrixVec(&s[i], r, &eigen_vec[i]);
219 w1 = 1.0 / VecLength(s[i]);
220 VecScaleSelf(s[i], w1);
221 #if DEBUG_FIT_COORDINATES
222 printf("s[%d] = %.6g %.6g %.6g\n", i+1, s[i].x, s[i].y, s[i].z);
225 /* for (i = 0; i < 3; i++) {
226 for (j = 0; j < 3; j++) {
227 for (k = 0; k < 3; k++) {
228 u[3*i+j] += VecIndex(&s[k], j) * VecIndex(&eigen_vec[k], i);
233 for (k = 0; k < 3; k++) {
234 u[0] += s[k].x * eigen_vec[k].x;
235 u[1] += s[k].x * eigen_vec[k].y;
236 u[2] += s[k].x * eigen_vec[k].z;
237 u[3] += s[k].y * eigen_vec[k].x;
238 u[4] += s[k].y * eigen_vec[k].y;
239 u[5] += s[k].y * eigen_vec[k].z;
240 u[6] += s[k].z * eigen_vec[k].x;
241 u[7] += s[k].z * eigen_vec[k].y;
242 u[8] += s[k].z * eigen_vec[k].z;
245 /* y = U*(x - org1) + org2 = U*x + (org2 - U*org1) */
246 MatrixVec(&org1, u, &org1);
248 for (i = 0; i < 9; i++)
258 s_register_missing_parameters(Int **missing, Int *nmissing, Int type, Int t1, Int t2, Int t3, Int t4)
262 for (i = 0, mp = *missing; i < *nmissing; i++, mp += 5) {
263 if (mp[0] == type && mp[1] == t1 && mp[2] == t2 && mp[3] == t3 && mp[4] == t4)
264 return; /* Already registered */
266 mp = (Int *)AssignArray(missing, nmissing, sizeof(Int)*5, *nmissing, NULL);
276 /* Check the bonded atoms and append to results if not already present */
277 /* results[] is terminated by -1, hence must be at least (natom+1) size */
279 s_check_bonded(Atom *ap, Int *results)
283 cp = AtomConnects(ap);
284 for (i = 0; i < ap->nconnects; i++, cp++) {
286 for (ip = results; *ip >= 0; ip++) {
295 for (ip = results; *ip >= 0; ip++)
301 s_make_exclusion_list(MDArena *arena)
304 Int natoms = arena->mol->natoms;
305 Atom *atoms = arena->mol->atoms;
307 int next_index, i, j;
309 results = (Int *)calloc(sizeof(Int), natoms + 1);
311 md_panic(arena, ERROR_out_of_memory);
313 if (arena->exlist != NULL) {
315 arena->exlist = NULL;
319 if (arena->exinfo != NULL)
321 arena->exinfo = (MDExclusion *)calloc(sizeof(MDExclusion), natoms + 1);
322 if (arena->exinfo == NULL)
323 md_panic(arena, ERROR_out_of_memory);
324 exinfo = arena->exinfo;
327 for (i = 0; i < natoms; i++) {
329 exinfo[i].index0 = 0;
330 /* special exclusion: only self */
333 exinfo[i].index1 = 1;
334 /* 1-2 exclusion (directly bonded) */
335 exinfo[i].index2 = s_check_bonded(&atoms[i], results);
336 n = exinfo[i].index2;
337 /* 1-3 exclusion: atoms bonded to 1-2 exclusions */
338 for (j = exinfo[i].index1; j < exinfo[i].index2; j++)
339 n = s_check_bonded(&atoms[results[j]], results);
340 exinfo[i].index3 = n;
341 /* 1-4 exclusion: atoms bonded to 1-3 exclusions */
342 for (j = exinfo[i].index2; j < exinfo[i].index3; j++)
343 n = s_check_bonded(&atoms[results[j]], results);
344 AssignArray(&arena->exlist, &arena->nexlist, sizeof(Int), next_index + n, NULL);
345 memcpy(arena->exlist + next_index, results, n * sizeof(Int));
346 exinfo[i].index0 += next_index;
347 exinfo[i].index1 += next_index;
348 exinfo[i].index2 += next_index;
349 exinfo[i].index3 += next_index;
352 exinfo[natoms].index0 = next_index; /* End of exlist */
358 s_lookup_improper_pars(Parameter *par, Int type1, Int type2, Int type3, Int type4)
362 for (idx = par->nimproperPars - 1; idx >= 0; idx--) {
363 t1 = par->improperPars[idx].type1;
364 t2 = par->improperPars[idx].type2;
365 t3 = par->improperPars[idx].type3;
366 t4 = par->improperPars[idx].type4;
368 continue; /* Custom parameter */
369 if (t3 >= 0 && t3 != type3)
371 if ((t1 < 0 || t1 == type1) &&
372 (t2 < 0 || t2 == type2) &&
373 (t4 < 0 || t4 == type4))
375 if ((t1 < 0 || t1 == type1) &&
376 (t2 < 0 || t2 == type4) &&
377 (t4 < 0 || t4 == type2))
379 if ((t1 < 0 || t1 == type2) &&
380 (t2 < 0 || t2 == type1) &&
381 (t4 < 0 || t4 == type4))
383 if ((t1 < 0 || t1 == type2) &&
384 (t2 < 0 || t2 == type4) &&
385 (t4 < 0 || t4 == type1))
387 if ((t1 < 0 || t1 == type4) &&
388 (t2 < 0 || t2 == type1) &&
389 (t4 < 0 || t4 == type2))
391 if ((t1 < 0 || t1 == type4) &&
392 (t2 < 0 || t2 == type2) &&
393 (t4 < 0 || t4 == type1))
400 md_check_abnormal_bond(MDArena *arena, Molecule *mol, int idx)
408 if (arena->par == NULL || idx < 0 || idx >= mol->nbonds || (idx2 = arena->bond_par_i[idx]) < 0 || idx2 >= arena->par->nbondPars)
410 ap1 = ATOM_AT_INDEX(mol->atoms, mol->bonds[idx * 2]);
411 ap2 = ATOM_AT_INDEX(mol->atoms, mol->bonds[idx * 2 + 1]);
412 bp = arena->par->bondPars + idx2;
413 if (bp->k == 0.0 || bp->r0 == 0.0)
415 d = MoleculeMeasureBond(mol, &(ap1->r), &(ap2->r));
416 return (fabs(d / bp->r0 - 1.0) >= 0.2);
420 md_check_abnormal_angle(MDArena *arena, Molecule *mol, int idx)
423 Atom *ap1, *ap2, *ap3;
428 if (arena->par == NULL || idx < 0 || idx >= mol->nangles || (idx2 = arena->angle_par_i[idx]) < 0 || idx2 >= arena->par->nanglePars)
430 ap1 = ATOM_AT_INDEX(mol->atoms, mol->angles[idx * 3]);
431 ap2 = ATOM_AT_INDEX(mol->atoms, mol->angles[idx * 3 + 1]);
432 ap3 = ATOM_AT_INDEX(mol->atoms, mol->angles[idx * 3 + 2]);
433 anp = arena->par->anglePars + idx2;
434 if (anp->k == 0.0 || anp->a0 == 0.0)
436 d = MoleculeMeasureAngle(mol, &(ap1->r), &(ap2->r), &(ap3->r));
437 return (fabs(d - anp->a0 * kRad2Deg) >= 20.0);
441 md_check_abnormal_dihedral(MDArena *arena, Molecule *mol, int idx)
444 Atom *ap1, *ap2, *ap3, *ap4;
449 if (arena->par == NULL || idx < 0 || idx >= mol->ndihedrals || (idx2 = arena->dihedral_par_i[idx]) < 0 || idx2 >= arena->par->ndihedralPars)
451 ap1 = ATOM_AT_INDEX(mol->atoms, mol->dihedrals[idx * 4]);
452 ap2 = ATOM_AT_INDEX(mol->atoms, mol->dihedrals[idx * 4 + 1]);
453 ap3 = ATOM_AT_INDEX(mol->atoms, mol->dihedrals[idx * 4 + 2]);
454 ap4 = ATOM_AT_INDEX(mol->atoms, mol->dihedrals[idx * 4 + 3]);
455 tp = arena->par->dihedralPars + idx2;
458 d = MoleculeMeasureDihedral(mol, &(ap1->r), &(ap2->r), &(ap3->r), &(ap4->r));
459 if (tp->period[0] == 0)
460 return (fabs(d - tp->phi0[0] * kRad2Deg) >= 20.0);
462 d = (tp->period[0] * (d - tp->phi0[0] * kRad2Deg)) / 360.0 + 0.5;
463 d = (d - floor(d) - 0.5) * 360.0; /* map to [-180, 180] */
464 return (fabs(d) >= 20.0);
469 md_check_abnormal_improper(MDArena *arena, Molecule *mol, int idx)
472 Atom *ap1, *ap2, *ap3, *ap4;
477 if (arena->par == NULL || idx < 0 || idx >= mol->ndihedrals || (idx2 = arena->improper_par_i[idx]) < 0 || idx2 >= arena->par->nimproperPars)
479 ap1 = ATOM_AT_INDEX(mol->atoms, mol->impropers[idx * 4]);
480 ap2 = ATOM_AT_INDEX(mol->atoms, mol->impropers[idx * 4 + 1]);
481 ap3 = ATOM_AT_INDEX(mol->atoms, mol->impropers[idx * 4 + 2]);
482 ap4 = ATOM_AT_INDEX(mol->atoms, mol->impropers[idx * 4 + 3]);
483 tp = arena->par->improperPars + idx2;
486 d = MoleculeMeasureDihedral(mol, &(ap1->r), &(ap2->r), &(ap3->r), &(ap4->r));
487 if (tp->period[0] == 0)
488 return (fabs(d - tp->phi0[0] * kRad2Deg) >= 20.0);
490 d = (tp->period[0] * (d - tp->phi0[0] * kRad2Deg)) / 360.0 + 0.5;
491 d = (d - floor(d) - 0.5) * 360.0; /* map to [-180, 180] */
492 return (fabs(d) >= 20.0);
497 s_search_bond(MDArena *arena, int n1, int n2)
500 if (n1 < 0 || n1 >= arena->mol->natoms || n2 < 0 || n2 >= arena->mol->natoms)
502 for (i = 0, ip = arena->mol->bonds; i < arena->mol->nbonds; i++, ip += 2) {
503 if ((ip[0] == n1 && ip[1] == n2) || (ip[0] == n2 && ip[1] == n1))
510 s_search_angle(MDArena *arena, int n1, int n2, int n3)
513 if (n1 < 0 || n1 >= arena->mol->natoms || n2 < 0 || n2 >= arena->mol->natoms || n3 < 0 || n3 >= arena->mol->natoms)
515 for (i = 0, ip = arena->mol->angles; i < arena->mol->nangles; i++, ip += 3) {
516 if (ip[1] == n2 && ((ip[0] == n1 && ip[2] == n3) || (ip[0] == n3 && ip[2] == n1)))
523 s_search_dihedral(MDArena *arena, int n1, int n2, int n3, int n4)
526 if (n1 < 0 || n1 >= arena->mol->natoms || n2 < 0 || n2 >= arena->mol->natoms || n3 < 0 || n3 >= arena->mol->natoms || n4 < 0 || n4 >= arena->mol->natoms)
528 for (i = 0, ip = arena->mol->dihedrals; i < arena->mol->ndihedrals; i++, ip += 4) {
529 if ((ip[0] == n1 && ip[1] == n2 && ip[2] == n3 && ip[3] == n4) || (ip[0] == n4 && ip[1] == n3 && ip[2] == n2 && ip[3] == n1))
536 s_search_improper(MDArena *arena, int n1, int n2, int n3, int n4)
539 if (n1 < 0 || n1 >= arena->mol->natoms || n2 < 0 || n2 >= arena->mol->natoms || n3 < 0 || n3 >= arena->mol->natoms || n4 < 0 || n4 >= arena->mol->natoms)
541 for (i = 0, ip = arena->mol->impropers; i < arena->mol->nimpropers; i++, ip += 4) {
542 if ((ip[0] == n1 && ip[1] == n2 && ip[2] == n3 && ip[3] == n4) || (ip[0] == n4 && ip[1] == n3 && ip[2] == n2 && ip[3] == n1))
548 /* Find vdw parameters and build the in-use list */
550 s_find_vdw_parameters(MDArena *arena)
552 Int idx, i, j, type1, type2, t1, nmissing;
553 Double cutoff6, cutoff12;
554 Parameter *par = arena->par;
555 Molecule *mol = arena->mol;
559 if (arena->vdw_par_i != NULL)
560 free(arena->vdw_par_i);
561 arena->vdw_par_i = (Int *)calloc(sizeof(Int), mol->natoms);
562 if (arena->vdw_par_i == NULL)
563 md_panic(arena, ERROR_out_of_memory);
565 /* Find the vdw parameter; priority: (1) variant-aware in mol->par, (2) mol->par ignoring variants,
566 (3) variant->aware in global par, (4) global par ignoring variants */
567 for (i = 0, ap = mol->atoms; i < mol->natoms; i++, ap = ATOM_NEXT(ap)) {
568 if (mol->par != NULL) {
569 vp = ParameterLookupVdwPar(mol->par, ap->type, 0);
570 /* vp = ParameterLookupVdwPar(mol->par, i, kParameterLookupLocal | kParameterLookupNoWildcard);
572 vp = ParameterLookupVdwPar(mol->par, ap->type, kParameterLookupLocal | kParameterLookupGlobal); */
574 arena->vdw_par_i[i] = (vp - mol->par->vdwPars) + ATOMS_MAX_NUMBER * 2;
578 vp = ParameterLookupVdwPar(gBuiltinParameters, ap->type, 0);
580 arena->vdw_par_i[i] = (vp - gBuiltinParameters->vdwPars) + ATOMS_MAX_NUMBER;
583 /* Record as missing */
584 vp = ParameterLookupVdwPar(par, ap->type, kParameterLookupMissing | kParameterLookupNoBaseAtomType);
586 vp = AssignArray(&par->vdwPars, &par->nvdwPars, sizeof(VdwPar), par->nvdwPars, NULL);
588 vp->type1 = ap->type;
590 arena->vdw_par_i[i] = (vp - par->vdwPars);
592 nmissing = par->nvdwPars;
594 /* Copy the vdw parameters */
595 /* Atoms with the same vdw parameters point to one common entry */
596 /* Except when the atom appears in one of the pair-specific vdw parameters with
597 atom index specification; in that case, that atom is given a separate entry */
598 for (i = 0, idx = par->nvdwPars; i < mol->natoms; i++) {
599 t1 = arena->vdw_par_i[i];
600 if (t1 < ATOMS_MAX_NUMBER)
602 arena->vdw_par_i[i] = idx;
603 if (mol->par != NULL) {
604 /* Look up the pair-specific vdw parameters with atom index specification */
605 for (j = mol->par->nvdwpPars - 1; j >= 0; j--) {
606 VdwPairPar *vpp = mol->par->vdwpPars + j;
607 if (vpp->type1 == i || vpp->type2 == i)
612 /* Not found: all other entries with the same vdw parameters share the entry */
613 for (j = i + 1; j < mol->natoms; j++) {
614 if (arena->vdw_par_i[j] == t1)
615 arena->vdw_par_i[j] = idx;
618 if (t1 >= ATOMS_MAX_NUMBER * 2)
619 vp = mol->par->vdwPars + (t1 - ATOMS_MAX_NUMBER * 2);
620 else vp = gBuiltinParameters->vdwPars + (t1 - ATOMS_MAX_NUMBER);
621 AssignArray(&par->vdwPars, &par->nvdwPars, sizeof(VdwPar), idx, vp);
626 if (arena->debug_result != NULL && arena->debug_output_level > 0) {
627 fprintf(arena->debug_result, "\n Atom van der Waals parameters\n");
628 fprintf(arena->debug_result, " No. type vdw_i sigma eps sigma14 eps14\n");
629 for (i = 0; i < mol->natoms; i++) {
631 idx = arena->vdw_par_i[i];
632 fprintf(arena->debug_result, "%5d %-4s %5d ", i+1, AtomTypeDecodeToString(mol->atoms[i].type, s), idx);
634 Double sigma, eps, sigma2, eps2;
635 sigma = par->vdwPars[idx].A;
636 eps = par->vdwPars[idx].B;
638 eps = 0.25 * eps * eps / sigma;
639 sigma = pow(sigma / eps * 0.25, 1.0/12.0);
643 sigma2 = par->vdwPars[idx].A14;
644 eps2 = par->vdwPars[idx].B14;
646 eps2 = 0.25 * eps2 * eps2 / sigma2;
647 sigma2 = pow(sigma2 / eps2 * 0.25, 1.0/12.0);
651 fprintf(arena->debug_result, " %7.3f %7.3f %7.3f %7.3f\n", sigma, eps*INTERNAL2KCAL, sigma2, eps2*INTERNAL2KCAL);
653 fprintf(arena->debug_result, " (not available)\n");
659 if (arena->vdw_cache != NULL)
660 free(arena->vdw_cache);
661 arena->vdw_cache = (MDVdwCache *)calloc(sizeof(MDVdwCache), par->nvdwPars * par->nvdwPars + 1);
662 if (arena->vdw_cache == NULL)
663 md_panic(arena, ERROR_out_of_memory);
664 cutoff6 = arena->cutoff * arena->cutoff;
665 cutoff6 = 1.0 / (cutoff6 * cutoff6 * cutoff6);
666 cutoff12 = cutoff6 * cutoff6;
667 if (arena->debug_result != NULL && arena->debug_output_level > 0) {
668 fprintf(arena->debug_result, "\n van der Waals parameter cache table\n");
669 fprintf(arena->debug_result, " idx1 idx2 type1 type2 sigma eps sigma14 eps14\n");
671 for (i = 0; i < par->nvdwPars; i++) {
672 /* t1 = arena->vdw_par_i[i];
673 type1 = par->vdwPars[t1].type1; */
674 type1 = par->vdwPars[i].type1;
675 for (j = i; j < par->nvdwPars; j++) {
676 VdwPairPar newpar, *vpp;
677 Double sigma1, sigma2, eps1, eps2;
679 /* t2 = arena->vdw_par_i[j];
680 type2 = par->vdwPars[t2].type1; */
681 type2 = par->vdwPars[j].type1; /* Not type2 */
682 /* Look up the pair-specific van der Waals parameters */
683 if (mol->par != NULL) {
684 vpp = ParameterLookupVdwPairPar(mol->par, type1, type2, 0);
687 vpp = ParameterLookupVdwPairPar(gBuiltinParameters, type1, type2, 0);
691 /* Create a pair-specific VdwPar for this pair */
693 p1 = par->vdwPars + i;
694 p2 = par->vdwPars + j;
695 if (p1->A < 1e-15 && p1->A > -1e-15) {
699 eps1 = 0.25 * p1->B * p1->B / p1->A;
700 sigma1 = pow(p1->B * 0.25 / eps1, 1.0/6.0);
702 if (p2->A < 1e-15 && p2->A > -1e-15) {
706 eps2 = 0.25 * p2->B * p2->B / p2->A;
707 sigma2 = pow(p2->B * 0.25 / eps2, 1.0/6.0);
709 sigma1 = (sigma1 + sigma2) * 0.5;
710 eps1 = sqrt(eps1 * eps2);
711 sigma1 = sigma1 * sigma1 * sigma1;
712 sigma1 = sigma1 * sigma1;
713 newpar.B = 4.0 * sigma1 * eps1;
714 newpar.A = newpar.B * sigma1;
715 if (p1->A14 < 1e-15 && p1->A14 > -1e-15) {
719 eps1 = 0.25 * p1->B14 * p1->B14 / p1->A14;
720 sigma1 = pow(p1->B14 * 0.25 / eps1, 1.0/6.0);
722 if (p2->A14 < 1e-15 && p2->A14 > -1e-15) {
726 eps2 = 0.25 * p2->B14 * p2->B14 / p2->A14;
727 sigma2 = pow(p2->B14 * 0.25 / eps2, 1.0/6.0);
729 sigma1 = (sigma1 + sigma2) * 0.5;
730 eps1 = sqrt(eps1 * eps2);
731 sigma1 = sigma1 * sigma1 * sigma1;
732 sigma1 = sigma1 * sigma1;
733 newpar.B14 = 4.0 * sigma1 * eps1;
734 newpar.A14 = newpar.B14 * sigma1;
735 newpar.type1 = type1;
736 newpar.type2 = type2;
738 idx = i * par->nvdwPars + j;
739 arena->vdw_cache[idx].par = newpar;
740 /* Cache the value at the cutoff distance */
741 arena->vdw_cache[idx].vcut = newpar.A * cutoff12 - newpar.B * cutoff6;
742 arena->vdw_cache[idx].vcut14 = newpar.A14 * cutoff12 - newpar.B * cutoff6;
743 arena->vdw_cache[j * par->nvdwPars + i] = arena->vdw_cache[idx];
744 if (arena->debug_result != NULL && arena->debug_output_level > 0) {
746 eps1 = 0.25 * newpar.B * newpar.B / newpar.A;
747 sigma1 = pow(newpar.B * 0.25 / eps1, 1.0/6.0);
748 eps2 = 0.25 * newpar.B14 * newpar.B14 / newpar.A14;
749 sigma2 = pow(newpar.B14 * 0.25 / eps2, 1.0/6.0);
750 fprintf(arena->debug_result, "%5d %5d %-4s %-4s %7.3f %7.3f %7.3f %7.3f\n", idx, i, AtomTypeDecodeToString(type1, s1), AtomTypeDecodeToString(type2, s2), sigma1, eps1*INTERNAL2KCAL, sigma2, eps2*INTERNAL2KCAL);
754 arena->nmissing += nmissing;
758 /* Find bond parameters */
760 s_find_bond_parameters(MDArena *arena)
762 Int i, j, idx, type1, type2, t1, nmissing = 0;
763 Molecule *mol = arena->mol;
764 Parameter *par = arena->par;
767 if (mol->nbonds > 0) {
768 if (arena->bond_par_i != NULL)
769 free(arena->bond_par_i);
770 arena->bond_par_i = (Int *)calloc(sizeof(Int), mol->nbonds);
771 if (arena->bond_par_i == NULL)
772 md_panic(arena, ERROR_out_of_memory);
773 if (arena->anbond_r0 != NULL)
774 free(arena->anbond_r0);
775 arena->anbond_r0 = (Double *)calloc(sizeof(Double), mol->nbonds);
776 if (arena->anbond_r0 == NULL)
777 md_panic(arena, ERROR_out_of_memory);
779 /* Find the bond parameter; priority: (1) atom index specific in mol->par, (2)
780 atom type specific in mol->par, (3) atom type specific in built-in */
781 for (i = 0; i < mol->nbonds; i++) {
784 i1 = mol->bonds[i * 2];
785 i2 = mol->bonds[i * 2 + 1];
786 ap1 = ATOM_AT_INDEX(mol->atoms, i1);
787 ap2 = ATOM_AT_INDEX(mol->atoms, i2);
791 if (mol->par != NULL) {
792 bp = ParameterLookupBondPar(mol->par, type1, type2, i1, i2, 0);
794 arena->bond_par_i[i] = (bp - mol->par->bondPars) + ATOMS_MAX_NUMBER * 2;
798 bp = ParameterLookupBondPar(gBuiltinParameters, type1, type2, -1, -1, 0);
800 arena->bond_par_i[i] = (bp - gBuiltinParameters->bondPars) + ATOMS_MAX_NUMBER;
803 bp = ParameterLookupBondPar(par, type1, type2, -1, -1, kParameterLookupMissing | kParameterLookupNoBaseAtomType);
805 /* Record as missing */
806 bp = AssignArray(&par->bondPars, &par->nbondPars, sizeof(BondPar), par->nbondPars, NULL);
811 arena->bond_par_i[i] = (bp - par->bondPars);
813 nmissing = par->nbondPars;
815 /* Copy the bond parameters */
816 for (i = 0, idx = par->nbondPars; i < mol->nbonds; i++) {
817 t1 = arena->bond_par_i[i];
818 if (t1 < ATOMS_MAX_NUMBER)
820 arena->bond_par_i[i] = idx;
821 for (j = i + 1; j < mol->nbonds; j++) {
822 if (arena->bond_par_i[j] == t1)
823 arena->bond_par_i[j] = idx;
825 if (t1 >= ATOMS_MAX_NUMBER * 2)
826 bp = mol->par->bondPars + (t1 - ATOMS_MAX_NUMBER * 2);
827 else bp = gBuiltinParameters->bondPars + (t1 - ATOMS_MAX_NUMBER);
828 AssignArray(&par->bondPars, &par->nbondPars, sizeof(BondPar), idx, bp);
832 if (arena->debug_result != NULL && arena->debug_output_level > 0) {
834 fprintf(arena->debug_result, "\n Bond parameters\n");
835 fprintf(arena->debug_result, " No. atom1 atom2 type1 type2 r0 k\n");
836 for (i = 0; i < mol->nbonds; i++) {
837 idx = arena->bond_par_i[i];
838 fprintf(arena->debug_result, "%5d %5d %5d ", i+1, mol->bonds[i*2]+1, mol->bonds[i*2+1]+1);
840 fprintf(arena->debug_result, "<< missing >>\n");
843 fprintf(arena->debug_result, " %-4s %-4s %7.3f %7.3f\n", AtomTypeDecodeToString(par->bondPars[idx].type1, s1), AtomTypeDecodeToString(par->bondPars[idx].type2, s2), par->bondPars[idx].r0, par->bondPars[idx].k*INTERNAL2KCAL);
846 arena->nmissing += nmissing;
850 /* Find angle parameters */
852 s_find_angle_parameters(MDArena *arena)
854 Int i, j, idx, type1, type2, type3, t1, nmissing = 0;
855 Molecule *mol = arena->mol;
856 Parameter *par = arena->par;
859 if (mol->nangles > 0) {
860 if (arena->angle_par_i != NULL)
861 free(arena->angle_par_i);
862 arena->angle_par_i = (Int *)calloc(sizeof(Int), mol->nangles);
863 if (arena->angle_par_i == NULL)
864 md_panic(arena, ERROR_out_of_memory);
866 /* Find the angle parameter; priority: (1) atom index specific in mol->par, (2)
867 atom type specific in mol->par, (3) atom type specific in built-in */
868 for (i = 0; i < mol->nangles; i++) {
870 i1 = mol->angles[i * 3];
871 i2 = mol->angles[i * 3 + 1];
872 i3 = mol->angles[i * 3 + 2];
873 type1 = ATOM_AT_INDEX(mol->atoms, i1)->type;
874 type2 = ATOM_AT_INDEX(mol->atoms, i2)->type;
875 type3 = ATOM_AT_INDEX(mol->atoms, i3)->type;
876 if (mol->par != NULL) {
877 ap = ParameterLookupAnglePar(mol->par, type1, type2, type3, i1, i2, i3, 0);
879 arena->angle_par_i[i] = (ap - mol->par->anglePars) + ATOMS_MAX_NUMBER * 2;
883 ap = ParameterLookupAnglePar(gBuiltinParameters, type1, type2, type3, -1, -1, -1, 0);
885 arena->angle_par_i[i] = (ap - gBuiltinParameters->anglePars) + ATOMS_MAX_NUMBER;
888 /* Record as missing */
889 ap = ParameterLookupAnglePar(par, type1, type2, type3, -1, -1, -1, kParameterLookupMissing | kParameterLookupNoBaseAtomType);
891 ap = AssignArray(&par->anglePars, &par->nanglePars, sizeof(AnglePar), par->nanglePars, NULL);
897 arena->angle_par_i[i] = (ap - par->anglePars);
899 nmissing = par->nanglePars;
901 /* Copy the angle parameters */
902 for (i = 0, idx = par->nanglePars; i < mol->nangles; i++) {
903 t1 = arena->angle_par_i[i];
904 if (t1 < ATOMS_MAX_NUMBER)
906 arena->angle_par_i[i] = idx;
907 for (j = i + 1; j < mol->nangles; j++) {
908 if (arena->angle_par_i[j] == t1)
909 arena->angle_par_i[j] = idx;
911 if (t1 >= ATOMS_MAX_NUMBER * 2)
912 ap = mol->par->anglePars + (t1 - ATOMS_MAX_NUMBER * 2);
913 else ap = gBuiltinParameters->anglePars + (t1 - ATOMS_MAX_NUMBER);
914 AssignArray(&par->anglePars, &par->nanglePars, sizeof(AnglePar), idx, ap);
919 if (arena->debug_result != NULL && arena->debug_output_level > 0) {
920 char s1[8], s2[8], s3[8];
921 fprintf(arena->debug_result, "\n Angle parameters\n");
922 fprintf(arena->debug_result, " No. atom1 atom2 atom3 type1 type2 type3 a0 k\n");
923 for (i = 0; i < mol->nangles; i++) {
924 idx = arena->angle_par_i[i];
925 fprintf(arena->debug_result, "%5d %5d %5d %5d ", i+1, mol->angles[i*3]+1, mol->angles[i*3+1]+1, mol->angles[i*3+2]+1);
927 fprintf(arena->debug_result, "<< missing >>\n");
930 fprintf(arena->debug_result, " %-4s %-4s %-4s %7.3f %7.3f\n", AtomTypeDecodeToString(par->anglePars[idx].type1, s1), AtomTypeDecodeToString(par->anglePars[idx].type2, s2), AtomTypeDecodeToString(par->anglePars[idx].type3, s3), par->anglePars[idx].a0 * 180.0 / 3.1415927, par->anglePars[idx].k*INTERNAL2KCAL);
933 arena->nmissing += nmissing;
937 /* Find dihedral parameters */
939 s_find_dihedral_parameters(MDArena *arena)
941 Int i, j, idx, type1, type2, type3, type4, t1, nmissing = 0;
942 Molecule *mol = arena->mol;
943 Parameter *par = arena->par;
946 if (mol->ndihedrals > 0) {
947 if (arena->dihedral_par_i != NULL)
948 free(arena->dihedral_par_i);
949 arena->dihedral_par_i = (Int *)calloc(sizeof(Int), mol->ndihedrals);
950 if (arena->dihedral_par_i == NULL)
951 md_panic(arena, ERROR_out_of_memory);
953 /* Find the dihedral parameter; priority: (1) atom index specific in mol->par, (2)
954 atom type specific in mol->par, (3) atom type specific in built-in */
955 for (i = 0; i < mol->ndihedrals; i++) {
957 i1 = mol->dihedrals[i * 4];
958 i2 = mol->dihedrals[i * 4 + 1];
959 i3 = mol->dihedrals[i * 4 + 2];
960 i4 = mol->dihedrals[i * 4 + 3];
961 type1 = ATOM_AT_INDEX(mol->atoms, i1)->type;
962 type2 = ATOM_AT_INDEX(mol->atoms, i2)->type;
963 type3 = ATOM_AT_INDEX(mol->atoms, i3)->type;
964 type4 = ATOM_AT_INDEX(mol->atoms, i4)->type;
965 if (mol->par != NULL) {
966 tp = ParameterLookupDihedralPar(mol->par, type1, type2, type3, type4, i1, i2, i3, i4, 0);
968 arena->dihedral_par_i[i] = (tp - mol->par->dihedralPars) + ATOMS_MAX_NUMBER * 2;
972 tp = ParameterLookupDihedralPar(gBuiltinParameters, type1, type2, type3, type4, -1, -1, -1, -1, 0);
974 arena->dihedral_par_i[i] = (tp - gBuiltinParameters->dihedralPars) + ATOMS_MAX_NUMBER;
977 /* Record as missing */
978 tp = ParameterLookupDihedralPar(par, type1, type2, type3, type4, -1, -1, -1, -1, kParameterLookupMissing | kParameterLookupNoBaseAtomType);
980 tp = AssignArray(&par->dihedralPars, &par->ndihedralPars, sizeof(TorsionPar), par->ndihedralPars, NULL);
987 arena->dihedral_par_i[i] = (tp - par->dihedralPars);
989 nmissing = par->ndihedralPars;
991 /* Copy the dihedral parameters */
992 for (i = 0, idx = par->ndihedralPars; i < mol->ndihedrals; i++) {
993 t1 = arena->dihedral_par_i[i];
994 if (t1 < ATOMS_MAX_NUMBER)
996 arena->dihedral_par_i[i] = idx;
997 for (j = i + 1; j < mol->ndihedrals; j++) {
998 if (arena->dihedral_par_i[j] == t1)
999 arena->dihedral_par_i[j] = idx;
1001 if (t1 >= ATOMS_MAX_NUMBER * 2)
1002 tp = mol->par->dihedralPars + (t1 - ATOMS_MAX_NUMBER * 2);
1003 else tp = gBuiltinParameters->dihedralPars + (t1 - ATOMS_MAX_NUMBER);
1004 AssignArray(&par->dihedralPars, &par->ndihedralPars, sizeof(TorsionPar), idx, tp);
1009 if (arena->debug_result != NULL && arena->debug_output_level > 0) {
1011 char s1[8], s2[8], s3[8], s4[8];
1012 fprintf(arena->debug_result, "\n Dihedral parameters\n");
1013 fprintf(arena->debug_result, " No. atom1 atom2 atom3 atom4 type1 type2 type3 type4 mult phi0 k per\n");
1014 for (i = 0; i < mol->ndihedrals; i++) {
1015 idx = arena->dihedral_par_i[i];
1016 fprintf(arena->debug_result, "%5d %5d %5d %5d %5d ", i+1, mol->dihedrals[i*4]+1, mol->dihedrals[i*4+1]+1, mol->dihedrals[i*4+2]+1, mol->dihedrals[i*4+3]+1);
1018 fprintf(arena->debug_result, "<< missing >>\n");
1021 fprintf(arena->debug_result, "%-4s %-4s %-4s %-4s %2d ", AtomTypeDecodeToString(par->dihedralPars[idx].type1, s1), AtomTypeDecodeToString(par->dihedralPars[idx].type2, s2), AtomTypeDecodeToString(par->dihedralPars[idx].type3, s3), AtomTypeDecodeToString(par->dihedralPars[idx].type4, s4), par->dihedralPars[idx].mult);
1022 for (j = 0; j < par->dihedralPars[idx].mult; j++) {
1023 fprintf(arena->debug_result, "%7.3f %7.3f %1d ", par->dihedralPars[idx].phi0[j]*180/PI, par->dihedralPars[idx].k[j]*INTERNAL2KCAL, par->dihedralPars[idx].period[j]);
1025 fprintf(arena->debug_result, "\n");
1028 arena->nmissing += nmissing;
1032 /* Find improper parameters */
1034 s_find_improper_parameters(MDArena *arena)
1036 Int i, j, idx, type1, type2, type3, type4, t1, nmissing = 0;
1037 Molecule *mol = arena->mol;
1038 Parameter *par = arena->par;
1041 if (mol->nimpropers > 0) {
1042 if (arena->improper_par_i != NULL)
1043 free(arena->improper_par_i);
1044 arena->improper_par_i = (Int *)calloc(sizeof(Int), mol->nimpropers);
1045 if (arena->improper_par_i == NULL)
1046 md_panic(arena, ERROR_out_of_memory);
1048 /* Find the improper parameter; priority: (1) atom index specific in mol->par, (2)
1049 atom type specific in mol->par, (3) atom type specific in built-in */
1050 for (i = 0; i < mol->nimpropers; i++) {
1052 i1 = mol->impropers[i * 4];
1053 i2 = mol->impropers[i * 4 + 1];
1054 i3 = mol->impropers[i * 4 + 2];
1055 i4 = mol->impropers[i * 4 + 3];
1056 type1 = ATOM_AT_INDEX(mol->atoms, i1)->type;
1057 type2 = ATOM_AT_INDEX(mol->atoms, i2)->type;
1058 type3 = ATOM_AT_INDEX(mol->atoms, i3)->type;
1059 type4 = ATOM_AT_INDEX(mol->atoms, i4)->type;
1060 if (mol->par != NULL) {
1061 tp = ParameterLookupImproperPar(mol->par, type1, type2, type3, type4, i1, i2, i3, i4, 0);
1063 arena->improper_par_i[i] = (tp - mol->par->improperPars) + ATOMS_MAX_NUMBER * 2;
1067 tp = ParameterLookupImproperPar(gBuiltinParameters, type1, type2, type3, type4, -1, -1, -1, -1, 0);
1069 arena->improper_par_i[i] = (tp - gBuiltinParameters->improperPars) + ATOMS_MAX_NUMBER;
1072 /* Record as missing */
1073 tp = ParameterLookupImproperPar(par, type1, type2, type3, type4, -1, -1, -1, -1, kParameterLookupMissing | kParameterLookupNoBaseAtomType);
1075 tp = AssignArray(&par->improperPars, &par->nimproperPars, sizeof(TorsionPar), par->nimproperPars, NULL);
1082 arena->improper_par_i[i] = (tp - par->improperPars);
1084 nmissing = par->nimproperPars;
1086 /* Copy the improper parameters */
1087 for (i = 0, idx = par->nimproperPars; i < mol->nimpropers; i++) {
1088 t1 = arena->improper_par_i[i];
1089 if (t1 < ATOMS_MAX_NUMBER)
1091 arena->improper_par_i[i] = idx;
1092 for (j = i + 1; j < mol->nimpropers; j++) {
1093 if (arena->improper_par_i[j] == t1)
1094 arena->improper_par_i[j] = idx;
1096 if (t1 >= ATOMS_MAX_NUMBER * 2)
1097 tp = mol->par->improperPars + (t1 - ATOMS_MAX_NUMBER * 2);
1098 else tp = gBuiltinParameters->improperPars + (t1 - ATOMS_MAX_NUMBER);
1099 AssignArray(&par->improperPars, &par->nimproperPars, sizeof(TorsionPar), idx, tp);
1104 if (arena->debug_result != NULL && arena->debug_output_level > 0) {
1106 char s1[8], s2[8], s3[8], s4[8];
1107 fprintf(arena->debug_result, "\n Improper parameters\n");
1108 fprintf(arena->debug_result, " No. atom1 atom2 atom3 atom4 type1 type2 type3 type4 mult phi0 k per\n");
1109 for (i = 0; i < mol->nimpropers; i++) {
1110 idx = arena->improper_par_i[i];
1111 fprintf(arena->debug_result, "%5d %5d %5d %5d %5d ", i+1, mol->impropers[i*4]+1, mol->impropers[i*4+1]+1, mol->impropers[i*4+2]+1, mol->impropers[i*4+3]+1);
1113 fprintf(arena->debug_result, "<< missing >>\n");
1116 fprintf(arena->debug_result, "%-4s %-4s %-4s %-4s %2d ", AtomTypeDecodeToString(par->improperPars[idx].type1, s1), AtomTypeDecodeToString(par->improperPars[idx].type2, s2), AtomTypeDecodeToString(par->improperPars[idx].type3, s3), AtomTypeDecodeToString(par->improperPars[idx].type4, s4), par->improperPars[idx].mult);
1117 for (j = 0; j < par->improperPars[idx].mult; j++) {
1118 fprintf(arena->debug_result, "%7.3f %7.3f %1d", par->improperPars[idx].phi0[j]*180/PI, par->improperPars[idx].k[j]*INTERNAL2KCAL, par->improperPars[idx].period[j]);
1120 fprintf(arena->debug_result, "\n");
1123 arena->nmissing += nmissing;
1127 /* Find one fragment, starting from start_index */
1129 s_find_fragment_sub(MDArena *arena, Int start_index, Int fragment_index)
1131 Atom *atoms = arena->mol->atoms;
1133 for (i = 0; i < atoms[start_index].nconnects; i++) {
1134 AtomConnectEntryAtIndex(ATOM_AT_INDEX(atoms, start_index), i);
1135 if (j >= 0 && j < arena->natoms_uniq) {
1136 int n = arena->fragment_indices[j];
1138 arena->fragment_indices[j] = fragment_index;
1139 s_find_fragment_sub(arena, j, fragment_index);
1140 } else if (n != fragment_index) {
1141 if (arena->log_result != NULL)
1142 fprintf(arena->log_result, "Warning: internal inconsistency in finding fragment at atom %d\n", j + 1);
1148 /* Find fragments */
1150 md_find_fragments(MDArena *arena)
1153 if (arena->fragment_indices != NULL)
1154 free(arena->fragment_indices);
1155 arena->fragment_indices = (Int *)malloc(sizeof(Int) * arena->natoms_uniq);
1156 if (arena->fragment_indices == NULL)
1157 md_panic(arena, "Low memory in md_find_fragments");
1158 nuniq = arena->natoms_uniq;
1159 for (i = 0; i < nuniq; i++)
1160 arena->fragment_indices[i] = -1;
1162 for (i = 0; i < nuniq; i++) {
1163 if (arena->fragment_indices[i] >= 0)
1165 s_find_fragment_sub(arena, i, idx);
1168 arena->nfragments = idx;
1169 if (arena->fragment_info != NULL)
1170 free(arena->fragment_info);
1171 arena->fragment_info = (struct MDFragmentInfo *)calloc(sizeof(struct MDFragmentInfo), idx);
1172 if (arena->fragment_info == NULL)
1173 md_panic(arena, "Low memory in md_find_fragments");
1176 /* Calculate center-of-mass */
1178 md_center_of_mass(MDArena *arena, Vector *cp)
1185 n = arena->mol->natoms;
1186 for (i = 0, ap = arena->mol->atoms; i < n; i++, ap++) {
1187 VecScaleInc(*cp, ap->r, ap->weight);
1190 VecScaleSelf(*cp, 1.0 / sumw);
1193 /* Relocate center-of-mass */
1195 md_relocate_center(MDArena *arena)
1200 n = arena->mol->natoms;
1201 md_center_of_mass(arena, &cm);
1202 VecDec(cm, arena->initial_center);
1203 for (i = 0, ap = arena->mol->atoms; i < n; i++, ap++) {
1209 /* Quench translational and rotational momenta */
1211 md_quench_momenta(MDArena *arena)
1215 Vector am, cm, m, v, v1, v2;
1216 Double w, sumw, kinetic;
1219 if (!arena->quench_angular_momentum && !arena->quench_translational_momentum)
1222 n = arena->mol->natoms;
1224 /* Center of mass */
1225 md_center_of_mass(arena, &cm);
1227 /* Initial kinetic energy (times 2) */
1229 for (i = 0, ap = arena->mol->atoms; i < n; i++, ap++) {
1230 kinetic += ap->weight * VecLength2(ap->v);
1233 /* Quench the angular momentum */
1234 /* Calculate the total angular momentum */
1236 if (arena->quench_angular_momentum) {
1238 for (i = 0, ap = arena->mol->atoms; i < n; i++, ap++) {
1239 VecSub(v, ap->r, cm);
1240 VecCross(v1, v, ap->v);
1241 VecScaleInc(am, v1, ap->weight);
1243 /* Moment of inertia */
1244 memset(mi, 0, sizeof(mi));
1245 for (i = 0, ap = arena->mol->atoms; i < n; i++, ap++) {
1246 Double x = ap->r.x - cm.x;
1247 Double y = ap->r.y - cm.y;
1248 Double z = ap->r.z - cm.z;
1250 mi[0] += w * (y * y + z * z);
1251 mi[4] += w * (z * z + x * x);
1252 mi[8] += w * (x * x + y * y);
1260 /* Calculate the angular velocity as a rigid body */
1261 /* I * w = L; I, moment of inertia; w, angular velocity; L, angular momentum */
1262 MatrixInvert(mi, mi);
1263 MatrixVec(&v, mi, &am);
1264 /* Subtract the velocity at the atom position derived from the angular velocity */
1265 for (i = 0, ap = arena->mol->atoms; i < n; i++, ap++) {
1266 VecSub(v1, ap->r, cm);
1267 VecCross(v2, v, v1);
1272 /* Quench the translational momentum */
1273 if (arena->quench_translational_momentum) {
1276 for (i = 0, ap = arena->mol->atoms; i < n; i++, ap++) {
1277 VecScaleInc(m, ap->v, ap->weight);
1280 VecScaleSelf(m, 1.0 / sumw);
1281 for (i = 0, ap = arena->mol->atoms; i < n; i++, ap++)
1285 /* Current kinetic energy (times 2) */
1287 for (i = 0, ap = arena->mol->atoms; i < n; i++, ap++) {
1288 w += ap->weight * VecLength2(ap->v);
1290 w = sqrt(kinetic / w);
1292 /* Scale the velocities to keep the kinetic energy */
1293 for (i = 0, ap = arena->mol->atoms; i < n; i++, ap++) {
1294 VecScaleSelf(ap->v, w);
1299 /* Initilize the runtime fields that are affected by the atom positions */
1300 /* (Should be called after coordinates are updated without changing structure info) */
1302 md_init_for_positions(MDArena *arena)
1308 if (arena == NULL || (mol = arena->mol) == NULL || (par = arena->par) == NULL)
1311 /* Initialize fix positions */
1312 for (i = j = 0; i < mol->natoms; i++) {
1313 Atom *ap = &(mol->atoms[i]);
1314 if (ap->fix_force != 0.0) {
1315 ap->fix_pos = ap->r;
1320 md_log(arena, "Number of fixed atoms = %d\n", j);
1321 /* if (arena->fix_atoms != NULL) {
1322 for (i = 0; i < arena->nfix_atoms; i++) {
1323 j = arena->fix_atoms[i].index;
1324 if (j >= 0 && j < mol->natoms)
1325 arena->fix_atoms[i].pos = mol->atoms[j].r;
1327 printf("Number of fixed atoms = %d\n", arena->nfix_atoms);
1330 /* Abnormal bonds */
1331 if (arena->anbond_thres > 0.0) {
1334 for (i = 0; i < mol->nbonds; i++) {
1335 idx = arena->bond_par_i[i];
1338 VecSub(r12, mol->atoms[mol->bonds[i*2]].r, mol->atoms[mol->bonds[i*2+1]].r);
1340 if (r >= (1 + arena->anbond_thres) * par->bondPars[idx].r0)
1341 arena->anbond_r0[i] = r - par->bondPars[idx].r0;
1343 arena->anbond_r0[i] = 0.0;
1347 /* Center of mass */
1348 md_center_of_mass(arena, &(arena->initial_center));
1351 /* Set the alchemical flags */
1352 /* Independent with arena->xmol, mol */
1354 md_set_alchemical_flags(MDArena *arena, int nflags, const char *flags)
1359 if (nflags == 0 || flags == NULL) {
1360 if (arena->alchem_flags != NULL)
1361 free(arena->alchem_flags);
1362 arena->alchem_flags = NULL;
1363 arena->nalchem_flags = 0;
1367 if (arena->alchem_flags == NULL)
1368 arena->alchem_flags = (char *)malloc(nflags);
1369 else arena->alchem_flags = (char *)realloc(arena->alchem_flags, nflags);
1370 if (arena->alchem_flags == NULL) {
1371 arena->nalchem_flags = 0;
1374 memmove(arena->alchem_flags, flags, nflags);
1375 arena->nalchem_flags = nflags;
1379 /* Set the external forces */
1380 /* Independent with arena->xmol, mol */
1382 md_set_external_forces(MDArena *arena, int nexforces, const Vector *exforces)
1387 if (nexforces == 0 || exforces == NULL) {
1388 if (arena->exforces != NULL)
1389 free(arena->exforces);
1390 arena->exforces = NULL;
1391 arena->nexforces = 0;
1395 if (arena->exforces == NULL)
1396 arena->exforces = (Vector *)malloc(nexforces * sizeof(Vector));
1397 else arena->exforces = (Vector *)realloc(arena->exforces, nexforces * sizeof(Vector));
1398 if (arena->exforces == NULL) {
1399 arena->nexforces = 0;
1402 memmove(arena->exforces, exforces, nexforces * sizeof(Vector));
1403 arena->nexforces = nexforces;
1408 md_prepare(MDArena *arena, int check_only)
1414 if (arena->xmol->needsMDRebuild) {
1415 /* Set molecule again */
1416 md_arena_set_molecule(arena, arena->xmol);
1417 arena->xmol->needsMDRebuild = 0;
1419 md_copy_coordinates_to_internal(arena);
1423 arena->errmsg[0] = 0;
1424 arena->setjmp_buf = NULL;
1426 /* Table of missing parameters */
1427 /* Int *missing = NULL; */
1428 /* Int nmissing = 0; */
1431 return "molecule is not defined";
1432 if (mol->natoms == 0 || mol->atoms == NULL)
1433 return "molecule has no atoms";
1438 const char *err = NULL;
1440 if (arena->xmol->path != NULL || mol->path != NULL) {
1441 /* Temporarily change to the document directory */
1443 char *fname = (char *)arena->xmol->path;
1445 fname = (char *)mol->path;
1446 fname = strdup(fname);
1447 if ((p = strrchr(fname, '/')) != NULL
1448 || (p = strrchr(fname, '\\')) != NULL
1451 cwd = getcwd(NULL, 0);
1456 if (arena->log_result_name != NULL && arena->log_result == NULL) {
1457 arena->log_result = fopen(arena->log_result_name, "wb");
1458 if (arena->log_result == NULL)
1459 err = "cannot create log file";
1461 if (err == NULL && arena->coord_result_name != NULL && arena->coord_result == NULL) {
1463 arena->coord_result = fopen(arena->coord_result_name, "wb");
1464 if (arena->coord_result == NULL)
1465 err = "cannot create coord file";
1467 int natoms = (arena->output_expanded_atoms ? arena->mol->natoms : arena->natoms_uniq);
1468 MoleculeCallback_displayName(mol, molname, sizeof molname);
1469 fprintf(arena->coord_result, "TITLE: %s, %d atoms\n", molname, natoms);
1470 fflush(arena->coord_result);
1473 if (err == NULL && arena->vel_result_name != NULL && arena->vel_result == NULL) {
1474 arena->vel_result = fopen(arena->vel_result_name, "wb");
1475 if (arena->vel_result == NULL)
1476 err = "cannot create vel file";
1478 if (err == NULL && arena->force_result_name != NULL && arena->force_result == NULL) {
1479 arena->force_result = fopen(arena->force_result_name, "wb");
1480 if (arena->force_result == NULL)
1481 err = "cannot create force file";
1483 if (err == NULL && arena->extend_result_name != NULL && arena->extend_result == NULL) {
1484 arena->extend_result = fopen(arena->extend_result_name, "wb");
1485 if (arena->extend_result == NULL)
1486 err = "cannot create extend file";
1488 if (err == NULL && arena->debug_result_name != NULL && arena->debug_result == NULL) {
1489 arena->debug_result = fopen(arena->debug_result_name, "wb");
1490 if (arena->debug_result == NULL)
1491 err = "cannot create debug file";
1501 /* Count symmetry unique atoms */
1502 /* Atoms should be ordered so that all symmetry related atoms come after symmetry unique atoms */
1503 for (i = t1 = 0, t2 = -1; i < mol->natoms; i++) {
1504 Atom *ap = mol->atoms + i;
1505 Symop symop = ap->symop;
1506 if (SYMOP_ALIVE(symop)) {
1508 t2 = i; /* The index of the first non-unique atom */
1510 t1++; /* The number of unique atoms */
1513 if (t2 >= 0 && t1 != t2)
1514 return "all symmetry related atoms should be after symmetry unique atoms";
1515 /* if (t1 > mol->natoms && mol->box == NULL)
1516 return "symmetry operation is used but no periodic box is defined"; */
1520 arena->natoms_uniq = t1;
1522 if (arena->debug_result != NULL) {
1525 fprintf(arena->debug_result, "---- LWMD Started at %s", ctime(&loc_time));
1528 /* Recalc angle/dihedral/improper tables from the bond table and parameters */
1529 /* s_rebuild_angles(arena);
1530 s_rebuild_dihedrals(arena);
1531 s_rebuild_impropers(arena); */
1533 /* Statistics of the molecule */
1535 "Number of bonds = %d\n"
1536 "Number of angles = %d\n"
1537 "Number of dihedrals = %d\n"
1538 "Number of impropers = %d\n", mol->nbonds, mol->nangles, mol->ndihedrals, mol->nimpropers);
1541 for (i = 0; i < mol->natoms; i++) {
1542 if (mol->atoms[i].fix_force > 0)
1544 if (mol->atoms[i].fix_force < 0)
1546 if (mol->atoms[i].mm_exclude)
1550 md_log(arena, "Number of constrained atoms = %d\n", t1);
1552 md_log(arena, "Number of fixed atoms = %d\n", t2);
1554 md_log(arena, "Number of excluded atoms = %d\n", t3);
1556 if (arena->natoms_uniq < mol->natoms) {
1557 md_log(arena, "Number of symmetry-unique atoms = %d\n", arena->natoms_uniq);
1559 for (i = 0; i < arena->natoms_uniq; i++) {
1560 if (mol->atoms[i].fix_force < 0)
1565 arena->degree_of_freedom = 3 * (arena->natoms_uniq - t2 - t3);
1566 md_log(arena, "Degree of freedom = %d\n", arena->degree_of_freedom);
1568 /* Build local cache of the used parameters */
1569 if (arena->par != NULL)
1570 ParameterRelease(arena->par);
1571 arena->par = ParameterNew();
1572 arena->nmissing = arena->nsuspicious = 0;
1573 s_find_vdw_parameters(arena);
1574 s_find_bond_parameters(arena);
1575 s_find_angle_parameters(arena);
1576 s_find_dihedral_parameters(arena);
1577 s_find_improper_parameters(arena);
1579 if (arena->nmissing > 0) {
1580 /* for (i = 0; i < nmissing; i++) {
1581 char s1[6], s2[6], s3[6], s4[6];
1582 type1 = missing[i * 5];
1583 AtomTypeDecodeToString(missing[i * 5 + 1], s1);
1584 AtomTypeDecodeToString(missing[i * 5 + 2], s2);
1585 AtomTypeDecodeToString(missing[i * 5 + 3], s3);
1586 AtomTypeDecodeToString(missing[i * 5 + 4], s4);
1588 md_warning(arena, "Missing vdw parameter for %s\n", s1, s2);
1589 else if (type1 == 1)
1590 md_warning(arena, "Missing bond parameter for %s-%s\n", s1, s2);
1591 else if (type1 == 2)
1592 md_warning(arena, "Missing angle parameter for %s-%s-%s\n", s1, s2, s3);
1593 else if (type1 == 3)
1594 md_warning(arena, "Missing dihedral parameter for %s-%s-%s-%s\n", s1, s2, s3, s4);
1595 else if (type1 == 4)
1596 md_warning(arena, "Missing improper parameter for %s-%s-%s-%s\n", s1, s2, s3, s4);
1599 return "some parameters are missing";
1602 /* Build the exclusion table */
1603 s_make_exclusion_list(arena);
1604 if (arena->debug_result != NULL && arena->debug_output_level > 0) {
1605 fprintf(arena->debug_result, "\n MDExclusion table for each atom\n");
1606 fprintf(arena->debug_result, " No. {self and special} {1-2} {1-3} {1-4}\n");
1607 for (i = 0; i < mol->natoms; i++) {
1608 fprintf(arena->debug_result, "%5d ", i+1);
1609 for (idx = arena->exinfo[i].index0; idx <= arena->exinfo[i+1].index0; idx++) {
1611 if (idx == arena->exinfo[i].index0)
1612 n += fprintf(arena->debug_result, "{");
1613 if (idx == arena->exinfo[i].index1)
1614 n += fprintf(arena->debug_result, "} {");
1615 if (idx == arena->exinfo[i].index2)
1616 n += fprintf(arena->debug_result, "} {");
1617 if (idx == arena->exinfo[i].index3)
1618 n += fprintf(arena->debug_result, "} {");
1619 if (idx < arena->exinfo[i+1].index0) {
1621 fprintf(arena->debug_result, " ");
1622 fprintf(arena->debug_result, "%d", arena->exlist[idx]+1);
1625 fprintf(arena->debug_result, "}\n");
1629 /* Parameter checking only */
1631 arena->is_initialized = 1; /* Only static fields are ready */
1632 arena->mol->needsMDRebuild = 0;
1636 /* Allocate storage for Verlet list */
1637 arena->max_nverlets = mol->natoms;
1638 if (arena->verlets != NULL)
1639 free(arena->verlets);
1640 arena->verlets = (MDVerlet *)calloc(sizeof(MDVerlet), arena->max_nverlets);
1641 arena->nverlets = 0;
1642 if (arena->verlets_dr != NULL)
1643 free(arena->verlets_dr);
1644 arena->verlets_dr = (Vector *)calloc(sizeof(Vector), mol->natoms);
1645 if (arena->verlets == NULL || arena->verlets_dr == NULL)
1646 md_panic(arena, ERROR_out_of_memory);
1647 arena->last_verlet_step = -1;
1648 if (arena->verlet_i != NULL)
1649 free(arena->verlet_i);
1650 arena->verlet_i = (Int *)calloc(sizeof(Int), mol->natoms + 1);
1652 /* Allocate storage for partial energy/force */
1653 if (arena->energies != NULL)
1654 free(arena->energies);
1655 arena->energies = (Double *)calloc(sizeof(Double), kEndIndex);
1656 if (arena->forces != NULL)
1657 free(arena->forces);
1658 arena->forces = (Vector *)calloc(sizeof(Vector), kKineticIndex * mol->natoms);
1659 if (arena->energies == NULL || arena->forces == NULL)
1660 md_panic(arena, ERROR_out_of_memory);
1662 /* Initialize storage for pair interaction calculations */
1663 /* (The storage will be allocated when necessary) */
1664 /* if (arena->group_flags != NULL) {
1665 free(arena->group_flags);
1666 arena->group_flags = NULL;
1668 if (arena->pair_forces != NULL) {
1669 free(arena->pair_forces);
1670 arena->pair_forces = NULL;
1673 /* Allocate ring buffer */
1674 if (arena->ring != NULL) {
1675 free(arena->ring->buf);
1678 arena->ring = (MDRing *)calloc(sizeof(MDRing), 1);
1679 if (arena->ring == NULL)
1680 md_panic(arena, ERROR_out_of_memory);
1681 arena->ring->size = mol->natoms;
1682 if (arena->pressure != NULL && arena->pressure->disabled == 0)
1683 arena->ring->size = mol->natoms + 4;
1685 if (arena->minimize_cell && arena->mol->cell != NULL)
1686 arena->ring->size = mol->natoms + 4;
1688 arena->ring->nframes = 2000 / arena->ring->size;
1689 if (arena->ring->nframes < 2)
1690 arena->ring->nframes = 2;
1691 arena->ring->buf = (Vector *)calloc(sizeof(Vector), arena->ring->size * arena->ring->nframes);
1692 if (arena->ring->buf == NULL)
1693 md_panic(arena, ERROR_out_of_memory);
1694 arena->ring->next = 0;
1695 arena->ring->count = 0;
1697 /* Initialize temperature statistics */
1698 arena->sum_temperature = 0.0;
1699 arena->nsum_temperature = 0;
1701 /* Initialize unique bond/angle/dihedral/improper table */
1702 /* s_find_symmetry_unique(arena); */
1704 /* Initialize the position-dependent fields */
1705 md_init_for_positions(arena);
1707 /* Clear the snapshot storage */
1708 /* if (arena->snapshots != NULL) {
1709 for (i = 0; i < arena->nsnapshots; i++) {
1710 if (arena->snapshots[i] != NULL)
1711 free(arena->snapshots[i]);
1713 free(arena->snapshots);
1714 arena->snapshots = NULL;
1716 arena->nsnapshots = 0;
1719 /* Random number seed */
1721 unsigned int seed = arena->random_seed;
1723 seed = (unsigned int)time(NULL);
1725 md_log(arena, "Random number seed = %u\n", seed);
1728 /* Clear the surface area record (will be reallocated within calc_surface_force() if necessary) */
1729 if (arena->sp_arena != NULL) {
1730 clear_sp_arena(arena);
1732 /* if (arena->sp2_arena != NULL) {
1733 clear_sp2_arena(arena);
1737 /* Graphite potential */
1738 if (arena->use_graphite) {
1739 if (arena->graphite == NULL)
1740 arena->graphite = graphite_new();
1741 graphite_set_needs_update(arena->graphite, 1);
1744 if (arena->velocities_read == 0)
1745 md_init_velocities(arena);
1747 /* Fragment analysis */
1748 md_find_fragments(arena);
1749 md_log(arena, "%d fragments found\n", arena->nfragments);
1751 /* Pressure control statistics */
1752 if (arena->pressure != NULL) {
1753 if (mol->cell == NULL)
1754 return "pressure control is requested but no unit cell is defined";
1755 pressure_prepare(arena);
1758 arena->is_initialized = 2; /* Runtime fields are ready */
1759 arena->mol->needsMDRebuild = 0;
1760 arena->request_abort = 0;
1767 #define srandom srand
1768 #define kRandMax ((double)RAND_MAX)
1770 #define kRandMax 2147483648.0
1773 /* A uniform random number in [0,1] */
1777 return (double)random() / kRandMax;
1780 /* A random number with gaussian distribution */
1782 md_gaussian_rand(void)
1784 static int waiting = 0;
1785 static Double next_value = 0;
1786 Double f, r, v1, v2;
1792 while (r >= 1.0 || r < 1.523e-8) {
1793 v1 = 2.0 * md_rand() - 1.0;
1794 v2 = 2.0 * md_rand() - 1.0;
1795 r = v1 * v1 + v2 * v2;
1797 f = sqrt(-2.0 * log(r) / r);
1799 next_value = v1 * f;
1803 /* Seed the random number */
1805 md_srand(unsigned int seed)
1810 /* Scale velocities to match the given temperature */
1812 md_scale_velocities(MDArena *arena)
1816 Double ttemp, scale;
1817 if (arena->nsum_temperature == 0) {
1818 Double kinetic = 0.0;
1819 for (i = 0, ap = arena->mol->atoms; i < arena->natoms_uniq; i++, ap++) {
1820 if (ap->fix_force < 0 || ap->mm_exclude)
1822 kinetic += ap->weight * VecLength2(ap->v);
1825 ttemp = 2.0 * kinetic / (arena->degree_of_freedom * BOLTZMANN);
1827 ttemp = arena->sum_temperature / arena->nsum_temperature;
1829 scale = sqrt(arena->temperature / ttemp);
1830 for (i = 0, ap = arena->mol->atoms; i < arena->mol->natoms; i++, ap++) {
1831 if (ap->fix_force < 0)
1833 VecScaleSelf(ap->v, scale);
1835 arena->sum_temperature = 0;
1836 arena->nsum_temperature = 0;
1839 /* Give random velocities that matches the given temperature */
1841 md_init_velocities(MDArena *arena)
1845 /* Double temp = arena->temperature; */
1846 Atom *ap = arena->mol->atoms;
1847 n = arena->mol->natoms;
1848 for (i = 0; i < n; i++, ap++) {
1849 if (ap->fix_force < 0 || fabs(ap->weight) < 1e-6 || ap->mm_exclude) {
1850 ap->v.x = ap->v.y = ap->v.z = 0;
1852 w = sqrt(arena->temperature * BOLTZMANN / ap->weight);
1853 ap->v.x = w * md_gaussian_rand();
1854 ap->v.y = w * md_gaussian_rand();
1855 ap->v.z = w * md_gaussian_rand();
1856 /* ap->v.x = md_rand() - 0.5;
1857 ap->v.y = md_rand() - 0.5;
1858 ap->v.z = md_rand() - 0.5; */
1861 arena->sum_temperature = 0;
1862 arena->nsum_temperature = 0;
1864 /* Quench the total momentum */
1865 md_quench_momenta(arena);
1867 /* Adjust the temperature */
1868 md_scale_velocities(arena);
1870 arena->velocities_read = 0;
1874 md_bootstrap(MDArena *arena)
1876 /* Set the initial velocities and calculate the current force */
1877 md_init_velocities(arena);
1882 s_md_output_extend_info(MDArena *arena, FILE *fp)
1884 Vector *ap, *bp, *cp, *op;
1885 static Vector zero = {0.0, 0.0, 0.0};
1886 if (arena->coord_result_frame % 10 == 0 || ftello(fp) == 0) {
1887 fprintf(fp, "EXLABEL: %7s %7s %11s ", "FRAME", "STEP", "POT_ENERGY");
1888 fprintf(fp, "%7s %7s %7s ", "CELL_AX", "CELL_AY", "CELL_AZ");
1889 fprintf(fp, "%7s %7s %7s ", "CELL_BX", "CELL_BY", "CELL_BZ");
1890 fprintf(fp, "%7s %7s %7s ", "CELL_CX", "CELL_CY", "CELL_CZ");
1891 fprintf(fp, "%7s %7s %7s\n", "CELL_OX", "CELL_OY", "CELL_OZ");
1894 fprintf(fp, "EXINFO: %7d %7d %11.5f ", arena->coord_result_frame, arena->step, arena->total_energy * INTERNAL2KCAL);
1895 if (arena->mol->cell != NULL) {
1896 ap = &(arena->mol->cell->axes[0]);
1897 bp = &(arena->mol->cell->axes[1]);
1898 cp = &(arena->mol->cell->axes[2]);
1899 op = &(arena->mol->cell->origin);
1901 ap = bp = cp = op = &zero;
1903 fprintf(fp, "%7.3f %7.3f %7.3f ", ap->x, ap->y, ap->z);
1904 fprintf(fp, "%7.3f %7.3f %7.3f ", bp->x, bp->y, bp->z);
1905 fprintf(fp, "%7.3f %7.3f %7.3f ", cp->x, cp->y, cp->z);
1906 fprintf(fp, "%7.3f %7.3f %7.3f\n", op->x, op->y, op->z);
1914 md_output_results(MDArena *arena)
1918 Vector *av, *bv, *cv;
1920 natoms = (arena->output_expanded_atoms ? arena->mol->natoms : arena->natoms_uniq);
1923 if (arena->coord_result == NULL && arena->coord_result_name != NULL) {
1924 arena->coord_result = fopen(arena->coord_result_name, "wb");
1925 if (arena->coord_result == NULL) {
1926 snprintf(sErrBuf, sizeof sErrBuf, "Cannot open coordinate result file %s", arena->coord_result_name);
1927 arena->errmsg = sErrBuf;
1930 fprintf(arena->coord_result, "TITLE: coordinates for %d atoms\n", natoms);
1931 arena->coord_result_frame = 0;
1933 if (arena->vel_result == NULL && arena->vel_result_name != NULL) {
1934 arena->vel_result = fopen(arena->vel_result_name, "wb");
1935 if (arena->vel_result == NULL) {
1936 snprintf(sErrBuf, sizeof sErrBuf, "Cannot open velocity result file %s", arena->vel_result_name);
1937 arena->errmsg = sErrBuf;
1940 fprintf(arena->vel_result, "TITLE: velocities for %d atoms\n", natoms);
1942 if (arena->force_result == NULL && arena->force_result_name != NULL) {
1943 arena->force_result = fopen(arena->force_result_name, "wb");
1944 if (arena->force_result == NULL) {
1945 snprintf(sErrBuf, sizeof sErrBuf, "Cannot open force result file %s", arena->force_result_name);
1946 arena->errmsg = sErrBuf;
1949 fprintf(arena->force_result, "TITLE: force for %d atoms\n", natoms);
1951 if (arena->extend_result == NULL && arena->extend_result_name != NULL) {
1952 arena->extend_result = fopen(arena->extend_result_name, "wb");
1953 if (arena->extend_result == NULL) {
1954 snprintf(sErrBuf, sizeof sErrBuf, "Cannot open extend info file %s", arena->extend_result_name);
1955 arena->errmsg = sErrBuf;
1958 fprintf(arena->extend_result, "# Frame step energy ax ay az bx by bz cx cy cz ox oy oz\n");
1962 ap = arena->mol->atoms;
1963 if (arena->wrap_coordinates && arena->mol->cell != NULL) {
1964 av = &(arena->mol->cell->axes[0]);
1965 bv = &(arena->mol->cell->axes[1]);
1966 cv = &(arena->mol->cell->axes[2]);
1968 av = bv = cv = NULL;
1970 if (arena->coord_result != NULL) {
1971 if (arena->wrap_coordinates)
1972 md_wrap_coordinates(arena);
1973 for (i = j = 0; i < natoms; i++, j = (j + 3) % 10) {
1976 VecScaleInc(r, *av, ap[i].wrap_dx);
1977 VecScaleInc(r, *bv, ap[i].wrap_dy);
1978 VecScaleInc(r, *cv, ap[i].wrap_dz);
1980 fprintf(arena->coord_result, "%8.3f%s%8.3f%s%8.3f%s",
1981 r.x, (j == 9 ? "\n" : ""),
1982 r.y, (j == 8 ? "\n" : ""),
1983 r.z, (j == 7 ? "\n" : ""));
1986 fprintf(arena->coord_result, "\n");
1987 if (arena->periodic_a || arena->periodic_b || arena->periodic_c) {
1988 fprintf(arena->coord_result, "%8.3f%8.3f%8.3f\n", arena->mol->cell->cell[0], arena->mol->cell->cell[1], arena->mol->cell->cell[2]);
1990 fflush(arena->coord_result);
1992 if (arena->vel_result != NULL) {
1993 for (i = j = 0; i < natoms; i++, j = (j + 3) % 10) {
1994 fprintf(arena->vel_result, " %7.3f%s %7.3f%s %7.3f%s",
1995 ap[i].v.x*1000, (j == 9 ? "\n" : ""),
1996 ap[i].v.y*1000, (j == 8 ? "\n" : ""),
1997 ap[i].v.z*1000, (j == 7 ? "\n" : ""));
2000 fprintf(arena->vel_result, "\n");
2001 fflush(arena->vel_result);
2003 if (arena->force_result != NULL) {
2004 for (i = j = 0; i < natoms; i++, j = (j + 3) % 10) {
2005 fprintf(arena->force_result, " %7.3f%s %7.3f%s %7.3f%s",
2006 ap[i].f.x, (j == 9 ? "\n" : ""),
2007 ap[i].f.y, (j == 8 ? "\n" : ""),
2008 ap[i].f.z, (j == 7 ? "\n" : ""));
2011 fprintf(arena->force_result, "\n");
2012 fflush(arena->force_result);
2014 if (arena->extend_result != NULL) {
2015 s_md_output_extend_info(arena, arena->extend_result);
2016 } else if (arena->log_result != NULL) {
2017 s_md_output_extend_info(arena, arena->log_result);
2019 arena->coord_result_frame++;
2024 md_output_energies(MDArena *arena)
2027 int periodic = (arena->mol->cell != NULL) && (arena->periodic_a || arena->periodic_b || arena->periodic_c);
2028 /* if (arena->log_result == NULL)
2030 if ((arena->step / arena->energy_output_freq) % 10 == 0) {
2031 md_log(arena, "ELABEL: %11s %11s %11s %11s %11s %11s", "STEP", "TOTAL_POT", "BOND", "ANGLE", "DIHEDRAL", "IMPROPER");
2032 md_log(arena, " %11s %11s %11s %11s %11s %11s %11s %11s", "VDW", "ELECT", "AUX", "SURFACE", "KINETIC", "NET", "TEMP", "TEMP_AVG");
2034 md_log(arena, " %11s", "VOLUME");
2035 if (arena->nalchem_flags > 0)
2036 md_log(arena, " %11s %11s", "LAMBDA", "DEDL");
2037 md_log(arena, "\n");
2039 md_log(arena, "ENERGY: %11d %11.5f", arena->step, arena->total_energy * INTERNAL2KCAL);
2040 for (i = 0; i < kEndIndex; i++)
2041 md_log(arena, " %11.5f", arena->energies[i] * INTERNAL2KCAL);
2042 md_log(arena, " %11.5f", (arena->energies[kKineticIndex] + arena->total_energy) * INTERNAL2KCAL);
2043 md_log(arena, " %11.5f", arena->transient_temperature);
2044 md_log(arena, " %11.5f", (arena->nsum_temperature > 0 ? arena->sum_temperature / arena->nsum_temperature : 0.0));
2046 Vector v, *av, *bv, *cv;
2047 av = &(arena->mol->cell->axes[0]);
2048 bv = &(arena->mol->cell->axes[1]);
2049 cv = &(arena->mol->cell->axes[2]);
2050 VecCross(v, *av, *bv);
2051 md_log(arena, " %11.5f", VecDot(v, *cv));
2053 if (arena->nalchem_flags > 0) {
2054 md_log(arena, " %11.5f %11.5f", arena->alchem_lambda, arena->alchem_energy * INTERNAL2KCAL / arena->alchem_dlambda);
2056 md_log(arena, "\n");
2057 md_log(arena, NULL);
2061 md_update_velocities(MDArena *arena)
2068 /* Vector m1, m2; */
2069 Double halftimestep = arena->timestep * 0.5;
2070 ap = arena->mol->atoms;
2071 natoms = arena->mol->natoms;
2072 use_sym = (arena->mol->nsyms > 0);
2073 Double limit = arena->velocity_limit;
2078 for (i = 0; i < natoms; i++, ap++) {
2079 if (use_sym && ap->symop.alive)
2081 if (ap->fix_force < 0)
2086 if (fabs(wt) < 1e-6)
2088 w = halftimestep / wt;
2089 /* VecScaleInc(m1, ap->v, wt); */
2090 VecScaleInc(ap->v, ap->f, w);
2091 w = VecLength2(ap->v);
2092 if (w > limit || !isfinite(w)) /* Is isfinite() available in other platforms?? */
2093 md_panic(arena, "the velocity for atom %d exceeded limit at step %d", i+1, arena->step);
2094 /* VecScaleInc(m2, ap->v, wt); */
2100 VecScaleSelf(m2, w);
2101 for (i = 0, ap = arena->mol->atoms; i < natoms; i++, ap++) {
2102 if (use_sym && ap->symop.alive)
2104 if (ap->fix_force < 0)
2109 arena->velocities_read = 0;
2112 for (i = 0, ap = arena->mol->atoms; i < natoms; i++, ap++) {
2113 if (use_sym && ap->sym_op > 0)
2116 VecScaleInc(m2, ap->v, wt);
2121 md_update_positions(MDArena *arena)
2125 Double timestep = arena->timestep;
2126 Vector *vdr = arena->verlets_dr;
2129 Double kinetic, kinetic_uniq; */
2131 ap = arena->mol->atoms;
2132 natoms = arena->mol->natoms;
2133 /* limit = arena->velocity_limit;
2135 use_sym = (arena->mol->nsyms > 0);
2136 /* kinetic = kinetic_uniq = 0.0; */
2137 for (i = 0; i < natoms; i++, ap++, vdr++) {
2138 if (use_sym && ap->symop.alive)
2140 if (ap->fix_force < 0)
2144 VecScale(dr, ap->v, timestep);
2149 /* Update the abnormal bond parameters */
2150 if (arena->anbond_thres > 0.0) {
2151 Double *fp = arena->anbond_r0;
2152 for (i = 0; i < arena->mol->nbonds; i++) {
2155 fp[i] -= arena->anbond_anneal_rate;
2161 /* Relocate the center of mass (if necessary) */
2162 if (arena->relocate_center) {
2163 md_relocate_center(arena);
2168 md_calc_kinetic_energy(MDArena *arena)
2171 Double w, kinetic, kinetic_uniq;
2173 n = arena->mol->natoms;
2174 nuniq = arena->natoms_uniq;
2175 kinetic = kinetic_uniq = 0;
2176 for (i = 0, ap = arena->mol->atoms; i < n; i++, ap++) {
2177 if (ap->fix_force < 0)
2179 w = VecLength2(ap->v) * ap->weight;
2184 arena->energies[kKineticIndex] = kinetic * 0.5;
2185 arena->transient_temperature = kinetic_uniq / (arena->degree_of_freedom * BOLTZMANN);
2186 arena->sum_temperature += arena->transient_temperature;
2187 arena->nsum_temperature++;
2188 arena->average_temperature = arena->sum_temperature / arena->nsum_temperature;
2191 /* Andersen thermostat */
2193 md_andersen_thermostat(MDArena *arena)
2195 int n = arena->natoms_uniq;
2199 Double q = arena->andersen_thermo_coupling;
2201 for (i = 0, ap = arena->mol->atoms; i < n; i++, ap++) {
2202 if (ap->fix_force < 0 || fabs(ap->weight) < 1e-6) {
2203 ap->v.x = ap->v.y = ap->v.z = 0;
2204 } else if (md_rand() < q) {
2205 de -= VecLength2(ap->v) * ap->weight;
2206 w = sqrt(arena->temperature * BOLTZMANN / ap->weight);
2207 ap->v.x = w * md_gaussian_rand();
2208 ap->v.y = w * md_gaussian_rand();
2209 ap->v.z = w * md_gaussian_rand();
2210 de += VecLength2(ap->v) * ap->weight;
2214 arena->energies[kKineticIndex] += de;
2218 md_transform_vec_by_symmetry(MDArena *arena, Vector *dst, const Vector *src, Symop rec, int no_translation)
2223 if (rec.sym > 0 && rec.sym <= arena->mol->nsyms) {
2224 memmove(temp, arena->cellsyms[rec.sym], sizeof(temp));
2226 temp[9] = temp[10] = temp[11] = 0.0;
2227 TransformVec(dst, temp, src);
2229 if (!no_translation) {
2230 Vector *vp = arena->mol->cell->axes;
2231 VecScaleInc(*dst, vp[0], rec.dx);
2232 VecScaleInc(*dst, vp[1], rec.dy);
2233 VecScaleInc(*dst, vp[2], rec.dz);
2238 md_wrap_coordinates(MDArena *arena)
2240 /* Calculate the offset for each fragment to wrap into the unit cell (0,0,0)-(1,1,1) */
2244 Molecule *mol = arena->mol;
2247 if (mol == NULL || mol->natoms == 0)
2250 if (arena->nfragments == 0)
2251 md_find_fragments(arena);
2253 /* Calculate the center of mass for each fragment */
2254 for (n = 0; n < arena->nfragments; n++) {
2255 VecZero(arena->fragment_info[n].pos);
2256 arena->fragment_info[n].mass = 0.0;
2258 for (i = 0, ap = mol->atoms; i < arena->natoms_uniq; i++, ap++) {
2259 n = arena->fragment_indices[i];
2260 VecScaleInc(arena->fragment_info[n].pos, ap->r, ap->weight);
2261 arena->fragment_info[n].mass += ap->weight;
2263 for (n = 0; n < arena->nfragments; n++) {
2264 VecScaleSelf(arena->fragment_info[n].pos, 1.0/arena->fragment_info[n].mass);
2267 /* Calculate the offset */
2268 /* A trick: atoms belonging to one fragment are almost always located in a consequent
2269 positions. So we cache the 'last' information to avoid duplicate calculation
2272 last_symop.alive = 0;
2273 for (i = 0, ap = mol->atoms; i < mol->natoms; i++, ap++) {
2274 if (ap->symop.alive)
2275 n = arena->fragment_indices[ap->symbase];
2276 else n = arena->fragment_indices[i];
2277 if (n == last_n && ap->symop.alive == last_symop.alive
2278 && (!last_symop.alive || (ap->symop.dx == last_symop.dx && ap->symop.dy == last_symop.dy && ap->symop.dz == last_symop.dz && ap->symop.sym == last_symop.sym))) {
2279 /* Belongs to the 'last' fragment */
2280 ap->wrap_dx = ap[-1].wrap_dx;
2281 ap->wrap_dy = ap[-1].wrap_dy;
2282 ap->wrap_dz = ap[-1].wrap_dz;
2284 /* Calculate the offset from the position of the center of mass */
2285 Vector r = arena->fragment_info[n].pos;
2286 TransformVec(&r, arena->mol->cell->rtr, &r);
2287 if (ap->symop.alive && ap->symop.sym > 0 && ap->symop.sym <= arena->mol->nsyms) {
2288 /* The translational components of symop are not included */
2289 TransformVec(&r, arena->mol->syms[ap->symop.sym - 1], &r);
2291 ap->wrap_dx = (arena->periodic_a ? -floor(r.x) : 0);
2292 ap->wrap_dy = (arena->periodic_b ? -floor(r.y) : 0);
2293 ap->wrap_dz = (arena->periodic_c ? -floor(r.z) : 0);
2296 last_symop = ap->symop;
2301 md_amend_by_symmetry(MDArena *arena)
2305 if (arena->mol->nsyms == 0)
2307 ap = ap0 = arena->mol->atoms;
2308 natoms = arena->mol->natoms;
2309 for (i = 0; i < natoms; i++, ap++) {
2311 if (!ap->symop.alive)
2314 ap0 = arena->mol->atoms + ap->symbase;
2315 md_transform_vec_by_symmetry(arena, &(ap->r), &(ap0->r), symop, 0);
2316 md_transform_vec_by_symmetry(arena, &(ap->f), &(ap0->f), symop, 1);
2317 md_transform_vec_by_symmetry(arena, &(ap->v), &(ap0->v), symop, 1);
2323 md_snapshot(MDArena *arena, int idx)
2332 spp = (MDSnapshot **)AssignArray(&arena->snapshots, &arena->nsnapshots, sizeof(*spp), idx, NULL);
2335 natoms = arena->mol->natoms;
2336 size = sizeof(**spp) + sizeof(Vector) * (natoms - 1) * 3;
2338 *spp = (MDSnapshot *)malloc(size);
2340 *spp = (MDSnapshot *)realloc(*spp, size);
2343 memset(*spp, 0, size);
2344 (*spp)->step = arena->step;
2345 (*spp)->natoms = natoms;
2347 for (i = 0, ap = arena->mol->atoms; i < natoms; i++, ap++) {
2354 md_panic(arena, "Low memory while saving snapshot");
2358 md_restore(MDArena *arena, int idx)
2360 int i, natoms, natoms1;
2363 /* MDSnapshot **spp; */
2365 if (idx < 0 || idx >= arena->nsnapshots)
2367 vp = arena->snapshots[idx]->rvf;
2368 natoms = arena->mol->natoms;
2369 natoms1 = arena->snapshots[idx]->natoms;
2370 if (natoms != natoms1) {
2371 md_warning(arena, "restore: the number of atoms in snapshot (%d) is different from the current number of atoms (%d)\n", natoms1, natoms);
2373 for (i = 0, ap = arena->mol->atoms; i < natoms && i < natoms1; i++, ap++) {
2378 arena->last_verlet_step = -1; /* The Verlet list needs update */
2382 md_step(MDArena *arena)
2384 md_update_velocities(arena);
2385 md_update_positions(arena);
2386 /* md_rattle_coordinate(arena); */
2387 md_amend_by_symmetry(arena);
2389 /* md_calc_kinetic_energy(arena); */
2390 md_update_velocities(arena);
2391 /* md_rattle_velocity(arena); */
2396 md_minimize_init(MDArena *arena)
2399 static const Vector zerov = {0, 0, 0};
2400 if (arena->old_forces != NULL)
2401 free(arena->old_forces);
2402 arena->old_forces = (Vector *)calloc(sizeof(Vector), arena->mol->natoms * 2);
2403 if (arena->old_forces == NULL)
2404 md_panic(arena, ERROR_out_of_memory);
2405 arena->old_pos = arena->old_forces + arena->mol->natoms;
2406 arena->f_len2 = arena->old_f_len2 = arena->max_gradient = 0.0;
2407 for (i = 0; i < arena->mol->natoms; i++) {
2408 arena->mol->atoms[i].v = arena->mol->atoms[i].f = zerov;
2410 arena->conv_flag = 0;
2412 memset(arena->cell_forces, 0, sizeof(Double) * 12);
2413 memset(arena->cell_vels, 0, sizeof(Double) * 12);
2414 memset(arena->old_cell_forces, 0, sizeof(Double) * 12);
2415 memset(arena->old_cell_pars, 0, sizeof(Double) * 12);
2416 arena->cf_len2 = arena->old_cf_len2 = arena->cv_len2 = arena->cell_max_gradient = 0.0;
2421 md_minimize_atoms_step(MDArena *arena)
2423 Double bk, w1, w2, w3, dump;
2424 Double low, mid, high, low_energy, mid_energy, high_energy, lambda;
2425 Double low_limit, high_limit;
2426 Int i, j, retval, natoms_movable;
2427 Atom *atoms = arena->mol->atoms;
2429 Int natoms = arena->mol->natoms;
2430 Vector r, *vp, *vdr;
2431 const Double phi = 0.618033988749895; /* The golden ratio */
2433 md_amend_by_symmetry(arena);
2438 for (i = 0, ap = atoms, vp = arena->old_forces; i < natoms; i++, ap++, vp++) {
2439 if (ap->fix_force < 0)
2441 w1 += VecLength2(ap->f);
2442 w2 += VecDot(ap->f, *vp);
2447 if (arena->old_f_len2 == 0.0) {
2451 bk = (w1 - w2) / arena->old_f_len2;
2453 bk = 0.0; /* New direction */
2455 /* Update the search direction */
2456 arena->old_f_len2 = arena->f_len2;
2459 for (i = 0, ap = atoms; i < natoms; i++, ap++) {
2460 if (ap->fix_force < 0)
2462 w1 = VecLength2(ap->f) * dump;
2463 if (!isfinite(w1)) /* Is isfinite() available in other platforms?? */
2464 md_panic(arena, "the gradient at atom %d exceeded limit at step %d", i+1, arena->step);
2469 for (i = 0, ap = atoms, vp = arena->old_forces; i < natoms; i++, ap++, vp++) {
2470 if (ap->fix_force < 0)
2473 *(vp + natoms) = ap->r;
2474 ap->v.x = ap->v.x * bk + ap->f.x * dump;
2475 ap->v.y = ap->v.y * bk + ap->f.y * dump;
2476 ap->v.z = ap->v.z * bk + ap->f.z * dump;
2477 w1 = VecLength2(ap->v);
2479 /* if (w1 > 1e4 || !isfinite(w1))
2480 md_panic(arena, "the gradient at atom %d exceeded limit at step %d", i+1, arena->step); */
2485 arena->max_gradient = w3;
2487 /* printf("f_len2 = %g, v_len2 = %g, bk = %g, max_grad = %g\n", arena->f_len2, arena->v_len2, bk, w3); */
2488 if (bk == 0.0 && w3 < arena->gradient_convergence)
2489 return 1; /* Gradient is sufficiently small */
2491 /* Proceed along ap->v until the energy increases */
2492 low_limit = arena->coordinate_convergence / arena->max_gradient;
2493 high_limit = 0.1 / arena->max_gradient;
2495 low_energy = arena->total_energy;
2496 /* lambda = 1e-3 * arena->f_len2 / w2; */
2497 lambda = high_limit;
2500 for (j = 0, ap = atoms, vp = arena->old_pos, vdr = arena->verlets_dr; j < natoms; j++, ap++, vp++, vdr++) {
2501 if (ap->fix_force < 0)
2504 ap->r.x = vp->x + ap->v.x * lambda;
2505 ap->r.y = vp->y + ap->v.y * lambda;
2506 ap->r.z = vp->z + ap->v.z * lambda;
2512 mid_energy = arena->total_energy;
2513 if (mid_energy < low_energy) {
2514 /* mid is the 'sufficiently large' step to give lower total energy */
2516 /* Higher limit: move by this amount */
2523 high_energy = mid_energy;
2525 if (lambda < low_limit) {
2526 /* Cannot find point with lower energy than the starting point */
2527 /* Restore the original position */
2528 for (j = 0, ap = atoms, vp = arena->old_pos, vdr = arena->verlets_dr; j < natoms; j++, ap++, vp++, vdr++) {
2529 if (ap->fix_force < 0)
2539 retval = 2; /* Atom movement is sufficiently small */
2543 /* printf("Line minimization [%g, %g, %g] (energy [%g, %g, %g]) ", low, mid, high, low_energy, mid_energy, high_energy); */
2544 /* low_energy >= mid_energy < high_energy */
2545 /* Binary search for minimum */
2546 for (i = 0; i < 5; i++) {
2547 if (high - mid > mid - low) {
2548 lambda = high - (high - mid) * phi;
2549 for (j = 0, ap = atoms, vp = arena->old_pos, vdr = arena->verlets_dr; j < natoms; j++, ap++, vp++, vdr++) {
2550 if (ap->fix_force < 0)
2553 ap->r.x = vp->x + ap->v.x * lambda;
2554 ap->r.y = vp->y + ap->v.y * lambda;
2555 ap->r.z = vp->z + ap->v.z * lambda;
2560 if (arena->total_energy < mid_energy) {
2562 low_energy = mid_energy;
2564 mid_energy = arena->total_energy;
2567 high_energy = arena->total_energy;
2570 lambda = mid - (mid - low) * phi;
2571 for (j = 0, ap = atoms, vp = arena->old_pos, vdr = arena->verlets_dr; j < natoms; j++, ap++, vp++, vdr++) {
2572 if (ap->fix_force < 0)
2575 ap->r.x = vp->x + ap->v.x * lambda;
2576 ap->r.y = vp->y + ap->v.y * lambda;
2577 ap->r.z = vp->z + ap->v.z * lambda;
2582 if (arena->total_energy < mid_energy) {
2584 high_energy = mid_energy;
2586 mid_energy = arena->total_energy;
2589 low_energy = arena->total_energy;
2592 if ((high - low) * arena->max_gradient < arena->coordinate_convergence) {
2593 /* retval = 2; *//* Atom movement is sufficiently small */
2598 /* printf("Final lambda = %g (%g)\n", lambda, arena->total_energy); */
2605 s_md_modify_atoms_and_cell_parameters(MDArena *arena, Double lambda, Double cell_lambda)
2609 Vector r, *vp, *vdr;
2610 XtalCell *cell = arena->mol->cell;
2611 natoms = arena->mol->natoms;
2612 for (j = 0, ap = arena->mol->atoms, vp = arena->old_pos, vdr = arena->verlets_dr; j < natoms; j++, ap++, vp++, vdr++) {
2613 if (ap->fix_force < 0)
2616 ap->r.x = vp->x + ap->v.x * lambda;
2617 ap->r.y = vp->y + ap->v.y * lambda;
2618 ap->r.z = vp->z + ap->v.z * lambda;
2622 if (cell_lambda >= 0.0) {
2623 if (arena->periodic_a) {
2624 cell->axes[0].x = arena->old_cell_pars[0] + arena->cell_vels[0] * cell_lambda;
2625 cell->axes[0].y = arena->old_cell_pars[1] + arena->cell_vels[1] * cell_lambda;
2626 cell->axes[0].z = arena->old_cell_pars[2] + arena->cell_vels[2] * cell_lambda;
2628 if (arena->periodic_b) {
2629 cell->axes[1].x = arena->old_cell_pars[3] + arena->cell_vels[3] * cell_lambda;
2630 cell->axes[1].y = arena->old_cell_pars[4] + arena->cell_vels[4] * cell_lambda;
2631 cell->axes[1].z = arena->old_cell_pars[5] + arena->cell_vels[5] * cell_lambda;
2633 if (arena->periodic_c) {
2634 cell->axes[2].x = arena->old_cell_pars[6] + arena->cell_vels[6] * cell_lambda;
2635 cell->axes[2].y = arena->old_cell_pars[7] + arena->cell_vels[7] * cell_lambda;
2636 cell->axes[2].z = arena->old_cell_pars[8] + arena->cell_vels[8] * cell_lambda;
2638 cell->origin.x = arena->old_cell_pars[9] + arena->cell_vels[9] * cell_lambda;
2639 cell->origin.y = arena->old_cell_pars[10] + arena->cell_vels[10] * cell_lambda;
2640 cell->origin.z = arena->old_cell_pars[11] + arena->cell_vels[11] * cell_lambda;
2641 md_update_cell(arena);
2643 md_amend_by_symmetry(arena);
2647 md_minimize_atoms_and_cell_step(MDArena *arena)
2649 Double bk, cbk, w1, w2, w3, w4, damp;
2650 Double low, mid, high, low_energy, mid_energy, high_energy, lambda;
2651 Double low_limit, scale_atom, scale_cell;
2652 Int i, retval, natoms_movable, do_cell;
2653 Atom *atoms = arena->mol->atoms;
2655 Int natoms = arena->mol->natoms;
2658 const Double phi = 0.618033988749895; /* The golden ratio */
2660 if (arena->minimize_cell && arena->mol->cell != NULL) {
2662 cell = arena->mol->cell;
2669 md_amend_by_symmetry(arena);
2671 /* Get weights of atomic forces */
2675 for (i = 0, ap = atoms, vp = arena->old_forces; i < natoms; i++, ap++, vp++) {
2676 if (ap->fix_force < 0)
2678 w1 += VecLength2(ap->f);
2679 w2 += VecDot(ap->f, *vp);
2683 if (arena->old_f_len2 == 0.0) {
2687 bk = (w1 - w2) / arena->old_f_len2;
2689 bk = 0.0; /* New direction */
2692 /* Update the search direction (atoms) */
2693 arena->old_f_len2 = arena->f_len2;
2696 for (i = 0, ap = atoms; i < natoms; i++, ap++) {
2697 if (ap->fix_force < 0)
2699 w1 = VecLength2(ap->f) * damp;
2700 if (!isfinite(w1)) /* Is isfinite() available in other platforms?? */
2701 md_panic(arena, "the gradient at atom %d exceeded limit at step %d", i+1, arena->step);
2706 for (i = 0, ap = atoms, vp = arena->old_forces; i < natoms; i++, ap++, vp++) {
2707 if (ap->fix_force < 0)
2710 *(vp + natoms) = ap->r;
2711 ap->v.x = ap->v.x * bk + ap->f.x * damp;
2712 ap->v.y = ap->v.y * bk + ap->f.y * damp;
2713 ap->v.z = ap->v.z * bk + ap->f.z * damp;
2714 w1 = VecLength2(ap->v);
2716 /* if (w1 > 1e4 || !isfinite(w1))
2717 md_panic(arena, "the gradient at atom %d exceeded limit at step %d", i+1, arena->step); */
2722 arena->max_gradient = w3;
2725 /* Get weights of cell forces */
2729 for (i = 0; i < 12; i++) {
2730 w3 = arena->cell_forces[i];
2732 w4 = arena->old_cell_forces[i];
2735 arena->cf_len2 = w1;
2736 if (arena->old_cf_len2 == 0.0) {
2740 cbk = (w1 - w2) / arena->old_cf_len2;
2742 cbk = 0.0; /* New direction */
2745 /* Update the search direction (cells) */
2746 arena->old_cf_len2 = arena->cf_len2;
2748 for (i = 0; i < 12; i++) {
2749 w1 = arena->cell_forces[i];
2750 w1 = w1 * w1 * damp;
2751 if (!isfinite(w1)) /* Is isfinite() available in other platforms?? */
2752 md_panic(arena, "the gradient at cell parameter %d exceeded limit at step %d", i+1, arena->step);
2758 for (i = 0; i < 12; i++) {
2759 arena->old_cell_forces[i] = w1 = arena->cell_forces[i];
2760 arena->old_cell_pars[i] = cell->tr[i];
2761 arena->cell_vels[i] = arena->cell_vels[i] * cbk + w1 * damp;
2768 arena->cell_max_gradient = w3;
2769 arena->cv_len2 = w2;
2772 arena->cell_max_gradient = 0.0;
2775 if (bk == 0.0 && arena->max_gradient < arena->gradient_convergence && cbk == 0.0 && arena->cell_max_gradient < arena->gradient_convergence)
2776 return 1; /* Gradient is sufficiently small */
2778 /* Proceed along ap->v/cell_vels until the energy increases */
2779 w1 = arena->coordinate_convergence / arena->max_gradient;
2781 w2 = arena->coordinate_convergence / arena->cell_max_gradient;
2782 low_limit = (w1 < w2 ? w1 : w2);
2783 } else low_limit = w1;
2784 scale_atom = 0.1 / arena->max_gradient;
2786 scale_cell = scale_atom;
2787 // scale_cell = 0.1 / arena->cell_max_gradient;
2788 else scale_cell = -1.0;
2790 low_energy = arena->total_energy;
2791 /* lambda = 1e-3 * arena->f_len2 / w2; */
2795 s_md_modify_atoms_and_cell_parameters(arena, lambda * scale_atom, lambda * scale_cell);
2798 mid_energy = arena->total_energy;
2799 if (mid_energy < low_energy) {
2800 /* mid is the 'sufficiently large' step to give lower total energy */
2802 /* Higher limit: move by this amount */
2809 high_energy = mid_energy;
2811 if (lambda < low_limit) {
2812 /* Cannot find point with lower energy than the starting point */
2813 /* Restore the original position */
2814 s_md_modify_atoms_and_cell_parameters(arena, 0, (do_cell ? 0 : -1));
2817 if (bk == 0.0 && cbk == 0.0)
2818 retval = 2; /* Movement is sufficiently small */
2822 /* Binary search for minimum */
2823 for (i = 0; i < 5; i++) {
2824 if (high - mid > mid - low) {
2825 lambda = high - (high - mid) * phi;
2826 s_md_modify_atoms_and_cell_parameters(arena, lambda * scale_atom, lambda * scale_cell);
2828 if (arena->total_energy < mid_energy) {
2830 low_energy = mid_energy;
2832 mid_energy = arena->total_energy;
2835 high_energy = arena->total_energy;
2838 lambda = mid - (mid - low) * phi;
2839 s_md_modify_atoms_and_cell_parameters(arena, lambda * scale_atom, lambda * scale_cell);
2841 if (arena->total_energy < mid_energy) {
2843 high_energy = mid_energy;
2845 mid_energy = arena->total_energy;
2848 low_energy = arena->total_energy;
2851 if ((high - low) < low_limit)
2855 /* printf("Final lambda = %g (%g)\n", lambda, arena->total_energy); */
2863 s_md_modify_cell_parameters(MDArena *arena, Double lambda)
2865 XtalCell *cell = arena->mol->cell;
2866 if (arena->periodic_a) {
2867 cell->axes[0].x = arena->old_cell_pars[0] + arena->cell_vels[0] * lambda;
2868 cell->axes[0].y = arena->old_cell_pars[1] + arena->cell_vels[1] * lambda;
2869 cell->axes[0].z = arena->old_cell_pars[2] + arena->cell_vels[2] * lambda;
2871 if (arena->periodic_b) {
2872 cell->axes[1].x = arena->old_cell_pars[3] + arena->cell_vels[3] * lambda;
2873 cell->axes[1].y = arena->old_cell_pars[4] + arena->cell_vels[4] * lambda;
2874 cell->axes[1].z = arena->old_cell_pars[5] + arena->cell_vels[5] * lambda;
2876 if (arena->periodic_b) {
2877 cell->axes[2].x = arena->old_cell_pars[6] + arena->cell_vels[6] * lambda;
2878 cell->axes[2].y = arena->old_cell_pars[7] + arena->cell_vels[7] * lambda;
2879 cell->axes[2].z = arena->old_cell_pars[8] + arena->cell_vels[8] * lambda;
2881 cell->origin.x = arena->old_cell_pars[9] + arena->cell_vels[9] * lambda;
2882 cell->origin.y = arena->old_cell_pars[10] + arena->cell_vels[10] * lambda;
2883 cell->origin.z = arena->old_cell_pars[11] + arena->cell_vels[11] * lambda;
2884 md_update_cell(arena);
2885 md_amend_by_symmetry(arena);
2889 md_minimize_cell_step(MDArena *arena)
2891 Double bk, w1, w2, w3, w4, damp;
2892 Double low, mid, high, low_energy, mid_energy, high_energy, lambda;
2893 Double low_limit, high_limit;
2896 const Double phi = 0.618033988749895; /* The golden ratio */
2898 if (arena->minimize_cell == 0 || (cell = arena->mol->cell) == NULL)
2903 for (i = 0; i < 12; i++) {
2904 w3 = arena->cell_forces[i];
2906 w4 = arena->old_cell_forces[i];
2910 arena->cf_len2 = w1;
2911 if (arena->old_cf_len2 == 0.0) {
2915 bk = (w1 - w2) / arena->old_cf_len2;
2917 bk = 0.0; /* New direction */
2919 /* Update the search direction */
2920 arena->old_cf_len2 = arena->cf_len2;
2922 for (i = 0; i < 12; i++) {
2923 w1 = arena->cell_forces[i];
2924 w1 = w1 * w1 * damp;
2925 if (!isfinite(w1)) /* Is isfinite() available in other platforms?? */
2926 md_panic(arena, "the gradient at cell parameter %d exceeded limit at step %d", i+1, arena->step);
2932 for (i = 0; i < 12; i++) {
2933 arena->old_cell_forces[i] = w1 = arena->cell_forces[i];
2934 arena->old_cell_pars[i] = cell->tr[i];
2935 arena->cell_vels[i] = arena->cell_vels[i] * bk + w1 * damp;
2942 arena->cell_max_gradient = w3;
2943 arena->cv_len2 = w2;
2944 if (bk == 0.0 && w3 < arena->gradient_convergence)
2945 return 1; /* Gradient is sufficiently small */
2947 /* Proceed along cell_vels[] until the energy increases */
2948 low_limit = arena->coordinate_convergence / arena->max_gradient;
2949 high_limit = 0.1 / arena->max_gradient;
2951 low_energy = arena->total_energy;
2952 lambda = high_limit;
2955 s_md_modify_cell_parameters(arena, lambda);
2958 mid_energy = arena->total_energy;
2959 if (mid_energy < low_energy) {
2960 /* mid is the 'sufficiently large' step to give lower total energy */
2962 /* Higher limit: move by this amount */
2969 high_energy = mid_energy;
2971 if (lambda < low_limit) {
2972 /* Cannot find point with lower energy than the starting point */
2973 /* Restore the original position */
2974 s_md_modify_cell_parameters(arena, 0);
2978 retval = 2; /* Atom movement is sufficiently small */
2983 /* low_energy >= mid_energy < high_energy */
2984 /* Binary search for minimum */
2985 for (i = 0; i < 5; i++) {
2986 if (high - mid > mid - low) {
2987 lambda = high - (high - mid) * phi;
2988 s_md_modify_cell_parameters(arena, lambda);
2990 if (arena->total_energy < mid_energy) {
2992 low_energy = mid_energy;
2994 mid_energy = arena->total_energy;
2997 high_energy = arena->total_energy;
3000 lambda = mid - (mid - low) * phi;
3001 s_md_modify_cell_parameters(arena, lambda);
3003 if (arena->total_energy < mid_energy) {
3005 high_energy = mid_energy;
3007 mid_energy = arena->total_energy;
3010 low_energy = arena->total_energy;
3013 if ((high - low) * arena->cell_max_gradient < arena->coordinate_convergence) {
3014 /* retval = 2; */ /* Atom movement is sufficiently small */
3019 /* printf("Cell minimize: ");
3020 for (i = 0; i < 12; i++) {
3021 printf(" %.6g", arena->cell_vels[i] * lambda);
3030 md_minimize_step(MDArena *arena)
3033 n1 = md_minimize_atoms_step(arena);
3036 if (arena->minimize_cell && arena->mol->cell != NULL)
3037 n2 = md_minimize_cell_step(arena);
3039 if (n1 > 0 && n2 > 0)
3045 md_update_cell(MDArena *arena)
3047 Molecule *mol = arena->mol;
3048 XtalCell *cell = mol->cell;
3050 MoleculeCalculateCellFromAxes(mol->cell, 1);
3051 for (i = 0; i < mol->nsyms; i++) {
3053 TransformMul(temp, mol->syms[i], cell->rtr);
3054 TransformMul(arena->cellsyms[i], cell->tr, temp);
3059 md_set_cell(MDArena *arena)
3061 Molecule *mol = arena->mol;
3064 if (mol->cell != NULL) {
3065 arena->periodic_a = (mol->cell->flags[0] != 0);
3066 arena->periodic_b = (mol->cell->flags[1] != 0);
3067 arena->periodic_c = (mol->cell->flags[2] != 0);
3068 if (mol->nsyms > 0) {
3070 if (mol->nsyms != arena->ncellsyms) {
3071 arena->ncellsyms = mol->nsyms;
3072 arena->cellsyms = (Transform *)realloc(arena->cellsyms, sizeof(Transform) * mol->nsyms);
3074 for (i = 0; i < mol->nsyms; i++) {
3076 TransformMul(temp, mol->syms[i], mol->cell->rtr);
3077 TransformMul(arena->cellsyms[i], mol->cell->tr, temp);
3080 arena->ncellsyms = 0;
3081 if (arena->cellsyms != NULL)
3082 free(arena->cellsyms);
3083 arena->cellsyms = NULL;
3086 arena->periodic_a = arena->periodic_b = arena->periodic_c = 0;
3090 /* scale_atoms = 1: symmetry-unique atoms are transformed to keep the fractional coordinate constant */
3091 /* scale_atoms = 2: same as scale_atoms = 1, except that the center of mass of each fragment of connected
3092 atoms are scaled and the atoms within one fragment are moved by the same amount */
3093 /* NOTE: only symmetry-unique atoms are moved, so don't forget to do md_symmetry_amend()! */
3095 md_scale_cell(MDArena *arena, const Transform tf, int scale_atoms)
3097 Transform grad, grad_inv, grad_tr, grad_inv_tr;
3102 XtalCell *cell = arena->mol->cell;
3103 memmove(grad, cell->rtr, sizeof(grad));
3104 VecCross(v, cell->axes[0], cell->axes[1]);
3105 volume = VecDot(v, cell->axes[2]);
3106 TransformVec(&cell->axes[0], tf, &cell->axes[0]);
3107 TransformVec(&cell->axes[1], tf, &cell->axes[1]);
3108 TransformVec(&cell->axes[2], tf, &cell->axes[2]);
3109 md_update_cell(arena);
3111 /* Deformation gradient (temp) = celltr * old_rcelltr */
3112 TransformMul(grad, cell->tr, grad);
3113 /* grad[9] = grad[10] = grad[11] = 0.0; */
3114 TransformInvert(grad_inv, grad);
3115 memmove(grad_tr, grad, sizeof(grad));
3116 MatrixTranspose(grad_tr, grad_tr);
3117 memmove(grad_inv_tr, grad_inv, sizeof(grad_inv));
3118 MatrixTranspose(grad_inv_tr, grad_inv_tr);
3120 if (scale_atoms == 1) {
3121 /* Scale atom positions and velocities */
3122 for (i = 0, ap = arena->mol->atoms; i < arena->natoms_uniq; i++, ap++) {
3123 if (ap->periodic_exclude)
3125 TransformVec(&ap->r, grad, &ap->r);
3126 MatrixVec(&ap->f, grad, &ap->f); /* No translational component */
3127 MatrixVec(&ap->v, grad_inv_tr, &ap->v); /* No translational component */
3129 } else if (scale_atoms == 2) {
3131 /* Scale atom positions and velocities by fragments */
3132 for (i = 0; i < arena->nfragments; i++) {
3133 VecZero(arena->fragment_info[i].pos);
3134 arena->fragment_info[i].mass = 0.0;
3136 /* Get the center of mass for each fragment */
3137 for (i = 0, ap = arena->mol->atoms; i < arena->natoms_uniq; i++, ap++) {
3138 j = arena->fragment_indices[i];
3139 if (j < 0 || j >= arena->nfragments)
3141 VecInc(arena->fragment_info[j].pos, ap->r);
3142 arena->fragment_info[j].mass += ap->weight;
3144 /* Calculate the offset for each fragment */
3145 for (j = 0; j < arena->nfragments; j++) {
3146 Vector *vp = &(arena->fragment_info[j].pos);
3147 if (arena->fragment_info[j].mass > 0.0) {
3148 VecScaleSelf(*vp, 1.0 / arena->fragment_info[j].mass);
3149 TransformVec(&v, grad, vp);
3150 VecSub(*vp, v, *vp);
3151 } else VecZero(*vp);
3154 for (i = 0, ap = arena->mol->atoms; i < arena->natoms_uniq; i++, ap++) {
3155 if (ap->periodic_exclude)
3157 MatrixVec(&ap->f, grad, &ap->f); /* This is not exact */
3158 MatrixVec(&ap->v, grad_inv_tr, &ap->v);
3159 j = arena->fragment_indices[i];
3160 if (j < 0 || j >= arena->nfragments)
3162 VecInc(ap->r, arena->fragment_info[j].pos);
3166 arena->last_verlet_step = -1;
3170 md_flush_output_files(MDArena *arena)
3172 if (arena->coord_result != NULL) {
3173 fflush(arena->coord_result);
3175 if (arena->vel_result != NULL) {
3176 fflush(arena->vel_result);
3178 if (arena->force_result != NULL) {
3179 fflush(arena->force_result);
3181 if (arena->extend_result != NULL) {
3182 fflush(arena->extend_result);
3185 if (arena->debug_result != NULL) {
3186 fflush(arena->debug_result);
3191 md_close_output_files(MDArena *arena)
3193 if (arena->coord_result != NULL) {
3194 fclose(arena->coord_result);
3195 arena->coord_result = NULL;
3197 if (arena->vel_result != NULL) {
3198 fclose(arena->vel_result);
3199 arena->vel_result = NULL;
3201 if (arena->force_result != NULL) {
3202 fclose(arena->force_result);
3203 arena->force_result = NULL;
3205 if (arena->extend_result != NULL) {
3206 fclose(arena->extend_result);
3207 arena->extend_result = NULL;
3210 if (arena->debug_result != NULL) {
3211 fclose(arena->debug_result);
3212 arena->debug_result = NULL;
3217 md_copy_coordinates_from_internal(MDArena *arena)
3219 /* Copy the internal r/v/f to xmol */
3222 if (arena->mol == NULL || arena->xmol == NULL)
3223 return -1; /* Not initialized */
3224 if (arena->mol->natoms != arena->xmol->natoms)
3225 return -2; /* Number of atoms does not match */
3226 for (i = 0, ap1 = arena->mol->atoms, ap2 = arena->xmol->atoms; i < arena->mol->natoms; i++, ap1 = ATOM_NEXT(ap1), ap2 = ATOM_NEXT(ap2)) {
3231 if (arena->mol->cell != NULL && arena->xmol->cell != NULL)
3232 memmove(arena->xmol->cell, arena->mol->cell, sizeof(XtalCell));
3237 md_copy_coordinates_to_internal(MDArena *arena)
3239 /* Copy the xmol coordinates to internal */
3242 if (arena->mol == NULL || arena->xmol == NULL)
3243 return -1; /* Not initialized */
3244 if (arena->mol->natoms != arena->xmol->natoms)
3245 return -2; /* Number of atoms does not match */
3246 for (i = 0, ap1 = arena->mol->atoms, ap2 = arena->xmol->atoms; i < arena->mol->natoms; i++, ap1 = ATOM_NEXT(ap1), ap2 = ATOM_NEXT(ap2)) {
3248 /* ap1->occupancy = ap2->occupancy; *//* Occupancy can be used to exclude particular atoms */
3249 ap1->mm_exclude = ap2->mm_exclude;
3251 if (arena->mol->cell != NULL && arena->xmol->cell != NULL)
3252 memmove(arena->mol->cell, arena->xmol->cell, sizeof(XtalCell));
3253 arena->xmol->needsMDCopyCoordinates = 0;
3258 md_is_running(MDArena *arena)
3260 if (arena != NULL && arena->is_running)
3266 md_main(MDArena *arena, int minimize)
3268 // extern int do_callback(MDArena *);
3272 int (*md_step_func)(MDArena *);
3274 if (arena->is_initialized < 2 || arena->xmol->needsMDRebuild) {
3275 /* Prepare MD parameters and runtime fields */
3276 msg = md_prepare(arena, 0);
3278 snprintf(arena->errmsg, sizeof(arena->errmsg), "%s", msg);
3281 arena->xmol->needsMDCopyCoordinates = 1; /* Coordinates will be copied below */
3284 if (arena->xmol->needsMDCopyCoordinates) {
3285 MoleculeLock(arena->xmol);
3286 retval = md_copy_coordinates_to_internal(arena);
3287 MoleculeUnlock(arena->xmol);
3290 arena->last_verlet_step = -1; /* The Verlet list needs update */
3293 arena->is_running = 1;
3294 arena->is_minimizing = minimize;
3296 if (setjmp(env) == 0) {
3297 arena->setjmp_buf = &env;
3299 md_minimize_init(arena);
3300 md_step_func = md_minimize_step;
3301 arena->minimize_complete = 0;
3303 md_step_func = md_step;
3306 /* Calculate initial energies and forces */
3307 arena->step = arena->start_step;
3308 md_amend_by_symmetry(arena);
3310 md_calc_kinetic_energy(arena);
3311 if (arena->step == 0 || arena->start_step == arena->end_step) {
3312 md_output_results(arena);
3313 md_output_energies(arena);
3315 if (arena->step == 0 && arena->md_callback_func != NULL) {
3316 retval = (*(arena->md_callback_func))(arena);
3318 snprintf(arena->errmsg, sizeof(arena->errmsg), "MD Interrupt");
3323 /* Run simulation */
3324 for (arena->step = arena->start_step + 1; arena->step <= arena->end_step; arena->step++) {
3326 /* Molecules may be modified from the callback procedure */
3327 if (arena->is_initialized < 2 || arena->xmol->needsMDRebuild) {
3328 msg = md_prepare(arena, 0);
3330 snprintf(arena->errmsg, sizeof(arena->errmsg), "%s", msg);
3336 retval = (*md_step_func)(arena);
3337 md_calc_kinetic_energy(arena);
3339 if (arena->rescale_temp_freq > 0 && arena->step % arena->rescale_temp_freq == 0)
3340 md_scale_velocities(arena);
3341 if (arena->reinit_temp_freq > 0 && arena->step % arena->reinit_temp_freq == 0)
3342 md_init_velocities(arena);
3343 if (arena->andersen_thermo_freq > 0 && arena->step % arena->andersen_thermo_freq == 0)
3344 md_andersen_thermostat(arena);
3345 if (arena->pressure != NULL)
3346 pressure_control(arena);
3349 if (arena->coord_output_freq > 0 && arena->step % arena->coord_output_freq == 0)
3350 md_output_results(arena);
3351 if (arena->energy_output_freq > 0 && arena->step % arena->energy_output_freq == 0)
3352 md_output_energies(arena);
3358 md_log(arena, "Minimize: minimization converged because the maximum gradient becomes less than the threshold.\n");
3360 arena->minimize_complete = 1;
3363 md_log(arena, "Minimize: minimization converged because the maximum movement of atoms becomes less than the threshold.\n");
3365 arena->minimize_complete = 1;
3371 if (arena->request_abort != 0) {
3372 snprintf(arena->errmsg, sizeof(arena->errmsg), "MD Abort by request");
3377 if (arena->md_callback_func != NULL && (arena->callback_freq == 0 || arena->step % arena->callback_freq == 0)) {
3378 retval = (*(arena->md_callback_func))(arena);
3380 snprintf(arena->errmsg, sizeof(arena->errmsg), "MD Interrupt");
3389 /* Return from md_panic() */
3390 retval = -1; /* Some fatal error */
3395 arena->start_step = arena->step; /* Prepare for next run */
3396 /* MoleculeLock(arena->xmol);
3397 retval = md_copy_coordinates_from_internal(arena);
3398 MoleculeUnlock(arena->xmol); */
3401 arena->setjmp_buf = NULL;
3403 if (arena->is_running) {
3404 arena->is_running = 0;
3405 md_flush_output_files(arena);
3412 md_set_default(MDArena *arena)
3414 arena->start_step = 0;
3415 arena->end_step = 1000;
3416 arena->timestep = 1;
3418 arena->coord_output_freq = 10;
3419 arena->energy_output_freq = 10;
3420 arena->cutoff = 9.0;
3421 arena->electro_cutoff = 9.0;
3422 arena->pairlist_distance = 10.0;
3423 arena->use_xplor_shift = 1;
3424 arena->scale14_vdw = 0.5;
3425 arena->scale14_elect = 0.83;
3426 arena->temperature = 300.0;
3427 arena->velocities_read = 0;
3428 arena->dielectric = 4.8;
3429 /* arena->probe_radius = 3.2; */
3430 arena->probe_radius = 0.0;
3431 arena->surface_tension = -0.005;
3432 arena->surface_potential_freq = 5;
3434 arena->velocity_limit = 100.0;
3435 arena->sym_tolerance = 5e-3;
3436 arena->gradient_convergence = 1e-6;
3437 arena->coordinate_convergence = 1e-8;
3438 arena->relocate_center = 1;
3439 arena->andersen_thermo_freq = 50;
3440 arena->andersen_thermo_coupling = 0.1;
3441 arena->pressure_freq = 0;
3443 arena->alchem_dlambda = 0.1;
3445 /* arena->pressure_coupling = 0.4;
3446 arena->pressure_trial_width = 0.01;
3447 arena->pressure_control_algorithm = 0;
3448 arena->pressure_fluctuate_cell_origin = 0.01;
3449 arena->pressure_fluctuate_cell_orientation = 0.01;
3450 arena->pressure[0] = 1;
3451 arena->pressure[1] = 0;
3452 arena->pressure[2] = 0;
3453 arena->pressure[3] = 0;
3454 arena->pressure[4] = 1;
3455 arena->pressure[5] = 0;
3456 arena->pressure[6] = 0;
3457 arena->pressure[7] = 0;
3458 arena->pressure[8] = 1;
3459 arena->cell_flexibility[0] = -1;
3460 arena->cell_flexibility[1] = -1;
3461 arena->cell_flexibility[2] = -1;
3462 arena->cell_flexibility[3] = 0;
3463 arena->cell_flexibility[4] = 0;
3464 arena->cell_flexibility[5] = 0;
3465 arena->cell_flexibility[6] = 0;
3466 arena->cell_flexibility[7] = 0; */
3467 /* arena->cella.x = 1;
3475 arena->cellc.z = 1; */
3476 /* if (arena->mol != NULL && arena->mol->box != NULL)
3477 md_update_cell(arena); */
3481 md_arena_new(Molecule *xmol)
3484 arena = (MDArena *)calloc(sizeof(MDArena), 1);
3487 arena->refCount = 1;
3488 md_set_default(arena);
3490 md_arena_set_molecule(arena, xmol);
3496 md_arena_set_molecule(MDArena *arena, Molecule *xmol)
3498 /* xmol is set to mol */
3501 if (arena->xmol != xmol) {
3502 if (arena->xmol != NULL) {
3503 if (arena->xmol->arena == arena)
3504 arena->xmol->arena = NULL;
3505 MoleculeRelease(arena->xmol);
3509 MoleculeRetain(arena->xmol);
3510 arena->xmol->arena = arena;
3514 /* Dispose the internal cache */
3515 if (arena->mol != NULL) {
3516 if (arena->mol->arena == arena)
3517 arena->mol->arena = NULL;
3518 MoleculeRelease(arena->mol);
3523 /* Create an internal copy */
3524 Molecule *mol = MoleculeNew();
3525 Atom *ap, *ap2, arec;
3527 NewArray(&mol->atoms, &mol->natoms, gSizeOfAtomRecord, xmol->natoms);
3528 for (i = 0, ap = mol->atoms, ap2 = xmol->atoms; i < xmol->natoms; i++, ap = ATOM_NEXT(ap), ap2 = ATOM_NEXT(ap2)) {
3529 memmove(&arec, ap2, gSizeOfAtomRecord);
3530 /* Aniso and frames are unnecessary */
3534 AtomDuplicate(ap, &arec);
3536 NewArray(&mol->bonds, &mol->nbonds, sizeof(Int) * 2, xmol->nbonds);
3537 memmove(mol->bonds, xmol->bonds, sizeof(Int) * 2 * xmol->nbonds);
3538 NewArray(&mol->angles, &mol->nangles, sizeof(Int) * 3, xmol->nangles);
3539 memmove(mol->angles, xmol->angles, sizeof(Int) * 3 * xmol->nangles);
3540 NewArray(&mol->dihedrals, &mol->ndihedrals, sizeof(Int) * 4, xmol->ndihedrals);
3541 memmove(mol->dihedrals, xmol->dihedrals, sizeof(Int) * 4 * xmol->ndihedrals);
3542 NewArray(&mol->impropers, &mol->nimpropers, sizeof(Int) * 4, xmol->nimpropers);
3543 memmove(mol->impropers, xmol->impropers, sizeof(Int) * 4 * xmol->nimpropers);
3544 NewArray(&mol->syms, &mol->nsyms, sizeof(Transform), xmol->nsyms);
3545 memmove(mol->syms, xmol->syms, sizeof(Transform) * xmol->nsyms);
3546 if (xmol->cell != NULL) {
3547 mol->cell = (XtalCell *)malloc(sizeof(XtalCell));
3548 memmove(mol->cell, xmol->cell, sizeof(XtalCell));
3550 if (xmol->path != NULL)
3551 mol->path = strdup(xmol->path);
3552 /* if (xmol->box != NULL) {
3553 mol->box = (PeriodicBox *)malloc(sizeof(PeriodicBox));
3554 memmove(mol->box, xmol->box, sizeof(PeriodicBox));
3557 mol->par = xmol->par;
3558 if (mol->par != NULL)
3559 ParameterRetain(mol->par);
3566 md_arena_retain(MDArena *arena)
3574 md_arena_release(MDArena *arena)
3579 if (--arena->refCount != 0)
3581 if (arena->mol != NULL) {
3582 if (arena->mol->arena == arena)
3583 arena->mol->arena = NULL;
3584 MoleculeRelease(arena->mol);
3586 if (arena->xmol != NULL) {
3587 if (arena->xmol->arena == arena)
3588 arena->xmol->arena = NULL;
3589 MoleculeRelease(arena->xmol);
3591 if (arena->par != NULL)
3592 ParameterRelease(arena->par);
3593 if (arena->log_result_name != NULL)
3594 free((void *)arena->log_result_name);
3595 if (arena->coord_result_name != NULL)
3596 free((void *)arena->coord_result_name);
3597 if (arena->vel_result_name != NULL)
3598 free((void *)arena->vel_result_name);
3599 if (arena->force_result_name != NULL)
3600 free((void *)arena->force_result_name);
3601 if (arena->extend_result_name != NULL)
3602 free((void *)arena->extend_result_name);
3603 if (arena->debug_result_name != NULL)
3604 free((void *)arena->debug_result_name);
3605 if (arena->log_result != NULL)
3606 fclose(arena->log_result);
3607 if (arena->coord_result != NULL)
3608 fclose(arena->coord_result);
3609 if (arena->vel_result != NULL)
3610 fclose(arena->vel_result);
3611 if (arena->force_result != NULL)
3612 fclose(arena->force_result);
3613 if (arena->extend_result != NULL)
3614 fclose(arena->extend_result);
3615 if (arena->debug_result != NULL)
3616 fclose(arena->debug_result);
3617 if (arena->custom_bond_pars != NULL)
3618 free(arena->custom_bond_pars);
3619 if (arena->custom_pars != NULL)
3620 free(arena->custom_pars);
3621 if (arena->alchem_flags != NULL)
3622 free(arena->alchem_flags);
3623 if (arena->exforces != NULL)
3624 free(arena->exforces);
3625 if (arena->bond_par_i != NULL)
3626 free(arena->bond_par_i);
3627 if (arena->angle_par_i != NULL)
3628 free(arena->angle_par_i);
3629 if (arena->dihedral_par_i != NULL)
3630 free(arena->dihedral_par_i);
3631 if (arena->improper_par_i != NULL)
3632 free(arena->improper_par_i);
3633 if (arena->vdw_par_i != NULL)
3634 free(arena->vdw_par_i);
3635 if (arena->vdw_cache != NULL)
3636 free(arena->vdw_cache);
3637 if (arena->energies != NULL)
3638 free(arena->energies);
3639 if (arena->forces != NULL)
3640 free(arena->forces);
3641 if (arena->pair_forces != NULL)
3642 free(arena->pair_forces);
3643 if (arena->cellsyms != NULL)
3644 free(arena->cellsyms);
3645 if (arena->pressure != NULL)
3646 pressure_release(arena->pressure);
3647 if (arena->fragment_indices != NULL)
3648 free(arena->fragment_indices);
3649 if (arena->fragment_info != NULL)
3650 free(arena->fragment_info);
3651 #warning "TODO: Is arena->exatoms really necessary? "
3652 if (arena->exatoms != NULL)
3653 free(arena->exatoms);
3654 if (arena->special_positions != NULL)
3655 free(arena->special_positions);
3656 if (arena->exlist != NULL)
3657 free(arena->exlist);
3658 if (arena->exinfo != NULL)
3659 free(arena->exinfo);
3660 if (arena->verlets != NULL)
3661 free(arena->verlets);
3662 if (arena->verlets_dr != NULL)
3663 free(arena->verlets_dr);
3664 if (arena->verlet_i != NULL)
3665 free(arena->verlet_i);
3666 if (arena->snapshots != NULL) {
3667 for (i = 0; i < arena->nsnapshots; i++) {
3668 if (arena->snapshots[i] != NULL)
3669 free(arena->snapshots[i]);
3671 free(arena->snapshots);
3673 if (arena->old_forces != NULL)
3674 free(arena->old_forces);
3675 if (arena->old_pos != NULL)
3676 free(arena->old_pos);
3677 if (arena->graphite != NULL)
3678 graphite_release(arena->graphite);
3679 if (arena->ring != NULL)
3685 md_arena_init_from_arena(MDArena *arena, MDArena *another_arena)
3687 if (arena == NULL || another_arena == NULL)
3690 arena->timestep = another_arena->timestep;
3692 arena->coord_output_freq = another_arena->coord_output_freq;
3693 arena->energy_output_freq = another_arena->energy_output_freq;
3694 arena->cutoff = another_arena->cutoff;
3695 arena->electro_cutoff = another_arena->electro_cutoff;
3696 arena->pairlist_distance = another_arena->pairlist_distance;
3697 arena->use_xplor_shift = another_arena->use_xplor_shift;
3698 arena->scale14_vdw = another_arena->scale14_vdw;
3699 arena->scale14_elect = another_arena->scale14_elect;
3700 arena->temperature = another_arena->temperature;
3701 arena->rescale_temp_freq = another_arena->rescale_temp_freq;
3702 arena->reinit_temp_freq = another_arena->reinit_temp_freq;
3703 arena->velocities_read = another_arena->velocities_read;
3704 arena->dielectric = another_arena->dielectric;
3705 arena->probe_radius = another_arena->probe_radius;
3706 arena->surface_tension = another_arena->surface_tension;
3707 arena->surface_potential_freq = another_arena->surface_potential_freq;
3708 arena->anbond_thres = another_arena->anbond_thres;
3709 arena->anbond_anneal_rate = another_arena->anbond_anneal_rate;
3710 arena->velocity_limit = another_arena->velocity_limit;
3711 arena->sym_tolerance = another_arena->sym_tolerance;
3712 arena->gradient_convergence = another_arena->gradient_convergence;
3713 arena->coordinate_convergence = another_arena->coordinate_convergence;
3714 arena->relocate_center = another_arena->relocate_center;
3715 arena->andersen_thermo_freq = another_arena->andersen_thermo_freq;
3716 arena->andersen_thermo_coupling = another_arena->andersen_thermo_coupling;
3717 arena->pressure_freq = another_arena->pressure_freq;
3725 v = v + (dt/2) * (f/m)
3727 call rattle_coodinate
3729 v = v + (dt/2) * (f/m)
3730 call rattle_velocity