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