3 * This source code is part of
7 * GROningen MAchine for Chemical Simulations
9 * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
10 * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
11 * Copyright (c) 2001-2009, The GROMACS development team,
12 * check out http://www.gromacs.org for more information.
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
19 * If you want to redistribute modifications, please consider that
20 * scientific software is very special. Version control is crucial -
21 * bugs must be traceable. We will be happy to consider code for
22 * inclusion in the official distribution, but derived work must not
23 * be called official GROMACS. Details are found in the README & COPYING
24 * files - if they are missing, get the official version at www.gromacs.org.
26 * To help us fund GROMACS development, we humbly ask that you cite
27 * the papers on the package - you can find them in the top README file.
29 * For more info, check our website at http://www.gromacs.org
31 /*! \page displacements Displacement calculation routines
33 * Functions to calculate particle displacements as a function of time are
34 * defined in displacement.h.
35 * These functions allow one to easily calculate the displacement during a
36 * single pass over the trajectory.
37 * A new calculation is initialized with gmx_ana_displ_create().
38 * For each frame, gmx_ana_displ_start_frame() needs to be called, followed by
39 * a series of gmx_ana_displ_store() or a single call to
40 * gmx_ana_displ_store_array(), gmx_ana_displ_store_all() or
41 * gmx_ana_displ_store_pos().
42 * The displacements for the current frame can then be calculated with
43 * gmx_ana_displ_vector(), gmx_ana_displ_vectors() and/or
44 * gmx_ana_displ_vectors_all().
45 * These calculate the displacements from old positions to the ones on the
47 * The input frames should be evenly spaced, otherwise a fatal error is
48 * reported. A time interval can be converted to a number of steps for
49 * the calculation functions using gmx_ana_displ_time_to_steps().
50 * When the structure is no longer required, gmx_ana_displ_free() can be used
53 * The functions support calculation for dynamic selections:
54 * when storing the positions, it is possible to specify whether a particle
56 * This data is then accessible in the \p pout array returned by the
57 * calculation functions.
58 * Note that if you only call gmx_ana_displ_store() for the particles that are
59 * present, use gmx_ana_displ_store_array(), or use positions calculated without
60 * \ref POS_MASKONLY for gmx_ana_displ_store_pos(), you should ensure that you
61 * do not use the displacements for which \p pout is FALSE (the values cannot
62 * be calculated based on the provided data, and are undefined).
65 * \brief Implementation of functions in displacement.h.
77 #include <displacement.h>
81 * Internal structure used by the displacement calculation routines in
84 typedef struct gmx_ana_displpos_t
86 /** Stored position vector. */
88 /** TRUE if there is something stored. */
93 * Stores displacement calculation data and parameters.
95 * There data can be accessed only through the functions defined in
98 struct gmx_ana_displ_t
100 /** Maximum number of particles for which the displacements are calculated. */
102 /** Maximum time for which the displacements are needed. */
105 /** TRUE if no frames have been read. */
107 /** Stores the time of the first frame. */
109 /** Stores the time interval between frames. */
111 /** Stores the time of the current frame. */
113 /** Stores the index in the store for the current positions. */
116 /** Maximum number of positions to store for a particle. */
118 /** The total number of positions ever stored (can be larger than \p max_store). */
120 /** Two-dimensional array of stored positions, second index is the particle position. */
121 gmx_ana_displpos_t **p;
122 /** Pointer to the memory allocated for \p p. */
123 gmx_ana_displpos_t *palloc;
127 * \param[out] data Displacement calculation data structure pointer to
129 * \param[in] nmax Number of particles
130 * for which displacements should be calculated.
131 * \param[in] tmax Maximum interval (in same units as in the trajectory)
132 * for which displacements are required.
133 * \returns 0 on success.
135 * This function only allocates memory for the first frame;
136 * gmx_ana_displ_start_frame() allocates a sufficient amount of memory for
137 * storing all the required positions once it known the interval between
138 * the trajectory frames.
141 gmx_ana_displ_create(gmx_ana_displ_t **data, int nmax, real tmax)
157 snew(d->palloc, nmax);
166 * \param[in,out] d Displacement calculation data.
167 * \param[in] t Time for the new frame.
168 * \returns 0 on success, -1 on failure.
170 * This function should be called at the beginning of each frame for which
171 * atomic positions should be stored.
172 * It is required that the times for which this function is called are
173 * evenly spaced; otherwise, it reports a fatal error.
176 gmx_ana_displ_start_frame(gmx_ana_displ_t *d, real t)
180 /* Initialize times */
191 if (!gmx_within_tol(t - d->t, d->dt, GMX_REAL_EPS))
193 gmx_input("Trajectory not evenly spaced");
199 /* Allocate memory for all the positions once it is possible */
200 if (d->max_store == -1 && !d->bFirst)
202 d->max_store = (int)(d->tmax/d->dt + 1);
203 srenew(d->palloc, d->nmax * d->max_store);
205 snew(d->p, d->max_store);
206 for (i = 0; i < d->max_store; ++i)
208 d->p[i] = &d->palloc[d->nmax*i];
212 /* Increment the index where current positions are stored */
214 if (d->ci >= d->max_store)
219 for (i = 0; i < d->nmax; ++i)
221 d->p[d->ci][i].bPres = FALSE;
229 * \param[in] d Displacement calculation data.
230 * \param[in] time Time to convert to steps.
231 * \param[out] steps The number of steps between the frames separated by
232 * \p time, 0 if the number of steps cannot be determined.
233 * \returns 0 on success (also if \p *steps is 0), -1 on error.
235 * \p *steps is set to zero if gmx_ana_displ_start_frame() has not yet been
237 * -1 is returned if \p time is not an integer multiple of the interval
241 gmx_ana_displ_time_to_steps(gmx_ana_displ_t *d, real time, int *steps)
248 if (!gmx_within_tol(fmod(time, d->dt), 0, GMX_REAL_EPS))
250 gmx_input("Interval not multiple of trajectory time step");
253 *steps = (int)(time / d->dt + 0.5);
258 * \param[in,out] d Displacement calculation data.
259 * \param[in] id Particle ID.
260 * \param[in] x Particle position.
261 * \param[in] bPres TRUE if the particle should be marked as present.
262 * \returns 0 on success.
265 gmx_ana_displ_store(gmx_ana_displ_t *d, atom_id id, rvec x, gmx_bool bPres)
267 copy_rvec(x, d->p[d->ci][id].x);
268 d->p[d->ci][id].bPres = bPres;
273 * \param[in,out] d Displacement calculation data.
274 * \param[in] n Number of elements in the \p id and \p x arrays.
275 * \param[in] id Particle IDs.
276 * \param[in] x Particle positions.
277 * \returns 0 on success.
279 * The positions of the given \p n particles are stored, and all of them
280 * are marked as present.
283 gmx_ana_displ_store_array(gmx_ana_displ_t *d, int n, atom_id id[], rvec x[])
287 for (i = 0; i < n; ++i)
289 gmx_ana_displ_store(d, id[i], x[i], TRUE);
295 * \param[in,out] d Displacement calculation data.
296 * \param[in] id Particle IDs.
297 * \param[in] x Particle positions.
298 * \returns 0 on success.
300 * Both the \p id and \p x arrays should have
301 * \p nmax items, where \p nmax was provided for gmx_ana_displ_create(), and
302 * the \p id[i] should be either \p i or -1.
303 * If \p id[i]==-1, then that particle is marked as not present,
304 * but the position is still stored.
307 gmx_ana_displ_store_all(gmx_ana_displ_t *d, atom_id id[], rvec x[])
311 for (i = 0; i < d->nmax; ++i)
313 gmx_ana_displ_store(d, i, x[i], id[i] >= 0);
319 * \param[in,out] d Displacement calculation data.
320 * \param[in] p Particle positions.
321 * \returns 0 on success.
323 * \p p should have at most \p nmax positions, where \p nmax was provided for
324 * gmx_ana_displ_create().
325 * If \p has exactly \p nmax positions, gmx_ana_displ_store_all() is called,
326 * otherwise gmx_ana_displ_store_array() is used.
329 gmx_ana_displ_store_pos(gmx_ana_displ_t *d, gmx_ana_pos_t *p)
331 if (p->nr == d->nmax)
333 gmx_ana_displ_store_all(d, p->m.refid, p->x);
337 gmx_ana_displ_store_array(d, p->nr, p->m.refid, p->x);
343 * Finds the index in the displacement position storage array.
345 * \param[in] d Displacement calculation data.
346 * \param[in] step Calculate the index of positions \p steps back.
347 * \returns Index into the \ref gmx_ana_displ_t::p "d->p" array
348 * that contains the positions \p steps back, -1 on error.
350 * If \p step is too large, -1 is returned.
353 find_store_index(gmx_ana_displ_t *d, int step)
364 gmx_incons("Displacement requested for an interval too long");
372 * \param[in] d Displacement calculation data.
373 * \param[in] step Displacement is calculated from the location
374 * \p step steps back.
375 * \param[in] pbc Periodic boundary structure
376 * (if NULL, PBC are not used in distance calculation).
377 * \param[in] id Particle ID for which the displacement is calculated.
378 * \param[in] x Current particle position.
379 * \param[out] xout Displacement of the particle.
380 * \param[out] pout TRUE if the old particle position was marked present.
381 * If \p *pout is FALSE and the old particle position was not stored,
382 * the value of \p xout is undefined.
383 * Can be NULL, in which case the value is not stored.
384 * \return 0 on success, -1 if less than \p step frames have been
385 * stored or \p step <= 0, or EINVAL if \p step is too large.
388 gmx_ana_displ_vector(gmx_ana_displ_t *d, int step, t_pbc *pbc,
389 atom_id id, rvec x, rvec xout, gmx_bool *pout)
393 if (step >= d->nstored || step <= 0)
397 si = find_store_index(d, step);
404 *pout = d->p[si][id].bPres;
408 pbc_dx(pbc, x, d->p[si][id].x, xout);
412 rvec_sub(x, d->p[si][id].x, xout);
418 * \param[in] d Displacement calculation data.
419 * \param[in] step Displacement is calculated from the location
420 * \p step steps back.
421 * \param[in] pbc Periodic boundary structure
422 * (if NULL, PBC are not used in distance calculation).
423 * \param[in] n Number of particles for which to calculate.
424 * \param[in] id Particle IDs for which the displacement is calculated.
425 * \param[in] x Current particle positions.
426 * \param[out] xout Displacement of the particles.
427 * \param[out] pout TRUE if the old particle position was marked present.
428 * If \p pout[i] is FALSE and the old particle position was not stored,
429 * the value of \p xout[i] is undefined.
430 * Can be NULL, in which case the value is not stored.
431 * \return 0 on success, -1 if less than \p step frames have been
432 * stored or \p step <= 0, or EINVAL if \p step is too large.
435 gmx_ana_displ_vectors(gmx_ana_displ_t *d, int step, t_pbc *pbc,
436 int n, atom_id id[], rvec x[], rvec xout[], gmx_bool *pout)
440 if (step >= d->nstored || step <= 0)
444 si = find_store_index(d, step);
449 for (i = 0; i < n; ++i)
453 pout[i] = d->p[si][id[i]].bPres;
457 pbc_dx(pbc, x[i], d->p[si][id[i]].x, xout[i]);
461 rvec_sub(x[i], d->p[si][id[i]].x, xout[i]);
468 * \param[in] d Displacement calculation data.
469 * \param[in] step Displacement is calculated from the location
470 * \p step steps back.
471 * \param[in] pbc Periodic boundary structure
472 * (if NULL, PBC are not used in distance calculation).
473 * \param[in] x Current particle positions.
474 * \param[out] xout Displacement of the particles.
475 * \param[out] pout TRUE if the old particle position was marked present.
476 * If \p pout[i] is FALSE and the old particle position was not stored,
477 * the value of \p xout[i] is undefined.
478 * Can be NULL, in which case the value is not stored.
479 * \return 0 on success, -1 if less than \p step frames have been
480 * stored or \p step <= 0, or EINVAL if \p step is too large.
482 * The \p x array should have \p nmax items, where \p nmax is the one provided
483 * to init_displ_calc().
486 gmx_ana_displ_vectors_all(gmx_ana_displ_t *d, int step, t_pbc *pbc,
487 rvec x[], rvec xout[], gmx_bool *pout)
491 if (step >= d->nstored || step <= 0)
495 si = find_store_index(d, step);
500 for (i = 0; i < d->nmax; ++i)
504 pout[i] = d->p[si][i].bPres;
508 pbc_dx(pbc, x[i], d->p[si][i].x, xout[i]);
512 rvec_sub(x[i], d->p[si][i].x, xout[i]);
519 * \param[in,out] d Displacement calculation data.
521 * After the call, the pointer \p d is invalid.
524 gmx_ana_displ_free(gmx_ana_displ_t *d)