static void constr_recur(t_blocka *at2con, t_ilist *ilist, t_iparams *iparams, gmx_bool bTopB, int at, int depth, int nc, int *path, real r0, real r1, real *r2max, int *count) { int ncon1; t_iatom *ia1, *ia2; int c, con, a1; gmx_bool bUse; t_iatom *ia; real len, rn0, rn1; (*count)++; ncon1 = ilist[F_CONSTR].nr/3; ia1 = ilist[F_CONSTR].iatoms; ia2 = ilist[F_CONSTRNC].iatoms; /* Loop over all constraints connected to this atom */ for (c = at2con->index[at]; c < at2con->index[at+1]; c++) { con = at2con->a[c]; /* Do not walk over already used constraints */ bUse = TRUE; for (a1 = 0; a1 < depth; a1++) { if (con == path[a1]) { bUse = FALSE; } } if (bUse) { ia = constr_iatomptr(ncon1, ia1, ia2, con); /* Flexible constraints currently have length 0, which is incorrect */ if (!bTopB) { len = iparams[ia[0]].constr.dA; } else { len = iparams[ia[0]].constr.dB; } /* In the worst case the bond directions alternate */ if (nc % 2 == 0) { rn0 = r0 + len; rn1 = r1; } else { rn0 = r0; rn1 = r1 + len; } /* Assume angles of 120 degrees between all bonds */ if (rn0*rn0 + rn1*rn1 + rn0*rn1 > *r2max) { *r2max = rn0*rn0 + rn1*rn1 + r0*rn1; if (debug) { fprintf(debug, "Found longer constraint distance: r0 %5.3f r1 %5.3f rmax %5.3f\n", rn0, rn1, sqrt(*r2max)); for (a1 = 0; a1 < depth; a1++) { fprintf(debug, " %d %5.3f", path[a1], iparams[constr_iatomptr(ncon1, ia1, ia2, con)[0]].constr.dA); } fprintf(debug, " %d %5.3f\n", con, len); } } /* Limit the number of recursions to 1000*nc, * so a call does not take more than a second, * even for highly connected systems. */ if (depth + 1 < nc && *count < 1000*nc) { if (ia[1] == at) { a1 = ia[2]; } else { a1 = ia[1]; } /* Recursion */ path[depth] = con; constr_recur(at2con, ilist, iparams, bTopB, a1, depth+1, nc, path, rn0, rn1, r2max, count); path[depth] = -1; } } } }
/*! \brief Looks up constraint for the local atoms */ static void atoms_to_constraints(gmx_domdec_t *dd, const gmx_mtop_t *mtop, const int *cginfo, const t_blocka *at2con_mt, int nrec, t_ilist *ilc_local, ind_req_t *ireq) { const t_blocka *at2con; gmx_ga2la_t *ga2la; gmx_mtop_atomlookup_t alook; int ncon1; gmx_molblock_t *molb; t_iatom *ia1, *ia2, *iap; int nhome, cg, a, a_gl, a_mol, a_loc, b_lo, offset, mb, molnr, b_mol, i, con, con_offset; gmx_domdec_constraints_t *dc; gmx_domdec_specat_comm_t *dcc; dc = dd->constraints; dcc = dd->constraint_comm; ga2la = dd->ga2la; alook = gmx_mtop_atomlookup_init(mtop); nhome = 0; for (cg = 0; cg < dd->ncg_home; cg++) { if (GET_CGINFO_CONSTR(cginfo[cg])) { for (a = dd->cgindex[cg]; a < dd->cgindex[cg+1]; a++) { a_gl = dd->gatindex[a]; gmx_mtop_atomnr_to_molblock_ind(alook, a_gl, &mb, &molnr, &a_mol); molb = &mtop->molblock[mb]; ncon1 = mtop->moltype[molb->type].ilist[F_CONSTR].nr/NRAL(F_SETTLE); ia1 = mtop->moltype[molb->type].ilist[F_CONSTR].iatoms; ia2 = mtop->moltype[molb->type].ilist[F_CONSTRNC].iatoms; /* Calculate the global constraint number offset for the molecule. * This is only required for the global index to make sure * that we use each constraint only once. */ con_offset = dc->molb_con_offset[mb] + molnr*dc->molb_ncon_mol[mb]; /* The global atom number offset for this molecule */ offset = a_gl - a_mol; at2con = &at2con_mt[molb->type]; for (i = at2con->index[a_mol]; i < at2con->index[a_mol+1]; i++) { con = at2con->a[i]; iap = constr_iatomptr(ncon1, ia1, ia2, con); if (a_mol == iap[1]) { b_mol = iap[2]; } else { b_mol = iap[1]; } if (ga2la_get_home(ga2la, offset+b_mol, &a_loc)) { /* Add this fully home constraint at the first atom */ if (a_mol < b_mol) { if (dc->ncon+1 > dc->con_nalloc) { dc->con_nalloc = over_alloc_large(dc->ncon+1); srenew(dc->con_gl, dc->con_nalloc); srenew(dc->con_nlocat, dc->con_nalloc); } dc->con_gl[dc->ncon] = con_offset + con; dc->con_nlocat[dc->ncon] = 2; if (ilc_local->nr + 3 > ilc_local->nalloc) { ilc_local->nalloc = over_alloc_dd(ilc_local->nr + 3); srenew(ilc_local->iatoms, ilc_local->nalloc); } b_lo = a_loc; ilc_local->iatoms[ilc_local->nr++] = iap[0]; ilc_local->iatoms[ilc_local->nr++] = (a_gl == iap[1] ? a : b_lo); ilc_local->iatoms[ilc_local->nr++] = (a_gl == iap[1] ? b_lo : a ); dc->ncon++; nhome++; } } else { /* We need the nrec constraints coupled to this constraint, * so we need to walk out of the home cell by nrec+1 atoms, * since already atom bg is not locally present. * Therefore we call walk_out with nrec recursions to go * after this first call. */ walk_out(con, con_offset, b_mol, offset, nrec, ncon1, ia1, ia2, at2con, dd->ga2la, TRUE, dc, dcc, ilc_local, ireq); } } } } } gmx_mtop_atomlookup_destroy(alook); if (debug) { fprintf(debug, "Constraints: home %3d border %3d atoms: %3d\n", nhome, dc->ncon-nhome, dd->constraint_comm ? ireq->n : 0); } }
static int count_triangle_constraints(t_ilist *ilist,t_blocka *at2con) { int ncon1,ncon_tot; int c0,a00,a01,n1,c1,a10,a11,ac1,n2,c2,a20,a21; int ncon_triangle; gmx_bool bTriangle; t_iatom *ia1,*ia2,*iap; ncon1 = ilist[F_CONSTR].nr/3; ncon_tot = ncon1 + ilist[F_CONSTRNC].nr/3; ia1 = ilist[F_CONSTR].iatoms; ia2 = ilist[F_CONSTRNC].iatoms; ncon_triangle = 0; for(c0=0; c0<ncon_tot; c0++) { bTriangle = FALSE; iap = constr_iatomptr(ncon1,ia1,ia2,c0); a00 = iap[1]; a01 = iap[2]; for(n1=at2con->index[a01]; n1<at2con->index[a01+1]; n1++) { c1 = at2con->a[n1]; if (c1 != c0) { iap = constr_iatomptr(ncon1,ia1,ia2,c1); a10 = iap[1]; a11 = iap[2]; if (a10 == a01) { ac1 = a11; } else { ac1 = a10; } for(n2=at2con->index[ac1]; n2<at2con->index[ac1+1]; n2++) { c2 = at2con->a[n2]; if (c2 != c0 && c2 != c1) { iap = constr_iatomptr(ncon1,ia1,ia2,c2); a20 = iap[1]; a21 = iap[2]; if (a20 == a00 || a21 == a00) { bTriangle = TRUE; } } } } } if (bTriangle) { ncon_triangle++; } } return ncon_triangle; }
/*! \brief Walks over the constraints out from the local atoms into the non-local atoms and adds them to a list */ static void walk_out(int con, int con_offset, int a, int offset, int nrec, int ncon1, const t_iatom *ia1, const t_iatom *ia2, const t_blocka *at2con, const gmx_ga2la_t *ga2la, gmx_bool bHomeConnect, gmx_domdec_constraints_t *dc, gmx_domdec_specat_comm_t *dcc, t_ilist *il_local, ind_req_t *ireq) { int a1_gl, a2_gl, a_loc, i, coni, b; const t_iatom *iap; if (dc->gc_req[con_offset+con] == 0) { /* Add this non-home constraint to the list */ if (dc->ncon+1 > dc->con_nalloc) { dc->con_nalloc = over_alloc_large(dc->ncon+1); srenew(dc->con_gl, dc->con_nalloc); srenew(dc->con_nlocat, dc->con_nalloc); } dc->con_gl[dc->ncon] = con_offset + con; dc->con_nlocat[dc->ncon] = (bHomeConnect ? 1 : 0); dc->gc_req[con_offset+con] = 1; if (il_local->nr + 3 > il_local->nalloc) { il_local->nalloc = over_alloc_dd(il_local->nr+3); srenew(il_local->iatoms, il_local->nalloc); } iap = constr_iatomptr(ncon1, ia1, ia2, con); il_local->iatoms[il_local->nr++] = iap[0]; a1_gl = offset + iap[1]; a2_gl = offset + iap[2]; /* The following indexing code can probably be optizimed */ if (ga2la_get_home(ga2la, a1_gl, &a_loc)) { il_local->iatoms[il_local->nr++] = a_loc; } else { /* We set this index later */ il_local->iatoms[il_local->nr++] = -a1_gl - 1; } if (ga2la_get_home(ga2la, a2_gl, &a_loc)) { il_local->iatoms[il_local->nr++] = a_loc; } else { /* We set this index later */ il_local->iatoms[il_local->nr++] = -a2_gl - 1; } dc->ncon++; } /* Check to not ask for the same atom more than once */ if (gmx_hash_get_minone(dc->ga2la, offset+a) == -1) { assert(dcc); /* Add this non-home atom to the list */ if (ireq->n+1 > ireq->nalloc) { ireq->nalloc = over_alloc_large(ireq->n+1); srenew(ireq->ind, ireq->nalloc); } ireq->ind[ireq->n++] = offset + a; /* Temporarily mark with -2, we get the index later */ gmx_hash_set(dc->ga2la, offset+a, -2); } if (nrec > 0) { for (i = at2con->index[a]; i < at2con->index[a+1]; i++) { coni = at2con->a[i]; if (coni != con) { /* Walk further */ iap = constr_iatomptr(ncon1, ia1, ia2, coni); if (a == iap[1]) { b = iap[2]; } else { b = iap[1]; } if (!ga2la_get_home(ga2la, offset+b, &a_loc)) { walk_out(coni, con_offset, b, offset, nrec-1, ncon1, ia1, ia2, at2con, ga2la, FALSE, dc, dcc, il_local, ireq); } } } } }