static real ekrot(rvec x[], rvec v[], real mass[], int isize, int index[]) { static real **TCM = NULL, **L; double tm, m0, lxx, lxy, lxz, lyy, lyz, lzz, ekrot; rvec a0, ocm; dvec dx, b0; dvec xcm, vcm, acm; int i, j, m, n; if (TCM == NULL) { snew(TCM, DIM); for (i = 0; i < DIM; i++) { snew(TCM[i], DIM); } snew(L, DIM); for (i = 0; i < DIM; i++) { snew(L[i], DIM); } } clear_dvec(xcm); clear_dvec(vcm); clear_dvec(acm); tm = 0.0; for (i = 0; i < isize; i++) { j = index[i]; m0 = mass[j]; tm += m0; cprod(x[j], v[j], a0); for (m = 0; (m < DIM); m++) { xcm[m] += m0*x[j][m]; /* c.o.m. position */ vcm[m] += m0*v[j][m]; /* c.o.m. velocity */ acm[m] += m0*a0[m]; /* rotational velocity around c.o.m. */ } } dcprod(xcm, vcm, b0); for (m = 0; (m < DIM); m++) { xcm[m] /= tm; vcm[m] /= tm; acm[m] -= b0[m]/tm; } lxx = lxy = lxz = lyy = lyz = lzz = 0.0; for (i = 0; i < isize; i++) { j = index[i]; m0 = mass[j]; for (m = 0; m < DIM; m++) { dx[m] = x[j][m] - xcm[m]; } lxx += dx[XX]*dx[XX]*m0; lxy += dx[XX]*dx[YY]*m0; lxz += dx[XX]*dx[ZZ]*m0; lyy += dx[YY]*dx[YY]*m0; lyz += dx[YY]*dx[ZZ]*m0; lzz += dx[ZZ]*dx[ZZ]*m0; } L[XX][XX] = lyy + lzz; L[YY][XX] = -lxy; L[ZZ][XX] = -lxz; L[XX][YY] = -lxy; L[YY][YY] = lxx + lzz; L[ZZ][YY] = -lyz; L[XX][ZZ] = -lxz; L[YY][ZZ] = -lyz; L[ZZ][ZZ] = lxx + lyy; m_inv_gen(L, DIM, TCM); /* Compute omega (hoeksnelheid) */ clear_rvec(ocm); ekrot = 0; for (m = 0; m < DIM; m++) { for (n = 0; n < DIM; n++) { ocm[m] += TCM[m][n]*acm[n]; } ekrot += 0.5*ocm[m]*acm[m]; } return ekrot; }
real calc_orires_dev(const gmx_multisim_t *ms, int nfa,const t_iatom forceatoms[],const t_iparams ip[], const t_mdatoms *md,const rvec x[],const t_pbc *pbc, t_fcdata *fcd,history_t *hist) { int fa,d,i,j,type,ex,nref; real edt,edt1,invn,pfac,r2,invr,corrfac,weight,wsv2,sw,dev; tensor *S,R,TMP; rvec5 *Dinsl,*Dins,*Dtav,*rhs; real *mref,***T; double mtot; rvec *xref,*xtmp,com,r_unrot,r; t_oriresdata *od; bool bTAV; const real two_thr=2.0/3.0; od = &(fcd->orires); if (od->nr == 0) { /* This means that this is not the master node */ gmx_fatal(FARGS,"Orientation restraints are only supported on the master node, use less processors"); } bTAV = (od->edt != 0); edt = od->edt; edt1 = od->edt1; S = od->S; Dinsl= od->Dinsl; Dins = od->Dins; Dtav = od->Dtav; T = od->TMP; rhs = od->tmp; nref = od->nref; mref = od->mref; xref = od->xref; xtmp = od->xtmp; if (bTAV) { od->exp_min_t_tau = hist->orire_initf*edt; /* Correction factor to correct for the lack of history * at short times. */ corrfac = 1.0/(1.0 - od->exp_min_t_tau); } else { corrfac = 1.0; } if (ms) { invn = 1.0/ms->nsim; } else { invn = 1.0; } clear_rvec(com); mtot = 0; j=0; for(i=0; i<md->nr; i++) { if (md->cORF[i] == 0) { copy_rvec(x[i],xtmp[j]); mref[j] = md->massT[i]; for(d=0; d<DIM; d++) { com[d] += mref[j]*xref[j][d]; } mtot += mref[j]; j++; } } svmul(1.0/mtot,com,com); for(j=0; j<nref; j++) { rvec_dec(xtmp[j],com); } /* Calculate the rotation matrix to rotate x to the reference orientation */ calc_fit_R(DIM,nref,mref,xref,xtmp,R); copy_mat(R,od->R); d = 0; for(fa=0; fa<nfa; fa+=3) { type = forceatoms[fa]; if (pbc) { pbc_dx_aiuc(pbc,x[forceatoms[fa+1]],x[forceatoms[fa+2]],r_unrot); } else { rvec_sub(x[forceatoms[fa+1]],x[forceatoms[fa+2]],r_unrot); } mvmul(R,r_unrot,r); r2 = norm2(r); invr = invsqrt(r2); /* Calculate the prefactor for the D tensor, this includes the factor 3! */ pfac = ip[type].orires.c*invr*invr*3; for(i=0; i<ip[type].orires.power; i++) { pfac *= invr; } Dinsl[d][0] = pfac*(2*r[0]*r[0] + r[1]*r[1] - r2); Dinsl[d][1] = pfac*(2*r[0]*r[1]); Dinsl[d][2] = pfac*(2*r[0]*r[2]); Dinsl[d][3] = pfac*(2*r[1]*r[1] + r[0]*r[0] - r2); Dinsl[d][4] = pfac*(2*r[1]*r[2]); if (ms) { for(i=0; i<5; i++) { Dins[d][i] = Dinsl[d][i]*invn; } } d++; } if (ms) { gmx_sum_sim(5*od->nr,Dins[0],ms); } /* Calculate the order tensor S for each experiment via optimization */ for(ex=0; ex<od->nex; ex++) { for(i=0; i<5; i++) { rhs[ex][i] = 0; for(j=0; j<=i; j++) { T[ex][i][j] = 0; } } } d = 0; for(fa=0; fa<nfa; fa+=3) { if (bTAV) { /* Here we update Dtav in t_fcdata using the data in history_t. * Thus the results stay correct when this routine * is called multiple times. */ for(i=0; i<5; i++) { Dtav[d][i] = edt*hist->orire_Dtav[d*5+i] + edt1*Dins[d][i]; } } type = forceatoms[fa]; ex = ip[type].orires.ex; weight = ip[type].orires.kfac; /* Calculate the vector rhs and half the matrix T for the 5 equations */ for(i=0; i<5; i++) { rhs[ex][i] += Dtav[d][i]*ip[type].orires.obs*weight; for(j=0; j<=i; j++) { T[ex][i][j] += Dtav[d][i]*Dtav[d][j]*weight; } } d++; } /* Now we have all the data we can calculate S */ for(ex=0; ex<od->nex; ex++) { /* Correct corrfac and copy one half of T to the other half */ for(i=0; i<5; i++) { rhs[ex][i] *= corrfac; T[ex][i][i] *= sqr(corrfac); for(j=0; j<i; j++) { T[ex][i][j] *= sqr(corrfac); T[ex][j][i] = T[ex][i][j]; } } m_inv_gen(T[ex],5,T[ex]); /* Calculate the orientation tensor S for this experiment */ S[ex][0][0] = 0; S[ex][0][1] = 0; S[ex][0][2] = 0; S[ex][1][1] = 0; S[ex][1][2] = 0; for(i=0; i<5; i++) { S[ex][0][0] += 1.5*T[ex][0][i]*rhs[ex][i]; S[ex][0][1] += 1.5*T[ex][1][i]*rhs[ex][i]; S[ex][0][2] += 1.5*T[ex][2][i]*rhs[ex][i]; S[ex][1][1] += 1.5*T[ex][3][i]*rhs[ex][i]; S[ex][1][2] += 1.5*T[ex][4][i]*rhs[ex][i]; } S[ex][1][0] = S[ex][0][1]; S[ex][2][0] = S[ex][0][2]; S[ex][2][1] = S[ex][1][2]; S[ex][2][2] = -S[ex][0][0] - S[ex][1][1]; } wsv2 = 0; sw = 0; d = 0; for(fa=0; fa<nfa; fa+=3) { type = forceatoms[fa]; ex = ip[type].orires.ex; od->otav[d] = two_thr* corrfac*(S[ex][0][0]*Dtav[d][0] + S[ex][0][1]*Dtav[d][1] + S[ex][0][2]*Dtav[d][2] + S[ex][1][1]*Dtav[d][3] + S[ex][1][2]*Dtav[d][4]); if (bTAV) { od->oins[d] = two_thr*(S[ex][0][0]*Dins[d][0] + S[ex][0][1]*Dins[d][1] + S[ex][0][2]*Dins[d][2] + S[ex][1][1]*Dins[d][3] + S[ex][1][2]*Dins[d][4]); } if (ms) { /* When ensemble averaging is used recalculate the local orientation * for output to the energy file. */ od->oinsl[d] = two_thr* (S[ex][0][0]*Dinsl[d][0] + S[ex][0][1]*Dinsl[d][1] + S[ex][0][2]*Dinsl[d][2] + S[ex][1][1]*Dinsl[d][3] + S[ex][1][2]*Dinsl[d][4]); } dev = od->otav[d] - ip[type].orires.obs; wsv2 += ip[type].orires.kfac*sqr(dev); sw += ip[type].orires.kfac; d++; } od->rmsdev = sqrt(wsv2/sw); /* Rotate the S matrices back, so we get the correct grad(tr(S D)) */ for(ex=0; ex<od->nex; ex++) { tmmul(R,S[ex],TMP); mmul(TMP,R,S[ex]); } return od->rmsdev; /* Approx. 120*nfa/3 flops */ }
real calc_orires_dev(t_commrec *mcr, int nfa,t_iatom forceatoms[],t_iparams ip[], t_mdatoms *md,rvec x[],t_fcdata *fcd) { int fa,d,i,j,type,ex,nref; real edt,edt1,invn,pfac,r2,invr,corrfac,weight,wsv2,sw,dev; tensor *S,R,TMP; rvec5 *Dinsl,*Dins,*Dtav,*rhs; real *mref,***T; rvec *xref,*xtmp,com,r_unrot,r; t_oriresdata *od; bool bTAV; static real two_thr=2.0/3.0; od = &(fcd->orires); bTAV = (fabs(od->edt)>GMX_REAL_MIN); edt = od->edt; edt1 = od->edt1; S = od->S; Dinsl= od->Dinsl; Dins = od->Dins; Dtav = od->Dtav; T = od->TMP; rhs = od->tmp; nref = od->nref; mref = od->mref; xref = od->xref; xtmp = od->xtmp; od->exp_min_t_tau *= edt; if (mcr) invn = 1.0/mcr->nnodes; else invn = 1.0; j=0; for(i=0; i<md->nr; i++) if (md->cORF[i] == 0) { copy_rvec(x[i],xtmp[j]); for(d=0; d<DIM; d++) com[d] += mref[j]*xref[j][d]; j++; } svmul(od->invmref,com,com); for(j=0; j<nref; j++) rvec_dec(xtmp[j],com); /* Calculate the rotation matrix to rotate x to the reference orientation */ calc_fit_R(nref,mref,xref,xtmp,R); copy_mat(R,od->R); d = 0; for(fa=0; fa<nfa; fa+=3) { type = forceatoms[fa]; rvec_sub(x[forceatoms[fa+1]],x[forceatoms[fa+2]],r_unrot); mvmul(R,r_unrot,r); r2 = norm2(r); invr = invsqrt(r2); /* Calculate the prefactor for the D tensor, this includes the factor 3! */ pfac = ip[type].orires.c*invr*invr*3; for(i=0; i<ip[type].orires.pow; i++) pfac *= invr; Dinsl[d][0] = pfac*(2*r[0]*r[0] + r[1]*r[1] - r2); Dinsl[d][1] = pfac*(2*r[0]*r[1]); Dinsl[d][2] = pfac*(2*r[0]*r[2]); Dinsl[d][3] = pfac*(2*r[1]*r[1] + r[0]*r[0] - r2); Dinsl[d][4] = pfac*(2*r[1]*r[2]); if (mcr) for(i=0; i<5; i++) Dins[d][i] = Dinsl[d][i]*invn; d++; } if (mcr) gmx_sum(5*od->nr,Dins[0],mcr); /* Correction factor to correct for the lack of history for short times */ corrfac = 1.0/(1.0-od->exp_min_t_tau); /* Calculate the order tensor S for each experiment via optimization */ for(ex=0; ex<od->nex; ex++) for(i=0; i<5; i++) { rhs[ex][i] = 0; for(j=0; j<=i; j++) T[ex][i][j] = 0; } d = 0; for(fa=0; fa<nfa; fa+=3) { if (bTAV) for(i=0; i<5; i++) Dtav[d][i] = edt*Dtav[d][i] + edt1*Dins[d][i]; type = forceatoms[fa]; ex = ip[type].orires.ex; weight = ip[type].orires.kfac; /* Calculate the vector rhs and half the matrix T for the 5 equations */ for(i=0; i<5; i++) { rhs[ex][i] += Dtav[d][i]*ip[type].orires.obs*weight; for(j=0; j<=i; j++) T[ex][i][j] += Dtav[d][i]*Dtav[d][j]*weight; } d++; } /* Now we have all the data we can calculate S */ for(ex=0; ex<od->nex; ex++) { /* Correct corrfac and copy one half of T to the other half */ for(i=0; i<5; i++) { rhs[ex][i] *= corrfac; T[ex][i][i] *= sqr(corrfac); for(j=0; j<i; j++) { T[ex][i][j] *= sqr(corrfac); T[ex][j][i] = T[ex][i][j]; } } m_inv_gen(T[ex],5,T[ex]); /* Calculate the orientation tensor S for this experiment */ S[ex][0][0] = 0; S[ex][0][1] = 0; S[ex][0][2] = 0; S[ex][1][1] = 0; S[ex][1][2] = 0; for(i=0; i<5; i++) { S[ex][0][0] += 1.5*T[ex][0][i]*rhs[ex][i]; S[ex][0][1] += 1.5*T[ex][1][i]*rhs[ex][i]; S[ex][0][2] += 1.5*T[ex][2][i]*rhs[ex][i]; S[ex][1][1] += 1.5*T[ex][3][i]*rhs[ex][i]; S[ex][1][2] += 1.5*T[ex][4][i]*rhs[ex][i]; } S[ex][1][0] = S[ex][0][1]; S[ex][2][0] = S[ex][0][2]; S[ex][2][1] = S[ex][1][2]; S[ex][2][2] = -S[ex][0][0] - S[ex][1][1]; } wsv2 = 0; sw = 0; d = 0; for(fa=0; fa<nfa; fa+=3) { type = forceatoms[fa]; ex = ip[type].orires.ex; od->otav[d] = two_thr* corrfac*(S[ex][0][0]*Dtav[d][0] + S[ex][0][1]*Dtav[d][1] + S[ex][0][2]*Dtav[d][2] + S[ex][1][1]*Dtav[d][3] + S[ex][1][2]*Dtav[d][4]); if (bTAV) od->oins[d] = two_thr*(S[ex][0][0]*Dins[d][0] + S[ex][0][1]*Dins[d][1] + S[ex][0][2]*Dins[d][2] + S[ex][1][1]*Dins[d][3] + S[ex][1][2]*Dins[d][4]); if (mcr) /* When ensemble averaging is used recalculate the local orientation * for output to the energy file. */ od->oinsl[d] = two_thr* (S[ex][0][0]*Dinsl[d][0] + S[ex][0][1]*Dinsl[d][1] + S[ex][0][2]*Dinsl[d][2] + S[ex][1][1]*Dinsl[d][3] + S[ex][1][2]*Dinsl[d][4]); dev = od->otav[d] - ip[type].orires.obs; wsv2 += ip[type].orires.kfac*sqr(dev); sw += ip[type].orires.kfac; d++; } od->rmsdev = sqrt(wsv2/sw); /* Rotate the S matrices back, so we get the correct grad(tr(S D)) */ for(ex=0; ex<od->nex; ex++) { tmmul(R,S[ex],TMP); mmul(TMP,R,S[ex]); } return od->rmsdev; /* Approx. 120*nfa/3 flops */ }