SchwarzschildGeodesic.hpp

00001 
00002 //
00003 // $Id: SchwarzschildGeodesic.hpp,v 1.12 2007/03/06 23:01:16 werner Exp $
00004 //
00005 // $Log: SchwarzschildGeodesic.hpp,v $
00006 // Revision 1.12  2007/03/06 23:01:16  werner
00007 // Integration of the Vector library into the Eagle library, for the sake
00008 // of type registration.
00009 //
00010 // Revision 1.11  2007/02/22 17:08:42  werner
00011 // A major revision of the vector/fixed array interface, unifying three independent
00012 // libraries into one. The vecal (Vector Algebra), fish/vector (Multidimensional
00013 // vector arrays) and the Eagle library (Geometric Algebra) thus share a common
00014 // root now.
00015 //
00016 // Revision 1.10  2005/08/02 18:16:57  werner
00017 // Using new metric interface.
00018 //
00019 // Revision 1.9  2004/09/23 11:22:49  werner
00020 // Little improvements.
00021 //
00022 // Revision 1.8  2004/09/15 21:43:46  werner
00023 // Removed include file.
00024 //
00025 // Revision 1.7  2004/09/15 16:49:41  werner
00026 // Various bugfixes and functionality fixes.
00027 //
00028 // Revision 1.6  2004/09/03 12:26:15  werner
00029 // Adjusted moved header files.
00030 //
00031 // Revision 1.5  2004/08/24 09:09:53  werner
00032 // Towards VC7
00033 //
00034 // Revision 1.4  2004/08/12 16:21:33  werner
00035 // Integration of numerical geodesics now compiles. Working is not yet satisfying.
00036 //
00037 // Revision 1.3  2004/05/14 10:01:24  werner
00038 // Towards position output, temporary commit.
00039 //
00040 // Revision 1.2  2004/05/13 12:19:48  werner
00041 // Adjustments for gcc 3.4.0.
00042 //
00043 // Revision 1.1  2004/05/13 12:07:53  werner
00044 // Schwarzschild geodesics via one-dimensional equatorial solution.
00045 //
00047 #ifndef __SCHWARZSCHILD_GEODESIC_HPP
00048 #define __SCHWARZSCHILD_GEODESIC_HPP "Created 12.05.2004 21:57:45 by werner benger"
00049 
00050 #include <ode/Integrate853.hpp>
00051 //#include <vecal/PolarChart.hpp>
00052 //#include <vecal/CartesianChart.hpp>
00053 
00054 #include <eagle/STA.hpp>
00055 
00056 namespace Traum
00057 {
00058 using namespace Eagle;
00059 
00060 #ifdef  DB_LOG
00061 using namespace wb;
00062 #endif
00063 
00068 class   EquatorialPlane
00069 {
00070 public: typedef long double real;
00071         typedef Eagle::STA::sphericalpoint      PolarPt;
00072         typedef Eagle::STA::point               CartesianPt;
00073         typedef Eagle::STA::vector              CartesianVec;
00074 
00075         CartesianPt     Center;
00076         CartesianVec    X, Y;
00077 
00078 // Koordinatentransformation Schwarzschild --> kartesisch
00079         CartesianPt operator()(const PolarPt&P) const
00080         {
00081         real    r  = P[P.R],
00082                 phi= P[P.PHI];
00083 
00084                 return CartesianPt( Center + r * ( sin(phi) * Y - cos(phi) * X) );
00085         }
00086 
00087 static  real cosine(const CartesianVec&l, const CartesianVec&r)
00088         {
00089                 return dot( l.spatial(), r.spatial() );
00090         }
00091 
00092 // Koordinatentransformation kartesisch --> Schwarzschild
00093         PolarPt operator()(const CartesianPt&P,  real&sinphi, real&cosphi) const
00094         {
00095         CartesianVec p = P-Center;
00096 //      CartesianVec p = difference(P, Center);
00097         /*
00098         Sei p der normalisierte Richtungsvektor zum Punkt,  dann gilt:
00099 
00100                 p = sin(phi) * Y - cos(phi) * X
00101 
00102                 p*X =           -cos(phi)
00103                 p*Y = sin(phi) 
00104          */
00105         PhysicalSpace::vector dist_vec = p.spatial();
00106 
00107         real    r       = norm( dist_vec );
00108                 cosphi  = -cosine(X,p) / r;
00109                 sinphi  =  cosine(Y,p) / r;
00110                 
00111         real    phi     = atan2(sinphi, cosphi);
00112 
00113                 if (phi<0)
00114                         phi += 2*M_PI; 
00115 
00116         PolarPt R;
00117                 R[R.T] = P[P.T];
00118                 R[R.R] = r;
00119                 R[R.PHI] = phi;
00120                 R[R.THETA] = 0;
00121                 return R;
00122         }
00123 
00124 #if 0
00125 
00126 /*
00127   Tangentialvektor einer Geodäten (u,u') am Punkt phi berechnen
00128   @returns u^2 dr(phi)/dphi
00129  */
00142 vector3 CoordinateAxes::direction(double sinphi, double cosphi,
00143                                   double u, double du) const
00144 {
00145         return  (-du * sinphi + u * cosphi) * Y +
00146                 ( du * cosphi + u * sinphi) * X;
00147 
00148 #if 0
00149 /*
00150 Geradengleichung in radialinversen Polarkoordinaten:
00151 
00152         u (phi) = sin(phi)/d - k/d  cos(phi)
00153         u'(phi) = cos(phi)/d + k/d  sin(phi)
00154 
00155 Daraus: d = (sin(phi)-k*cos(phi))/u = (cos(phi)+k*sin(phi))/u'
00156 
00157 Damit:  z = k*n
00158 
00159 Mit     */
00160 double  z = sinphi/u  - cosphi/du,
00161         n = sinphi/du + cosphi/u;
00162 /*
00163 Nun ist
00164         dir = X + k*Y = X + z/n Y
00165 
00166 und daher:
00167         n*dir = n*X + z*Y;
00168  */ 
00169         return  n*X - z*Y; // wo kommt das '-' her??? 
00170 //      return  n*X + z*Y; 
00171 #endif
00172 }
00173 
00174 #endif
00175 
00176 };
00177 
00178 
00179 class   SchwarzschildGeodesic : public IntegratePath853<long double>
00180 {
00181 public: typedef long double real;
00182         real    M;
00183         EquatorialPlane EQ;
00184 
00185         typedef STA::sphericalpoint     PolarPt;
00186         typedef STA::sphericalvector    PolarVec;
00187         typedef STA::point              CartesianPt;
00188         typedef STA::vector             CartesianVec;
00189 
00190         typedef PhysicalSpace::point    point3;
00191         typedef PhysicalSpace::vector   vector3;
00192 
00193         SchwarzschildGeodesic(const real&mass=0)
00194         : M(mass)
00195         {
00196                 EQ.Center.set(0.0);
00197         }
00198 
00199 /*
00200   Eine Gerade ist in Polarkoordinaten gegeben durch:
00201 
00202         r(phi) = d / [ sin(phi) - k cos(phi) ]
00203 
00204 bzw.
00205         u(phi) = 1/r(phi) = [sin(phi) - k cos(phi) ] / d
00206 
00207 Durch die Wahl der Strahlrichtung als X-Achse wird die Steigung
00208 in der Geraden in diesem Koordinatensystem k=0. Der Parameter d ist
00209 der Minimalabstand der Geraden vom Koordinatenursprung.
00210  Mit dieser Wahl der X,Y - Achse ergibt sich:
00211 
00212         r(phi) = d / sin(phi)
00213 
00214         u(phi) = sin(phi) / d
00215 
00216         u'(phi) = cos(phi) / d
00217 
00218   
00219 */
00220         bool restart(const real&s, const CartesianPt&x0, const CartesianVec&v0)
00221         {
00222         enum { N = 1, i=0 }; 
00223 
00224 
00225         point3   q0 = x0.spatial();
00226         vector3 dq0 = v0.spatial();
00227                 dq0 /= norm(dq0);
00228 
00229         const point3 & Center = EQ.Center.spatial(); 
00230 
00231 #ifdef  DB_LOG
00232                 db_logf(21, "SchwarzschildGeodesic: EQ Axis: Ray (%lg,%lg,%lg) + l (%lg,%lg,%lg) \n", 
00233                         double( q0[0]), double( q0[1]), double( q0[2]),
00234                         double(dq0[0]), double(dq0[1]), double(dq0[2])
00235                         );
00236 #endif
00237 
00238         // 
00239         // Nm ist derjenige Punkt auf der Geraden, der dem Massenzentrum 
00240         // am nächsten liegt. Der Richtungsvektor von diesem Punkt zum 
00241         // Massenzentrum bildet somit die Y-Achse. Die X-Achse wird 
00242         // durch den Sichtstrahl selbst gebildet. 
00243         //
00244         // Geradenparameter für Punktabstand
00245         //  l = (P-O)*d / (d*d)
00246         //
00247         real    l = dot(Center - q0, dq0);
00248 
00249 //      cout << "Closest linear approach at lambda="<< l << endl; 
00250 #ifdef  DB_LOG
00251         db_logf(21, "SchwarzschildGeodesic: EQ Axis: Closest linear approach is at lambda=%lg\n", double(l) );
00252 #endif
00253 
00254         point3  Nm = q0 + l*dq0; 
00255 //      point3  Nm = q0 + l*dq0;
00256 
00257                 EQ.X = tvector4( 0, dq0);
00258 
00259         vector3 y = Nm-Center; 
00260 //      vector3 y = difference(Nm, Center); 
00261 
00262 #ifdef  DB_LOG
00263 #define SVECP(V) double(V[V->x]),double(V[V->y]),double(V[V->z])
00264 
00265         db_logf(21,"SchwarzschildGeodesic: CLOSEPOINT: (%lg,%lg,%lg) (lambda=%lg [%lg])\n", 
00266                                                      SVECP(y),     double(l), double(l/M) );
00267 #endif
00268         
00269         // 
00270         // d ist der Minimale Abstand des Sichtstrahles vom Massenzentrum 
00271         //   dh. der Impact Parameter 
00272         //
00273 //      real    d = q - Center; 
00274         real    d = norm(y);
00275                 //cout << "Impact parameter " << d << endl;
00276 
00277                 if (d < 1E-8)
00278                 {
00279                 real *u  = initialize(2*N,s);
00280                 real *du = u + N;
00281                          u[i] = 0; 
00282                         du[i] = 0;
00283 
00284 #ifdef  DB_LOG 
00285                         db_logf(21,"SchwarzschildGeodesic: DIRECT VIEW with impact parameter %lg (relative %lg, mass %lg), cannot setup axis!\n",
00286                                 double(d), double(d/M), double(M) );
00287 #endif
00288                         return false;
00289                 }
00290 
00291                 y /= d;
00292                 EQ.Y = tvector4(0, y);
00293 
00294 #ifdef  DB_LOG 
00295                 db_logf(21,"SchwarzschildGeodesic: AXIS: (%lg,%lg,%lg) x (%lg,%lg,%lg) \n",
00296                         SVECP(EQ.X), SVECP(EQ.Y) ); 
00297 #endif
00298 
00299 
00300         real sinphi, cosphi;
00301         PolarPt p0 = EQ(x0, sinphi, cosphi); 
00302 #ifdef  DB_LOG
00303         db_logf(21,"SchwarzschildGeodesic: Initial point at polar coordinates (r=%lg,theta=%lg,phi=%lg)\n", 
00304                 double(p0[p0->r]),double(p0[p0->th]),double(p0[p0->ph]) );
00305 #endif
00306 
00307         real    phi = p0[p0.PHI]; 
00308         real    *u  = initialize(2*N, phi);
00309         real    *du = u + N;
00310         
00311                  u[i] = sinphi/d;       // u (phi0) 
00312                 du[i] = cosphi/d;       // u'(phi0) 
00313 #ifdef  DB_LOG 
00314                 db_logf(21,"SchwarzschildGeodesic: sinphi=%lg  cosphi=%lg d=%lg\n",
00315                         double(sinphi), double(cosphi), double(d) );
00316 
00317                 //cout << "u(0)= " << u[i] << "  u'(0)=" << du[0] << endl;
00318 #endif 
00319                 return true;
00320         }
00321 
00326         void Accel(real, const real *x, const real *v, real *d2x_ds2)
00327         {
00328                 for(unsigned int i=0; i<nPaths(); i++)
00329                 {
00330                         d2x_ds2[i] = 3*M*x[i]*x[i]-x[i]; // ddy == y''=3my^2-y
00331                 }
00332         }
00333 
00334         CartesianPt     position() const
00335         {
00336         PolarPt P; 
00337                 P = EQ.Center[P.T], 1/q(0), 0, s1();
00338 
00339                 return EQ( P );
00340         }
00341 
00342 
00343         CartesianVec velocity() const
00344         {
00345         real    phi = s1(),
00346                   u = q(0),
00347                  du = q(1),
00348              sinphi = sin(phi),
00349              cosphi = cos(phi);
00350 
00351         double  r_sin_delta = du * sinphi - u * cosphi,
00352                 r_cos_delta =  u * sinphi +du * cosphi; 
00353 
00354                 return r_cos_delta * EQ.X + r_sin_delta * EQ.Y; 
00355         }
00356 
00357         CartesianPt     position(real phi) const
00358         {
00359         PolarPt P; 
00360                 P = EQ.Center[P.T],
00361                     1/q(0, phi),
00362                     0,
00363                     phi;
00364 
00365                 return EQ( P );
00366         }
00367 
00368 
00369         CartesianVec velocity(real phi) const
00370         {
00371         real      u = q(0, phi),
00372                  du = q(1, phi),
00373              sinphi = sin(phi),
00374              cosphi = cos(phi);
00375 
00376         double  r_sin_delta = du * sinphi - u * cosphi,
00377                 r_cos_delta =  u * sinphi +du * cosphi; 
00378 
00379                 return r_cos_delta * EQ.X + r_sin_delta * EQ.Y; 
00380         }
00381 
00382 
00383 };
00384 
00385 } // namespace Vecal
00386 
00387 #endif // __SCHWARZSCHILD_GEODESIC_HPP