double AngleConstraintContrib::getEnergy(double *pos) const { PRECONDITION(dp_forceField, "no owner"); PRECONDITION(pos, "bad vector"); double dist1 = dp_forceField->distance(d_at1Idx, d_at2Idx, pos); double dist2 = dp_forceField->distance(d_at2Idx, d_at3Idx, pos); RDGeom::Point3D p1(pos[3 * d_at1Idx], pos[3 * d_at1Idx + 1], pos[3 * d_at1Idx + 2]); RDGeom::Point3D p2(pos[3 * d_at2Idx], pos[3 * d_at2Idx + 1], pos[3 * d_at2Idx + 2]); RDGeom::Point3D p3(pos[3 * d_at3Idx], pos[3 * d_at3Idx + 1], pos[3 * d_at3Idx + 2]); RDGeom::Point3D p12 = (p1 - p2) / dist1; RDGeom::Point3D p32 = (p3 - p2) / dist2; double cosTheta = p12.dotProduct(p32); clipToOne(cosTheta); double angle = RAD2DEG * acos(cosTheta); double angleTerm = 0.0; if (angle < d_minAngleDeg) { angleTerm = angle - d_minAngleDeg; } else if (angle > d_maxAngleDeg) { angleTerm = angle - d_maxAngleDeg; } double const c = 0.5 * DEG2RAD * DEG2RAD; double res = c * d_forceConstant * angleTerm * angleTerm; return res; }
void TorsionAngleContrib::getGrad(double *pos, double *grad) const { PRECONDITION(dp_forceField, "no owner"); PRECONDITION(pos, "bad vector"); PRECONDITION(grad, "bad vector"); RDGeom::Point3D iPoint(pos[3 * d_at1Idx], pos[3 * d_at1Idx + 1], pos[3 * d_at1Idx + 2]); RDGeom::Point3D jPoint(pos[3 * d_at2Idx], pos[3 * d_at2Idx + 1], pos[3 * d_at2Idx + 2]); RDGeom::Point3D kPoint(pos[3 * d_at3Idx], pos[3 * d_at3Idx + 1], pos[3 * d_at3Idx + 2]); RDGeom::Point3D lPoint(pos[3 * d_at4Idx], pos[3 * d_at4Idx + 1], pos[3 * d_at4Idx + 2]); double *g[4] = {&(grad[3 * d_at1Idx]), &(grad[3 * d_at2Idx]), &(grad[3 * d_at3Idx]), &(grad[3 * d_at4Idx])}; RDGeom::Point3D r[4] = {iPoint - jPoint, kPoint - jPoint, jPoint - kPoint, lPoint - kPoint}; RDGeom::Point3D t[2] = {r[0].crossProduct(r[1]), r[2].crossProduct(r[3])}; double d[2] = {t[0].length(), t[1].length()}; if (isDoubleZero(d[0]) || isDoubleZero(d[1])) { return; } t[0] /= d[0]; t[1] /= d[1]; double cosPhi = t[0].dotProduct(t[1]); clipToOne(cosPhi); double sinPhiSq = 1.0 - cosPhi * cosPhi; double sinPhi = ((sinPhiSq > 0.0) ? sqrt(sinPhiSq) : 0.0); double sin2Phi = 2.0 * sinPhi * cosPhi; double sin3Phi = 3.0 * sinPhi - 4.0 * sinPhi * sinPhiSq; // dE/dPhi is independent of cartesians: double dE_dPhi = 0.5 * (-(d_V1)*sinPhi + 2.0 * d_V2 * sin2Phi - 3.0 * d_V3 * sin3Phi); #if 0 if(dE_dPhi!=dE_dPhi){ std::cout << "\tNaN in Torsion("<<d_at1Idx<<","<<d_at2Idx<<","<<d_at3Idx<<","<<d_at4Idx<<")"<< std::endl; std::cout << "sin: " << sinPhi << std::endl; std::cout << "cos: " << cosPhi << std::endl; } #endif // FIX: use a tolerance here // this is hacky, but it's per the // recommendation from Niketic and Rasmussen: double sinTerm = -dE_dPhi * (isDoubleZero(sinPhi) ? (1.0 / cosPhi) : (1.0 / sinPhi)); Utils::calcTorsionGrad(r, t, d, g, sinTerm, cosPhi); }
double calcTorsionCosPhi(const RDGeom::Point3D &iPoint, const RDGeom::Point3D &jPoint, const RDGeom::Point3D &kPoint, const RDGeom::Point3D &lPoint) { RDGeom::Point3D r1 = iPoint - jPoint; RDGeom::Point3D r2 = kPoint - jPoint; RDGeom::Point3D r3 = jPoint - kPoint; RDGeom::Point3D r4 = lPoint - kPoint; RDGeom::Point3D t1 = r1.crossProduct(r2); RDGeom::Point3D t2 = r3.crossProduct(r4); double cosPhi = t1.dotProduct(t2) / (t1.length() * t2.length()); clipToOne(cosPhi); return cosPhi; }
void AngleConstraintContrib::getGrad(double *pos, double *grad) const { PRECONDITION(dp_forceField,"no owner"); PRECONDITION(pos,"bad vector"); PRECONDITION(grad,"bad vector"); double dist[2] = { dp_forceField->distance(d_at1Idx, d_at2Idx, pos), dp_forceField->distance(d_at2Idx, d_at3Idx, pos) }; RDGeom::Point3D p1(pos[3 * d_at1Idx], pos[3 * d_at1Idx + 1], pos[3 * d_at1Idx + 2]); RDGeom::Point3D p2(pos[3 * d_at2Idx], pos[3 * d_at2Idx + 1], pos[3 * d_at2Idx + 2]); RDGeom::Point3D p3(pos[3 * d_at3Idx], pos[3 * d_at3Idx + 1], pos[3 * d_at3Idx + 2]); double *g[3] = { &(grad[3 * d_at1Idx]), &(grad[3 * d_at2Idx]), &(grad[3 * d_at3Idx]) }; RDGeom::Point3D r[2] = { (p1 - p2) / dist[0], (p3 - p2) / dist[1] }; double cosTheta = r[0].dotProduct(r[1]); clipToOne(cosTheta); double sinThetaSq = 1.0 - cosTheta * cosTheta; double sinTheta = std::max(((sinThetaSq > 0.0) ? sqrt(sinThetaSq) : 0.0), 1.0e-8); // use the chain rule: // dE/dx = dE/dTheta * dTheta/dx // dE/dTheta is independent of cartesians: double angle = RAD2DEG * acos(cosTheta); double angleTerm = 0.0; if (angle < d_minAngleDeg) { angleTerm = angle - d_minAngleDeg; } else if (angle > d_maxAngleDeg) { angleTerm = angle - d_maxAngleDeg; } double dE_dTheta = DEG2RAD * d_forceConstant * angleTerm; Utils::calcAngleBendGrad(r, dist, g, dE_dTheta, cosTheta, sinTheta); }
double calcOopChi(const RDGeom::Point3D &iPoint, const RDGeom::Point3D &jPoint, const RDGeom::Point3D &kPoint, const RDGeom::Point3D &lPoint) { RDGeom::Point3D rJI = iPoint - jPoint; RDGeom::Point3D rJK = kPoint - jPoint; RDGeom::Point3D rJL = lPoint - jPoint; rJI /= rJI.length(); rJK /= rJK.length(); rJL /= rJL.length(); RDGeom::Point3D n = rJI.crossProduct(rJK); n /= n.length(); double sinChi = n.dotProduct(rJL); clipToOne(sinChi); return RAD2DEG * asin(sinChi); }
AngleConstraintContrib::AngleConstraintContrib(ForceField *owner, unsigned int idx1, unsigned int idx2, unsigned int idx3, bool relative, double minAngleDeg, double maxAngleDeg, double forceConst) { PRECONDITION(owner,"bad owner"); const RDGeom::PointPtrVect &pos = owner->positions(); RANGE_CHECK(0, idx1, pos.size() - 1); RANGE_CHECK(0, idx2, pos.size() - 1); RANGE_CHECK(0, idx3, pos.size() - 1); PRECONDITION(maxAngleDeg >= minAngleDeg, "allowedDeltaDeg must be >= 0.0"); double angle = 0.0; if (relative) { RDGeom::Point3D p1 = *((RDGeom::Point3D *)pos[idx1]); RDGeom::Point3D p2 = *((RDGeom::Point3D *)pos[idx2]); RDGeom::Point3D p3 = *((RDGeom::Point3D *)pos[idx3]); double dist1 = (p1 - p2).length(); double dist2 = (p3 - p2).length(); RDGeom::Point3D p12 = (p1 - p2) / dist1; RDGeom::Point3D p32 = (p3 - p2) / dist2; double cosTheta = p12.dotProduct(p32); clipToOne(cosTheta); angle = RAD2DEG * acos(cosTheta); } dp_forceField = owner; d_at1Idx = idx1; d_at2Idx = idx2; d_at3Idx = idx3; minAngleDeg += angle; maxAngleDeg += angle; _pretreatAngles(minAngleDeg, maxAngleDeg); d_minAngleDeg = minAngleDeg; d_maxAngleDeg = maxAngleDeg; d_forceConstant = forceConst; }
void OopBendContrib::getGrad(double *pos, double *grad) const { PRECONDITION(dp_forceField, "no owner"); PRECONDITION(pos, "bad vector"); PRECONDITION(grad, "bad vector"); RDGeom::Point3D iPoint(pos[3 * d_at1Idx], pos[3 * d_at1Idx + 1], pos[3 * d_at1Idx + 2]); RDGeom::Point3D jPoint(pos[3 * d_at2Idx], pos[3 * d_at2Idx + 1], pos[3 * d_at2Idx + 2]); RDGeom::Point3D kPoint(pos[3 * d_at3Idx], pos[3 * d_at3Idx + 1], pos[3 * d_at3Idx + 2]); RDGeom::Point3D lPoint(pos[3 * d_at4Idx], pos[3 * d_at4Idx + 1], pos[3 * d_at4Idx + 2]); double *g1 = &(grad[3 * d_at1Idx]); double *g2 = &(grad[3 * d_at2Idx]); double *g3 = &(grad[3 * d_at3Idx]); double *g4 = &(grad[3 * d_at4Idx]); RDGeom::Point3D rJI = iPoint - jPoint; RDGeom::Point3D rJK = kPoint - jPoint; RDGeom::Point3D rJL = lPoint - jPoint; double dJI = rJI.length(); double dJK = rJK.length(); double dJL = rJL.length(); if (isDoubleZero(dJI) || isDoubleZero(dJK) || isDoubleZero(dJL)) { return; } rJI /= dJI; rJK /= dJK; rJL /= dJL; RDGeom::Point3D n = (-rJI).crossProduct(rJK); n /= n.length(); double const c2 = MDYNE_A_TO_KCAL_MOL * DEG2RAD * DEG2RAD; double sinChi = rJL.dotProduct(n); clipToOne(sinChi); double cosChiSq = 1.0 - sinChi * sinChi; double cosChi = std::max(((cosChiSq > 0.0) ? sqrt(cosChiSq) : 0.0), 1.0e-8); double chi = RAD2DEG * asin(sinChi); double cosTheta = rJI.dotProduct(rJK); clipToOne(cosTheta); double sinThetaSq = std::max(1.0 - cosTheta * cosTheta, 1.0e-8); double sinTheta = std::max(((sinThetaSq > 0.0) ? sqrt(sinThetaSq) : 0.0), 1.0e-8); double dE_dChi = RAD2DEG * c2 * d_koop * chi; RDGeom::Point3D t1 = rJL.crossProduct(rJK); RDGeom::Point3D t2 = rJI.crossProduct(rJL); RDGeom::Point3D t3 = rJK.crossProduct(rJI); double term1 = cosChi * sinTheta; double term2 = sinChi / (cosChi * sinThetaSq); double tg1[3] = {(t1.x / term1 - (rJI.x - rJK.x * cosTheta) * term2) / dJI, (t1.y / term1 - (rJI.y - rJK.y * cosTheta) * term2) / dJI, (t1.z / term1 - (rJI.z - rJK.z * cosTheta) * term2) / dJI}; double tg3[3] = {(t2.x / term1 - (rJK.x - rJI.x * cosTheta) * term2) / dJK, (t2.y / term1 - (rJK.y - rJI.y * cosTheta) * term2) / dJK, (t2.z / term1 - (rJK.z - rJI.z * cosTheta) * term2) / dJK}; double tg4[3] = {(t3.x / term1 - rJL.x * sinChi / cosChi) / dJL, (t3.y / term1 - rJL.y * sinChi / cosChi) / dJL, (t3.z / term1 - rJL.z * sinChi / cosChi) / dJL}; for (unsigned int i = 0; i < 3; ++i) { g1[i] += dE_dChi * tg1[i]; g2[i] += -dE_dChi * (tg1[i] + tg3[i] + tg4[i]); g3[i] += dE_dChi * tg3[i]; g4[i] += dE_dChi * tg4[i]; } }
void StretchBendContrib::getGrad(double *pos, double *grad) const { PRECONDITION(dp_forceField, "no owner"); PRECONDITION(pos, "bad vector"); PRECONDITION(grad, "bad vector"); double dist1 = dp_forceField->distance(d_at1Idx, d_at2Idx, pos); double dist2 = dp_forceField->distance(d_at2Idx, d_at3Idx, pos); RDGeom::Point3D p1(pos[3 * d_at1Idx], pos[3 * d_at1Idx + 1], pos[3 * d_at1Idx + 2]); RDGeom::Point3D p2(pos[3 * d_at2Idx], pos[3 * d_at2Idx + 1], pos[3 * d_at2Idx + 2]); RDGeom::Point3D p3(pos[3 * d_at3Idx], pos[3 * d_at3Idx + 1], pos[3 * d_at3Idx + 2]); double *g1 = &(grad[3 * d_at1Idx]); double *g2 = &(grad[3 * d_at2Idx]); double *g3 = &(grad[3 * d_at3Idx]); RDGeom::Point3D p12 = (p1 - p2) / dist1; RDGeom::Point3D p32 = (p3 - p2) / dist2; double const c5 = MDYNE_A_TO_KCAL_MOL * DEG2RAD; double cosTheta = p12.dotProduct(p32); clipToOne(cosTheta); double sinThetaSq = 1.0 - cosTheta * cosTheta; double sinTheta = std::max(((sinThetaSq > 0.0) ? sqrt(sinThetaSq) : 0.0), 1.0e-8); double angleTerm = RAD2DEG * acos(cosTheta) - d_theta0; double distTerm = RAD2DEG * (d_forceConstants.first * (dist1 - d_restLen1) + d_forceConstants.second * (dist2 - d_restLen2)); double dCos_dS1 = 1.0 / dist1 * (p32.x - cosTheta * p12.x); double dCos_dS2 = 1.0 / dist1 * (p32.y - cosTheta * p12.y); double dCos_dS3 = 1.0 / dist1 * (p32.z - cosTheta * p12.z); double dCos_dS4 = 1.0 / dist2 * (p12.x - cosTheta * p32.x); double dCos_dS5 = 1.0 / dist2 * (p12.y - cosTheta * p32.y); double dCos_dS6 = 1.0 / dist2 * (p12.z - cosTheta * p32.z); g1[0] += c5 * (p12.x * d_forceConstants.first * angleTerm + dCos_dS1 / (-sinTheta) * distTerm); g1[1] += c5 * (p12.y * d_forceConstants.first * angleTerm + dCos_dS2 / (-sinTheta) * distTerm); g1[2] += c5 * (p12.z * d_forceConstants.first * angleTerm + dCos_dS3 / (-sinTheta) * distTerm); g2[0] += c5 * ((-p12.x * d_forceConstants.first - p32.x * d_forceConstants.second) * angleTerm + (-dCos_dS1 - dCos_dS4) / (-sinTheta) * distTerm); g2[1] += c5 * ((-p12.y * d_forceConstants.first - p32.y * d_forceConstants.second) * angleTerm + (-dCos_dS2 - dCos_dS5) / (-sinTheta) * distTerm); g2[2] += c5 * ((-p12.z * d_forceConstants.first - p32.z * d_forceConstants.second) * angleTerm + (-dCos_dS3 - dCos_dS6) / (-sinTheta) * distTerm); g3[0] += c5 * (p32.x * d_forceConstants.second * angleTerm + dCos_dS4 / (-sinTheta) * distTerm); g3[1] += c5 * (p32.y * d_forceConstants.second * angleTerm + dCos_dS5 / (-sinTheta) * distTerm); g3[2] += c5 * (p32.z * d_forceConstants.second * angleTerm + dCos_dS6 / (-sinTheta) * distTerm); }
void TorsionConstraintContrib::getGrad(double *pos, double *grad) const { PRECONDITION(dp_forceField,"no owner"); PRECONDITION(pos,"bad vector"); PRECONDITION(grad,"bad vector"); RDGeom::Point3D p1(pos[3 * d_at1Idx], pos[3 * d_at1Idx + 1], pos[3 * d_at1Idx + 2]); RDGeom::Point3D p2(pos[3 * d_at2Idx], pos[3 * d_at2Idx + 1], pos[3 * d_at2Idx + 2]); RDGeom::Point3D p3(pos[3 * d_at3Idx], pos[3 * d_at3Idx + 1], pos[3 * d_at3Idx + 2]); RDGeom::Point3D p4(pos[3 * d_at4Idx], pos[3 * d_at4Idx + 1], pos[3 * d_at4Idx + 2]); double *g[4] = { &(grad[3 * d_at1Idx]), &(grad[3 * d_at2Idx]), &(grad[3 * d_at3Idx]), &(grad[3 * d_at4Idx]) }; RDGeom::Point3D r[4] = { p1 - p2, p3 - p2, p2 - p3, p4 - p3 }; RDGeom::Point3D t[2] = { r[0].crossProduct(r[1]), r[2].crossProduct(r[3]) }; double d[2] = { t[0].length(), t[1].length() }; if (isDoubleZero(d[0]) || isDoubleZero(d[1])) { return; } t[0] /= d[0]; t[1] /= d[1]; double cosPhi = t[0].dotProduct(t[1]); clipToOne(cosPhi); double sinPhiSq = 1.0 - cosPhi * cosPhi; double sinPhi = ((sinPhiSq > 0.0) ? sqrt(sinPhiSq) : 0.0); // dE/dPhi is independent of cartesians: RDGeom::Point3D n123 = (-r[0]).crossProduct(r[1]); double n123SqLength = n123.lengthSq(); RDGeom::Point3D n234 = r[1].crossProduct(r[3]); double n234SqLength = n234.lengthSq(); RDGeom::Point3D m = n123.crossProduct(r[1]); // we want a signed dihedral, that's why we use atan2 instead of acos double dihedral = RAD2DEG * (-atan2(m.dotProduct(n234) / sqrt(n234SqLength * m.lengthSq()), n123.dotProduct(n234) / sqrt(n123SqLength * n234SqLength))); if (dihedral < 0.0) dihedral += 360.0; //double dihedral = RAD2DEG * acos(cosPhi); double dihedralTerm = 0.0; if (dihedral < d_minDihedralDeg) { dihedralTerm = dihedral - d_minDihedralDeg; } else if (dihedral > d_maxDihedralDeg) { dihedralTerm = dihedral - d_maxDihedralDeg; } if (dihedral > 180.0) dihedralTerm = -dihedralTerm; double dE_dPhi = DEG2RAD * d_forceConstant * dihedralTerm; // FIX: use a tolerance here // this is hacky, but it's per the // recommendation from Niketic and Rasmussen: double sinTerm = -dE_dPhi * (isDoubleZero(sinPhi) ? (1.0 / cosPhi) : (1.0 / sinPhi)); Utils::calcTorsionGrad(r, t, d, g, sinTerm, cosPhi); }
void InversionContrib::getGrad(double *pos, double *grad) const { PRECONDITION(dp_forceField, "no owner"); PRECONDITION(pos, "bad vector"); PRECONDITION(grad, "bad vector"); RDGeom::Point3D p1(pos[3 * d_at1Idx], pos[3 * d_at1Idx + 1], pos[3 * d_at1Idx + 2]); RDGeom::Point3D p2(pos[3 * d_at2Idx], pos[3 * d_at2Idx + 1], pos[3 * d_at2Idx + 2]); RDGeom::Point3D p3(pos[3 * d_at3Idx], pos[3 * d_at3Idx + 1], pos[3 * d_at3Idx + 2]); RDGeom::Point3D p4(pos[3 * d_at4Idx], pos[3 * d_at4Idx + 1], pos[3 * d_at4Idx + 2]); double *g1 = &(grad[3 * d_at1Idx]); double *g2 = &(grad[3 * d_at2Idx]); double *g3 = &(grad[3 * d_at3Idx]); double *g4 = &(grad[3 * d_at4Idx]); RDGeom::Point3D rJI = p1 - p2; RDGeom::Point3D rJK = p3 - p2; RDGeom::Point3D rJL = p4 - p2; double dJI = rJI.length(); double dJK = rJK.length(); double dJL = rJL.length(); if (isDoubleZero(dJI) || isDoubleZero(dJK) || isDoubleZero(dJL)) { return; } rJI /= dJI; rJK /= dJK; rJL /= dJL; RDGeom::Point3D n = (-rJI).crossProduct(rJK); n /= n.length(); double cosY = n.dotProduct(rJL); clipToOne(cosY); double sinYSq = 1.0 - cosY * cosY; double sinY = std::max(((sinYSq > 0.0) ? sqrt(sinYSq) : 0.0), 1.0e-8); double cosTheta = rJI.dotProduct(rJK); clipToOne(cosTheta); double sinThetaSq = std::max(1.0 - cosTheta * cosTheta, 1.0e-8); double sinTheta = std::max(((sinThetaSq > 0.0) ? sqrt(sinThetaSq) : 0.0), 1.0e-8); // sin(2 * W) = 2 * sin(W) * cos(W) = 2 * cos(Y) * sin(Y) double dE_dW = -d_forceConstant * (d_C1 * cosY - 4.0 * d_C2 * cosY * sinY); RDGeom::Point3D t1 = rJL.crossProduct(rJK); RDGeom::Point3D t2 = rJI.crossProduct(rJL); RDGeom::Point3D t3 = rJK.crossProduct(rJI); double term1 = sinY * sinTheta; double term2 = cosY / (sinY * sinThetaSq); double tg1[3] = { (t1.x / term1 - (rJI.x - rJK.x * cosTheta) * term2) / dJI, (t1.y / term1 - (rJI.y - rJK.y * cosTheta) * term2) / dJI, (t1.z / term1 - (rJI.z - rJK.z * cosTheta) * term2) / dJI }; double tg3[3] = { (t2.x / term1 - (rJK.x - rJI.x * cosTheta) * term2) / dJK, (t2.y / term1 - (rJK.y - rJI.y * cosTheta) * term2) / dJK, (t2.z / term1 - (rJK.z - rJI.z * cosTheta) * term2) / dJK }; double tg4[3] = { (t3.x / term1 - rJL.x * cosY / sinY) / dJL, (t3.y / term1 - rJL.y * cosY / sinY) / dJL, (t3.z / term1 - rJL.z * cosY / sinY) / dJL }; for (unsigned int i = 0; i < 3; ++i) { g1[i] += dE_dW * tg1[i]; g2[i] += -dE_dW * (tg1[i] + tg3[i] + tg4[i]); g3[i] += dE_dW * tg3[i]; g4[i] += dE_dW * tg4[i]; } }