4 * This source code is part of
8 * GROningen MAchine for Chemical Simulations
11 * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
12 * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
13 * Copyright (c) 2001-2004, The GROMACS development team,
14 * check out http://www.gromacs.org for more information.
16 * This program is free software; you can redistribute it and/or
17 * modify it under the terms of the GNU General Public License
18 * as published by the Free Software Foundation; either version 2
19 * of the License, or (at your option) any later version.
21 * If you want to redistribute modifications, please consider that
22 * scientific software is very special. Version control is crucial -
23 * bugs must be traceable. We will be happy to consider code for
24 * inclusion in the official distribution, but derived work must not
25 * be called official GROMACS. Details are found in the README & COPYING
26 * files - if they are missing, get the official version at www.gromacs.org.
28 * To help us fund GROMACS development, we humbly ask that you cite
29 * the papers on the package - you can find them in the top README file.
31 * For more info, check our website at http://www.gromacs.org
34 * Gallium Rubidium Oxygen Manganese Argon Carbon Silicon
58 static void copy_atom(t_atoms
*atoms1
,int a1
,t_atoms
*atoms2
,int a2
)
60 atoms2
->atom
[a2
] = atoms1
->atom
[a1
];
61 snew(atoms2
->atomname
[a2
],1);
62 *atoms2
->atomname
[a2
]=strdup(*atoms1
->atomname
[a1
]);
65 atom_id
pdbasearch_atom(char *name
,int resnr
,t_atoms
*pdba
)
69 for(i
=0; (i
<pdba
->nr
) && (pdba
->atom
[i
].resnr
!= resnr
); i
++)
72 return search_atom(name
,i
,pdba
->nr
,pdba
->atom
,pdba
->atomname
);
75 void hacksearch_atom(int *ii
, int *jj
, char *name
, int nab
[], t_hack
*ab
[],
76 int resnr
, t_atoms
*pdba
)
85 for(i
=0; (i
<pdba
->nr
) && (pdba
->atom
[i
].resnr
!= resnr
); i
++)
87 for( ; (i
<pdba
->nr
) && (pdba
->atom
[i
].resnr
== resnr
) && (*ii
<0); i
++)
88 for(j
=0; (j
< nab
[i
]) && (*ii
<0); j
++)
89 if (ab
[i
][j
].nname
&& strcmp(name
,ab
[i
][j
].nname
) == 0) {
97 void dump_ab(FILE *out
,int natom
,int nab
[], t_hack
*ab
[], bool bHeader
)
101 #define SS(s) (s)?(s):"-"
104 fprintf(out
,"ADDBLOCK (t_hack) natom=%d\n"
105 "%4s %2s %-4s %-4s %2s %-4s %-4s %-4s %-4s %1s %s\n",
106 natom
,"atom","nr","old","new","tp","ai","aj","ak","al","a","x");
107 for(i
=0; i
<natom
; i
++)
108 for(j
=0; j
<nab
[i
]; j
++)
109 fprintf(out
,"%4d %2d %-4s %-4s %2d %-4s %-4s %-4s %-4s %s %g %g %g\n",
110 i
+1, ab
[i
][j
].nr
, SS(ab
[i
][j
].oname
), SS(ab
[i
][j
].nname
),
112 SS(ab
[i
][j
].AI
), SS(ab
[i
][j
].AJ
),
113 SS(ab
[i
][j
].AK
), SS(ab
[i
][j
].AL
),
114 ab
[i
][j
].atom
?"+":"",
115 ab
[i
][j
].newx
[XX
], ab
[i
][j
].newx
[YY
], ab
[i
][j
].newx
[ZZ
]);
119 static t_hackblock
*get_hackblocks(t_atoms
*pdba
, int nah
, t_hackblock ah
[],
121 t_hackblock
**ntdb
, t_hackblock
**ctdb
,
125 t_hackblock
*hb
,*ahptr
;
129 /* first the termini */
130 for(i
=0; i
<nterpairs
; i
++) {
131 copy_t_hackblock(ntdb
[i
], &hb
[rN
[i
]]);
132 merge_t_hackblock(ctdb
[i
], &hb
[rC
[i
]]);
134 /* then the whole hdb */
135 for(rnr
=0; rnr
< pdba
->nres
; rnr
++) {
136 ahptr
=search_h_db(nah
,ah
,*pdba
->resname
[rnr
]);
138 if (hb
[rnr
].name
==NULL
)
139 hb
[rnr
].name
=strdup(ahptr
->name
);
140 merge_hacks(ahptr
, &hb
[rnr
]);
146 static const char Hnum
[] = "123456";
148 static void expand_hackblocks_one(t_hackblock
*hbr
, char *atomname
,
149 int *nabi
, t_hack
**abi
, bool bN
, bool bC
)
154 /* we'll recursively add atoms to atoms */
155 for(j
=0; j
< hbr
->nhack
; j
++) {
156 /* first check if we're in the N- or C-terminus, then we should ignore
157 all hacks involving atoms from resp. previous or next residue
158 (i.e. which name begins with '-' (N) or '+' (C) */
160 if ( bN
) /* N-terminus: ignore '-' */
161 for(k
=0; k
<4 && hbr
->hack
[j
].a
[k
] && !bIgnore
; k
++)
162 bIgnore
= hbr
->hack
[j
].a
[k
][0]=='-';
163 if ( bC
) /* C-terminus: ignore '+' */
164 for(k
=0; k
<4 && hbr
->hack
[j
].a
[k
] && !bIgnore
; k
++)
165 bIgnore
= hbr
->hack
[j
].a
[k
][0]=='+';
166 /* must be either hdb entry (tp>0) or add from tdb (oname==NULL)
167 and first control aton (AI) matches this atom or
168 delete/replace from tdb (oname!=NULL) and oname matches this atom */
169 if (debug
) fprintf(debug
," %s",
170 hbr
->hack
[j
].oname
?hbr
->hack
[j
].oname
:hbr
->hack
[j
].AI
);
172 ( ( ( hbr
->hack
[j
].tp
> 0 || hbr
->hack
[j
].oname
==NULL
) &&
173 strcmp(atomname
, hbr
->hack
[j
].AI
) == 0 ) ||
174 ( hbr
->hack
[j
].oname
!=NULL
&&
175 strcmp(atomname
, hbr
->hack
[j
].oname
) == 0) ) ) {
176 /* now expand all hacks for this atom */
177 if (debug
) fprintf(debug
," +%dh",hbr
->hack
[j
].nr
);
178 srenew(*abi
,*nabi
+ hbr
->hack
[j
].nr
);
179 for(k
=0; k
< hbr
->hack
[j
].nr
; k
++) {
180 copy_t_hack(&hbr
->hack
[j
], &(*abi
)[*nabi
+ k
]);
182 (*abi
)[*nabi
+ k
].newx
[d
]=NOTSET
;
183 /* if we're adding (oname==NULL) and don't have a new name (nname)
184 yet, build it from atomname */
185 if ( (*abi
)[*nabi
+ k
].nname
==NULL
) {
186 if ( (*abi
)[*nabi
+ k
].oname
==NULL
) {
187 (*abi
)[*nabi
+ k
].nname
=strdup(atomname
);
188 (*abi
)[*nabi
+ k
].nname
[0]='H';
191 sfree((*abi
)[*nabi
+ k
].nname
);
192 (*abi
)[*nabi
+ k
].nname
=strdup(hbr
->hack
[j
].nname
);
194 /* if adding more than one atom, number them */
195 if ( hbr
->hack
[j
].nr
> 1 ) {
196 l
= strlen((*abi
)[*nabi
+ k
].nname
);
197 srenew((*abi
)[*nabi
+ k
].nname
, l
+2);
198 (*abi
)[*nabi
+ k
].nname
[l
] = Hnum
[k
]; /* 1, 2, 3 .... */
199 (*abi
)[*nabi
+ k
].nname
[l
+1] = '\0';
202 (*nabi
) += hbr
->hack
[j
].nr
;
204 /* add hacks to atoms we've just added */
205 if ( hbr
->hack
[j
].tp
> 0 || hbr
->hack
[j
].oname
==NULL
)
206 for(k
=0; k
< hbr
->hack
[j
].nr
; k
++)
207 expand_hackblocks_one(hbr
, (*abi
)[*nabi
-hbr
->hack
[j
].nr
+k
].nname
,
213 static void expand_hackblocks(t_atoms
*pdba
, t_hackblock hb
[],
214 int nab
[], t_hack
*ab
[],
215 int nterpairs
, int *rN
, int *rC
)
220 for(i
=0; i
< pdba
->nr
; i
++) {
222 for(j
=0; j
<nterpairs
&& !bN
; j
++)
223 bN
= pdba
->atom
[i
].resnr
==rN
[j
];
225 for(j
=0; j
<nterpairs
&& !bC
; j
++)
226 bC
= pdba
->atom
[i
].resnr
==rC
[j
];
228 /* add hacks to this atom */
229 expand_hackblocks_one(&hb
[pdba
->atom
[i
].resnr
], *pdba
->atomname
[i
],
230 &nab
[i
], &ab
[i
], bN
, bC
);
232 if (debug
) fprintf(debug
,"\n");
235 static int check_atoms_present(t_atoms
*pdba
, int nab
[], t_hack
*ab
[])
237 int i
, j
, k
, d
, rnr
, nadd
;
240 for(i
=0; i
< pdba
->nr
; i
++) {
241 rnr
= pdba
->atom
[i
].resnr
;
242 for(j
=0; j
<nab
[i
]; j
++)
243 if ( ab
[i
][j
].oname
==NULL
) {
245 assert(ab
[i
][j
].nname
!=NULL
);
246 /* check if the atom is already present */
247 k
=pdbasearch_atom(ab
[i
][j
].nname
, rnr
, pdba
);
249 /* we found the added atom, so move the hack there: */
250 srenew(ab
[k
], nab
[k
]+1);
251 ab
[k
][nab
[k
]] = ab
[i
][j
];
252 ab
[k
][nab
[k
]].oname
= strdup(ab
[k
][nab
[k
]].nname
);
253 /* reset any possible new coordinates: */
255 ab
[k
][nab
[k
]].newx
[d
]=NOTSET
;
258 /* remove the hack from this atom: */
259 for(k
=j
+1; k
<nab
[i
]; k
++)
260 ab
[i
][k
-1] = ab
[i
][k
];
264 srenew(ab
[i
], nab
[i
]);
266 /* count how many atoms we'll add */
268 } else if ( ab
[i
][j
].nname
==NULL
)
276 static void calc_all_pos(t_atoms
*pdba
, rvec x
[], int nab
[], t_hack
*ab
[])
278 int i
, j
, ii
, jj
, m
, ia
, d
, rnr
;
279 rvec xa
[4]; /* control atoms for calc_h_pos */
280 rvec xh
[3]; /* hydrogen positions from calc_h_pos */
282 for(i
=0; i
< pdba
->nr
; i
++) {
283 rnr
= pdba
->atom
[i
].resnr
;
284 for(j
=0; j
< nab
[i
]; j
+=ab
[i
][j
].nr
) {
285 /* check if we're adding: */
286 if (ab
[i
][j
].oname
==NULL
&& ab
[i
][j
].tp
> 0) {
287 for(m
=0; m
<ncontrol
[ab
[i
][j
].tp
]; m
++) {
288 ia
= pdbasearch_atom(ab
[i
][j
].a
[m
], rnr
, pdba
);
290 /* not found in original atoms, might still be in t_hack (ab) */
291 hacksearch_atom(&ii
, &jj
, ab
[i
][j
].a
[m
], nab
, ab
, rnr
, pdba
);
293 fatal_error(0,"Atom %s not found in residue %s%d"
294 " while adding hydrogens",
295 ab
[i
][j
].a
[m
],*pdba
->resname
[rnr
],rnr
+1);
297 copy_rvec(ab
[ii
][jj
].newx
, xa
[m
]);
299 copy_rvec(x
[ia
], xa
[m
]);
307 calc_h_pos(ab
[i
][j
].tp
, xa
, xh
);
308 for(m
=0; m
<ab
[i
][j
].nr
; m
++)
309 copy_rvec(xh
[m
],ab
[i
][j
+m
].newx
);
315 int add_h(t_atoms
**pdbaptr
, rvec
*xptr
[],
316 int nah
, t_hackblock ah
[],
317 int nterpairs
, t_hackblock
**ntdb
, t_hackblock
**ctdb
,
318 int *rN
, int *rC
, int **nabptr
, t_hack
***abptr
,
319 bool bUpdate_pdba
, bool bKeep_old_pdba
)
321 t_atoms
*newpdba
=NULL
,*pdba
=NULL
;
324 int i
,newi
,j
,d
,natoms
;
331 /* set flags for adding hydrogens (accoring to hdb) */
335 if (nabptr
&& abptr
) {
336 /* the first time these will be pointers to NULL, but we will
337 return in them the completed arrays, which we will get back
342 if (debug
) fprintf(debug
,"pointer to ab found\n");
347 /* WOW, everything was already figured out */
348 bUpdate_pdba
= FALSE
;
349 if (debug
) fprintf(debug
,"pointer to non-null ab found\n");
351 /* We'll have to do all the hard work */
353 /* first get all the hackblocks for each residue: */
354 hb
= get_hackblocks(pdba
, nah
, ah
, nterpairs
, ntdb
, ctdb
, rN
, rC
);
355 if (debug
) dump_hb(debug
, pdba
->nres
, hb
);
357 /* expand the hackblocks to atom level */
360 expand_hackblocks(pdba
, hb
, nab
, ab
, nterpairs
, rN
, rC
);
361 free_t_hackblock(pdba
->nres
, &hb
);
365 fprintf(debug
,"before calc_all_pos\n");
366 dump_ab(debug
, natoms
, nab
, ab
, TRUE
);
369 /* Now calc the positions */
370 calc_all_pos(pdba
, *xptr
, nab
, ab
);
373 fprintf(debug
,"after calc_all_pos\n");
374 dump_ab(debug
, natoms
, nab
, ab
, TRUE
);
378 /* we don't have to add atoms that are already present in pdba,
379 so we will remove them from the ab (t_hack) */
380 nadd
= check_atoms_present(pdba
, nab
, ab
);
382 fprintf(debug
, "removed add hacks that were already in pdba:\n");
383 dump_ab(debug
, natoms
, nab
, ab
, TRUE
);
384 fprintf(debug
, "will be adding %d atoms\n",nadd
);
387 /* Copy old atoms, making space for new ones */
389 init_t_atoms(newpdba
,natoms
+nadd
,FALSE
);
390 newpdba
->nres
= pdba
->nres
;
391 sfree(newpdba
->resname
);
392 newpdba
->resname
= pdba
->resname
;
396 if (debug
) fprintf(debug
,"snew xn for %d old + %d new atoms %d total)\n",
397 natoms
, nadd
, natoms
+nadd
);
398 snew(xn
,natoms
+nadd
);
400 for(i
=0; (i
<natoms
); i
++) {
401 /* check if this atom wasn't scheduled for deletion */
402 if ( nab
[i
]==0 || ab
[i
][0].nname
!=NULL
) {
403 if (newi
>= natoms
+nadd
) {
405 srenew(xn
,natoms
+nadd
);
407 if (debug
) fprintf(debug
,"(%3d) %3d %4s %4s%3d %3d",
408 i
+1, newi
+1, *pdba
->atomname
[i
],
409 *pdba
->resname
[pdba
->atom
[i
].resnr
],
410 pdba
->atom
[i
].resnr
+1, nab
[i
]);
412 copy_atom(pdba
,i
, newpdba
,newi
);
413 copy_rvec((*xptr
)[i
],xn
[newi
]);
414 /* process the hacks for this atom */
415 for(j
=0; j
<nab
[i
]; j
++) {
416 if ( ab
[i
][j
].oname
==NULL
) { /* add */
418 if (newi
>= natoms
+nadd
) {
420 srenew(xn
,natoms
+nadd
);
423 newpdba
->atom
[newi
].resnr
=pdba
->atom
[i
].resnr
;
424 if (debug
) fprintf(debug
," + %d",newi
+1);
426 if ( ab
[i
][j
].nname
!=NULL
) { /* add or replace */
428 snew(newpdba
->atomname
[newi
],1);
429 *newpdba
->atomname
[newi
]=strdup(ab
[i
][j
].nname
);
430 if ( ab
[i
][j
].oname
!=NULL
&& ab
[i
][j
].atom
) { /* replace */
431 /* newpdba->atom[newi].m = ab[i][j].atom->m; */
432 /* newpdba->atom[newi].q = ab[i][j].atom->q; */
433 /* newpdba->atom[newi].type = ab[i][j].atom->type; */
438 bSet
= bSet
&& ab
[i
][j
].newx
[d
]!=NOTSET
;
440 copy_rvec(ab
[i
][j
].newx
, xn
[newi
]);
441 if (bUpdate_pdba
&& debug
)
442 fprintf(debug
," %s %g %g",*newpdba
->atomname
[newi
],
443 newpdba
->atom
[newi
].m
,newpdba
->atom
[newi
].q
);
447 if (debug
) fprintf(debug
,"\n");
456 for(i
=0; i
<natoms
; i
++)
457 free_t_hack(nab
[i
], &ab
[i
]);
462 if ( bUpdate_pdba
) {
463 if ( !bKeep_old_pdba
) {
464 for(i
=0; i
< natoms
; i
++) {
465 sfree(*(pdba
->atomname
[i
]));
466 /* sfree(pdba->atomname[i]); */
468 sfree(pdba
->atomname
);
470 sfree(pdba
->pdbinfo
);
471 done_block(&(pdba
->excl
));
484 void deprotonate(t_atoms
*atoms
,rvec
*x
)
489 for(i
=0; i
<atoms
->nr
; i
++) {
490 if ( (*atoms
->atomname
[i
])[0] != 'H' ) {
491 atoms
->atomname
[j
]=atoms
->atomname
[i
];
492 atoms
->atom
[j
]=atoms
->atom
[i
];
493 copy_rvec(x
[i
],x
[j
]);
500 int protonate(t_atoms
**atomsptr
,rvec
**xptr
,t_protonate
*protdata
)
504 bool bUpdate_pdba
,bKeep_old_pdba
;
508 if ( !protdata
->bInit
) {
509 if (debug
) fprintf(debug
,"protonate: Initializing protdata\n");
510 /* set forcefield to use: */
511 strcpy(protdata
->FF
,"ffgmx2");
512 /* get the databases: */
513 protdata
->nah
=read_h_db(protdata
->FF
,&protdata
->ah
);
514 open_symtab(&protdata
->tab
);
515 protdata
->atype
=read_atype(protdata
->FF
,&protdata
->tab
);
516 if(read_ter_db(protdata
->FF
,'n',&protdata
->ntdb
,protdata
->atype
) < 4)
517 fatal_error(0,"no n-terminus db");
518 if(read_ter_db(protdata
->FF
,'c',&protdata
->ctdb
,protdata
->atype
) < 2)
519 fatal_error(0,"no c-terminus db");
521 /* set terminus types: -NH3+ (different for Proline) and -COO- */
523 snew(protdata
->sel_ntdb
, NTERPAIRS
);
524 snew(protdata
->sel_ctdb
, NTERPAIRS
);
525 if (strncmp(*atoms
->resname
[atoms
->atom
[atoms
->nr
-1].resnr
],"PRO",3)==0)
526 protdata
->sel_ntdb
[0]=&(protdata
->ntdb
[3]);
528 protdata
->sel_ntdb
[0]=&(protdata
->ntdb
[1]);
529 protdata
->sel_ctdb
[0]=&(protdata
->ctdb
[1]);
531 /* set terminal residue numbers: */
532 snew(protdata
->rN
, NTERPAIRS
);
533 snew(protdata
->rC
, NTERPAIRS
);
535 protdata
->rC
[0]=atoms
->atom
[atoms
->nr
-1].resnr
;
537 /* keep unprotonated topology: */
538 protdata
->upatoms
= atoms
;
539 /* we don't have these yet: */
540 protdata
->patoms
= NULL
;
544 /* clear hackblocks: */
548 /* set flag to show we're initialized: */
549 protdata
->bInit
=TRUE
;
551 if (debug
) fprintf(debug
,"protonate: using available protdata\n");
552 /* add_h will need the unprotonated topoloy again: */
553 atoms
= protdata
->upatoms
;
555 bKeep_old_pdba
=FALSE
;
559 nadd
= add_h(&atoms
, xptr
, protdata
->nah
, protdata
->ah
,
560 NTERPAIRS
, protdata
->sel_ntdb
, protdata
->sel_ctdb
,
561 protdata
->rN
, protdata
->rC
,
562 &protdata
->nab
, &protdata
->ab
, bUpdate_pdba
, bKeep_old_pdba
);
563 if ( ! protdata
->patoms
)
564 /* store protonated topology */
565 protdata
->patoms
= atoms
;
566 *atomsptr
= protdata
->patoms
;
567 if (debug
) fprintf(debug
,"natoms: %d -> %d (nadd=%d)\n",
568 protdata
->upatoms
->nr
, protdata
->patoms
->nr
, nadd
);