NumericalPolarGeodesic2D.cpp

Compute a straight line in polar coordinates (r,phi) in two dimensions to check performance and numerical stability.

#include <iostream>

#include <spacetime/Schwarzschild.hpp>
#include <spacetime/Geodesic853.hpp>
#include <spacetime/Acceleration.hpp>
#include <vecal/CartesianChart.hpp>
#include <spacetime/NumericalSpacetime.hpp>
#include <spacetime/IntegrateGeodesic.hpp>

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

using namespace VecAl;
using namespace Traum;
using namespace std;

struct  ExplicitPolarGeodesics2DEquation : IntegratePath853<double>
{
        typedef double real;

        override void Accel(real s, const real *x, const real *v, real *d2x_ds2)
        {
                d2x_ds2[0] =   x[0] * v[1] * v[1];
                d2x_ds2[1] = 2/x[0] * v[0] * v[1];
        }
};

void ExplicitPolarGeodesics2D()
{
Vector<2,double> q; q = 5,0;
Vector<2,double> v; v = 0,1;

ExplicitPolarGeodesics2DEquation PolarPath;

        PolarPath.init(2, 0.0, q.ptr(), v.ptr() );

        for(int is=0; is<100; is++)
        {
                PolarPath.advance();
                
                if (is %10 == 0)
                {
                double  x = PolarPath.q(0) * sin(PolarPath.q(1)),
                        y = PolarPath.q(0) * cos(PolarPath.q(1));
                        cout << "{" << PolarPath.q(0) << ","<< PolarPath.q(1) << "}" << endl;
                        cout << "\t{x=" << x << ", y=" << y << "}" << endl;
                }
        }
}

void PolarGeodesics2D()
{
        //ExplicitPolarGeodesics2D();

typedef TangentialSpace<PolarCoordinates<2>, float > Polar2Df;
typedef TangentialSpace<PolarCoordinates<2>, double > Polar2Dd;
typedef Polar2Df myChart;

typedef myChart::Metric_t Tensor;
typedef MultiArray<2, Tensor, Tensor*> TensorField;
typedef NumericalSpacetime<TensorField, myChart> NumSpacetime_t;

enum { r = PolarCoordinates<2>::r, p = PolarCoordinates<2>::phi }; 

        // grid size
enum { N = 10 };

        // define metric tensor field's storage
Tensor TensorStorage[N*N];
        // define multidimensional field
TensorField G(TensorStorage, MIndex(N,N) );

        // initialize tensor field by unit metric
Tensor  InitValue;
        InitValue.set(0.L);
        InitValue(r,r) = InitValue(p,p) = 1;
        G.set( InitValue );

        // set up polar metric
        for(int ri=0; ri<N; ri++)
        for(int pi=0; pi<N; pi++)
        {
        double  P = pi * 2 * M_PI / N,
                R = ri *    5.0  / N;

        Tensor&g = G[ MIndex(ri, pi) ];

                g(0,0) = 1;
                g(1,1) = R*R;
        }

        // Define a spacetime with this tensor field
NumSpacetime_t NumSpacetime(G);

        // Define a geodesic integrator on this spacetime
Geodesic853<NumSpacetime_t> myPath(NumSpacetime); 

//if (false)
{
        // Define initial conditions for the geodesic
        // Note: q->r = 0 is a coordinate singularity!
myChart::Point   q; 
                  q[q->r] = 5; q[q->phi] = 0;

myChart::Vector v; v = 0,1;
        cout <<"Geodesic starts at q="<<q<<"\t v="<<v<< endl;

        myPath.restart1(0, q, v);

clock_t start, finish;
        start = clock();
        {for(int is = 0; is<10000; is++)
        {
                if (is==0)
                        cout << "Path Accel: " << NumSpacetime(myPath.position(), myPath.velocity() ) << endl;

                myPath.advance();

        myChart::Point  q = myPath.position();
        myChart::Vector v = myPath.velocity();

        double  x = q[q->r] * sin(q[q->phi] ),
                y = q[q->r] * cos(q[q->phi] );
                if (is %1000 == 0)
                {
                        cout <<" q="<<q<<"\tv="<<v;
                        cout << "\t{x=" << x << ", y=" << y << "}" << endl;
                }
        }}
        finish = clock();
        printf( "DOP Geodesic: %2.1f seconds\n", (double)(finish - start) / CLOCKS_PER_SEC );

}
{
        // Define initial conditions for the geodesic
        // Note: q->r = 0 is a coordinate singularity!
myChart::Point   q; 
                  q[q->r] = 5; q[q->phi] = 0;

myChart::Vector v; v = 0,1;
        cout <<"Geodesic starts at q="<<q<<"\t v="<<v<< endl;

typedef ChristoffelField<MultiArray<2, Tensor, Tensor*> > Chris_t;
Chris_t Chris(G, q);

clock_t start, finish;
        start = clock();
        {for(int is = 0; is<10000; is++)
        {
                // path parameter increment
        float   ds = 0.001;

                // coordinate acceleration, \ddot q
        myChart::Vector a;

                Chris.getCoordinateAcceleration(a, v);

                if (is==0)
                {
                        cout << "Accel: "<<a<<endl;
                Chris_t::Christoffel_t Gamma;
                        Chris.getLowerChristoffel(Gamma);
                        cout << "Gamma: " << Gamma << endl;

                }

                // Euler step
                q += v*ds;
                v += a*ds;

        double  x = q[q->r] * sin(q[q->phi] ),
                y = q[q->r] * cos(q[q->phi] );
                if (is %1000 == 0)
                {
                        cout <<" q="<<q<<"\tv="<<v;//"\t a="<< a << endl;
                        cout << "\t{x=" << x << ", y=" << y << "}" << endl;
                }
        }}
        finish = clock();
        printf( "2D Geodesic: %2.1f seconds\n", (double)(finish - start) / CLOCKS_PER_SEC );
        /*
        DBL PREC
Geodesic starts at q=(1,0)       v=[0,1]
 q=(1,0.000367496)      v=[-0.000183748,1]      {x=0.000367496, y=1}
 q=(0.967869,0.352351)  v=[-0.16644,0.878467]   {x=0.334017, y=0.908407}
 q=(0.886769,0.630182)  v=[-0.262461,0.627296]  {x=0.522566, y=0.716438}
 q=(0.782168,0.81662)   v=[-0.30019,0.397274]   {x=0.570072, y=0.535541}
 q=(0.669226,0.930705)  v=[-0.312087,0.234651]  {x=0.536746, y=0.399708}
 q=(0.553803,0.996365)  v=[-0.315352,0.130865]  {x=0.464919, y=0.300913}
 q=(0.437733,1.03191)   v=[-0.316143,0.0679784] {x=0.375698, y=0.224635}
 q=(0.321513,1.04955)   v=[-0.316306,0.0314362] {x=0.278817, y=0.1601}
 q=(0.205266,1.05704)   v=[-0.316332,0.0114268] {x=0.178767, y=0.100879}
 q=(0.0890146,1.05924)  v=[-0.316334,0.00200836]        {x=0.0776194, y=0.043575
5}
2D Geodesic: 2.0 seconds

        FLT PREC
Geodesic starts at q=(1,0)       v=[0,1]
 q=(1,0.000367496)      v=[-0.000183748,1]      {x=0.000367496, y=1}
 q=(0.967619,0.352353)  v=[-0.168996,0.878504]  {x=0.333932, y=0.908171}
 q=(0.883886,0.630329)  v=[-0.275108,0.628434]  {x=0.520972, y=0.714032}
 q=(0.772552,0.817846)  v=[-0.323736,0.402541]  {x=0.563712, y=0.528267}
 q=(0.649521,0.934973)  v=[-0.342776,0.246054]  {x=0.522594, y=0.385712}
 q=(0.522055,1.00588)   v=[-0.349765,0.147755]  {x=0.440946, y=0.279478}
 q=(0.39298,1.04832)    v=[-0.352269,0.0881573] {x=0.34055, y=0.196109}
 q=(0.263332,1.0736)    v=[-0.353158,0.052478]  {x=0.231449, y=0.125599}
 q=(0.13348,1.08865)    v=[-0.353473,0.0312136] {x=0.118264, y=0.0618924}
 q=(0.00355618,1.0976)  v=[-0.353584,0.0185603] {x=0.00316541, y=0.00162068}
2D Geodesic: 1.5 seconds
        */
}
}