08cf72fabcbcf64582d58796a132bfbb262a794b
[alexxy/gromacs.git] / src / gromacs / domdec / domdec_constraints.cpp
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * Copyright (c) 2006,2007,2008,2009,2010,2012,2013,2014,2015,2016,2017,2018, by the GROMACS development team, led by
5  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
6  * and including many others, as listed in the AUTHORS file in the
7  * top-level source directory and at http://www.gromacs.org.
8  *
9  * GROMACS is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public License
11  * as published by the Free Software Foundation; either version 2.1
12  * of the License, or (at your option) any later version.
13  *
14  * GROMACS is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with GROMACS; if not, see
21  * http://www.gnu.org/licenses, or write to the Free Software Foundation,
22  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
23  *
24  * If you want to redistribute modifications to GROMACS, please
25  * consider that scientific software is very special. Version
26  * control is crucial - bugs must be traceable. We will be happy to
27  * consider code for inclusion in the official distribution, but
28  * derived work must not be called official GROMACS. Details are found
29  * in the README & COPYING files - if they are missing, get the
30  * official version at http://www.gromacs.org.
31  *
32  * To help us fund GROMACS development, we humbly ask that you cite
33  * the research papers on the package. Check out http://www.gromacs.org.
34  */
35
36 /*! \internal \file
37  *
38  * \brief This file implements functions for domdec to use
39  * while managing inter-atomic constraints.
40  *
41  * \author Berk Hess <hess@kth.se>
42  * \ingroup module_domdec
43  */
44
45 #include "gmxpre.h"
46
47 #include "domdec_constraints.h"
48
49 #include <assert.h>
50
51 #include <algorithm>
52
53 #include "gromacs/compat/make_unique.h"
54 #include "gromacs/domdec/dlbtiming.h"
55 #include "gromacs/domdec/domdec.h"
56 #include "gromacs/domdec/domdec_struct.h"
57 #include "gromacs/domdec/ga2la.h"
58 #include "gromacs/math/vec.h"
59 #include "gromacs/mdlib/constr.h"
60 #include "gromacs/mdlib/gmx_omp_nthreads.h"
61 #include "gromacs/mdtypes/commrec.h"
62 #include "gromacs/mdtypes/forcerec.h" // only for GET_CGINFO_*
63 #include "gromacs/pbcutil/ishift.h"
64 #include "gromacs/topology/ifunc.h"
65 #include "gromacs/topology/mtop_lookup.h"
66 #include "gromacs/utility/exceptions.h"
67 #include "gromacs/utility/fatalerror.h"
68 #include "gromacs/utility/gmxassert.h"
69
70 #include "domdec_specatomcomm.h"
71 #include "domdec_vsite.h"
72 #include "hash.h"
73
74 /*! \brief Struct used during constraint setup with domain decomposition */
75 struct gmx_domdec_constraints_t
76 {
77     //! @cond Doxygen_Suppress
78     std::vector<int>  molb_con_offset; /**< Offset in the constraint array for each molblock */
79     std::vector<int>  molb_ncon_mol;   /**< The number of constraints per molecule for each molblock */
80
81     int               ncon;            /**< The fully local and conneced constraints */
82     /* The global constraint number, only required for clearing gc_req */
83     std::vector<int>  con_gl;          /**< Global constraint indices for local constraints */
84     std::vector<int>  con_nlocat;      /**< Number of local atoms (2/1/0) for each constraint */
85
86     std::vector<bool> gc_req;          /**< Boolean that tells if a global constraint index has been requested; note: size global #constraints */
87
88     /* Hash table for keeping track of requests */
89     std::unique_ptr<gmx_hash_t> ga2la; /**< Global to local communicated constraint atom only index */
90
91     /* Multi-threading stuff */
92     int                  nthread; /**< Number of threads used for DD constraint setup */
93     std::vector<t_ilist> ils;     /**< Constraint ilist working arrays, size \p nthread */
94
95     /* Buffers for requesting atoms */
96     std::vector < std::vector < int>> requestedGlobalAtomIndices; /**< Buffers for requesting global atom indices, one per thread */
97
98     //! @endcond
99 };
100
101 void dd_move_x_constraints(gmx_domdec_t *dd, matrix box,
102                            rvec *x0, rvec *x1, gmx_bool bX1IsCoord)
103 {
104     if (dd->constraint_comm)
105     {
106         dd_move_x_specat(dd, dd->constraint_comm, box, x0, x1, bX1IsCoord);
107
108         ddReopenBalanceRegionCpu(dd);
109     }
110 }
111
112 gmx::ArrayRef<const int> dd_constraints_nlocalatoms(const gmx_domdec_t *dd)
113 {
114     if (dd && dd->constraints)
115     {
116         return dd->constraints->con_nlocat;
117     }
118     else
119     {
120         return gmx::EmptyArrayRef();
121     }
122 }
123
124 void dd_clear_local_constraint_indices(gmx_domdec_t *dd)
125 {
126     gmx_domdec_constraints_t *dc = dd->constraints;
127
128     std::fill(dc->gc_req.begin(), dc->gc_req.end(), false);
129
130     if (dd->constraint_comm)
131     {
132         gmx_hash_clear_and_optimize(dc->ga2la.get());
133     }
134 }
135
136 void dd_clear_local_vsite_indices(gmx_domdec_t *dd)
137 {
138     if (dd->vsite_comm)
139     {
140         gmx_hash_clear_and_optimize(dd->ga2la_vsite);
141     }
142 }
143
144 /*! \brief Walks over the constraints out from the local atoms into the non-local atoms and adds them to a list */
145 static void walk_out(int con, int con_offset, int a, int offset, int nrec,
146                      int ncon1, const t_iatom *ia1, const t_iatom *ia2,
147                      const t_blocka *at2con,
148                      const gmx_ga2la_t *ga2la, gmx_bool bHomeConnect,
149                      gmx_domdec_constraints_t *dc,
150                      gmx_domdec_specat_comm_t *dcc,
151                      t_ilist *il_local,
152                      std::vector<int> *ireq)
153 {
154     int            a1_gl, a2_gl, a_loc, i, coni, b;
155     const t_iatom *iap;
156
157     if (!dc->gc_req[con_offset + con])
158     {
159         /* Add this non-home constraint to the list */
160         dc->con_gl.push_back(con_offset + con);
161         dc->con_nlocat.push_back(bHomeConnect ? 1 : 0);
162         dc->gc_req[con_offset + con] = true;
163         if (il_local->nr + 3 > il_local->nalloc)
164         {
165             il_local->nalloc = over_alloc_dd(il_local->nr+3);
166             srenew(il_local->iatoms, il_local->nalloc);
167         }
168         iap = constr_iatomptr(ncon1, ia1, ia2, con);
169         il_local->iatoms[il_local->nr++] = iap[0];
170         a1_gl = offset + iap[1];
171         a2_gl = offset + iap[2];
172         /* The following indexing code can probably be optizimed */
173         if (ga2la_get_home(ga2la, a1_gl, &a_loc))
174         {
175             il_local->iatoms[il_local->nr++] = a_loc;
176         }
177         else
178         {
179             /* We set this index later */
180             il_local->iatoms[il_local->nr++] = -a1_gl - 1;
181         }
182         if (ga2la_get_home(ga2la, a2_gl, &a_loc))
183         {
184             il_local->iatoms[il_local->nr++] = a_loc;
185         }
186         else
187         {
188             /* We set this index later */
189             il_local->iatoms[il_local->nr++] = -a2_gl - 1;
190         }
191         dc->ncon++;
192     }
193     /* Check to not ask for the same atom more than once */
194     if (gmx_hash_get_minone(dc->ga2la.get(), offset+a) == -1)
195     {
196         assert(dcc);
197         /* Add this non-home atom to the list */
198         ireq->push_back(offset + a);
199         /* Temporarily mark with -2, we get the index later */
200         gmx_hash_set(dc->ga2la.get(), offset+a, -2);
201     }
202
203     if (nrec > 0)
204     {
205         for (i = at2con->index[a]; i < at2con->index[a+1]; i++)
206         {
207             coni = at2con->a[i];
208             if (coni != con)
209             {
210                 /* Walk further */
211                 iap = constr_iatomptr(ncon1, ia1, ia2, coni);
212                 if (a == iap[1])
213                 {
214                     b = iap[2];
215                 }
216                 else
217                 {
218                     b = iap[1];
219                 }
220                 if (!ga2la_get_home(ga2la, offset+b, &a_loc))
221                 {
222                     walk_out(coni, con_offset, b, offset, nrec-1,
223                              ncon1, ia1, ia2, at2con,
224                              ga2la, FALSE, dc, dcc, il_local, ireq);
225                 }
226             }
227         }
228     }
229 }
230
231 /*! \brief Looks up SETTLE constraints for a range of charge-groups */
232 static void atoms_to_settles(gmx_domdec_t *dd,
233                              const gmx_mtop_t *mtop,
234                              const int *cginfo,
235                              const int **at2settle_mt,
236                              int cg_start, int cg_end,
237                              t_ilist *ils_local,
238                              std::vector<int> *ireq)
239 {
240     gmx_ga2la_t *ga2la = dd->ga2la;
241     int          nral  = NRAL(F_SETTLE);
242
243     int          mb    = 0;
244     for (int cg = cg_start; cg < cg_end; cg++)
245     {
246         if (GET_CGINFO_SETTLE(cginfo[cg]))
247         {
248             for (int a : dd->atomGrouping().block(cg))
249             {
250                 int a_gl = dd->globalAtomIndices[a];
251                 int a_mol;
252                 mtopGetMolblockIndex(mtop, a_gl, &mb, nullptr, &a_mol);
253
254                 const gmx_molblock_t *molb   = &mtop->molblock[mb];
255                 int                   settle = at2settle_mt[molb->type][a_mol];
256
257                 if (settle >= 0)
258                 {
259                     int      offset  = a_gl - a_mol;
260
261                     t_iatom *ia1     = mtop->moltype[molb->type].ilist[F_SETTLE].iatoms;
262
263                     int      a_gls[3], a_locs[3];
264                     gmx_bool bAssign = FALSE;
265                     int      nlocal  = 0;
266                     for (int sa = 0; sa < nral; sa++)
267                     {
268                         int a_glsa = offset + ia1[settle*(1+nral)+1+sa];
269                         a_gls[sa]  = a_glsa;
270                         if (ga2la_get_home(ga2la, a_glsa, &a_locs[sa]))
271                         {
272                             if (nlocal == 0 && a_gl == a_glsa)
273                             {
274                                 bAssign = TRUE;
275                             }
276                             nlocal++;
277                         }
278                     }
279
280                     if (bAssign)
281                     {
282                         if (ils_local->nr+1+nral > ils_local->nalloc)
283                         {
284                             ils_local->nalloc = over_alloc_dd(ils_local->nr+1+nral);
285                             srenew(ils_local->iatoms, ils_local->nalloc);
286                         }
287
288                         ils_local->iatoms[ils_local->nr++] = ia1[settle*4];
289
290                         for (int sa = 0; sa < nral; sa++)
291                         {
292                             if (ga2la_get_home(ga2la, a_gls[sa], &a_locs[sa]))
293                             {
294                                 ils_local->iatoms[ils_local->nr++] = a_locs[sa];
295                             }
296                             else
297                             {
298                                 ils_local->iatoms[ils_local->nr++] = -a_gls[sa] - 1;
299                                 /* Add this non-home atom to the list */
300                                 ireq->push_back(a_gls[sa]);
301                                 /* A check on double atom requests is
302                                  * not required for settle.
303                                  */
304                             }
305                         }
306                     }
307                 }
308             }
309         }
310     }
311 }
312
313 /*! \brief Looks up constraint for the local atoms */
314 static void atoms_to_constraints(gmx_domdec_t *dd,
315                                  const gmx_mtop_t *mtop,
316                                  const int *cginfo,
317                                  gmx::ArrayRef<const t_blocka> at2con_mt, int nrec,
318                                  t_ilist *ilc_local,
319                                  std::vector<int> *ireq)
320 {
321     const t_blocka             *at2con;
322     int                         ncon1;
323     t_iatom                    *ia1, *ia2, *iap;
324     int                         a_loc, b_lo, offset, b_mol, i, con, con_offset;
325
326     gmx_domdec_constraints_t   *dc     = dd->constraints;
327     gmx_domdec_specat_comm_t   *dcc    = dd->constraint_comm;
328
329     gmx_ga2la_t                *ga2la  = dd->ga2la;
330
331     dc->con_gl.clear();
332     dc->con_nlocat.clear();
333
334     int mb    = 0;
335     int nhome = 0;
336     for (int cg = 0; cg < dd->ncg_home; cg++)
337     {
338         if (GET_CGINFO_CONSTR(cginfo[cg]))
339         {
340             for (int a : dd->atomGrouping().block(cg))
341             {
342                 int a_gl = dd->globalAtomIndices[a];
343                 int molnr, a_mol;
344                 mtopGetMolblockIndex(mtop, a_gl, &mb, &molnr, &a_mol);
345
346                 const gmx_molblock_t *molb = &mtop->molblock[mb];
347
348                 ncon1 = mtop->moltype[molb->type].ilist[F_CONSTR].nr/NRAL(F_SETTLE);
349
350                 ia1 = mtop->moltype[molb->type].ilist[F_CONSTR].iatoms;
351                 ia2 = mtop->moltype[molb->type].ilist[F_CONSTRNC].iatoms;
352
353                 /* Calculate the global constraint number offset for the molecule.
354                  * This is only required for the global index to make sure
355                  * that we use each constraint only once.
356                  */
357                 con_offset =
358                     dc->molb_con_offset[mb] + molnr*dc->molb_ncon_mol[mb];
359
360                 /* The global atom number offset for this molecule */
361                 offset = a_gl - a_mol;
362                 at2con = &at2con_mt[molb->type];
363                 for (i = at2con->index[a_mol]; i < at2con->index[a_mol+1]; i++)
364                 {
365                     con = at2con->a[i];
366                     iap = constr_iatomptr(ncon1, ia1, ia2, con);
367                     if (a_mol == iap[1])
368                     {
369                         b_mol = iap[2];
370                     }
371                     else
372                     {
373                         b_mol = iap[1];
374                     }
375                     if (ga2la_get_home(ga2la, offset+b_mol, &a_loc))
376                     {
377                         /* Add this fully home constraint at the first atom */
378                         if (a_mol < b_mol)
379                         {
380                             dc->con_gl.push_back(con_offset + con);
381                             dc->con_nlocat.push_back(2);
382                             if (ilc_local->nr + 3 > ilc_local->nalloc)
383                             {
384                                 ilc_local->nalloc = over_alloc_dd(ilc_local->nr + 3);
385                                 srenew(ilc_local->iatoms, ilc_local->nalloc);
386                             }
387                             b_lo = a_loc;
388                             ilc_local->iatoms[ilc_local->nr++] = iap[0];
389                             ilc_local->iatoms[ilc_local->nr++] = (a_gl == iap[1] ? a    : b_lo);
390                             ilc_local->iatoms[ilc_local->nr++] = (a_gl == iap[1] ? b_lo : a   );
391                             dc->ncon++;
392                             nhome++;
393                         }
394                     }
395                     else
396                     {
397                         /* We need the nrec constraints coupled to this constraint,
398                          * so we need to walk out of the home cell by nrec+1 atoms,
399                          * since already atom bg is not locally present.
400                          * Therefore we call walk_out with nrec recursions to go
401                          * after this first call.
402                          */
403                         walk_out(con, con_offset, b_mol, offset, nrec,
404                                  ncon1, ia1, ia2, at2con,
405                                  dd->ga2la, TRUE, dc, dcc, ilc_local, ireq);
406                     }
407                 }
408             }
409         }
410     }
411
412     GMX_ASSERT(dc->con_gl.size() == static_cast<size_t>(dc->ncon), "con_gl size should match the number of constraints");
413     GMX_ASSERT(dc->con_nlocat.size() == static_cast<size_t>(dc->ncon), "con_nlocat size should match the number of constraints");
414
415     if (debug)
416     {
417         fprintf(debug,
418                 "Constraints: home %3d border %3d atoms: %3zu\n",
419                 nhome, dc->ncon-nhome,
420                 dd->constraint_comm ? ireq->size() : 0);
421     }
422 }
423
424 int dd_make_local_constraints(gmx_domdec_t *dd, int at_start,
425                               const struct gmx_mtop_t *mtop,
426                               const int *cginfo,
427                               gmx::Constraints *constr, int nrec,
428                               t_ilist *il_local)
429 {
430     gmx_domdec_constraints_t     *dc;
431     t_ilist                      *ilc_local, *ils_local;
432     std::vector<int>             *ireq;
433     gmx::ArrayRef<const t_blocka> at2con_mt;
434     const int                   **at2settle_mt;
435     gmx_hash_t                   *ga2la_specat;
436     int at_end, i, j;
437     t_iatom                      *iap;
438
439     // This code should not be called unless this condition is true,
440     // because that's the only time init_domdec_constraints is
441     // called...
442     GMX_RELEASE_ASSERT(dd->bInterCGcons || dd->bInterCGsettles, "dd_make_local_constraints called when there are no local constraints");
443     // ... and init_domdec_constraints always sets
444     // dd->constraint_comm...
445     GMX_RELEASE_ASSERT(dd->constraint_comm, "Invalid use of dd_make_local_constraints before construction of constraint_comm");
446     // ... which static analysis needs to be reassured about, because
447     // otherwise, when dd->bInterCGsettles is
448     // true. dd->constraint_comm is unilaterally dereferenced before
449     // the call to atoms_to_settles.
450
451     dc = dd->constraints;
452
453     ilc_local = &il_local[F_CONSTR];
454     ils_local = &il_local[F_SETTLE];
455
456     dc->ncon      = 0;
457     ilc_local->nr = 0;
458     if (dd->constraint_comm)
459     {
460         // TODO Perhaps gmx_domdec_constraints_t should keep a valid constr?
461         GMX_RELEASE_ASSERT(constr != nullptr, "Must have valid constraints object");
462         at2con_mt = constr->atom2constraints_moltype();
463         ireq      = &dc->requestedGlobalAtomIndices[0];
464         ireq->clear();
465     }
466     else
467     {
468         // Currently unreachable
469         at2con_mt = gmx::EmptyArrayRef();
470         ireq      = nullptr;
471     }
472
473     if (dd->bInterCGsettles)
474     {
475         // TODO Perhaps gmx_domdec_constraints_t should keep a valid constr?
476         GMX_RELEASE_ASSERT(constr != nullptr, "Must have valid constraints object");
477         at2settle_mt  = constr->atom2settle_moltype();
478         ils_local->nr = 0;
479     }
480     else
481     {
482         /* Settle works inside charge groups, we assigned them already */
483         at2settle_mt = nullptr;
484     }
485
486     if (at2settle_mt == nullptr)
487     {
488         atoms_to_constraints(dd, mtop, cginfo, at2con_mt, nrec,
489                              ilc_local, ireq);
490     }
491     else
492     {
493         int t0_set;
494         int thread;
495
496         /* Do the constraints, if present, on the first thread.
497          * Do the settles on all other threads.
498          */
499         t0_set = ((!at2con_mt.empty() && dc->nthread > 1) ? 1 : 0);
500
501 #pragma omp parallel for num_threads(dc->nthread) schedule(static)
502         for (thread = 0; thread < dc->nthread; thread++)
503         {
504             try
505             {
506                 if (!at2con_mt.empty() && thread == 0)
507                 {
508                     atoms_to_constraints(dd, mtop, cginfo, at2con_mt, nrec,
509                                          ilc_local, ireq);
510                 }
511
512                 if (thread >= t0_set)
513                 {
514                     int        cg0, cg1;
515                     t_ilist   *ilst;
516
517                     /* Distribute the settle check+assignments over
518                      * dc->nthread or dc->nthread-1 threads.
519                      */
520                     cg0 = (dd->ncg_home*(thread-t0_set  ))/(dc->nthread-t0_set);
521                     cg1 = (dd->ncg_home*(thread-t0_set+1))/(dc->nthread-t0_set);
522
523                     if (thread == t0_set)
524                     {
525                         ilst = ils_local;
526                     }
527                     else
528                     {
529                         ilst = &dc->ils[thread];
530                     }
531                     ilst->nr = 0;
532
533                     std::vector<int> &ireqt = dc->requestedGlobalAtomIndices[thread];
534                     if (thread > 0)
535                     {
536                         ireqt.clear();
537                     }
538
539                     atoms_to_settles(dd, mtop, cginfo, at2settle_mt,
540                                      cg0, cg1,
541                                      ilst, &ireqt);
542                 }
543             }
544             GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
545         }
546
547         /* Combine the generate settles and requested indices */
548         for (thread = 1; thread < dc->nthread; thread++)
549         {
550             t_ilist   *ilst;
551             int        ia;
552
553             if (thread > t0_set)
554             {
555                 ilst = &dc->ils[thread];
556                 if (ils_local->nr + ilst->nr > ils_local->nalloc)
557                 {
558                     ils_local->nalloc = over_alloc_large(ils_local->nr + ilst->nr);
559                     srenew(ils_local->iatoms, ils_local->nalloc);
560                 }
561                 for (ia = 0; ia < ilst->nr; ia++)
562                 {
563                     ils_local->iatoms[ils_local->nr+ia] = ilst->iatoms[ia];
564                 }
565                 ils_local->nr += ilst->nr;
566             }
567
568             const std::vector<int> &ireqt = dc->requestedGlobalAtomIndices[thread];
569             ireq->insert(ireq->end(), ireqt.begin(), ireqt.end());
570         }
571
572         if (debug)
573         {
574             fprintf(debug, "Settles: total %3d\n", ils_local->nr/4);
575         }
576     }
577
578     if (dd->constraint_comm)
579     {
580         int nral1;
581
582         at_end =
583             setup_specat_communication(dd, ireq, dd->constraint_comm,
584                                        dd->constraints->ga2la.get(),
585                                        at_start, 2,
586                                        "constraint", " or lincs-order");
587
588         /* Fill in the missing indices */
589         ga2la_specat = dd->constraints->ga2la.get();
590
591         nral1 = 1 + NRAL(F_CONSTR);
592         for (i = 0; i < ilc_local->nr; i += nral1)
593         {
594             iap = ilc_local->iatoms + i;
595             for (j = 1; j < nral1; j++)
596             {
597                 if (iap[j] < 0)
598                 {
599                     iap[j] = gmx_hash_get_minone(ga2la_specat, -iap[j]-1);
600                 }
601             }
602         }
603
604         nral1 = 1 + NRAL(F_SETTLE);
605         for (i = 0; i < ils_local->nr; i += nral1)
606         {
607             iap = ils_local->iatoms + i;
608             for (j = 1; j < nral1; j++)
609             {
610                 if (iap[j] < 0)
611                 {
612                     iap[j] = gmx_hash_get_minone(ga2la_specat, -iap[j]-1);
613                 }
614             }
615         }
616     }
617     else
618     {
619         // Currently unreachable
620         at_end = at_start;
621     }
622
623     return at_end;
624 }
625
626 void init_domdec_constraints(gmx_domdec_t     *dd,
627                              const gmx_mtop_t *mtop)
628 {
629     gmx_domdec_constraints_t *dc;
630     const gmx_molblock_t     *molb;
631
632     if (debug)
633     {
634         fprintf(debug, "Begin init_domdec_constraints\n");
635     }
636
637     dd->constraints = new gmx_domdec_constraints_t;
638     dc              = dd->constraints;
639
640     dc->molb_con_offset.resize(mtop->molblock.size());
641     dc->molb_ncon_mol.resize(mtop->molblock.size());
642
643     int ncon = 0;
644     for (size_t mb = 0; mb < mtop->molblock.size(); mb++)
645     {
646         molb                    = &mtop->molblock[mb];
647         dc->molb_con_offset[mb] = ncon;
648         dc->molb_ncon_mol[mb]   =
649             mtop->moltype[molb->type].ilist[F_CONSTR].nr/3 +
650             mtop->moltype[molb->type].ilist[F_CONSTRNC].nr/3;
651         ncon += molb->nmol*dc->molb_ncon_mol[mb];
652     }
653
654     if (ncon > 0)
655     {
656         dc->gc_req.resize(ncon);
657     }
658
659     /* Use a hash table for the global to local index.
660      * The number of keys is a rough estimate, it will be optimized later.
661      */
662     int numKeysEstimate = std::min(mtop->natoms/20,
663                                    mtop->natoms/(2*dd->nnodes));
664     dc->ga2la = gmx::compat::make_unique<gmx_hash_t>(numKeysEstimate);
665
666     dc->nthread = gmx_omp_nthreads_get(emntDomdec);
667     dc->ils.resize(dc->nthread);
668
669     dd->constraint_comm = new gmx_domdec_specat_comm_t;
670
671     dc->requestedGlobalAtomIndices.resize(dc->nthread);
672 }