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