static void get_vsite_masses(const gmx_moltype_t *moltype, const gmx_ffparams_t *ffparams, real *vsite_m, int *n_nonlin_vsite) { int ft, i; const t_ilist *il; *n_nonlin_vsite = 0; /* Check for virtual sites, determine mass from constructing atoms */ for (ft = 0; ft < F_NRE; ft++) { if (IS_VSITE(ft)) { il = &moltype->ilist[ft]; for (i = 0; i < il->nr; i += 1+NRAL(ft)) { const t_iparams *ip; real cam[5] = {0}, inv_mass, coeff, m_aj; int a1, j, aj; ip = &ffparams->iparams[il->iatoms[i]]; a1 = il->iatoms[i+1]; if (ft != F_VSITEN) { for (j = 1; j < NRAL(ft); j++) { cam[j] = moltype->atoms.atom[il->iatoms[i+1+j]].m; if (cam[j] == 0) { cam[j] = vsite_m[il->iatoms[i+1+j]]; } if (cam[j] == 0) { gmx_fatal(FARGS, "In molecule type '%s' %s construction involves atom %d, which is a virtual site of equal or high complexity. This is not supported.", *moltype->name, interaction_function[ft].longname, il->iatoms[i+1+j]+1); } } } switch (ft) { case F_VSITE2: /* Exact */ vsite_m[a1] = (cam[1]*cam[2])/(cam[2]*sqr(1-ip->vsite.a) + cam[1]*sqr(ip->vsite.a)); break; case F_VSITE3: /* Exact */ vsite_m[a1] = (cam[1]*cam[2]*cam[3])/(cam[2]*cam[3]*sqr(1-ip->vsite.a-ip->vsite.b) + cam[1]*cam[3]*sqr(ip->vsite.a) + cam[1]*cam[2]*sqr(ip->vsite.b)); break; case F_VSITEN: /* Exact */ inv_mass = 0; for (j = 0; j < 3*ffparams->iparams[il->iatoms[i]].vsiten.n; j += 3) { aj = il->iatoms[i+j+2]; coeff = ffparams->iparams[il->iatoms[i+j]].vsiten.a; if (moltype->atoms.atom[aj].ptype == eptVSite) { m_aj = vsite_m[aj]; } else { m_aj = moltype->atoms.atom[aj].m; } if (m_aj <= 0) { gmx_incons("The mass of a vsiten constructing atom is <= 0"); } inv_mass += coeff*coeff/m_aj; } vsite_m[a1] = 1/inv_mass; /* Correct for loop increment of i */ i += j - 1 - NRAL(ft); break; default: /* Use the mass of the lightest constructing atom. * This is an approximation. * If the distance of the virtual site to the * constructing atom is less than all distances * between constructing atoms, this is a safe * over-estimate of the displacement of the vsite. * This condition holds for all H mass replacement * vsite constructions, except for SP2/3 groups. * In SP3 groups one H will have a F_VSITE3 * construction, so even there the total drift * estimate shouldn't be far off. */ assert(j >= 1); vsite_m[a1] = cam[1]; for (j = 2; j < NRAL(ft); j++) { vsite_m[a1] = min(vsite_m[a1], cam[j]); } (*n_nonlin_vsite)++; break; } if (gmx_debug_at) { fprintf(debug, "atom %4d %-20s mass %6.3f\n", a1, interaction_function[ft].longname, vsite_m[a1]); } } } } }
static void get_verlet_buffer_atomtypes(const gmx_mtop_t *mtop, verletbuf_atomtype_t **att_p, int *natt_p, int *n_nonlin_vsite) { verletbuf_atomtype_t *att; int natt; int mb, nmol, ft, i, j, a1, a2, a3, a; const t_atoms *atoms; const t_ilist *il; const t_atom *at; const t_iparams *ip; real *con_m, *vsite_m, cam[5]; att = NULL; natt = 0; if (n_nonlin_vsite != NULL) { *n_nonlin_vsite = 0; } for (mb = 0; mb < mtop->nmolblock; mb++) { nmol = mtop->molblock[mb].nmol; atoms = &mtop->moltype[mtop->molblock[mb].type].atoms; /* Check for constraints, as they affect the kinetic energy */ snew(con_m, atoms->nr); snew(vsite_m, atoms->nr); for (ft = F_CONSTR; ft <= F_CONSTRNC; ft++) { il = &mtop->moltype[mtop->molblock[mb].type].ilist[ft]; for (i = 0; i < il->nr; i += 1+NRAL(ft)) { a1 = il->iatoms[i+1]; a2 = il->iatoms[i+2]; con_m[a1] += atoms->atom[a2].m; con_m[a2] += atoms->atom[a1].m; } } il = &mtop->moltype[mtop->molblock[mb].type].ilist[F_SETTLE]; for (i = 0; i < il->nr; i += 1+NRAL(F_SETTLE)) { a1 = il->iatoms[i+1]; a2 = il->iatoms[i+2]; a3 = il->iatoms[i+3]; con_m[a1] += atoms->atom[a2].m + atoms->atom[a3].m; con_m[a2] += atoms->atom[a1].m + atoms->atom[a3].m; con_m[a3] += atoms->atom[a1].m + atoms->atom[a2].m; } /* Check for virtual sites, determine mass from constructing atoms */ for (ft = 0; ft < F_NRE; ft++) { if (IS_VSITE(ft)) { il = &mtop->moltype[mtop->molblock[mb].type].ilist[ft]; for (i = 0; i < il->nr; i += 1+NRAL(ft)) { ip = &mtop->ffparams.iparams[il->iatoms[i]]; a1 = il->iatoms[i+1]; for (j = 1; j < NRAL(ft); j++) { cam[j] = atoms->atom[il->iatoms[i+1+j]].m; if (cam[j] == 0) { cam[j] = vsite_m[il->iatoms[i+1+j]]; } if (cam[j] == 0) { gmx_fatal(FARGS, "In molecule type '%s' %s construction involves atom %d, which is a virtual site of equal or high complexity. This is not supported.", *mtop->moltype[mtop->molblock[mb].type].name, interaction_function[ft].longname, il->iatoms[i+1+j]+1); } } switch (ft) { case F_VSITE2: /* Exact except for ignoring constraints */ vsite_m[a1] = (cam[2]*sqr(1-ip->vsite.a) + cam[1]*sqr(ip->vsite.a))/(cam[1]*cam[2]); break; case F_VSITE3: /* Exact except for ignoring constraints */ vsite_m[a1] = (cam[2]*cam[3]*sqr(1-ip->vsite.a-ip->vsite.b) + cam[1]*cam[3]*sqr(ip->vsite.a) + cam[1]*cam[2]*sqr(ip->vsite.b))/(cam[1]*cam[2]*cam[3]); break; default: /* Use the mass of the lightest constructing atom. * This is an approximation. * If the distance of the virtual site to the * constructing atom is less than all distances * between constructing atoms, this is a safe * over-estimate of the displacement of the vsite. * This condition holds for all H mass replacement * replacement vsite constructions, except for SP2/3 * groups. In SP3 groups one H will have a F_VSITE3 * construction, so even there the total drift * estimation shouldn't be far off. */ assert(j >= 1); vsite_m[a1] = cam[1]; for (j = 2; j < NRAL(ft); j++) { vsite_m[a1] = min(vsite_m[a1], cam[j]); } if (n_nonlin_vsite != NULL) { *n_nonlin_vsite += nmol; } break; } } } } for (a = 0; a < atoms->nr; a++) { at = &atoms->atom[a]; /* We consider an atom constrained, #DOF=2, when it is * connected with constraints to one or more atoms with * total mass larger than 1.5 that of the atom itself. */ add_at(&att, &natt, at->m, at->type, at->q, con_m[a] > 1.5*at->m, nmol); } sfree(vsite_m); sfree(con_m); } if (gmx_debug_at) { for (a = 0; a < natt; a++) { fprintf(debug, "type %d: m %5.2f t %d q %6.3f con %d n %d\n", a, att[a].mass, att[a].type, att[a].q, att[a].con, att[a].n); } } *att_p = att; *natt_p = natt; }