2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
5 * Copyright (c) 2001-2004, The GROMACS development team.
6 * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
7 * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
8 * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
9 * and including many others, as listed in the AUTHORS file in the
10 * top-level source directory and at http://www.gromacs.org.
12 * GROMACS is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public License
14 * as published by the Free Software Foundation; either version 2.1
15 * of the License, or (at your option) any later version.
17 * GROMACS is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with GROMACS; if not, see
24 * http://www.gnu.org/licenses, or write to the Free Software Foundation,
25 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
27 * If you want to redistribute modifications to GROMACS, please
28 * consider that scientific software is very special. Version
29 * control is crucial - bugs must be traceable. We will be happy to
30 * consider code for inclusion in the official distribution, but
31 * derived work must not be called official GROMACS. Details are found
32 * in the README & COPYING files - if they are missing, get the
33 * official version at http://www.gromacs.org.
35 * To help us fund GROMACS development, we humbly ask that you cite
36 * the research papers on the package. Check out http://www.gromacs.org.
48 #include "gromacs/fileio/pdbio.h"
49 #include "gromacs/gmxpreprocess/pdb2top.h"
50 #include "gromacs/math/vec.h"
51 #include "gromacs/utility/arrayref.h"
52 #include "gromacs/utility/cstringutil.h"
53 #include "gromacs/utility/fatalerror.h"
54 #include "gromacs/utility/smalloc.h"
55 #include "gromacs/utility/strdb.h"
59 std::string firstResidue
, secondResidue
;
60 std::string firstAtomName
, secondAtomName
;
61 std::string newFirstResidue
, newSecondResidue
;
62 int firstBondNumber
, secondBondNumber
;
72 c
= toupper(fgetc(stdin
));
73 } while ((c
!= 'Y') && (c
!= 'N'));
78 std::vector
<SpecialBond
> generateSpecialBonds()
80 const char* sbfile
= "specbond.dat";
82 std::vector
<SpecialBond
> specialBonds
;
83 char r1buf
[32], r2buf
[32], a1buf
[32], a2buf
[32], nr1buf
[32], nr2buf
[32];
88 int nlines
= get_lines(sbfile
, &lines
);
89 for (int i
= 0; (i
< nlines
); i
++)
91 if (sscanf(lines
[i
], "%s%s%d%s%s%d%lf%s%s", r1buf
, a1buf
, &nb1
, r2buf
, a2buf
, &nb2
, &length
,
95 fprintf(stderr
, "Invalid line '%s' in %s\n", lines
[i
], sbfile
);
101 newBond
.firstResidue
= r1buf
;
102 newBond
.secondResidue
= r2buf
;
103 newBond
.newFirstResidue
= nr1buf
;
104 newBond
.newSecondResidue
= nr2buf
;
105 newBond
.firstAtomName
= a1buf
;
106 newBond
.secondAtomName
= a2buf
;
107 newBond
.firstBondNumber
= nb1
;
108 newBond
.secondBondNumber
= nb2
;
109 newBond
.length
= length
;
110 specialBonds
.push_back(newBond
);
118 fprintf(stderr
, "%zu out of %d lines of %s converted successfully\n", specialBonds
.size(),
124 static bool is_special(gmx::ArrayRef
<const SpecialBond
> sb
, const char* res
, const char* atom
)
126 for (const auto& bond
: sb
)
128 if (((strncmp(bond
.firstResidue
.c_str(), res
, 3) == 0)
129 && (gmx::equalCaseInsensitive(bond
.firstAtomName
, atom
)))
130 || ((strncmp(bond
.secondResidue
.c_str(), res
, 3) == 0)
131 && (gmx::equalCaseInsensitive(bond
.secondAtomName
, atom
))))
139 static bool is_bond(gmx::ArrayRef
<const SpecialBond
> sb
, t_atoms
* pdba
, int a1
, int a2
, real d
, int* index_sb
, bool* bSwap
)
141 const char* at1
= *pdba
->atomname
[a1
];
142 const char* at2
= *pdba
->atomname
[a2
];
143 const char* res1
= *pdba
->resinfo
[pdba
->atom
[a1
].resind
].name
;
144 const char* res2
= *pdba
->resinfo
[pdba
->atom
[a2
].resind
].name
;
147 for (const auto& bond
: sb
)
150 if (((strncmp(bond
.firstResidue
.c_str(), res1
, 3) == 0)
151 && (gmx::equalCaseInsensitive(bond
.firstAtomName
, at1
))
152 && (strncmp(bond
.secondResidue
.c_str(), res2
, 3) == 0)
153 && (gmx::equalCaseInsensitive(bond
.secondAtomName
, at2
))))
156 if ((0.9 * bond
.length
< d
) && (1.1 * bond
.length
> d
))
161 if (((strncmp(bond
.firstResidue
.c_str(), res2
, 3) == 0)
162 && (gmx::equalCaseInsensitive(bond
.firstAtomName
, at2
))
163 && (strncmp(bond
.secondResidue
.c_str(), res1
, 3) == 0)
164 && (gmx::equalCaseInsensitive(bond
.secondAtomName
, at1
))))
167 if ((0.9 * bond
.length
< d
) && (1.1 * bond
.length
> d
))
177 static void rename_1res(t_atoms
* pdba
, int resind
, const char* newres
, bool bVerbose
)
181 printf("Using rtp entry %s for %s %d\n", newres
, *pdba
->resinfo
[resind
].name
,
182 pdba
->resinfo
[resind
].nr
);
184 /* this used to free *resname, which messes up the symtab! */
185 snew(pdba
->resinfo
[resind
].rtp
, 1);
186 *pdba
->resinfo
[resind
].rtp
= gmx_strdup(newres
);
189 std::vector
<DisulfideBond
> makeDisulfideBonds(t_atoms
* pdba
, rvec x
[], bool bInteractive
, bool bVerbose
)
191 std::vector
<SpecialBond
> specialBonds
= generateSpecialBonds();
192 std::vector
<DisulfideBond
> bonds
;
198 if (!specialBonds
.empty())
200 std::vector
<int> specialBondResIdxs
;
201 std::vector
<int> specialBondAtomIdxs
;
203 for (int i
= 0; (i
< pdba
->nr
); i
++)
205 /* Check if this atom is special and if it is not a double atom
206 * in the input that still needs to be removed.
209 if (!specialBondAtomIdxs
.empty())
211 prevAtom
= specialBondAtomIdxs
.back();
213 if (is_special(specialBonds
, *pdba
->resinfo
[pdba
->atom
[i
].resind
].name
, *pdba
->atomname
[i
])
214 && !(!specialBondAtomIdxs
.empty() && pdba
->atom
[prevAtom
].resind
== pdba
->atom
[i
].resind
215 && gmx_strcasecmp(*pdba
->atomname
[prevAtom
], *pdba
->atomname
[i
]) == 0))
217 specialBondResIdxs
.push_back(pdba
->atom
[i
].resind
);
218 specialBondAtomIdxs
.push_back(i
);
221 /* distance matrix d[nspec][nspec] */
222 int nspec
= specialBondAtomIdxs
.size();
223 std::vector
<std::vector
<real
>> d(nspec
);
224 for (int i
= 0; (i
< nspec
); i
++)
227 int ai
= specialBondAtomIdxs
[i
];
228 for (int j
= 0; (j
< nspec
); j
++)
230 int aj
= specialBondAtomIdxs
[j
];
231 d
[i
][j
] = std::sqrt(distance2(x
[ai
], x
[aj
]));
237 fprintf(stderr
, "Special Atom Distance matrix:\n");
238 for (int b
= 0; (b
< nspec
); b
+= MAXCOL
)
240 /* print resname/number column headings */
241 fprintf(stderr
, "%8s%8s", "", "");
242 int e
= std::min(b
+ MAXCOL
, nspec
- 1);
243 for (int i
= b
; (i
< e
); i
++)
245 sprintf(buf
, "%s%d", *pdba
->resinfo
[pdba
->atom
[specialBondAtomIdxs
[i
]].resind
].name
,
246 pdba
->resinfo
[specialBondResIdxs
[i
]].nr
);
247 fprintf(stderr
, "%8s", buf
);
249 fprintf(stderr
, "\n");
250 /* print atomname/number column headings */
251 fprintf(stderr
, "%8s%8s", "", "");
252 e
= std::min(b
+ MAXCOL
, nspec
- 1);
253 for (int i
= b
; (i
< e
); i
++)
255 std::string buf
= gmx::formatString("%s%d", *pdba
->atomname
[specialBondAtomIdxs
[i
]],
256 specialBondAtomIdxs
[i
] + 1);
257 fprintf(stderr
, "%8s", buf
.c_str());
259 fprintf(stderr
, "\n");
261 e
= std::min(b
+ MAXCOL
, nspec
);
262 for (int i
= b
+ 1; (i
< nspec
); i
++)
264 std::string buf
= gmx::formatString(
265 "%s%d", *pdba
->resinfo
[pdba
->atom
[specialBondAtomIdxs
[i
]].resind
].name
,
266 pdba
->resinfo
[specialBondResIdxs
[i
]].nr
);
267 fprintf(stderr
, "%8s", buf
.c_str());
268 buf
= gmx::formatString("%s%d", *pdba
->atomname
[specialBondAtomIdxs
[i
]],
269 specialBondAtomIdxs
[i
] + 1);
270 fprintf(stderr
, "%8s", buf
.c_str());
271 int e2
= std::min(i
, e
);
272 for (int j
= b
; (j
< e2
); j
++)
274 fprintf(stderr
, " %7.3f", d
[i
][j
]);
276 fprintf(stderr
, "\n");
281 for (int i
= 0; (i
< nspec
); i
++)
283 int ai
= specialBondAtomIdxs
[i
];
284 for (int j
= i
+ 1; (j
< nspec
); j
++)
286 int aj
= specialBondAtomIdxs
[j
];
287 /* Ensure creation of at most nspec special bonds to avoid overflowing bonds[] */
288 if (bonds
.size() < specialBondAtomIdxs
.size()
289 && is_bond(specialBonds
, pdba
, ai
, aj
, d
[i
][j
], &index_sb
, &bSwap
))
291 fprintf(stderr
, "%s %s-%d %s-%d and %s-%d %s-%d%s", bInteractive
? "Link" : "Linking",
292 *pdba
->resinfo
[pdba
->atom
[ai
].resind
].name
,
293 pdba
->resinfo
[specialBondResIdxs
[i
]].nr
, *pdba
->atomname
[ai
], ai
+ 1,
294 *pdba
->resinfo
[pdba
->atom
[aj
].resind
].name
,
295 pdba
->resinfo
[specialBondResIdxs
[j
]].nr
, *pdba
->atomname
[aj
], aj
+ 1,
296 bInteractive
? " (y/n) ?" : "...\n");
297 bool bDoit
= bInteractive
? yesno() : true;
301 DisulfideBond newBond
;
302 /* Store the residue numbers in the bonds array */
303 newBond
.firstResidue
= specialBondResIdxs
[i
];
304 newBond
.secondResidue
= specialBondResIdxs
[j
];
305 newBond
.firstAtom
= *pdba
->atomname
[ai
];
306 newBond
.secondAtom
= *pdba
->atomname
[aj
];
307 bonds
.push_back(newBond
);
308 /* rename residues */
311 rename_1res(pdba
, specialBondResIdxs
[i
],
312 specialBonds
[index_sb
].newSecondResidue
.c_str(), bVerbose
);
313 rename_1res(pdba
, specialBondResIdxs
[j
],
314 specialBonds
[index_sb
].newFirstResidue
.c_str(), bVerbose
);
318 rename_1res(pdba
, specialBondResIdxs
[i
],
319 specialBonds
[index_sb
].newFirstResidue
.c_str(), bVerbose
);
320 rename_1res(pdba
, specialBondResIdxs
[j
],
321 specialBonds
[index_sb
].newSecondResidue
.c_str(), bVerbose
);