d1340d1d3f0e9dced11cb8a5701d8ee28704bf1e
[alexxy/gromacs.git] / src / gromacs / swap / swapcoords.cpp
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * Copyright (c) 2013,2014,2015,2016,2017,2018, by the GROMACS development team, led by
5  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
6  * and including many others, as listed in the AUTHORS file in the
7  * top-level source directory and at http://www.gromacs.org.
8  *
9  * GROMACS is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public License
11  * as published by the Free Software Foundation; either version 2.1
12  * of the License, or (at your option) any later version.
13  *
14  * GROMACS is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with GROMACS; if not, see
21  * http://www.gnu.org/licenses, or write to the Free Software Foundation,
22  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
23  *
24  * If you want to redistribute modifications to GROMACS, please
25  * consider that scientific software is very special. Version
26  * control is crucial - bugs must be traceable. We will be happy to
27  * consider code for inclusion in the official distribution, but
28  * derived work must not be called official GROMACS. Details are found
29  * in the README & COPYING files - if they are missing, get the
30  * official version at http://www.gromacs.org.
31  *
32  * To help us fund GROMACS development, we humbly ask that you cite
33  * the research papers on the package. Check out http://www.gromacs.org.
34  */
35 /*! \internal \file
36  * \brief
37  * Implements functions in swapcoords.h.
38  *
39  * \author Carsten Kutzner <ckutzne@gwdg.de>
40  * \ingroup module_swap
41  */
42 #include "gmxpre.h"
43
44 #include "swapcoords.h"
45
46 #include <cstdio>
47 #include <cstdlib>
48 #include <ctime>
49
50 #include <string>
51 #include <vector>
52
53 #include "gromacs/compat/make_unique.h"
54 #include "gromacs/domdec/domdec_struct.h"
55 #include "gromacs/domdec/localatomset.h"
56 #include "gromacs/domdec/localatomsetmanager.h"
57 #include "gromacs/fileio/confio.h"
58 #include "gromacs/fileio/gmxfio.h"
59 #include "gromacs/fileio/xvgr.h"
60 #include "gromacs/gmxlib/network.h"
61 #include "gromacs/math/vec.h"
62 #include "gromacs/mdlib/groupcoord.h"
63 #include "gromacs/mdlib/mdrun.h"
64 #include "gromacs/mdlib/sim_util.h"
65 #include "gromacs/mdtypes/commrec.h"
66 #include "gromacs/mdtypes/inputrec.h"
67 #include "gromacs/mdtypes/md_enums.h"
68 #include "gromacs/mdtypes/observableshistory.h"
69 #include "gromacs/mdtypes/state.h"
70 #include "gromacs/mdtypes/swaphistory.h"
71 #include "gromacs/pbcutil/pbc.h"
72 #include "gromacs/timing/wallcycle.h"
73 #include "gromacs/topology/mtop_lookup.h"
74 #include "gromacs/topology/topology.h"
75 #include "gromacs/utility/cstringutil.h"
76 #include "gromacs/utility/fatalerror.h"
77 #include "gromacs/utility/pleasecite.h"
78 #include "gromacs/utility/smalloc.h"
79 #include "gromacs/utility/snprintf.h"
80
81 static const char *SwS      = {"SWAP:"};                                           /**< For output that comes from the swap module */
82 static const char *SwSEmpty = {"     "};                                           /**< Placeholder for multi-line output */
83 static const char* CompStr[eCompNR] = {"A", "B" };                                 /**< Compartment name */
84 static const char *SwapStr[eSwapTypesNR+1] = { "", "X-", "Y-", "Z-", nullptr};     /**< Name for the swap types. */
85 static const char *DimStr[DIM+1] = { "X", "Y", "Z", nullptr};                      /**< Name for the swap dimension. */
86
87 /** Keep track of through which channel the ions have passed */
88 enum eChannelHistory {
89     eChHistPassedNone, eChHistPassedCh0, eChHistPassedCh1, eChHistNr
90 };
91 static const char* ChannelString[eChHistNr] = { "none", "channel0", "channel1" };  /**< Name for the channels */
92
93 /*! \brief Domain identifier.
94  *
95  * Keeps track of from which compartment the ions came before passing the
96  * channel.
97  */
98 enum eDomain {
99     eDomainNotset, eDomainA, eDomainB, eDomainNr
100 };
101 static const char* DomainString[eDomainNr] = { "not_assigned", "Domain_A", "Domain_B" }; /**< Name for the domains */
102
103
104
105 /*! \internal \brief
106  * Structure containing compartment-specific data.
107  */
108 typedef struct swap_compartment
109 {
110     int                nMol;                  /**< Number of ion or water molecules detected
111                                                    in this compartment.                          */
112     int                nMolBefore;            /**< Number of molecules before swapping.          */
113     int                nMolReq;               /**< Requested number of molecules in compartment. */
114     real               nMolAv;                /**< Time-averaged number of molecules matching
115                                                    the compartment conditions.                   */
116     int               *nMolPast;              /**< Past molecule counts for time-averaging.      */
117     int               *ind;                   /**< Indices to collective array of atoms.         */
118     real              *dist;                  /**< Distance of atom to bulk layer, which is
119                                                    normally the center layer of the compartment  */
120     int                nalloc;                /**< Allocation size for ind array.                */
121     int                inflow_net;            /**< Net inflow of ions into this compartment.     */
122 } t_compartment;
123
124
125 /*! \internal \brief
126  * This structure contains data needed for the groups involved in swapping:
127  * split group 0, split group 1, solvent group, ion groups.
128  */
129 typedef struct swap_group
130 {
131     /*!\brief Construct a swap group given the managed swap atoms.
132      *
133      * \param[in] atomset Managed indices of atoms that are part of the swap group.
134      */
135     swap_group(const gmx::LocalAtomSet &atomset);
136     char             *molname = nullptr;       /**< Name of the group or ion type                         */
137     int               apm     = 0;             /**< Number of atoms in each molecule                      */
138     gmx::LocalAtomSet atomset;                 /**< The atom indices in the swap group                    */
139     rvec             *xc            = nullptr; /**< Collective array of group atom positions (size nat)   */
140     ivec             *xc_shifts     = nullptr; /**< Current (collective) shifts (size nat)                */
141     ivec             *xc_eshifts    = nullptr; /**< Extra shifts since last DD step (size nat)            */
142     rvec             *xc_old        = nullptr; /**< Old (collective) positions (size nat)                 */
143     real              q             = 0.;      /**< Total charge of one molecule of this group            */
144     real             *m             = nullptr; /**< Masses (can be omitted, size apm)                     */
145     unsigned char    *comp_from     = nullptr; /**< (Collective) Stores from which compartment this
146                                                   molecule has come. This way we keep track of
147                                                   through which channel an ion permeates
148                                                   (size nMol = nat/apm)                                 */
149     unsigned char    *comp_now      = nullptr; /**< In which compartment this ion is now (size nMol)      */
150     unsigned char    *channel_label = nullptr; /**< Which channel was passed at last by this ion?
151                                                   (size nMol)                                           */
152     rvec              center;                  /**< Center of the group; COM if masses are used           */
153     t_compartment     comp[eCompNR];           /**< Distribution of particles of this group across
154                                                      the two compartments                                 */
155     real              vacancy[eCompNR];        /**< How many molecules need to be swapped in?             */
156     int               fluxfromAtoB[eChanNR];   /**< Net flux of ions per channel                          */
157     int               nCyl[eChanNR];           /**< Number of ions residing in a channel                  */
158     int               nCylBoth = 0;            /**< Ions assigned to cyl0 and cyl1. Not good.             */
159 } t_swapgrp;
160
161 t_swapgrp::swap_group(const gmx::LocalAtomSet& atomset) : atomset {
162     atomset
163 } {
164     center[0] = 0;
165     center[1] = 0;
166     center[2] = 0;
167     for (int compartment = eCompA; compartment < eCompNR; ++compartment)
168     {
169         comp[compartment] = {};
170         vacancy[compartment] = 0;
171     }
172     for (int channel = eChan0; channel < eChanNR; ++channel)
173     {
174         fluxfromAtoB[channel] = 0;
175         nCyl[channel]         = 0;
176     }
177 };
178
179 /*! \internal \brief
180  * Main (private) data structure for the position swapping protocol.
181  */
182 typedef struct t_swap
183 {
184     int                    swapdim;                  /**< One of XX, YY, ZZ                               */
185     t_pbc                 *pbc;                      /**< Needed to make molecules whole.                 */
186     FILE                  *fpout;                    /**< Output file.                                    */
187     int                    ngrp;                     /**< Number of t_swapgrp groups                      */
188     std::vector<t_swapgrp> group;                    /**< Separate groups for channels, solvent, ions     */
189     int                    fluxleak;                 /**< Flux not going through any of the channels.     */
190     real                   deltaQ;                   /**< The charge imbalance between the compartments.  */
191 } t_swap;
192
193
194
195 /*! \brief Check whether point is in channel.
196  *
197  * A channel is a cylinder defined by a disc
198  * with radius r around its center c. The thickness of the cylinder is
199  * d_up - d_down.
200  *
201  * \code
202  *               ^  d_up
203  *               |
204  *     r         |
205  *     <---------c--------->
206  *               |
207  *               v  d_down
208  *
209  * \endcode
210  *
211  * \param[in] point    The position (xyz) under consideration.
212  * \param[in] center   The center of the cylinder.
213  * \param[in] d_up     The upper extension of the cylinder.
214  * \param[in] d_down   The lower extension.
215  * \param[in] r_cyl2   Cylinder radius squared.
216  * \param[in] pbc      Structure with info about periodic boundary conditions.
217  * \param[in] normal   The membrane normal direction is typically 3, i.e. z, but can be x or y also.
218  *
219  * \returns   Whether the point is inside the defined cylindric channel.
220  */
221 static gmx_bool is_in_channel(
222         rvec   point,
223         rvec   center,
224         real   d_up,
225         real   d_down,
226         real   r_cyl2,
227         t_pbc *pbc,
228         int    normal)
229 {
230     rvec dr;
231     int  plane1, plane2; /* Directions tangential to membrane */
232
233
234     plane1 = (normal + 1) % 3; /* typically 0, i.e. XX */
235     plane2 = (normal + 2) % 3; /* typically 1, i.e. YY */
236
237     /* Get the distance vector dr between the point and the center of the cylinder */
238     pbc_dx(pbc, point, center, dr); /* This puts center in the origin */
239
240     /* Check vertical direction */
241     if ( (dr[normal] > d_up) || (dr[normal] < -d_down) )
242     {
243         return FALSE;
244     }
245
246     /* Check radial direction */
247     if ( (dr[plane1]*dr[plane1] + dr[plane2]*dr[plane2]) > r_cyl2)
248     {
249         return FALSE;
250     }
251
252     /* All check passed, this point is in the cylinder */
253     return TRUE;
254 }
255
256
257 /*! \brief Prints output to CompEL output file.
258  *
259  * Prints to swap output file how many ions are in each compartment,
260  * where the centers of the split groups are, and how many ions of each type
261  * passed the channels.
262  */
263 static void print_ionlist(
264         t_swap       *s,
265         double        time,
266         const char    comment[])
267 {
268     // Output time
269     fprintf(s->fpout, "%12.5e", time);
270
271     // Output number of molecules and difference to reference counts for each
272     // compartment and ion type
273     for (int iComp = 0; iComp < eCompNR; iComp++)
274     {
275         for (int ig = eSwapFixedGrpNR; ig < s->ngrp; ig++)
276         {
277             t_compartment *comp = &s->group[ig].comp[iComp];
278
279             fprintf(s->fpout, "%10d%10.1f%10d", comp->nMol, comp->nMolAv - comp->nMolReq, comp->inflow_net);
280         }
281     }
282
283     // Output center of split groups
284     fprintf(s->fpout, "%10g%10g",
285             s->group[eGrpSplit0].center[s->swapdim],
286             s->group[eGrpSplit1].center[s->swapdim]);
287
288     // Output ion flux for each channel and ion type
289     for (int iChan = 0; iChan < eChanNR; iChan++)
290     {
291         for (int ig = eSwapFixedGrpNR; ig < s->ngrp; ig++)
292         {
293             t_swapgrp *g = &s->group[ig];
294             fprintf(s->fpout, "%10d", g->fluxfromAtoB[iChan]);
295         }
296     }
297
298     /* Output the number of molecules that leaked from A to B */
299     fprintf(s->fpout, "%10d", s->fluxleak);
300
301     fprintf(s->fpout, "%s\n", comment);
302 }
303
304
305 /*! \brief Get the center of a group of nat atoms.
306  *
307  * Since with PBC an atom group might not be whole, use the first atom as the
308  * reference atom and determine the center with respect to this reference.
309  */
310 static void get_molecule_center(
311         rvec         x[],
312         int          nat,
313         const real  *weights,
314         rvec         center,
315         t_pbc       *pbc)
316 {
317     int  i;
318     rvec weightedPBCimage;
319     real wi, wsum;
320     rvec reference, correctPBCimage, dx;
321
322
323     /* Use the first atom as the reference and put other atoms near that one */
324     /* This does not work for large molecules that span > half of the box! */
325     copy_rvec(x[0], reference);
326
327     /* Calculate either the weighted center or simply the center of geometry */
328     wsum = 0.0;
329     clear_rvec(center);
330     for (i = 0; i < nat; i++)
331     {
332         /* PBC distance between position and reference */
333         pbc_dx(pbc, x[i], reference, dx);
334
335         /* Add PBC distance to reference */
336         rvec_add(reference, dx, correctPBCimage);
337
338         /* Take weight into account */
339         if (nullptr == weights)
340         {
341             wi = 1.0;
342         }
343         else
344         {
345             wi = weights[i];
346         }
347         wsum += wi;
348         svmul(wi, correctPBCimage, weightedPBCimage);
349
350         /* Add to center */
351         rvec_inc(center, weightedPBCimage);
352     }
353
354     /* Normalize */
355     svmul(1.0/wsum, center, center);
356 }
357
358
359
360 /*! \brief Return TRUE if position x of ion (or water) is found in the compartment,
361  * i.e. between w1 and w2.
362  *
363  * One can define and additional offset "b" if one wants to exchange ions/water
364  * to or from a plane not directly in the middle of w1 and w2. The offset can be
365  * in  ]-1.0, ..., +1.0 [.
366  * A bulkOffset of 0.0 means 'no offset', so the swap-layer is directly in the
367  * middle between w1 and w2. Offsets -1.0 < b <  0.0 will yield swaps nearer to w1,
368  * whereas offsets  0.0 < 0 < +1.0 will yield swaps nearer to w2.
369  *
370  * \code
371  *
372  * ||--------------+-------------|-------------+------------------------||
373  *                w1  ? ? ? ? ? ? ? ? ? ? ?   w2
374  * ||--------------+-------------|----b--------+------------------------||
375  *                -1            0.0           +1
376  *
377  * \endcode
378  *
379  * \param[in]  w1               Position of 'wall' atom 1.
380  * \param[in]  w2               Position of 'wall' atom 2.
381  * \param[in]  x                Position of the ion or the water molecule under consideration.
382  * \param[in]  l                Length of the box, from || to || in the sketch.
383  * \param[in]  bulkOffset       Where is the bulk layer "b" to be found between w1 and w2?
384  * \param[out] distance_from_b  Distance of x to the bulk layer "b".
385  *
386  * \returns TRUE if x is between w1 and w2.
387  *
388  * Also computes the distance of x to the compartment center (the layer that is
389  * normally situated in the middle of w1 and w2 that would be considered as having
390  * the bulk concentration of ions).
391  */
392 static gmx_bool compartment_contains_atom(
393         real  w1,
394         real  w2,
395         real  x,
396         real  l,
397         real  bulkOffset,
398         real *distance_from_b)
399 {
400     real m, l_2;
401     real width;
402
403
404     /* First set the origin in the middle of w1 and w2 */
405     m     = 0.5 * (w1 + w2);
406     w1   -= m;
407     w2   -= m;
408     x    -= m;
409     width = w2 - w1;
410
411     /* Now choose the PBC image of x that is closest to the origin: */
412     l_2 = 0.5*l;
413     while (x  > l_2)
414     {
415         x -= l;
416     }
417     while (x <= -l_2)
418     {
419         x += l;
420     }
421
422     *distance_from_b = static_cast<real>(fabs(x - bulkOffset*0.5*width));
423
424     /* Return TRUE if we now are in area "????" */
425     return (x >= w1) &&  (x < w2);
426 }
427
428
429 /*! \brief Updates the time-averaged number of ions in a compartment. */
430 static void update_time_window(t_compartment *comp, int values, int replace)
431 {
432     real average;
433     int  i;
434
435
436     /* Put in the new value */
437     if (replace >= 0)
438     {
439         comp->nMolPast[replace] = comp->nMol;
440     }
441
442     /* Compute the new time-average */
443     average = 0.0;
444     for (i = 0; i < values; i++)
445     {
446         average += comp->nMolPast[i];
447     }
448     average     /= values;
449     comp->nMolAv = average;
450 }
451
452
453 /*! \brief Add the atom with collective index ci to the atom list in compartment 'comp'.
454  *
455  * \param[in]     ci        Index of this ion in the collective xc array.
456  * \param[inout]  comp      Compartment to add this atom to.
457  * \param[in]     distance  Shortest distance of this atom to the bulk layer,
458  *                          from which ion/water pairs are selected for swapping.
459  */
460 static void add_to_list(
461         int            ci,
462         t_compartment *comp,
463         real           distance)
464 {
465     int nr = comp->nMol;
466
467     if (nr >= comp->nalloc)
468     {
469         comp->nalloc = over_alloc_dd(nr+1);
470         srenew(comp->ind, comp->nalloc);
471         srenew(comp->dist, comp->nalloc);
472     }
473     comp->ind[nr]  = ci;
474     comp->dist[nr] = distance;
475     comp->nMol++;
476 }
477
478
479 /*! \brief Determine the compartment boundaries from the channel centers. */
480 static void get_compartment_boundaries(
481         int c,
482         t_swap *s,
483         const matrix box,
484         real *left, real *right)
485 {
486     real pos0, pos1;
487     real leftpos, rightpos, leftpos_orig;
488
489
490     if (c >= eCompNR)
491     {
492         gmx_fatal(FARGS, "No compartment %c.", c+'A');
493     }
494
495     pos0 = s->group[eGrpSplit0].center[s->swapdim];
496     pos1 = s->group[eGrpSplit1].center[s->swapdim];
497
498     if (pos0 < pos1)
499     {
500         leftpos  = pos0;
501         rightpos = pos1;
502     }
503     else
504     {
505         leftpos  = pos1;
506         rightpos = pos0;
507     }
508
509     /* This gets us the other compartment: */
510     if (c == eCompB)
511     {
512         leftpos_orig = leftpos;
513         leftpos      = rightpos;
514         rightpos     = leftpos_orig + box[s->swapdim][s->swapdim];
515     }
516
517     *left  = leftpos;
518     *right = rightpos;
519 }
520
521
522 /*! \brief Determine the per-channel ion flux.
523  *
524  * To determine the flux through the individual channels, we
525  * remember the compartment and channel history of each ion. An ion can be
526  * either in channel0 or channel1, or in the remaining volume of compartment
527  * A or B.
528  *
529  * \code
530  *    +-----------------+
531  *    |                 | B
532  *    |                 | B compartment
533  *    ||||||||||0|||||||| bilayer with channel 0
534  *    |                 | A
535  *    |                 | A
536  *    |                 | A compartment
537  *    |                 | A
538  *    |||||1||||||||||||| bilayer with channel 1
539  *    |                 | B
540  *    |                 | B compartment
541  *    +-----------------+
542  *
543  * \endcode
544  */
545 static void detect_flux_per_channel(
546         t_swapgrp      *g,
547         int             iAtom,
548         int             comp,
549         rvec            atomPosition,
550         unsigned char  *comp_now,
551         unsigned char  *comp_from,
552         unsigned char  *channel_label,
553         t_swapcoords   *sc,
554         real            cyl0_r2,
555         real            cyl1_r2,
556         int64_t         step,
557         gmx_bool        bRerun,
558         FILE           *fpout)
559 {
560     gmx_swapcoords_t s;
561     int              sd, chan_nr;
562     gmx_bool         in_cyl0, in_cyl1;
563     char             buf[STRLEN];
564
565
566     s    = sc->si_priv;
567     sd   = s->swapdim;
568
569     /* Check whether ion is inside any of the channels */
570     in_cyl0 = is_in_channel(atomPosition, s->group[eGrpSplit0].center, sc->cyl0u, sc->cyl0l, cyl0_r2, s->pbc, sd);
571     in_cyl1 = is_in_channel(atomPosition, s->group[eGrpSplit1].center, sc->cyl1u, sc->cyl1l, cyl1_r2, s->pbc, sd);
572
573     if (in_cyl0 && in_cyl1)
574     {
575         /* Ion appears to be in both channels. Something is severely wrong! */
576         g->nCylBoth++;
577         *comp_now      = eDomainNotset;
578         *comp_from     = eDomainNotset;
579         *channel_label = eChHistPassedNone;
580     }
581     else if (in_cyl0)
582     {
583         /* Ion is in channel 0 now */
584         *channel_label = eChHistPassedCh0;
585         *comp_now      = eDomainNotset;
586         g->nCyl[eChan0]++;
587     }
588     else if (in_cyl1)
589     {
590         /* Ion is in channel 1 now */
591         *channel_label = eChHistPassedCh1;
592         *comp_now      = eDomainNotset;
593         g->nCyl[eChan1]++;
594     }
595     else
596     {
597         /* Ion is not in any of the channels, so it must be in domain A or B */
598         if (eCompA == comp)
599         {
600             *comp_now = eDomainA;
601         }
602         else
603         {
604             *comp_now = eDomainB;
605         }
606     }
607
608     /* Only take action, if ion is now in domain A or B, and was before
609      * in the other domain!
610      */
611     if (eDomainNotset == *comp_from)
612     {
613         /* Maybe we can set the domain now */
614         *comp_from = *comp_now;               /* Could still be eDomainNotset, though */
615     }
616     else if (  (*comp_now  != eDomainNotset ) /* if in channel */
617                && (*comp_from != *comp_now)  )
618     {
619         /* Obviously the ion changed its domain.
620          * Count this for the channel through which it has passed. */
621         switch (*channel_label)
622         {
623             case eChHistPassedNone:
624                 ++s->fluxleak;
625
626                 fprintf(stderr, " %s Warning! Step %s, ion %d moved from %s to %s\n",
627                         SwS, gmx_step_str(step, buf), iAtom, DomainString[*comp_from], DomainString[*comp_now]);
628                 if (bRerun)
629                 {
630                     fprintf(stderr, ", possibly due to a swap in the original simulation.\n");
631                 }
632                 else
633                 {
634                     fprintf(stderr, "but did not pass cyl0 or cyl1 as defined in the .mdp file.\n"
635                             "Do you have an ion somewhere within the membrane?\n");
636                     /* Write this info to the CompEL output file: */
637                     fprintf(s->fpout, " # Warning: step %s, ion %d moved from %s to %s (probably through the membrane)\n",
638                             gmx_step_str(step, buf), iAtom,
639                             DomainString[*comp_from], DomainString[*comp_now]);
640
641                 }
642                 break;
643             case eChHistPassedCh0:
644             case eChHistPassedCh1:
645                 if (*channel_label == eChHistPassedCh0)
646                 {
647                     chan_nr = 0;
648                 }
649                 else
650                 {
651                     chan_nr = 1;
652                 }
653
654                 if (eDomainA == *comp_from)
655                 {
656                     g->fluxfromAtoB[chan_nr]++;
657                 }
658                 else
659                 {
660                     g->fluxfromAtoB[chan_nr]--;
661                 }
662                 fprintf(fpout, "# Atom nr. %d finished passing %s.\n", iAtom, ChannelString[*channel_label]);
663                 break;
664             default:
665                 gmx_fatal(FARGS, "%s Unknown channel history entry for ion type '%s'\n",
666                           SwS, g->molname);
667         }
668
669         /* This ion has moved to the _other_ compartment ... */
670         *comp_from = *comp_now;
671         /* ... and it did not pass any channel yet */
672         *channel_label = eChHistPassedNone;
673     }
674 }
675
676
677 /*! \brief Determines which ions or solvent molecules are in compartment A and B */
678 static void sortMoleculesIntoCompartments(
679         t_swapgrp      *g,
680         t_commrec      *cr,
681         t_swapcoords   *sc,
682         const matrix    box,
683         int64_t         step,
684         FILE           *fpout,
685         gmx_bool        bRerun,
686         gmx_bool        bIsSolvent)
687 {
688     gmx_swapcoords_t s = sc->si_priv;
689     int              nMolNotInComp[eCompNR]; /* consistency check */
690     real             cyl0_r2 = sc->cyl0r * sc->cyl0r;
691     real             cyl1_r2 = sc->cyl1r * sc->cyl1r;
692
693     /* Get us a counter that cycles in the range of [0 ... sc->nAverage[ */
694     int replace = (step/sc->nstswap) % sc->nAverage;
695
696     for (int comp = eCompA; comp <= eCompB; comp++)
697     {
698         real left, right;
699
700         /* Get lists of atoms that match criteria for this compartment */
701         get_compartment_boundaries(comp, sc->si_priv, box, &left, &right);
702
703         /* First clear the ion molecule lists */
704         g->comp[comp].nMol  = 0;
705         nMolNotInComp[comp] = 0; /* consistency check */
706
707         /* Loop over the molecules and atoms of this group */
708         for (int iMol = 0, iAtom = 0; iAtom < static_cast<int>(g->atomset.numAtomsGlobal()); iAtom += g->apm, iMol++)
709         {
710             real dist;
711             int  sd = s->swapdim;
712
713             /* Is this first atom of the molecule in the compartment that we look at? */
714             if (compartment_contains_atom(left, right, g->xc[iAtom][sd], box[sd][sd], sc->bulkOffset[comp], &dist) )
715             {
716                 /* Add the first atom of this molecule to the list of molecules in this compartment */
717                 add_to_list(iAtom, &g->comp[comp], dist);
718
719                 /* Master also checks for ion groups through which channel each ion has passed */
720                 if (MASTER(cr) && (g->comp_now != nullptr) && !bIsSolvent)
721                 {
722                     int globalAtomNr = g->atomset.globalIndex()[iAtom] + 1; /* PDB index starts at 1 ... */
723                     detect_flux_per_channel(g, globalAtomNr, comp, g->xc[iAtom],
724                                             &g->comp_now[iMol], &g->comp_from[iMol], &g->channel_label[iMol],
725                                             sc, cyl0_r2, cyl1_r2, step, bRerun, fpout);
726                 }
727             }
728             else
729             {
730                 nMolNotInComp[comp]++;
731             }
732         }
733         /* Correct the time-averaged number of ions in the compartment */
734         if (!bIsSolvent)
735         {
736             update_time_window(&g->comp[comp], sc->nAverage, replace);
737         }
738     }
739
740     /* Flux detection warnings */
741     if (MASTER(cr) && !bIsSolvent)
742     {
743         if (g->nCylBoth > 0)
744         {
745             fprintf(stderr, "\n"
746                     "%s Warning: %d atoms were detected as being in both channels! Probably your split\n"
747                     "%s          cylinder is way too large, or one compartment has collapsed (step %" PRId64 ")\n",
748                     SwS, g->nCylBoth, SwS, step);
749
750             fprintf(s->fpout, "Warning: %d atoms were assigned to both channels!\n", g->nCylBoth);
751
752             g->nCylBoth = 0;
753         }
754     }
755
756     if (bIsSolvent && nullptr != fpout)
757     {
758         fprintf(fpout, "# Solv. molecules in comp.%s: %d   comp.%s: %d\n",
759                 CompStr[eCompA], g->comp[eCompA].nMol,
760                 CompStr[eCompB], g->comp[eCompB].nMol);
761     }
762
763     /* Consistency checks */
764     const auto numMolecules = static_cast<int>(g->atomset.numAtomsGlobal() / g->apm);
765     if (nMolNotInComp[eCompA] + nMolNotInComp[eCompB] != numMolecules)
766     {
767         fprintf(stderr, "%s Warning: Inconsistency while assigning '%s' molecules to compartments. !inA: %d, !inB: %d, total molecules %d\n",
768                 SwS, g->molname, nMolNotInComp[eCompA], nMolNotInComp[eCompB], numMolecules);
769     }
770
771     int sum = g->comp[eCompA].nMol + g->comp[eCompB].nMol;
772     if (sum != numMolecules)
773     {
774         fprintf(stderr, "%s Warning: %d molecules are in group '%s', but altogether %d have been assigned to the compartments.\n",
775                 SwS, numMolecules, g->molname, sum);
776     }
777 }
778
779
780 /*! \brief Find out how many group atoms are in the compartments initially */
781 static void get_initial_ioncounts(
782         t_inputrec       *ir,
783         const rvec        x[],   /* the initial positions */
784         const matrix      box,
785         t_commrec        *cr,
786         gmx_bool          bRerun)
787 {
788     t_swapcoords *sc;
789     t_swap       *s;
790     t_swapgrp    *g;
791
792     sc = ir->swap;
793     s  = sc->si_priv;
794
795     /* Loop over the user-defined (ion) groups */
796     for (int ig = eSwapFixedGrpNR; ig < s->ngrp; ig++)
797     {
798         g = &s->group[ig];
799
800         /* Copy the initial positions of the atoms in the group
801          * to the collective array so that we can compartmentalize */
802         for (size_t i = 0; i < g->atomset.numAtomsGlobal(); i++)
803         {
804             int ind = g->atomset.globalIndex()[i];
805             copy_rvec(x[ind], g->xc[i]);
806         }
807
808         /* Set up the compartments and get lists of atoms in each compartment */
809         sortMoleculesIntoCompartments(g, cr, sc, box, 0, s->fpout, bRerun, FALSE);
810
811         /* Set initial molecule counts if requested (as signaled by "-1" value) */
812         for (int ic = 0; ic < eCompNR; ic++)
813         {
814             int requested = sc->grp[ig].nmolReq[ic];
815             if (requested < 0)
816             {
817                 g->comp[ic].nMolReq = g->comp[ic].nMol;
818             }
819             else
820             {
821                 g->comp[ic].nMolReq = requested;
822             }
823         }
824
825         /* Check whether the number of requested molecules adds up to the total number */
826         int req = g->comp[eCompA].nMolReq + g->comp[eCompB].nMolReq;
827         int tot = g->comp[eCompA].nMol + g->comp[eCompB].nMol;
828
829         if ( (req != tot) )
830         {
831             gmx_fatal(FARGS, "Mismatch of the number of %s ions summed over both compartments.\n"
832                       "You requested a total of %d ions (%d in A and %d in B),\n"
833                       "but there are a total of %d ions of this type in the system.\n",
834                       g->molname, req, g->comp[eCompA].nMolReq,
835                       g->comp[eCompB].nMolReq, tot);
836         }
837
838         /* Initialize time-averaging:
839          * Write initial concentrations to all time bins to start with */
840         for (int ic = 0; ic < eCompNR; ic++)
841         {
842             g->comp[ic].nMolAv = g->comp[ic].nMol;
843             for (int i = 0; i < sc->nAverage; i++)
844             {
845                 g->comp[ic].nMolPast[i] = g->comp[ic].nMol;
846             }
847         }
848     }
849 }
850
851
852 /*! \brief Copy history of ion counts from checkpoint file.
853  *
854  * When called, the checkpoint file has already been read in. Here we copy
855  * over the values from .cpt file to the swap data structure.
856  */
857 static void get_initial_ioncounts_from_cpt(
858         t_inputrec *ir, swaphistory_t *swapstate,
859         t_commrec *cr, gmx_bool bVerbose)
860 {
861     t_swapcoords    *sc;
862     t_swap          *s;
863     t_swapgrp       *g;
864     swapstateIons_t *gs;
865
866     sc = ir->swap;
867     s  = sc->si_priv;
868
869     if (MASTER(cr))
870     {
871         /* Copy the past values from the checkpoint values that have been read in already */
872         if (bVerbose)
873         {
874             fprintf(stderr, "%s Copying values from checkpoint\n", SwS);
875         }
876
877         for (int ig = eSwapFixedGrpNR; ig < s->ngrp; ig++)
878         {
879             g  = &s->group[ig];
880             gs = &swapstate->ionType[ig - eSwapFixedGrpNR];
881
882             for (int ic = 0; ic < eCompNR; ic++)
883             {
884                 g->comp[ic].nMolReq    = gs->nMolReq[ic];
885                 g->comp[ic].inflow_net = gs->inflow_net[ic];
886
887                 if (bVerbose)
888                 {
889                     fprintf(stderr, "%s ... Influx netto: %d   Requested: %d   Past values: ", SwS,
890                             g->comp[ic].inflow_net, g->comp[ic].nMolReq);
891                 }
892
893                 for (int j = 0; j < sc->nAverage; j++)
894                 {
895                     g->comp[ic].nMolPast[j] = gs->nMolPast[ic][j];
896                     if (bVerbose)
897                     {
898                         fprintf(stderr, "%d ", g->comp[ic].nMolPast[j]);
899                     }
900                 }
901                 if (bVerbose)
902                 {
903                     fprintf(stderr, "\n");
904                 }
905             }
906         }
907     }
908 }
909
910
911 /*! \brief The master lets all others know about the initial ion counts. */
912 static void bc_initial_concentrations(
913         t_commrec    *cr,
914         t_swapcoords *swap)
915 {
916     int        ic, ig;
917     t_swap    *s;
918     t_swapgrp *g;
919
920
921     s = swap->si_priv;
922
923     for (ig = eSwapFixedGrpNR; ig < s->ngrp; ig++)
924     {
925         g = &s->group[ig];
926
927         for (ic = 0; ic < eCompNR; ic++)
928         {
929             gmx_bcast(sizeof(g->comp[ic].nMolReq), &(g->comp[ic].nMolReq), cr);
930             gmx_bcast(sizeof(g->comp[ic].nMol   ), &(g->comp[ic].nMol   ), cr);
931             gmx_bcast( swap->nAverage * sizeof(g->comp[ic].nMolPast[0]), g->comp[ic].nMolPast, cr);
932         }
933     }
934 }
935
936
937 /*! \brief Ensure that each atom belongs to at most one of the swap groups. */
938 static void check_swap_groups(t_swap *s, int nat, gmx_bool bVerbose)
939 {
940     int  *nGroup    = nullptr; /* This array counts for each atom in the MD system to
941                                   how many swap groups it belongs (should be 0 or 1!) */
942     int   ind       = -1;
943     int   nMultiple = 0;       /* Number of atoms belonging to multiple groups */
944
945
946     if (bVerbose)
947     {
948         fprintf(stderr, "%s Making sure each atom belongs to at most one of the swap groups.\n", SwS);
949     }
950
951     /* Add one to the group count of atoms belonging to a swap group: */
952     snew(nGroup, nat);
953     for (int i = 0; i < s->ngrp; i++)
954     {
955         t_swapgrp *g = &s->group[i];
956         for (size_t j = 0; j < g->atomset.numAtomsGlobal(); j++)
957         {
958             /* Get the global index of this atom of this group: */
959             ind = g->atomset.globalIndex()[j];
960             nGroup[ind]++;
961         }
962     }
963     /* Make sure each atom belongs to at most one of the groups: */
964     for (int i = 0; i < nat; i++)
965     {
966         if (nGroup[i] > 1)
967         {
968             nMultiple++;
969         }
970     }
971     sfree(nGroup);
972
973     if (nMultiple)
974     {
975         gmx_fatal(FARGS, "%s Cannot perform swapping since %d atom%s allocated to more than one swap index group.\n"
976                   "%s Each atom must be allocated to at most one of the split groups, the swap groups, or the solvent.\n"
977                   "%s Check the .mdp file settings regarding the swap index groups or the index groups themselves.\n",
978                   SwS, nMultiple, (1 == nMultiple) ? " is" : "s are", SwSEmpty, SwSEmpty);
979     }
980 }
981
982
983 /*! \brief Get the number of atoms per molecule for this group.
984  *
985  * Also ensure that all the molecules in this group have this number of atoms.
986  */
987 static int get_group_apm_check(
988         int                         igroup,
989         t_swap                     *s,
990         gmx_bool                    bVerbose,
991         gmx_mtop_t                 *mtop)
992 {
993     t_swapgrp *g   = &s->group[igroup];
994     const int *ind = s->group[igroup].atomset.globalIndex().data();
995     int        nat = s->group[igroup].atomset.numAtomsGlobal();
996
997     /* Determine the number of solvent atoms per solvent molecule from the
998      * first solvent atom: */
999     int molb = 0;
1000     mtopGetMolblockIndex(mtop, ind[0], &molb, nullptr, nullptr);
1001     int apm = mtop->moleculeBlockIndices[molb].numAtomsPerMolecule;
1002
1003     if (bVerbose)
1004     {
1005         fprintf(stderr, "%s Checking whether all %s molecules consist of %d atom%s\n", SwS,
1006                 g->molname, apm, apm > 1 ? "s" : "");
1007     }
1008
1009     /* Check whether this is also true for all other solvent atoms */
1010     for (int i = 1; i < nat; i++)
1011     {
1012         mtopGetMolblockIndex(mtop, ind[i], &molb, nullptr, nullptr);
1013         if (apm != mtop->moleculeBlockIndices[molb].numAtomsPerMolecule)
1014         {
1015             gmx_fatal(FARGS, "Not all molecules of swap group %d consist of %d atoms.",
1016                       igroup, apm);
1017         }
1018     }
1019
1020     //TODO: check whether charges and masses of each molecule are identical!
1021     return apm;
1022 }
1023
1024
1025 /*! \brief Print the legend to the swap output file.
1026  *
1027  * Also print the initial values of ion counts and position of split groups.
1028  */
1029 static void print_ionlist_legend(t_inputrec             *ir,
1030                                  const gmx_output_env_t *oenv)
1031 {
1032     const char **legend;
1033     int          count = 0;
1034     char         buf[STRLEN];
1035
1036     t_swap      *s         = ir->swap->si_priv;
1037     int          nIonTypes = ir->swap->ngrp - eSwapFixedGrpNR;
1038     snew(legend, eCompNR*nIonTypes*3 + 2 + eChanNR*nIonTypes + 1);
1039
1040     // Number of molecules and difference to reference counts for each
1041     // compartment and ion type
1042     for (int ic = count = 0; ic < eCompNR; ic++)
1043     {
1044         for (int ig = eSwapFixedGrpNR; ig < s->ngrp; ig++)
1045         {
1046             t_swapGroup *g = &ir->swap->grp[ig];
1047             real         q = s->group[ig].q;
1048
1049             snprintf(buf, STRLEN, "%s %s ions (charge %s%g)", CompStr[ic], g->molname, q > 0 ? "+" : "", q);
1050             legend[count++] = gmx_strdup(buf);
1051
1052             snprintf(buf, STRLEN, "%s av. mismatch to %d %s ions",
1053                      CompStr[ic],  s->group[ig].comp[ic].nMolReq, g->molname);
1054             legend[count++] = gmx_strdup(buf);
1055
1056             snprintf(buf, STRLEN, "%s net %s ion influx", CompStr[ic], g->molname);
1057             legend[count++] = gmx_strdup(buf);
1058         }
1059     }
1060
1061     // Center of split groups
1062     snprintf(buf, STRLEN, "%scenter of %s of split group 0", SwapStr[ir->eSwapCoords], (nullptr != s->group[eGrpSplit0].m) ? "mass" : "geometry");
1063     legend[count++] = gmx_strdup(buf);
1064     snprintf(buf, STRLEN, "%scenter of %s of split group 1", SwapStr[ir->eSwapCoords], (nullptr != s->group[eGrpSplit1].m) ? "mass" : "geometry");
1065     legend[count++] = gmx_strdup(buf);
1066
1067     // Ion flux for each channel and ion type
1068     for (int ic = 0; ic < eChanNR; ic++)
1069     {
1070         for (int ig = eSwapFixedGrpNR; ig < s->ngrp; ig++)
1071         {
1072             t_swapGroup *g = &ir->swap->grp[ig];
1073             snprintf(buf, STRLEN, "A->ch%d->B %s permeations", ic, g->molname);
1074             legend[count++] = gmx_strdup(buf);
1075         }
1076     }
1077
1078     // Number of molecules that leaked from A to B
1079     snprintf(buf, STRLEN, "leakage");
1080     legend[count++] = gmx_strdup(buf);
1081
1082     xvgr_legend(s->fpout, count, legend, oenv);
1083
1084     fprintf(s->fpout, "# Instantaneous ion counts and time-averaged differences to requested numbers\n");
1085
1086     // We add a simple text legend helping to identify the columns with xvgr legend strings
1087     fprintf(s->fpout, "#  time (ps)");
1088     for (int i = 0; i < count; i++)
1089     {
1090         snprintf(buf, STRLEN, "s%d", i);
1091         fprintf(s->fpout, "%10s", buf);
1092     }
1093     fprintf(s->fpout, "\n");
1094     fflush(s->fpout);
1095 }
1096
1097
1098 /*! \brief Initialize channel ion flux detection routine.
1099  *
1100  * Initialize arrays that keep track of where the ions come from and where
1101  * they go.
1102  */
1103 static void detect_flux_per_channel_init(
1104         t_swap        *s,
1105         swaphistory_t *swapstate,
1106         gmx_bool       bStartFromCpt)
1107 {
1108     t_swapgrp       *g;
1109     swapstateIons_t *gs;
1110
1111     /* All these flux detection routines run on the master only */
1112     if (swapstate == nullptr)
1113     {
1114         return;
1115     }
1116
1117     for (int ig = eSwapFixedGrpNR; ig < s->ngrp; ig++)
1118     {
1119         g  = &s->group[ig];
1120         gs = &swapstate->ionType[ig - eSwapFixedGrpNR];
1121
1122         /******************************************************/
1123         /* Channel and domain history for the individual ions */
1124         /******************************************************/
1125         if (bStartFromCpt) /* set the pointers right */
1126         {
1127             g->comp_from     = gs->comp_from;
1128             g->channel_label = gs->channel_label;
1129         }
1130         else /* allocate memory for molecule counts */
1131         {
1132             snew(g->comp_from, g->atomset.numAtomsGlobal()/g->apm);
1133             gs->comp_from = g->comp_from;
1134             snew(g->channel_label, g->atomset.numAtomsGlobal()/g->apm);
1135             gs->channel_label = g->channel_label;
1136         }
1137         snew(g->comp_now, g->atomset.numAtomsGlobal()/g->apm);
1138
1139         /* Initialize the channel and domain history counters */
1140         for (size_t i = 0; i < g->atomset.numAtomsGlobal()/g->apm; i++)
1141         {
1142             g->comp_now[i] = eDomainNotset;
1143             if (!bStartFromCpt)
1144             {
1145                 g->comp_from[i]     = eDomainNotset;
1146                 g->channel_label[i] = eChHistPassedNone;
1147             }
1148         }
1149
1150         /************************************/
1151         /* Channel fluxes for both channels */
1152         /************************************/
1153         g->nCyl[eChan0] = 0;
1154         g->nCyl[eChan1] = 0;
1155         g->nCylBoth     = 0;
1156     }
1157
1158     if (bStartFromCpt)
1159     {
1160         fprintf(stderr, "%s Copying channel fluxes from checkpoint file data\n", SwS);
1161     }
1162
1163
1164     // Loop over ion types (and both channels)
1165     for (int ig = eSwapFixedGrpNR; ig < s->ngrp; ig++)
1166     {
1167         g  = &s->group[ig];
1168         gs = &swapstate->ionType[ig - eSwapFixedGrpNR];
1169
1170         for (int ic = 0; ic < eChanNR; ic++)
1171         {
1172             fprintf(stderr, "%s Channel %d flux history for ion type %s (charge %g): ", SwS, ic, g->molname, g->q);
1173             if (bStartFromCpt)
1174             {
1175                 g->fluxfromAtoB[ic] = gs->fluxfromAtoB[ic];
1176             }
1177             else
1178             {
1179                 g->fluxfromAtoB[ic] = 0;
1180             }
1181
1182             fprintf(stderr, "%d molecule%s",
1183                     g->fluxfromAtoB[ic], g->fluxfromAtoB[ic] == 1 ? "" : "s");
1184             fprintf(stderr, "\n");
1185         }
1186     }
1187
1188     /* Set pointers for checkpoint writing */
1189     swapstate->fluxleak_p = &s->fluxleak;
1190     for (int ig = eSwapFixedGrpNR; ig < s->ngrp; ig++)
1191     {
1192         g  = &s->group[ig];
1193         gs = &swapstate->ionType[ig - eSwapFixedGrpNR];
1194
1195         for (int ic = 0; ic < eChanNR; ic++)
1196         {
1197             gs->fluxfromAtoB_p[ic] = &g->fluxfromAtoB[ic];
1198         }
1199     }
1200 }
1201
1202
1203 /*! \brief Outputs the initial structure to PDB file for debugging reasons.
1204  *
1205  * Output the starting structure so that in case of multimeric channels
1206  * the user can check whether we have the correct PBC image for all atoms.
1207  * If this is not correct, the ion counts per channel will be very likely
1208  * wrong.
1209  */
1210 static void outputStartStructureIfWanted(gmx_mtop_t *mtop, rvec *x, int ePBC, const matrix box)
1211 {
1212     char *env = getenv("GMX_COMPELDUMP");
1213
1214     if (env != nullptr)
1215     {
1216         fprintf(stderr, "\n%s Found env.var. GMX_COMPELDUMP, will output CompEL starting structure made whole.\n"
1217                 "%s In case of multimeric channels, please check whether they have the correct PBC representation.\n",
1218                 SwS, SwSEmpty);
1219
1220         write_sto_conf_mtop("CompELAssumedWholeConfiguration.pdb", *mtop->name, mtop, x, nullptr, ePBC, box);
1221     }
1222 }
1223
1224
1225 /*! \brief Initialize the swapstate structure, used for checkpoint writing.
1226  *
1227  * The swapstate struct stores the information we need to make the channels
1228  * whole again after restarts from a checkpoint file. Here we do the following:
1229  * a) If we did not start from .cpt, we prepare the struct for proper .cpt writing,
1230  * b) if we did start from .cpt, we copy over the last whole structures from .cpt,
1231  * c) in any case, for subsequent checkpoint writing, we set the pointers in
1232  * swapstate to the x_old arrays, which contain the correct PBC representation of
1233  * multimeric channels at the last time step.
1234  */
1235 static void init_swapstate(
1236         swaphistory_t    *swapstate,
1237         t_swapcoords     *sc,
1238         gmx_mtop_t       *mtop,
1239         const rvec       *x,      /* the initial positions */
1240         const matrix      box,
1241         t_inputrec       *ir)
1242 {
1243     rvec      *x_pbc  = nullptr; /* positions of the whole MD system with molecules made whole */
1244     t_swapgrp *g;
1245     t_swap    *s;
1246
1247
1248     s = sc->si_priv;
1249
1250     /* We always need the last whole positions such that
1251      * in the next time step we can make the channels whole again in PBC */
1252     if (swapstate->bFromCpt)
1253     {
1254         /* Copy the last whole positions of each channel from .cpt */
1255         g = &(s->group[eGrpSplit0]);
1256         for (size_t i = 0; i <  g->atomset.numAtomsGlobal(); i++)
1257         {
1258             copy_rvec(swapstate->xc_old_whole[eChan0][i], g->xc_old[i]);
1259         }
1260         g = &(s->group[eGrpSplit1]);
1261         for (size_t i = 0; i <  g->atomset.numAtomsGlobal(); i++)
1262         {
1263             copy_rvec(swapstate->xc_old_whole[eChan1][i], g->xc_old[i]);
1264         }
1265     }
1266     else
1267     {
1268         swapstate->eSwapCoords = ir->eSwapCoords;
1269
1270         /* Set the number of ion types and allocate memory for checkpointing */
1271         swapstate->nIonTypes = s->ngrp - eSwapFixedGrpNR;
1272         snew(swapstate->ionType, swapstate->nIonTypes);
1273
1274         /* Store the total number of ions of each type in the swapstateIons
1275          * structure that is accessible during checkpoint writing */
1276         for (int ii = 0; ii < swapstate->nIonTypes; ii++)
1277         {
1278             swapstateIons_t *gs = &swapstate->ionType[ii];
1279             gs->nMol = sc->grp[ii + eSwapFixedGrpNR].nat;
1280         }
1281
1282         /* Extract the initial split group positions. */
1283
1284         /* Remove pbc, make molecule whole. */
1285         snew(x_pbc, mtop->natoms);
1286         copy_rvecn(x, x_pbc, 0, mtop->natoms);
1287
1288         /* This can only make individual molecules whole, not multimers */
1289         do_pbc_mtop(nullptr, ir->ePBC, box, mtop, x_pbc);
1290
1291         /* Output the starting structure? */
1292         outputStartStructureIfWanted(mtop, x_pbc, ir->ePBC, box);
1293
1294         /* If this is the first run (i.e. no checkpoint present) we assume
1295          * that the starting positions give us the correct PBC representation */
1296         for (int ig = eGrpSplit0; ig <= eGrpSplit1; ig++)
1297         {
1298             g = &(s->group[ig]);
1299             for (size_t i = 0; i < g->atomset.numAtomsGlobal(); i++)
1300             {
1301                 copy_rvec(x_pbc[g->atomset.globalIndex()[i]], g->xc_old[i]);
1302             }
1303         }
1304         sfree(x_pbc);
1305
1306         /* Prepare swapstate arrays for later checkpoint writing */
1307         swapstate->nat[eChan0] = s->group[eGrpSplit0].atomset.numAtomsGlobal();
1308         swapstate->nat[eChan1] = s->group[eGrpSplit1].atomset.numAtomsGlobal();
1309     }
1310
1311     /* For subsequent checkpoint writing, set the swapstate pointers to the xc_old
1312      * arrays that get updated at every swapping step */
1313     swapstate->xc_old_whole_p[eChan0] = &s->group[eGrpSplit0].xc_old;
1314     swapstate->xc_old_whole_p[eChan1] = &s->group[eGrpSplit1].xc_old;
1315 }
1316
1317 /*! \brief Determine the total charge imbalance resulting from the swap groups */
1318 static real getRequestedChargeImbalance(t_swap *s)
1319 {
1320     int        ig;
1321     real       DeltaQ = 0.0;
1322     t_swapgrp *g;
1323     real       particle_charge;
1324     real       particle_number[eCompNR];
1325
1326     //        s->deltaQ =  ( (-1) * s->comp[eCompA][eIonNEG].nat_req + s->comp[eCompA][eIonPOS].nat_req )
1327     //                   - ( (-1) * s->comp[eCompB][eIonNEG].nat_req + s->comp[eCompB][eIonPOS].nat_req );
1328
1329     for (ig = eSwapFixedGrpNR; ig < s->ngrp; ig++)
1330     {
1331         g = &s->group[ig];
1332
1333         particle_charge         = g->q;
1334         particle_number[eCompA] = g->comp[eCompA].nMolReq;
1335         particle_number[eCompB] = g->comp[eCompB].nMolReq;
1336
1337         DeltaQ += particle_charge * (particle_number[eCompA] - particle_number[eCompB]);
1338     }
1339
1340     return DeltaQ;
1341 }
1342
1343
1344 /*! \brief Sorts anions and cations into two separate groups
1345  *
1346  * This routine should be called for the 'anions' and 'cations' group,
1347  * of which the indices were lumped together in the older version of the code.
1348  */
1349 static void copyIndicesToGroup(
1350         const int         *indIons,
1351         int                nIons,
1352         t_swapGroup       *g,
1353         t_commrec         *cr)
1354 {
1355     g->nat = nIons;
1356
1357     /* If explicit ion counts were requested in the .mdp file
1358      * (by setting positive values for the number of ions),
1359      * we can make an additional consistency check here */
1360     if ( (g->nmolReq[eCompA] < 0) && (g->nmolReq[eCompB] < 0) )
1361     {
1362         if (g->nat != (g->nmolReq[eCompA] + g->nmolReq[eCompB]) )
1363         {
1364             gmx_fatal_collective(FARGS, cr->mpi_comm_mysim, MASTER(cr),
1365                                  "%s Inconsistency while importing swap-related data from an old input file version.\n"
1366                                  "%s The requested ion counts in compartments A (%d) and B (%d)\n"
1367                                  "%s do not add up to the number of ions (%d) of this type for the group '%s'.\n",
1368                                  SwS, SwSEmpty, g->nmolReq[eCompA], g->nmolReq[eCompB], SwSEmpty, g->nat, g->molname);
1369         }
1370     }
1371
1372     srenew(g->ind, g->nat);
1373     for (int i = 0; i < g->nat; i++)
1374     {
1375         g->ind[i] = indIons[i];
1376     }
1377 }
1378
1379
1380 /*! \brief Converts old .tpr file CompEL contents to new data layout.
1381  *
1382  *  If we have read an old .tpr file (tpxv <= tpxv_CompElPolyatomicIonsAndMultipleIonTypes),
1383  * anions and cations are stored together in group #3. In the new
1384  * format we store each ion type in a separate group.
1385  * The 'classic' groups are:
1386  * #0 split group 0  - OK
1387  * #1 split group 1  - OK
1388  * #2 solvent        - OK
1389  * #3 anions         - contains also cations, needs to be converted
1390  * #4 cations        - empty before conversion
1391  *
1392  */
1393 static void convertOldToNewGroupFormat(
1394         t_swapcoords *sc,
1395         gmx_mtop_t   *mtop,
1396         gmx_bool      bVerbose,
1397         t_commrec    *cr)
1398 {
1399     t_swapGroup           *g     = &sc->grp[3];
1400
1401     /* Loop through the atom indices of group #3 (anions) and put all indices
1402      * that belong to cations into the cation group.
1403      */
1404     int  nAnions    = 0;
1405     int  nCations   = 0;
1406     int *indAnions  = nullptr;
1407     int *indCations = nullptr;
1408     snew(indAnions, g->nat);
1409     snew(indCations, g->nat);
1410
1411     int molb = 0;
1412     for (int i = 0; i < g->nat; i++)
1413     {
1414         const t_atom &atom = mtopGetAtomParameters(mtop, g->ind[i], &molb);
1415         if (atom.q < 0)
1416         {
1417             // This is an anion, add it to the list of anions
1418             indAnions[nAnions++] = g->ind[i];
1419         }
1420         else
1421         {
1422             // This is a cation, add it to the list of cations
1423             indCations[nCations++] = g->ind[i];
1424         }
1425     }
1426
1427     if (bVerbose)
1428     {
1429         fprintf(stdout, "%s Sorted %d ions into separate groups of %d anions and %d cations.\n",
1430                 SwS, g->nat, nAnions, nCations);
1431     }
1432
1433
1434     /* Now we have the correct lists of anions and cations.
1435      * Copy it to the right groups.
1436      */
1437     copyIndicesToGroup(indAnions, nAnions, g, cr);
1438     g = &sc->grp[4];
1439     copyIndicesToGroup(indCations, nCations, g, cr);
1440     sfree(indAnions);
1441     sfree(indCations);
1442 }
1443
1444
1445 /*! \brief Returns TRUE if we started from an old .tpr
1446  *
1447  * Then we need to re-sort anions and cations into separate groups */
1448 static gmx_bool bConvertFromOldTpr(t_swapcoords *sc)
1449 {
1450     // If the last group has no atoms it means we need to convert!
1451     return (sc->ngrp >= 5) && (0 == sc->grp[4].nat);
1452 }
1453
1454
1455 void init_swapcoords(
1456         FILE                     *fplog,
1457         t_inputrec               *ir,
1458         const char               *fn,
1459         gmx_mtop_t               *mtop,
1460         const t_state            *globalState,
1461         ObservablesHistory       *oh,
1462         t_commrec                *cr,
1463         gmx::LocalAtomSetManager *atomSets,
1464         const gmx_output_env_t   *oenv,
1465         const MdrunOptions       &mdrunOptions)
1466 {
1467     t_swapcoords          *sc;
1468     t_swap                *s;
1469     t_swapgrp             *g;
1470     swapstateIons_t       *gs;
1471     gmx_bool               bAppend, bStartFromCpt;
1472     swaphistory_t         *swapstate = nullptr;
1473
1474     if ( (PAR(cr)) && !DOMAINDECOMP(cr) )
1475     {
1476         gmx_fatal(FARGS, "Position swapping is only implemented for domain decomposition!");
1477     }
1478
1479     bAppend       = mdrunOptions.continuationOptions.appendFiles;
1480     bStartFromCpt = mdrunOptions.continuationOptions.startedFromCheckpoint;
1481
1482     sc          = ir->swap;
1483     sc->si_priv = new t_swap();
1484     s           = sc->si_priv;
1485
1486     if (mdrunOptions.rerun)
1487     {
1488         if (PAR(cr))
1489         {
1490             gmx_fatal(FARGS, "%s This module does not support reruns in parallel\nPlease request a serial run with -nt 1 / -np 1\n", SwS);
1491         }
1492
1493         fprintf(stderr, "%s Rerun - using every available frame\n", SwS);
1494         sc->nstswap  = 1;
1495         sc->nAverage = 1;  /* averaging makes no sense for reruns */
1496     }
1497
1498     if (MASTER(cr) && !bAppend)
1499     {
1500         fprintf(fplog, "\nInitializing ion/water position exchanges\n");
1501         please_cite(fplog, "Kutzner2011b");
1502     }
1503
1504     switch (ir->eSwapCoords)
1505     {
1506         case eswapX:
1507             s->swapdim = XX;
1508             break;
1509         case eswapY:
1510             s->swapdim = YY;
1511             break;
1512         case eswapZ:
1513             s->swapdim = ZZ;
1514             break;
1515         default:
1516             s->swapdim = -1;
1517             break;
1518     }
1519
1520     const gmx_bool bVerbose = mdrunOptions.verbose;
1521
1522     // For compatibility with old .tpr files
1523     if (bConvertFromOldTpr(sc) )
1524     {
1525         convertOldToNewGroupFormat(sc, mtop, bVerbose && MASTER(cr), cr);
1526     }
1527
1528     /* Copy some data and pointers to the group structures for convenience */
1529     /* Number of atoms in the group */
1530     s->ngrp = sc->ngrp;
1531     for (int i = 0; i < s->ngrp; i++)
1532     {
1533         s->group.emplace_back(atomSets->add(gmx::ArrayRef<const int>( sc->grp[i].ind, sc->grp[i].ind+sc->grp[i].nat)));
1534         s->group[i].molname = sc->grp[i].molname;
1535     }
1536
1537     /* Check for overlapping atoms */
1538     check_swap_groups(s, mtop->natoms, bVerbose && MASTER(cr));
1539
1540     /* Allocate space for the collective arrays for all groups */
1541     /* For the collective position array */
1542     for (int i = 0; i < s->ngrp; i++)
1543     {
1544         g = &s->group[i];
1545         snew(g->xc, g->atomset.numAtomsGlobal());
1546
1547         /* For the split groups (the channels) we need some extra memory to
1548          * be able to make the molecules whole even if they span more than
1549          * half of the box size. */
1550         if ( (i == eGrpSplit0) || (i == eGrpSplit1) )
1551         {
1552             snew(g->xc_shifts, g->atomset.numAtomsGlobal());
1553             snew(g->xc_eshifts, g->atomset.numAtomsGlobal());
1554             snew(g->xc_old, g->atomset.numAtomsGlobal());
1555         }
1556     }
1557
1558     if (MASTER(cr))
1559     {
1560         if (oh->swapHistory == nullptr)
1561         {
1562             oh->swapHistory = gmx::compat::make_unique<swaphistory_t>(swaphistory_t {});
1563         }
1564         swapstate = oh->swapHistory.get();
1565
1566         init_swapstate(swapstate, sc, mtop, as_rvec_array(globalState->x.data()), globalState->box, ir);
1567     }
1568
1569     /* After init_swapstate we have a set of (old) whole positions for our
1570      * channels. Now transfer that to all nodes */
1571     if (PAR(cr))
1572     {
1573         for (int ig = eGrpSplit0; ig <= eGrpSplit1; ig++)
1574         {
1575             g = &(s->group[ig]);
1576             gmx_bcast((g->atomset.numAtomsGlobal())*sizeof((g->xc_old)[0]), g->xc_old, (cr));
1577         }
1578     }
1579
1580     /* Make sure that all molecules in the solvent and ion groups contain the
1581      * same number of atoms each */
1582     for (int ig = eGrpSolvent; ig < s->ngrp; ig++)
1583     {
1584         real charge;
1585
1586         g      = &(s->group[ig]);
1587         g->apm = get_group_apm_check(ig, s, MASTER(cr) && bVerbose, mtop);
1588
1589         /* Since all molecules of a group are equal, we only need enough space
1590          * to determine properties of a single molecule at at time */
1591         snew(g->m, g->apm);  /* For the center of mass */
1592         charge = 0;          /* To determine the charge imbalance */
1593         int molb = 0;
1594         for (int j = 0; j < g->apm; j++)
1595         {
1596             const t_atom &atom = mtopGetAtomParameters(mtop, g->atomset.globalIndex()[j], &molb);
1597             g->m[j] = atom.m;
1598             charge += atom.q;
1599         }
1600         /* Total charge of one molecule of this group: */
1601         g->q = charge;
1602     }
1603
1604
1605     /* Need mass-weighted center of split group? */
1606     for (int j = eGrpSplit0; j <= eGrpSplit1; j++)
1607     {
1608         g = &(s->group[j]);
1609         if (TRUE == sc->massw_split[j])
1610         {
1611             /* Save the split group masses if mass-weighting is requested */
1612             snew(g->m, g->atomset.numAtomsGlobal());
1613             int molb = 0;
1614             for (size_t i = 0; i < g->atomset.numAtomsGlobal(); i++)
1615             {
1616                 g->m[i] = mtopGetAtomMass(mtop, g->atomset.globalIndex()[i], &molb);
1617             }
1618         }
1619     }
1620
1621     /* Make a t_pbc struct on all nodes so that the molecules
1622      * chosen for an exchange can be made whole. */
1623     snew(s->pbc, 1);
1624
1625     if (MASTER(cr))
1626     {
1627         if (bVerbose)
1628         {
1629             fprintf(stderr, "%s Opening output file %s%s\n", SwS, fn, bAppend ? " for appending" : "");
1630         }
1631
1632         s->fpout = gmx_fio_fopen(fn, bAppend ? "a" : "w" );
1633
1634         if (!bAppend)
1635         {
1636             xvgr_header(s->fpout, "Molecule counts", "Time (ps)", "counts", exvggtXNY, oenv);
1637
1638             for (int ig = 0; ig < s->ngrp; ig++)
1639             {
1640                 g = &(s->group[ig]);
1641                 fprintf(s->fpout, "# %s group '%s' contains %d atom%s",
1642                         ig < eSwapFixedGrpNR ? eSwapFixedGrp_names[ig] : "Ion",
1643                         g->molname, static_cast<int>(g->atomset.numAtomsGlobal()), (g->atomset.numAtomsGlobal() > 1) ? "s" : "");
1644                 if (!(eGrpSplit0 == ig || eGrpSplit1 == ig) )
1645                 {
1646                     fprintf(s->fpout, " with %d atom%s in each molecule of charge %g",
1647                             g->apm, (g->apm > 1) ? "s" : "", g->q);
1648                 }
1649                 fprintf(s->fpout, ".\n");
1650             }
1651
1652             fprintf(s->fpout, "#\n# Initial positions of split groups:\n");
1653         }
1654
1655         for (int j = eGrpSplit0; j <= eGrpSplit1; j++)
1656         {
1657             g = &(s->group[j]);
1658             for (size_t i = 0; i < g->atomset.numAtomsGlobal(); i++)
1659             {
1660                 copy_rvec(globalState->x[sc->grp[j].ind[i]], g->xc[i]);
1661             }
1662             /* xc has the correct PBC representation for the two channels, so we do
1663              * not need to correct for that */
1664             get_center(g->xc, g->m, g->atomset.numAtomsGlobal(), g->center);
1665             if (!bAppend)
1666             {
1667                 fprintf(s->fpout, "# %s group %s-center %5f nm\n", eSwapFixedGrp_names[j],
1668                         DimStr[s->swapdim], g->center[s->swapdim]);
1669             }
1670         }
1671
1672         if (!bAppend)
1673         {
1674             if ( (0 != sc->bulkOffset[eCompA]) || (0 != sc->bulkOffset[eCompB]) )
1675             {
1676                 fprintf(s->fpout, "#\n");
1677                 fprintf(s->fpout, "# You provided an offset for the position of the bulk layer(s).\n");
1678                 fprintf(s->fpout, "# That means the layers to/from which ions and water molecules are swapped\n");
1679                 fprintf(s->fpout, "# are not midway (= at 0.0) between the compartment-defining layers (at +/- 1.0).\n");
1680                 fprintf(s->fpout, "# bulk-offsetA = %g\n", sc->bulkOffset[eCompA]);
1681                 fprintf(s->fpout, "# bulk-offsetB = %g\n", sc->bulkOffset[eCompB]);
1682             }
1683
1684             fprintf(s->fpout, "#\n");
1685             fprintf(s->fpout, "# Split0 cylinder radius %f nm, up %f nm, down %f nm\n",
1686                     sc->cyl0r, sc->cyl0u, sc->cyl0l);
1687             fprintf(s->fpout, "# Split1 cylinder radius %f nm, up %f nm, down %f nm\n",
1688                     sc->cyl1r, sc->cyl1u, sc->cyl1l);
1689
1690             fprintf(s->fpout, "#\n");
1691             if (!mdrunOptions.rerun)
1692             {
1693                 fprintf(s->fpout, "# Coupling constant (number of swap attempt steps to average over): %d  (translates to %f ps).\n",
1694                         sc->nAverage, sc->nAverage*sc->nstswap*ir->delta_t);
1695                 fprintf(s->fpout, "# Threshold is %f\n", sc->threshold);
1696                 fprintf(s->fpout, "#\n");
1697                 fprintf(s->fpout, "# Remarks about which atoms passed which channel use global atoms numbers starting at one.\n");
1698             }
1699         }
1700     }
1701     else
1702     {
1703         s->fpout = nullptr;
1704     }
1705
1706     /* Allocate memory to remember the past particle counts for time averaging */
1707     for (int ig = eSwapFixedGrpNR; ig < s->ngrp; ig++)
1708     {
1709         g = &(s->group[ig]);
1710         for (int ic = 0; ic < eCompNR; ic++)
1711         {
1712             snew(g->comp[ic].nMolPast, sc->nAverage);
1713         }
1714     }
1715
1716     /* Get the initial particle concentrations and let the other nodes know */
1717     if (MASTER(cr))
1718     {
1719         if (bStartFromCpt)
1720         {
1721             get_initial_ioncounts_from_cpt(ir, swapstate, cr, bVerbose);
1722         }
1723         else
1724         {
1725             fprintf(stderr, "%s Determining initial numbers of ions per compartment.\n", SwS);
1726             get_initial_ioncounts(ir, as_rvec_array(globalState->x.data()), globalState->box, cr, mdrunOptions.rerun);
1727         }
1728
1729         /* Prepare (further) checkpoint writes ... */
1730         if (bStartFromCpt)
1731         {
1732             /* Consistency check */
1733             if (swapstate->nAverage != sc->nAverage)
1734             {
1735                 gmx_fatal(FARGS, "%s Ion count averaging steps mismatch! checkpoint: %d, tpr: %d",
1736                           SwS, swapstate->nAverage, sc->nAverage);
1737             }
1738         }
1739         else
1740         {
1741             swapstate->nAverage = sc->nAverage;
1742         }
1743         fprintf(stderr, "%s Setting pointers for checkpoint writing\n", SwS);
1744         for (int ic = 0; ic < eCompNR; ic++)
1745         {
1746             for (int ig = eSwapFixedGrpNR; ig < s->ngrp; ig++)
1747             {
1748                 g  = &s->group[ig];
1749                 gs = &swapstate->ionType[ig - eSwapFixedGrpNR];
1750
1751                 gs->nMolReq_p[ic]    = &(g->comp[ic].nMolReq);
1752                 gs->nMolPast_p[ic]   = &(g->comp[ic].nMolPast[0]);
1753                 gs->inflow_net_p[ic] = &(g->comp[ic].inflow_net);
1754             }
1755         }
1756
1757         /* Determine the total charge imbalance */
1758         s->deltaQ = getRequestedChargeImbalance(s);
1759
1760         if (bVerbose)
1761         {
1762             fprintf(stderr, "%s Requested charge imbalance is Q(A) - Q(B) = %g e.\n", SwS, s->deltaQ);
1763         }
1764         if (!bAppend)
1765         {
1766             fprintf(s->fpout, "# Requested charge imbalance is Q(A)-Q(B) = %g e.\n", s->deltaQ);
1767         }
1768     }
1769
1770     if (PAR(cr))
1771     {
1772         bc_initial_concentrations(cr, ir->swap);
1773     }
1774
1775     /* Update the time-averaged number of molecules for all groups and compartments */
1776     for (int ig = eSwapFixedGrpNR; ig < sc->ngrp; ig++)
1777     {
1778         g = &s->group[ig];
1779         for (int ic = 0; ic < eCompNR; ic++)
1780         {
1781             update_time_window(&g->comp[ic], sc->nAverage, -1);
1782         }
1783     }
1784
1785     /* Initialize arrays that keep track of through which channel the ions go */
1786     detect_flux_per_channel_init(s, swapstate, bStartFromCpt);
1787
1788     /* We need to print the legend if we open this file for the first time. */
1789     if (MASTER(cr) && !bAppend)
1790     {
1791         print_ionlist_legend(ir, oenv);
1792     }
1793 }
1794
1795
1796 void finish_swapcoords(t_swapcoords *sc)
1797 {
1798     if (sc->si_priv->fpout)
1799     {
1800         // Close the swap output file
1801         gmx_fio_fclose(sc->si_priv->fpout);
1802     }
1803 }
1804
1805 /*! \brief Do we need to swap a molecule in any of the ion groups with a water molecule at this step?
1806  *
1807  * From the requested and average molecule counts we determine whether a swap is needed
1808  * at this time step.
1809  */
1810 static gmx_bool need_swap(t_swapcoords *sc)
1811 {
1812     t_swap    *s;
1813     int        ic, ig;
1814     t_swapgrp *g;
1815
1816     s = sc->si_priv;
1817
1818     for (ig = eSwapFixedGrpNR; ig < sc->ngrp; ig++)
1819     {
1820         g = &s->group[ig];
1821
1822         for (ic = 0; ic < eCompNR; ic++)
1823         {
1824             if (g->comp[ic].nMolReq - g->comp[ic].nMolAv >= sc->threshold)
1825             {
1826                 return TRUE;
1827             }
1828         }
1829     }
1830     return FALSE;
1831 }
1832
1833
1834 /*! \brief Return the index of an atom or molecule suitable for swapping.
1835  *
1836  * Returns the index of an atom that is far off the compartment boundaries,
1837  * that is near to the bulk layer to/from which the swaps take place.
1838  * Other atoms of the molecule (if any) will directly follow the returned index.
1839  *
1840  * \param[in] comp    Structure containing compartment-specific data.
1841  * \param[in] molname Name of the molecule.
1842  *
1843  * \returns Index of the first atom of the molecule chosen for a position exchange.
1844  */
1845 static int get_index_of_distant_atom(
1846         t_compartment *comp,
1847         const char     molname[])
1848 {
1849     int  ibest = -1;
1850     real d     = GMX_REAL_MAX;
1851
1852
1853     /* comp->nat contains the original number of atoms in this compartment
1854      * prior to doing any swaps. Some of these atoms may already have been
1855      * swapped out, but then they are marked with a distance of GMX_REAL_MAX
1856      */
1857     for (int iMol  = 0; iMol < comp->nMolBefore; iMol++)
1858     {
1859         if (comp->dist[iMol] < d)
1860         {
1861             ibest = iMol;
1862             d     = comp->dist[ibest];
1863         }
1864     }
1865
1866     if (ibest < 0)
1867     {
1868         gmx_fatal(FARGS, "Could not get index of %s atom. Compartment contains %d %s molecules before swaps.",
1869                   molname, comp->nMolBefore, molname);
1870     }
1871
1872     /* Set the distance of this index to infinity such that it won't get selected again in
1873      * this time step
1874      */
1875     comp->dist[ibest] = GMX_REAL_MAX;
1876
1877     return comp->ind[ibest];
1878 }
1879
1880
1881 /*! \brief Swaps centers of mass and makes molecule whole if broken */
1882 static void translate_positions(
1883         rvec  *x,
1884         int    apm,
1885         rvec   old_com,
1886         rvec   new_com,
1887         t_pbc *pbc)
1888 {
1889     int  i;
1890     rvec reference, dx, correctPBCimage;
1891
1892
1893     /* Use the first atom as the reference for PBC */
1894     copy_rvec(x[0], reference);
1895
1896     for (i = 0; i < apm; i++)
1897     {
1898         /* PBC distance between position and reference */
1899         pbc_dx(pbc, x[i], reference, dx);
1900
1901         /* Add PBC distance to reference */
1902         rvec_add(reference, dx, correctPBCimage);
1903
1904         /* Subtract old_com from correct image and add new_com */
1905         rvec_dec(correctPBCimage, old_com);
1906         rvec_inc(correctPBCimage, new_com);
1907
1908         copy_rvec(correctPBCimage, x[i]);
1909     }
1910 }
1911
1912
1913 /*! \brief Write back the the modified local positions from the collective array to the official positions. */
1914 static void apply_modified_positions(
1915         swap_group *g,
1916         rvec        x[])
1917 {
1918     auto collectiveIndex = g->atomset.collectiveIndex().begin();
1919     for (const auto localIndex : g->atomset.localIndex())
1920     {
1921         /* Copy the possibly modified position */
1922         copy_rvec(g->xc[*collectiveIndex], x[localIndex]);
1923         ++collectiveIndex;
1924     }
1925 }
1926
1927
1928 gmx_bool do_swapcoords(
1929         t_commrec        *cr,
1930         int64_t           step,
1931         double            t,
1932         t_inputrec       *ir,
1933         gmx_wallcycle    *wcycle,
1934         rvec              x[],
1935         matrix            box,
1936         gmx_bool          bVerbose,
1937         gmx_bool          bRerun)
1938 {
1939     t_swapcoords         *sc;
1940     t_swap               *s;
1941     int                   j, ic, ig, nswaps;
1942     int                   thisC, otherC; /* Index into this compartment and the other one */
1943     gmx_bool              bSwap = FALSE;
1944     t_swapgrp            *g, *gsol;
1945     int                   isol, iion;
1946     rvec                  com_solvent, com_particle; /* solvent and swap molecule's center of mass */
1947
1948
1949     wallcycle_start(wcycle, ewcSWAP);
1950
1951     sc  = ir->swap;
1952     s   = sc->si_priv;
1953
1954     set_pbc(s->pbc, ir->ePBC, box);
1955
1956     /* Assemble the positions of the split groups, i.e. the channels.
1957      * Here we also pass a shifts array to communicate_group_positions(), so that it can make
1958      * the molecules whole even in cases where they span more than half of the box in
1959      * any dimension */
1960     for (ig = eGrpSplit0; ig <= eGrpSplit1; ig++)
1961     {
1962         g = &(s->group[ig]);
1963         communicate_group_positions(cr, g->xc, g->xc_shifts, g->xc_eshifts, TRUE,
1964                                     x, g->atomset.numAtomsGlobal(), g->atomset.numAtomsLocal(), g->atomset.localIndex().data(), g->atomset.collectiveIndex().data(), g->xc_old, box);
1965
1966         get_center(g->xc, g->m, g->atomset.numAtomsGlobal(), g->center); /* center of split groups == channels */
1967     }
1968
1969     /* Assemble the positions of the ions (ig = 3, 4, ...). These molecules should
1970      * be small and we can always make them whole with a simple distance check.
1971      * Therefore we pass NULL as third argument. */
1972     for (ig = eSwapFixedGrpNR; ig < s->ngrp; ig++)
1973     {
1974         g = &(s->group[ig]);
1975         communicate_group_positions(cr, g->xc, nullptr, nullptr, FALSE,
1976                                     x, g->atomset.numAtomsGlobal(), g->atomset.numAtomsLocal(), g->atomset.localIndex().data(), g->atomset.collectiveIndex().data(), nullptr, nullptr);
1977
1978         /* Determine how many ions of this type each compartment contains */
1979         sortMoleculesIntoCompartments(g, cr, sc, box, step, s->fpout, bRerun, FALSE);
1980     }
1981
1982     /* Output how many ions are in the compartments */
1983     if (MASTER(cr))
1984     {
1985         print_ionlist(s, t, "");
1986     }
1987
1988     /* If we are doing a rerun, we are finished here, since we cannot perform
1989      * swaps anyway */
1990     if (bRerun)
1991     {
1992         return FALSE;
1993     }
1994
1995     /* Do we have to perform a swap? */
1996     bSwap = need_swap(sc);
1997     if (bSwap)
1998     {
1999         /* Since we here know that we have to perform ion/water position exchanges,
2000          * we now assemble the solvent positions */
2001         g = &(s->group[eGrpSolvent]);
2002         communicate_group_positions(cr, g->xc, nullptr, nullptr, FALSE,
2003                                     x, g->atomset.numAtomsGlobal(), g->atomset.numAtomsLocal(), g->atomset.localIndex().data(), g->atomset.collectiveIndex().data(), nullptr, nullptr);
2004
2005         /* Determine how many molecules of solvent each compartment contains */
2006         sortMoleculesIntoCompartments(g, cr, sc, box, step, s->fpout, bRerun, TRUE);
2007
2008         /* Save number of solvent molecules per compartment prior to any swaps */
2009         g->comp[eCompA].nMolBefore = g->comp[eCompA].nMol;
2010         g->comp[eCompB].nMolBefore = g->comp[eCompB].nMol;
2011
2012         for (ig = eSwapFixedGrpNR; ig < s->ngrp; ig++)
2013         {
2014             g = &(s->group[ig]);
2015
2016             for (ic = 0; ic < eCompNR; ic++)
2017             {
2018                 /* Determine in which compartment ions are missing and where they are too many */
2019                 g->vacancy[ic] = g->comp[ic].nMolReq - g->comp[ic].nMolAv;
2020
2021                 /* Save number of ions per compartment prior to swaps */
2022                 g->comp[ic].nMolBefore = g->comp[ic].nMol;
2023             }
2024         }
2025
2026         /* Now actually perform the particle exchanges, one swap group after another */
2027         gsol   = &s->group[eGrpSolvent];
2028         for (ig = eSwapFixedGrpNR; ig < s->ngrp; ig++)
2029         {
2030             nswaps = 0;
2031             g      = &s->group[ig];
2032             for (thisC = 0; thisC < eCompNR; thisC++)
2033             {
2034                 /* Index to the other compartment */
2035                 otherC = (thisC+1) % eCompNR;
2036
2037                 while (g->vacancy[thisC] >= sc->threshold)
2038                 {
2039                     /* Swap in an ion */
2040
2041                     /* Get the xc-index of the first atom of a solvent molecule of this compartment */
2042                     isol = get_index_of_distant_atom(&gsol->comp[thisC], gsol->molname);
2043
2044                     /* Get the xc-index of a particle from the other compartment */
2045                     iion = get_index_of_distant_atom(&g->comp[otherC], g->molname);
2046
2047                     get_molecule_center(&gsol->xc[isol], gsol->apm, gsol->m, com_solvent, s->pbc);
2048                     get_molecule_center(&g->xc[iion], g->apm, g->m, com_particle, s->pbc);
2049
2050                     /* Subtract solvent molecule's center of mass and add swap particle's center of mass */
2051                     translate_positions(&gsol->xc[isol], gsol->apm, com_solvent, com_particle, s->pbc);
2052                     /* Similarly for the swap particle, subtract com_particle and add com_solvent */
2053                     translate_positions(&g->xc[iion], g->apm, com_particle, com_solvent, s->pbc);
2054
2055                     /* Keep track of the changes */
2056                     g->vacancy[thisC ]--;
2057                     g->vacancy[otherC]++;
2058                     g->comp   [thisC ].nMol++;
2059                     g->comp   [otherC].nMol--;
2060                     g->comp   [thisC ].inflow_net++;
2061                     g->comp   [otherC].inflow_net--;
2062                     /* Correct the past time window to still get the right averages from now on */
2063                     g->comp   [thisC ].nMolAv++;
2064                     g->comp   [otherC].nMolAv--;
2065                     for (j = 0; j < sc->nAverage; j++)
2066                     {
2067                         g->comp[thisC ].nMolPast[j]++;
2068                         g->comp[otherC].nMolPast[j]--;
2069                     }
2070                     /* Clear ion history */
2071                     if (MASTER(cr))
2072                     {
2073                         int iMol = iion / g->apm;
2074                         g->channel_label[iMol] = eChHistPassedNone;
2075                         g->comp_from[iMol]     = eDomainNotset;
2076                     }
2077                     /* That was the swap */
2078                     nswaps++;
2079                 }
2080             }
2081
2082             if (nswaps && bVerbose)
2083             {
2084                 fprintf(stderr, "%s Performed %d swap%s in step %" PRId64 " for iontype %s.\n",
2085                         SwS, nswaps, nswaps > 1 ? "s" : "", step, g->molname);
2086             }
2087         }
2088
2089         if (s->fpout != nullptr)
2090         {
2091             print_ionlist(s, t, "  # after swap");
2092         }
2093
2094         /* For the solvent and user-defined swap groups, each rank writes back its
2095          * (possibly modified) local positions to the official position array. */
2096         for (ig = eGrpSolvent; ig < s->ngrp; ig++)
2097         {
2098             g  = &s->group[ig];
2099             apply_modified_positions(g, x);
2100         }
2101
2102     } /* end of if(bSwap) */
2103
2104     wallcycle_stop(wcycle, ewcSWAP);
2105
2106     return bSwap;
2107 }