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