Example #1
0
  /*!  This function calculates the torsion angle of three vectors, represented
    by four points A--B--C--D, i.e. B and C are vertexes, but none of A--B,
    B--C, and C--D are colinear.  A "torsion angle" is the amount of "twist"
    or torsion needed around the B--C axis to bring A--B into the same plane
    as B--C--D.  The torsion is measured by "looking down" the vector B--C so
    that B is superimposed on C, then noting how far you'd have to rotate
    A--B to superimpose A over D.  Angles are + in theanticlockwise
    direction.  The operation is symmetrical in that if you reverse the image
    (look from C to B and rotate D over A), you get the same answer.
  */
  OBAPI double VectorTorsion(const Eigen::Vector3d& a, const Eigen::Vector3d& b,
      const Eigen::Vector3d& c, const Eigen::Vector3d& d)
  {
    // Bond vectors of the three atoms
    Eigen::Vector3d ab = b - a;
    Eigen::Vector3d bc = c - b;
    Eigen::Vector3d cd = d - c;

    // length of the three bonds
    const double l_ab = ab.norm();
    const double l_bc = bc.norm();
    const double l_cd = cd.norm();
    
    if (IsNearZero(l_ab) || IsNearZero(l_bc) || IsNearZero(l_cd) ) {
      return 0.0;
    }
 
    // normalize the bond vectors:
    ab *= (1.0 / l_ab);
    bc *= (1.0 / l_bc);
    cd *= (1.0 / l_cd);

    const Eigen::Vector3d ca = ab.cross(bc);
    const Eigen::Vector3d cb = bc.cross(cd);
    const Eigen::Vector3d cc = ca.cross(cb);
    const double d1 = cc.dot(bc);
    const double d2 = ca.dot(cb);
    const double tor = RAD_TO_DEG * atan2(d1, d2);
    
    return tor;  
  }
Example #2
0
  /*! This method calculates the angle between two vectors
     
  \warning If length() of any of the two vectors is == 0.0,
  this method will divide by zero. If the product of the
  length() of the two vectors is very close to 0.0, but not ==
  0.0, this method may behave in unexpected ways and return
  almost random results; details may depend on your particular
  floating point implementation. The use of this method is
  therefore highly discouraged, unless you are certain that the
  length()es are in a reasonable range, away from 0.0 (Stefan
  Kebekus)

  \deprecated This method will probably replaced by a safer
  algorithm in the future.

  \todo Replace this method with a more fool-proof version.

  @returns the angle in degrees (0-360)
  */
  OBAPI double VectorAngle (const Eigen::Vector3d& ab, const Eigen::Vector3d& bc)
  {
    // length of the two bonds
    const double l_ab = ab.norm();
    const double l_bc = bc.norm();
 
    if (IsNearZero(l_ab) || IsNearZero(l_bc)) {
      return 0.0;
    }

    // Calculate the cross product of v1 and v2, test if it has length unequal 0
    const Eigen::Vector3d c1 = ab.cross(bc);
    if (IsNearZero(c1.norm())) {
      return 0.0;
    }

    // Calculate the cos of theta and then theta
    const double dp = ab.dot(bc) / (l_ab * l_bc);
    if (dp > 1.0) {
      return 0.0;
    } else if (dp < -1.0) {
      return 180.0;
    } else {
      #ifdef USE_ACOS_LOOKUP_TABLE
      return (RAD_TO_DEG * acosLookup(dp));
      #else
      return (RAD_TO_DEG * acos(dp));
      #endif
    }
    
    return 0.0;
  }
    double DiscretizedArcLength(const LLPoint &center, double dRadius,
                                double dStartCrs, double dEndCrs,
                                int nOrient, int nSegments, double dTol)
    {
        nSegments = clamp(nSegments, 1, 128);

        double dError = 0.0;
        double dArcLength = 0.0;
        double dOldArcLength = 0.0;
        const double dSubtendedAngle = GetArcExtent(dStartCrs, dEndCrs, nOrient, dTol);

        // with k equal to 0 then there will only be nSegments subsegments calculated.
        // need to figure out how to make this flexible based on the value in dRadius.
        // Bigger radius need more segments than 16 and smaller segments need less.
        // For now 16 is enough to pass the 8260.54A test case.
        int k = 0;
        while (k == 0 || ((dError > kTol) && (k <= 0)))
        {
            const double dTheta = dSubtendedAngle / nSegments;
            const double dAltitude = 0.0;
            dArcLength = 0.0;

            for (int i = 0; i < nSegments; i++)
            {
                const double theta = dStartCrs + i * dTheta;
                const LLPoint p1 = DestVincenty(center, theta, dRadius);
                const LLPoint p2 = DestVincenty(center, theta + 0.5 * dTheta, dRadius);
                const LLPoint p3 = DestVincenty(center, theta + dTheta, dRadius);

                const VMath::Vector3 v1 = ECEF(p1, dAltitude);
                const VMath::Vector3 v2 = ECEF(p2, dAltitude);
                const VMath::Vector3 v3 = ECEF(p3, dAltitude);
                const VMath::Vector3 vChord1 = v2 - v1;
                const VMath::Vector3 vChord2 = v2 - v3;
                const double x1 = VMath::Vector3::Length(vChord1); //v2 - v1);
                const double x2 = VMath::Vector3::Length(vChord2); //v2 - v3);
                const double d = VMath::Vector3::Dot(vChord1, vChord2);

                if (IsNearZero(x1, kTol) && IsNearZero(x2, kTol) && IsNearZero(d, kTol))
                {
                    dArcLength = 0.0;
                    break;
                }

                const double xi = d / (x1 * x2);
                const double _x1_x2Sq = x1 / x2 - xi;
                const double sigma = sqrt(1.0 - (xi * xi));
                const double R = (x2 * sqrt((_x1_x2Sq * _x1_x2Sq) + (sigma * sigma))) / (2.0 * sigma);
                const double A = 2 * (M_PI - acos(xi));
                const double L = R * A;
                dArcLength += L;
            }
            nSegments *= 2;
            dError = fabs(dArcLength - dOldArcLength);
            dOldArcLength = dArcLength;
            k++;
        }
        return dArcLength;
    }
Example #4
0
  OBAPI double VectorOOP(const Eigen::Vector3d &a, const Eigen::Vector3d &b,
      const Eigen::Vector3d &c,const Eigen::Vector3d &d)
  {
    // This is adapted from http://scidok.sulb.uni-saarland.de/volltexte/2007/1325/pdf/Dissertation_1544_Moll_Andr_2007.pdf
    // Many thanks to Andreas Moll and the BALLView developers for this

    // calculate normalized bond vectors from central atom to outer atoms:
    Eigen::Vector3d ab = a - b;
    // store length of this bond:
    const double length_ab = ab.norm();
    if (IsNearZero(length_ab)) {
      return 0.0;
    }
    // store the normalized bond vector from central atom to outer atoms:
    // normalize the bond vector:
    ab /= length_ab;
		
    Eigen::Vector3d cb = c - b;
    const double length_cb = cb.norm();
    if (IsNearZero(length_cb)) {
      return 0.0;
    }
    cb /= length_cb;
	
    Eigen::Vector3d db = d - b;
    const double length_db = db.norm();
    if (IsNearZero(length_db)) {
      return 0.0;
    }
    db /= length_db;
	
    // the normal vectors of the three planes:
    const Eigen::Vector3d an = ab.cross(cb); 
    const Eigen::Vector3d bn = cb.cross(db); 
    const Eigen::Vector3d cn = db.cross(ab); 

    // Bond angle ji to jk
    const double cos_theta = ab.dot(cb);
    #ifdef USE_ACOS_LOOKUP_TABLE
    const double theta = acosLookup(cos_theta);
    #else
    const double theta = acos(cos_theta);
    #endif
    // If theta equals 180 degree or 0 degree
    if (IsNearZero(theta) || IsNearZero(fabs(theta - M_PI))) {
      return 0.0;
    }
				
    const double sin_theta = sin(theta);
    const double sin_dl = an.dot(db) / sin_theta;

    // the wilson angle:
    const double dl = asin(sin_dl);

    return RAD_TO_DEG * dl;
  }
Example #5
0
void FindLinearRoot( double *x, double *errArray, double & root )
	{
		if(x[0] == x[1]) {
			root = std::numeric_limits<double>::signaling_NaN();
		} else if(errArray[0] == errArray[1]) {
			if(IsNearZero(errArray[0] - errArray[1], 1e-15)) {
				root = x[0];
			} else {
				root = std::numeric_limits<double>::signaling_NaN();
			}
		} else {
			root = -errArray[0] * (x[1] - x[0]) / (errArray[1] - errArray[0]) + x[0];
		}
	}
Example #6
0
  void OBBond::SetLength(OBAtom *fixed, double length)
  {
    unsigned int i;
    OBMol *mol = (OBMol*)fixed->GetParent();
    vector3 v1,v2,v3,v4,v5;
    vector<int> children;

    obErrorLog.ThrowError(__FUNCTION__,
                          "Ran OpenBabel::SetBondLength", obAuditMsg);

    int a = fixed->GetIdx();
    int b = GetNbrAtom(fixed)->GetIdx();

    if (a == b)
      return; // this would be a problem...

    mol->FindChildren(children,a,b);
    children.push_back(b);

    v1 = GetNbrAtom(fixed)->GetVector();
    v2 = fixed->GetVector();
    v3 = v1 - v2;

    if (IsNearZero(v3.length_2())) { // too small to normalize, move the atoms apart
      obErrorLog.ThrowError(__FUNCTION__,
                            "Atoms are both at the same location, moving out of the way.", obWarning);
      v3.randomUnitVector();
    } else {
      v3.normalize();
    }

    v3 *= length;
    v3 += v2;
    v4 = v3 - v1;

    cerr << "v3: " << v3 << " v4: " << v4 << endl;

    for ( i = 0 ; i < children.size() ; i++ )
      {
        v1 = mol->GetAtom(children[i])->GetVector();
        v1 += v4;
        mol->GetAtom(children[i])->SetVector(v1);
      }
  }
Example #7
0
    int GeoLocusIntersect(const LLPoint &gStart, const LLPoint &gEnd, const Locus &loc, LLPoint &intersect,
                          double dTol, double dEps)
    {
        InverseResult result;
        DistVincenty(gStart, gEnd, result);
        const double gAz = result.azimuth;

        DistVincenty(loc.locusStart, loc.locusEnd, result);
        const double locStAz = result.azimuth;
        const double locLength = result.distance;

        double crs31, crs32, dist13, dist23;
        LLPoint pt1;
        if (!CrsIntersect(loc.locusStart, locStAz, crs31, dist13, gStart, gAz, crs32, dist23, dTol, pt1))
            return 0;

        DistVincenty(loc.geoStart, loc.geoEnd, result);

        const double tcrs = result.azimuth;
        double crsFromPt, distFromPt;
        LLPoint ptInt = PerpIntercept(loc.geoStart, tcrs, pt1, crsFromPt, distFromPt, dTol);

        double distLoc = DistToLocusP(loc, ptInt, dTol, dEps);

        double distarray[2];
        double errarray[2];
        errarray[1] = distFromPt - fabs(distLoc);
        distarray[1] = dist23;

        double distBase = dist23 - errarray[1] / cos(fabs(SignAzimuthDifference(crsFromPt, crs32)));

        int k = 0;
        const int maxCount = 10;
        while (!std::isnan(distBase) && fabs(errarray[1]) > dTol && k < maxCount)
        {
            pt1 = DestVincenty(gStart, gAz, distBase);
            errarray[0] = errarray[1];
            distarray[0] = distarray[1];
            distarray[1] = distBase;

            ptInt = PerpIntercept(loc.geoStart, tcrs, pt1, crsFromPt, distFromPt, dTol);
            distLoc = DistToLocusP(loc, ptInt, dTol, dEps);
            errarray[1] = distFromPt - fabs(distLoc);

            FindLinearRoot(distarray, errarray, distBase);
            k++;
        }
        intersect = pt1;

        DistVincenty(intersect, loc.locusStart, result);
        const double distLocStPt1 = result.distance;
        DistVincenty(intersect, loc.locusEnd, result);

        // found intersect point must be on or between locus
        // If 5e-3 is to tight a tolerance then try setting to 5e-2
        // For the 8260.54A Appendix test cases 1e-3 was to tight, 5e-3
        // works just fine.
        if (!IsNearZero(locLength - (distLocStPt1 + result.distance), 5e-3))
            return 0;
        return 1;
    }
Example #8
0
  bool MOL2Format::ReadMolecule(OBBase* pOb, OBConversion* pConv)
  {

    OBMol* pmol = pOb->CastAndClear<OBMol>();
    if(pmol==NULL)
      return false;

    //Define some references so we can use the old parameter names
    istream &ifs = *pConv->GetInStream();
    OBMol &mol = *pmol;

    //Old code follows...
    bool foundAtomLine = false;
    char buffer[BUFF_SIZE];
    char *comment = NULL;
    string str,str1;
    vector<string> vstr;
    int len;

    mol.BeginModify();

    for (;;)
      {
        if (!ifs.getline(buffer,BUFF_SIZE))
          return(false);
        if (EQn(buffer,"@<TRIPOS>MOLECULE",17))
          break;
      }

    int lcount;
    int natoms,nbonds;
    for (lcount=0;;lcount++)
      {
        if (!ifs.getline(buffer,BUFF_SIZE))
          return(false);
        if (EQn(buffer,"@<TRIPOS>ATOM",13))
          {
            foundAtomLine = true;
            break;
          }

        if (lcount == 0)
          {
            tokenize(vstr,buffer);
            if (!vstr.empty())
              mol.SetTitle(buffer);
          }
        else if (lcount == 1)
          sscanf(buffer,"%d%d",&natoms,&nbonds);
        else if (lcount == 4) //energy
          {
            tokenize(vstr,buffer);
            if (!vstr.empty() && vstr.size() == 3)
              if (vstr[0] == "Energy")
                mol.SetEnergy(atof(vstr[2].c_str()));
          }
        else if (lcount == 5) //comment
          {
            if ( buffer[0] )
              {
                len = (int) strlen(buffer)+1;
                // TODO allow better multi-line comments
                // which don't allow ill-formed data to consume memory
                // Thanks to Andrew Dalke for the pointer
                if (comment != NULL)
                  delete [] comment;
                comment = new char [len];
                memcpy(comment,buffer,len);
              }
          }
      }

    if (!foundAtomLine)
      {
        mol.EndModify();
        mol.Clear();
        obErrorLog.ThrowError(__FUNCTION__, "Unable to read Mol2 format file. No atoms found.", obWarning);
        return(false);
      }

    mol.ReserveAtoms(natoms);

    int i;
    vector3 v;
    OBAtom atom;
    bool hasPartialCharges=false;
    double x,y,z,pcharge;
    char temp_type[BUFF_SIZE], resname[BUFF_SIZE], atmid[BUFF_SIZE];
    int elemno, resnum = -1;

    ttab.SetFromType("SYB");
    for (i = 0;i < natoms;i++)
      {
        if (!ifs.getline(buffer,BUFF_SIZE))
          return(false);
        sscanf(buffer," %*s %1024s %lf %lf %lf %1024s %d %1024s %lf",
               atmid, &x,&y,&z, temp_type, &resnum, resname, &pcharge);

        atom.SetVector(x, y, z);

        // Handle "CL" and "BR" and other mis-typed atoms
        str = temp_type;
        if (strncmp(temp_type, "CL", 2) == 0) {
          str = "Cl";
        } else  if (strncmp(temp_type,"BR",2) == 0) {
          str = "Br";
        } else if (strncmp(temp_type,"S.o2", 4) == 02) {
          str = "S.O2";
        } else if (strncmp(temp_type,"S.o", 3) == 0) {
          str = "S.O";
        } else if (strncmp(temp_type,"SI", 2) == 0) {
          str = "Si";
        // The following cases are entries which are not in openbabel/data/types.txt
        // and should probably be added there
        } else if (strncmp(temp_type,"S.1", 3) == 0) {
          str = "S.2"; // no idea what the best type might be here
        } else if (strncmp(temp_type,"P.", 2) == 0) {
          str = "P.3";
        } else if (strncasecmp(temp_type,"Ti.", 3) == 0) { // e.g. Ti.th
          str = "Ti";
        } else if (strncasecmp(temp_type,"Ru.", 3) == 0) { // e.g. Ru.oh
          str = "Ru";
        }

        ttab.SetToType("ATN");
        ttab.Translate(str1,str);
        elemno = atoi(str1.c_str());
        ttab.SetToType("IDX");

        // We might have missed some SI or FE type things above, so here's
        // another check
        if( !elemno && isupper(temp_type[1]) )
          {
            temp_type[1] = (char)tolower(temp_type[1]);
            str = temp_type;
            ttab.Translate(str1,str);
            elemno = atoi(str1.c_str());
          }
        // One last check if there isn't a period in the type,
        // it's a malformed atom type, but it may be the element symbol
        // GaussView does this (PR#1739905)
        if ( !elemno ) {
          obErrorLog.ThrowError(__FUNCTION__, "This Mol2 file is non-standard. Cannot interpret atom types correctly, instead attempting to interpret as elements instead.", obWarning);

          string::size_type dotPos = str.find('.');
          if (dotPos == string::npos) {
            elemno = etab.GetAtomicNum(str.c_str());
          }
        }

        atom.SetAtomicNum(elemno);
        ttab.SetToType("INT");
        ttab.Translate(str1,str);
        atom.SetType(str1);
        atom.SetPartialCharge(pcharge);
        if (!mol.AddAtom(atom))
          return(false);
        if (!IsNearZero(pcharge))
          hasPartialCharges = true;

        // Add residue information if it exists
        if (resnum != -1 && resnum != 0 &&
            strlen(resname) != 0 && strncmp(resname,"<1>", 3) != 0)
          {
            OBResidue *res  = (mol.NumResidues() > 0) ?
              mol.GetResidue(mol.NumResidues()-1) : NULL;
            if (res == NULL || res->GetName() != resname ||
                static_cast<int>(res->GetNum()) != resnum)
              {
                vector<OBResidue*>::iterator ri;
                for (res = mol.BeginResidue(ri) ; res ; res = mol.NextResidue(ri))
                  if (res->GetName() == resname &&
                      static_cast<int>(res->GetNum())
                      == resnum)
                    break;

                if (res == NULL)
                  {
                    res = mol.NewResidue();
                    res->SetName(resname);
                    res->SetNum(resnum);
                  }
              }
            OBAtom *atomPtr = mol.GetAtom(mol.NumAtoms());
            res->AddAtom(atomPtr);
            res->SetAtomID(atomPtr, atmid);
          } // end adding residue info
      }

    for (;;)
      {
        if (!ifs.getline(buffer,BUFF_SIZE))
          return(false);
        str = buffer;
        if (!strncmp(buffer,"@<TRIPOS>BOND",13))
          break;
      }

    int start,end,order;
    for (i = 0; i < nbonds; i++)
      {
        if (!ifs.getline(buffer,BUFF_SIZE))
          return(false);

        sscanf(buffer,"%*d %d %d %1024s",&start,&end,temp_type);
        str = temp_type;
        order = 1;
        if (str == "ar" || str == "AR" || str == "Ar")
          order = 5;
        else if (str == "AM" || str == "am" || str == "Am")
          order = 1;
        else
          order = atoi(str.c_str());

        mol.AddBond(start,end,order);
      }

 
    // update neighbour bonds information for each atom.
    vector<OBAtom*>::iterator apos;
    vector<OBBond*>::iterator bpos;
    OBAtom* patom;
    OBBond* pbond;
    
    for (patom = mol.BeginAtom(apos); patom; patom = mol.NextAtom(apos))
      {
        patom->ClearBond();
        for (pbond = mol.BeginBond(bpos); pbond; pbond = mol.NextBond(bpos))
          {
            if (patom == pbond->GetBeginAtom() || patom == pbond->GetEndAtom())
              {
                patom->AddBond(pbond);
              }
          }
      }

    // Suggestion by Liu Zhiguo 2008-01-26
    // Mol2 files define atom types -- there is no need to re-perceive
    mol.SetAtomTypesPerceived();
    mol.EndModify();

    //must add generic data after end modify - otherwise it will be blown away
    if (comment)
      {
        OBCommentData *cd = new OBCommentData;
        cd->SetData(comment);
        cd->SetOrigin(fileformatInput);
        mol.SetData(cd);
        delete [] comment;
        comment = NULL;
      }
    if (hasPartialCharges)
      mol.SetPartialChargesPerceived();

    // continue untill EOF or untill next molecule record
    streampos pos;
    for(;;)
      {
        pos = ifs.tellg();
        if (!ifs.getline(buffer,BUFF_SIZE))
          break;
        if (EQn(buffer,"@<TRIPOS>MOLECULE",17))
          break;
      }

    ifs.seekg(pos); // go back to the end of the molecule
    return(true);
  }
Example #9
0
  OBAPI double VectorAngleDerivative(const Eigen::Vector3d &a, const Eigen::Vector3d &b, const Eigen::Vector3d &c,
      Eigen::Vector3d &Fa, Eigen::Vector3d &Fb, Eigen::Vector3d &Fc)
  {
    // This is adapted from http://scidok.sulb.uni-saarland.de/volltexte/2007/1325/pdf/Dissertation_1544_Moll_Andr_2007.pdf
    // Many thanks to Andreas Moll and the BALLView developers for this

    Eigen::Vector3d v1, v2;

    // Calculate the vector between atom1 and atom2,
    // test if the vector has length larger than 0 and normalize it
    v1 = a - b;
    v2 = c - b;

    const double length1 = v1.norm();
    const double length2 = v2.norm();

    // test if the vector has length larger than 0 and normalize it
    if (IsNearZero(length1) || IsNearZero(length2)) {
      Fa = VZero;
      Fb = VZero;
      Fc = VZero;
      return 0.0;
    }

    // Calculate the normalized bond vectors
    const double inverse_length_v1 = 1.0 / length1;
    const double inverse_length_v2 = 1.0 / length2;
    v1 *= inverse_length_v1 ;
    v2 *= inverse_length_v2;

    // Calculate the cross product of v1 and v2, test if it has length unequal 0,
    // and normalize it.
    Eigen::Vector3d c1 = v1.cross(v2);
    const double length = c1.norm();
    if (IsNearZero(length)) {
      Fa = VZero;
      Fb = VZero;
      Fc = VZero;
      return 0.0;
    }

    c1 /= length;

    // Calculate the cos of theta and then theta
    double costheta = v1.dot(v2);
    double theta;
    if (costheta > 1.0) {
      theta = 0.0;
      costheta = 1.0;
    } else if (costheta < -1.0) {
      theta = 180.0;
      costheta = -1.0;
    } else {
      #ifdef USE_ACOS_LOOKUP_TABLE
      theta = RAD_TO_DEG * acosLookup(costheta);
      #else
      theta = RAD_TO_DEG * acos(costheta);
      #endif
    }

    Eigen::Vector3d t1 = v1.cross(c1);
    t1.normalize();
    Eigen::Vector3d t2 = v2.cross(c1);
    t2.normalize();

    Fa = -t1 * inverse_length_v1;
    Fc =  t2 * inverse_length_v2;
    Fb = - (Fa + Fc);

    return theta;
  }
Example #10
0
  OBAPI double VectorOOPDerivative(const Eigen::Vector3d &a, const Eigen::Vector3d &b, const Eigen::Vector3d &c, 
      const Eigen::Vector3d &d, Eigen::Vector3d &Fa, Eigen::Vector3d &Fb, Eigen::Vector3d &Fc, Eigen::Vector3d &Fd)
  {
    // This is adapted from http://scidok.sulb.uni-saarland.de/volltexte/2007/1325/pdf/Dissertation_1544_Moll_Andr_2007.pdf
    // Many thanks to Andreas Moll and the BALLView developers for this

    // temp variables:
    double length;
    Eigen::Vector3d delta;

    // calculate normalized bond vectors from central atom to outer atoms:
    delta = a - b;
    length = delta.norm();
    if (IsNearZero(length)) {
      Fa = VZero;
      Fb = VZero;
      Fc = VZero;
      Fd = VZero;
      return 0.0;
    }
    // normalize the bond vector:
    delta /= length;
    // store the normalized bond vector from central atom to outer atoms:
    const Eigen::Vector3d ab = delta;
    // store length of this bond:
    const double length_ab = length;
		
    delta = c - b;
    length = delta.norm();
    if (IsNearZero(length)) {
      Fa = VZero;
      Fb = VZero;
      Fc = VZero;
      Fd = VZero;
      return 0.0;
    }
    // normalize the bond vector:
    delta /= length;
    // store the normalized bond vector from central atom to outer atoms:
    const Eigen::Vector3d bc = delta;
    // store length of this bond:
    const double length_bc = length;
	
    delta = d - b;
    length = delta.norm();
    if (IsNearZero(length)) {
      Fa = VZero;
      Fb = VZero;
      Fc = VZero;
      Fd = VZero;
      return 0.0;
    }
    // normalize the bond vector:
    delta /= length;
    // store the normalized bond vector from central atom to outer atoms:
    const Eigen::Vector3d bd = delta;
    // store length of this bond:
    const double length_bd = length;
	
    // the normal vectors of the three planes:
    const Eigen::Vector3d an = ab.cross(bc);
    const Eigen::Vector3d bn = bc.cross(bd);
    const Eigen::Vector3d cn = bd.cross(ab);

    // Bond angle ab to bc
    const double cos_theta = ab.dot(bc);
    #ifdef USE_ACOS_LOOKUP_TABLE
    const double theta = acosLookup(cos_theta);
    #else
    const double theta = acos(cos_theta);
    #endif
    // If theta equals 180 degree or 0 degree
    if (IsNearZero(theta) || IsNearZero(fabs(theta - M_PI))) {
      Fa = VZero;
      Fb = VZero;
      Fc = VZero;
      Fd = VZero;
      return 0.0;
    }
				
    const double sin_theta = sin(theta);
    const double sin_dl = an.dot(bd) / sin_theta;

    // the wilson angle:
    const double dl = asin(sin_dl);

    // In case: wilson angle equals 0 or 180 degree: do nothing
    if (IsNearZero(dl) || IsNearZero(fabs(dl - M_PI))) {
      Fa = VZero;
      Fb = VZero;
      Fc = VZero;
      Fd = VZero;
      return RAD_TO_DEG * dl;
    }
				
    const double cos_dl = cos(dl);

    // if wilson angle equal 90 degree: abort
    if (cos_dl < 0.0001) {
      Fa = VZero;
      Fb = VZero;
      Fc = VZero;
      Fd = VZero;
      return RAD_TO_DEG * dl;
    }

    Fd = (an / sin_theta - bd * sin_dl) / length_bd;
    Fa = ((bn + (((-ab + bc * cos_theta) * sin_dl) / sin_theta)) / length_ab) / sin_theta;
    Fc = ((cn + (((-bc + ab * cos_theta) * sin_dl) / sin_theta)) / length_bc) / sin_theta;
    Fb = -(Fa + Fc + Fd);
    
    return RAD_TO_DEG * dl;
  }
Example #11
0
  OBAPI double VectorTorsionDerivative(const Eigen::Vector3d &a, const Eigen::Vector3d &b, const Eigen::Vector3d &c,
      const Eigen::Vector3d &d, Eigen::Vector3d &Fa, Eigen::Vector3d &Fb, Eigen::Vector3d &Fc, Eigen::Vector3d &Fd) 
  {
    // This is adapted from http://scidok.sulb.uni-saarland.de/volltexte/2007/1325/pdf/Dissertation_1544_Moll_Andr_2007.pdf
    // Many thanks to Andreas Moll and the BALLView developers for this
    
    // angle between abc and bcd:
    double angle_abc, angle_bcd;
    
    // Bond vectors of the three atoms
    Eigen::Vector3d ab = b - a;
    Eigen::Vector3d bc = c - b;
    Eigen::Vector3d cd = d - c;
    
    // length of the three bonds
    const double l_ab = ab.norm();
    const double l_bc = bc.norm();
    const double l_cd = cd.norm();
    
    if (IsNearZero(l_ab) || IsNearZero(l_bc) || IsNearZero(l_cd) ) {
      Fa = VZero;
      Fb = VZero;
      Fc = VZero;
      Fd = VZero;
      return 0.0;
    }
    
    angle_abc = DEG_TO_RAD * VectorAngle(ab, bc);
    angle_bcd = DEG_TO_RAD * VectorAngle(bc, cd);
    
    // normalize the bond vectors:
    ab /= l_ab;
    bc /= l_bc;
    cd /= l_cd;

    const double sin_j = sin(angle_abc);
    const double sin_k = sin(angle_bcd);

    const double rsj = l_ab * sin_j;
    const double rsk = l_cd * sin_k;

    const double rs2j = 1. / (rsj * sin_j);
    const double rs2k = 1. / (rsk * sin_k);
  
    const double rrj = l_ab / l_bc;
    const double rrk = l_cd / l_bc;

    const double rrcj = rrj * (-cos(angle_abc));
    const double rrck = rrk * (-cos(angle_bcd));
    
    const Eigen::Vector3d ca = ab.cross(bc);
    const Eigen::Vector3d cb = bc.cross(cd);
    const Eigen::Vector3d cc = ca.cross(cb);
    double d1 = cc.dot(bc);
    double d2 = ca.dot(cb);
    double tor = RAD_TO_DEG * atan2(d1, d2);

    Fa = -ca * rs2j;
    Fd = cb * rs2k;

    Fb = Fa * (rrcj - 1.) - Fd * rrck;
    Fc = -(Fa + Fb + Fd);
    
    return tor;  
  }
Example #12
0
 constexpr bool IsRotated() const {
   return !IsNearZero(y_rotation) || !IsNearZero(x_rotation);
 }