Demonstration of the interpolated derivative of a vector field.
#include <vector/CubicIpol.hpp> #include <vector/LinearIpol.hpp> #include <vector/MultiArray.hpp> #include <vector/Interpolate.hpp> #include <vector/Vector.hpp> #include <vector/Matrix.hpp> #include <vector/QuadraticMatrix.hpp> #include <time.h> using namespace std; using namespace Fiber; template class LowerTriangular<3, double>; // Demonstration on how to compute the partial derivative of // the nth component of a multi-valued (e.g. vector or tensor) // field by the mth coordinate function. static int DemonstrateTensorDerivative() { // symbolic names for coordinates enum { x=0, y=1, z=2 }; // untyped tensorial object typedef FixedArray<6, double> uTensor; // typed tensorial object: // Symmetric tensor typedef LowerTriangular<3, double> Tensor; // General tensor of rank two. typedef Quadratic<3, double> gTensor; // The data storage of the tensor field is an automatic variable. Tensor TensorStorage[1000]; // This tensor field, consisting of 1000 points, is defined over // a three-dimensional base manifold with 10 vertices in each dimension. MultiArray<3, Tensor> G(TensorStorage, MIndex(10,10,10) ); // Initialize all elements through the MultiArray interface Tensor InitValue; InitValue(0,0) = InitValue(1,1) = InitValue(2,2) = 1; InitValue(0,1) = InitValue(1,2) = InitValue(2,0) = 0; G.set( InitValue ); // Define some point of interesting. MultiIndex<3> I; I = 5,6,7; // modify the data values there G[ I ] (2,2) = 2; // Determine the vectorial index of the tensorial component int Component = Tensor::mem_index(2,2); // Define field referring to the third component of the tensor field. // Note that we need to view the tensorial data as vector here, thus // requiring the vec() call. Iterator<double> GnmPtr( G.count()*Tensor::SIZE, G.ptr(), Component); cout << G[I]; // Define a multidimensional array on the view pointer. // Note that the view pointer could also be constructed as local argument. typedef MultiArray<3, double> Gnm_t; Gnm_t Gnm( GnmPtr, G.Size() ); { FixedArray<3, double> point; // Interpolate<3, double, LinearIpol<double> , double, NoDelimiter<double>, x> Interpolate<3, double, CubicIpol<double> , double, NoDelimiter<double>, x> Gnm_k(Gnm, point); for(double fr=0; fr<2; fr+=0.1) { point = 5.1, 6.2, 7 + fr; cout << "Cubic interpolated derived tensor component Gmn,k " << point << " " << Gnm_k.eval() << endl ; } } // Starting point VVector<3, double> q; q = 5.1, 6.8, 5.03; // Velocity Row<3, double> v; v = 0.01,0.02,.2; clock_t start, finish; start = clock(); for(int is = 0; is<40000; is++) { // // Computation of coordinate acceleration from metric tensor at specific point. // // path parameter increment double ds = 0.001; #ifndef EXPLICIT_CHRISTOFFEL_OPERATIONS //FixedArray<3, FixedArray<3, FixedArray<3, double> > > g_ij_k; LowerTriangular<3, FixedArray<3, double> > g_ij_k; #if 0 TensorDerivative<MultiArray<3, Tensor, Tensor*> > dG(G, q); dG.eval( g_ij_k ); #elif 0 //const char C[4] = "xyz"; {for(int j=0; j<3; j++) for(int i=j; i<3; i++) { int Component = Tensor::mem_index(i,j); Gnm_t Gnm( &G.storage().vec(), Component, G.Size() ); #if 1 Derivator<MultiArray<3, double, ViewPtr<double> >, CubicIpol<double>, double, NoDelimiter<double> > D(Gnm, q); D.eval( g_ij_k(i,j) ); #else #if 1 Interpolate<3, double, Gnm_t::Storage_t, CubicIpol<double> , double, NoDelimiter<double>, 0> Gij_0(Gnm, q ); Interpolate<3, double, Gnm_t::Storage_t, CubicIpol<double> , double, NoDelimiter<double>, 1> Gij_1(Gnm, q ); Interpolate<3, double, Gnm_t::Storage_t, CubicIpol<double> , double, NoDelimiter<double>, 2> Gij_2(Gnm, q ); #else Interpolate<3, double, Gnm_t::Storage_t, LinearIpol<double> , double, NoDelimiter<double>, 0> Gij_0(Gnm, q ); Interpolate<3, double, Gnm_t::Storage_t, LinearIpol<double> , double, NoDelimiter<double>, 1> Gij_1(Gnm, q ); Interpolate<3, double, Gnm_t::Storage_t, LinearIpol<double> , double, NoDelimiter<double>, 2> Gij_2(Gnm, q ); #endif #if 0 g_ij_k[i][j][0] = Gij_0.eval(); g_ij_k[i][j][1] = Gij_1.eval(); g_ij_k[i][j][2] = Gij_2.eval(); #else g_ij_k(i,j)[0] = Gij_0.eval(); g_ij_k(i,j)[1] = Gij_1.eval(); g_ij_k(i,j)[2] = Gij_2.eval(); #endif // if (!is) // { // cout << "g_"<< C[i] << C[j] << ",x=" << g_ij_k[i][j][0] << " "; // cout << "g_"<< C[i] << C[j] << ",y=" << g_ij_k[i][j][1] << " "; // cout << "g_"<< C[i] << C[j] << ",z=" << g_ij_k[i][j][2] << " "; // } #endif } } #endif //FixedArray<3, FixedArray<3, FixedArray<3, double> > > G_ijk; LowerTriangular<3, FixedArray<3, double> > G_ijk; // Gij_k = gik,j + gjk,i - gij,k {for(int j=0; j<3; j++) for(int i=j; i<3; i++) for(int k=0; k<3; k++) { // G_ijk[i][j][k] = g_ij_k[i][k][j] + g_ij_k[j][k][i] - g_ij_k[i][j][k]; G_ijk(i,j)[k] = g_ij_k(i,k)[j] + g_ij_k(j,k)[i] - g_ij_k(i,j)[k]; } } Interpolate<3, Tensor, CubicIpol<Tensor>, double> Gfield(G, q ); const Tensor&Glocal = Gfield.eval(); Column<3, double> dv; // Compute coordinate co-acceleration via Lower Christoffels // // dv_k = G_{ij_k} v^i v^j // {for(int k=0; k<3; k++) { dv[k] = 0; for(int j=0; j<3; j++) { double G_ijk_vi = 0; for(int i=0; i<3; i++) { G_ijk_vi += G_ijk(i,j)[k] * v[i]; } G_ijk_vi *= v[j]; dv[k] += G_ijk_vi; } } } Quadratic<3,double> Glocal_q = Glocal; Quadratic<3,double>::PermutationVector_t PV; Glocal_q.GaussDecompose(PV); // coordinate acceleration, \ddot q Column<3, double> a; Glocal_q.GaussSolve(PV, dv, a ); cout << " Coordinate Acceleration:" << a << endl; #else // EXPLICIT_CHRISTOFFEL_OPERATIONS ChristoffelField<MultiArray<3, Tensor, Tensor*> > Chris(G,q); Chris.getAcceleration(a, v); #endif // v == dq/ds // a == dv/ds; q += v*ds; v += a*ds; if (is %1000 == 0) cout << "v="<<v<<"\t q="<<q<<endl; } finish = clock(); printf( "Geodesic computation: %2.1f seconds\n", (double)(finish - start) / CLOCKS_PER_SEC ); cout << "Final: v="<<v<<"\t q="<<q<<endl; cout << "EXPECT v=(0.00628477,0.088151,0.180334) q=(5.3987,9.70163,12.4076)" << endl; /* ----- P4 1.6GHz, Cubic Christoffel Ipol, Intel C++, Optimize: Geodesic computation: 5.7 seconds Final: v=(0.00628477,0.088151,0.180334) q=(5.3987,9.70163,12.4076) ----> Employing symmetry on Christoffel: Geodesic computation: 4.0 seconds Final: v=(0.00628477,0.088151,0.180334) q=(5.3987,9.70163,12.4076) ----- P4 1.6GHz, Linear Christoffel Ipol, Intel C++, Optimize: Geodesic computation: 1.8 seconds Final: v=(0.00160945,0.00741571,0.0737203) q=(5.38425,7.92392,10.8191) ----- P4 1.6GHz, Cubic Christoffel Ipol, Intel C++, Debug: Geodesic computation: 56.5 seconds Final: v=(0.00628477,0.088151,0.180334) q=(5.3987,9.70163,12.4076) */ return 1; } // Demonstration the computation of geodesics in a numerical tensor field // and the numerical precision via back-integration to the starting point. static int DemonstrateGeodesics() { // symbolic names for coordinates enum { x=0, y=1, z=2 }; // typed tensorial object: typedef LowerTriangular<3, double> Tensor; // The data storage of the tensor field is an automatic variable. Tensor TensorStorage[1000]; // This tensor field, consisting of 1000 points, is defined over // a three-dimensional base manifold with 10 vertices in each dimension. MultiArray<3, Tensor> G(TensorStorage, MIndex(10,10,10) ); // Initialize all elements through the MultiArray interface Tensor InitValue; InitValue(0,0) = InitValue(1,1) = InitValue(2,2) = 1; InitValue(0,1) = InitValue(1,2) = InitValue(2,0) = 0; G.set( InitValue ); // Modify the data values at some point of interest G[ MIndex(5,6,7) ] (2,2) = 2; // Starting point VVector<3, double> q0, q; q = 5.1, 6.8, 5.03; q0 = q; // Velocity Row<3, double> v0, v; v = 0.01,0.02,.2; v0 = v; #if 0 ChristoffelField<MultiArray<3, Tensor, Tensor*> > Chris(G,q); // EXCERPT: #if 1 { typedef Tensor metric_type; typedef Tensor* MetricStorage_t; typedef CubicIpol<metric_type> MetricInterpol; typedef double CoordinateType; FixedArray<3, CoordinateType> p; Interpolate<3, metric_type, MetricStorage_t, MetricInterpol, CoordinateType> MetricField(G, p); NoDelimiter<metric_type> ND; // metric_type m = G[0]; metric_type m = MetricField[0]; // metric_type m = ND.limit( MetricField[0] ); // metric_type m = MetricField.myDelimiter.limit( MetricField[0] ); //MetricInterpol::interpolate( MetricField, p[2], G.Size[2], MetricField.myDelimiter ); //IpolDerivative<metric_type, MetricInterpol, false>::interpolate(MetricField, p[2], G.Size[2], MetricField.myDelimiter ); // metric_type g = MetricField.eval(); } #else clock_t start, finish; start = clock(); {for(int is = 0; is<40000; is++) { // path parameter increment double ds = 0.001; // coordinate acceleration, \ddot q Row<3, double> a; Chris.getCoordinateAcceleration(a, v); // Euler step q += v*ds; v += a*ds; if (is %1000 == 0) cout << "v="<<v<<"\t q="<<q<<endl; }} finish = clock(); printf( "Geodesic computation: %2.1f seconds\n", (double)(finish - start) / CLOCKS_PER_SEC ); {for(int is = 0; is<40000; is++) { // path parameter increment double ds = -0.001; // coordinate acceleration, \ddot q Row<3, double> a; Chris.getCoordinateAcceleration(a, v); // Euler step q += v*ds; v += a*ds; if (is %1000 == 0) cout << "v="<<v<<"\t q="<<q<<endl; }} cout << "q=" << q << "\t q0=" << q0 << " Diff: " << q-q0 << endl; cout << "v=" << v << "\t v0=" << v0 << " Diff: " << v-v0 << endl; double Qerror = norm2(q-q0); cout << "Qerror =" << Qerror << endl; assert( Qerror < 1E-8 ); #endif #endif return 1; } int dVInterpolCheck() { int r=0; // r+=DemonstrateTensorDerivative(); // r+=DemonstrateGeodesics(); return r; }