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