/* File: Phys.java University of Applied Science Berne,HTA-Biel/Bienne, Computer Science Department. Diploma thesis J3D Solar System Simulator Originally written by Marcel Portner & Bernhard Hari (c) 2000 CVS - Information : $Header: /var/cvsreps/projects/c450/2000/sss3d/source_diploma/sss3d/utils/astronomy/Kepler.java,v 1.4 2000/12/13 13:42:48 portm Exp $ $Author: portm $ $Date: 2000/12/13 13:42:48 $ $State: Exp $ */ package sss3d.utils.astronomy; import sss3d.calculations.constants.AstronomicalConstants; import sss3d.calculations.*; import javax.vecmath.Matrix3d; /** * This class handle the two body problem. * * @author Marcel Portner & Bernhard Hari * @version $Revision: 1.4 $ */ public class Kepler { /** * Constructor */ public Kepler() { } /** * Calculate the eccentric anomaly for elliptical ways. * * @param m middle anomaly in [rad]. * @param e eccentric way [0,1[. * * @return eccentric anomaly in [rad]. */ public double eccAnom(double m, double e) { int maxit = 15; double eps = 100.0 * AstronomicalConstants.EPSILON; int i = 0; double _E, f; // Startwert double _M = MoreMath.modulo(m, MoreMath.PI2); if(e < 0.8) { _E = _M; } else { _E = StrictMath.PI; } // Iteration do { f = _E - e * StrictMath.sin(_E) - _M; _E = _E - f / (1.0 - e * StrictMath.cos(_E) ); i++; if(i == maxit) { System.out.println("Konvergenzprobleme in eccAnom"); break; } } while(StrictMath.abs(f) > eps); return _E; } /** * Calculate the eccentric anomaly for hyperbolic ways. * * @param mh middle anomaly in [rad]. * @param e eccentric way [0,1[. * * @return eccentric anomaly in [rad]. */ public double hypAnom(double mh, double e) { int maxit = 15; double eps = 100.0 * AstronomicalConstants.EPSILON; int i = 0; double _H, f; // Startwert _H = StrictMath.log(2.0 * StrictMath.abs(mh) / e + 1.8); if(mh < 0.0) { _H = -_H; } // Iteration do { f = e * MoreMath.sinh(_H) - _H - mh; _H = _H - f / (e * MoreMath.cosh(_H) - 1.0); ++i; if(i == maxit) { System.out.println("Konvergenzprobleme in hypAnom"); break; } } while(StrictMath.abs(f) > eps * (1.0 + StrictMath.abs(_H + mh))); return _H; } /** * Calculate the place- and velocity vector for elliptical ways. * * @param gm product of the constant gravitation and the central mass. * @param m middle anomaly in [rad]. * @param a half axle of the way in [AE]. * @param e eccentric way < 1. * * @return an array with the place- and velocity vector.
* Vec3D[0] = place vector in [AE].
* Vec3D[1] = velocity vector in [AE / d]. */ public Vec3D[] ellip(double gm, double m, double a, double e) { double k = StrictMath.sqrt(gm / a); double _E = eccAnom(m, e); double cosE = StrictMath.cos(_E); double sinE = StrictMath.sin(_E); double fac = StrictMath.sqrt((1.0 - e) * (1.0 + e)); double rho = 1.0 - e * cosE; Vec3D[] vec = new Vec3D[2]; vec[0] = new Vec3D(a * (cosE - e), a * fac * sinE, 0.0); vec[1] = new Vec3D(-k * sinE / rho, k * fac * cosE / rho, 0.0); return vec; } /** * Calculate the place- and velocity vector for hyperbolic ways. * * @param gm product of the constant gravitation and the central mass. * @param t0 time of perihel transit in julianish century. * @param t calculation time in julianish century. * @param a half axle of the way in [AE]. * @param e eccentric way > 1. * * @return an array with the place- and velocity vector.
* Vec3D[0] = place vector in [AE].
* Vec3D[1] = velocity vector in [AE / d]. */ public Vec3D[] hyperb(double gm, double t0, double t, double a, double e) { double aa = StrictMath.abs(a); double k = StrictMath.sqrt(gm / aa); double mh = k * (t - t0) / aa; double _H = hypAnom(mh, e); double coshH = MoreMath.cosh(_H); double sinhH = MoreMath.sinh(_H); double fac = StrictMath.sqrt((e + 1.0) * (e - 1.0)); double rho = e * coshH - 1.0; Vec3D[] vec = new Vec3D[2]; vec[0] = new Vec3D(aa * (e - coshH), aa * fac * sinhH, 0.0); vec[1] = new Vec3D(-k * sinhH / rho, k * fac * coshH / rho, 0.0); return vec; } /** * Get the difference between the ephemeriden time and the world time. * This method can only calculate the difference of this time from 1825 to 2005. * * @param e2 eccentric anomaly squared (e2 = e * e) in [rad^2]. * * @return an array with the values:
* double[0] = sin(e) / e.
* double[1] = (1 - cos(e)) / e^2.
* double[2] = (e - sin(e)) / e^3. */ public double[] stumpff(double e2) { double eps = 100.0 * AstronomicalConstants.EPSILON; double[] c = new double[3]; c[0] = 0.0; c[1] = 0.0; c[2] = 0.0; double add = 1.0; double n = 1.0; do { c[0] += add; add /= (2.0 * n); c[1] += add; add /= (2.0 * n + 1.0); c[2] += add; add *= -e2; n += 1.0; } while(StrictMath.abs(add) >= eps); return c; } /** * Calculate the place- and velocity vector for parabolically ways. * * @param gm product of the constant gravitation and the central mass. * @param t0 time of perihel transit in julianish century. * @param t calculation time in julianish century. * @param q perihel distance in [AE]. * @param e eccentric way ~ 1. * * @return an array with the place- and velocity vector.
* Vec3D[0] = place vector in [AE].
* Vec3D[1] = velocity vector in [AE / d]. */ public Vec3D[] parab(double gm, double t0, double t, double q, double e) { int maxit = 15; double eps = 100.0 * AstronomicalConstants.EPSILON; int i = 0; double e2 = 0.0; double e20, u, u2; double[] c; double fac = 0.5 * e; double k = StrictMath.sqrt(gm / (q * (1.0 + e))); double tau = StrictMath.sqrt(gm) * (t - t0); do { i++; e20 = e2; double a = 1.5 * StrictMath.sqrt(fac / (q * q * q)) * tau; double b = StrictMath.pow(StrictMath.sqrt(a * a + 1.0) + a, 1.0 / 3.0 ); u = b - 1.0 / b; u2 = u * u; e2 = u2 * (1.0 - e) / fac; c = stumpff(e2); fac = 3.0 * e * c[2]; if(i == maxit) { System.out.println("Konvergenzprobleme in parab"); break; } } while(StrictMath.abs(e2 - e20) >= eps); double _R = q * (1.0 + u2 * c[1] * e / fac); Vec3D[] vec = new Vec3D[2]; vec[0] = new Vec3D(q * (1.0 - u2 * c[1] / fac), q * StrictMath.sqrt((1.0 + e) / fac) * u * c[0], 0.0); vec[1] = new Vec3D(-k * vec[0].y / _R, k * (vec[0].x / _R + e), 0.0); return vec; } /** * Calculate the place- and velocity vector for the kepler ways based on ecliptic. * * @param gm product of the constant gravitation and the central mass. * @param t0 time of perihel transit in julianish century. * @param t calculation time in julianish century. * @param q perihel distance in [AE]. * @param e eccentric way. * @param pqr Transform matrix of the plane way -> ecliptic (gauss vector). * * @return an array with the place- and velocity vector.
* Vec3D[0] = place vector in [AE].
* Vec3D[1] = velocity vector in [AE / d]. */ public Vec3D[] kepler(double gm, double t0, double t, double q, double e, Matrix3d pqr) { double m0 = 0.1; // [rad] double eps = 0.1; Vec3D[] vec; double delta = StrictMath.abs(1.0 - e); double invax = delta / q; double tau = StrictMath.sqrt(gm) * (t - t0); double m = tau * StrictMath.sqrt(invax * invax * invax); if((m < m0) && (delta < eps)) { vec = parab(gm, t0, t, q, e); } else if(e < 1.0) { vec = ellip(gm, m, 1.0 / invax, e); } else { vec = hyperb(gm, t0, t, 1.0 / invax, e); } vec[0].mul(pqr); vec[1].mul(pqr); return vec; } /** * Calculate the transform matrix of the coordinate system in the plane way * to ecliptical coordinate. * * @param h the length of ascending nodes of the way in [rad]. * @param i inclination of the way to the ecliptic in [rad]. * @param j argument of the perihel in [rad]. * * @return a transform matrix with the gauss vectors p, q and r. */ public Matrix3d gaussVec(double h, double i, double j) { Matrix3d mat1 = new Matrix3d(); Matrix3d mat2 = new Matrix3d(); Matrix3d mat3 = new Matrix3d(); mat1.setIdentity(); mat2.setIdentity(); mat3.setIdentity(); // R_z(-h) * R_x(-i) * R_z(-j) mat1.rotZ(-h); mat2.rotX(-i); mat3.rotZ(-j); mat3.mul(mat2); mat3.mul(mat1); return mat3; } /** * Calculate the elements of a elliptical way of place- and velocity vector. * * @param gm product of the constant gravitation and the central mass. * @param r heliocentrically ecliptical place in [AE]. * @param v heliocentrically ecliptical velocity in [AE / d]. * * @return a double array with the follow values:
* double[0] = big half axle of the way in [AE].
* double[1] = eccentric way.
* double[2] = inclination of the way to the ecliptic in [rad].
* double[3] = the length of ascending nodes of the way in [rad].
* double[4] = argument of the perihel in [rad].
* double[5] = middle anomaly in [rad].
*/ public double[] elements(double gm, Vec3D r, Vec3D v) { double[] result = new double[6]; Vec3D vec = new Vec3D(); vec.cross(r, v); // Flaechengeschwindigkeit double h = vec.norm(); result[3] = StrictMath.atan2(vec.x, -vec.y); // Laenge aufst. Knoten result[2] = StrictMath.atan2(StrictMath.sqrt(vec.x * vec.x + vec.y * vec.y), vec.z); // Bahnneigung double u = StrictMath.atan2( r.z * h, -r.x * vec.y + r.y * vec.x); // Argument der Breite double _R = r.norm(); // Entfernung double v2 = v.dot(v); // Quadrat der Geschw. result[0] = 1.0 / (2.0 / _R - v2 / gm); // Grosse Halbachse double eCosE = 1.0 - _R / result[0]; // e*cos(E) double eSinE = r.dot(v) / StrictMath.sqrt(gm * result[0]); // e*sin(E) double e2 = eCosE * eCosE + eSinE * eSinE; result[1] = StrictMath.sqrt(e2); // Exzentrizitaet double e = StrictMath.atan2(eSinE, eCosE); // Exzentrische Anomalie result[5] = e - eSinE; // Mittlere Anomalie double nu = StrictMath.atan2(StrictMath.sqrt(1.0 - e2) * eSinE, eCosE - e2); // Wahre Anomalie result[4] = u - nu; // Argument des Perihels if(result[3] < 0.0) { result[3] += MoreMath.PI2; } if(result[4] < 0.0) { result[4] += MoreMath.PI2; } if(result[5] < 0.0) { result[5] += MoreMath.PI2; } return result; } /** * Calculate the elements of a kepler way from two given places. * * @param gm product of the constant gravitation and the central mass. * @param mjd_a time of the passage at place A [mjd]. * @param mjd_b time of the passage at place B [mjd]. * @param r_a place A in heliocentrically ecliptical coordinate in [AU]. * @param r_b place B in heliocentrically ecliptical coordinate in [AU]. * * @return a double array with the follow values:
* double[0] = time of the perihel transit.
* double[1] = perihel distance in [AE].
* double[2] = inclination of the way to the ecliptic in [rad].
* double[3] = the length of ascending nodes of the way in [rad].
* double[4] = argument of the perihel in [rad].
* double[5] = middle anomaly in [rad].
*/ public double[] elements(double gm, double mjd_a, double mjd_b, Vec3D r_a, Vec3D r_b) { double[] result = new double[6]; // Berechnen Vektor r_0 (Anteil von r_b, der senkrecht auf r_a steht) // und die Betraege der Vektoren r_a,r_b und r_0 double s_a = r_a.norm(); Vec3D e_a = new Vec3D(); e_a.scale(1.0 / s_a, r_a); double s_b = r_b.norm(); double fac = r_b.dot(e_a); //r_0 = r_b - fac * e_a; Vec3D r_0 = new Vec3D(); r_0.scale(fac, e_a); r_0.sub(r_b, r_0); double s_0 = r_0.norm(); Vec3D e_0 = new Vec3D(); e_0.scale(1.0 / s_0, r_0); // Bahnneigung und aufsteigender Knoten Vec3D r = new Vec3D(); r.cross(e_a, e_0); result[2] = StrictMath.PI / 2.0 - r.getElevation(); result[3] = MoreMath.modulo(StrictMath.PI / 2.0 + r.getAzimut(), MoreMath.PI2); double u; if(result[2] == 0.0) { u = StrictMath.atan2(r_a.y, r_a.x); } else { u = StrictMath.atan2( e_0.x * r.y - e_0.y * r.x, -e_a.x * r.y + e_a.y * r.x); } // Semilatus rectum double tau = StrictMath.sqrt(gm) * StrictMath.abs(mjd_b - mjd_a); double eta = findEta(r_a, r_b, tau); double p = StrictMath.pow(s_a * s_0 * eta / tau, 2); // Exzentrizitaet, wahre Anomalie und Argument des Perihels double cos_dnu = fac / s_b; double sin_dnu = s_0 / s_b; double ecos_nu = p / s_a - 1.0; double esin_nu = (ecos_nu * cos_dnu - (p / s_b - 1.0)) / sin_dnu; result[5] = StrictMath.sqrt(ecos_nu * ecos_nu + esin_nu * esin_nu); double nu = StrictMath.atan2(esin_nu, ecos_nu); result[4] = MoreMath.modulo(u - nu, MoreMath.PI2); // Periheldistanz, grosse Halbachse und mittlere Bewegung result[1] = p / (1.0 + result[5]); double a = result[1] / (1.0 - result[5]); double n = StrictMath.sqrt(gm / StrictMath.abs(a * a * a) ); double m; // Mittlere Anomalie und Zeitpunkt des Periheldurchgangs if (result[5] < 1.0) { double e = StrictMath.atan2(StrictMath.sqrt((1.0 - result[5]) * (1.0 + result[5])) * esin_nu, ecos_nu + result[5] * result[5]); m = e - result[5] * StrictMath.sin(e); } else { double sinhH = StrictMath.sqrt((result[5] - 1.0) * (result[5] + 1.0)) * esin_nu / (result[5] + result[5] * ecos_nu); m = result[5] * sinhH - StrictMath.log(sinhH + StrictMath.sqrt(1.0 + sinhH * sinhH)); } result[0] = mjd_a - m / n; return result; } /** * Calculate the sector to triangle ratio of two given places and the meantime. * * @param r_a place at time A in [AE]. * @param r_b place at time B in [AE]. * @param tau time between the passage from A and B (kGauss * dT in [d]). * * @return the sector to triangle ratio. */ public double findEta(Vec3D r_a, Vec3D r_b, double tau) { int maxit = 30; double delta = 100.0 * AstronomicalConstants.EPSILON; double s_a = r_a.norm(); double s_b = r_b.norm(); double kappa = StrictMath.sqrt(2.0 * (s_a * s_b + r_a.dot(r_b)) ); double m = tau * tau / StrictMath.pow(kappa, 3); double l = (s_a + s_b) / (2.0 * kappa) - 0.5; double eta_min = StrictMath.sqrt(m / (l + 1.0)); // Start mit der Hansen'schen Naeherung double eta2 = (12.0 + 10.0 * StrictMath.sqrt(1.0 + (44.0 / 9.0) * m / (l + 5.0 / 6.0))) / 22.0; double eta1 = eta2 + 0.1; // Sekantenverfahren double f1 = f(eta1, m, l); double f2 = f(eta2, m, l); int i = 0; while(Math.abs(f2 - f1) > delta) { double d_eta = -f2 * (eta2 - eta1) / (f2 - f1); eta1 = eta2; f1 = f2; while(eta2 + d_eta <= eta_min) { d_eta *= 0.5; } eta2 += d_eta; f2 = f(eta2, m, l); ++i; if(i == maxit) { System.out.println("Konvergenzprobleme in findEta");; break; } } return eta2; } /** * Locale: used from the findEta method. * * @param eta a double value. * @param m a double value. * @param l a double value. * * @return the result of this arithmetic:
* f = 1 - eta + (m / eta^2) * w(m / eta^2-l). */ private double f(double eta, double m, double l) { double _W = 4.0 / 3.0; double eps = 100.0 * AstronomicalConstants.EPSILON; double w = m / (eta * eta) - l; if(StrictMath.abs(w) < 0.1) { // Reihenentwicklung double a = _W; double n = 0.0; do { n += 1.0; a *= w * (n + 2.0) / (n + 1.5); _W += a; } while(StrictMath.abs(a) >= eps); } else { double g; if(w > 0.0) { g = 2.0 * StrictMath.asin(StrictMath.sqrt(w)); _W = (2.0 * g - StrictMath.sin(2.0 * g)) / StrictMath.pow(StrictMath.sin(g), 3); } else { g = 2.0 * StrictMath.log(StrictMath.sqrt(-w) + StrictMath.sqrt(1.0 - w)); // =2.0*arsinh(sqrt(-w)) _W = (MoreMath.sinh(2.0 * g) - 2.0 * g) / StrictMath.pow(MoreMath.sinh(g), 3); } } return 1.0 - eta + (w + l) * _W; } }