void AngleBendContrib::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]); double sinThetaSq = 1.0 - cosTheta * cosTheta; double sinTheta = std::max(((sinThetaSq > 0.0) ? sqrt(sinThetaSq) : 0.0), 1.0e-8); //std::cerr << "GRAD: " << cosTheta << " (" << acos(cosTheta)<< "), "; //std::cerr << sinTheta << " (" << asin(sinTheta)<< ")" << std::endl; // use the chain rule: // dE/dx = dE/dTheta * dTheta/dx // dE/dTheta is independent of cartesians: double dE_dTheta=getThetaDeriv(cosTheta,sinTheta); Utils::calcAngleBendGrad(r, dist, g, dE_dTheta, cosTheta, sinTheta); }
void AngleBendContrib::getGrad(double *pos,double *grad) const { PRECONDITION(dp_forceField,"no owner"); PRECONDITION(pos,"bad vector"); PRECONDITION(grad,"bad vector"); double dist1=this->dp_forceField->distance(this->d_at1Idx,this->d_at2Idx,pos); double dist2=this->dp_forceField->distance(this->d_at2Idx,this->d_at3Idx,pos); //std::cout << "\tAngle("<<this->d_at1Idx<<","<<this->d_at2Idx<<","<<this->d_at3Idx<<") " << dist1 << " " << dist2 << std::endl; RDGeom::Point3D p1(pos[3*this->d_at1Idx], pos[3*this->d_at1Idx+1], pos[3*this->d_at1Idx+2]); RDGeom::Point3D p2(pos[3*this->d_at2Idx], pos[3*this->d_at2Idx+1], pos[3*this->d_at2Idx+2]); RDGeom::Point3D p3(pos[3*this->d_at3Idx], pos[3*this->d_at3Idx+1], pos[3*this->d_at3Idx+2]); double *g1=&(grad[3*this->d_at1Idx]); double *g2=&(grad[3*this->d_at2Idx]); double *g3=&(grad[3*this->d_at3Idx]); RDGeom::Point3D p12=p1-p2; RDGeom::Point3D p32=p3-p2; double cosTheta = p12.dotProduct(p32)/(dist1*dist2); double sinTheta = std::max(sqrt(1.0-cosTheta*cosTheta),1e-8); //std::cerr << "GRAD: " << cosTheta << " (" << acos(cosTheta)<< "), "; //std::cerr << sinTheta << " (" << asin(sinTheta)<< ")" << std::endl; // use the chain rule: // dE/dx = dE/dTheta * dTheta/dx // dE/dTheta is independent of cartesians: double dE_dTheta=getThetaDeriv(cosTheta,sinTheta); // ------- // dTheta/dx is trickier: double dCos_dS1=1./dist1 * (p32.x/dist2 - cosTheta*p12.x/dist1); double dCos_dS2=1./dist1 * (p32.y/dist2 - cosTheta*p12.y/dist1); double dCos_dS3=1./dist1 * (p32.z/dist2 - cosTheta*p12.z/dist1); double dCos_dS4=1./dist2 * (p12.x/dist1 - cosTheta*p32.x/dist2); double dCos_dS5=1./dist2 * (p12.y/dist1 - cosTheta*p32.y/dist2); double dCos_dS6=1./dist2 * (p12.z/dist1 - cosTheta*p32.z/dist2); g1[0] += dE_dTheta*dCos_dS1/(-sinTheta); g1[1] += dE_dTheta*dCos_dS2/(-sinTheta); g1[2] += dE_dTheta*dCos_dS3/(-sinTheta); g2[0] += dE_dTheta*(-dCos_dS1 - dCos_dS4)/(-sinTheta); g2[1] += dE_dTheta*(-dCos_dS2 - dCos_dS5)/(-sinTheta); g2[2] += dE_dTheta*(-dCos_dS3 - dCos_dS6)/(-sinTheta); g3[0] += dE_dTheta*dCos_dS4/(-sinTheta); g3[1] += dE_dTheta*dCos_dS5/(-sinTheta); g3[2] += dE_dTheta*dCos_dS6/(-sinTheta); }