4 * Created by Toshi Nagata on 06/03/11.
5 * Copyright 2006-2008 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.
23 /* Global parameter: it is initialized by the first call to ParameterReadFromFile() */
24 Parameter *gBuiltinParameters = NULL;
26 /* Global parameter */
27 ElementPar *gElementParameters = NULL;
28 Int gCountElementParameters = 0;
30 static Parameter *sParameterRoot = NULL;
31 static int sParameterUntitledCount = 0;
33 /* Global struct for storing information for global parameter files */
34 GlobalParInfoRecord gGlobalParInfo;
36 #pragma mark ====== Parameter Alloc/Release ======
42 Parameter *par = (Parameter *)calloc(sizeof(Parameter), 1);
44 Panic("Cannot allocate new parameter record");
45 snprintf(name, sizeof name, "Untitled %d", sParameterUntitledCount++);
46 ObjectInit((Object *)par, (Object **)&sParameterRoot, name);
51 ParameterDuplicate(const Parameter *par)
53 Parameter *npar = ParameterNew();
54 if (par->bondPars != NULL) {
55 npar->bondPars = (BondPar *)malloc(sizeof(BondPar) * par->nbondPars);
56 if (npar->bondPars == NULL)
58 memmove(npar->bondPars, par->bondPars, sizeof(BondPar) * par->nbondPars);
59 npar->nbondPars = par->nbondPars;
61 if (par->anglePars != NULL) {
62 npar->anglePars = (AnglePar *)malloc(sizeof(AnglePar) * par->nanglePars);
63 if (npar->anglePars == NULL)
65 memmove(npar->anglePars, par->anglePars, sizeof(AnglePar) * par->nanglePars);
66 npar->nanglePars = par->nanglePars;
68 if (par->dihedralPars != NULL) {
69 npar->dihedralPars = (TorsionPar *)malloc(sizeof(TorsionPar) * par->ndihedralPars);
70 if (npar->dihedralPars == NULL)
72 memmove(npar->dihedralPars, par->dihedralPars, sizeof(TorsionPar) * par->ndihedralPars);
73 npar->ndihedralPars = par->ndihedralPars;
75 if (par->improperPars != NULL) {
76 npar->improperPars = (TorsionPar *)malloc(sizeof(TorsionPar) * par->nimproperPars);
77 if (npar->improperPars == NULL)
79 memmove(npar->improperPars, par->improperPars, sizeof(TorsionPar) * par->nimproperPars);
80 npar->nimproperPars = par->nimproperPars;
82 if (par->vdwPars != NULL) {
83 npar->vdwPars = (VdwPar *)malloc(sizeof(VdwPar) * par->nvdwPars);
84 if (npar->vdwPars == NULL)
86 memmove(npar->vdwPars, par->vdwPars, sizeof(VdwPar) * par->nvdwPars);
87 npar->nvdwPars = par->nvdwPars;
89 if (par->vdwpPars != NULL) {
90 npar->vdwpPars = (VdwPairPar *)malloc(sizeof(VdwPairPar) * par->nvdwpPars);
91 if (npar->vdwpPars == NULL)
93 memmove(npar->vdwpPars, par->vdwpPars, sizeof(VdwPairPar) * par->nvdwpPars);
94 npar->nvdwpPars = par->nvdwpPars;
96 if (par->vdwCutoffPars != NULL) {
97 npar->vdwCutoffPars = (VdwCutoffPar *)malloc(sizeof(VdwCutoffPar) * par->nvdwCutoffPars);
98 if (npar->vdwCutoffPars == NULL)
100 memmove(npar->vdwCutoffPars, par->vdwCutoffPars, sizeof(VdwCutoffPar) * par->nvdwCutoffPars);
101 npar->nvdwCutoffPars = par->nvdwCutoffPars;
103 /* if (par->atomPars != NULL) {
104 npar->atomPars = (ElementPar *)malloc(sizeof(ElementPar) * par->natomPars);
105 if (npar->atomPars == NULL)
107 memmove(npar->atomPars, par->atomPars, sizeof(ElementPar) * par->natomPars);
108 npar->natomPars = par->natomPars;
112 ParameterRelease(npar);
117 ParameterWithName(const char *name)
119 return (Parameter *)ObjectWithName(name, (Object *)sParameterRoot);
122 /* Assign a unique name to this parameter record */
124 ParameterSetName(Parameter *par, const char *name)
126 ObjectSetName((Object *)par, name, (Object *)sParameterRoot);
130 ParameterGetName(Parameter *par)
132 return ObjectGetName((Object *)par);
136 ParameterRetain(Parameter *par)
138 ObjectIncrRefCount((Object *)par);
142 ParameterRelease(Parameter *par)
144 if (ObjectDecrRefCount((Object *)par) == 0) {
145 if (par->bondPars != NULL)
147 if (par->anglePars != NULL)
148 free(par->anglePars);
149 if (par->dihedralPars != NULL)
150 free(par->dihedralPars);
151 if (par->improperPars != NULL)
152 free(par->improperPars);
153 if (par->vdwPars != NULL)
155 if (par->vdwpPars != NULL)
157 if (par->vdwCutoffPars != NULL)
158 free(par->vdwCutoffPars);
159 /* if (par->atomPars != NULL)
160 free(par->atomPars); */
161 ObjectDealloc((Object *)par, (Object **)&sParameterRoot);
165 #pragma mark ====== ParameterRef Definitions ======
168 ParameterRefNew(struct Molecule *mol, int type, int idx)
170 ParameterRef *pref = (ParameterRef *)calloc(sizeof(ParameterRef), 1);
175 pref->parType = type;
182 ParameterRefRelease(ParameterRef *pref)
185 if (pref->mol != NULL)
186 MoleculeRelease(pref->mol);
192 ParameterGetUnionParFromTypeAndIndex(Parameter *par, int type, int index)
198 if (index >= 0 && index < par->nbondPars)
199 return (UnionPar *)(par->bondPars + index);
202 if (index >= 0 && index < par->nanglePars)
203 return (UnionPar *)(par->anglePars + index);
205 case kDihedralParType:
206 if (index >= 0 && index < par->ndihedralPars)
207 return (UnionPar *)(par->dihedralPars + index);
209 case kImproperParType:
210 if (index >= 0 && index < par->nimproperPars)
211 return (UnionPar *)(par->improperPars + index);
214 if (index >= 0 && index < par->nvdwPars)
215 return (UnionPar *)(par->vdwPars + index);
217 case kVdwPairParType:
218 if (index >= 0 && index < par->nvdwpPars)
219 return (UnionPar *)(par->vdwpPars + index);
221 case kVdwCutoffParType:
222 if (index >= 0 && index < par->nvdwCutoffPars)
223 return (UnionPar *)(par->vdwCutoffPars + index);
225 /* case kElementParType:
226 if (index >= 0 && index < par->natomPars)
227 return (UnionPar *)(par->atomPars + index);
235 ParameterGetCountForType(Parameter *par, int type)
241 return par->nbondPars;
243 return par->nanglePars;
244 case kDihedralParType:
245 return par->ndihedralPars;
246 case kImproperParType:
247 return par->nimproperPars;
249 return par->nvdwPars;
250 case kVdwPairParType:
251 return par->nvdwpPars;
252 case kVdwCutoffParType:
253 return par->nvdwCutoffPars;
254 /* case kElementParType:
255 return par->natomPars; */
262 ParameterGetSizeForType(int type)
266 return sizeof(BondPar);
268 return sizeof(AnglePar);
269 case kDihedralParType:
270 return sizeof(TorsionPar);
271 case kImproperParType:
272 return sizeof(TorsionPar);
274 return sizeof(VdwPar);
275 case kVdwPairParType:
276 return sizeof(VdwPairPar);
277 case kVdwCutoffParType:
278 return sizeof(VdwCutoffPar);
279 /* case kElementParType:
280 return par->natomPars; */
287 ParameterCopyOneWithType(UnionPar *dst, const UnionPar *src, int type)
289 int size = ParameterGetSizeForType(type);
290 memmove(dst, src, size);
294 ParameterRefGetPar(ParameterRef *pref)
299 if (pref->mol != NULL)
300 par = pref->mol->par;
301 else par = gBuiltinParameters;
304 return ParameterGetUnionParFromTypeAndIndex(par, pref->parType, pref->idx);
307 #pragma mark ====== Insert/Delete (for MolAction) ======
310 ParameterInsert(Parameter *par, Int type, const UnionPar *up, struct IntGroup *where)
312 Int i, n1, n2, size, *ip;
319 ip = &par->nbondPars;
320 size = sizeof(BondPar);
324 ip = &par->nanglePars;
325 size = sizeof(AnglePar);
327 case kDihedralParType:
328 p = &par->dihedralPars;
329 ip = &par->ndihedralPars;
330 size = sizeof(TorsionPar);
332 case kImproperParType:
333 p = &par->improperPars;
334 ip = &par->nimproperPars;
335 size = sizeof(TorsionPar);
340 size = sizeof(VdwPar);
342 case kVdwPairParType:
344 ip = &par->nvdwpPars;
345 size = sizeof(VdwPairPar);
347 case kVdwCutoffParType:
348 p = &par->vdwCutoffPars;
349 ip = &par->nvdwCutoffPars;
350 size = sizeof(VdwCutoffPar);
352 /* case kElementParType:
354 ip = &par->natomPars;
355 size = sizeof(ElementPar);
361 for (i = 0; (n1 = IntGroupGetNthPoint(where, i)) >= 0; i++) {
362 if (InsertArray(p, ip, size, n1, 1, (up ? up + i : NULL)) == NULL)
370 sParameterDeleteOrCopy(Parameter *par, Int type, UnionPar *up, struct IntGroup *where, Int copyflag)
372 Int i, n1, n2, size, *ip;
378 p = (char **)&par->bondPars;
379 ip = &par->nbondPars;
380 size = sizeof(BondPar);
383 p = (char **)&par->anglePars;
384 ip = &par->nanglePars;
385 size = sizeof(AnglePar);
387 case kDihedralParType:
388 p = (char **)&par->dihedralPars;
389 ip = &par->ndihedralPars;
390 size = sizeof(TorsionPar);
392 case kImproperParType:
393 p = (char **)&par->improperPars;
394 ip = &par->nimproperPars;
395 size = sizeof(TorsionPar);
398 p = (char **)&par->vdwPars;
400 size = sizeof(VdwPar);
402 case kVdwPairParType:
403 p = (char **)&par->vdwpPars;
404 ip = &par->nvdwpPars;
405 size = sizeof(VdwPairPar);
407 case kVdwCutoffParType:
408 p = (char **)&par->vdwCutoffPars;
409 ip = &par->nvdwCutoffPars;
410 size = sizeof(VdwCutoffPar);
412 /* case kElementParType:
413 p = (char **)&par->atomPars;
414 ip = &par->natomPars;
415 size = sizeof(ElementPar);
421 for (i = IntGroupGetCount(where) - 1; i >= 0 && (n1 = IntGroupGetNthPoint(where, i)) >= 0; i--) {
423 return -1; /* Internal error */
426 memmove(up + i, *p + size * n1, size);
428 if (DeleteArray(p, ip, size, n1, 1, (up ? up + i : NULL)) == NULL)
437 ParameterDelete(Parameter *par, Int type, UnionPar *up, struct IntGroup *where)
439 return sParameterDeleteOrCopy(par, type, up, where, 0);
443 ParameterCopy(Parameter *par, Int type, UnionPar *up, struct IntGroup *where)
445 return sParameterDeleteOrCopy(par, type, up, where, 1);
448 /* Renumber the atom index field according to the conversion table. If the atom index
449 points to a non-existing atom, returns non-zero. */
451 ParameterRenumberAtoms(Int type, UnionPar *up, Int oldnatoms, const Int *old2new)
453 #define RENUMBER_FIELD(_tp, _field) \
454 (((_tp *)up)->_field >= 0 && ((_tp *)up)->_field < oldnatoms && \
455 (old2new[((_tp *)up)->_field] >= 0 ? \
456 ((((_tp *)up)->_field = old2new[((_tp *)up)->_field]), 0) : \
457 ((((_tp *)up)->_field = kAtomTypeWildcard), 1)))
460 return RENUMBER_FIELD(BondPar, type1) + RENUMBER_FIELD(BondPar, type2);
462 return RENUMBER_FIELD(AnglePar, type1) + RENUMBER_FIELD(AnglePar, type2) + RENUMBER_FIELD(AnglePar, type3);
463 case kDihedralParType:
464 case kImproperParType:
465 return RENUMBER_FIELD(TorsionPar, type1) + RENUMBER_FIELD(TorsionPar, type2) + RENUMBER_FIELD(TorsionPar, type3) + RENUMBER_FIELD(TorsionPar, type4);
467 return RENUMBER_FIELD(VdwPar, type1);
468 case kVdwPairParType:
469 return RENUMBER_FIELD(VdwPairPar, type1) + RENUMBER_FIELD(VdwPairPar, type2);
470 case kVdwCutoffParType:
471 if (((VdwCutoffPar *)up)->type == 1)
472 return RENUMBER_FIELD(VdwCutoffPar, n1) + RENUMBER_FIELD(VdwCutoffPar, n2) + RENUMBER_FIELD(VdwCutoffPar, n3) || RENUMBER_FIELD(VdwCutoffPar, n4);
479 #pragma mark ====== Load from Files ======
482 s_AppendWarning(char **ptr, const char *fmt, ...)
490 *ptr = (char *)malloc(128);
498 for (len = 128; len <= n; len *= 2);
501 nn = vasprintf(&buf, fmt, ap);
505 while (len <= n + nn)
507 *ptr = (char *)realloc(*ptr, len);
511 strncpy(*ptr + n, buf, nn);
512 *(*ptr + n + nn) = 0;
518 ParameterGlobalParIndexForSrcIndex(int src)
521 if (src == 0 || src == -1)
523 for (i = 0; i < gGlobalParInfo.count; i++) {
524 if (gGlobalParInfo.files[i].src == src)
531 ParameterCommentIndexForGlobalFileName(const char *p)
533 const char *pp = p + strlen(p), *p1 = NULL, *p2 = NULL;
536 if (p2 == NULL && *pp == '.')
538 if (p1 == NULL && (*pp == '\'' || *pp == '/'))
545 snprintf(buf, sizeof(buf), "%.*s", (int)(p2 - p1), p1);
546 return ParameterCommentIndex(buf);
550 ParameterCompare(const UnionPar *up1, const UnionPar *up2, int type)
554 const BondPar *bp1 = &up1->bond;
555 const BondPar *bp2 = &up2->bond;
556 return (((bp1->type1 == bp2->type1 && bp1->type2 == bp2->type2)
557 || (bp1->type1 == bp2->type2 && bp1->type2 == bp2->type1))
558 && fabs(bp1->k - bp2->k) < 1e-8 && fabs(bp1->r0 - bp2->r0) < 1e-8);
560 case kAngleParType: {
561 const AnglePar *ap1 = &up1->angle;
562 const AnglePar *ap2 = &up2->angle;
563 return (ap1->type2 == ap2->type2
564 && ((ap1->type1 == ap2->type1 && ap1->type3 == ap2->type3)
565 || (ap1->type1 == ap2->type3 && ap1->type3 == ap2->type1))
566 && fabs(ap1->k - ap2->k) < 1e-8 && fabs(ap1->a0 - ap2->a0) < 1e-8);
568 case kDihedralParType:
569 case kImproperParType: {
570 const TorsionPar *tp1 = &up1->torsion;
571 const TorsionPar *tp2 = &up2->torsion;
573 if (tp1->mult != tp2->mult)
575 if (type == kDihedralParType) {
576 if ((tp1->type1 != tp2->type1 || tp1->type2 != tp2->type2 || tp1->type3 != tp2->type3 || tp1->type4 != tp2->type4)
577 && (tp1->type1 != tp2->type4 || tp1->type2 != tp2->type3 || tp1->type3 != tp2->type2 || tp1->type4 != tp2->type1))
580 if (tp1->type3 != tp2->type3)
582 if ((tp1->type1 != tp2->type1 || tp1->type2 != tp2->type2 || tp1->type4 != tp2->type4)
583 && (tp1->type1 != tp2->type1 || tp1->type2 != tp2->type4 || tp1->type4 != tp2->type2)
584 && (tp1->type1 != tp2->type2 || tp1->type2 != tp2->type1 || tp1->type4 != tp2->type4)
585 && (tp1->type1 != tp2->type2 || tp1->type2 != tp2->type4 || tp1->type4 != tp2->type1)
586 && (tp1->type1 != tp2->type4 || tp1->type2 != tp2->type1 || tp1->type4 != tp2->type2)
587 && (tp1->type1 != tp2->type4 || tp1->type2 != tp2->type2 || tp1->type4 != tp2->type1))
590 for (i = 0; i < tp1->mult; i++) {
591 if (tp1->period[i] != tp2->period[i] || fabs(tp1->k[i] - tp2->k[i]) > 1e-8 || fabs(tp1->phi0[i] - tp2->phi0[i]) > 1e-8)
597 const VdwPar *vp1 = &up1->vdw;
598 const VdwPar *vp2 = &up2->vdw;
599 return (vp1->type1 == vp2->type1 && fabs(vp1->eps - vp2->eps) < 1e-6 && fabs(vp1->r_eq - vp2->r_eq) < 1e-6 && fabs(vp1->eps14 - vp2->eps14) < 1e-4 && fabs(vp1->r_eq14 - vp2->r_eq14) < 1e-4);
601 case kVdwPairParType: {
602 const VdwPairPar *vp1 = &up1->vdwp;
603 const VdwPairPar *vp2 = &up2->vdwp;
604 return (vp1->type1 == vp2->type1 && fabs(vp1->eps - vp2->eps) < 1e-6 && fabs(vp1->r_eq - vp2->r_eq) < 1e-6 && fabs(vp1->eps14 - vp2->eps14) < 1e-4 && fabs(vp1->r_eq14 - vp2->r_eq14) < 1e-4);
606 case kVdwCutoffParType: {
607 const VdwCutoffPar *vp1 = &up1->vdwcutoff;
608 const VdwCutoffPar *vp2 = &up2->vdwcutoff;
609 if (vp1->type != vp2->type)
611 if (vp1->type == 0) {
612 if ((vp1->n1 != vp2->n1 || vp1->n2 != vp2->n2) && (vp1->n1 != vp2->n2 || vp1->n2 != vp2->n1))
615 if (vp1->n1 != vp2->n1 || vp1->n2 != vp2->n2 || vp1->n3 != vp2->n3 || vp1->n4 != vp2->n4)
618 return fabs(vp1->cutoff - vp2->cutoff) < 1e-8;
624 /* bp can also be AnglePar *, TorsionPar *, etc. */
626 s_StoreComment(int parType, BondPar *bp, char *p, const char *src)
628 char *s, *pp, *pcom, buf[40];
629 int embedded = 0, src_idx;
632 while (isspace(*p) || *p == ';' || *p == '!')
635 if (src == NULL && *p == '[') {
636 /* Source is embedded */
640 while (*p != ']' && *p != 0)
643 if (len >= sizeof(buf))
644 len = sizeof(buf) - 1;
645 strncpy(buf, s, len);
656 while (*pp != 0 && *pp != '\r' && *pp != '\n')
659 if (src != NULL && *src != 0) {
660 src_idx = ParameterCommentIndex(src);
662 /* Compare with already known global parameters, and src is set if the same one is found */
665 for (i = 0; (up2 = ParameterGetUnionParFromTypeAndIndex(gBuiltinParameters, parType, i)) != NULL; i++) {
666 if (up2->bond.src == src_idx && ParameterCompare((UnionPar *)bp, up2, parType)) {
672 /* Not found: embedded source is retained, and this entry is regarded as "no source" */
676 } else bp->src = src_idx;
679 bp->com = ParameterCommentIndex(p);
682 /* bp can also be BondPar*, AnglePar *, TorsionPar *, etc. */
684 s_CommentToString(char *buf, int bufsize, void *bp)
686 const char *src, *com;
687 src = ParameterGetComment(((BondPar *)bp)->src);
688 com = ParameterGetComment(((BondPar *)bp)->com);
689 if (src == NULL && com == NULL)
691 else if (src != NULL)
692 snprintf(buf, bufsize, " ![%s] %s", src, (com == NULL ? "" : com));
694 snprintf(buf, bufsize, " ! %s", com);
698 ParameterReadFromString(Parameter *par, char *buf, char **wbufp, const char *fname, int lineNumber, int src_idx)
701 char com[12], com2[12], type[4][8];
703 float val[6]; /* not Double */
708 if (sscanf(buf, " %11s", com) <= 0 || !isalpha(com[0]))
711 for (i = 0; i < len; i++)
712 com[i] = tolower(com[i]);
713 if (strncmp(com, "include", len) == 0) {
718 for ( ; (c = buf[len]) != 0; len++) {
719 if (c == ' ' || c == '\t')
737 p = (char *)malloc(strlen(fname) + i + 1);
742 pp = strrchr(p, '/');
747 i = ParameterReadFromFile(par, p, &wbuf1, &wc1);
749 s_AppendWarning(wbufp, "In included file %s:\n%s", p, wbuf1);
759 if (par == gBuiltinParameters && src_idx == 0) {
760 /* Comes here only when the reading file is "default.par" at the initialization of the built-in parameters. */
761 /* In this case, only "include" statements are allowed. */
766 else src = ParameterGetComment(src_idx);
767 options = kParameterLookupNoWildcard | kParameterLookupNoBaseAtomType;
768 if (strncmp(com, "bond", len) == 0) {
770 if (sscanf(buf, " %11s %4s %4s %f %f %n", com2, type[0], type[1], &val[0], &val[1], &n) < 5) {
771 s_AppendWarning(wbufp, "%s:%d: missing parameter in BOND record\n", fname, lineNumber);
774 itype[0] = AtomTypeEncodeToUInt(type[0]);
775 itype[1] = AtomTypeEncodeToUInt(type[1]);
776 if (itype[0] > itype[1]) {
781 val[0] *= KCAL2INTERNAL;
782 bp = ParameterLookupBondPar(par, itype[0], itype[1], options);
784 if (bp->k != val[0] || bp->r0 != val[1]) {
785 s_AppendWarning(wbufp, "%s:%d: The BOND %s-%s parameter appeared twice; the values (%f, %f) are used\n", fname, lineNumber, AtomTypeDecodeToString(itype[0], type[0]), AtomTypeDecodeToString(itype[1], type[1]), val[0], val[1]);
789 bp = AssignArray(&par->bondPars, &par->nbondPars, sizeof(*bp), par->nbondPars, NULL);
790 bp->type1 = itype[0];
791 bp->type2 = itype[1];
794 s_StoreComment(kBondParType, bp, buf + n, src);
795 } else if (strncmp(com, "angle", len) == 0) {
797 if (sscanf(buf, " %11s %4s %4s %4s %f %f %n", com2, type[0], type[1], type[2], &val[0], &val[1], &n) < 6) {
798 s_AppendWarning(wbufp, "%s:%d: missing parameter in ANGLE record\n", fname, lineNumber);
801 itype[0] = AtomTypeEncodeToUInt(type[0]);
802 itype[1] = AtomTypeEncodeToUInt(type[1]);
803 itype[2] = AtomTypeEncodeToUInt(type[2]);
804 if (itype[0] > itype[2]) {
809 val[0] *= KCAL2INTERNAL;
810 val[1] *= (3.14159265358979 / 180.0);
811 ap = ParameterLookupAnglePar(par, itype[0], itype[1], itype[2], options);
813 if (ap->k != val[0] || ap->a0 != val[1]) {
814 s_AppendWarning(wbufp, "%s:%d: The ANGLE %s-%s-%s parameter appeared twice; the values (%f, %f) are used\n", fname, lineNumber, AtomTypeDecodeToString(itype[0], type[0]), AtomTypeDecodeToString(itype[1], type[1]), AtomTypeDecodeToString(itype[2], type[2]), val[0], val[1]);
818 ap = AssignArray(&par->anglePars, &par->nanglePars, sizeof(*ap), par->nanglePars, NULL);
819 ap->type1 = itype[0];
820 ap->type2 = itype[1];
821 ap->type3 = itype[2];
824 s_StoreComment(kAngleParType, (BondPar *)ap, buf + n, src);
825 } else if (strncmp(com, "dihedral", len) == 0) {
827 if (sscanf(buf, " %11s %4s %4s %4s %4s %f %d %f %n", com2, type[0], type[1], type[2], type[3], &val[0], &ival[0], &val[1], &n) < 8) {
828 s_AppendWarning(wbufp, "%s:%d: missing parameter in DIHEDRAL record\n", fname, lineNumber);
831 itype[0] = AtomTypeEncodeToUInt(type[0]);
832 itype[1] = AtomTypeEncodeToUInt(type[1]);
833 itype[2] = AtomTypeEncodeToUInt(type[2]);
834 itype[3] = AtomTypeEncodeToUInt(type[3]);
835 if (itype[0] > itype[3]) {
843 dp = ParameterLookupDihedralPar(par, itype[0], itype[1], itype[2], itype[3], options);
844 val[0] *= KCAL2INTERNAL;
845 val[1] *= 3.14159265358979 / 180.0;
847 if (dp->mult != 1 || dp->k[0] != val[0] || dp->period[0] != ival[0] || dp->phi0[0] != val[1]) {
848 s_AppendWarning(wbufp, "%s:%d: The DIHEDRAL %s-%s-%s-%s parameter appeared twice; the values (%f, %d, %f) are used\n", fname, lineNumber, AtomTypeDecodeToString(itype[0], type[0]), AtomTypeDecodeToString(itype[1], type[1]), AtomTypeDecodeToString(itype[2], type[2]), AtomTypeDecodeToString(itype[3], type[3]), val[0], ival[0], val[1]);
852 dp = AssignArray(&par->dihedralPars, &par->ndihedralPars, sizeof(*dp), par->ndihedralPars, NULL);
853 dp->type1 = itype[0];
854 dp->type2 = itype[1];
855 dp->type3 = itype[2];
856 dp->type4 = itype[3];
858 dp->period[0] = ival[0];
859 dp->phi0[0] = val[1];
861 s_StoreComment(kDihedralParType, (BondPar *)dp, buf + n, src);
862 } else if (strncmp(com, "improper", len) == 0) {
864 if (sscanf(buf, " %11s %4s %4s %4s %4s %f %d %f %n", com2, type[0], type[1], type[2], type[3], &val[0], &ival[0], &val[1], &n) < 8) {
865 s_AppendWarning(wbufp, "%s:%d: missing parameter in IMPROPER record\n", fname, lineNumber);
868 itype[0] = AtomTypeEncodeToUInt(type[0]);
869 itype[1] = AtomTypeEncodeToUInt(type[1]);
870 itype[2] = AtomTypeEncodeToUInt(type[2]);
871 itype[3] = AtomTypeEncodeToUInt(type[3]);
872 if (itype[0] > itype[1]) {
877 if (itype[0] > itype[3]) {
882 if (itype[1] > itype[3]) {
887 ip = ParameterLookupImproperPar(par, itype[0], itype[1], itype[2], itype[3], options);
888 val[0] *= KCAL2INTERNAL;
889 val[1] *= 3.14159265358979 / 180.0;
891 if (ip->mult != 1 || ip->k[0] != val[0] || ip->period[0] != ival[0] || ip->phi0[0] != val[1]) {
892 s_AppendWarning(wbufp, "%s:%d: The IMPROPER %s-%s-%s-%s parameter appeared twice; the values (%f, %d, %f) are used\n", fname, lineNumber, AtomTypeDecodeToString(itype[0], type[0]), AtomTypeDecodeToString(itype[1], type[1]), AtomTypeDecodeToString(itype[2], type[2]), AtomTypeDecodeToString(itype[3], type[3]), val[0], ival[0], val[1]);
896 ip = AssignArray(&par->improperPars, &par->nimproperPars, sizeof(*ip), par->nimproperPars, NULL);
897 ip->type1 = itype[0];
898 ip->type2 = itype[1];
899 ip->type3 = itype[2];
900 ip->type4 = itype[3];
902 ip->period[0] = ival[0];
903 ip->phi0[0] = val[1];
905 s_StoreComment(kImproperParType, (BondPar *)ip, buf + n, src);
906 } else if (strncmp(com, "nonbonded", len) == 0 || strncmp(com, "vdw", len) == 0) {
909 /* NOTE: the nonbonded record lists "2*sigma", not "sigma"! */
910 int flag = (com[0] == 'v');
911 if (sscanf(buf, " %11s %4s %f %f %f %f %n", com2, type[0], &val[0], &val[1], &val[2], &val[3], &n) < 6) {
912 s_AppendWarning(wbufp, "%s:%d: missing parameter in %s record\n", fname, lineNumber, (flag ? "VDW" : "NONBONDED"));
915 itype[0] = AtomTypeEncodeToUInt(type[0]);
916 memset(&vtemp, 0, sizeof(vtemp));
917 vtemp.type1 = itype[0];
918 vtemp.atomicNumber = 0; /* No definition given */
919 vtemp.eps = val[0] * KCAL2INTERNAL;
920 vtemp.r_eq = val[1] * (flag ? 1.0 : 0.561231024154687); /* 1/2 * 2**(1/6) */
921 vtemp.A = pow(vtemp.r_eq * 2, 12) * vtemp.eps;
922 vtemp.B = 2 * pow(vtemp.r_eq * 2, 6) * vtemp.eps;
923 vtemp.eps14 = val[2] * KCAL2INTERNAL;
924 vtemp.r_eq14 = val[3] * (flag ? 1.0 : 0.561231024154687); /* 1/2 * 2**(1/6) */
925 vtemp.A14 = pow(vtemp.r_eq14 * 2, 12) * vtemp.eps14;
926 vtemp.B14 = 2 * pow(vtemp.r_eq14 * 2, 6) * vtemp.eps14;
929 val[4] = val[5] = 0.0;
930 if (sscanf(p, "%d %n", &ival[0], &n) == 1) {
931 vtemp.atomicNumber = ival[0];
934 if (sscanf(p, "%f %n", &val[4], &n) == 1) {
935 vtemp.weight = val[4];
938 if (val[4] == 0.0 && ival[0] != 0)
939 vtemp.weight = WeightForAtomicNumber(ival[0]);
940 if (sscanf(p, "%f %n", &val[5], &n) == 1) {
941 vtemp.polarizability = val[5];
945 if (ival[0] == 0 && val[4] != 0.0) {
946 for (i = 1; (val[5] = WeightForAtomicNumber(i)) != 0.0; i++) {
947 if (fabs(val[4] - val[5]) < 0.1) {
948 vtemp.atomicNumber = i;
954 for (i = 0; i < par->nvdwPars; i++) {
955 if (itype[0] == par->vdwPars[i].type1) {
956 vp = par->vdwPars + i;
957 if (vp->A != vtemp.A || vp->B != vtemp.B || vp->A14 != vtemp.A14 || vp->B14 != vtemp.B14) {
958 s_AppendWarning(wbufp, "%s:%d: The %s %s parameter appeared twice; the values (%f, %f, %f, %f, %d, %f, %f) are used\n", fname, lineNumber, (flag ? "VDW" : "NONBONDED"), AtomTypeDecodeToString(itype[0], type[0]), val[0], val[1], val[2], val[3], ival[0], val[4], val[5]);
964 vp = AssignArray(&par->vdwPars, &par->nvdwPars, sizeof(*vp), i, NULL);
965 vtemp.com = vp->com; /* Keep comment field */
967 s_StoreComment(kVdwParType, (BondPar *)vp, buf + n, src);
968 } else if (strncmp(com, "nbfi", len) == 0 || strncmp(com, "vdwpair", len) == 0) {
969 VdwPairPar *vp, vtemp;
970 int flag = (com[0] == 'v');
971 if (sscanf(buf, " %11s %4s %4s %f %f %f %f %n", com2, type[0], type[1], &val[0], &val[1], &val[2], &val[3], &n) < 6) {
972 s_AppendWarning(wbufp, "%s:%d: missing parameter in %s record\n", fname, lineNumber, (flag ? "VDWP" : "NBFI"));
975 itype[0] = AtomTypeEncodeToUInt(type[0]);
976 itype[1] = AtomTypeEncodeToUInt(type[1]);
977 if (itype[0] > itype[1]) {
982 vtemp.type1 = itype[0];
983 vtemp.type2 = itype[1];
984 if (flag) { /* eps/r_eq representation */
985 vtemp.eps = val[0] * KCAL2INTERNAL;
987 vtemp.A = pow(val[1] * 2, 12) * vtemp.eps;
988 vtemp.B = 2 * pow(val[1] * 2, 6) * vtemp.eps;
989 vtemp.eps14 = val[2] * KCAL2INTERNAL;
990 vtemp.r_eq14 = val[3];
991 vtemp.A14 = pow(val[3] * 2, 12) * vtemp.eps14;
992 vtemp.B14 = 2 * pow(val[3] * 2, 6) * vtemp.eps14;
993 } else { /* A/B representation */
994 vtemp.A = val[0] * KCAL2INTERNAL;
995 vtemp.B = val[1] * KCAL2INTERNAL;
996 vtemp.eps = pow(0.25 * vtemp.B * vtemp.B / vtemp.A, 0.16666666667);
997 vtemp.r_eq = pow(vtemp.A / vtemp.B * 2.0, 0.16666666667) * 0.5;
998 vtemp.A14 = val[2] * KCAL2INTERNAL;
999 vtemp.B14 = val[3] * KCAL2INTERNAL;
1000 vtemp.eps14 = pow(0.25 * vtemp.B14 * vtemp.B14 / vtemp.A14, 0.16666666667);
1001 vtemp.r_eq14 = pow(vtemp.A14 / vtemp.B14 * 2.0, 0.16666666667) * 0.5;
1004 for (i = 0; i < par->nvdwpPars; i++) {
1005 if (itype[0] == par->vdwpPars[i].type1 && itype[1] == par->vdwpPars[i].type2) {
1006 vp = par->vdwpPars + i;
1007 if (vp->A != vtemp.A || vp->B != vtemp.B || vp->A14 != vtemp.A14 || vp->B14 != vtemp.B14) {
1008 s_AppendWarning(wbufp, "%s:%d: The %s %s-%s parameter appeared twice; the values (%f, %f, %f, %f) are used\n", fname, lineNumber, (flag ? "VDWP" : "NBFI"), AtomTypeDecodeToString(itype[0], type[0]), AtomTypeDecodeToString(itype[1], type[1]), val[0], val[1], val[2], val[3]);
1014 vp = AssignArray(&par->vdwpPars, &par->nvdwpPars, sizeof(*vp), i, NULL);
1015 vtemp.com = vp->com; /* Keep comment field */
1017 s_StoreComment(kVdwPairParType, (BondPar *)vp, buf + n, src);
1019 s_AppendWarning(wbufp, "%s:%d: unknown keyword %s\n", fname, lineNumber, com);
1026 ParameterReadFromFile(Parameter *par, const char *fname, char **outWarningMessage, int *outWarningCount)
1037 par = gBuiltinParameters;
1039 par = ParameterNew();
1040 gBuiltinParameters = par;
1048 fp = fopen(fname, "rb");
1050 s_AppendWarning(&wbuf, "Cannot open parameter file %s\n", fname);
1055 if (par != gBuiltinParameters || first)
1058 src_idx = ParameterCommentIndexForGlobalFileName(fname);
1060 if (par == gBuiltinParameters && !first) {
1061 /* Ensure the "source" field is unique */
1065 for (i = 0; i < gGlobalParInfo.count; i++) {
1066 if (gGlobalParInfo.files[i].src == src_idx)
1069 if (i < gGlobalParInfo.count) {
1070 /* Delete the existing Parameters from the same source */
1071 ParameterDeleteAllEntriesForSource(par, src_idx);
1074 /* Register the global file info */
1075 ip = AssignArray(&(gGlobalParInfo.files), &(gGlobalParInfo.count), sizeof(ParFileInfo), gGlobalParInfo.count, NULL);
1076 for (p = fname + strlen(fname) - 1; p >= fname; p--) {
1077 if (*p == '/' || *p == '\\')
1084 ip->dir = (char *)malloc(i + 1);
1085 if (ip->dir != NULL) {
1086 strncpy(ip->dir, fname, i);
1091 ip->name = strdup(p);
1096 while (ReadLine(buf, sizeof buf, fp, &lineNumber) > 0) {
1097 int wc1 = ParameterReadFromString(par, buf, &wbuf, fname, lineNumber, src_idx);
1106 gGlobalParInfo.builtinCount = gGlobalParInfo.count;
1111 if (outWarningMessage != NULL)
1112 *outWarningMessage = wbuf;
1113 else if (wbuf != NULL)
1115 if (outWarningCount != NULL)
1116 *outWarningCount = (wcount >= 0 ? wcount : 0);
1118 return (wcount >= 0 ? 0 : wcount);
1122 ParameterAppendToFile(Parameter *par, FILE *fp)
1127 int bufsize = sizeof(buf);
1133 if (par->nbondPars > 0)
1134 fprintf(fp, "! type1 type2 k r0\n");
1135 for (i = 0; i < par->nbondPars; i++) {
1136 BondPar *bp = par->bondPars + i;
1137 AtomTypeDecodeToString(bp->type1, cbuf[0]);
1138 AtomTypeDecodeToString(bp->type2, cbuf[1]);
1139 s_CommentToString(buf, bufsize, bp);
1140 fprintf(fp, "bond %s %s %.6f %f%s\n", cbuf[0], cbuf[1], bp->k * INTERNAL2KCAL, bp->r0, buf);
1143 if (par->nanglePars > 0)
1144 fprintf(fp, "! type1 type2 type3 k a0\n");
1145 for (i = 0; i < par->nanglePars; i++) {
1146 AnglePar *ap = par->anglePars + i;
1147 AtomTypeDecodeToString(ap->type1, cbuf[0]);
1148 AtomTypeDecodeToString(ap->type2, cbuf[1]);
1149 AtomTypeDecodeToString(ap->type3, cbuf[2]);
1150 s_CommentToString(buf, bufsize, ap);
1151 fprintf(fp, "angle %s %s %s %.6f %f%s\n", cbuf[0], cbuf[1], cbuf[2], ap->k * INTERNAL2KCAL, ap->a0 * kRad2Deg, buf);
1154 if (par->ndihedralPars > 0)
1155 fprintf(fp, "! type1 type2 type3 type4 k periodicity phi0\n");
1156 for (i = 0; i < par->ndihedralPars; i++) {
1157 TorsionPar *tp = par->dihedralPars + i;
1158 AtomTypeDecodeToString(tp->type1, cbuf[0]);
1159 AtomTypeDecodeToString(tp->type2, cbuf[1]);
1160 AtomTypeDecodeToString(tp->type3, cbuf[2]);
1161 AtomTypeDecodeToString(tp->type4, cbuf[3]);
1162 s_CommentToString(buf, bufsize, tp);
1163 fprintf(fp, "dihe %s %s %s %s %.6f %d %f%s\n", cbuf[0], cbuf[1], cbuf[2], cbuf[3], tp->k[0] * INTERNAL2KCAL, tp->period[0], tp->phi0[0] * kRad2Deg, buf);
1166 if (par->nimproperPars > 0)
1167 fprintf(fp, "! type1 type2 type3 type4 k periodicity phi0\n");
1168 for (i = 0; i < par->nimproperPars; i++) {
1169 TorsionPar *tp = par->improperPars + i;
1170 AtomTypeDecodeToString(tp->type1, cbuf[0]);
1171 AtomTypeDecodeToString(tp->type2, cbuf[1]);
1172 AtomTypeDecodeToString(tp->type3, cbuf[2]);
1173 AtomTypeDecodeToString(tp->type4, cbuf[3]);
1174 s_CommentToString(buf, bufsize, tp);
1175 fprintf(fp, "impr %s %s %s %s %.6f %d %f%s\n", cbuf[0], cbuf[1], cbuf[2], cbuf[3], tp->k[0] * INTERNAL2KCAL, tp->period[0], tp->phi0[0] * kRad2Deg, buf);
1178 if (par->nvdwPars > 0)
1179 fprintf(fp, "! type eps r_eq eps14 r_eq14 atomic_number weight\n");
1180 for (i = 0; i < par->nvdwPars; i++) {
1181 VdwPar *vp = par->vdwPars + i;
1182 /* Double eps, eps14; */
1183 AtomTypeDecodeToString(vp->type1, cbuf[0]);
1184 /* eps = (vp->A == 0.0 ? 0.0 : vp->B * vp->B / vp->A * 0.25 * INTERNAL2KCAL);
1185 eps14 = (vp->A14 == 0.0 ? 0.0 : vp->B14 * vp->B14 / vp->A14 * 0.25 * INTERNAL2KCAL); */
1186 s_CommentToString(buf, bufsize, vp);
1187 fprintf(fp, "vdw %s %.6f %.6f %.6f %.6f %d %f%s\n", cbuf[0], vp->eps * INTERNAL2KCAL, vp->r_eq, vp->eps14 * INTERNAL2KCAL, vp->r_eq14, vp->atomicNumber, vp->weight, buf); /* polarizability is not written because it is not used now */
1190 if (par->nvdwpPars > 0)
1191 fprintf(fp, "! type1 type2 eps r_eq eps14 r_eq14\n");
1192 for (i = 0; i < par->nvdwpPars; i++) {
1193 VdwPairPar *vpp = par->vdwpPars + i;
1194 /* Double eps, eps14; */
1195 AtomTypeDecodeToString(vpp->type1, cbuf[0]);
1196 AtomTypeDecodeToString(vpp->type2, cbuf[1]);
1197 /* eps = (vpp->A == 0.0 ? 0.0 : vpp->B * vpp->B / vpp->A * 0.25 * INTERNAL2KCAL);
1198 eps14 = (vpp->A14 == 0.0 ? 0.0 : vpp->B14 * vpp->B14 / vpp->A14 * 0.25 * INTERNAL2KCAL); */
1199 s_CommentToString(buf, bufsize, vpp);
1200 fprintf(fp, "vdwp %s %s %.6f %.6f %.6f %.6f%s\n", cbuf[0], cbuf[1], vpp->eps * INTERNAL2KCAL, vpp->r_eq, vpp->eps14 * INTERNAL2KCAL, vpp->r_eq14, buf);
1203 /* if (par->natomPars > 0)
1204 fprintf(fp, "! name atomic_number radius red green blue weight\n");
1205 for (i = 0; i < par->natomPars; i++) {
1206 ElementPar *app = par->atomPars + i;
1207 s_CommentToString(buf, bufsize, app);
1208 fprintf(fp, "element %.4s %d %f %f %f %f %f%s\n", app->name, app->number, app->radius, app->r, app->g, app->b, app->weight, buf);
1215 ParameterDeleteAllEntriesForSource(Parameter *par, int src_idx)
1220 /* if (fname == NULL)
1222 src_idx = ParameterCommentIndexForGlobalFileName(fname); */
1226 for (type = kFirstParType; type <= kLastParType; type++) {
1228 for (i = ParameterGetCountForType(par, type) - 1; i >= 0; i--) {
1229 up = ParameterGetUnionParFromTypeAndIndex(par, type, i);
1230 if (up != NULL && up->bond.src == src_idx)
1231 IntGroupAdd(ig, i, 1);
1233 i = IntGroupGetCount(ig);
1235 ParameterDelete(par, type, NULL, ig);
1238 IntGroupRelease(ig);
1240 if (par == gBuiltinParameters) {
1241 /* Unregister from the global info */
1242 for (i = gGlobalParInfo.builtinCount; i < gGlobalParInfo.count; i++) {
1243 if (gGlobalParInfo.files[i].src == src_idx) {
1244 DeleteArray(&gGlobalParInfo.files, &gGlobalParInfo.count, sizeof(ParFileInfo), i, 1, NULL);
1252 #pragma mark ====== Parameter Comments ======
1254 static const char **sParameterComments;
1255 static Int sNumberOfParameterComments;
1258 ParameterCommentIndex(const char *comment)
1262 if (comment == NULL || comment[0] == 0)
1264 /* Duplicate the comment, convert whitespaces to ' ', and chop trailing whitespaces */
1265 p = strdup(comment);
1267 for (pp = p + strlen(p) - 1; pp >= p; pp--) {
1274 for (i = 1; i < sNumberOfParameterComments; i++) {
1275 if (strcmp(sParameterComments[i], p) == 0) {
1280 if (sNumberOfParameterComments == 0) {
1281 /* Index 0 is skipped */
1282 AssignArray(&sParameterComments, &sNumberOfParameterComments, sizeof(char *), 1, &p);
1284 AssignArray(&sParameterComments, &sNumberOfParameterComments, sizeof(char *), sNumberOfParameterComments, &p);
1286 return sNumberOfParameterComments - 1;
1290 ParameterGetComment(int idx)
1292 if (idx <= 0 || idx >= sNumberOfParameterComments)
1293 return NULL; /* No such number */
1294 return sParameterComments[idx];
1297 #pragma mark ====== Parameter Lookup ======
1299 #define s_ParMatch(_t1, _t2, _nowildcard) (_t1 == _t2 || (!_nowildcard && _t1 == kAtomTypeWildcard))
1301 /* Returns non-zero if the parameter record contains designated atom_type.
1302 The atom_type can also be an atom index. */
1304 ParameterDoesContainAtom(Int type, UnionPar *up, UInt atom_type, Int options)
1306 #define CHECK_FIELD(_tp, _field) s_ParMatch((((_tp *)up)->_field), atom_type, nowildcard)
1307 Int nowildcard = (options & kParameterLookupNoWildcard);
1310 return CHECK_FIELD(BondPar, type1) || CHECK_FIELD(BondPar, type2);
1312 return CHECK_FIELD(AnglePar, type1) || CHECK_FIELD(AnglePar, type2) || CHECK_FIELD(AnglePar, type3);
1313 case kDihedralParType:
1314 case kImproperParType:
1315 return CHECK_FIELD(TorsionPar, type1) || CHECK_FIELD(TorsionPar, type2) || CHECK_FIELD(TorsionPar, type3) || CHECK_FIELD(TorsionPar, type4);
1317 return CHECK_FIELD(VdwPar, type1);
1318 case kVdwPairParType:
1319 return CHECK_FIELD(VdwPairPar, type1) || CHECK_FIELD(VdwPairPar, type2);
1320 case kVdwCutoffParType:
1321 if (((VdwCutoffPar *)up)->type == 1)
1322 return CHECK_FIELD(VdwCutoffPar, n1) || CHECK_FIELD(VdwCutoffPar, n2) || CHECK_FIELD(VdwCutoffPar, n3) || CHECK_FIELD(VdwCutoffPar, n4);
1329 ParameterLookupBondPar(Parameter *par, UInt t1, UInt t2, Int options)
1333 Int nowildcard = (options & kParameterLookupNoWildcard);
1336 if ((options & (kParameterLookupGlobal | kParameterLookupLocal | kParameterLookupMissing)) == 0)
1337 options |= kParameterLookupGlobal | kParameterLookupLocal;
1338 for (i = par->nbondPars - 1, bp = par->bondPars + i; i >= 0; i--, bp--) {
1339 if ((bp->src > 0 && !(options & kParameterLookupGlobal))
1340 || (bp->src == 0 && !(options & kParameterLookupLocal))
1341 || (bp->src < 0 && !(options & kParameterLookupMissing)))
1343 if (s_ParMatch(bp->type1, t1, nowildcard) && s_ParMatch(bp->type2, t2, nowildcard))
1345 if (s_ParMatch(bp->type1, t2, nowildcard) && s_ParMatch(bp->type2, t1, nowildcard))
1348 if (options & kParameterLookupNoBaseAtomType)
1350 return ParameterLookupBondPar(par, t1 % kAtomTypeVariantBase, t2 % kAtomTypeVariantBase, options | kParameterLookupNoBaseAtomType);
1354 ParameterLookupAnglePar(Parameter *par, UInt t1, UInt t2, UInt t3, Int options)
1358 Int nowildcard = (options & kParameterLookupNoWildcard);
1361 if ((options & (kParameterLookupGlobal | kParameterLookupLocal | kParameterLookupMissing)) == 0)
1362 options |= kParameterLookupGlobal | kParameterLookupLocal;
1363 for (i = par->nanglePars - 1, ap = par->anglePars + i; i >= 0; i--, ap--) {
1364 if ((ap->src > 0 && !(options & kParameterLookupGlobal))
1365 || (ap->src == 0 && !(options & kParameterLookupLocal))
1366 || (ap->src < 0 && !(options & kParameterLookupMissing)))
1368 if (s_ParMatch(ap->type1, t1, nowildcard) && s_ParMatch(ap->type2, t2, nowildcard) && s_ParMatch(ap->type3, t3, nowildcard))
1370 if (s_ParMatch(ap->type1, t3, nowildcard) && s_ParMatch(ap->type2, t2, nowildcard) && s_ParMatch(ap->type3, t1, nowildcard))
1373 if (options & kParameterLookupNoBaseAtomType)
1375 return ParameterLookupAnglePar(par, t1 % kAtomTypeVariantBase, t2 % kAtomTypeVariantBase, t3 % kAtomTypeVariantBase, options | kParameterLookupNoBaseAtomType);
1379 ParameterLookupDihedralPar(Parameter *par, UInt t1, UInt t2, UInt t3, UInt t4, Int options)
1383 Int nowildcard = (options & kParameterLookupNoWildcard);
1386 if ((options & (kParameterLookupGlobal | kParameterLookupLocal | kParameterLookupMissing)) == 0)
1387 options |= kParameterLookupGlobal | kParameterLookupLocal;
1388 for (i = par->ndihedralPars - 1, tp = par->dihedralPars + i; i >= 0; i--, tp--) {
1389 if ((tp->src > 0 && !(options & kParameterLookupGlobal))
1390 || (tp->src == 0 && !(options & kParameterLookupLocal))
1391 || (tp->src < 0 && !(options & kParameterLookupMissing)))
1393 if (s_ParMatch(tp->type1, t1, nowildcard) && s_ParMatch(tp->type2, t2, nowildcard) && s_ParMatch(tp->type3, t3, nowildcard) && s_ParMatch(tp->type4, t4, nowildcard))
1395 if (s_ParMatch(tp->type1, t4, nowildcard) && s_ParMatch(tp->type2, t3, nowildcard) && s_ParMatch(tp->type3, t2, nowildcard) && s_ParMatch(tp->type4, t1, nowildcard))
1398 if (options & kParameterLookupNoBaseAtomType)
1400 return ParameterLookupDihedralPar(par, t1 % kAtomTypeVariantBase, t2 % kAtomTypeVariantBase, t3 % kAtomTypeVariantBase, t4 % kAtomTypeVariantBase, options | kParameterLookupNoBaseAtomType);
1404 ParameterLookupImproperPar(Parameter *par, UInt t1, UInt t2, UInt t3, UInt t4, Int options)
1408 Int nowildcard = (options & kParameterLookupNoWildcard);
1411 if ((options & (kParameterLookupGlobal | kParameterLookupLocal | kParameterLookupMissing)) == 0)
1412 options |= kParameterLookupGlobal | kParameterLookupLocal;
1413 for (i = par->nimproperPars - 1, tp = par->improperPars + i; i >= 0; i--, tp--) {
1414 if ((tp->src > 0 && !(options & kParameterLookupGlobal))
1415 || (tp->src == 0 && !(options & kParameterLookupLocal))
1416 || (tp->src < 0 && !(options & kParameterLookupMissing)))
1418 if (!s_ParMatch(tp->type3, t3, nowildcard))
1420 if ((s_ParMatch(tp->type1, t1, nowildcard) && s_ParMatch(tp->type2, t2, nowildcard) && s_ParMatch(tp->type4, t4, nowildcard))
1421 || (s_ParMatch(tp->type1, t1, nowildcard) && s_ParMatch(tp->type2, t4, nowildcard) && s_ParMatch(tp->type4, t2, nowildcard))
1422 || (s_ParMatch(tp->type1, t2, nowildcard) && s_ParMatch(tp->type2, t1, nowildcard) && s_ParMatch(tp->type4, t4, nowildcard))
1423 || (s_ParMatch(tp->type1, t2, nowildcard) && s_ParMatch(tp->type2, t4, nowildcard) && s_ParMatch(tp->type4, t1, nowildcard))
1424 || (s_ParMatch(tp->type1, t4, nowildcard) && s_ParMatch(tp->type2, t1, nowildcard) && s_ParMatch(tp->type4, t2, nowildcard))
1425 || (s_ParMatch(tp->type1, t4, nowildcard) && s_ParMatch(tp->type2, t2, nowildcard) && s_ParMatch(tp->type4, t1, nowildcard)))
1428 if (options & kParameterLookupNoBaseAtomType)
1430 return ParameterLookupImproperPar(par, t1 % kAtomTypeVariantBase, t2 % kAtomTypeVariantBase, t3 % kAtomTypeVariantBase, t4 % kAtomTypeVariantBase, options | kParameterLookupNoBaseAtomType);
1434 ParameterLookupVdwPar(Parameter *par, UInt t1, Int options)
1438 Int nowildcard = (options & kParameterLookupNoWildcard);
1441 if ((options & (kParameterLookupGlobal | kParameterLookupLocal | kParameterLookupMissing)) == 0)
1442 options |= kParameterLookupGlobal | kParameterLookupLocal;
1443 for (i = par->nvdwPars - 1, vp = par->vdwPars + i; i >= 0; i--, vp--) {
1444 if ((vp->src > 0 && !(options & kParameterLookupGlobal))
1445 || (vp->src == 0 && !(options & kParameterLookupLocal))
1446 || (vp->src < 0 && !(options & kParameterLookupMissing)))
1448 if (s_ParMatch(vp->type1, t1, nowildcard))
1451 if (options & kParameterLookupNoBaseAtomType)
1453 return ParameterLookupVdwPar(par, t1 % kAtomTypeVariantBase, options | kParameterLookupNoBaseAtomType);
1457 ParameterLookupVdwPairPar(Parameter *par, UInt t1, UInt t2, Int options)
1461 Int nowildcard = (options & kParameterLookupNoWildcard);
1464 if ((options & (kParameterLookupGlobal | kParameterLookupLocal | kParameterLookupMissing)) == 0)
1465 options |= kParameterLookupGlobal | kParameterLookupLocal;
1466 for (i = par->nvdwpPars - 1, vp = par->vdwpPars + i; i >= 0; i--, vp--) {
1467 if ((vp->src > 0 && !(options & kParameterLookupGlobal))
1468 || (vp->src == 0 && !(options & kParameterLookupLocal))
1469 || (vp->src < 0 && !(options & kParameterLookupMissing)))
1471 if ((s_ParMatch(vp->type1, t1, nowildcard) && s_ParMatch(vp->type2, t2, nowildcard))
1472 || (s_ParMatch(vp->type1, t2, nowildcard) && s_ParMatch(vp->type2, t1, nowildcard)))
1475 if (options & kParameterLookupNoBaseAtomType)
1477 return ParameterLookupVdwPairPar(par, t1 % kAtomTypeVariantBase, t2 % kAtomTypeVariantBase, options | kParameterLookupNoBaseAtomType);
1481 ParameterLookupVdwCutoffPar(Parameter *par, UInt t1, UInt t2, Int options)
1485 Int nowildcard = (options & kParameterLookupNoWildcard);
1488 if ((options & (kParameterLookupGlobal | kParameterLookupLocal | kParameterLookupMissing)) == 0)
1489 options |= kParameterLookupGlobal | kParameterLookupLocal;
1490 for (i = par->nvdwCutoffPars - 1, vp = par->vdwCutoffPars + i; i >= 0; i--, vp--) {
1491 if ((vp->src > 0 && !(options & kParameterLookupGlobal))
1492 || (vp->src == 0 && !(options & kParameterLookupLocal))
1493 || (vp->src < 0 && !(options & kParameterLookupMissing)))
1495 if (vp->type == 0) {
1496 if (s_ParMatch(vp->n1, t1, nowildcard) && s_ParMatch(vp->n2, t2, nowildcard))
1498 if (s_ParMatch(vp->n1, t2, nowildcard) && s_ParMatch(vp->n2, t1, nowildcard))
1501 if (vp->n1 <= t1 && vp->n2 >= t1 && vp->n3 <= t2 && vp->n4 <= t2)
1503 if (vp->n1 <= t2 && vp->n2 >= t2 && vp->n3 <= t1 && vp->n4 >= t1)
1507 if (options & kParameterLookupNoBaseAtomType)
1509 return ParameterLookupVdwCutoffPar(par, t1 % kAtomTypeVariantBase, t2 % kAtomTypeVariantBase, options | kParameterLookupNoBaseAtomType);
1512 #pragma mark ====== Table View Support ======
1515 ParameterTableNumberOfRows(Parameter *par)
1519 return par->nvdwPars + par->nbondPars + par->nanglePars + par->ndihedralPars + par->nimproperPars + par->nvdwpPars + 6;
1523 ParameterTableGetItemIndex(Parameter *par, int row, int *type)
1525 if (par == NULL || row < 0) {
1526 *type = kInvalidParType;
1529 if (--row < par->nvdwPars) {
1530 *type = kVdwParType;
1531 } else if ((row -= par->nvdwPars + 1) < par->nbondPars) {
1532 *type = kBondParType;
1533 } else if ((row -= par->nbondPars + 1) < par->nanglePars) {
1534 *type = kAngleParType;
1535 } else if ((row -= par->nanglePars + 1) < par->ndihedralPars) {
1536 *type = kDihedralParType;
1537 } else if ((row -= par->ndihedralPars + 1) < par->nimproperPars) {
1538 *type = kImproperParType;
1539 } else if ((row -= par->nimproperPars + 1) < par->nvdwpPars) {
1540 *type = kVdwPairParType;
1542 *type = kInvalidParType;
1549 ParameterTableGetRowFromTypeAndIndex(Parameter *par, int type, int idx)
1553 return -1; /* Invalid */
1554 if (type == kVdwParType)
1555 return (idx < par->nvdwPars ? idx + ofs : -1);
1556 ofs += par->nvdwPars + 1;
1557 if (type == kBondParType)
1558 return (idx < par->nbondPars ? idx + ofs : -1);
1559 ofs += par->nbondPars + 1;
1560 if (type == kAngleParType)
1561 return (idx < par->nanglePars ? idx + ofs : -1);
1562 ofs += par->nanglePars + 1;
1563 if (type == kDihedralParType)
1564 return (idx < par->ndihedralPars ? idx + ofs : -1);
1565 ofs += par->ndihedralPars + 1;
1566 if (type == kImproperParType)
1567 return (idx < par->nimproperPars ? idx + ofs : -1);
1568 ofs += par->nimproperPars + 1;
1569 if (type == kVdwPairParType)
1570 return (idx < par->nvdwpPars ? idx + ofs : -1);
1575 ParameterTableGetItemPtr(Parameter *par, int row, int *type)
1577 if (par == NULL || row < 0) {
1578 *type = kInvalidParType;
1581 if (--row < par->nvdwPars) {
1582 *type = kVdwParType;
1583 return (UnionPar *)(row >= 0 ? par->vdwPars + row : NULL);
1584 } else if ((row -= par->nvdwPars + 1) < par->nbondPars) {
1585 *type = kBondParType;
1586 return (UnionPar *)(row >= 0 ? par->bondPars + row : NULL);
1587 } else if ((row -= par->nbondPars + 1) < par->nanglePars) {
1588 *type = kAngleParType;
1589 return (UnionPar *)(row >= 0 ? par->anglePars + row : NULL);
1590 } else if ((row -= par->nanglePars + 1) < par->ndihedralPars) {
1591 *type = kDihedralParType;
1592 return (UnionPar *)(row >= 0 ? par->dihedralPars + row : NULL);
1593 } else if ((row -= par->ndihedralPars + 1) < par->nimproperPars) {
1594 *type = kImproperParType;
1595 return (UnionPar *)(row >= 0 ? par->improperPars + row : NULL);
1596 } else if ((row -= par->nimproperPars + 1) < par->nvdwpPars) {
1597 *type = kVdwPairParType;
1598 return (UnionPar *)(row >= 0 ? par->vdwpPars + row : NULL);
1599 /* } else if ((row -= par->nvdwpPars + 1) < par->natomPars) {
1600 *type = kElementParType;
1601 return (UnionPar *)(row >= 0 ? par->atomPars + row : NULL); */
1603 *type = kInvalidParType;
1609 ParameterTableGetItemText(Parameter *par, int column, int row, char *buf, int bufsize)
1611 static char *sBondParTitles[] = {"", "Bonds", "k", "r0"};
1612 static char *sAngleParTitles[] = {"", "Angles", "k", "a0"};
1613 static char *sDihedralParTitles[] = {"", "Dihedrals", "k", "period", "phi0"};
1614 static char *sImproperParTitles[] = {"", "Impropers", "k", "period", "phi0"};
1615 static char *sVdwParTitles[] = {"", "VDWs", "eps", "r", "eps14", "r14", "atomNo", "weight"};
1616 static char *sVdwPairParTitles[] = {"", "VDW Pairs", "eps", "r", "eps14", "r14"};
1617 /* static char *sAtomParTitles[] = {"", "Atom Display", "atomNo", "radius", "red", "green", "blue", "weight"}; */
1620 UnionPar *up = NULL;
1623 if (par == NULL || row < 0)
1625 up = ParameterTableGetItemPtr(par, row, &type);
1628 VdwPar *vp = (VdwPar *)up;
1630 if (column >= 0 && column < 8)
1631 snprintf(buf, bufsize, "%s", sVdwParTitles[column]);
1635 case 0: snprintf(buf, bufsize, "vdw"); break;
1637 AtomTypeDecodeToString(vp->type1, types[0]);
1638 snprintf(buf, bufsize, "%s", types[0]);
1641 snprintf(buf, bufsize, "%.5f", vp->eps * INTERNAL2KCAL);
1644 snprintf(buf, bufsize, "%.5f", vp->r_eq);
1647 snprintf(buf, bufsize, "%.5f", vp->eps14 * INTERNAL2KCAL);
1650 snprintf(buf, bufsize, "%.5f", vp->r_eq14);
1653 snprintf(buf, bufsize, "%d", vp->atomicNumber);
1656 snprintf(buf, bufsize, "%.3f", vp->weight);
1661 case kBondParType: {
1662 BondPar *bp = (BondPar *)up;
1664 if (column >= 0 && column < 4)
1665 snprintf(buf, bufsize, "%s", sBondParTitles[column]);
1669 case 0: snprintf(buf, bufsize, "bond"); break;
1671 AtomTypeDecodeToString(bp->type1, types[0]);
1672 AtomTypeDecodeToString(bp->type2, types[1]);
1673 snprintf(buf, bufsize, "%s-%s", types[0], types[1]);
1677 snprintf(buf, bufsize, "%.3f", (column == 2 ? bp->k * INTERNAL2KCAL : bp->r0));
1682 case kAngleParType: {
1683 AnglePar *ap = (AnglePar *)up;
1685 if (column >= 0 && column < 4)
1686 snprintf(buf, bufsize, "%s", sAngleParTitles[column]);
1690 case 0: snprintf(buf, bufsize, "angle"); break;
1692 AtomTypeDecodeToString(ap->type1, types[0]);
1693 AtomTypeDecodeToString(ap->type2, types[1]);
1694 AtomTypeDecodeToString(ap->type3, types[2]);
1695 snprintf(buf, bufsize, "%s-%s-%s", types[0], types[1], types[2]);
1699 snprintf(buf, bufsize, "%.3f", (column == 2 ? ap->k * INTERNAL2KCAL : ap->a0 * kRad2Deg));
1704 case kDihedralParType: {
1705 TorsionPar *tp = (TorsionPar *)up;
1707 if (column >= 0 && column < 5)
1708 snprintf(buf, bufsize, "%s", sDihedralParTitles[column]);
1712 case 0: snprintf(buf, bufsize, "dihe"); break;
1714 AtomTypeDecodeToString(tp->type1, types[0]);
1715 AtomTypeDecodeToString(tp->type2, types[1]);
1716 AtomTypeDecodeToString(tp->type3, types[2]);
1717 AtomTypeDecodeToString(tp->type4, types[3]);
1718 snprintf(buf, bufsize, "%s-%s-%s-%s", types[0], types[1], types[2], types[3]);
1721 snprintf(buf, bufsize, "%d", tp->period[0]);
1725 snprintf(buf, bufsize, "%.3f", (column == 2 ? tp->k[0] * INTERNAL2KCAL : tp->phi0[0] * kRad2Deg));
1730 case kImproperParType: {
1731 TorsionPar *tp = (TorsionPar *)up;
1733 if (column >= 0 && column < 5)
1734 snprintf(buf, bufsize, "%s", sImproperParTitles[column]);
1738 case 0: snprintf(buf, bufsize, "impr"); break;
1740 AtomTypeDecodeToString(tp->type1, types[0]);
1741 AtomTypeDecodeToString(tp->type2, types[1]);
1742 AtomTypeDecodeToString(tp->type3, types[2]);
1743 AtomTypeDecodeToString(tp->type4, types[3]);
1744 snprintf(buf, bufsize, "%s-%s-%s-%s", types[0], types[1], types[2], types[3]);
1747 snprintf(buf, bufsize, "%d", tp->period[0]);
1751 snprintf(buf, bufsize, "%.3f", (column == 2 ? tp->k[0] * INTERNAL2KCAL : tp->phi0[0] * kRad2Deg));
1756 case kVdwPairParType: {
1757 VdwPairPar *vp = (VdwPairPar *)up;
1759 if (column >= 0 && column < 6)
1760 snprintf(buf, bufsize, "%s", sVdwPairParTitles[column]);
1764 case 0: snprintf(buf, bufsize, "pvdw"); break;
1766 AtomTypeDecodeToString(vp->type1, types[0]);
1767 AtomTypeDecodeToString(vp->type2, types[1]);
1768 snprintf(buf, bufsize, "%s-%s", types[0], types[1]);
1771 snprintf(buf, bufsize, "%.6f", vp->eps * INTERNAL2KCAL);
1774 snprintf(buf, bufsize, "%.6f", vp->r_eq);
1777 snprintf(buf, bufsize, "%.6f", (vp->A14 == 0.0 ? 0.0 : vp->B14 * vp->B14 / vp->A14 * 0.25 * INTERNAL2KCAL));
1780 snprintf(buf, bufsize, "%.6f", vp->eps14 * INTERNAL2KCAL);
1785 /* case kElementParType: {
1786 ElementPar *ap = (ElementPar *)up;
1788 if (column >= 0 && column < 8)
1789 snprintf(buf, bufsize, "%s", sAtomParTitles[column]);
1793 case 0: snprintf(buf, bufsize, "disp"); break;
1794 case 1: snprintf(buf, bufsize, "%.4s", ap->name); break;
1795 case 2: snprintf(buf, bufsize, "%d", ap->number); break;
1796 case 3: snprintf(buf, bufsize, "%.2f", ap->radius); break;
1797 case 4: snprintf(buf, bufsize, "%.3f", ap->r); break;
1798 case 5: snprintf(buf, bufsize, "%.3f", ap->g); break;
1799 case 6: snprintf(buf, bufsize, "%.3f", ap->b); break;
1800 case 7: snprintf(buf, bufsize, "%.3f", ap->weight); break;
1806 if (up != NULL && (column == 8 || column == 9)) {
1807 if (column == 8 && ((BondPar *)up)->src == -1)
1808 snprintf(buf, bufsize, "!NONE!");
1809 else if ((p = ParameterGetComment(column == 8 ? ((BondPar *)up)->src : ((BondPar *)up)->com)) != NULL)
1810 snprintf(buf, bufsize, "%s", p);
1817 -1: missing parameter
1818 0: molecule-local parameter
1819 1 and larger: global parameter values (gGlobalParInfo index + 1) */
1821 ParameterTableGetItemSource(Parameter *par, int row)
1825 if (par == NULL || row < 0)
1827 up = ParameterTableGetItemPtr(par, row, &type);
1828 src = (type == kInvalidParType ? -3 : (up == NULL ? -2 : ((BondPar *)up)->src));
1829 if (type == kInvalidParType)
1831 else if (up == NULL)
1833 else src = ((BondPar *)up)->src;
1835 /* Search src in gGlobalParInfo */
1837 for (i = 0; i < gGlobalParInfo.count; i++) {
1838 if (gGlobalParInfo.files[i].src == src)
1841 return -3; /* Must not happen */
1847 ParameterTableIsItemEditable(Parameter *par, int column, int row)
1851 if (par == NULL || row < 0)
1853 up = ParameterTableGetItemPtr(par, row, &type);
1854 if (type != kInvalidParType && up != NULL) {
1855 /* Valid type, not separator row, molecule-local value */
1856 int src = ((BondPar *)up)->src;
1857 f = (src == 0 || src == -1);
1860 case kVdwParType: return (f && column > 0 && column < 8);
1861 case kBondParType: return (f && column > 0 && column < 4);
1862 case kAngleParType: return (f && column > 0 && column < 4);
1863 case kDihedralParType: return (f && column > 0 && column < 5);
1864 case kImproperParType: return (f && column > 0 && column < 5);
1865 case kVdwPairParType: return (f && column > 0 && column < 5);
1866 /* case kElementParType: return (f && column > 0 && column < 7); */
1871 #pragma mark ====== Utility Functions ======
1874 ElementParameterInitialize(const char *fname, char **outWarningMessage)
1876 char buf[1024], name[6], fullname[16];
1879 int i, lineNumber, retval = 0;
1882 fp = fopen(fname, "rb");
1888 while (ReadLine(buf, sizeof buf, fp, &lineNumber) > 0) {
1890 if (strncmp(buf, "element ", 8) != 0)
1891 continue; /* Skip non-relevant lines */
1893 if (sscanf(buf + 8, " %4s %f %f %f %f %f %f %15s", name, &val[0], &val[1], &val[2], &val[3], &val[4], &val[5], fullname) < 7) {
1894 asprintf(&wbuf, "%s:%d: missing parameter in ELEMENT record", fname, lineNumber);
1899 if (i < 0 || i >= 200) {
1900 asprintf(&wbuf, "%s:%d: The atomic number (%d) in ELEMENT record is out of range", fname, lineNumber, i);
1904 ep = AssignArray(&gElementParameters, &gCountElementParameters, sizeof(ElementPar), i, NULL);
1905 memmove(ep->name, name, 4);
1907 ep->radius = val[1];
1911 ep->weight = val[5];
1913 memmove(ep->fullname, fullname, 16);
1918 if (outWarningMessage != NULL)
1919 *outWarningMessage = wbuf;
1924 AtomTypeEncodeToUInt(const char *s)
1928 if ((s[0] == 'x' || s[0] == 'X') && s[1] == 0)
1929 return kAtomTypeWildcard;
1930 if (s[0] >= '0' && s[0] <= '9')
1932 for (i = t = 0; i < 4; i++, s++) {
1933 /* Encode: variant*96*96*96*96 + a[0]*96*96*96 + a[1]*96*96 + a[2] * 96 + a[3] */
1934 static const UInt s_coeff[4] = {96*96*96, 96*96, 96, 1};
1939 if (*s == ',' || *s == '.' || *s == ';' || *s == ':') {
1940 /* Variant (only [0-9a-z] are allowed) */
1942 if (*s >= '0' && *s <= '9')
1944 else if (*s >= 'A' && *s <= 'Z')
1946 else if (*s >= 'a' && *s <= 'z')
1948 else n = (*s % 36) + 1; /* Map to something non-zero */
1949 t += n * (96*96*96*96);
1952 n = (*s - 0x20) % 96; /* Map to 1..95 */
1953 if (i == 0 && n < 32)
1955 t += n * s_coeff[i];
1961 AtomTypeDecodeToString(UInt type, char *s)
1963 static const UInt s_coeff[4] = {96*96*96, 96*96, 96, 1};
1971 if (type == kAtomTypeWildcard) {
1976 if (type < kAtomTypeMinimum) {
1977 snprintf(s, 6, "%d", type);
1980 for (i = 0; i < 4; i++) {
1981 s[i] = (type / s_coeff[i]) % 96;
1987 if ((variant = (type / (96*96*96*96)) % 96) != 0) {
1989 s[n + 1] = (variant <= 10 ? '0' + variant - 1 : 'a' + variant - 11);
1996 ElementToInt(const char *s)
2000 for (i = 0, p = gElementParameters; i < gCountElementParameters; i++, p++) {
2001 if (p->name[0] == toupper(s[0]) && p->name[1] == tolower(s[1]))
2008 ElementToString(Int elem, char *s)
2010 if (elem >= 0 && elem < gCountElementParameters) {
2011 const char *cs = gElementParameters[elem].name;
2020 AtomNameToElement(const char *s)
2024 /* $element = ($name =~ /([A-Za-z]{1,2})/); # in Perl */
2026 for (p = s; *p != 0; p++) {
2027 if (isalpha(*p) && *p != '_') {
2028 element[0] = toupper(*p);
2029 if (isalpha(p[1]) && p[1] != '_') {
2030 element[1] = toupper(p[1]);
2038 return ElementToInt(element);
2042 GuessAtomicNumber(const char *name, Double weight)
2048 for (i = 0, p = gElementParameters; i < gCountElementParameters; i++, p++) {
2049 if (p->weight > 0.0 && fabs(weight - p->weight) < 0.1)
2053 for (cp = name; *cp != 0 && cp < name + 4; cp++) {
2054 if (isalpha(*cp) && *cp != '_') {
2055 buf[0] = toupper(*cp);
2056 if (isalpha(cp[1]) && cp[1] != '_') {
2057 buf[1] = toupper(cp[1]);
2065 return ElementToInt(buf);
2069 WeightForAtomicNumber(Int elem)
2071 if (elem >= 1 && elem < gCountElementParameters)
2072 return gElementParameters[elem].weight;
2077 RadiusForAtomicNumber(Int elem)
2079 if (elem >= 1 && elem < gCountElementParameters)
2080 return gElementParameters[elem].radius;