21e4ea67c5d40cb04720ab6177959d638a230298
[alexxy/gromacs.git] / src / gmxlib / trajana / poscalc.c
1 /*
2  *
3  *                This source code is part of
4  *
5  *                 G   R   O   M   A   C   S
6  *
7  *          GROningen MAchine for Chemical Simulations
8  *
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.
13
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.
18  *
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.
25  *
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.
28  *
29  * For more info, check our website at http://www.gromacs.org
30  */
31 /*! \internal
32  * \page poscalcengine Position calculation engine
33  *
34  * The header file \ref poscalc.h defines an API for calculating positions
35  * in an automated way. This is useful mostly in the selection engine, in
36  * particular with dynamic selections, because the same COM/COG positions
37  * may be needed in several contexts. The API makes it possible to
38  * optimize the evaluation such that any heavy calculation is only done once,
39  * and the results just copied if needed more than once.
40  * The functions also provide a convenient interface for keeping the whole
41  * \c gmx_ana_pos_t structure up-to-date.
42  *
43  * A new collection of position calculations is allocated with
44  * gmx_ana_poscalc_coll_create().
45  * Calculations within one collection should share the same topology, and
46  * they are optimized. Calculations in different collections do not interact.
47  * The topology for a collection can be set with
48  * gmx_ana_poscalc_coll_set_topology().
49  * This needs to be done before calling gmx_ana_poscalc_set_maxindex() for
50  * any calculation in the collection, unless that calculation does not
51  * require topology information.
52  * All memory allocated for a collection and the calculations in it can be
53  * freed with gmx_ana_poscalc_coll_free().
54  *
55  * A new calculation is created with gmx_ana_poscalc_create().
56  * If flags need to be adjusted later, gmx_ana_poscalc_set_flags() can be
57  * used.
58  * After the flags are final, the largest possible index group for which the
59  * positions are needed has to be set with gmx_ana_poscalc_set_maxindex().
60  * gmx_ana_poscalc_coll_set_topology() should have been called before this
61  * function is called.
62  * After the above calls, gmx_ana_poscalc_init_pos() can be used to initialize
63  * output to a \c gmx_ana_pos_t structure. Several different structures can be
64  * initialized for the same calculation; the only requirement is that the
65  * structure passed later to gmx_ana_poscalc_update() has been initialized
66  * properly.
67  * The memory allocated for a calculation can be freed with
68  * gmx_ana_poscalc_free().
69  *
70  * The position evaluation is simple: gmx_ana_poscalc_init_frame() should be
71  * called once for each frame, and gmx_ana_poscalc_update() can then be called
72  * for each calculation that is needed for that frame.
73  *
74  * It is also possible to initialize the calculations based on a type provided
75  * as a string.
76  * The possible strings are returned by gmx_ana_poscalc_create_type_enum(),
77  * and the string can be converted to the parameters for
78  * gmx_ana_poscalc_create() using gmx_ana_poscalc_type_from_enum().
79  * gmx_ana_poscalc_create_enum() is also provided for convenience.
80  */
81 /*! \internal \file
82  * \brief Implementation of functions in poscalc.h.
83  *
84  * \todo
85  * There is probably some room for optimization in the calculation of
86  * positions with bases.
87  * In particular, the current implementation may do a lot of unnecessary
88  * copying.
89  * The interface would need to be changed to make it possible to use the
90  * same output positions for several calculations.
91  *
92  * \todo
93  * The current algorithm for setting up base calculations could be improved
94  * in cases when there are calculations that cannot use a common base but
95  * still overlap partially (e.g., with three calculations A, B, and C
96  * such that A could use both B and C as a base, but B and C cannot use the
97  * same base).
98  * Setting up the bases in an optimal manner in every possible situation can
99  * be quite difficult unless several bases are allowed for one calculation,
100  * but better heuristics could probably be implemented.
101  * For best results, the setup should probably be postponed (at least
102  * partially) to gmx_ana_poscalc_init_eval().
103  */
104 #ifdef HAVE_CONFIG_H
105 #include <config.h>
106 #endif
107
108 #include <string.h>
109
110 #include <macros.h>
111 #include <smalloc.h>
112 #include <typedefs.h>
113 #include <pbc.h>
114 #include <vec.h>
115
116 #include <centerofmass.h>
117 #include <indexutil.h>
118 #include <poscalc.h>
119 #include <position.h>
120
121 /*! \internal \brief
122  * Collection of \c gmx_ana_poscalc_t structures for the same topology.
123  *
124  * Calculations within the same structure are optimized to eliminate duplicate
125  * calculations.
126  */
127 struct gmx_ana_poscalc_coll_t
128 {
129     /*! \brief
130      * Topology data.
131      *
132      * Can be NULL if none of the calculations require topology data or if
133      * gmx_ana_poscalc_coll_set_topology() has not been called.
134      */
135     t_topology               *top;
136     /** Pointer to the first data structure. */
137     gmx_ana_poscalc_t        *first;
138     /** Pointer to the last data structure. */
139     gmx_ana_poscalc_t        *last;
140     /** Whether the collection has been initialized for evaluation. */
141     bool                      bInit;
142 };
143
144 /*! \internal \brief
145  * Data structure for position calculation.
146  */
147 struct gmx_ana_poscalc_t
148 {
149     /*! \brief
150      * Type of calculation.
151      *
152      * This field may differ from the type requested by the user, because
153      * it is changed internally to the most effective calculation.
154      * For example, if the user requests a COM calculation for residues
155      * consisting of single atoms, it is simply set to POS_ATOM.
156      * To provide a consistent interface to the user, the field \p itype
157      * should be used when information should be given out.
158      */
159     e_poscalc_t               type;
160     /*! \brief
161      * Flags for calculation options.
162      *
163      * See \ref poscalc_flags "documentation of the flags".
164      */
165     int                       flags;
166
167     /*! \brief
168      * Type for the created indices.
169      *
170      * This field always agrees with the type that the user requested, but
171      * may differ from \p type.
172      */
173     e_index_t                 itype;
174     /*! \brief
175      * Block data for the calculation.
176      */
177     t_blocka                  b;
178     /*! \brief
179      * Mapping from the blocks to the blocks of \p sbase.
180      *
181      * If \p sbase is NULL, this field is also.
182      */
183     int                      *baseid;
184     /*! \brief
185      * Maximum evaluation group.
186      */
187     gmx_ana_index_t           gmax;
188
189     /** Position storage for calculations that are used as a base. */
190     gmx_ana_pos_t            *p;
191
192     /** TRUE if the positions have been evaluated for the current frame. */
193     bool                      bEval;
194     /*! \brief
195      * Base position data for this calculation.
196      *
197      * If not NULL, the centers required by this calculation have
198      * already been calculated in \p sbase.
199      * The structure pointed by \p sbase is always a static calculation.
200      */
201     struct gmx_ana_poscalc_t *sbase;
202     /** Next structure in the linked list of calculations. */
203     struct gmx_ana_poscalc_t *next;
204     /** Previous structure in the linked list of calculations. */
205     struct gmx_ana_poscalc_t *prev;
206     /** Number of references to this structure. */
207     int                       refcount;
208     /** Collection this calculation belongs to. */
209     gmx_ana_poscalc_coll_t   *coll;
210 };
211     
212 static const char *const poscalc_enum_strings[] = {
213     "atom",
214     "res_com",       "res_cog",
215     "mol_com",       "mol_cog",
216     "whole_res_com", "whole_res_cog",
217     "whole_mol_com", "whole_mol_cog",
218     "part_res_com",  "part_res_cog",
219     "part_mol_com",  "part_mol_cog",
220     "dyn_res_com",   "dyn_res_cog",
221     "dyn_mol_com",   "dyn_mol_cog",
222     NULL,
223 };
224 #define NENUM asize(poscalc_enum_strings)
225
226 /*! \brief
227  * Returns the partition type for a given position type.
228  *
229  * \param [in] type  \c e_poscalc_t value to convert.
230  * \returns    Corresponding \c e_indet_t.
231  */
232 static e_index_t
233 index_type_for_poscalc(e_poscalc_t type)
234 {
235     switch(type)
236     {
237         case POS_ATOM:    return INDEX_ATOM;
238         case POS_RES:     return INDEX_RES;
239         case POS_MOL:     return INDEX_MOL;
240         case POS_ALL:     return INDEX_ALL;
241         case POS_ALL_PBC: return INDEX_ALL;
242     }
243     return INDEX_UNKNOWN;
244 }
245
246 /*!
247  * \param[in]     post  String (typically an enum command-line argument).
248  *   Allowed values: 'atom', 'res_com', 'res_cog', 'mol_com', 'mol_cog',
249  *   or one of the last four prepended by 'whole_', 'part_', or 'dyn_'.
250  * \param[out]    type  \c e_poscalc_t corresponding to \p post.
251  * \param[in,out] flags Flags corresponding to \p post.
252  *   On input, the flags should contain the default flags.
253  *   On exit, the flags \ref POS_MASS, \ref POS_COMPLMAX and
254  *   \ref POS_COMPLWHOLE have been set according to \p post
255  *   (the completion flags are left at the default values if no completion
256  *   prefix is given).
257  * \returns       0 if \p post is one of the valid strings, EINVAL otherwise.
258  *
259  * \attention
260  * Checking is not complete, and other values than those listed above
261  * may be accepted for \p post, but the results are undefined.
262  */
263 int
264 gmx_ana_poscalc_type_from_enum(const char *post, e_poscalc_t *type, int *flags)
265 {
266     const char *ptr;
267
268     if (post[0] == 'a')
269     {
270         *type   = POS_ATOM;
271         *flags &= ~(POS_MASS | POS_COMPLMAX | POS_COMPLWHOLE);
272         return 0;
273     }
274
275     /* Process the prefix */
276     ptr = post;
277     if (post[0] == 'w')
278     {
279         *flags &= ~POS_COMPLMAX;
280         *flags |= POS_COMPLWHOLE;
281         ptr = post + 6;
282     }
283     else if (post[0] == 'p')
284     {
285         *flags &= ~POS_COMPLWHOLE;
286         *flags |= POS_COMPLMAX;
287         ptr = post + 5;
288     }
289     else if (post[0] == 'd')
290     {
291         *flags &= ~(POS_COMPLMAX | POS_COMPLWHOLE);
292         ptr = post + 4;
293     }
294
295     if (ptr[0] == 'r')
296     {
297         *type = POS_RES;
298     }
299     else if (ptr[0] == 'm')
300     {
301         *type = POS_MOL;
302     }
303     else
304     {
305         gmx_incons("unknown position calculation type");
306         return EINVAL;
307     }
308     if (ptr[6] == 'm')
309     {
310         *flags |= POS_MASS;
311     }
312     else if (ptr[6] == 'g')
313     {
314         *flags &= ~POS_MASS;
315     }
316     else
317     {
318         gmx_incons("unknown position calculation type");
319         return EINVAL;
320     }
321     return 0;
322 }
323
324 /*!
325  * \param[in]  bAtom    If TRUE, the "atom" value is included.
326  * \returns    NULL-terminated array of strings that contains the string
327  *   values acceptable for gmx_ana_poscalc_type_from_enum().
328  *
329  * The first string in the returned list is always NULL to allow the list to
330  * be used with Gromacs command-line parsing.
331  */
332 const char **
333 gmx_ana_poscalc_create_type_enum(bool bAtom)
334 {
335     const char **pcenum;
336     size_t       i;
337
338     if (bAtom)
339     {
340         snew(pcenum, NENUM+1);
341         for (i = 0; i < NENUM; ++i)
342         {
343             pcenum[i+1] = poscalc_enum_strings[i];
344         }
345     }
346     else
347     {
348         snew(pcenum, NENUM+1-1);
349         for (i = 1; i < NENUM; ++i)
350         {
351             pcenum[i] = poscalc_enum_strings[i];
352         }
353     }
354     pcenum[0] = NULL;
355     return pcenum;
356 }
357
358 /*!
359  * \param[out] pccp   Allocated position calculation collection.
360  * \returns    0 for success.
361  */
362 int
363 gmx_ana_poscalc_coll_create(gmx_ana_poscalc_coll_t **pccp)
364 {
365     gmx_ana_poscalc_coll_t *pcc;
366
367     snew(pcc, 1);
368     pcc->top   = NULL;
369     pcc->first = NULL;
370     pcc->last  = NULL;
371     pcc->bInit = FALSE;
372     *pccp = pcc;
373     return 0;
374 }
375
376 /*!
377  * \param[in,out] pcc   Position calculation collection data structure.
378  * \param[in]     top   Topology data structure.
379  *
380  * This function should be called to set the topology before using
381  * gmx_ana_poscalc_set_maxindex() for any calculation that requires
382  * topology information.
383  */
384 void
385 gmx_ana_poscalc_coll_set_topology(gmx_ana_poscalc_coll_t *pcc, t_topology *top)
386 {
387     pcc->top = top;
388 }
389
390 /*!
391  * \param[in] pcc   Position calculation collection to free.
392  *
393  * The pointer \p pcc is invalid after the call.
394  * Any calculations in the collection are also freed, no matter how many
395  * references to them are left.
396  */
397 void
398 gmx_ana_poscalc_coll_free(gmx_ana_poscalc_coll_t *pcc)
399 {
400     while (pcc->first)
401     {
402         gmx_ana_poscalc_free(pcc->first);
403     }
404     sfree(pcc);
405 }
406
407 /*!
408  * \param[in] fp    File handle to receive the output.
409  * \param[in] pcc   Position calculation collection to print.
410  *
411  * The output is very technical, making this function mainly useful for
412  * debugging purposes.
413  */
414 void
415 gmx_ana_poscalc_coll_print_tree(FILE *fp, gmx_ana_poscalc_coll_t *pcc)
416 {
417     gmx_ana_poscalc_t *pc;
418     int                i, j;
419
420     fprintf(fp, "Position calculations:\n");
421     i  = 1;
422     pc = pcc->first;
423     while (pc)
424     {
425         fprintf(fp, "%2d ", i);
426         switch (pc->type)
427         {
428             case POS_ATOM:    fprintf(fp, "ATOM");    break;
429             case POS_RES:     fprintf(fp, "RES");     break;
430             case POS_MOL:     fprintf(fp, "MOL");     break;
431             case POS_ALL:     fprintf(fp, "ALL");     break;
432             case POS_ALL_PBC: fprintf(fp, "ALL_PBC"); break;
433         }
434         if (pc->itype != index_type_for_poscalc(pc->type))
435         {
436             fprintf(fp, " (");
437             switch (pc->itype)
438             {
439                 case INDEX_UNKNOWN: fprintf(fp, "???");  break;
440                 case INDEX_ATOM:    fprintf(fp, "ATOM"); break;
441                 case INDEX_RES:     fprintf(fp, "RES");  break;
442                 case INDEX_MOL:     fprintf(fp, "MOL");  break;
443                 case INDEX_ALL:     fprintf(fp, "ALL");  break;
444             }
445             fprintf(fp, ")");
446         }
447         fprintf(fp, " flg=");
448         if (pc->flags & POS_MASS)
449         {
450             fprintf(fp, "M");
451         }
452         if (pc->flags & POS_DYNAMIC)
453         {
454             fprintf(fp, "D");
455         }
456         if (pc->flags & POS_MASKONLY)
457         {
458             fprintf(fp, "A");
459         }
460         if (pc->flags & POS_COMPLMAX)
461         {
462             fprintf(fp, "Cm");
463         }
464         if (pc->flags & POS_COMPLWHOLE)
465         {
466             fprintf(fp, "Cw");
467         }
468         if (!pc->flags)
469         {
470             fprintf(fp, "0");
471         }
472         fprintf(fp, " nr=%d nra=%d", pc->b.nr, pc->b.nra);
473         fprintf(fp, " refc=%d", pc->refcount);
474         fprintf(fp, "\n");
475         if (pc->gmax.nalloc_index > 0)
476         {
477             fprintf(fp, "   Group: ");
478             if (pc->gmax.isize > 20)
479             {
480                 fprintf(fp, " %d atoms", pc->gmax.isize);
481             }
482             else
483             {
484                 for (j = 0; j < pc->gmax.isize; ++j)
485                 {
486                     fprintf(fp, " %d", pc->gmax.index[j] + 1);
487                 }
488             }
489             fprintf(fp, "\n");
490         }
491         if (pc->b.nalloc_a > 0)
492         {
493             fprintf(fp, "   Atoms: ");
494             if (pc->b.nra > 20)
495             {
496                 fprintf(fp, " %d atoms", pc->b.nra);
497             }
498             else
499             {
500                 for (j = 0; j < pc->b.nra; ++j)
501                 {
502                     fprintf(fp, " %d", pc->b.a[j] + 1);
503                 }
504             }
505             fprintf(fp, "\n");
506         }
507         if (pc->b.nalloc_index > 0)
508         {
509             fprintf(fp, "   Blocks:");
510             if (pc->b.nr > 20)
511             {
512                 fprintf(fp, " %d pcs", pc->b.nr);
513             }
514             else
515             {
516                 for (j = 0; j <= pc->b.nr; ++j)
517                 {
518                     fprintf(fp, " %d", pc->b.index[j]);
519                 }
520             }
521             fprintf(fp, "\n");
522         }
523         if (pc->sbase)
524         {
525             gmx_ana_poscalc_t *base;
526
527             fprintf(fp, "   Base: ");
528             j = 1;
529             base = pcc->first;
530             while (base && base != pc->sbase)
531             {
532                 ++j;
533                 base = base->next;
534             }
535             fprintf(fp, "%d", j);
536             if (pc->baseid && pc->b.nr <= 20)
537             {
538                 fprintf(fp, " id:");
539                 for (j = 0; j < pc->b.nr; ++j)
540                 {
541                     fprintf(fp, " %d", pc->baseid[j]+1);
542                 }
543             }
544             fprintf(fp, "\n");
545         }
546         ++i;
547         pc = pc->next;
548     }
549 }
550
551 /*! \brief
552  * Inserts a position calculation structure into its collection.
553  *
554  * \param pc     Data structure to insert.
555  * \param before Data structure before which to insert
556  *   (NULL = insert at end).
557  *
558  * Inserts \p pc to its collection before \p before.
559  * If \p before is NULL, \p pc is appended to the list.
560  */
561 static void
562 insert_poscalc(gmx_ana_poscalc_t *pc, gmx_ana_poscalc_t *before)
563 {
564     if (before == NULL)
565     {
566         pc->next = NULL;
567         pc->prev = pc->coll->last;
568         if (pc->coll->last)
569         {
570             pc->coll->last->next = pc;
571         }
572         pc->coll->last = pc;
573     }
574     else
575     {
576         pc->prev     = before->prev;
577         pc->next     = before;
578         if (before->prev)
579         {
580             before->prev->next = pc;
581         }
582         before->prev = pc;
583     }
584     if (!pc->prev)
585     {
586         pc->coll->first = pc;
587     }
588 }
589
590 /*! \brief
591  * Removes a position calculation structure from its collection.
592  *
593  * \param pc    Data structure to remove.
594  *
595  * Removes \p pc from its collection.
596  */
597 static void
598 remove_poscalc(gmx_ana_poscalc_t *pc)
599 {
600     if (pc->prev)
601     {
602         pc->prev->next = pc->next;
603     }
604     else if (pc == pc->coll->first)
605     {
606         pc->coll->first = pc->next;
607     }
608     if (pc->next)
609     {
610         pc->next->prev = pc->prev;
611     }
612     else if (pc == pc->coll->last)
613     {
614         pc->coll->last = pc->prev;
615     }
616     pc->prev = pc->next = NULL;
617 }
618
619 /*! \brief
620  * Initializes position calculation using the maximum possible input index.
621  *
622  * \param[in,out] pc  Position calculation data structure.
623  * \param[in]     g   Maximum index group for the calculation.
624  * \param[in]     bBase Whether \p pc will be used as a base or not.
625  *
626  * \p bBase affects on how the \p pc->gmax field is initialized.
627  */
628 static void
629 set_poscalc_maxindex(gmx_ana_poscalc_t *pc, gmx_ana_index_t *g, bool bBase)
630 {
631     gmx_ana_index_make_block(&pc->b, pc->coll->top, g, pc->itype, pc->flags & POS_COMPLWHOLE);
632     /* Set the type to POS_ATOM if the calculation in fact is such. */
633     if (pc->b.nr == pc->b.nra)
634     {
635         pc->type   = POS_ATOM; 
636         pc->flags &= ~(POS_MASS | POS_COMPLMAX | POS_COMPLWHOLE);
637     }
638     /* Set the POS_COMPLWHOLE flag if the calculation in fact always uses
639      * complete residues and molecules. */
640     if (!(pc->flags & POS_COMPLWHOLE)
641         && (!(pc->flags & POS_DYNAMIC) || (pc->flags & POS_COMPLMAX))
642         && (pc->type == POS_RES || pc->type == POS_MOL)
643         && gmx_ana_index_has_complete_elems(g, pc->itype, pc->coll->top))
644     {
645         pc->flags &= ~POS_COMPLMAX;
646         pc->flags |= POS_COMPLWHOLE;
647     }
648     /* Setup the gmax field */
649     if ((pc->flags & POS_COMPLWHOLE) && !bBase && pc->b.nra > g->isize)
650     {
651         gmx_ana_index_copy(&pc->gmax, g, TRUE);
652         sfree(pc->gmax.name);
653         pc->gmax.name  = NULL;
654     }
655     else
656     {
657         gmx_ana_index_set(&pc->gmax, pc->b.nra, pc->b.a, NULL, 0);
658     }
659 }
660
661 /*! \brief
662  * Checks whether a position calculation should use a base at all.
663  *
664  * \param[in] pc   Position calculation data to check.
665  * \returns   TRUE if \p pc can use a base and gets some benefit out of it,
666  *   FALSE otherwise.
667  */
668 static bool
669 can_use_base(gmx_ana_poscalc_t *pc)
670 {
671     /* For atoms, it should be faster to do a simple copy, so don't use a
672      * base. */
673     if (pc->type == POS_ATOM)
674     {
675         return FALSE;
676     }
677     /* For dynamic selections that do not use completion, it is not possible
678      * to use a base. */
679     if ((pc->type == POS_RES || pc->type == POS_MOL)
680         && (pc->flags & POS_DYNAMIC) && !(pc->flags & (POS_COMPLMAX | POS_COMPLWHOLE)))
681     {
682         return FALSE;
683     }
684     /* Dynamic calculations for a single position cannot use a base. */
685     if ((pc->type == POS_ALL || pc->type == POS_ALL_PBC)
686         && (pc->flags & POS_DYNAMIC))
687     {
688         return FALSE;
689     }
690     return TRUE;
691 }
692
693 /*! \brief
694  * Checks whether two position calculations should use a common base.
695  *
696  * \param[in]     pc1 Calculation 1 to check for.
697  * \param[in]     pc2 Calculation 2 to check for.
698  * \param[in]     g1  Index group structure that contains the atoms from
699  *   \p pc1.
700  * \param[in,out] g   Working space, should have enough allocated memory to
701  *   contain the intersection of the atoms in \p pc1 and \p pc2.
702  * \returns   TRUE if the two calculations should be merged to use a common
703  *   base, FALSE otherwise.
704  */
705 static bool
706 should_merge(gmx_ana_poscalc_t *pc1, gmx_ana_poscalc_t *pc2,
707              gmx_ana_index_t *g1, gmx_ana_index_t *g)
708 {
709     gmx_ana_index_t  g2;
710
711     /* Do not merge calculations with different mass weighting. */
712     if ((pc1->flags & POS_MASS) != (pc2->flags & POS_MASS))
713     {
714         return FALSE;
715     }
716     /* Avoid messing up complete calculations. */
717     if ((pc1->flags & POS_COMPLWHOLE) != (pc2->flags & POS_COMPLWHOLE))
718     {
719         return FALSE;
720     }
721     /* Find the overlap between the calculations. */
722     gmx_ana_index_set(&g2, pc2->b.nra, pc2->b.a, NULL, 0);
723     gmx_ana_index_intersection(g, g1, &g2);
724     /* Do not merge if there is no overlap. */
725     if (g->isize == 0)
726     {
727         return FALSE;
728     }
729     /* Full completion calculations always match if the type is correct. */
730     if ((pc1->flags & POS_COMPLWHOLE) && (pc2->flags & POS_COMPLWHOLE)
731         && pc1->type == pc2->type)
732     {
733         return TRUE;
734     }
735     /* The calculations also match if the intersection consists of full
736      * blocks. */
737     if (gmx_ana_index_has_full_ablocks(g, &pc1->b)
738         && gmx_ana_index_has_full_ablocks(g, &pc2->b))
739     {
740         return TRUE;
741     }
742     return FALSE;
743 }
744
745 /*! \brief
746  * Creates a static base for position calculation.
747  *
748  * \param     pc  Data structure to copy.
749  * \returns   Pointer to a newly allocated base for \p pc.
750  *
751  * Creates and returns a deep copy of \p pc, but clears the
752  * \ref POS_DYNAMIC and \ref POS_MASKONLY flags.
753  * The newly created structure is set as the base (\c gmx_ana_poscalc_t::sbase)
754  * of \p pc and inserted in the collection before \p pc.
755  */
756 static gmx_ana_poscalc_t *
757 create_simple_base(gmx_ana_poscalc_t *pc)
758 {
759     gmx_ana_poscalc_t *base;
760     int                flags;
761     int                rc;
762
763     flags = pc->flags & ~(POS_DYNAMIC | POS_MASKONLY);
764     rc = gmx_ana_poscalc_create(&base, pc->coll, pc->type, flags);
765     if (rc != 0)
766     {
767         gmx_fatal(FARGS, "position calculation base creation failed");
768     }
769     set_poscalc_maxindex(base, &pc->gmax, TRUE);
770
771     snew(base->p, 1);
772
773     pc->sbase = base;
774     remove_poscalc(base);
775     insert_poscalc(base, pc);
776
777     return base;
778 }
779
780 /*! \brief
781  * Merges a calculation into another calculation such that the new calculation
782  * can be used as a base.
783  *
784  * \param[in,out] base Base calculation to merge to.
785  * \param[in,out] pc   Position calculation to merge to \p base.
786  *
787  * After the call, \p base can be used as a base for \p pc (or any calculation
788  * that used it as a base).
789  * It is assumed that any overlap between \p base and \p pc is in complete
790  * blocks, i.e., that the merge is possible.
791  */
792 static void
793 merge_to_base(gmx_ana_poscalc_t *base, gmx_ana_poscalc_t *pc)
794 {
795     gmx_ana_index_t  gp, gb, g;
796     int              isize, bnr;
797     int              i, j, bi, bj, bo;
798
799     base->flags |= pc->flags & (POS_VELOCITIES | POS_FORCES);
800     gmx_ana_index_set(&gp, pc->b.nra, pc->b.a, NULL, 0);
801     gmx_ana_index_set(&gb, base->b.nra, base->b.a, NULL, 0);
802     isize = gmx_ana_index_difference_size(&gp, &gb);
803     if (isize > 0)
804     {
805         gmx_ana_index_clear(&g);
806         gmx_ana_index_reserve(&g, base->b.nra + isize);
807         /* Find the new blocks */
808         gmx_ana_index_difference(&g, &gp, &gb);
809         /* Count the blocks in g */
810         i = bi = bnr = 0;
811         while (i < g.isize)
812         {
813             while (pc->b.a[pc->b.index[bi]] != g.index[i])
814             {
815                 ++bi;
816             }
817             i += pc->b.index[bi+1] - pc->b.index[bi];
818             ++bnr;
819             ++bi;
820         }
821         /* Merge the atoms into a temporary structure */
822         gmx_ana_index_merge(&g, &gb, &g);
823         /* Merge the blocks */
824         srenew(base->b.index, base->b.nr + bnr + 1);
825         i  = g.isize - 1;
826         bi = base->b.nr - 1;
827         bj = pc->b.nr - 1;
828         bo = base->b.nr + bnr - 1;
829         base->b.index[bo+1] = i + 1;
830         while (bo >= 0)
831         {
832             if (bi < 0 || base->b.a[base->b.index[bi+1]-1] != g.index[i])
833             {
834                 i -= pc->b.index[bj+1] - pc->b.index[bj];
835                 --bj;
836             }
837             else
838             {
839                 if (bj >= 0 && pc->b.a[pc->b.index[bj+1]-1] == g.index[i])
840                 {
841                     --bj;
842                 }
843                 i -= base->b.index[bi+1] - base->b.index[bi];
844                 --bi;
845             }
846             base->b.index[bo] = i + 1;
847             --bo;
848         }
849         base->b.nr           += bnr;
850         base->b.nalloc_index += bnr;
851         sfree(base->b.a);
852         base->b.nra      = g.isize;
853         base->b.a        = g.index;
854         base->b.nalloc_a = g.isize;
855         /* Refresh the gmax field */
856         gmx_ana_index_set(&base->gmax, base->b.nra, base->b.a, NULL, 0);
857     }
858 }
859
860 /*! \brief
861  * Merges two bases into one.
862  *
863  * \param[in,out] tbase Base calculation to merge to.
864  * \param[in]     mbase Base calculation to merge to \p tbase.
865  *
866  * After the call, \p mbase has been freed and \p tbase is used as the base
867  * for all calculations that previously had \p mbase as their base.
868  * It is assumed that any overlap between \p tbase and \p mbase is in complete
869  * blocks, i.e., that the merge is possible.
870  */
871 static void
872 merge_bases(gmx_ana_poscalc_t *tbase, gmx_ana_poscalc_t *mbase)
873 {
874     gmx_ana_poscalc_t *pc;
875
876     merge_to_base(tbase, mbase);
877     remove_poscalc(mbase);
878     /* Set tbase as the base for all calculations that had mbase */
879     pc = tbase->coll->first;
880     while (pc)
881     {
882         if (pc->sbase == mbase)
883         {
884             pc->sbase = tbase;
885             tbase->refcount++;
886         }
887         pc = pc->next;
888     }
889     /* Free mbase */
890     mbase->refcount = 0;
891     gmx_ana_poscalc_free(mbase);
892 }
893
894 /*! \brief
895  * Setups the static base calculation for a position calculation.
896  *
897  * \param[in,out] pc   Position calculation to setup the base for.
898  */
899 static void
900 setup_base(gmx_ana_poscalc_t *pc)
901 {
902     gmx_ana_poscalc_t *base, *pbase, *next;
903     gmx_ana_index_t    gp, g;
904
905     /* Exit immediately if pc should not have a base. */
906     if (!can_use_base(pc))
907     {
908         return;
909     }
910
911     gmx_ana_index_set(&gp, pc->b.nra, pc->b.a, NULL, 0);
912     gmx_ana_index_clear(&g);
913     gmx_ana_index_reserve(&g, pc->b.nra);
914     pbase = pc;
915     base = pc->coll->first;
916     while (base)
917     {
918         /* Save the next calculation so that we can safely delete base */
919         next = base->next;
920         /* Skip pc, calculations that already have a base (we should match the
921          * base instead), as well as calculations that should not have a base.
922          * If the above conditions are met, check whether we should do a
923          * merge.
924          */
925         if (base != pc && !base->sbase && can_use_base(base)
926             && should_merge(pbase, base, &gp, &g))
927         {
928             /* Check whether this is the first base found */
929             if (pbase == pc)
930             {
931                 /* Create a real base if one is not present */
932                 if (!base->p)
933                 {
934                     pbase = create_simple_base(base);
935                 }
936                 else
937                 {
938                     pbase = base;
939                 }
940                 /* Make it a base for pc as well */
941                 merge_to_base(pbase, pc);
942                 pc->sbase = pbase;
943                 pbase->refcount++;
944             }
945             else /* This was not the first base */
946             {
947                 if (!base->p)
948                 {
949                     /* If it is not a real base, just make the new base as
950                      * the base for it as well. */
951                     merge_to_base(pbase, base);
952                     base->sbase = pbase;
953                     pbase->refcount++;
954                 }
955                 else
956                 {
957                     /* If base is a real base, merge it with the new base
958                      * and delete it. */
959                     merge_bases(pbase, base);
960                 }
961             }
962             gmx_ana_index_set(&gp, pbase->b.nra, pbase->b.a, NULL, 0);
963             gmx_ana_index_reserve(&g, pc->b.nra);
964         }
965         /* Proceed to the next unchecked calculation */
966         base = next;
967     }
968
969     gmx_ana_index_deinit(&g);
970
971     /* If no base was found, create one if one is required */
972     if (!pc->sbase && (pc->flags & POS_DYNAMIC)
973         && (pc->flags & (POS_COMPLMAX | POS_COMPLWHOLE)))
974     {
975         create_simple_base(pc);
976     }
977 }
978
979 /*!
980  * \param[out] pcp   Position calculation data structure pointer to initialize.
981  * \param[in,out] pcc   Position calculation collection.
982  * \param[in]  type  Type of calculation.
983  * \param[in]  flags Flags for setting calculation options
984  *   (see \ref poscalc_flags "documentation of the flags").
985  * \returns    0 on success.
986  */
987 int
988 gmx_ana_poscalc_create(gmx_ana_poscalc_t **pcp, gmx_ana_poscalc_coll_t *pcc,
989                        e_poscalc_t type, int flags)
990 {
991     gmx_ana_poscalc_t *pc;
992
993     snew(pc, 1);
994     pc->type     = type;
995     pc->itype    = index_type_for_poscalc(type);
996     gmx_ana_poscalc_set_flags(pc, flags);
997     pc->refcount = 1;
998     pc->coll     = pcc;
999     insert_poscalc(pc, NULL);
1000     *pcp = pc;
1001     return 0;
1002 }
1003
1004 /*!
1005  * \param[out] pcp   Position calculation data structure pointer to initialize.
1006  * \param[in,out] pcc   Position calculation collection.
1007  * \param[in]  post  One of the strings acceptable for
1008  *   gmx_ana_poscalc_type_from_enum().
1009  * \param[in]  flags Flags for setting calculation options
1010  *   (see \ref poscalc_flags "documentation of the flags").
1011  * \returns    0 on success, a non-zero error value on error.
1012  *
1013  * This is a convenience wrapper for gmx_ana_poscalc_create().
1014  * \p flags sets the default calculation options if not overridden by \p post;
1015  * see gmx_ana_poscalc_type_from_enum().
1016  *
1017  * \see gmx_ana_poscalc_create(), gmx_ana_poscalc_type_from_enum()
1018  */
1019 int
1020 gmx_ana_poscalc_create_enum(gmx_ana_poscalc_t **pcp, gmx_ana_poscalc_coll_t *pcc,
1021                             const char *post, int flags)
1022 {
1023     e_poscalc_t  type;
1024     int          cflags;
1025     int          rc;
1026
1027     cflags = flags;
1028     rc = gmx_ana_poscalc_type_from_enum(post, &type, &cflags);
1029     if (rc != 0)
1030     {
1031         *pcp = NULL;
1032         return rc;
1033     }
1034     return gmx_ana_poscalc_create(pcp, pcc, type, cflags);
1035 }
1036
1037 /*!
1038  * \param[in,out] pc    Position calculation data structure.
1039  * \param[in]     flags New flags.
1040  *
1041  * \p flags are added to the old flags.
1042  * If calculation type is \ref POS_ATOM, \ref POS_MASS is automatically
1043  * cleared.
1044  * If both \ref POS_DYNAMIC and \ref POS_MASKONLY are provided,
1045  * \ref POS_DYNAMIC is cleared.
1046  * If calculation type is not \ref POS_RES or \ref POS_MOL,
1047  * \ref POS_COMPLMAX and \ref POS_COMPLWHOLE are automatically cleared.
1048  */
1049 void
1050 gmx_ana_poscalc_set_flags(gmx_ana_poscalc_t *pc, int flags)
1051 {
1052     if (pc->type == POS_ATOM)
1053     {
1054         flags &= ~POS_MASS;
1055     }
1056     if (flags & POS_MASKONLY)
1057     {
1058         flags &= ~POS_DYNAMIC;
1059     }
1060     if (pc->type != POS_RES && pc->type != POS_MOL)
1061     {
1062         flags &= ~(POS_COMPLMAX | POS_COMPLWHOLE);
1063     }
1064     pc->flags |= flags;
1065 }
1066
1067 /*!
1068  * \param[in,out] pc  Position calculation data structure.
1069  * \param[in]     g   Maximum index group for the calculation.
1070  *
1071  * Subsequent calls to gmx_ana_poscalc_update() should use only subsets of
1072  * \p g for evaluation.
1073  *
1074  * The topology should have been set for the collection of which \p pc is
1075  * a member.
1076  */
1077 void
1078 gmx_ana_poscalc_set_maxindex(gmx_ana_poscalc_t *pc, gmx_ana_index_t *g)
1079 {
1080     set_poscalc_maxindex(pc, g, FALSE);
1081     setup_base(pc);
1082 }
1083
1084 /*!
1085  * \param[in]  pc  Position calculation data structure.
1086  * \param[out] p   Output positions.
1087  *
1088  * Calls to gmx_ana_poscalc_update() using \p pc should use only positions
1089  * initialized with this function.
1090  * The \c p->g pointer is initialized to point to an internal group that
1091  * contains the maximum index group set with gmx_ana_poscalc_set_maxindex().
1092  */
1093 void
1094 gmx_ana_poscalc_init_pos(gmx_ana_poscalc_t *pc, gmx_ana_pos_t *p)
1095 {
1096     gmx_ana_indexmap_init(&p->m, &pc->gmax, pc->coll->top, pc->itype);
1097     if (!(pc->flags & POS_DYNAMIC))
1098     {
1099         gmx_ana_indexmap_set_static(&p->m, &pc->b);
1100     }
1101     gmx_ana_pos_reserve(p, p->m.nr, 0);
1102     if (pc->flags & POS_VELOCITIES)
1103     {
1104         gmx_ana_pos_reserve_velocities(p);
1105     }
1106     if (pc->flags & POS_FORCES)
1107     {
1108         gmx_ana_pos_reserve_forces(p);
1109     }
1110     gmx_ana_pos_set_nr(p, p->m.nr);
1111     gmx_ana_pos_set_evalgrp(p, &pc->gmax);
1112 }
1113
1114 /*!
1115  * \param  pc  Position calculation data to be freed.
1116  *
1117  * The \p pc pointer is invalid after the call.
1118  */
1119 void
1120 gmx_ana_poscalc_free(gmx_ana_poscalc_t *pc)
1121 {
1122     if (!pc)
1123     {
1124         return;
1125     }
1126
1127     pc->refcount--;
1128     if (pc->refcount > 0)
1129     {
1130         return;
1131     }
1132
1133     remove_poscalc(pc);
1134     if (pc->b.nalloc_index > 0)
1135     {
1136         sfree(pc->b.index);
1137     }
1138     if (pc->b.nalloc_a > 0)
1139     {
1140         sfree(pc->b.a);
1141     }
1142     if (pc->flags & POS_COMPLWHOLE)
1143     {
1144         gmx_ana_index_deinit(&pc->gmax);
1145     }
1146     if (pc->p)
1147     {
1148         gmx_ana_pos_free(pc->p);
1149     }
1150     if (pc->sbase)
1151     {
1152         gmx_ana_poscalc_free(pc->sbase);
1153         sfree(pc->baseid);
1154     }
1155     sfree(pc);
1156 }
1157
1158 /*!
1159  * \param[in] pc  Position calculation data to query.
1160  * \returns   TRUE if \p pc requires topology for initialization and/or
1161  *   evaluation, FALSE otherwise.
1162  */
1163 bool
1164 gmx_ana_poscalc_requires_top(gmx_ana_poscalc_t *pc)
1165 {
1166     if ((pc->flags & POS_MASS) || pc->type == POS_RES || pc->type == POS_MOL)
1167     {
1168         return TRUE;
1169     }
1170     return FALSE;
1171 }
1172
1173 /*!
1174  * \param[in,out] pcc Position calculation collection to initialize.
1175  *
1176  * This function does some final initialization of the data structures in the
1177  * collection to prepare them for evaluation.
1178  * After this function has been called, it is no longer possible to add new
1179  * calculations to the collection.
1180  *
1181  * This function is automatically called by gmx_ana_poscalc_init_frame() 
1182  * if not called by the user earlier.
1183  * Multiple calls to the function are ignored.
1184  */
1185 void
1186 gmx_ana_poscalc_init_eval(gmx_ana_poscalc_coll_t *pcc)
1187 {
1188     gmx_ana_poscalc_t      *pc;
1189     int                     bi, bj;
1190
1191     if (pcc->bInit)
1192     {
1193         return;
1194     }
1195     pc = pcc->first;
1196     while (pc)
1197     {
1198         /* Initialize position storage for base calculations */
1199         if (pc->p)
1200         {
1201             gmx_ana_poscalc_init_pos(pc, pc->p);
1202         }
1203         /* Construct the mapping of the base positions */
1204         if (pc->sbase)
1205         {
1206             snew(pc->baseid, pc->b.nr);
1207             for (bi = bj = 0; bi < pc->b.nr; ++bi, ++bj)
1208             {
1209                 while (pc->sbase->b.a[pc->sbase->b.index[bj]] != pc->b.a[pc->b.index[bi]])
1210                 {
1211                     ++bj;
1212                 }
1213                 pc->baseid[bi] = bj;
1214             }
1215         }
1216         /* Free the block data for dynamic calculations */
1217         if (pc->flags & POS_DYNAMIC)
1218         {
1219             if (pc->b.nalloc_index > 0)
1220             {
1221                 sfree(pc->b.index);
1222                 pc->b.nalloc_index = 0;
1223             }
1224             if (pc->b.nalloc_a > 0)
1225             {
1226                 sfree(pc->b.a);
1227                 pc->b.nalloc_a = 0;
1228             }
1229         }
1230         pc = pc->next;
1231     }
1232     pcc->bInit = TRUE;
1233 }
1234
1235 /*!
1236  * \param[in,out] pcc Position calculation collection to initialize.
1237  *
1238  * Clears the evaluation flag for all calculations.
1239  * Should be called for each frame before calling gmx_ana_poscalc_update().
1240  *
1241  * This function is automatically called by gmx_ana_do() for each
1242  * frame, and should not be called by the user unless gmx_ana_do() is
1243  * not being used.
1244  *
1245  * This function calls gmx_ana_poscalc_init_eval() automatically if it has
1246  * not been called earlier.
1247  */
1248 void
1249 gmx_ana_poscalc_init_frame(gmx_ana_poscalc_coll_t *pcc)
1250 {
1251     gmx_ana_poscalc_t      *pc;
1252
1253     if (!pcc->bInit)
1254     {
1255         gmx_ana_poscalc_init_eval(pcc);
1256     }
1257     /* Clear the evaluation flags */
1258     pc = pcc->first;
1259     while (pc)
1260     {
1261         pc->bEval = FALSE;
1262         pc = pc->next;
1263     }
1264 }
1265
1266 /*!
1267  * \param[in]     pc   Position calculation data.
1268  * \param[in,out] p    Output positions, initialized previously with
1269  *   gmx_ana_poscalc_init_pos() using \p pc.
1270  * \param[in]     g    Index group to use for the update.
1271  * \param[in]     fr   Current frame.
1272  * \param[in]     pbc  PBC data, or NULL if no PBC should be used.
1273  *
1274  * gmx_ana_poscalc_init_frame() should be called for each frame before calling
1275  * this function.
1276  */
1277 void
1278 gmx_ana_poscalc_update(gmx_ana_poscalc_t *pc, gmx_ana_pos_t *p,
1279                        gmx_ana_index_t *g, t_trxframe *fr, t_pbc *pbc)
1280 {
1281     int  i, j, bi, bj;
1282     
1283     if (pc->bEval == TRUE && !(pc->flags & POS_MASKONLY))
1284     {
1285         return;
1286     }
1287     if (pc->sbase)
1288     {
1289         gmx_ana_poscalc_update(pc->sbase, NULL, NULL, fr, pbc);
1290     }
1291     if (!p)
1292     {
1293         p = pc->p;
1294     }
1295     if (!g)
1296     {
1297         g = &pc->gmax;
1298     }
1299     gmx_ana_pos_set_evalgrp(p, g);
1300
1301     /* Update the index map */
1302     if (pc->flags & POS_DYNAMIC)
1303     {
1304         gmx_ana_indexmap_update(&p->m, g, FALSE);
1305         p->nr = p->m.nr;
1306     }
1307     else if (pc->flags & POS_MASKONLY)
1308     {
1309         gmx_ana_indexmap_update(&p->m, g, TRUE);
1310         if (pc->bEval)
1311             return;
1312     }
1313     if (!(pc->flags & POS_DYNAMIC))
1314     {
1315         pc->bEval = TRUE;
1316     }
1317
1318     /* Evaluate the positions */
1319     if (pc->sbase)
1320     {
1321         /* TODO: It might be faster to evaluate the positions within this
1322          * loop instead of in the beginning. */
1323         if (pc->flags & POS_DYNAMIC)
1324         {
1325             for (bi = 0; bi < p->nr; ++bi)
1326             {
1327                 bj = pc->baseid[p->m.refid[bi]];
1328                 copy_rvec(pc->sbase->p->x[bj], p->x[bi]);
1329             }
1330             if (p->v)
1331             {
1332                 for (bi = 0; bi < p->nr; ++bi)
1333                 {
1334                     bj = pc->baseid[p->m.refid[bi]];
1335                     copy_rvec(pc->sbase->p->v[bj], p->v[bi]);
1336                 }
1337             }
1338             if (p->f)
1339             {
1340                 for (bi = 0; bi < p->nr; ++bi)
1341                 {
1342                     bj = pc->baseid[p->m.refid[bi]];
1343                     copy_rvec(pc->sbase->p->f[bj], p->f[bi]);
1344                 }
1345             }
1346         }
1347         else
1348         {
1349             for (bi = 0; bi < p->nr; ++bi)
1350             {
1351                 bj = pc->baseid[bi];
1352                 copy_rvec(pc->sbase->p->x[bj], p->x[bi]);
1353             }
1354             if (p->v)
1355             {
1356                 for (bi = 0; bi < p->nr; ++bi)
1357                 {
1358                     bj = pc->baseid[bi];
1359                     copy_rvec(pc->sbase->p->v[bj], p->v[bi]);
1360                 }
1361             }
1362             if (p->f)
1363             {
1364                 for (bi = 0; bi < p->nr; ++bi)
1365                 {
1366                     bj = pc->baseid[bi];
1367                     copy_rvec(pc->sbase->p->f[bj], p->f[bi]);
1368                 }
1369             }
1370         }
1371     }
1372     else /* pc->sbase is NULL */
1373     {
1374         if (pc->flags & POS_DYNAMIC)
1375         {
1376             pc->b.nr    = p->m.mapb.nr;
1377             pc->b.index = p->m.mapb.index;
1378             pc->b.nra   = g->isize;
1379             pc->b.a     = g->index;
1380         }
1381         if (p->v && !fr->bV)
1382         {
1383             for (i = 0; i < pc->b.nra; ++i)
1384             {
1385                 clear_rvec(p->v[i]);
1386             }
1387         }
1388         if (p->f && !fr->bF)
1389         {
1390             for (i = 0; i < pc->b.nra; ++i)
1391             {
1392                 clear_rvec(p->f[i]);
1393             }
1394         }
1395         /* Here, we assume that the topology has been properly initialized,
1396          * and do not check the return values of gmx_calc_comg*(). */
1397         switch (pc->type)
1398         {
1399         case POS_ATOM:
1400             for (i = 0; i < pc->b.nra; ++i)
1401             {
1402                 copy_rvec(fr->x[pc->b.a[i]], p->x[i]);
1403             }
1404             if (p->v && fr->bV)
1405             {
1406                 for (i = 0; i < pc->b.nra; ++i)
1407                 {
1408                     copy_rvec(fr->v[pc->b.a[i]], p->v[i]);
1409                 }
1410             }
1411             if (p->f && fr->bF)
1412             {
1413                 for (i = 0; i < pc->b.nra; ++i)
1414                 {
1415                     copy_rvec(fr->f[pc->b.a[i]], p->f[i]);
1416                 }
1417             }
1418             break;
1419         case POS_ALL:
1420             gmx_calc_comg(pc->coll->top, fr->x, pc->b.nra, pc->b.a,
1421                           pc->flags & POS_MASS, p->x[0]);
1422             if (p->v && fr->bV)
1423             {
1424                 gmx_calc_comg(pc->coll->top, fr->v, pc->b.nra, pc->b.a,
1425                               pc->flags & POS_MASS, p->v[0]);
1426             }
1427             if (p->f && fr->bF)
1428             {
1429                 gmx_calc_comg_f(pc->coll->top, fr->f, pc->b.nra, pc->b.a,
1430                                 pc->flags & POS_MASS, p->f[0]);
1431             }
1432             break;
1433         case POS_ALL_PBC:
1434             gmx_calc_comg_pbc(pc->coll->top, fr->x, pbc, pc->b.nra, pc->b.a,
1435                               pc->flags & POS_MASS, p->x[0]);
1436             if (p->v && fr->bV)
1437             {
1438                 gmx_calc_comg(pc->coll->top, fr->v, pc->b.nra, pc->b.a,
1439                               pc->flags & POS_MASS, p->v[0]);
1440             }
1441             if (p->f && fr->bF)
1442             {
1443                 gmx_calc_comg_f(pc->coll->top, fr->f, pc->b.nra, pc->b.a,
1444                                 pc->flags & POS_MASS, p->f[0]);
1445             }
1446             break;
1447         default:
1448             gmx_calc_comg_blocka(pc->coll->top, fr->x, &pc->b,
1449                                  pc->flags & POS_MASS, p->x);
1450             if (p->v && fr->bV)
1451             {
1452                 gmx_calc_comg_blocka(pc->coll->top, fr->v, &pc->b,
1453                                      pc->flags & POS_MASS, p->v);
1454             }
1455             if (p->f && fr->bF)
1456             {
1457                 gmx_calc_comg_blocka(pc->coll->top, fr->f, &pc->b,
1458                                      pc->flags & POS_MASS, p->f);
1459             }
1460             break;
1461         }
1462     }
1463 }