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