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-2009, The GROMACS development team,
6 * check out http://www.gromacs.org for more information.
7 * Copyright (c) 2012, by the GROMACS development team, led by
8 * David van der Spoel, Berk Hess, Erik Lindahl, and including many
9 * others, as listed in the AUTHORS file in the top-level source
10 * 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.
38 /*! \page displacements Displacement calculation routines
40 * Functions to calculate particle displacements as a function of time are
41 * defined in displacement.h.
42 * These functions allow one to easily calculate the displacement during a
43 * single pass over the trajectory.
44 * A new calculation is initialized with gmx_ana_displ_create().
45 * For each frame, gmx_ana_displ_start_frame() needs to be called, followed by
46 * a series of gmx_ana_displ_store() or a single call to
47 * gmx_ana_displ_store_array(), gmx_ana_displ_store_all() or
48 * gmx_ana_displ_store_pos().
49 * The displacements for the current frame can then be calculated with
50 * gmx_ana_displ_vector(), gmx_ana_displ_vectors() and/or
51 * gmx_ana_displ_vectors_all().
52 * These calculate the displacements from old positions to the ones on the
54 * The input frames should be evenly spaced, otherwise a fatal error is
55 * reported. A time interval can be converted to a number of steps for
56 * the calculation functions using gmx_ana_displ_time_to_steps().
57 * When the structure is no longer required, gmx_ana_displ_free() can be used
60 * The functions support calculation for dynamic selections:
61 * when storing the positions, it is possible to specify whether a particle
63 * This data is then accessible in the \p pout array returned by the
64 * calculation functions.
65 * Note that if you only call gmx_ana_displ_store() for the particles that are
66 * present, use gmx_ana_displ_store_array(), or use positions calculated without
67 * \ref POS_MASKONLY for gmx_ana_displ_store_pos(), you should ensure that you
68 * do not use the displacements for which \p pout is FALSE (the values cannot
69 * be calculated based on the provided data, and are undefined).
72 * \brief Implementation of functions in displacement.h.
84 #include <displacement.h>
88 * Internal structure used by the displacement calculation routines in
91 typedef struct gmx_ana_displpos_t
93 /** Stored position vector. */
95 /** TRUE if there is something stored. */
100 * Stores displacement calculation data and parameters.
102 * There data can be accessed only through the functions defined in
105 struct gmx_ana_displ_t
107 /** Maximum number of particles for which the displacements are calculated. */
109 /** Maximum time for which the displacements are needed. */
112 /** TRUE if no frames have been read. */
114 /** Stores the time of the first frame. */
116 /** Stores the time interval between frames. */
118 /** Stores the time of the current frame. */
120 /** Stores the index in the store for the current positions. */
123 /** Maximum number of positions to store for a particle. */
125 /** The total number of positions ever stored (can be larger than \p max_store). */
127 /** Two-dimensional array of stored positions, second index is the particle position. */
128 gmx_ana_displpos_t **p;
129 /** Pointer to the memory allocated for \p p. */
130 gmx_ana_displpos_t *palloc;
134 * \param[out] data Displacement calculation data structure pointer to
136 * \param[in] nmax Number of particles
137 * for which displacements should be calculated.
138 * \param[in] tmax Maximum interval (in same units as in the trajectory)
139 * for which displacements are required.
140 * \returns 0 on success.
142 * This function only allocates memory for the first frame;
143 * gmx_ana_displ_start_frame() allocates a sufficient amount of memory for
144 * storing all the required positions once it known the interval between
145 * the trajectory frames.
148 gmx_ana_displ_create(gmx_ana_displ_t **data, int nmax, real tmax)
164 snew(d->palloc, nmax);
173 * \param[in,out] d Displacement calculation data.
174 * \param[in] t Time for the new frame.
175 * \returns 0 on success, -1 on failure.
177 * This function should be called at the beginning of each frame for which
178 * atomic positions should be stored.
179 * It is required that the times for which this function is called are
180 * evenly spaced; otherwise, it reports a fatal error.
183 gmx_ana_displ_start_frame(gmx_ana_displ_t *d, real t)
187 /* Initialize times */
198 if (!gmx_within_tol(t - d->t, d->dt, GMX_REAL_EPS))
200 gmx_input("Trajectory not evenly spaced");
206 /* Allocate memory for all the positions once it is possible */
207 if (d->max_store == -1 && !d->bFirst)
209 d->max_store = (int)(d->tmax/d->dt + 1);
210 srenew(d->palloc, d->nmax * d->max_store);
212 snew(d->p, d->max_store);
213 for (i = 0; i < d->max_store; ++i)
215 d->p[i] = &d->palloc[d->nmax*i];
219 /* Increment the index where current positions are stored */
221 if (d->ci >= d->max_store)
226 for (i = 0; i < d->nmax; ++i)
228 d->p[d->ci][i].bPres = FALSE;
236 * \param[in] d Displacement calculation data.
237 * \param[in] time Time to convert to steps.
238 * \param[out] steps The number of steps between the frames separated by
239 * \p time, 0 if the number of steps cannot be determined.
240 * \returns 0 on success (also if \p *steps is 0), -1 on error.
242 * \p *steps is set to zero if gmx_ana_displ_start_frame() has not yet been
244 * -1 is returned if \p time is not an integer multiple of the interval
248 gmx_ana_displ_time_to_steps(gmx_ana_displ_t *d, real time, int *steps)
255 if (!gmx_within_tol(fmod(time, d->dt), 0, GMX_REAL_EPS))
257 gmx_input("Interval not multiple of trajectory time step");
260 *steps = (int)(time / d->dt + 0.5);
265 * \param[in,out] d Displacement calculation data.
266 * \param[in] id Particle ID.
267 * \param[in] x Particle position.
268 * \param[in] bPres TRUE if the particle should be marked as present.
269 * \returns 0 on success.
272 gmx_ana_displ_store(gmx_ana_displ_t *d, atom_id id, rvec x, gmx_bool bPres)
274 copy_rvec(x, d->p[d->ci][id].x);
275 d->p[d->ci][id].bPres = bPres;
280 * \param[in,out] d Displacement calculation data.
281 * \param[in] n Number of elements in the \p id and \p x arrays.
282 * \param[in] id Particle IDs.
283 * \param[in] x Particle positions.
284 * \returns 0 on success.
286 * The positions of the given \p n particles are stored, and all of them
287 * are marked as present.
290 gmx_ana_displ_store_array(gmx_ana_displ_t *d, int n, atom_id id[], rvec x[])
294 for (i = 0; i < n; ++i)
296 gmx_ana_displ_store(d, id[i], x[i], TRUE);
302 * \param[in,out] d Displacement calculation data.
303 * \param[in] id Particle IDs.
304 * \param[in] x Particle positions.
305 * \returns 0 on success.
307 * Both the \p id and \p x arrays should have
308 * \p nmax items, where \p nmax was provided for gmx_ana_displ_create(), and
309 * the \p id[i] should be either \p i or -1.
310 * If \p id[i]==-1, then that particle is marked as not present,
311 * but the position is still stored.
314 gmx_ana_displ_store_all(gmx_ana_displ_t *d, atom_id id[], rvec x[])
318 for (i = 0; i < d->nmax; ++i)
320 gmx_ana_displ_store(d, i, x[i], id[i] >= 0);
326 * \param[in,out] d Displacement calculation data.
327 * \param[in] p Particle positions.
328 * \returns 0 on success.
330 * \p p should have at most \p nmax positions, where \p nmax was provided for
331 * gmx_ana_displ_create().
332 * If \p has exactly \p nmax positions, gmx_ana_displ_store_all() is called,
333 * otherwise gmx_ana_displ_store_array() is used.
336 gmx_ana_displ_store_pos(gmx_ana_displ_t *d, gmx_ana_pos_t *p)
338 if (p->nr == d->nmax)
340 gmx_ana_displ_store_all(d, p->m.refid, p->x);
344 gmx_ana_displ_store_array(d, p->nr, p->m.refid, p->x);
350 * Finds the index in the displacement position storage array.
352 * \param[in] d Displacement calculation data.
353 * \param[in] step Calculate the index of positions \p steps back.
354 * \returns Index into the \ref gmx_ana_displ_t::p "d->p" array
355 * that contains the positions \p steps back, -1 on error.
357 * If \p step is too large, -1 is returned.
360 find_store_index(gmx_ana_displ_t *d, int step)
371 gmx_incons("Displacement requested for an interval too long");
379 * \param[in] d Displacement calculation data.
380 * \param[in] step Displacement is calculated from the location
381 * \p step steps back.
382 * \param[in] pbc Periodic boundary structure
383 * (if NULL, PBC are not used in distance calculation).
384 * \param[in] id Particle ID for which the displacement is calculated.
385 * \param[in] x Current particle position.
386 * \param[out] xout Displacement of the particle.
387 * \param[out] pout TRUE if the old particle position was marked present.
388 * If \p *pout is FALSE and the old particle position was not stored,
389 * the value of \p xout is undefined.
390 * Can be NULL, in which case the value is not stored.
391 * \return 0 on success, -1 if less than \p step frames have been
392 * stored or \p step <= 0, or EINVAL if \p step is too large.
395 gmx_ana_displ_vector(gmx_ana_displ_t *d, int step, t_pbc *pbc,
396 atom_id id, rvec x, rvec xout, gmx_bool *pout)
400 if (step >= d->nstored || step <= 0)
404 si = find_store_index(d, step);
411 *pout = d->p[si][id].bPres;
415 pbc_dx(pbc, x, d->p[si][id].x, xout);
419 rvec_sub(x, d->p[si][id].x, xout);
425 * \param[in] d Displacement calculation data.
426 * \param[in] step Displacement is calculated from the location
427 * \p step steps back.
428 * \param[in] pbc Periodic boundary structure
429 * (if NULL, PBC are not used in distance calculation).
430 * \param[in] n Number of particles for which to calculate.
431 * \param[in] id Particle IDs for which the displacement is calculated.
432 * \param[in] x Current particle positions.
433 * \param[out] xout Displacement of the particles.
434 * \param[out] pout TRUE if the old particle position was marked present.
435 * If \p pout[i] is FALSE and the old particle position was not stored,
436 * the value of \p xout[i] is undefined.
437 * Can be NULL, in which case the value is not stored.
438 * \return 0 on success, -1 if less than \p step frames have been
439 * stored or \p step <= 0, or EINVAL if \p step is too large.
442 gmx_ana_displ_vectors(gmx_ana_displ_t *d, int step, t_pbc *pbc,
443 int n, atom_id id[], rvec x[], rvec xout[], gmx_bool *pout)
447 if (step >= d->nstored || step <= 0)
451 si = find_store_index(d, step);
456 for (i = 0; i < n; ++i)
460 pout[i] = d->p[si][id[i]].bPres;
464 pbc_dx(pbc, x[i], d->p[si][id[i]].x, xout[i]);
468 rvec_sub(x[i], d->p[si][id[i]].x, xout[i]);
475 * \param[in] d Displacement calculation data.
476 * \param[in] step Displacement is calculated from the location
477 * \p step steps back.
478 * \param[in] pbc Periodic boundary structure
479 * (if NULL, PBC are not used in distance calculation).
480 * \param[in] x Current particle positions.
481 * \param[out] xout Displacement of the particles.
482 * \param[out] pout TRUE if the old particle position was marked present.
483 * If \p pout[i] is FALSE and the old particle position was not stored,
484 * the value of \p xout[i] is undefined.
485 * Can be NULL, in which case the value is not stored.
486 * \return 0 on success, -1 if less than \p step frames have been
487 * stored or \p step <= 0, or EINVAL if \p step is too large.
489 * The \p x array should have \p nmax items, where \p nmax is the one provided
490 * to init_displ_calc().
493 gmx_ana_displ_vectors_all(gmx_ana_displ_t *d, int step, t_pbc *pbc,
494 rvec x[], rvec xout[], gmx_bool *pout)
498 if (step >= d->nstored || step <= 0)
502 si = find_store_index(d, step);
507 for (i = 0; i < d->nmax; ++i)
511 pout[i] = d->p[si][i].bPres;
515 pbc_dx(pbc, x[i], d->p[si][i].x, xout[i]);
519 rvec_sub(x[i], d->p[si][i].x, xout[i]);
526 * \param[in,out] d Displacement calculation data.
528 * After the call, the pointer \p d is invalid.
531 gmx_ana_displ_free(gmx_ana_displ_t *d)