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,2018,2019, by the GROMACS development team, led by
7 * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
8 * and including many others, as listed in the AUTHORS file in the
9 * top-level source directory and at http://www.gromacs.org.
11 * GROMACS is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public License
13 * as published by the Free Software Foundation; either version 2.1
14 * of the License, or (at your option) any later version.
16 * GROMACS is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with GROMACS; if not, see
23 * http://www.gnu.org/licenses, or write to the Free Software Foundation,
24 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26 * If you want to redistribute modifications to GROMACS, please
27 * consider that scientific software is very special. Version
28 * control is crucial - bugs must be traceable. We will be happy to
29 * consider code for inclusion in the official distribution, but
30 * derived work must not be called official GROMACS. Details are found
31 * in the README & COPYING files - if they are missing, get the
32 * official version at http://www.gromacs.org.
34 * To help us fund GROMACS development, we humbly ask that you cite
35 * the research papers on the package. Check out http://www.gromacs.org.
41 #include "gromacs/commandline/pargs.h"
42 #include "gromacs/fileio/confio.h"
43 #include "gromacs/fileio/trxio.h"
44 #include "gromacs/math/3dtransforms.h"
45 #include "gromacs/math/utilities.h"
46 #include "gromacs/math/vec.h"
47 #include "gromacs/mdtypes/md_enums.h"
48 #include "gromacs/pbcutil/pbc.h"
49 #include "gromacs/random/threefry.h"
50 #include "gromacs/random/uniformrealdistribution.h"
51 #include "gromacs/topology/mtop_util.h"
52 #include "gromacs/topology/topology.h"
53 #include "gromacs/utility/arraysize.h"
54 #include "gromacs/utility/cstringutil.h"
55 #include "gromacs/utility/fatalerror.h"
56 #include "gromacs/utility/smalloc.h"
59 rand_rot(int natoms, rvec x[], rvec v[], vec4 xrot[], vec4 vrot[], gmx::DefaultRandomEngine* rng, const rvec max_rot)
61 mat4 mt1, mt2, mr[DIM], mtemp1, mtemp2, mtemp3, mxtot, mvtot;
65 gmx::UniformRealDistribution<real> dist(-1.0, 1.0);
68 for (i = 0; (i < natoms); i++)
70 for (m = 0; (m < DIM); m++)
72 xcm[m] += x[i][m] / natoms; /* get center of mass of one molecule */
75 fprintf(stderr, "center of geometry: %f, %f, %f\n", xcm[0], xcm[1], xcm[2]);
77 /* move c.o.ma to origin */
78 gmx_mat4_init_translation(-xcm[XX], -xcm[YY], -xcm[ZZ], mt1);
79 for (m = 0; (m < DIM); m++)
81 phi = M_PI * max_rot[m] * dist(*rng) / 180;
82 gmx_mat4_init_rotation(m, phi, mr[m]);
84 gmx_mat4_init_translation(xcm[XX], xcm[YY], xcm[ZZ], mt2);
86 /* For gmx_mat4_mmul() we need to multiply in the opposite order
87 * compared to normal mathematical notation.
89 gmx_mat4_mmul(mtemp1, mt1, mr[XX]);
90 gmx_mat4_mmul(mtemp2, mr[YY], mr[ZZ]);
91 gmx_mat4_mmul(mtemp3, mtemp1, mtemp2);
92 gmx_mat4_mmul(mxtot, mtemp3, mt2);
93 gmx_mat4_mmul(mvtot, mr[XX], mtemp2);
95 for (i = 0; (i < natoms); i++)
97 gmx_mat4_transform_point(mxtot, x[i], xrot[i]);
98 gmx_mat4_transform_point(mvtot, v[i], vrot[i]);
102 int gmx_genconf(int argc, char* argv[])
104 const char* desc[] = {
105 "[THISMODULE] multiplies a given coordinate file by simply stacking them",
106 "on top of each other, like a small child playing with wooden blocks.",
107 "The program makes a grid of [IT]user-defined[it]",
108 "proportions ([TT]-nbox[tt]), ",
109 "and interspaces the grid point with an extra space [TT]-dist[tt].[PAR]",
110 "When option [TT]-rot[tt] is used the program does not check for overlap",
111 "between molecules on grid points. It is recommended to make the box in",
112 "the input file at least as big as the coordinates + ",
113 "van der Waals radius.[PAR]",
114 "If the optional trajectory file is given, conformations are not",
115 "generated, but read from this file and translated appropriately to",
119 const char* bugs[] = { "The program should allow for random displacement of lattice points." };
122 rvec * x, *xx, *v; /* coordinates? */
126 matrix box, boxx; /* box length matrix */
128 int natoms; /* number of atoms in one molecule */
129 int nres; /* number of molecules? */
130 int i, j, k, l, m, ndx, nrdx, nx, ny, nz;
133 gmx_output_env_t* oenv;
135 t_filenm fnm[] = { { efSTX, "-f", "conf", ffREAD },
136 { efSTO, "-o", "out", ffWRITE },
137 { efTRX, "-trj", nullptr, ffOPTRD } };
138 #define NFILE asize(fnm)
139 rvec nrbox = { 1, 1, 1 };
140 int seed = 0; /* seed for random number generator */
141 gmx_bool bRandom = FALSE; /* False: no random rotations */
142 gmx_bool bRenum = TRUE; /* renumber residues */
143 rvec dist = { 0, 0, 0 }; /* space added between molecules ? */
144 rvec max_rot = { 180, 180, 180 }; /* maximum rotation */
146 { "-nbox", FALSE, etRVEC, { nrbox }, "Number of boxes" },
147 { "-dist", FALSE, etRVEC, { dist }, "Distance between boxes" },
148 { "-seed", FALSE, etINT, { &seed }, "Random generator seed (0 means generate)" },
149 { "-rot", FALSE, etBOOL, { &bRandom }, "Randomly rotate conformations" },
150 { "-maxrot", FALSE, etRVEC, { max_rot }, "Maximum random rotation" },
151 { "-renumber", FALSE, etBOOL, { &bRenum }, "Renumber residues" }
154 if (!parse_common_args(&argc, argv, 0, NFILE, fnm, asize(pa), pa, asize(desc), desc,
155 asize(bugs), bugs, &oenv))
162 seed = static_cast<int>(gmx::makeRandomSeed());
164 gmx::DefaultRandomEngine rng(seed);
166 bTRX = ftp2bSet(efTRX, NFILE, fnm);
167 nx = gmx::roundToInt(nrbox[XX]);
168 ny = gmx::roundToInt(nrbox[YY]);
169 nz = gmx::roundToInt(nrbox[ZZ]);
171 if ((nx <= 0) || (ny <= 0) || (nz <= 0))
173 gmx_fatal(FARGS, "Number of boxes (-nbox) should be larger than zero");
176 vol = nx * ny * nz; /* calculate volume in grid points (= nr. molecules) */
179 bool haveTop = false;
180 readConfAndTopology(opt2fn("-f", NFILE, fnm), &haveTop, &mtop, &ePBC, &x, &v, box);
181 t_atoms atoms = gmx_mtop_global_atoms(&mtop);
183 nres = atoms.nres; /* nr of residues in one element? */
184 /* make space for all the atoms */
185 add_t_atoms(&atoms, natoms * (vol - 1), nres * (vol - 1));
186 srenew(x, natoms * vol); /* get space for coordinates of all atoms */
187 srenew(v, natoms * vol); /* velocities. not really needed? */
188 snew(xrot, natoms); /* get space for rotation matrix? */
193 if (!read_first_x(oenv, &status, ftp2fn(efTRX, NFILE, fnm), &t, &xx, boxx))
195 gmx_fatal(FARGS, "No atoms in trajectory %s", ftp2fn(efTRX, NFILE, fnm));
201 for (i = 0; i < natoms; i++)
203 copy_rvec(x[i], xx[i]);
208 for (k = 0; (k < nz); k++) /* loop over all gridpositions */
210 shift[ZZ] = k * (dist[ZZ] + box[ZZ][ZZ]);
212 for (j = 0; (j < ny); j++)
214 shift[YY] = j * (dist[YY] + box[YY][YY]) + k * box[ZZ][YY];
216 for (i = 0; (i < nx); i++)
218 shift[XX] = i * (dist[XX] + box[XX][XX]) + j * box[YY][XX] + k * box[ZZ][XX];
220 ndx = (i * ny * nz + j * nz + k) * natoms;
221 nrdx = (i * ny * nz + j * nz + k) * nres;
223 /* Random rotation on input coords */
226 rand_rot(natoms, xx, v, xrot, vrot, &rng, max_rot);
229 for (l = 0; (l < natoms); l++)
231 for (m = 0; (m < DIM); m++)
235 x[ndx + l][m] = xrot[l][m];
236 v[ndx + l][m] = vrot[l][m];
240 x[ndx + l][m] = xx[l][m];
241 v[ndx + l][m] = v[l][m];
244 if (ePBC == epbcSCREW && i % 2 == 1)
246 /* Rotate around x axis */
247 for (m = YY; m <= ZZ; m++)
249 x[ndx + l][m] = box[YY][m] + box[ZZ][m] - x[ndx + l][m];
250 v[ndx + l][m] = -v[ndx + l][m];
253 for (m = 0; (m < DIM); m++)
255 x[ndx + l][m] += shift[m];
257 atoms.atom[ndx + l].resind = nrdx + atoms.atom[l].resind;
258 atoms.atomname[ndx + l] = atoms.atomname[l];
261 for (l = 0; (l < nres); l++)
263 atoms.resinfo[nrdx + l] = atoms.resinfo[l];
266 atoms.resinfo[nrdx + l].nr += nrdx;
271 if (!read_next_x(oenv, status, &t, xx, boxx) && ((i + 1) * (j + 1) * (k + 1) < vol))
273 gmx_fatal(FARGS, "Not enough frames in trajectory");
284 /* make box bigger */
285 for (m = 0; (m < DIM); m++)
287 box[m][m] += dist[m];
289 svmul(nx, box[XX], box[XX]);
290 svmul(ny, box[YY], box[YY]);
291 svmul(nz, box[ZZ], box[ZZ]);
292 if (ePBC == epbcSCREW && nx % 2 == 0)
294 /* With an even number of boxes in x we can forgot about the screw */
298 /*depending on how you look at it, this is either a nasty hack or the way it should work*/
301 for (i = 0; i < atoms.nres; i++)
303 atoms.resinfo[i].nr = i + 1;
307 write_sto_conf(opt2fn("-o", NFILE, fnm), *mtop.name, &atoms, x, v, ePBC, box);
315 output_env_done(oenv);