1 /* -*- mode: c; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; c-file-style: "stroustrup"; -*- */
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 * Green Red Orange Magenta Azure Cyan Skyblue
56 #include "gmx_fatal.h"
67 void print_stat(rvec *x, int natoms, matrix box)
71 for (m = 0; (m < DIM); m++)
76 for (i = 0; (i < natoms); i++)
78 for (m = 0; m < DIM; m++)
80 xmin[m] = min(xmin[m], x[i][m]);
81 xmax[m] = max(xmax[m], x[i][m]);
84 for (m = 0; (m < DIM); m++)
86 fprintf(stderr, "DIM %d XMIN %8.3f XMAX %8.3f BOX %8.3f\n",
87 m, xmin[m], xmax[m], box[m][m]);
92 static gmx_bool in_box(t_pbc *pbc, rvec x)
97 /* pbc_dx_aiuc only works correctly with the rectangular box center */
98 calc_box_center(ecenterRECT, pbc->box, box_center);
100 shift = pbc_dx_aiuc(pbc, x, box_center, dx);
102 return (shift == CENTRAL);
105 static void mk_vdw(t_atoms *a, real rvdw[], gmx_atomprop_t aps,
110 /* initialise van der waals arrays of configuration */
111 fprintf(stderr, "Initialising van der waals distances...\n");
112 for (i = 0; (i < a->nr); i++)
114 if (!gmx_atomprop_query(aps, epropVDW,
115 *(a->resinfo[a->atom[i].resind].name),
116 *(a->atomname[i]), &(rvdw[i])))
118 rvdw[i] = r_distance;
131 void sort_molecule(t_atoms **atoms_solvt, rvec *x, rvec *v, real *r)
133 int atnr, i, j, moltp = 0, nrmoltypes, resi_o, resi_n, resnr;
134 t_moltypes *moltypes;
135 t_atoms *atoms, *newatoms;
136 rvec *newx, *newv = NULL;
139 fprintf(stderr, "Sorting configuration\n");
141 atoms = *atoms_solvt;
143 /* copy each residue from *atoms to a molecule in *molecule */
146 for (i = 0; i < atoms->nr; i++)
148 if ( (i == 0) || (atoms->atom[i].resind != atoms->atom[i-1].resind) )
150 /* see if this was a molecule type we haven't had yet: */
152 for (j = 0; (j < nrmoltypes) && (moltp == NOTSET); j++)
154 if (strcmp(*(atoms->resinfo[atoms->atom[i].resind].name),
155 moltypes[j].name) == 0)
164 srenew(moltypes, nrmoltypes);
165 moltypes[moltp].name = *(atoms->resinfo[atoms->atom[i].resind].name);
167 while ((i+atnr < atoms->nr) &&
168 (atoms->atom[i].resind == atoms->atom[i+atnr].resind))
172 moltypes[moltp].natoms = atnr;
173 moltypes[moltp].nmol = 0;
175 moltypes[moltp].nmol++;
179 fprintf(stderr, "Found %d%s molecule type%s:\n",
180 nrmoltypes, nrmoltypes == 1 ? "" : " different", nrmoltypes == 1 ? "" : "s");
181 for (j = 0; j < nrmoltypes; j++)
185 moltypes[j].res0 = 0;
189 moltypes[j].res0 = moltypes[j-1].res0+moltypes[j-1].nmol;
191 fprintf(stderr, "%7s (%4d atoms): %5d residues\n",
192 moltypes[j].name, moltypes[j].natoms, moltypes[j].nmol);
195 /* if we have only 1 moleculetype, we don't have to sort */
198 /* find out which molecules should go where: */
199 moltypes[0].i = moltypes[0].i0 = 0;
200 for (j = 1; j < nrmoltypes; j++)
204 moltypes[j-1].i0+moltypes[j-1].natoms*moltypes[j-1].nmol;
207 /* now put them there: */
209 init_t_atoms(newatoms, atoms->nr, FALSE);
210 newatoms->nres = atoms->nres;
211 snew(newatoms->resinfo, atoms->nres);
212 snew(newx, atoms->nr);
215 snew(newv, atoms->nr);
217 snew(newr, atoms->nr);
222 for (moltp = 0; moltp < nrmoltypes; moltp++)
225 while (i < atoms->nr)
227 resi_o = atoms->atom[i].resind;
228 if (strcmp(*atoms->resinfo[resi_o].name, moltypes[moltp].name) == 0)
230 /* Copy the residue info */
231 newatoms->resinfo[resi_n] = atoms->resinfo[resi_o];
232 newatoms->resinfo[resi_n].nr = resnr;
233 /* Copy the atom info */
236 newatoms->atom[j] = atoms->atom[i];
237 newatoms->atomname[j] = atoms->atomname[i];
238 newatoms->atom[j].resind = resi_n;
239 copy_rvec(x[i], newx[j]);
242 copy_rvec(v[i], newv[j]);
248 while (i < atoms->nr && atoms->atom[i].resind == resi_o);
249 /* Increase the new residue counters */
255 /* Skip this residue */
260 while (i < atoms->nr && atoms->atom[i].resind == resi_o);
265 /* put them back into the original arrays and throw away temporary arrays */
266 sfree(atoms->atomname);
267 sfree(atoms->resinfo);
270 *atoms_solvt = newatoms;
271 for (i = 0; i < (*atoms_solvt)->nr; i++)
273 copy_rvec(newx[i], x[i]);
276 copy_rvec(newv[i], v[i]);
290 void rm_res_pbc(t_atoms *atoms, rvec *x, matrix box)
292 int i, start, n, d, nat;
298 for (n = 0; n < atoms->nr; n++)
300 if (!is_hydrogen(*(atoms->atomname[n])))
305 if ( (n+1 == atoms->nr) ||
306 (atoms->atom[n+1].resind != atoms->atom[n].resind) )
308 /* if nat==0 we have only hydrogens in the solvent,
309 we take last coordinate as cg */
313 copy_rvec(x[n], xcg);
315 svmul(1.0/nat, xcg, xcg);
316 for (d = 0; d < DIM; d++)
320 for (i = start; i <= n; i++)
322 x[i][d] += box[d][d];
326 while (xcg[d] >= box[d][d])
328 for (i = start; i <= n; i++)
330 x[i][d] -= box[d][d];
342 /* This is a (maybe) slow workaround to avoid the neighbor searching in addconf.c, which
343 * leaks memory (May 2012). The function could be deleted as soon as the momory leaks
344 * in addconf.c are fixed.
345 * However, when inserting a small molecule in a system containing not too many atoms,
346 * allPairsDistOk is probably even faster than addconf.c
349 allPairsDistOk(t_atoms *atoms, rvec *x, real *r,
350 int ePBC, matrix box,
351 t_atoms *atoms_insrt, rvec *x_n, real *r_insrt)
358 set_pbc(&pbc, ePBC, box);
359 for (i = 0; i < atoms->nr; i++)
361 for (j = 0; j < atoms_insrt->nr; j++)
363 pbc_dx(&pbc, x[i], x_n[j], dx);
365 r2 = sqr(r[i]+r_insrt[j]);
375 /* enum for random rotations of inserted solutes */
377 en_rot, en_rotXYZ, en_rotZ, en_rotNone, en_NR
380 static char *insert_mols(const char *mol_insrt, int nmol_insrt, int ntry, int seed,
381 t_atoms *atoms, rvec **x, real **r, int ePBC, matrix box,
382 gmx_atomprop_t aps, real r_distance, real rshell,
383 const output_env_t oenv,
384 const char* posfn, const rvec deltaR, int enum_rot,
385 gmx_bool bCheckAllPairDist)
388 static char *title_insrt;
394 int i, mol, onr, ncol;
395 real alfa = 0., beta = 0., gamma = 0.;
400 set_pbc(&pbc, ePBC, box);
402 /* read number of atoms of insert molecules */
403 get_stx_coordnum(mol_insrt, &atoms_insrt.nr);
404 if (atoms_insrt.nr == 0)
406 gmx_fatal(FARGS, "No molecule in %s, please check your input\n", mol_insrt);
408 /* allocate memory for atom coordinates of insert molecules */
409 snew(x_insrt, atoms_insrt.nr);
410 snew(r_insrt, atoms_insrt.nr);
411 snew(atoms_insrt.resinfo, atoms_insrt.nr);
412 snew(atoms_insrt.atomname, atoms_insrt.nr);
413 snew(atoms_insrt.atom, atoms_insrt.nr);
414 atoms_insrt.pdbinfo = NULL;
415 snew(x_n, atoms_insrt.nr);
416 snew(title_insrt, STRLEN);
418 /* read residue number, residue names, atomnames, coordinates etc. */
419 fprintf(stderr, "Reading molecule configuration \n");
420 read_stx_conf(mol_insrt, title_insrt, &atoms_insrt, x_insrt, NULL,
421 &ePBC_insrt, box_insrt);
422 fprintf(stderr, "%s\nContaining %d atoms in %d residue\n",
423 title_insrt, atoms_insrt.nr, atoms_insrt.nres);
424 srenew(atoms_insrt.resinfo, atoms_insrt.nres);
426 /* initialise van der waals arrays of insert molecules */
427 mk_vdw(&atoms_insrt, r_insrt, aps, r_distance);
429 /* With -ip, take nmol_insrt from file posfn */
432 nmol_insrt = read_xvg(posfn, &rpos, &ncol);
435 gmx_fatal(FARGS, "Expected 3 columns (x/y/z coordinates) in file %s\n", ncol, posfn);
437 fprintf(stderr, "Read %d positions from file %s\n\n", nmol_insrt, posfn);
440 srenew(atoms->resinfo, (atoms->nres+nmol_insrt*atoms_insrt.nres));
441 srenew(atoms->atomname, (atoms->nr+atoms_insrt.nr*nmol_insrt));
442 srenew(atoms->atom, (atoms->nr+atoms_insrt.nr*nmol_insrt));
443 srenew(*x, (atoms->nr+atoms_insrt.nr*nmol_insrt));
444 srenew(*r, (atoms->nr+atoms_insrt.nr*nmol_insrt));
447 while ((mol < nmol_insrt) && (trial < ntry*nmol_insrt))
449 fprintf(stderr, "\rTry %d", trial++);
450 for (i = 0; (i < atoms_insrt.nr); i++)
452 copy_rvec(x_insrt[i], x_n[i]);
457 alfa = 2*M_PI *rando(&seed);
458 beta = 2*M_PI *rando(&seed);
459 gamma = 2*M_PI *rando(&seed);
463 gamma = 2*M_PI*rando(&seed);
466 alfa = beta = gamma = 0.;
469 if (enum_rot == en_rotXYZ || (enum_rot == en_rotZ))
471 rotate_conf(atoms_insrt.nr, x_n, NULL, alfa, beta, gamma);
475 /* insert at random positions */
476 offset_x[XX] = box[XX][XX]*rando(&seed);
477 offset_x[YY] = box[YY][YY]*rando(&seed);
478 offset_x[ZZ] = box[ZZ][ZZ]*rando(&seed);
479 gen_box(0, atoms_insrt.nr, x_n, box_insrt, offset_x, TRUE);
480 if (!in_box(&pbc, x_n[0]) || !in_box(&pbc, x_n[atoms_insrt.nr-1]))
487 /* Insert at positions taken from option -ip file */
488 offset_x[XX] = rpos[XX][mol] + deltaR[XX]*(2*rando(&seed)-1);
489 offset_x[YY] = rpos[YY][mol] + deltaR[YY]*(2*rando(&seed)-1);
490 offset_x[ZZ] = rpos[ZZ][mol] + deltaR[ZZ]*(2*rando(&seed)-1);
491 for (i = 0; i < atoms_insrt.nr; i++)
493 rvec_inc(x_n[i], offset_x);
499 /* This is a (maybe) slow workaround to avoid too many calls of add_conf, which
500 * leaks memory (status May 2012). If the momory leaks in add_conf() are fixed,
501 * this check could be removed. Note, however, that allPairsDistOk is probably
502 * even faster than add_conf() when inserting a small molecule into a moderately
505 if (bCheckAllPairDist && !allPairsDistOk(atoms, *x, *r, ePBC, box, &atoms_insrt, x_n, r_insrt))
510 add_conf(atoms, x, NULL, r, FALSE, ePBC, box, TRUE,
511 &atoms_insrt, x_n, NULL, r_insrt, FALSE, rshell, 0, oenv);
513 if (atoms->nr == (atoms_insrt.nr+onr))
516 fprintf(stderr, " success (now %d atoms)!\n", atoms->nr);
519 srenew(atoms->resinfo, atoms->nres);
520 srenew(atoms->atomname, atoms->nr);
521 srenew(atoms->atom, atoms->nr);
522 srenew(*x, atoms->nr);
523 srenew(*r, atoms->nr);
525 fprintf(stderr, "\n");
526 /* print number of molecules added */
527 fprintf(stderr, "Added %d molecules (out of %d requested) of %s\n",
528 mol, nmol_insrt, *atoms_insrt.resinfo[0].name);
533 static void add_solv(const char *fn, t_atoms *atoms, rvec **x, rvec **v, real **r,
534 int ePBC, matrix box,
535 gmx_atomprop_t aps, real r_distance, int *atoms_added,
536 int *residues_added, real rshell, int max_sol,
537 const output_env_t oenv)
541 char filename[STRLEN];
542 char title_solvt[STRLEN];
543 t_atoms *atoms_solvt;
544 rvec *x_solvt, *v_solvt = NULL;
552 strncpy(filename, lfn, STRLEN);
554 snew(atoms_solvt, 1);
555 get_stx_coordnum(filename, &(atoms_solvt->nr));
556 if (atoms_solvt->nr == 0)
558 gmx_fatal(FARGS, "No solvent in %s, please check your input\n", filename);
560 snew(x_solvt, atoms_solvt->nr);
563 snew(v_solvt, atoms_solvt->nr);
565 snew(r_solvt, atoms_solvt->nr);
566 snew(atoms_solvt->resinfo, atoms_solvt->nr);
567 snew(atoms_solvt->atomname, atoms_solvt->nr);
568 snew(atoms_solvt->atom, atoms_solvt->nr);
569 atoms_solvt->pdbinfo = NULL;
570 fprintf(stderr, "Reading solvent configuration%s\n",
571 v_solvt ? " and velocities" : "");
572 read_stx_conf(filename, title_solvt, atoms_solvt, x_solvt, v_solvt,
573 &ePBC_solvt, box_solvt);
574 fprintf(stderr, "\"%s\"\n", title_solvt);
575 fprintf(stderr, "solvent configuration contains %d atoms in %d residues\n",
576 atoms_solvt->nr, atoms_solvt->nres);
577 fprintf(stderr, "\n");
579 /* apply pbc for solvent configuration for whole molecules */
580 rm_res_pbc(atoms_solvt, x_solvt, box_solvt);
582 /* initialise van der waals arrays of solvent configuration */
583 mk_vdw(atoms_solvt, r_solvt, aps, r_distance);
585 /* calculate the box multiplication factors n_box[0...DIM] */
587 for (i = 0; (i < DIM); i++)
590 while (n_box[i]*box_solvt[i][i] < box[i][i])
596 fprintf(stderr, "Will generate new solvent configuration of %dx%dx%d boxes\n",
597 n_box[XX], n_box[YY], n_box[ZZ]);
599 /* realloc atoms_solvt for the new solvent configuration */
600 srenew(atoms_solvt->resinfo, atoms_solvt->nres*nmol);
601 srenew(atoms_solvt->atomname, atoms_solvt->nr*nmol);
602 srenew(atoms_solvt->atom, atoms_solvt->nr*nmol);
603 srenew(x_solvt, atoms_solvt->nr*nmol);
606 srenew(v_solvt, atoms_solvt->nr*nmol);
608 srenew(r_solvt, atoms_solvt->nr*nmol);
610 /* generate a new solvent configuration */
611 genconf(atoms_solvt, x_solvt, v_solvt, r_solvt, box_solvt, n_box);
614 print_stat(x_solvt, atoms_solvt->nr, box_solvt);
618 print_stat(x_solvt, atoms_solvt->nr, box_solvt);
620 /* Sort the solvent mixture, not the protein... */
621 sort_molecule(&atoms_solvt, x_solvt, v_solvt, r_solvt);
623 /* add the two configurations */
626 add_conf(atoms, x, v, r, TRUE, ePBC, box, FALSE,
627 atoms_solvt, x_solvt, v_solvt, r_solvt, TRUE, rshell, max_sol, oenv);
628 *atoms_added = atoms->nr-onr;
629 *residues_added = atoms->nres-onres;
634 fprintf(stderr, "Generated solvent containing %d atoms in %d residues\n",
635 *atoms_added, *residues_added);
638 static char *read_prot(const char *confin, t_atoms *atoms, rvec **x, rvec **v,
639 real **r, int *ePBC, matrix box, gmx_atomprop_t aps,
646 get_stx_coordnum(confin, &natoms);
648 /* allocate memory for atom coordinates of configuration 1 */
655 init_t_atoms(atoms, natoms, FALSE);
657 /* read residue number, residue names, atomnames, coordinates etc. */
658 fprintf(stderr, "Reading solute configuration%s\n", v ? " and velocities" : "");
659 read_stx_conf(confin, title, atoms, *x, v ? *v : NULL, ePBC, box);
660 fprintf(stderr, "%s\nContaining %d atoms in %d residues\n",
661 title, atoms->nr, atoms->nres);
663 /* initialise van der waals arrays of configuration 1 */
664 mk_vdw(atoms, *r, aps, r_distance);
669 static void update_top(t_atoms *atoms, matrix box, int NFILE, t_filenm fnm[],
672 #define TEMP_FILENM "temp.top"
674 char buf[STRLEN], buf2[STRLEN], *temp;
675 const char *topinout;
677 gmx_bool bSystem, bMolecules, bSkip;
682 for (i = 0; (i < atoms->nres); i++)
684 /* calculate number of SOLvent molecules */
685 if ( (strcmp(*atoms->resinfo[i].name, "SOL") == 0) ||
686 (strcmp(*atoms->resinfo[i].name, "WAT") == 0) ||
687 (strcmp(*atoms->resinfo[i].name, "HOH") == 0) )
693 for (i = 0; (i < atoms->nr); i++)
695 gmx_atomprop_query(aps, epropMass,
696 *atoms->resinfo[atoms->atom[i].resind].name,
697 *atoms->atomname[i], &mm);
703 fprintf(stderr, "Volume : %10g (nm^3)\n", vol);
704 fprintf(stderr, "Density : %10g (g/l)\n",
705 (mtot*1e24)/(AVOGADRO*vol));
706 fprintf(stderr, "Number of SOL molecules: %5d \n\n", nsol);
708 /* open topology file and append sol molecules */
709 topinout = ftp2fn(efTOP, NFILE, fnm);
710 if (ftp2bSet(efTOP, NFILE, fnm) )
712 fprintf(stderr, "Processing topology\n");
713 fpin = ffopen(topinout, "r");
714 fpout = ffopen(TEMP_FILENM, "w");
716 bSystem = bMolecules = FALSE;
717 while (fgets(buf, STRLEN, fpin))
722 if ((temp = strchr(buf2, '\n')) != NULL)
730 if ((temp = strchr(buf2, '\n')) != NULL)
735 if (buf2[strlen(buf2)-1] == ']')
737 buf2[strlen(buf2)-1] = '\0';
740 bSystem = (gmx_strcasecmp(buf2, "system") == 0);
741 bMolecules = (gmx_strcasecmp(buf2, "molecules") == 0);
744 else if (bSystem && nsol && (buf[0] != ';') )
746 /* if sol present, append "in water" to system name */
748 if (buf2[0] && (!strstr(buf2, " water")) )
750 sprintf(buf, "%s in water\n", buf2);
756 /* check if this is a line with solvent molecules */
757 sscanf(buf, "%4095s", buf2);
758 if (strcmp(buf2, "SOL") == 0)
760 sscanf(buf, "%*4095s %20d", &i);
771 if ((temp = strchr(buf, '\n')) != NULL)
775 fprintf(stdout, "Removing line #%d '%s' from topology file (%s)\n",
776 line, buf, topinout);
780 fprintf(fpout, "%s", buf);
786 fprintf(stdout, "Adding line for %d solvent molecules to "
787 "topology file (%s)\n", nsol, topinout);
788 fprintf(fpout, "%-15s %5d\n", "SOL", nsol);
791 /* use ffopen to generate backup of topinout */
792 fpout = ffopen(topinout, "w");
794 rename(TEMP_FILENM, topinout);
799 int gmx_genbox(int argc, char *argv[])
801 const char *desc[] = {
802 "[TT]genbox[tt] can do one of 4 things:[PAR]",
804 "1) Generate a box of solvent. Specify [TT]-cs[tt] and [TT]-box[tt]. Or specify [TT]-cs[tt] and",
805 "[TT]-cp[tt] with a structure file with a box, but without atoms.[PAR]",
807 "2) Solvate a solute configuration, e.g. a protein, in a bath of solvent ",
808 "molecules. Specify [TT]-cp[tt] (solute) and [TT]-cs[tt] (solvent). ",
809 "The box specified in the solute coordinate file ([TT]-cp[tt]) is used,",
810 "unless [TT]-box[tt] is set.",
811 "If you want the solute to be centered in the box,",
812 "the program [TT]editconf[tt] has sophisticated options",
813 "to change the box dimensions and center the solute.",
814 "Solvent molecules are removed from the box where the ",
815 "distance between any atom of the solute molecule(s) and any atom of ",
816 "the solvent molecule is less than the sum of the van der Waals radii of ",
817 "both atoms. A database ([TT]vdwradii.dat[tt]) of van der Waals radii is ",
818 "read by the program, and atoms not in the database are ",
819 "assigned a default distance [TT]-vdwd[tt].",
820 "Note that this option will also influence the distances between",
821 "solvent molecules if they contain atoms that are not in the database.",
824 "3) Insert a number ([TT]-nmol[tt]) of extra molecules ([TT]-ci[tt]) ",
825 "at random positions.",
826 "The program iterates until [TT]nmol[tt] molecules",
827 "have been inserted in the box. To test whether an insertion is ",
828 "successful the same van der Waals criterium is used as for removal of ",
829 "solvent molecules. When no appropriately-sized ",
830 "holes (holes that can hold an extra molecule) are available, the ",
831 "program tries for [TT]-nmol[tt] * [TT]-try[tt] times before giving up. ",
832 "Increase [TT]-try[tt] if you have several small holes to fill.",
833 "Option [TT]-rot[tt] defines if the molecules are randomly oriented.",
836 "4) Insert a number of molecules ([TT]-ci[tt]) at positions defined in",
837 "positions.dat ([TT]-ip[tt]). positions.dat should have 3 columns (x/y/z),",
838 "that give the displacements compared to the input molecule position ([TT]-ci[tt]).",
839 "Hence, if positions.dat should contain the absolut positions, the molecule ",
840 "must be centered to 0/0/0 before using genbox (use, e.g., editconf -center).",
841 "Comments in positions.dat starting with # are ignored. Option [TT]-dr[tt]",
842 "defines the maximally allowed displacements during insertial trials.",
843 "[TT]-try[tt] and [TT]-rot[tt] work as in mode (3) (see above)",
846 "If you need to do more than one of the above operations, it can be",
847 "best to call [TT]genbox[tt] separately for each operation, so that",
848 "you are sure of the order in which the operations occur.[PAR]",
850 "The default solvent is Simple Point Charge water (SPC), with coordinates ",
851 "from [TT]$GMXLIB/spc216.gro[tt]. These coordinates can also be used",
852 "for other 3-site water models, since a short equibilibration will remove",
853 "the small differences between the models.",
854 "Other solvents are also supported, as well as mixed solvents. The",
855 "only restriction to solvent types is that a solvent molecule consists",
856 "of exactly one residue. The residue information in the coordinate",
857 "files is used, and should therefore be more or less consistent.",
858 "In practice this means that two subsequent solvent molecules in the ",
859 "solvent coordinate file should have different residue number.",
860 "The box of solute is built by stacking the coordinates read from",
861 "the coordinate file. This means that these coordinates should be ",
862 "equlibrated in periodic boundary conditions to ensure a good",
863 "alignment of molecules on the stacking interfaces.",
864 "The [TT]-maxsol[tt] option simply adds only the first [TT]-maxsol[tt]",
865 "solvent molecules and leaves out the rest that would have fitted",
866 "into the box. This can create a void that can cause problems later.",
867 "Choose your volume wisely.[PAR]",
869 "The program can optionally rotate the solute molecule to align the",
870 "longest molecule axis along a box edge. This way the amount of solvent",
871 "molecules necessary is reduced.",
872 "It should be kept in mind that this only works for",
873 "short simulations, as e.g. an alpha-helical peptide in solution can ",
874 "rotate over 90 degrees, within 500 ps. In general it is therefore ",
875 "better to make a more or less cubic box.[PAR]",
877 "Setting [TT]-shell[tt] larger than zero will place a layer of water of",
878 "the specified thickness (nm) around the solute. Hint: it is a good",
879 "idea to put the protein in the center of a box first (using [TT]editconf[tt]).",
882 "Finally, [TT]genbox[tt] will optionally remove lines from your topology file in ",
883 "which a number of solvent molecules is already added, and adds a ",
884 "line with the total number of solvent molecules in your coordinate file."
887 const char *bugs[] = {
888 "Molecules must be whole in the initial configurations.",
889 "Many repeated neighbor searchings with -ci blows up the allocated memory. "
890 "Option -allpair avoids this using all-to-all distance checks (slow for large systems)"
894 gmx_bool bSol, bProt, bBox;
895 const char *conf_prot, *confout;
901 /* protein configuration data */
908 /* other data types */
909 int atoms_added, residues_added;
912 { efSTX, "-cp", "protein", ffOPTRD },
913 { efSTX, "-cs", "spc216", ffLIBOPTRD},
914 { efSTX, "-ci", "insert", ffOPTRD},
915 { efDAT, "-ip", "positions", ffOPTRD},
916 { efSTO, NULL, NULL, ffWRITE},
917 { efTOP, NULL, NULL, ffOPTRW},
919 #define NFILE asize(fnm)
921 static int nmol_ins = 0, nmol_try = 10, seed = 1997, enum_rot;
922 static real r_distance = 0.105, r_shell = 0;
923 static rvec new_box = {0.0, 0.0, 0.0}, deltaR = {0.0, 0.0, 0.0};
924 static gmx_bool bReadV = FALSE, bCheckAllPairDist = FALSE;
925 static int max_sol = 0;
927 const char *enum_rot_string[] = {NULL, "xyz", "z", "none", NULL};
929 { "-box", FALSE, etRVEC, {new_box},
931 { "-nmol", FALSE, etINT, {&nmol_ins},
932 "Number of extra molecules to insert" },
933 { "-try", FALSE, etINT, {&nmol_try},
934 "Try inserting [TT]-nmol[tt] times [TT]-try[tt] times" },
935 { "-seed", FALSE, etINT, {&seed},
936 "Random generator seed"},
937 { "-vdwd", FALSE, etREAL, {&r_distance},
938 "Default van der Waals distance"},
939 { "-shell", FALSE, etREAL, {&r_shell},
940 "Thickness of optional water layer around solute" },
941 { "-maxsol", FALSE, etINT, {&max_sol},
942 "Maximum number of solvent molecules to add if they fit in the box. If zero (default) this is ignored" },
943 { "-vel", FALSE, etBOOL, {&bReadV},
944 "Keep velocities from input solute and solvent" },
945 { "-dr", FALSE, etRVEC, {deltaR},
946 "Allowed displacement in x/y/z from positions in [TT]-ip[tt] file" },
947 { "-rot", FALSE, etENUM, {enum_rot_string},
948 "rotate inserted molecules randomly" },
949 { "-allpair", FALSE, etBOOL, {&bCheckAllPairDist},
950 "Avoid momory leaks during neighbor searching with option -ci. May be slow for large systems." },
953 parse_common_args(&argc, argv, PCA_BE_NICE, NFILE, fnm, asize(pa), pa,
954 asize(desc), desc, asize(bugs), bugs, &oenv);
956 bInsert = opt2bSet("-ci", NFILE, fnm) && ((nmol_ins > 0) || opt2bSet("-ip", NFILE, fnm));
957 bSol = opt2bSet("-cs", NFILE, fnm);
958 bProt = opt2bSet("-cp", NFILE, fnm);
959 bBox = opt2parg_bSet("-box", asize(pa), pa);
960 enum_rot = nenum(enum_rot_string);
963 if (bInsert && (nmol_ins <= 0 && !opt2bSet("-ip", NFILE, fnm)))
965 gmx_fatal(FARGS, "When specifying inserted molecules (-ci), "
966 "-nmol must be larger than 0 or positions must be given with -ip");
970 gmx_fatal(FARGS, "When no solute (-cp) is specified, "
971 "a box size (-box) must be specified");
974 aps = gmx_atomprop_init();
978 /*generate a solute configuration */
979 conf_prot = opt2fn("-cp", NFILE, fnm);
980 title = read_prot(conf_prot, &atoms, &x, bReadV ? &v : NULL, &r, &ePBC, box,
984 fprintf(stderr, "Note: no velocities found\n");
988 fprintf(stderr, "Note: no atoms in %s\n", conf_prot);
996 atoms.resinfo = NULL;
997 atoms.atomname = NULL;
999 atoms.pdbinfo = NULL;
1007 box[XX][XX] = new_box[XX];
1008 box[YY][YY] = new_box[YY];
1009 box[ZZ][ZZ] = new_box[ZZ];
1013 gmx_fatal(FARGS, "Undefined solute box.\nCreate one with editconf "
1014 "or give explicit -box command line option");
1017 /* add nmol_ins molecules of atoms_ins
1018 in random orientation at random place */
1021 title_ins = insert_mols(opt2fn("-ci", NFILE, fnm), nmol_ins, nmol_try, seed,
1022 &atoms, &x, &r, ePBC, box, aps, r_distance, r_shell,
1023 oenv, opt2fn_null("-ip", NFILE, fnm), deltaR, enum_rot,
1028 title_ins = strdup("Generated by genbox");
1034 add_solv(opt2fn("-cs", NFILE, fnm), &atoms, &x, v ? &v : NULL, &r, ePBC, box,
1035 aps, r_distance, &atoms_added, &residues_added, r_shell, max_sol,
1039 /* write new configuration 1 to file confout */
1040 confout = ftp2fn(efSTO, NFILE, fnm);
1041 fprintf(stderr, "Writing generated configuration to %s\n", confout);
1044 write_sto_conf(confout, title, &atoms, x, v, ePBC, box);
1045 /* print box sizes and box type to stderr */
1046 fprintf(stderr, "%s\n", title);
1050 write_sto_conf(confout, title_ins, &atoms, x, v, ePBC, box);
1055 /* print size of generated configuration */
1056 fprintf(stderr, "\nOutput configuration contains %d atoms in %d residues\n",
1057 atoms.nr, atoms.nres);
1058 update_top(&atoms, box, NFILE, fnm, aps);
1060 gmx_atomprop_destroy(aps);