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