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, 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.
43 #include "gromacs/commandline/pargs.h"
44 #include "gromacs/commandline/viewit.h"
45 #include "gromacs/correlationfunctions/autocorr.h"
46 #include "gromacs/fft/fft.h"
47 #include "gromacs/fileio/confio.h"
48 #include "gromacs/fileio/trx.h"
49 #include "gromacs/fileio/trxio.h"
50 #include "gromacs/fileio/xvgr.h"
51 #include "gromacs/gmxana/gmx_ana.h"
52 #include "gromacs/gmxana/gstat.h"
53 #include "gromacs/math/units.h"
54 #include "gromacs/math/utilities.h"
55 #include "gromacs/math/vec.h"
56 #include "gromacs/topology/index.h"
57 #include "gromacs/topology/topology.h"
58 #include "gromacs/utility/arraysize.h"
59 #include "gromacs/utility/fatalerror.h"
60 #include "gromacs/utility/futil.h"
61 #include "gromacs/utility/smalloc.h"
63 static void index_atom2mol(int *n
, int *index
, t_block
*mols
)
65 int nat
, i
, nmol
, mol
, j
;
73 while (index
[i
] > mols
->index
[mol
])
78 gmx_fatal(FARGS
, "Atom index out of range: %d", index
[i
]+1);
81 for (j
= mols
->index
[mol
]; j
< mols
->index
[mol
+1]; j
++)
83 if (i
>= nat
|| index
[i
] != j
)
85 gmx_fatal(FARGS
, "The index group does not consist of whole molecules");
92 fprintf(stderr
, "\nSplit group of %d atoms into %d molecules\n", nat
, nmol
);
97 static void precalc(t_topology top
, real normm
[])
103 for (i
= 0; i
< top
.mols
.nr
; i
++)
105 k
= top
.mols
.index
[i
];
106 l
= top
.mols
.index
[i
+1];
109 for (j
= k
; j
< l
; j
++)
111 mtot
+= top
.atoms
.atom
[j
].m
;
114 for (j
= k
; j
< l
; j
++)
116 normm
[j
] = top
.atoms
.atom
[j
].m
/mtot
;
123 static void calc_spectrum(int n
, real c
[], real dt
, const char *fn
,
124 gmx_output_env_t
*oenv
, gmx_bool bRecip
)
130 real nu
, omega
, recip_fac
;
133 for (i
= 0; (i
< n
); i
++)
138 if ((status
= gmx_fft_init_1d_real(&fft
, n
, GMX_FFT_FLAG_NONE
)) != 0)
140 gmx_fatal(FARGS
, "Invalid fft return status %d", status
);
142 if ((status
= gmx_fft_1d_real(fft
, GMX_FFT_REAL_TO_COMPLEX
, data
, data
)) != 0)
144 gmx_fatal(FARGS
, "Invalid fft return status %d", status
);
146 fp
= xvgropen(fn
, "Vibrational Power Spectrum",
147 bRecip
? "\\f{12}w\\f{4} (cm\\S-1\\N)" :
148 "\\f{12}n\\f{4} (ps\\S-1\\N)",
150 /* This is difficult.
151 * The length of the ACF is dt (as passed to this routine).
152 * We pass the vacf with N time steps from 0 to dt.
153 * That means that after FFT we have lowest frequency = 1/dt
154 * then 1/(2 dt) etc. (this is the X-axis of the data after FFT).
155 * To convert to 1/cm we need to have to realize that
156 * E = hbar w = h nu = h c/lambda. We want to have reciprokal cm
157 * on the x-axis, that is 1/lambda, so we then have
158 * 1/lambda = nu/c. Since nu has units of 1/ps and c has gromacs units
159 * of nm/ps, we need to multiply by 1e7.
160 * The timestep between saving the trajectory is
161 * 1e7 is to convert nanometer to cm
163 recip_fac
= bRecip
? (1e7
/SPEED_OF_LIGHT
) : 1.0;
164 for (i
= 0; (i
< n
); i
+= 2)
167 omega
= nu
*recip_fac
;
168 /* Computing the square magnitude of a complex number, since this is a power
171 fprintf(fp
, "%10g %10g\n", omega
, sqr(data
[i
])+sqr(data
[i
+1]));
174 gmx_fft_destroy(fft
);
178 int gmx_velacc(int argc
, char *argv
[])
180 const char *desc
[] = {
181 "[THISMODULE] computes the velocity autocorrelation function.",
182 "When the [TT]-m[tt] option is used, the momentum autocorrelation",
183 "function is calculated.[PAR]",
184 "With option [TT]-mol[tt] the velocity autocorrelation function of",
185 "molecules is calculated. In this case the index group should consist",
186 "of molecule numbers instead of atom numbers.[PAR]",
187 "Be sure that your trajectory contains frames with velocity information",
188 "(i.e. [TT]nstvout[tt] was set in your original [REF].mdp[ref] file),",
189 "and that the time interval between data collection points is",
190 "much shorter than the time scale of the autocorrelation."
193 static gmx_bool bMass
= FALSE
, bMol
= FALSE
, bRecip
= TRUE
;
195 { "-m", FALSE
, etBOOL
, {&bMass
},
196 "Calculate the momentum autocorrelation function" },
197 { "-recip", FALSE
, etBOOL
, {&bRecip
},
198 "Use cm^-1 on X-axis instead of 1/ps for spectra." },
199 { "-mol", FALSE
, etBOOL
, {&bMol
},
200 "Calculate the velocity acf of molecules" }
207 gmx_bool bTPS
= FALSE
, bTop
= FALSE
;
211 /* t0, t1 are the beginning and end time respectively.
212 * dt is the time step, mass is temp variable for atomic mass.
214 real t0
, t1
, dt
, mass
;
216 int counter
, n_alloc
, i
, j
, counter_dim
, k
, l
;
218 /* Array for the correlation function */
221 gmx_output_env_t
*oenv
;
226 { efTRN
, "-f", NULL
, ffREAD
},
227 { efTPS
, NULL
, NULL
, ffOPTRD
},
228 { efNDX
, NULL
, NULL
, ffOPTRD
},
229 { efXVG
, "-o", "vac", ffWRITE
},
230 { efXVG
, "-os", "spectrum", ffOPTWR
}
232 #define NFILE asize(fnm)
237 ppa
= add_acf_pargs(&npargs
, pa
);
238 if (!parse_common_args(&argc
, argv
, PCA_CAN_VIEW
| PCA_CAN_TIME
,
239 NFILE
, fnm
, npargs
, ppa
, asize(desc
), desc
, 0, NULL
, &oenv
))
246 bTPS
= ftp2bSet(efTPS
, NFILE
, fnm
) || !ftp2bSet(efNDX
, NFILE
, fnm
);
251 bTop
= read_tps_conf(ftp2fn(efTPS
, NFILE
, fnm
), &top
, &ePBC
, NULL
, NULL
, box
,
253 get_index(&top
.atoms
, ftp2fn_null(efNDX
, NFILE
, fnm
), 1, &gnx
, &index
, &grpname
);
257 rd_index(ftp2fn(efNDX
, NFILE
, fnm
), 1, &gnx
, &index
, &grpname
);
264 gmx_fatal(FARGS
, "Need a topology to determine the molecules");
266 snew(normm
, top
.atoms
.nr
);
268 index_atom2mol(&gnx
, index
, &top
.mols
);
271 /* Correlation stuff */
273 for (i
= 0; (i
< gnx
); i
++)
278 read_first_frame(oenv
, &status
, ftp2fn(efTRN
, NFILE
, fnm
), &fr
, TRX_NEED_V
);
285 if (counter
>= n_alloc
)
288 for (i
= 0; i
< gnx
; i
++)
290 srenew(c1
[i
], DIM
*n_alloc
);
293 counter_dim
= DIM
*counter
;
296 for (i
= 0; i
< gnx
; i
++)
299 k
= top
.mols
.index
[index
[i
]];
300 l
= top
.mols
.index
[index
[i
]+1];
301 for (j
= k
; j
< l
; j
++)
305 mass
= top
.atoms
.atom
[j
].m
;
311 mv_mol
[XX
] += mass
*fr
.v
[j
][XX
];
312 mv_mol
[YY
] += mass
*fr
.v
[j
][YY
];
313 mv_mol
[ZZ
] += mass
*fr
.v
[j
][ZZ
];
315 c1
[i
][counter_dim
+XX
] = mv_mol
[XX
];
316 c1
[i
][counter_dim
+YY
] = mv_mol
[YY
];
317 c1
[i
][counter_dim
+ZZ
] = mv_mol
[ZZ
];
322 for (i
= 0; i
< gnx
; i
++)
326 mass
= top
.atoms
.atom
[index
[i
]].m
;
332 c1
[i
][counter_dim
+XX
] = mass
*fr
.v
[index
[i
]][XX
];
333 c1
[i
][counter_dim
+YY
] = mass
*fr
.v
[index
[i
]][YY
];
334 c1
[i
][counter_dim
+ZZ
] = mass
*fr
.v
[index
[i
]][ZZ
];
342 while (read_next_frame(oenv
, status
, &fr
));
348 /* Compute time step between frames */
349 dt
= (t1
-t0
)/(counter
-1);
350 do_autocorr(opt2fn("-o", NFILE
, fnm
), oenv
,
352 "Momentum Autocorrelation Function" :
353 "Velocity Autocorrelation Function",
354 counter
, gnx
, c1
, dt
, eacVector
, TRUE
);
356 do_view(oenv
, opt2fn("-o", NFILE
, fnm
), "-nxy");
358 if (opt2bSet("-os", NFILE
, fnm
))
360 calc_spectrum(counter
/2, (real
*) (c1
[0]), (t1
-t0
)/2, opt2fn("-os", NFILE
, fnm
),
362 do_view(oenv
, opt2fn("-os", NFILE
, fnm
), "-nxy");
367 fprintf(stderr
, "Not enough frames in trajectory - no output generated.\n");