pele
Python energy landscape explorer
/home/js850/projects/pele/source/rotations.cpp
00001 #include "pele/rotations.h"
00002 #include "pele/vecn.h"
00003 
00004 namespace pele{
00005 
00006 
00010 MatrixNM<3,3> aa_to_rot_mat(pele::VecN<3> const & p)
00011 {
00012 
00013     double theta2 = pele::dot<3>(p,p);
00014     MatrixNM<3,3> rm;
00015     if (theta2 < 1e-12) {
00016         MatrixNM<3,3> temp;
00017         rot_mat_derivatives_small_theta(p, rm, temp, temp, temp, false);
00018         return rm;
00019     }
00020     // Execute for the general case, where THETA dos not equal zero
00021     // Find values of THETA, CT, ST and THETA3
00022     double theta   = std::sqrt(theta2);
00023     double ct      = std::cos(theta);
00024     double st      = std::sin(theta);
00025 
00026     // Set THETA to 1/THETA purely for convenience
00027     theta   = 1./theta;
00028 
00029     // Normalise p and construct the skew-symmetric matrix E
00030     // ESQ is calculated as the square of E
00031     pele::VecN<3> pn = p;
00032     pn*= theta;
00033     MatrixNM<3,3> e(0);
00034     e(0,1)  = -pn[2];
00035     e(0,2)  =  pn[1];
00036     e(1,2)  = -pn[0];
00037     e(1,0)  = -e(0,1);
00038     e(2,0)  = -e(0,2);
00039     e(2,1)  = -e(1,2);
00040     auto esq     = pele::dot<3,3,3>(e, e);
00041 
00042     // RM is calculated from Rodrigues' rotation formula [equation [1]
00043     // in the paper]
00044     // rm  = np.eye(3) + [1. - ct] * esq + st * e
00045     rm.assign(0);
00046     for (size_t i = 0; i < 3; ++i) rm(i,i) = 1; // identiy matrix
00047     for (size_t i = 0; i < 3; ++i) {
00048         for (size_t j = 0; j < 3; ++j) {
00049             rm(i,j) += (1.-ct) * esq(i,j) + st * e(i,j);
00050         }
00051     }
00052     return rm;
00053 }
00054 
00055 pele::VecN<4> rot_mat_to_quaternion(pele::MatrixNM<3,3> const & mx)
00056 {
00057     VecN<4> q(0);
00058     auto m = pele::transpose<3,3>(mx);
00059     double trace = m.trace();
00060 
00061     double s;
00062     if (trace > 0.){
00063         s = std::sqrt(trace+1.0) * 2.0;
00064         q[0] = 0.25 * s;
00065         q[1] = (m(1,2) - m(2,1)) / s;
00066         q[2] = (m(2,0) - m(0,2)) / s;
00067         q[3] = (m(0,1) - m(1,0)) / s;
00068     } else if ((m(0,0) > m(1,1)) and (m(0,0) > m(2,2))) {
00069         s = std::sqrt(1.0 + m(0,0) - m(1,1) - m(2,2)) * 2.0;
00070         q[0] = (m(1,2) - m(2,1)) / s;
00071         q[1] = 0.25 * s;
00072         q[2] = (m(1,0) + m(0,1)) / s;
00073         q[3] = (m(2,0) + m(0,2)) / s;
00074     } else if (m(1,1) > m(2,2)) {
00075         s = std::sqrt(1.0 + m(1,1) - m(0,0) - m(2,2)) * 2.0;
00076         q[0] = (m(2,0) - m(0,2)) / s;
00077         q[1] = (m(1,0) + m(0,1)) / s;
00078         q[2] = 0.25 * s;
00079         q[3] = (m(2,1) + m(1,2)) / s;
00080     } else {
00081         s = std::sqrt(1.0 + m(2,2) - m(0,0) - m(1,1)) * 2.0;
00082         q[0] = (m(0,1) - m(1,0)) / s;
00083         q[1] = (m(2,0) + m(0,2)) / s;
00084         q[2] = (m(2,1) + m(1,2)) / s;
00085         q[3] = 0.25 * s;
00086     }
00087 
00088     if (q[0] < 0) {
00089         q *= -1;
00090     }
00091     return q;
00092 }
00093 
00094 pele::VecN<3> quaternion_to_aa(pele::VecN<4> const & qin)
00095 {
00096     double eps = 1e-6;
00097     VecN<3> p;
00098     VecN<4> q = qin;
00099     if (q[0] < 0.) {
00100         q *= -1;
00101     }
00102     if (q[0] > 1.0) {
00103         q /= std::sqrt(pele::dot<4>(q,q));
00104     }
00105     double theta = 2. * std::acos(q[0]);
00106     double s = std::sqrt(1. - q[0]*q[0]);
00107     for (size_t i = 0; i < 3; ++i) {
00108         p[i] = q[i+1];
00109     }
00110     if (s < eps) {
00111         p *= 2.;
00112     } else {
00113         p *= theta / s;
00114 //        p = q[1:4] / s * theta
00115     }
00116     return p;
00117 }
00118 
00119 pele::VecN<4> aa_to_quaternion(pele::VecN<3> const & aa)
00120 {
00121     static const double rot_epsilon = 1e-6;
00122     VecN<4> q;
00123 
00124     double thetah = 0.5 * pele::norm<3>(aa);
00125     q[0]  = std::cos(thetah);
00126 
00127     // do linear expansion for small epsilon
00128     VecN<3> v = aa;
00129     if (thetah < rot_epsilon) {
00130         v *= 0.5;
00131     } else {
00132         v *= 0.5 * std::sin(thetah) / thetah;
00133     }
00134     for (size_t i = 0; i < 3; ++i) {
00135         q[i+1] = v[i];
00136     }
00137 
00138     // make sure to have normal form
00139     if (q[0] < 0.0) q *= -1;
00140     return q;
00141 
00142 }
00143 
00144 
00145 pele::VecN<4> quaternion_multiply(pele::VecN<4> const & q0, pele::VecN<4> const & q1)
00146 {
00147     VecN<4> q3;
00148     q3[0] = q0[0]*q1[0]-q0[1]*q1[1]-q0[2]*q1[2]-q0[3]*q1[3];
00149     q3[1] = q0[0]*q1[1]+q0[1]*q1[0]+q0[2]*q1[3]-q0[3]*q1[2];
00150     q3[2] = q0[0]*q1[2]-q0[1]*q1[3]+q0[2]*q1[0]+q0[3]*q1[1];
00151     q3[3] = q0[0]*q1[3]+q0[1]*q1[2]-q0[2]*q1[1]+q0[3]*q1[0];
00152     return q3;
00153 }
00154 
00155 
00159 void rot_mat_derivatives_small_theta(
00160         pele::VecN<3> const & p,
00161         MatrixNM<3,3> & rmat,
00162         MatrixNM<3,3> & drm1,
00163         MatrixNM<3,3> & drm2,
00164         MatrixNM<3,3> & drm3,
00165         bool with_grad)
00166 {
00167     double theta2 = pele::dot<3>(p, p);
00168     if (theta2 > 1e-2) {
00169         throw std::invalid_argument("theta must be small");
00170     }
00171     // Execute if the angle of rotation is zero
00172     // In this case the rotation matrix is the identity matrix
00173     rmat.assign(0);
00174     for (size_t i = 0; i<3; ++i) rmat(i,i) = 1; // identity matrix
00175 
00176 
00177     // vr274> first order corrections to rotation matrix
00178     rmat(0,1) = -p[2];
00179     rmat(1,0) = p[2];
00180     rmat(0,2) = p[1];
00181     rmat(2,0) = -p[1];
00182     rmat(1,2) = -p[0];
00183     rmat(2,1) = p[0];
00184 
00185     // If derivatives do not need to found, we're finished
00186     if (not with_grad) {
00187         return;
00188     }
00189 
00190     // hk286 - now up to the linear order in theta
00191     drm1.assign(0);
00192     drm1(0,0)    = 0.0;
00193     drm1(0,1)    = p[1];
00194     drm1(0,2)    = p[2];
00195     drm1(1,0)    = p[1];
00196     drm1(1,1)    = -2.0*p[0];
00197     drm1(1,2)    = -2.0;
00198     drm1(2,0)    = p[2];
00199     drm1(2,1)    = 2.0;
00200     drm1(2,2)    = -2.0*p[0];
00201     drm1 *= 0.5;
00202 
00203     drm2.assign(0);
00204     drm2(0,0)    = -2.0*p[1];
00205     drm2(0,1)    = p[0];
00206     drm2(0,2)    = 2.0;
00207     drm2(1,0)    = p[0];
00208     drm2(1,1)    = 0.0;
00209     drm2(1,2)    = p[2];
00210     drm2(2,0)    = -2.0;
00211     drm2(2,1)    = p[2];
00212     drm2(2,2)    = -2.0*p[1];
00213     drm2 *= 0.5;
00214 
00215     drm3.assign(0);
00216     drm3(0,0)    = -2.0*p[2];
00217     drm3(0,1)    = -2.0;
00218     drm3(0,2)    = p[0];
00219     drm3(1,0)    = 2.0;
00220     drm3(1,1)    = -2.0*p[2];
00221     drm3(1,2)    = p[1];
00222     drm3(2,0)    = p[0];
00223     drm3(2,1)    = p[1];
00224     drm3(2,2)    = 0.0;
00225     drm3 *= 0.5;
00226 }
00227 
00228 
00232 void rot_mat_derivatives(
00233         pele::VecN<3> const & p,
00234         MatrixNM<3,3> & rmat,
00235         MatrixNM<3,3> & drm1,
00236         MatrixNM<3,3> & drm2,
00237         MatrixNM<3,3> & drm3)
00238 {
00239     assert(p.size() == 3);
00240     if (rmat.shape() != std::pair<size_t, size_t>(3,3)) {
00241         throw std::invalid_argument("rmat matrix has the wrong size");
00242     }
00243     if (drm1.shape() != std::pair<size_t, size_t>(3,3)) {
00244         throw std::invalid_argument("drm1 matrix has the wrong size");
00245     }
00246     if (drm2.shape() != std::pair<size_t, size_t>(3,3)) {
00247         throw std::invalid_argument("drm2 matrix has the wrong size");
00248     }
00249     if (drm3.shape() != std::pair<size_t, size_t>(3,3)) {
00250         throw std::invalid_argument("drm2 matrix has the wrong size");
00251     }
00252 
00253     double theta2 = pele::dot<3>(p,p);
00254     if (theta2 < 1e-12) {
00255         return rot_mat_derivatives_small_theta(p, rmat, drm1, drm2, drm3, true);
00256     }
00257     // Execute for the general case, where THETA dos not equal zero
00258     // Find values of THETA, CT, ST and THETA3
00259     double theta   = std::sqrt(theta2);
00260     double ct      = std::cos(theta);
00261     double st      = std::sin(theta);
00262     double theta3  = 1./(theta2*theta);
00263 
00264 
00265     // Set THETA to 1/THETA purely for convenience
00266     theta   = 1./theta;
00267 
00268     // Normalise p and construct the skew-symmetric matrix E
00269     // ESQ is calculated as the square of E
00270     pele::VecN<3> pn = p;
00271     pn *= theta;
00272     MatrixNM<3,3> e(0);
00273     e(0,1)  = -pn[2];
00274     e(0,2)  =  pn[1];
00275     e(1,2)  = -pn[0];
00276     e(1,0)  = -e(0,1);
00277     e(2,0)  = -e(0,2);
00278     e(2,1)  = -e(1,2);
00279     auto esq     = pele::dot<3,3,3>(e, e);
00280 
00281     // compute the rotation matrix
00282     // RM is calculated from Rodrigues' rotation formula [equation [1]
00283     // in the paper]
00284     // rm  = np.eye(3) + [1. - ct] * esq + st * e
00285     rmat.assign(0.);
00286     for (size_t i = 0; i < 3; ++i) rmat(i,i) = 1; // identiy matrix
00287     for (size_t i = 0; i < 3; ++i) {
00288         for (size_t j = 0; j < 3; ++j) {
00289             rmat(i,j) += (1.-ct) * esq(i,j) + st * e(i,j);
00290         }
00291     }
00292 
00293     MatrixNM<3,3> de1(0.);
00294     de1(0,1) = p[2]*p[0]*theta3;
00295     de1(0,2) = -p[1]*p[0]*theta3;
00296     de1(1,2) = -(theta - p[0]*p[0]*theta3);
00297     de1(1,0) = -de1(0,1);
00298     de1(2,0) = -de1(0,2);
00299     de1(2,1) = -de1(1,2);
00300 
00301     MatrixNM<3,3> de2(0.);
00302     de2(0,1) = p[2]*p[1]*theta3;
00303     de2(0,2) = theta - p[1]*p[1]*theta3;
00304     de2(1,2) = p[0]*p[1]*theta3;
00305     de2(1,0) = -de2(0,1);
00306     de2(2,0) = -de2(0,2);
00307     de2(2,1) = -de2(1,2);
00308 
00309     MatrixNM<3,3> de3(0.);
00310     de3(0,1) = -(theta - p[2]*p[2]*theta3);
00311     de3(0,2) = -p[1]*p[2]*theta3;
00312     de3(1,2) = p[0]*p[2]*theta3;
00313     de3(1,0) = -de3(0,1);
00314     de3(2,0) = -de3(0,2);
00315     de3(2,1) = -de3(1,2);
00316 
00317     // compute the x derivative of the rotation matrix
00318     // drm1 = (st*pn[0]*esq + (1.-ct)*(de1.dot(e) + e.dot(de1))
00319     //         + ct*pn[0]*e + st*de1)
00320     auto de_e = pele::dot<3,3,3>(de1, e);
00321     auto ede_ = pele::dot<3,3,3>(e, de1);
00322     for (size_t i = 0; i < 3; ++i) {
00323         for (size_t j = 0; j < 3; ++j) {
00324             drm1(i,j) = (st * pn[0] * esq(i,j)
00325                          + (1.-ct) * (de_e(i,j) + ede_(i,j))
00326                          + ct * pn[0] * e(i,j)
00327                          + st * de1(i,j)
00328                          );
00329         }
00330     }
00331 
00332     // compute the y derivative of the rotation matrix
00333     de_e = pele::dot<3,3,3>(de2, e);
00334     ede_ = pele::dot<3,3,3>(e, de2);
00335     for (size_t i = 0; i < 3; ++i) {
00336         for (size_t j = 0; j < 3; ++j) {
00337             drm2(i,j) = (st * pn[1] * esq(i,j)
00338                          + (1.-ct) * (de_e(i,j) + ede_(i,j))
00339                          + ct * pn[1] * e(i,j)
00340                          + st * de2(i,j)
00341                          );
00342         }
00343     }
00344 
00345     // compute the z derivative of the rotation matrix
00346     de_e = pele::dot<3,3,3>(de3, e);
00347     ede_ = pele::dot<3,3,3>(e, de3);
00348     for (size_t i = 0; i < 3; ++i) {
00349         for (size_t j = 0; j < 3; ++j) {
00350             drm3(i,j) = (st * pn[2] * esq(i,j)
00351                          + (1.-ct) * (de_e(i,j) + ede_(i,j))
00352                          + ct * pn[2] * e(i,j)
00353                          + st * de3(i,j)
00354                          );
00355         }
00356     }
00357 }
00358 
00359 } // namespace pele
 All Classes Namespaces Functions Variables Typedefs