From 0e8ed0c57e5e5af3e06887d6423fd4ea1be4eeee Mon Sep 17 00:00:00 2001
From: Oliver Sander <sander@igpm.rwth-aachen.de>
Date: Wed, 2 Jan 2013 08:14:12 +0000
Subject: [PATCH] Implement method
 'secondDerivativeOfDistanceSquaredWRTFirstAndSecondArgument'

Not tested yet.

[[Imported from SVN: r9084]]
---
 dune/gfe/hyperbolichalfspacepoint.hh | 95 ++++++++++++++++++++--------
 1 file changed, 67 insertions(+), 28 deletions(-)

diff --git a/dune/gfe/hyperbolichalfspacepoint.hh b/dune/gfe/hyperbolichalfspacepoint.hh
index c4b4ae1d..2110624c 100644
--- a/dune/gfe/hyperbolichalfspacepoint.hh
+++ b/dune/gfe/hyperbolichalfspacepoint.hh
@@ -76,6 +76,17 @@ class HyperbolicHalfspacePoint
         }
     }
 
+    /** \brief Compute the third derivative of arccos^2 without getting unstable for x close to 1 */
+    static T thirdDerivativeOfArcCosHSquared(const T& x) {
+        const T eps = 1e-4;
+        if (x < 1+eps) {  // regular expression is unstable, use the series expansion instead
+            return 8.0/15 - 24*(x-1)/35;
+        } else {
+            T d = x*x-1;
+            return -6*x/(d*d) + (4*x*x+2)*std::acos(x)/(std::pow(d,5.2));
+        }
+    }
+
 public:
 
     /** \brief The type used for coordinates */
@@ -250,43 +261,71 @@ public:
         return result;
     }
 
-    /** \brief Compute the mixed second derivate \partial d^2 / \partial da db
+    /** \brief Compute the mixed second derivative \partial d^2 / \partial da db
 
-    Unlike the distance itself the squared distance is differentiable at zero
      */
-    static Dune::FieldMatrix<T,N,N> secondDerivativeOfDistanceSquaredWRTFirstAndSecondArgument(const HyperbolicHalfspacePoint& a, const HyperbolicHalfspacePoint& b) {
-
-        T sp = a.data_ * b.data_;
+    static Dune::FieldMatrix<T,N,N> secondDerivativeOfDistanceSquaredWRTFirstAndSecondArgument(const HyperbolicHalfspacePoint& a, const HyperbolicHalfspacePoint& b)
+    {
+        // abbreviate notation
+        const Dune::FieldVector<T,N>& p = a.data_;
+        const Dune::FieldVector<T,N>& q = b.data_;
+        
+        T diffNormSquared = (p-q).two_norm2();
 
-        // Compute vector A (see notes)
-        Dune::FieldMatrix<T,1,N> row;
-        row[0] = b.projectOntoTangentSpace(a.globalCoordinates());
+        // Compute first derivatives of F with respect to p and q
+        Dune::FieldVector<T,N> dFdp;
+        for (size_t i=0; i<N-1; i++)
+            dFdp[i] = ( p[i] - q[i] ) / (p[N-1] * q[N-1]);
+        
+        dFdp[N-1] = - diffNormSquared / (2*p[N-1]*q[N-1]*q[N-1]) - (p[N-1] - q[N-1]) / (p[N-1]*q[N-1]);
 
-        Dune::FieldVector<T,N> tmp = a.projectOntoTangentSpace(b.globalCoordinates());
-        Dune::FieldMatrix<T,N,1> column;
-        for (int i=0; i<N; i++)  // turn row vector into column vector
-            column[i] = tmp[i];
+        Dune::FieldVector<T,N> dFdq;
+        for (size_t i=0; i<N-1; i++)
+            dFdq[i] = ( q[i] - p[i] ) / (p[N-1] * q[N-1]);
+        
+        dFdq[N-1] = - diffNormSquared / (2*p[N-1]*q[N-1]*q[N-1]) - (p[N-1] - q[N-1]) / (p[N-1]*q[N-1]);
 
-        Dune::FieldMatrix<T,N,N> A;
-        // A = row * column
-        Dune::FMatrixHelp::multMatrix(column,row,A);
-        A *= secondDerivativeOfArcCosSquared(sp);
+        // Compute second derivatives of F
+        Dune::FieldMatrix<T,N,N> dFdpdq;
+       
+        for (size_t i=0; i<N; i++) {
+            
+            for (size_t j=0; j<N; j++) {
 
-        // Compute matrix B (see notes)
-        Dune::FieldMatrix<T,N,N> Pp, Pq;
-        for (int i=0; i<N; i++)
-            for (int j=0; j<N; j++) {
-                Pp[i][j] = (i==j) - a.data_[i]*a.data_[j];
-                Pq[i][j] = (i==j) - b.data_[i]*b.data_[j];
+                if (i!=N-1 and j!=N-1) {
+                    
+                    dFdpdq[i][j] = -(i==j) / (p[N-1]*q[N-1]);
+                    
+                } else if (i!=N-1 and j==N-1) {
+                    
+                    dFdpdq[i][j] = -(p[i] - q[i]) / (p[N-1]*q[N-1]*q[N-1]);
+                    
+                } else if (i!=N-1 and j==N-1) {
+                    
+                    dFdpdq[i][j] = (p[j] - q[j]) / (p[N-1]*p[N-1]*q[N-1]);
+                    
+                } else if (i==N-1 and j==N-1) {
+                    
+                    dFdpdq[i][j] = -1/(p[N-1]*p[N-1]*q[N-1]) - (p[N-1]-q[N-1]) / (p[N-1]*q[N-1]*q[N-1]) + diffNormSquared / (p[N-1]*p[N-1]*q[N-1]*q[N-1]);
+                
+                }
+                
             }
             
-        Dune::FieldMatrix<T,N,N> B;
-        Dune::FMatrixHelp::multMatrix(Pp,Pq,B);
-
-        // Bring it all together
-        A.axpy(derivativeOfArcCosSquared(sp), B);
+        }
+        
+        //
+        T x = 1 + diffNormSquared/ (2*p[N-1]*q[N-1]);
+        T alphaPrime      = derivativeOfArcCosHSquared(x);
+        T alphaPrimePrime = secondDerivativeOfArcCosHSquared(x);
 
-        return A;
+        // Sum it all together
+        Dune::FieldMatrix<T,N,N> result;
+        for (size_t i=0; i<N; i++)
+            for (size_t j=0; j<N; j++)
+                result[i][j] = alphaPrimePrime * dFdp[i] * dFdq[j] + alphaPrime * dFdpdq[i][j];
+        
+        return result;
     }
     
     
-- 
GitLab