From d340e8ebb47ea260bfb0a71a6f0befd79bef1acd Mon Sep 17 00:00:00 2001 From: Oliver Sander <sander@igpm.rwth-aachen.de> Date: Mon, 20 Apr 2009 12:32:47 +0000 Subject: [PATCH] implement interpolation of the gradient for members of SO(3), some of this is still educated guesswork, though [[Imported from SVN: r4060]] --- src/localgeodesicfefunction.hh | 167 ++++++++++++++++++++++++++++++++- 1 file changed, 165 insertions(+), 2 deletions(-) diff --git a/src/localgeodesicfefunction.hh b/src/localgeodesicfefunction.hh index 5ae292a1..55e6baa4 100644 --- a/src/localgeodesicfefunction.hh +++ b/src/localgeodesicfefunction.hh @@ -39,13 +39,21 @@ public: private: /** \brief Compute the derivate of geodesic interpolation wrt to the initial point - and return it as an _embedded_ tangent vector + and return it as a linear map on quaternion space \todo This is group-specific and should not really be here */ static Dune::FieldMatrix<ctype, EmbeddedTangentVector::size, EmbeddedTangentVector::size> derivativeWRTFirstPoint(const Rotation<3,ctype>& a, const Rotation<3,ctype>& b, double s); + /** \brief Compute the derivate of geodesic interpolation wrt to the initial point + + \todo This is group-specific and should not really be here + */ + static void interpolationVelocityDerivative(const Rotation<3,ctype>& q0, const Rotation<3,ctype>& q1, double s, + double intervalLength, Dune::array<Quaternion<double>,6>& grad); + + /** \brief The type of the reference element */ Dune::GeometryType type_; @@ -59,7 +67,162 @@ Dune::FieldMatrix<ctype, TargetSpace::EmbeddedTangentVector::size, TargetSpace:: LocalGeodesicFEFunction<dim,ctype,TargetSpace>:: derivativeWRTFirstPoint(const Rotation<3,ctype>& a, const Rotation<3,ctype>& b, double s) { - DUNE_THROW(Dune::NotImplemented, "derivativeWRTFirstPoint"); + // Get the derivative of [a,b](s) wrt 'a' + /** \brief The method actually compute the derivatives wrt to 'a' and 'b'. This is a waste! */ + Dune::array<Quaternion<double>,6> grad; + interpolationVelocityDerivative(a,b,s,1,grad); + + // We are really only interested in the first three entries + + Quaternion<ctype> aInv = a; + aInv.invert(); + + Dune::array<Quaternion<double>,3> derAlpha; + derAlpha[0] = aInv.mult(grad[0]); + derAlpha[1] = aInv.mult(grad[1]); + derAlpha[2] = aInv.mult(grad[2]); + + // Copy the thing into a matrix + Dune::FieldMatrix<ctype,3,4> derAlphaMatrix; + for (int i=0; i<3; i++) + derAlphaMatrix[i] = derAlpha[i]; + + // Get derivative of the exponential map at the identity. Incidentally, the implementation + // maps skew-symmetric matrices (== three-vectors) to quaternions + + Dune::FieldMatrix<ctype,4,3> Dexp = Rotation<3,ctype>::Dexp(Dune::FieldVector<ctype,3>(0)); + + Dune::FieldMatrix<ctype, TargetSpace::EmbeddedTangentVector::size, TargetSpace::EmbeddedTangentVector::size> result; + + Dune::FMatrixHelp::multMatrix(Dexp, derAlphaMatrix, result); + + return result; +} + +template <int dim, class ctype, class TargetSpace> +void LocalGeodesicFEFunction<dim,ctype,TargetSpace>:: +interpolationVelocityDerivative(const Rotation<3,ctype>& q0, const Rotation<3,ctype>& q1, double s, + double intervalLength, Dune::array<Quaternion<double>,6>& grad) +{ + // Clear output array + for (int i=0; i<6; i++) + grad[i] = 0; + + // Compute q_0^{-1} + Rotation<3,ctype> q0Inv = q0; + q0Inv.invert(); + + + // Compute v = s \exp^{-1} ( q_0^{-1} q_1) + Dune::FieldVector<ctype,3> v = Rotation<3,ctype>::expInv(q0Inv.mult(q1)); + v *= s/intervalLength; + + Dune::FieldMatrix<ctype,4,3> dExp_v = Rotation<3,ctype>::Dexp(v); + + Dune::array<Dune::FieldMatrix<ctype,3,3>, 4> ddExp; + Rotation<3,ctype>::DDexp(v, ddExp); + + Dune::FieldMatrix<ctype,3,4> dExpInv = Rotation<3,ctype>::DexpInv(q0Inv.mult(q1)); + + Dune::FieldMatrix<ctype,4,4> mat(0); + for (int i=0; i<4; i++) + for (int j=0; j<4; j++) + for (int k=0; k<3; k++) + mat[i][j] += 1/intervalLength * dExp_v[i][k] * dExpInv[k][j]; + + + // ///////////////////////////////////////////////// + // The derivatives with respect to w^0 + // ///////////////////////////////////////////////// + for (int i=0; i<3; i++) { + + // \partial exp \partial w^1_j at 0 + Quaternion<ctype> dw; + for (int j=0; j<4; j++) + dw[j] = 0.5*(i==j); // dExp_v_0[j][i]; + + // \xi = \exp^{-1} q_0^{-1} q_1 + Dune::FieldVector<ctype,3> xi = Rotation<3,ctype>::expInv(q0Inv.mult(q1)); + + Quaternion<ctype> addend0; + addend0 = 0; + dExp_v.umv(xi,addend0); + addend0 = dw.mult(addend0); + addend0 /= intervalLength; + + // \parder{\xi}{w^1_j} = ... + Quaternion<ctype> dwConj = dw; + dwConj.conjugate(); + //dwConj[3] -= 2 * dExp_v_0[3][i]; the last row of dExp_v_0 is zero + dwConj = dwConj.mult(q0Inv.mult(q1)); + + Dune::FieldVector<ctype,3> dxi(0); + Rotation<3,ctype>::DexpInv(q0Inv.mult(q1)).umv(dwConj, dxi); + + Quaternion<ctype> vHv; + for (int j=0; j<4; j++) { + vHv[j] = 0; + // vHv[j] = dxi * DDexp * xi + for (int k=0; k<3; k++) + for (int l=0; l<3; l++) + vHv[j] += ddExp[j][k][l]*dxi[k]*xi[l]; + } + + vHv *= s/intervalLength/intervalLength; + + // Third addend + mat.umv(dwConj,grad[i]); + + // add up + grad[i] += addend0; + grad[i] += vHv; + + grad[i] = q0.mult(grad[i]); + } + + + // ///////////////////////////////////////////////// + // The derivatives with respect to w^1 + // ///////////////////////////////////////////////// + for (int i=3; i<6; i++) { + + // \partial exp \partial w^1_j at 0 + Quaternion<ctype> dw; + for (int j=0; j<4; j++) + dw[j] = 0.5 * ((i-3)==j); // dw[j] = dExp_v_0[j][i-3]; + + // \xi = \exp^{-1} q_0^{-1} q_1 + Dune::FieldVector<ctype,3> xi = Rotation<3,ctype>::expInv(q0Inv.mult(q1)); + + // \parder{\xi}{w^1_j} = ... + Dune::FieldVector<ctype,3> dxi(0); + dExpInv.umv(q0Inv.mult(q1.mult(dw)), dxi); + + Quaternion<ctype> vHv; + for (int j=0; j<4; j++) { + // vHv[j] = dxi * DDexp * xi + vHv[j] = 0; + for (int k=0; k<3; k++) + for (int l=0; l<3; l++) + vHv[j] += ddExp[j][k][l]*dxi[k]*xi[l]; + } + + vHv *= s/intervalLength/intervalLength; + + // /////////////////////////////////// + // second addend + // /////////////////////////////////// + + + dw = q0Inv.mult(q1.mult(dw)); + + mat.umv(dw,grad[i]); + grad[i] += vHv; + + grad[i] = q0.mult(grad[i]); + + } + } -- GitLab