From 157dc573a23dd6657a6e551830d12e1e0853b2bb Mon Sep 17 00:00:00 2001
From: carlocamilloni <carlo.camilloni@gmail.com>
Date: Tue, 6 Feb 2018 09:40:55 +0100
Subject: [PATCH] cs2back: fix for openmp

---
 src/isdb/CS2Backbone.cpp | 568 ++++++++++++++++++++-------------------
 1 file changed, 286 insertions(+), 282 deletions(-)

diff --git a/src/isdb/CS2Backbone.cpp b/src/isdb/CS2Backbone.cpp
index a87952324..cc65ac772 100644
--- a/src/isdb/CS2Backbone.cpp
+++ b/src/isdb/CS2Backbone.cpp
@@ -658,7 +658,9 @@ void CS2Backbone::init_cs(const string &file, const string &nucl, const PDB &pdb
       } else begin=1;
       continue;
     }
-    int resnum = atoi(tok.c_str());
+    int ro = atoi(tok.c_str());
+    if(ro<0) plumed_merror("Residue numbers should be positive\n");
+    unsigned resnum = static_cast<unsigned> (ro);
     tok = *iter;
     ++iter;
     double cs = atof(tok.c_str());
@@ -976,303 +978,292 @@ void CS2Backbone::calculate()
     rank   = 0;
   }
 
-  double score = 0.;
-
   unsigned nt=OpenMP::getNumThreads();
   if(nt*stride*10>chemicalshifts.size()) nt=chemicalshifts.size()/stride/10;
   if(nt==0) nt=1;
 
   // a single loop over all chemical shifts
-  #pragma omp parallel for reduction(+:score) num_threads(nt)
-  for(unsigned cs=rank; cs<chemicalshifts.size(); cs+=stride) {
-    const unsigned kdx=cs*max_cs_atoms;
-    const ChemicalShift *myfrag = &chemicalshifts[cs];
-    const unsigned aa_kind = myfrag->res_kind;
-    const unsigned at_kind = myfrag->atm_kind;
-    // Common constant and AATYPE
-    const double * CONSTAACURR = db.CONSTAACURR(aa_kind,at_kind);
-    const double * CONSTAANEXT = db.CONSTAANEXT(aa_kind,at_kind);
-    const double * CONSTAAPREV = db.CONSTAAPREV(aa_kind,at_kind);
-
-    double shift = CONSTAAPREV[myfrag->res_type_prev] +
-                   CONSTAACURR[myfrag->res_type_curr] +
-                   CONSTAANEXT[myfrag->res_type_next];
-
-    const unsigned ipos = myfrag->ipos;
-    cs_atoms[kdx+0] = ipos;
-    unsigned atom_counter = 1;
-
-    //BACKBONE (PREV CURR NEXT)
-    const double * CONST_BB2 = db.CONST_BB2(aa_kind,at_kind);
-    const unsigned bbsize = 16;
-    for(unsigned q=0; q<bbsize; q++) {
-      const double cb2q = CONST_BB2[q];
-      if(cb2q==0.) continue;
-      const unsigned jpos = myfrag->bb[q];
-      if(ipos==jpos) continue;
-      const Vector distance = delta(getPosition(jpos),getPosition(ipos));
-      const double d = distance.modulo();
-      const double fact = cb2q/d;
-
-      shift += cb2q*d;
-      const Vector der = fact*distance;
-
-      cs_derivs[kdx+0] += der;
-      cs_derivs[kdx+q+atom_counter] = -der;
-      cs_atoms[kdx+q+atom_counter] = jpos;
-    }
-
-    atom_counter += bbsize;
-
-    //DIHEDRAL ANGLES
-    const double *CO_DA = db.CO_DA(aa_kind,at_kind);
-    //Phi
-    {
-      const Vector d0 = delta(getPosition(myfrag->bb[Nc]), getPosition(myfrag->bb[Cp]));
-      const Vector d1 = delta(getPosition(myfrag->bb[CAc]), getPosition(myfrag->bb[Nc]));
-      const Vector d2 = delta(getPosition(myfrag->bb[Cc]), getPosition(myfrag->bb[CAc]));
-      Torsion t;
-      Vector dd0, dd1, dd2;
-      const double t_phi = t.compute(d0,d1,d2,dd0,dd1,dd2);
-      const double *PARS_DA = db.PARS_DA(aa_kind,at_kind,0);
-      const double val1 = 3.*t_phi+PARS_DA[3];
-      const double val2 = t_phi+PARS_DA[4];
-      shift += CO_DA[0]*(PARS_DA[0]*cos(val1)+PARS_DA[1]*cos(val2)+PARS_DA[2]);
-      const double fact = -CO_DA[0]*(+3.*PARS_DA[0]*sin(val1)+PARS_DA[1]*sin(val2));
-
-      cs_derivs[kdx+Cp+1] += fact*dd0;
-      cs_derivs[kdx+Nc+1] += fact*(dd1-dd0);
-      cs_derivs[kdx+CAc+1]+= fact*(dd2-dd1);
-      cs_derivs[kdx+Cc+1] += -fact*dd2;
-      cs_atoms[kdx+Cp+1] = myfrag->bb[Cp];
-      cs_atoms[kdx+Nc+1] = myfrag->bb[Nc];
-      cs_atoms[kdx+CAc+1]= myfrag->bb[CAc];
-      cs_atoms[kdx+Cc+1] = myfrag->bb[Cc];
-    }
-
-    //Psi
-    {
-      const Vector d0 = delta(getPosition(myfrag->bb[CAc]), getPosition(myfrag->bb[Nc]));
-      const Vector d1 = delta(getPosition(myfrag->bb[Cc]), getPosition(myfrag->bb[CAc]));
-      const Vector d2 = delta(getPosition(myfrag->bb[Nn]), getPosition(myfrag->bb[Cc]));
-      Torsion t;
-      Vector dd0, dd1, dd2;
-      const double t_psi = t.compute(d0,d1,d2,dd0,dd1,dd2);
-      const double *PARS_DA = db.PARS_DA(aa_kind,at_kind,1);
-      const double val1 = 3.*t_psi+PARS_DA[3];
-      const double val2 = t_psi+PARS_DA[4];
-      shift += CO_DA[1]*(PARS_DA[0]*cos(val1)+PARS_DA[1]*cos(val2)+PARS_DA[2]);
-      const double fact = -CO_DA[1]*(+3.*PARS_DA[0]*sin(val1)+PARS_DA[1]*sin(val2));
-
-      cs_derivs[kdx+Nc+1] += fact*dd0;
-      cs_derivs[kdx+CAc+1] += fact*(dd1-dd0);
-      cs_derivs[kdx+Cc+1] += fact*(dd2-dd1);
-      cs_derivs[kdx+Nn+1] += -fact*dd2;
-      cs_atoms[kdx+Nc+1] = myfrag->bb[Nc];
-      cs_atoms[kdx+CAc+1]= myfrag->bb[CAc];
-      cs_atoms[kdx+Cc+1] = myfrag->bb[Cc];
-      cs_atoms[kdx+Nn+1] = myfrag->bb[Nn];
-    }
-
-    //Chi
-    if(myfrag->has_chi1) {
-      const Vector d0 = delta(getPosition(myfrag->bb[CAc]), getPosition(myfrag->bb[Nc]));
-      const Vector d1 = delta(getPosition(myfrag->bb[CBc]), getPosition(myfrag->bb[CAc]));
-      const Vector d2 = delta(getPosition(myfrag->bb[CGc]), getPosition(myfrag->bb[CBc]));
-      Torsion t;
-      Vector dd0, dd1, dd2;
-      const double t_chi1 = t.compute(d0,d1,d2,dd0,dd1,dd2);
-      const double *PARS_DA = db.PARS_DA(aa_kind,at_kind,2);
-      const double val1 = 3.*t_chi1+PARS_DA[3];
-      const double val2 = t_chi1+PARS_DA[4];
-      shift += CO_DA[2]*(PARS_DA[0]*cos(val1)+PARS_DA[1]*cos(val2)+PARS_DA[2]);
-      const double fact = -CO_DA[2]*(+3.*PARS_DA[0]*sin(val1)+PARS_DA[1]*sin(val2));
-
-      cs_derivs[kdx+Nc+1] += fact*dd0;
-      cs_derivs[kdx+CAc+1] += fact*(dd1-dd0);
-      cs_derivs[kdx+CBc+1] += fact*(dd2-dd1);
-      cs_derivs[kdx+CGc+1] += -fact*dd2;
-      cs_atoms[kdx+Nc+1]  = myfrag->bb[Nc];
-      cs_atoms[kdx+CAc+1] = myfrag->bb[CAc];
-      cs_atoms[kdx+CBc+1] = myfrag->bb[CBc];
-      cs_atoms[kdx+CGc+1] = myfrag->bb[CGc];
-
-      atom_counter += 2;
-    }
-    //END OF DIHE
-
-    //SIDE CHAIN
-    const double * CONST_SC2 = db.CONST_SC2(aa_kind,at_kind,myfrag->res_type_curr);
-    const unsigned sidsize = myfrag->side_chain.size();
-    for(unsigned q=0; q<sidsize; q++) {
-      const double cs2q = CONST_SC2[q];
-      if(cs2q==0.) continue;
-      const unsigned jpos = myfrag->side_chain[q];
-      if(ipos==jpos) continue;
-      const Vector distance = delta(getPosition(jpos),getPosition(ipos));
-      const double d = distance.modulo();
-      const double fact = cs2q/d;
-
-      shift += cs2q*d;
-      const Vector der = fact*distance;
-      cs_derivs[kdx+0] += der;
-      cs_derivs[kdx+q+atom_counter] = -der;
-      cs_atoms[kdx+q+atom_counter] = jpos;
-    }
+  #pragma omp parallel num_threads(nt)
+  {
+    #pragma omp for
+    for(unsigned cs=rank; cs<chemicalshifts.size(); cs+=stride) {
+      const unsigned kdx=cs*max_cs_atoms;
+      const ChemicalShift *myfrag = &chemicalshifts[cs];
+      const unsigned aa_kind = myfrag->res_kind;
+      const unsigned at_kind = myfrag->atm_kind;
+
+      double shift = db.CONSTAAPREV(aa_kind,at_kind)[myfrag->res_type_prev] +
+                     db.CONSTAACURR(aa_kind,at_kind)[myfrag->res_type_curr] +
+                     db.CONSTAANEXT(aa_kind,at_kind)[myfrag->res_type_next];
+
+      const unsigned ipos = myfrag->ipos;
+      cs_atoms[kdx+0] = ipos;
+      unsigned atom_counter = 1;
+
+      //BACKBONE (PREV CURR NEXT)
+      const double * CONST_BB2 = db.CONST_BB2(aa_kind,at_kind);
+      const unsigned bbsize = 16;
+      for(unsigned q=0; q<bbsize; q++) {
+        const double cb2q = CONST_BB2[q];
+        if(cb2q==0.) continue;
+        const unsigned jpos = myfrag->bb[q];
+        if(ipos==jpos) continue;
+        const Vector distance = delta(getPosition(jpos),getPosition(ipos));
+        const double d = distance.modulo();
+        const double fact = cb2q/d;
+
+        shift += cb2q*d;
+        const Vector der = fact*distance;
 
-    atom_counter += sidsize;
-
-    //EXTRA DIST
-    const double * CONST_XD  = db.CONST_XD(aa_kind,at_kind);
-    const unsigned xdsize=myfrag->xd1.size();
-    for(unsigned q=0; q<xdsize; q++) {
-      const double cxdq = CONST_XD[q];
-      if(cxdq==0.) continue;
-      if(myfrag->xd1[q]==-1||myfrag->xd2[q]==-1) continue;
-      const Vector distance = delta(getPosition(myfrag->xd1[q]),getPosition(myfrag->xd2[q]));
-      const double d = distance.modulo();
-      const double fact = cxdq/d;
-
-      shift += cxdq*d;
-      const Vector der = fact*distance;
-      cs_derivs[kdx+2*q+atom_counter  ] = der;
-      cs_derivs[kdx+2*q+atom_counter+1] = -der;
-      cs_atoms[kdx+2*q+atom_counter] = myfrag->xd2[q];
-      cs_atoms[kdx+2*q+atom_counter+1] = myfrag->xd1[q];
-    }
+        cs_derivs[kdx+0] += der;
+        cs_derivs[kdx+q+atom_counter] = -der;
+        cs_atoms[kdx+q+atom_counter] = jpos;
+      }
 
-    atom_counter += 2*xdsize;
-
-    //RINGS
-    const double *rc = db.CO_RING(aa_kind,at_kind);
-    const unsigned rsize = ringInfo.size();
-    // cycle over the list of rings
-    for(unsigned q=0; q<rsize; q++) {
-      // compute angle from ring middle point to current atom position
-      // get distance vector from query atom to ring center and normal vector to ring plane
-      const Vector n   = ringInfo[q].normVect;
-      const double nL  = ringInfo[q].lengthNV;
-      const double inL2 = ringInfo[q].lengthN2;
-
-      const Vector d = delta(ringInfo[q].position, getPosition(ipos));
-      const double dL2 = d.modulo2();
-      double dL  = sqrt(dL2);
-      const double idL3 = 1./(dL2*dL);
-
-      const double dn    = dotProduct(d,n);
-      const double dn2   = dn*dn;
-      const double dLnL  = dL*nL;
-      const double dL_nL = dL/nL;
-
-      const double ang2 = dn2*inL2/dL2;
-      const double u    = 1.-3.*ang2;
-      const double cc   = rc[ringInfo[q].rtype];
-
-      shift += cc*u*idL3;
-
-      const double fUU    = -6.*dn*inL2;
-      const double fUQ    = fUU/dL;
-      const Vector gradUQ = fUQ*(dL2*n - dn*d);
-      const Vector gradVQ = (3.*dL*u)*d;
-
-      const double fact   = cc*idL3*idL3;
-      cs_derivs[kdx+0] += fact*(gradUQ - gradVQ);
-
-      const double fU       = fUU/nL;
-      double OneOverN = 1./6.;
-      if(ringInfo[q].numAtoms==5) OneOverN=1./3.;
-      const Vector factor2  = OneOverN*n;
-      const Vector factor4  = (OneOverN/dL_nL)*d;
-
-      const Vector gradV    = -OneOverN*gradVQ;
-
-      if(ringInfo[q].numAtoms==6) {
-        // update forces on ring atoms
-        for(unsigned at=0; at<6; at++) {
-          const Vector ab = crossProduct(d,ringInfo[q].g[at]);
-          const Vector c  = crossProduct(n,ringInfo[q].g[at]);
-          const Vector factor3 = 0.5*dL_nL*c;
-          const Vector factor1 = 0.5*ab;
-          const Vector gradU   = fU*( dLnL*(factor1 - factor2) -dn*(factor3 - factor4) );
-          cs_derivs[kdx+at+atom_counter] = fact*(gradU - gradV);
-          cs_atoms[kdx+at+atom_counter] = ringInfo[q].atom[at];
-        }
-        atom_counter += 6;
-      }  else {
-        for(unsigned at=0; at<3; at++) {
-          const Vector ab = crossProduct(d,ringInfo[q].g[at]);
-          const Vector c  = crossProduct(n,ringInfo[q].g[at]);
-          const Vector factor3 = dL_nL*c;
-          const Vector factor1 = ab;
-          const Vector gradU   = fU*( dLnL*(factor1 - factor2) -dn*(factor3 - factor4) );
-          cs_derivs[kdx+at+atom_counter] = fact*(gradU - gradV);
-        }
-        cs_atoms[kdx+atom_counter] = ringInfo[q].atom[0];
-        cs_atoms[kdx+atom_counter+1] = ringInfo[q].atom[2];
-        cs_atoms[kdx+atom_counter+2] = ringInfo[q].atom[3];
-        atom_counter += 3;
+      atom_counter += bbsize;
+
+      //DIHEDRAL ANGLES
+      const double *CO_DA = db.CO_DA(aa_kind,at_kind);
+      //Phi
+      {
+        const Vector d0 = delta(getPosition(myfrag->bb[Nc]), getPosition(myfrag->bb[Cp]));
+        const Vector d1 = delta(getPosition(myfrag->bb[CAc]), getPosition(myfrag->bb[Nc]));
+        const Vector d2 = delta(getPosition(myfrag->bb[Cc]), getPosition(myfrag->bb[CAc]));
+        Torsion t;
+        Vector dd0, dd1, dd2;
+        const double t_phi = t.compute(d0,d1,d2,dd0,dd1,dd2);
+        const double *PARS_DA = db.PARS_DA(aa_kind,at_kind,0);
+        const double val1 = 3.*t_phi+PARS_DA[3];
+        const double val2 = t_phi+PARS_DA[4];
+        shift += CO_DA[0]*(PARS_DA[0]*cos(val1)+PARS_DA[1]*cos(val2)+PARS_DA[2]);
+        const double fact = -CO_DA[0]*(+3.*PARS_DA[0]*sin(val1)+PARS_DA[1]*sin(val2));
+
+        cs_derivs[kdx+Cp+1] += fact*dd0;
+        cs_derivs[kdx+Nc+1] += fact*(dd1-dd0);
+        cs_derivs[kdx+CAc+1]+= fact*(dd2-dd1);
+        cs_derivs[kdx+Cc+1] += -fact*dd2;
+        cs_atoms[kdx+Cp+1] = myfrag->bb[Cp];
+        cs_atoms[kdx+Nc+1] = myfrag->bb[Nc];
+        cs_atoms[kdx+CAc+1]= myfrag->bb[CAc];
+        cs_atoms[kdx+Cc+1] = myfrag->bb[Cc];
       }
-    }
-    //END OF RINGS
-
-    //NON BOND
-    const double * CONST_CO_SPHERE3 = db.CO_SPHERE(aa_kind,at_kind,0);
-    const double * CONST_CO_SPHERE  = db.CO_SPHERE(aa_kind,at_kind,1);
-    const unsigned boxsize = myfrag->box_nb.size();
-    for(unsigned q=0; q<boxsize; q++) {
-      const unsigned jpos = myfrag->box_nb[q];
-      const Vector distance = delta(getPosition(jpos),getPosition(ipos));
-      const double d2 = distance.modulo2();
-
-      if(d2<cutOffDist2) {
-        double factor1  = sqrt(d2);
-        double dfactor1 = 1./factor1;
-        double factor3  = dfactor1*dfactor1*dfactor1;
-        double dfactor3 = -3.*factor3*dfactor1*dfactor1;
-
-        if(d2>cutOnDist2) {
-          const double af = cutOffDist2 - d2;
-          const double bf = cutOffDist2 - 3.*cutOnDist2 + 2.*d2;
-          const double cf = invswitch*af;
-          const double df = cf*af*bf;
-          factor1 *= df;
-          factor3 *= df;
-
-          const double d4  = d2*d2;
-          const double af1 = 15.*cutOnDist2*d2;
-          const double bf1 = -14.*d4;
-          const double cf1 = -3.*cutOffDist2*cutOnDist2 + cutOffDist2*d2;
-          const double df1 = af1+bf1+cf1;
-          dfactor1 *= cf*(cutOffDist4+df1);
-
-          const double af3 = +2.*cutOffDist2*cutOnDist2;
-          const double bf3 = d2*(cutOffDist2+cutOnDist2);
-          const double cf3 = -2.*d4;
-          const double df3 = (af3+bf3+cf3)*d2;
-          dfactor3 *= invswitch*(cutMixed+df3);
-        }
 
-        const unsigned t = type[jpos];
-        shift += factor1*CONST_CO_SPHERE[t] + factor3*CONST_CO_SPHERE3[t] ;
-        const double fact = dfactor1*CONST_CO_SPHERE[t]+dfactor3*CONST_CO_SPHERE3[t];
-        const Vector der  = fact*distance;
+      //Psi
+      {
+        const Vector d0 = delta(getPosition(myfrag->bb[CAc]), getPosition(myfrag->bb[Nc]));
+        const Vector d1 = delta(getPosition(myfrag->bb[Cc]), getPosition(myfrag->bb[CAc]));
+        const Vector d2 = delta(getPosition(myfrag->bb[Nn]), getPosition(myfrag->bb[Cc]));
+        Torsion t;
+        Vector dd0, dd1, dd2;
+        const double t_psi = t.compute(d0,d1,d2,dd0,dd1,dd2);
+        const double *PARS_DA = db.PARS_DA(aa_kind,at_kind,1);
+        const double val1 = 3.*t_psi+PARS_DA[3];
+        const double val2 = t_psi+PARS_DA[4];
+        shift += CO_DA[1]*(PARS_DA[0]*cos(val1)+PARS_DA[1]*cos(val2)+PARS_DA[2]);
+        const double fact = -CO_DA[1]*(+3.*PARS_DA[0]*sin(val1)+PARS_DA[1]*sin(val2));
+
+        cs_derivs[kdx+Nc+1] += fact*dd0;
+        cs_derivs[kdx+CAc+1] += fact*(dd1-dd0);
+        cs_derivs[kdx+Cc+1] += fact*(dd2-dd1);
+        cs_derivs[kdx+Nn+1] += -fact*dd2;
+        cs_atoms[kdx+Nc+1] = myfrag->bb[Nc];
+        cs_atoms[kdx+CAc+1]= myfrag->bb[CAc];
+        cs_atoms[kdx+Cc+1] = myfrag->bb[Cc];
+        cs_atoms[kdx+Nn+1] = myfrag->bb[Nn];
+      }
 
+      //Chi
+      if(myfrag->has_chi1) {
+        const Vector d0 = delta(getPosition(myfrag->bb[CAc]), getPosition(myfrag->bb[Nc]));
+        const Vector d1 = delta(getPosition(myfrag->bb[CBc]), getPosition(myfrag->bb[CAc]));
+        const Vector d2 = delta(getPosition(myfrag->bb[CGc]), getPosition(myfrag->bb[CBc]));
+        Torsion t;
+        Vector dd0, dd1, dd2;
+        const double t_chi1 = t.compute(d0,d1,d2,dd0,dd1,dd2);
+        const double *PARS_DA = db.PARS_DA(aa_kind,at_kind,2);
+        const double val1 = 3.*t_chi1+PARS_DA[3];
+        const double val2 = t_chi1+PARS_DA[4];
+        shift += CO_DA[2]*(PARS_DA[0]*cos(val1)+PARS_DA[1]*cos(val2)+PARS_DA[2]);
+        const double fact = -CO_DA[2]*(+3.*PARS_DA[0]*sin(val1)+PARS_DA[1]*sin(val2));
+
+        cs_derivs[kdx+Nc+1] += fact*dd0;
+        cs_derivs[kdx+CAc+1] += fact*(dd1-dd0);
+        cs_derivs[kdx+CBc+1] += fact*(dd2-dd1);
+        cs_derivs[kdx+CGc+1] += -fact*dd2;
+        cs_atoms[kdx+Nc+1]  = myfrag->bb[Nc];
+        cs_atoms[kdx+CAc+1] = myfrag->bb[CAc];
+        cs_atoms[kdx+CBc+1] = myfrag->bb[CBc];
+        cs_atoms[kdx+CGc+1] = myfrag->bb[CGc];
+
+        atom_counter += 2;
+      }
+      //END OF DIHE
+
+      //SIDE CHAIN
+      const double * CONST_SC2 = db.CONST_SC2(aa_kind,at_kind,myfrag->res_type_curr);
+      const unsigned sidsize = myfrag->side_chain.size();
+      for(unsigned q=0; q<sidsize; q++) {
+        const double cs2q = CONST_SC2[q];
+        if(cs2q==0.) continue;
+        const unsigned jpos = myfrag->side_chain[q];
+        if(ipos==jpos) continue;
+        const Vector distance = delta(getPosition(jpos),getPosition(ipos));
+        const double d = distance.modulo();
+        const double fact = cs2q/d;
+
+        shift += cs2q*d;
+        const Vector der = fact*distance;
         cs_derivs[kdx+0] += der;
         cs_derivs[kdx+q+atom_counter] = -der;
         cs_atoms[kdx+q+atom_counter] = jpos;
       }
-    }
-    //END NON BOND
 
-    atom_counter += boxsize;
-    all_shifts[cs] = shift;
+      atom_counter += sidsize;
+
+      //EXTRA DIST
+      const double * CONST_XD  = db.CONST_XD(aa_kind,at_kind);
+      const unsigned xdsize=myfrag->xd1.size();
+      for(unsigned q=0; q<xdsize; q++) {
+        const double cxdq = CONST_XD[q];
+        if(cxdq==0.) continue;
+        if(myfrag->xd1[q]==-1||myfrag->xd2[q]==-1) continue;
+        const Vector distance = delta(getPosition(myfrag->xd1[q]),getPosition(myfrag->xd2[q]));
+        const double d = distance.modulo();
+        const double fact = cxdq/d;
+
+        shift += cxdq*d;
+        const Vector der = fact*distance;
+        cs_derivs[kdx+2*q+atom_counter  ] = der;
+        cs_derivs[kdx+2*q+atom_counter+1] = -der;
+        cs_atoms[kdx+2*q+atom_counter] = myfrag->xd2[q];
+        cs_atoms[kdx+2*q+atom_counter+1] = myfrag->xd1[q];
+      }
 
-    if(camshift) {
-      score += (all_shifts[cs] - chemicalshifts[cs].exp_cs)*(all_shifts[cs] - chemicalshifts[cs].exp_cs)/camshift_sigma2[chemicalshifts[cs].atm_kind];
-      double fact = 2.0*(all_shifts[cs] - chemicalshifts[cs].exp_cs)/camshift_sigma2[chemicalshifts[cs].atm_kind];
-      for(unsigned i=0; i<chemicalshifts[cs].totcsatoms; i++) {
-        aa_derivs[cs_atoms[kdx+i]] += cs_derivs[kdx+i]*fact;
+      atom_counter += 2*xdsize;
+
+      //RINGS
+      const double *rc = db.CO_RING(aa_kind,at_kind);
+      const unsigned rsize = ringInfo.size();
+      // cycle over the list of rings
+      for(unsigned q=0; q<rsize; q++) {
+        // compute angle from ring middle point to current atom position
+        // get distance vector from query atom to ring center and normal vector to ring plane
+        const Vector n   = ringInfo[q].normVect;
+        const double nL  = ringInfo[q].lengthNV;
+        const double inL2 = ringInfo[q].lengthN2;
+
+        const Vector d = delta(ringInfo[q].position, getPosition(ipos));
+        const double dL2 = d.modulo2();
+        double dL  = sqrt(dL2);
+        const double idL3 = 1./(dL2*dL);
+
+        const double dn    = dotProduct(d,n);
+        const double dn2   = dn*dn;
+        const double dLnL  = dL*nL;
+        const double dL_nL = dL/nL;
+
+        const double ang2 = dn2*inL2/dL2;
+        const double u    = 1.-3.*ang2;
+        const double cc   = rc[ringInfo[q].rtype];
+
+        shift += cc*u*idL3;
+
+        const double fUU    = -6.*dn*inL2;
+        const double fUQ    = fUU/dL;
+        const Vector gradUQ = fUQ*(dL2*n - dn*d);
+        const Vector gradVQ = (3.*dL*u)*d;
+
+        const double fact   = cc*idL3*idL3;
+        cs_derivs[kdx+0] += fact*(gradUQ - gradVQ);
+
+        const double fU       = fUU/nL;
+        double OneOverN = 1./6.;
+        if(ringInfo[q].numAtoms==5) OneOverN=1./3.;
+        const Vector factor2  = OneOverN*n;
+        const Vector factor4  = (OneOverN/dL_nL)*d;
+
+        const Vector gradV    = -OneOverN*gradVQ;
+
+        if(ringInfo[q].numAtoms==6) {
+          // update forces on ring atoms
+          for(unsigned at=0; at<6; at++) {
+            const Vector ab = crossProduct(d,ringInfo[q].g[at]);
+            const Vector c  = crossProduct(n,ringInfo[q].g[at]);
+            const Vector factor3 = 0.5*dL_nL*c;
+            const Vector factor1 = 0.5*ab;
+            const Vector gradU   = fU*( dLnL*(factor1 - factor2) -dn*(factor3 - factor4) );
+            cs_derivs[kdx+at+atom_counter] = fact*(gradU - gradV);
+            cs_atoms[kdx+at+atom_counter] = ringInfo[q].atom[at];
+          }
+          atom_counter += 6;
+        }  else {
+          for(unsigned at=0; at<3; at++) {
+            const Vector ab = crossProduct(d,ringInfo[q].g[at]);
+            const Vector c  = crossProduct(n,ringInfo[q].g[at]);
+            const Vector factor3 = dL_nL*c;
+            const Vector factor1 = ab;
+            const Vector gradU   = fU*( dLnL*(factor1 - factor2) -dn*(factor3 - factor4) );
+            cs_derivs[kdx+at+atom_counter] = fact*(gradU - gradV);
+          }
+          cs_atoms[kdx+atom_counter] = ringInfo[q].atom[0];
+          cs_atoms[kdx+atom_counter+1] = ringInfo[q].atom[2];
+          cs_atoms[kdx+atom_counter+2] = ringInfo[q].atom[3];
+          atom_counter += 3;
+        }
       }
+      //END OF RINGS
+
+      //NON BOND
+      const double * CONST_CO_SPHERE3 = db.CO_SPHERE(aa_kind,at_kind,0);
+      const double * CONST_CO_SPHERE  = db.CO_SPHERE(aa_kind,at_kind,1);
+      const unsigned boxsize = myfrag->box_nb.size();
+      for(unsigned q=0; q<boxsize; q++) {
+        const unsigned jpos = myfrag->box_nb[q];
+        const Vector distance = delta(getPosition(jpos),getPosition(ipos));
+        const double d2 = distance.modulo2();
+
+        if(d2<cutOffDist2) {
+          double factor1  = sqrt(d2);
+          double dfactor1 = 1./factor1;
+          double factor3  = dfactor1*dfactor1*dfactor1;
+          double dfactor3 = -3.*factor3*dfactor1*dfactor1;
+
+          if(d2>cutOnDist2) {
+            const double af = cutOffDist2 - d2;
+            const double bf = cutOffDist2 - 3.*cutOnDist2 + 2.*d2;
+            const double cf = invswitch*af;
+            const double df = cf*af*bf;
+            factor1 *= df;
+            factor3 *= df;
+
+            const double d4  = d2*d2;
+            const double af1 = 15.*cutOnDist2*d2;
+            const double bf1 = -14.*d4;
+            const double cf1 = -3.*cutOffDist2*cutOnDist2 + cutOffDist2*d2;
+            const double df1 = af1+bf1+cf1;
+            dfactor1 *= cf*(cutOffDist4+df1);
+
+            const double af3 = +2.*cutOffDist2*cutOnDist2;
+            const double bf3 = d2*(cutOffDist2+cutOnDist2);
+            const double cf3 = -2.*d4;
+            const double df3 = (af3+bf3+cf3)*d2;
+            dfactor3 *= invswitch*(cutMixed+df3);
+          }
+
+          const unsigned t = type[jpos];
+          shift += factor1*CONST_CO_SPHERE[t] + factor3*CONST_CO_SPHERE3[t] ;
+          const double fact = dfactor1*CONST_CO_SPHERE[t]+dfactor3*CONST_CO_SPHERE3[t];
+          const Vector der  = fact*distance;
+
+          cs_derivs[kdx+0] += der;
+          cs_derivs[kdx+q+atom_counter] = -der;
+          cs_atoms[kdx+q+atom_counter] = jpos;
+        }
+      }
+      //END NON BOND
+
+      atom_counter += boxsize;
+      all_shifts[cs] = shift;
     }
   }
 
@@ -1304,10 +1295,11 @@ void CS2Backbone::calculate()
     if(!getDoScore()) return;
   }
 
+  double score = 0.;
+
   /* Metainference */
   if(getDoScore()) {
     score = getScore();
-    #pragma omp parallel for num_threads(nt)
     for(unsigned cs=rank; cs<chemicalshifts.size(); cs+=stride) {
       const unsigned kdx=cs*max_cs_atoms;
       const double fact = getMetaDer(cs);
@@ -1317,6 +1309,18 @@ void CS2Backbone::calculate()
     }
   }
 
+  /* camshift */
+  if(camshift) {
+    for(unsigned cs=rank; cs<chemicalshifts.size(); cs+=stride) {
+      const unsigned kdx=cs*max_cs_atoms;
+      score += (all_shifts[cs] - chemicalshifts[cs].exp_cs)*(all_shifts[cs] - chemicalshifts[cs].exp_cs)/camshift_sigma2[chemicalshifts[cs].atm_kind];
+      double fact = 2.0*(all_shifts[cs] - chemicalshifts[cs].exp_cs)/camshift_sigma2[chemicalshifts[cs].atm_kind];
+      for(unsigned i=0; i<chemicalshifts[cs].totcsatoms; i++) {
+        aa_derivs[cs_atoms[kdx+i]] += cs_derivs[kdx+i]*fact;
+      }
+    }
+  }
+
   if(!serial) {
     comm.Sum(&aa_derivs[0][0], 3*aa_derivs.size());
     if(camshift) comm.Sum(&score, 1);
-- 
GitLab