├── .gitattributes ├── C ├── makefile ├── sofa.h ├── sofa_a.c └── sofam.h ├── Example ├── Application in CHES │ ├── Fig4.png │ ├── Fig4.py │ └── input.xls ├── Precession-nutation.py ├── coordinate.py └── time.py ├── LICENSE.md ├── PyMsOfa introduction.md ├── README.md ├── cffi ├── PyMsOfa.py ├── PyMsOfa_astrometry.py ├── PyMsOfa_basic.py ├── PyMsOfa_earth_attitude.py ├── PyMsOfa_t.py └── PyMsOfa_time.py ├── ctypes ├── PyMsOfa.py ├── PyMsOfa_astrometry.py ├── PyMsOfa_basic.py ├── PyMsOfa_earth_attitude.py ├── PyMsOfa_t.py └── PyMsOfa_time.py └── python ├── PyMsOfa.py ├── PyMsOfa_astrometry.py ├── PyMsOfa_basic.py ├── PyMsOfa_earth_attitude.py ├── PyMsOfa_t.py └── PyMsOfa_time.py /.gitattributes: -------------------------------------------------------------------------------- 1 | *.c linguist-language=Python 2 | -------------------------------------------------------------------------------- /C/makefile: -------------------------------------------------------------------------------- 1 | libsofa_c.so: sofa.h sofa_a.c sofam.h 2 | gcc -shared -fPIC -o libsofa_c.so sofa_a.c 3 | clean: 4 | rm -r libsofa_c.so 5 | -------------------------------------------------------------------------------- /C/sofa.h: -------------------------------------------------------------------------------- 1 | #ifndef SOFAHDEF 2 | #define SOFAHDEF 3 | 4 | /* 5 | ** - - - - - - - 6 | ** s o f a . h 7 | ** - - - - - - - 8 | ** 9 | ** Prototype function declarations for SOFA library. 10 | ** 11 | ** This file is part of the International Astronomical Union's 12 | ** SOFA (Standards of Fundamental Astronomy) software collection. 13 | ** 14 | ** This revision: 2023 April 16 15 | ** 16 | ** SOFA release 2023-10-11 17 | ** 18 | ** Copyright (C) 2023 IAU SOFA Board. See notes at end. 19 | */ 20 | 21 | #include "math.h" 22 | 23 | #ifdef __cplusplus 24 | extern "C" { 25 | #endif 26 | 27 | /* Star-independent astrometry parameters */ 28 | typedef struct { 29 | double pmt; /* PM time interval (SSB, Julian years) */ 30 | double eb[3]; /* SSB to observer (vector, au) */ 31 | double eh[3]; /* Sun to observer (unit vector) */ 32 | double em; /* distance from Sun to observer (au) */ 33 | double v[3]; /* barycentric observer velocity (vector, c) */ 34 | double bm1; /* sqrt(1-|v|^2): reciprocal of Lorenz factor */ 35 | double bpn[3][3]; /* bias-precession-nutation matrix */ 36 | double along; /* longitude + s' + dERA(DUT) (radians) */ 37 | double phi; /* geodetic latitude (radians) */ 38 | double xpl; /* polar motion xp wrt local meridian (radians) */ 39 | double ypl; /* polar motion yp wrt local meridian (radians) */ 40 | double sphi; /* sine of geodetic latitude */ 41 | double cphi; /* cosine of geodetic latitude */ 42 | double diurab; /* magnitude of diurnal aberration vector */ 43 | double eral; /* "local" Earth rotation angle (radians) */ 44 | double refa; /* refraction constant A (radians) */ 45 | double refb; /* refraction constant B (radians) */ 46 | } iauASTROM; 47 | /* (Vectors eb, eh, em and v are all with respect to BCRS axes.) */ 48 | 49 | /* Body parameters for light deflection */ 50 | typedef struct { 51 | double bm; /* mass of the body (solar masses) */ 52 | double dl; /* deflection limiter (radians^2/2) */ 53 | double pv[2][3]; /* barycentric PV of the body (au, au/day) */ 54 | } iauLDBODY; 55 | 56 | /* Astronomy/Calendars */ 57 | int iauCal2jd(int iy, int im, int id, double *djm0, double *djm); 58 | double iauEpb(double dj1, double dj2); 59 | void iauEpb2jd(double epb, double *djm0, double *djm); 60 | double iauEpj(double dj1, double dj2); 61 | void iauEpj2jd(double epj, double *djm0, double *djm); 62 | int iauJd2cal(double dj1, double dj2, 63 | int *iy, int *im, int *id, double *fd); 64 | int iauJdcalf(int ndp, double dj1, double dj2, int iymdf[4]); 65 | 66 | /* Astronomy/Astrometry */ 67 | void iauAb(double pnat[3], double v[3], double s, double bm1, 68 | double ppr[3]); 69 | void iauApcg(double date1, double date2, 70 | double ebpv[2][3], double ehp[3], 71 | iauASTROM *astrom); 72 | void iauApcg13(double date1, double date2, iauASTROM *astrom); 73 | void iauApci(double date1, double date2, 74 | double ebpv[2][3], double ehp[3], 75 | double x, double y, double s, 76 | iauASTROM *astrom); 77 | void iauApci13(double date1, double date2, 78 | iauASTROM *astrom, double *eo); 79 | void iauApco(double date1, double date2, 80 | double ebpv[2][3], double ehp[3], 81 | double x, double y, double s, double theta, 82 | double elong, double phi, double hm, 83 | double xp, double yp, double sp, 84 | double refa, double refb, 85 | iauASTROM *astrom); 86 | int iauApco13(double utc1, double utc2, double dut1, 87 | double elong, double phi, double hm, double xp, double yp, 88 | double phpa, double tc, double rh, double wl, 89 | iauASTROM *astrom, double *eo); 90 | void iauApcs(double date1, double date2, double pv[2][3], 91 | double ebpv[2][3], double ehp[3], 92 | iauASTROM *astrom); 93 | void iauApcs13(double date1, double date2, double pv[2][3], 94 | iauASTROM *astrom); 95 | void iauAper(double theta, iauASTROM *astrom); 96 | void iauAper13(double ut11, double ut12, iauASTROM *astrom); 97 | void iauApio(double sp, double theta, 98 | double elong, double phi, double hm, double xp, double yp, 99 | double refa, double refb, 100 | iauASTROM *astrom); 101 | int iauApio13(double utc1, double utc2, double dut1, 102 | double elong, double phi, double hm, double xp, double yp, 103 | double phpa, double tc, double rh, double wl, 104 | iauASTROM *astrom); 105 | void iauAtcc13(double rc, double dc, 106 | double pr, double pd, double px, double rv, 107 | double date1, double date2, 108 | double *ra, double *da); 109 | void iauAtccq(double rc, double dc, 110 | double pr, double pd, double px, double rv, 111 | iauASTROM *astrom, double *ra, double *da); 112 | void iauAtci13(double rc, double dc, 113 | double pr, double pd, double px, double rv, 114 | double date1, double date2, 115 | double *ri, double *di, double *eo); 116 | void iauAtciq(double rc, double dc, double pr, double pd, 117 | double px, double rv, iauASTROM *astrom, 118 | double *ri, double *di); 119 | void iauAtciqn(double rc, double dc, double pr, double pd, 120 | double px, double rv, iauASTROM *astrom, 121 | int n, iauLDBODY b[], double *ri, double *di); 122 | void iauAtciqz(double rc, double dc, iauASTROM *astrom, 123 | double *ri, double *di); 124 | int iauAtco13(double rc, double dc, 125 | double pr, double pd, double px, double rv, 126 | double utc1, double utc2, double dut1, 127 | double elong, double phi, double hm, double xp, double yp, 128 | double phpa, double tc, double rh, double wl, 129 | double *aob, double *zob, double *hob, 130 | double *dob, double *rob, double *eo); 131 | void iauAtic13(double ri, double di, 132 | double date1, double date2, 133 | double *rc, double *dc, double *eo); 134 | void iauAticq(double ri, double di, iauASTROM *astrom, 135 | double *rc, double *dc); 136 | void iauAticqn(double ri, double di, iauASTROM *astrom, 137 | int n, iauLDBODY b[], double *rc, double *dc); 138 | int iauAtio13(double ri, double di, 139 | double utc1, double utc2, double dut1, 140 | double elong, double phi, double hm, double xp, double yp, 141 | double phpa, double tc, double rh, double wl, 142 | double *aob, double *zob, double *hob, 143 | double *dob, double *rob); 144 | void iauAtioq(double ri, double di, iauASTROM *astrom, 145 | double *aob, double *zob, 146 | double *hob, double *dob, double *rob); 147 | int iauAtoc13(const char *type, double ob1, double ob2, 148 | double utc1, double utc2, double dut1, 149 | double elong, double phi, double hm, double xp, double yp, 150 | double phpa, double tc, double rh, double wl, 151 | double *rc, double *dc); 152 | int iauAtoi13(const char *type, double ob1, double ob2, 153 | double utc1, double utc2, double dut1, 154 | double elong, double phi, double hm, double xp, double yp, 155 | double phpa, double tc, double rh, double wl, 156 | double *ri, double *di); 157 | void iauAtoiq(const char *type, 158 | double ob1, double ob2, iauASTROM *astrom, 159 | double *ri, double *di); 160 | void iauLd(double bm, double p[3], double q[3], double e[3], 161 | double em, double dlim, double p1[3]); 162 | void iauLdn(int n, iauLDBODY b[], double ob[3], double sc[3], 163 | double sn[3]); 164 | void iauLdsun(double p[3], double e[3], double em, double p1[3]); 165 | void iauPmpx(double rc, double dc, double pr, double pd, 166 | double px, double rv, double pmt, double pob[3], 167 | double pco[3]); 168 | int iauPmsafe(double ra1, double dec1, double pmr1, double pmd1, 169 | double px1, double rv1, 170 | double ep1a, double ep1b, double ep2a, double ep2b, 171 | double *ra2, double *dec2, double *pmr2, double *pmd2, 172 | double *px2, double *rv2); 173 | void iauPvtob(double elong, double phi, double height, double xp, 174 | double yp, double sp, double theta, double pv[2][3]); 175 | void iauRefco(double phpa, double tc, double rh, double wl, 176 | double *refa, double *refb); 177 | 178 | /* Astronomy/Ephemerides */ 179 | int iauEpv00(double date1, double date2, 180 | double pvh[2][3], double pvb[2][3]); 181 | void iauMoon98(double date1, double date2, double pv[2][3]); 182 | int iauPlan94(double date1, double date2, int np, double pv[2][3]); 183 | 184 | /* Astronomy/FundamentalArgs */ 185 | double iauFad03(double t); 186 | double iauFae03(double t); 187 | double iauFaf03(double t); 188 | double iauFaju03(double t); 189 | double iauFal03(double t); 190 | double iauFalp03(double t); 191 | double iauFama03(double t); 192 | double iauFame03(double t); 193 | double iauFane03(double t); 194 | double iauFaom03(double t); 195 | double iauFapa03(double t); 196 | double iauFasa03(double t); 197 | double iauFaur03(double t); 198 | double iauFave03(double t); 199 | 200 | /* Astronomy/PrecNutPolar */ 201 | void iauBi00(double *dpsibi, double *depsbi, double *dra); 202 | void iauBp00(double date1, double date2, 203 | double rb[3][3], double rp[3][3], double rbp[3][3]); 204 | void iauBp06(double date1, double date2, 205 | double rb[3][3], double rp[3][3], double rbp[3][3]); 206 | void iauBpn2xy(double rbpn[3][3], double *x, double *y); 207 | void iauC2i00a(double date1, double date2, double rc2i[3][3]); 208 | void iauC2i00b(double date1, double date2, double rc2i[3][3]); 209 | void iauC2i06a(double date1, double date2, double rc2i[3][3]); 210 | void iauC2ibpn(double date1, double date2, double rbpn[3][3], 211 | double rc2i[3][3]); 212 | void iauC2ixy(double date1, double date2, double x, double y, 213 | double rc2i[3][3]); 214 | void iauC2ixys(double x, double y, double s, double rc2i[3][3]); 215 | void iauC2t00a(double tta, double ttb, double uta, double utb, 216 | double xp, double yp, double rc2t[3][3]); 217 | void iauC2t00b(double tta, double ttb, double uta, double utb, 218 | double xp, double yp, double rc2t[3][3]); 219 | void iauC2t06a(double tta, double ttb, double uta, double utb, 220 | double xp, double yp, double rc2t[3][3]); 221 | void iauC2tcio(double rc2i[3][3], double era, double rpom[3][3], 222 | double rc2t[3][3]); 223 | void iauC2teqx(double rbpn[3][3], double gst, double rpom[3][3], 224 | double rc2t[3][3]); 225 | void iauC2tpe(double tta, double ttb, double uta, double utb, 226 | double dpsi, double deps, double xp, double yp, 227 | double rc2t[3][3]); 228 | void iauC2txy(double tta, double ttb, double uta, double utb, 229 | double x, double y, double xp, double yp, 230 | double rc2t[3][3]); 231 | double iauEo06a(double date1, double date2); 232 | double iauEors(double rnpb[3][3], double s); 233 | void iauFw2m(double gamb, double phib, double psi, double eps, 234 | double r[3][3]); 235 | void iauFw2xy(double gamb, double phib, double psi, double eps, 236 | double *x, double *y); 237 | void iauLtp(double epj, double rp[3][3]); 238 | void iauLtpb(double epj, double rpb[3][3]); 239 | void iauLtpecl(double epj, double vec[3]); 240 | void iauLtpequ(double epj, double veq[3]); 241 | void iauNum00a(double date1, double date2, double rmatn[3][3]); 242 | void iauNum00b(double date1, double date2, double rmatn[3][3]); 243 | void iauNum06a(double date1, double date2, double rmatn[3][3]); 244 | void iauNumat(double epsa, double dpsi, double deps, double rmatn[3][3]); 245 | void iauNut00a(double date1, double date2, double *dpsi, double *deps); 246 | void iauNut00b(double date1, double date2, double *dpsi, double *deps); 247 | void iauNut06a(double date1, double date2, double *dpsi, double *deps); 248 | void iauNut80(double date1, double date2, double *dpsi, double *deps); 249 | void iauNutm80(double date1, double date2, double rmatn[3][3]); 250 | double iauObl06(double date1, double date2); 251 | double iauObl80(double date1, double date2); 252 | void iauP06e(double date1, double date2, 253 | double *eps0, double *psia, double *oma, double *bpa, 254 | double *bqa, double *pia, double *bpia, 255 | double *epsa, double *chia, double *za, double *zetaa, 256 | double *thetaa, double *pa, 257 | double *gam, double *phi, double *psi); 258 | void iauPb06(double date1, double date2, 259 | double *bzeta, double *bz, double *btheta); 260 | void iauPfw06(double date1, double date2, 261 | double *gamb, double *phib, double *psib, double *epsa); 262 | void iauPmat00(double date1, double date2, double rbp[3][3]); 263 | void iauPmat06(double date1, double date2, double rbp[3][3]); 264 | void iauPmat76(double date1, double date2, double rmatp[3][3]); 265 | void iauPn00(double date1, double date2, double dpsi, double deps, 266 | double *epsa, 267 | double rb[3][3], double rp[3][3], double rbp[3][3], 268 | double rn[3][3], double rbpn[3][3]); 269 | void iauPn00a(double date1, double date2, 270 | double *dpsi, double *deps, double *epsa, 271 | double rb[3][3], double rp[3][3], double rbp[3][3], 272 | double rn[3][3], double rbpn[3][3]); 273 | void iauPn00b(double date1, double date2, 274 | double *dpsi, double *deps, double *epsa, 275 | double rb[3][3], double rp[3][3], double rbp[3][3], 276 | double rn[3][3], double rbpn[3][3]); 277 | void iauPn06(double date1, double date2, double dpsi, double deps, 278 | double *epsa, 279 | double rb[3][3], double rp[3][3], double rbp[3][3], 280 | double rn[3][3], double rbpn[3][3]); 281 | void iauPn06a(double date1, double date2, 282 | double *dpsi, double *deps, double *epsa, 283 | double rb[3][3], double rp[3][3], double rbp[3][3], 284 | double rn[3][3], double rbpn[3][3]); 285 | void iauPnm00a(double date1, double date2, double rbpn[3][3]); 286 | void iauPnm00b(double date1, double date2, double rbpn[3][3]); 287 | void iauPnm06a(double date1, double date2, double rnpb[3][3]); 288 | void iauPnm80(double date1, double date2, double rmatpn[3][3]); 289 | void iauPom00(double xp, double yp, double sp, double rpom[3][3]); 290 | void iauPr00(double date1, double date2, 291 | double *dpsipr, double *depspr); 292 | void iauPrec76(double date01, double date02, 293 | double date11, double date12, 294 | double *zeta, double *z, double *theta); 295 | double iauS00(double date1, double date2, double x, double y); 296 | double iauS00a(double date1, double date2); 297 | double iauS00b(double date1, double date2); 298 | double iauS06(double date1, double date2, double x, double y); 299 | double iauS06a(double date1, double date2); 300 | double iauSp00(double date1, double date2); 301 | void iauXy06(double date1, double date2, double *x, double *y); 302 | void iauXys00a(double date1, double date2, 303 | double *x, double *y, double *s); 304 | void iauXys00b(double date1, double date2, 305 | double *x, double *y, double *s); 306 | void iauXys06a(double date1, double date2, 307 | double *x, double *y, double *s); 308 | 309 | /* Astronomy/RotationAndTime */ 310 | double iauEe00(double date1, double date2, double epsa, double dpsi); 311 | double iauEe00a(double date1, double date2); 312 | double iauEe00b(double date1, double date2); 313 | double iauEe06a(double date1, double date2); 314 | double iauEect00(double date1, double date2); 315 | double iauEqeq94(double date1, double date2); 316 | double iauEra00(double dj1, double dj2); 317 | double iauGmst00(double uta, double utb, double tta, double ttb); 318 | double iauGmst06(double uta, double utb, double tta, double ttb); 319 | double iauGmst82(double dj1, double dj2); 320 | double iauGst00a(double uta, double utb, double tta, double ttb); 321 | double iauGst00b(double uta, double utb); 322 | double iauGst06(double uta, double utb, double tta, double ttb, 323 | double rnpb[3][3]); 324 | double iauGst06a(double uta, double utb, double tta, double ttb); 325 | double iauGst94(double uta, double utb); 326 | 327 | /* Astronomy/SpaceMotion */ 328 | int iauPvstar(double pv[2][3], double *ra, double *dec, 329 | double *pmr, double *pmd, double *px, double *rv); 330 | int iauStarpv(double ra, double dec, 331 | double pmr, double pmd, double px, double rv, 332 | double pv[2][3]); 333 | 334 | /* Astronomy/StarCatalogs */ 335 | void iauFk425(double r1950, double d1950, 336 | double dr1950, double dd1950, 337 | double p1950, double v1950, 338 | double *r2000, double *d2000, 339 | double *dr2000, double *dd2000, 340 | double *p2000, double *v2000); 341 | void iauFk45z(double r1950, double d1950, double bepoch, 342 | double *r2000, double *d2000); 343 | void iauFk524(double r2000, double d2000, 344 | double dr2000, double dd2000, 345 | double p2000, double v2000, 346 | double *r1950, double *d1950, 347 | double *dr1950, double *dd1950, 348 | double *p1950, double *v1950); 349 | void iauFk52h(double r5, double d5, 350 | double dr5, double dd5, double px5, double rv5, 351 | double *rh, double *dh, 352 | double *drh, double *ddh, double *pxh, double *rvh); 353 | void iauFk54z(double r2000, double d2000, double bepoch, 354 | double *r1950, double *d1950, 355 | double *dr1950, double *dd1950); 356 | void iauFk5hip(double r5h[3][3], double s5h[3]); 357 | void iauFk5hz(double r5, double d5, double date1, double date2, 358 | double *rh, double *dh); 359 | void iauH2fk5(double rh, double dh, 360 | double drh, double ddh, double pxh, double rvh, 361 | double *r5, double *d5, 362 | double *dr5, double *dd5, double *px5, double *rv5); 363 | void iauHfk5z(double rh, double dh, double date1, double date2, 364 | double *r5, double *d5, double *dr5, double *dd5); 365 | int iauStarpm(double ra1, double dec1, 366 | double pmr1, double pmd1, double px1, double rv1, 367 | double ep1a, double ep1b, double ep2a, double ep2b, 368 | double *ra2, double *dec2, 369 | double *pmr2, double *pmd2, double *px2, double *rv2); 370 | 371 | /* Astronomy/EclipticCoordinates */ 372 | void iauEceq06(double date1, double date2, double dl, double db, 373 | double *dr, double *dd); 374 | void iauEcm06(double date1, double date2, double rm[3][3]); 375 | void iauEqec06(double date1, double date2, double dr, double dd, 376 | double *dl, double *db); 377 | void iauLteceq(double epj, double dl, double db, double *dr, double *dd); 378 | void iauLtecm(double epj, double rm[3][3]); 379 | void iauLteqec(double epj, double dr, double dd, double *dl, double *db); 380 | 381 | /* Astronomy/GalacticCoordinates */ 382 | void iauG2icrs(double dl, double db, double *dr, double *dd); 383 | void iauIcrs2g(double dr, double dd, double *dl, double *db); 384 | 385 | /* Astronomy/GeodeticGeocentric */ 386 | int iauEform(int n, double *a, double *f); 387 | int iauGc2gd(int n, double xyz[3], 388 | double *elong, double *phi, double *height); 389 | int iauGc2gde(double a, double f, double xyz[3], 390 | double *elong, double *phi, double *height); 391 | int iauGd2gc(int n, double elong, double phi, double height, 392 | double xyz[3]); 393 | int iauGd2gce(double a, double f, 394 | double elong, double phi, double height, double xyz[3]); 395 | 396 | /* Astronomy/Timescales */ 397 | int iauD2dtf(const char *scale, int ndp, double d1, double d2, 398 | int *iy, int *im, int *id, int ihmsf[4]); 399 | int iauDat(int iy, int im, int id, double fd, double *deltat); 400 | double iauDtdb(double date1, double date2, 401 | double ut, double elong, double u, double v); 402 | int iauDtf2d(const char *scale, int iy, int im, int id, 403 | int ihr, int imn, double sec, double *d1, double *d2); 404 | int iauTaitt(double tai1, double tai2, double *tt1, double *tt2); 405 | int iauTaiut1(double tai1, double tai2, double dta, 406 | double *ut11, double *ut12); 407 | int iauTaiutc(double tai1, double tai2, double *utc1, double *utc2); 408 | int iauTcbtdb(double tcb1, double tcb2, double *tdb1, double *tdb2); 409 | int iauTcgtt(double tcg1, double tcg2, double *tt1, double *tt2); 410 | int iauTdbtcb(double tdb1, double tdb2, double *tcb1, double *tcb2); 411 | int iauTdbtt(double tdb1, double tdb2, double dtr, 412 | double *tt1, double *tt2); 413 | int iauTttai(double tt1, double tt2, double *tai1, double *tai2); 414 | int iauTttcg(double tt1, double tt2, double *tcg1, double *tcg2); 415 | int iauTttdb(double tt1, double tt2, double dtr, 416 | double *tdb1, double *tdb2); 417 | int iauTtut1(double tt1, double tt2, double dt, 418 | double *ut11, double *ut12); 419 | int iauUt1tai(double ut11, double ut12, double dta, 420 | double *tai1, double *tai2); 421 | int iauUt1tt(double ut11, double ut12, double dt, 422 | double *tt1, double *tt2); 423 | int iauUt1utc(double ut11, double ut12, double dut1, 424 | double *utc1, double *utc2); 425 | int iauUtctai(double utc1, double utc2, double *tai1, double *tai2); 426 | int iauUtcut1(double utc1, double utc2, double dut1, 427 | double *ut11, double *ut12); 428 | 429 | /* Astronomy/HorizonEquatorial */ 430 | void iauAe2hd(double az, double el, double phi, 431 | double *ha, double *dec); 432 | void iauHd2ae(double ha, double dec, double phi, 433 | double *az, double *el); 434 | double iauHd2pa(double ha, double dec, double phi); 435 | 436 | /* Astronomy/Gnomonic */ 437 | int iauTpors(double xi, double eta, double a, double b, 438 | double *a01, double *b01, double *a02, double *b02); 439 | int iauTporv(double xi, double eta, double v[3], 440 | double v01[3], double v02[3]); 441 | void iauTpsts(double xi, double eta, double a0, double b0, 442 | double *a, double *b); 443 | void iauTpstv(double xi, double eta, double v0[3], double v[3]); 444 | int iauTpxes(double a, double b, double a0, double b0, 445 | double *xi, double *eta); 446 | int iauTpxev(double v[3], double v0[3], double *xi, double *eta); 447 | 448 | /* VectorMatrix/AngleOps */ 449 | void iauA2af(int ndp, double angle, char *sign, int idmsf[4]); 450 | void iauA2tf(int ndp, double angle, char *sign, int ihmsf[4]); 451 | int iauAf2a(char s, int ideg, int iamin, double asec, double *rad); 452 | double iauAnp(double a); 453 | double iauAnpm(double a); 454 | void iauD2tf(int ndp, double days, char *sign, int ihmsf[4]); 455 | int iauTf2a(char s, int ihour, int imin, double sec, double *rad); 456 | int iauTf2d(char s, int ihour, int imin, double sec, double *days); 457 | 458 | /* VectorMatrix/BuildRotations */ 459 | void iauRx(double phi, double r[3][3]); 460 | void iauRy(double theta, double r[3][3]); 461 | void iauRz(double psi, double r[3][3]); 462 | 463 | /* VectorMatrix/CopyExtendExtract */ 464 | void iauCp(double p[3], double c[3]); 465 | void iauCpv(double pv[2][3], double c[2][3]); 466 | void iauCr(double r[3][3], double c[3][3]); 467 | void iauP2pv(double p[3], double pv[2][3]); 468 | void iauPv2p(double pv[2][3], double p[3]); 469 | 470 | /* VectorMatrix/Initialization */ 471 | void iauIr(double r[3][3]); 472 | void iauZp(double p[3]); 473 | void iauZpv(double pv[2][3]); 474 | void iauZr(double r[3][3]); 475 | 476 | /* VectorMatrix/MatrixOps */ 477 | void iauRxr(double a[3][3], double b[3][3], double atb[3][3]); 478 | void iauTr(double r[3][3], double rt[3][3]); 479 | 480 | /* VectorMatrix/MatrixVectorProducts */ 481 | void iauRxp(double r[3][3], double p[3], double rp[3]); 482 | void iauRxpv(double r[3][3], double pv[2][3], double rpv[2][3]); 483 | void iauTrxp(double r[3][3], double p[3], double trp[3]); 484 | void iauTrxpv(double r[3][3], double pv[2][3], double trpv[2][3]); 485 | 486 | /* VectorMatrix/RotationVectors */ 487 | void iauRm2v(double r[3][3], double w[3]); 488 | void iauRv2m(double w[3], double r[3][3]); 489 | 490 | /* VectorMatrix/SeparationAndAngle */ 491 | double iauPap(double a[3], double b[3]); 492 | double iauPas(double al, double ap, double bl, double bp); 493 | double iauSepp(double a[3], double b[3]); 494 | double iauSeps(double al, double ap, double bl, double bp); 495 | 496 | /* VectorMatrix/SphericalCartesian */ 497 | void iauC2s(double p[3], double *theta, double *phi); 498 | void iauP2s(double p[3], double *theta, double *phi, double *r); 499 | void iauPv2s(double pv[2][3], 500 | double *theta, double *phi, double *r, 501 | double *td, double *pd, double *rd); 502 | void iauS2c(double theta, double phi, double c[3]); 503 | void iauS2p(double theta, double phi, double r, double p[3]); 504 | void iauS2pv(double theta, double phi, double r, 505 | double td, double pd, double rd, 506 | double pv[2][3]); 507 | 508 | /* VectorMatrix/VectorOps */ 509 | double iauPdp(double a[3], double b[3]); 510 | double iauPm(double p[3]); 511 | void iauPmp(double a[3], double b[3], double amb[3]); 512 | void iauPn(double p[3], double *r, double u[3]); 513 | void iauPpp(double a[3], double b[3], double apb[3]); 514 | void iauPpsp(double a[3], double s, double b[3], double apsb[3]); 515 | void iauPvdpv(double a[2][3], double b[2][3], double adb[2]); 516 | void iauPvm(double pv[2][3], double *r, double *s); 517 | void iauPvmpv(double a[2][3], double b[2][3], double amb[2][3]); 518 | void iauPvppv(double a[2][3], double b[2][3], double apb[2][3]); 519 | void iauPvu(double dt, double pv[2][3], double upv[2][3]); 520 | void iauPvup(double dt, double pv[2][3], double p[3]); 521 | void iauPvxpv(double a[2][3], double b[2][3], double axb[2][3]); 522 | void iauPxp(double a[3], double b[3], double axb[3]); 523 | void iauS2xpv(double s1, double s2, double pv[2][3], double spv[2][3]); 524 | void iauSxp(double s, double p[3], double sp[3]); 525 | void iauSxpv(double s, double pv[2][3], double spv[2][3]); 526 | 527 | #ifdef __cplusplus 528 | } 529 | #endif 530 | 531 | #endif 532 | 533 | /*---------------------------------------------------------------------- 534 | ** 535 | ** Copyright (C) 2023 536 | ** Standards of Fundamental Astronomy Board 537 | ** of the International Astronomical Union. 538 | ** 539 | ** ===================== 540 | ** SOFA Software License 541 | ** ===================== 542 | ** 543 | ** NOTICE TO USER: 544 | ** 545 | ** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND 546 | ** CONDITIONS WHICH APPLY TO ITS USE. 547 | ** 548 | ** 1. The Software is owned by the IAU SOFA Board ("SOFA"). 549 | ** 550 | ** 2. Permission is granted to anyone to use the SOFA software for any 551 | ** purpose, including commercial applications, free of charge and 552 | ** without payment of royalties, subject to the conditions and 553 | ** restrictions listed below. 554 | ** 555 | ** 3. You (the user) may copy and distribute SOFA source code to others, 556 | ** and use and adapt its code and algorithms in your own software, 557 | ** on a world-wide, royalty-free basis. That portion of your 558 | ** distribution that does not consist of intact and unchanged copies 559 | ** of SOFA source code files is a "derived work" that must comply 560 | ** with the following requirements: 561 | ** 562 | ** a) Your work shall be marked or carry a statement that it 563 | ** (i) uses routines and computations derived by you from 564 | ** software provided by SOFA under license to you; and 565 | ** (ii) does not itself constitute software provided by and/or 566 | ** endorsed by SOFA. 567 | ** 568 | ** b) The source code of your derived work must contain descriptions 569 | ** of how the derived work is based upon, contains and/or differs 570 | ** from the original SOFA software. 571 | ** 572 | ** c) The names of all routines in your derived work shall not 573 | ** include the prefix "iau" or "sofa" or trivial modifications 574 | ** thereof such as changes of case. 575 | ** 576 | ** d) The origin of the SOFA components of your derived work must 577 | ** not be misrepresented; you must not claim that you wrote the 578 | ** original software, nor file a patent application for SOFA 579 | ** software or algorithms embedded in the SOFA software. 580 | ** 581 | ** e) These requirements must be reproduced intact in any source 582 | ** distribution and shall apply to anyone to whom you have 583 | ** granted a further right to modify the source code of your 584 | ** derived work. 585 | ** 586 | ** Note that, as originally distributed, the SOFA software is 587 | ** intended to be a definitive implementation of the IAU standards, 588 | ** and consequently third-party modifications are discouraged. All 589 | ** variations, no matter how minor, must be explicitly marked as 590 | ** such, as explained above. 591 | ** 592 | ** 4. You shall not cause the SOFA software to be brought into 593 | ** disrepute, either by misuse, or use for inappropriate tasks, or 594 | ** by inappropriate modification. 595 | ** 596 | ** 5. The SOFA software is provided "as is" and SOFA makes no warranty 597 | ** as to its use or performance. SOFA does not and cannot warrant 598 | ** the performance or results which the user may obtain by using the 599 | ** SOFA software. SOFA makes no warranties, express or implied, as 600 | ** to non-infringement of third party rights, merchantability, or 601 | ** fitness for any particular purpose. In no event will SOFA be 602 | ** liable to the user for any consequential, incidental, or special 603 | ** damages, including any lost profits or lost savings, even if a 604 | ** SOFA representative has been advised of such damages, or for any 605 | ** claim by any third party. 606 | ** 607 | ** 6. The provision of any version of the SOFA software under the terms 608 | ** and conditions specified herein does not imply that future 609 | ** versions will also be made available under the same terms and 610 | ** conditions. 611 | * 612 | ** In any published work or commercial product which uses the SOFA 613 | ** software directly, acknowledgement (see www.iausofa.org) is 614 | ** appreciated. 615 | ** 616 | ** Correspondence concerning SOFA software should be addressed as 617 | ** follows: 618 | ** 619 | ** By email: sofa@ukho.gov.uk 620 | ** By post: IAU SOFA Center 621 | ** HM Nautical Almanac Office 622 | ** UK Hydrographic Office 623 | ** Admiralty Way, Taunton 624 | ** Somerset, TA1 2DN 625 | ** United Kingdom 626 | ** 627 | **--------------------------------------------------------------------*/ 628 | -------------------------------------------------------------------------------- /C/sofam.h: -------------------------------------------------------------------------------- 1 | #ifndef SOFAMHDEF 2 | #define SOFAMHDEF 3 | 4 | /* 5 | ** - - - - - - - - 6 | ** s o f a m . h 7 | ** - - - - - - - - 8 | ** 9 | ** Macros used by SOFA library. 10 | ** 11 | ** This file is part of the International Astronomical Union's 12 | ** SOFA (Standards of Fundamental Astronomy) software collection. 13 | ** 14 | ** Please note that the constants defined below are to be used only in 15 | ** the context of the SOFA software, and have no other official IAU 16 | ** status. In addition, self consistency is not guaranteed. 17 | ** 18 | ** This revision: 2021 February 24 19 | ** 20 | ** SOFA release 2023-10-11 21 | ** 22 | ** Copyright (C) 2023 IAU SOFA Board. See notes at end. 23 | */ 24 | 25 | /* Pi */ 26 | #define DPI (3.141592653589793238462643) 27 | 28 | /* 2Pi */ 29 | #define D2PI (6.283185307179586476925287) 30 | 31 | /* Radians to degrees */ 32 | #define DR2D (57.29577951308232087679815) 33 | 34 | /* Degrees to radians */ 35 | #define DD2R (1.745329251994329576923691e-2) 36 | 37 | /* Radians to arcseconds */ 38 | #define DR2AS (206264.8062470963551564734) 39 | 40 | /* Arcseconds to radians */ 41 | #define DAS2R (4.848136811095359935899141e-6) 42 | 43 | /* Seconds of time to radians */ 44 | #define DS2R (7.272205216643039903848712e-5) 45 | 46 | /* Arcseconds in a full circle */ 47 | #define TURNAS (1296000.0) 48 | 49 | /* Milliarcseconds to radians */ 50 | #define DMAS2R (DAS2R / 1e3) 51 | 52 | /* Length of tropical year B1900 (days) */ 53 | #define DTY (365.242198781) 54 | 55 | /* Seconds per day. */ 56 | #define DAYSEC (86400.0) 57 | 58 | /* Days per Julian year */ 59 | #define DJY (365.25) 60 | 61 | /* Days per Julian century */ 62 | #define DJC (36525.0) 63 | 64 | /* Days per Julian millennium */ 65 | #define DJM (365250.0) 66 | 67 | /* Reference epoch (J2000.0), Julian Date */ 68 | #define DJ00 (2451545.0) 69 | 70 | /* Julian Date of Modified Julian Date zero */ 71 | #define DJM0 (2400000.5) 72 | 73 | /* Reference epoch (J2000.0), Modified Julian Date */ 74 | #define DJM00 (51544.5) 75 | 76 | /* 1977 Jan 1.0 as MJD */ 77 | #define DJM77 (43144.0) 78 | 79 | /* TT minus TAI (s) */ 80 | #define TTMTAI (32.184) 81 | 82 | /* Astronomical unit (m, IAU 2012) */ 83 | #define DAU (149597870.7e3) 84 | 85 | /* Speed of light (m/s) */ 86 | #define CMPS 299792458.0 87 | 88 | /* Light time for 1 au (s) */ 89 | #define AULT (DAU/CMPS) 90 | 91 | /* Speed of light (au per day) */ 92 | #define DC (DAYSEC/AULT) 93 | 94 | /* L_G = 1 - d(TT)/d(TCG) */ 95 | #define ELG (6.969290134e-10) 96 | 97 | /* L_B = 1 - d(TDB)/d(TCB), and TDB (s) at TAI 1977/1/1.0 */ 98 | #define ELB (1.550519768e-8) 99 | #define TDB0 (-6.55e-5) 100 | 101 | /* Schwarzschild radius of the Sun (au) */ 102 | /* = 2 * 1.32712440041e20 / (2.99792458e8)^2 / 1.49597870700e11 */ 103 | #define SRS 1.97412574336e-8 104 | 105 | /* dint(A) - truncate to nearest whole number towards zero (double) */ 106 | #define dint(A) ((A)<0.0?ceil(A):floor(A)) 107 | 108 | /* dnint(A) - round to nearest whole number (double) */ 109 | #define dnint(A) (fabs(A)<0.5?0.0\ 110 | :((A)<0.0?ceil((A)-0.5):floor((A)+0.5))) 111 | 112 | /* dsign(A,B) - magnitude of A with sign of B (double) */ 113 | #define dsign(A,B) ((B)<0.0?-fabs(A):fabs(A)) 114 | 115 | /* max(A,B) - larger (most +ve) of two numbers (generic) */ 116 | #define gmax(A,B) (((A)>(B))?(A):(B)) 117 | 118 | /* min(A,B) - smaller (least +ve) of two numbers (generic) */ 119 | #define gmin(A,B) (((A)<(B))?(A):(B)) 120 | 121 | /* Reference ellipsoids */ 122 | #define WGS84 1 123 | #define GRS80 2 124 | #define WGS72 3 125 | 126 | #endif 127 | 128 | /*---------------------------------------------------------------------- 129 | ** 130 | ** Copyright (C) 2023 131 | ** Standards of Fundamental Astronomy Board 132 | ** of the International Astronomical Union. 133 | ** 134 | ** ===================== 135 | ** SOFA Software License 136 | ** ===================== 137 | ** 138 | ** NOTICE TO USER: 139 | ** 140 | ** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND 141 | ** CONDITIONS WHICH APPLY TO ITS USE. 142 | ** 143 | ** 1. The Software is owned by the IAU SOFA Board ("SOFA"). 144 | ** 145 | ** 2. Permission is granted to anyone to use the SOFA software for any 146 | ** purpose, including commercial applications, free of charge and 147 | ** without payment of royalties, subject to the conditions and 148 | ** restrictions listed below. 149 | ** 150 | ** 3. You (the user) may copy and distribute SOFA source code to others, 151 | ** and use and adapt its code and algorithms in your own software, 152 | ** on a world-wide, royalty-free basis. That portion of your 153 | ** distribution that does not consist of intact and unchanged copies 154 | ** of SOFA source code files is a "derived work" that must comply 155 | ** with the following requirements: 156 | ** 157 | ** a) Your work shall be marked or carry a statement that it 158 | ** (i) uses routines and computations derived by you from 159 | ** software provided by SOFA under license to you; and 160 | ** (ii) does not itself constitute software provided by and/or 161 | ** endorsed by SOFA. 162 | ** 163 | ** b) The source code of your derived work must contain descriptions 164 | ** of how the derived work is based upon, contains and/or differs 165 | ** from the original SOFA software. 166 | ** 167 | ** c) The names of all routines in your derived work shall not 168 | ** include the prefix "iau" or "sofa" or trivial modifications 169 | ** thereof such as changes of case. 170 | ** 171 | ** d) The origin of the SOFA components of your derived work must 172 | ** not be misrepresented; you must not claim that you wrote the 173 | ** original software, nor file a patent application for SOFA 174 | ** software or algorithms embedded in the SOFA software. 175 | ** 176 | ** e) These requirements must be reproduced intact in any source 177 | ** distribution and shall apply to anyone to whom you have 178 | ** granted a further right to modify the source code of your 179 | ** derived work. 180 | ** 181 | ** Note that, as originally distributed, the SOFA software is 182 | ** intended to be a definitive implementation of the IAU standards, 183 | ** and consequently third-party modifications are discouraged. All 184 | ** variations, no matter how minor, must be explicitly marked as 185 | ** such, as explained above. 186 | ** 187 | ** 4. You shall not cause the SOFA software to be brought into 188 | ** disrepute, either by misuse, or use for inappropriate tasks, or 189 | ** by inappropriate modification. 190 | ** 191 | ** 5. The SOFA software is provided "as is" and SOFA makes no warranty 192 | ** as to its use or performance. SOFA does not and cannot warrant 193 | ** the performance or results which the user may obtain by using the 194 | ** SOFA software. SOFA makes no warranties, express or implied, as 195 | ** to non-infringement of third party rights, merchantability, or 196 | ** fitness for any particular purpose. In no event will SOFA be 197 | ** liable to the user for any consequential, incidental, or special 198 | ** damages, including any lost profits or lost savings, even if a 199 | ** SOFA representative has been advised of such damages, or for any 200 | ** claim by any third party. 201 | ** 202 | ** 6. The provision of any version of the SOFA software under the terms 203 | ** and conditions specified herein does not imply that future 204 | ** versions will also be made available under the same terms and 205 | ** conditions. 206 | * 207 | ** In any published work or commercial product which uses the SOFA 208 | ** software directly, acknowledgement (see www.iausofa.org) is 209 | ** appreciated. 210 | ** 211 | ** Correspondence concerning SOFA software should be addressed as 212 | ** follows: 213 | ** 214 | ** By email: sofa@ukho.gov.uk 215 | ** By post: IAU SOFA Center 216 | ** HM Nautical Almanac Office 217 | ** UK Hydrographic Office 218 | ** Admiralty Way, Taunton 219 | ** Somerset, TA1 2DN 220 | ** United Kingdom 221 | ** 222 | **--------------------------------------------------------------------*/ 223 | -------------------------------------------------------------------------------- /Example/Application in CHES/Fig4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CHES2023/PyMsOfa/10c374794398e6c0d3cb699f4dd9ed7b1ac6a0bf/Example/Application in CHES/Fig4.png -------------------------------------------------------------------------------- /Example/Application in CHES/Fig4.py: -------------------------------------------------------------------------------- 1 | #An example of the use of pymsofa in CHES. 2 | #Used to simulate the image of a target star in the tangent plane 3 | #when it is observed at point L2 4 | 5 | import PyMsOfa as sf 6 | import numpy as np 7 | import xlrd 8 | import math as ma 9 | import matplotlib.pyplot as plt 10 | import matplotlib.colors as mcolors 11 | 12 | xl=xlrd.open_workbook(r'.\input.xls') 13 | xltar=xl.sheets()[0] 14 | xlref=xl.sheets()[1] 15 | xlref15=xl.sheets()[2] 16 | 17 | #input the information of the target star 18 | tarinfo=[xltar.cell(2,i).value for i in range(10)] 19 | tarinfo[1]=ma.radians(tarinfo[1]) 20 | tarinfo[2]=ma.radians(tarinfo[2]) 21 | tarinfo[4]=ma.radians(tarinfo[4]/1000/3600) 22 | tarinfo[5]=ma.radians(tarinfo[5]/1000/3600) 23 | tarinfo[6]=ma.radians(tarinfo[6]/1000/3600) 24 | tarinfo[7]=ma.radians(tarinfo[7]/1000/3600) 25 | 26 | 27 | #input the information of the reference star (Mag<13) 28 | refinfo=[xlref.cell(1,0).value,int(xlref.cell(1,1).value)] 29 | refinfo.append([[0 for k in range(9)] for i in range(refinfo[1])]) 30 | for i in range(refinfo[1]): 31 | for k in range(9): 32 | refinfo[2][i][k]=float(xlref.cell(2+i,k+1).value) 33 | if (k==0)|(k==1): 34 | refinfo[2][i][k]=ma.radians(refinfo[2][i][k]) 35 | elif (k==3)|(k==4)|(k==5)|(k==6): 36 | refinfo[2][i][k]=ma.radians(refinfo[2][i][k]/1000/3600) 37 | 38 | #input the information of the reference star (13ec 7 | date1, date2 = 2400000.5, 57388.5 8 | dr, dd = 2.8, -0.6 9 | dl, db = sf.pymEqec06(date1, date2, dr, dd) 10 | print(dl, db) 11 | #3.108110717008802 -0.679015560765235 12 | 13 | #ec->eq 14 | dr, dd = sf.pymEceq06(date1, date2, dl, db) 15 | print(dr, dd) 16 | #2.8 -0.6000000000000002 17 | 18 | #Star proper motion(Fig.2 in paper) 19 | ra1,dec1=0.08788796644747092,-1.132188403551008 20 | pmr1,pmd1=8.27454225597756e-06,5.647882757242327e-06 21 | px1=116.18257854098105e-3 22 | rv1=9.283571 23 | ep1a,ep1b=2400000.5,57388.450625000056 24 | ep2a,ep2b=2400000.5,60991.538933193 25 | ra2,dec2,pmr2,pmd2,px2,rv2\ 26 | =sf.pymPmsafe(ra1, dec1, pmr1, pmd1, 27 | px1, rv1, ep1a, ep1b, ep2a, ep2b) 28 | print(ra2,dec2,pmr2,pmd2,px2,rv2) 29 | #0.08796958189264041 -1.1321326881050646 8.272396933840485e-06 30 | #5.648019447684745e-06 0.11618131477951303 9.287244274111199 31 | 32 | #Projection theorem(Fig.3 in paper) 33 | ra1,dec1=0.09025370018535234,-1.1308656514899067 34 | pmr1,pmd1=-1.4191556529435842e-08,4.093790696930718e-08 35 | px1=1.6330602766416882e-3 36 | rv1=-2.694851 37 | ep1a,ep1b=2400000.5,57388.450625000056 38 | ep2a,ep2b=2400000.5,60991.538933193 39 | 40 | ra21,dec21,pmr2,pmd2,px2,rv2\ 41 | =sf.pymPmsafe(ra1, dec1, pmr1, pmd1, 42 | px1, rv1, ep1a, ep1b, ep2a, ep2b) 43 | a,b=ra21,dec21 44 | a0,b0=ra2,dec2 45 | xi,eta=sf.pymTpxes(a, b, a0, b0) 46 | print(xi,eta) 47 | #0.0009726944659440729 0.001266436096867058 48 | 49 | #ICRS->GCRS 50 | date1, date2 = 2400000.5, 60188.0 51 | pv = np.array([[-6241497.16 , 401346.896, -1251136.04], 52 | [-29.264597, -455.021831, 0.0266151194]]) 53 | astrom = sf.pymApcs13(date1, date2, pv) 54 | rc,dc=0.08788796644747092,-1.132188403551008 55 | pr,pd=8.27454225597756e-06,5.647882757242327e-06 56 | px=116.18257854098105e-3 57 | rv=9.283571 58 | ri, di = sf.pymAtciq(rc, dc, pr, pd, px, rv, astrom) 59 | print(ri, di) 60 | #0.0882705549440727 -1.1320010534992886 61 | 62 | #mean longitude of Mars 63 | t=2460188.5 64 | lamda = sf.pymFama03(t) 65 | print(lamda) 66 | #1.9096191364710933 -------------------------------------------------------------------------------- /Example/time.py: -------------------------------------------------------------------------------- 1 | #Example-time 2 | 3 | import PyMsOfa as sf 4 | 5 | #Day->Hour, minute, second 6 | ndp=0 7 | days=0.34 8 | sign, ihmsf=sf.pymD2tf(ndp, days) 9 | print(sign, ihmsf) 10 | #b'+' (8, 9, 36, 0) 11 | 12 | #Hour, minute, second->Radian 13 | s = b'-' 14 | ihour, imin, sec = 15, 25, 12.5 15 | rad = sf.pymTf2a(s, ihour, imin, sec) 16 | print(rad) 17 | #-4.036982920888967 18 | 19 | #Calendar->Julian day 20 | iyear, imon, iday = 2023 , 9, 1 21 | dj1,dj2 = sf.pymCal2jd(iyear, imon, iday) 22 | print(dj1,dj2) 23 | #2400000.5 60188.0 24 | 25 | #Julian epoch->Julian day 26 | epj = 2023.1 27 | djm0, djm = sf.pymEpj2jd(epj) 28 | print(djm0, djm) 29 | #2400000.5 59981.774999999965 30 | 31 | #UTC->TAI 32 | utc1 = 2400000.5 33 | utc2 = 57388.5 34 | tai1, tai2 = sf.pymUtctai(utc1, utc2) 35 | print(tai1, tai2) 36 | #2400000.5 57388.50041666667 37 | 38 | #TAI->TT 39 | tt1, tt2 = sf.pymTaitt(tai1, tai2) 40 | print(tt1, tt2) 41 | #2400000.5 57388.50078916667 42 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | # The MIT License (MIT) 2 | 3 | Copyright (c) 2023 CHES 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PyMsOfa 2 | [![arXiv](https://img.shields.io/badge/arxiv-2310.08673-b31b1b.svg)](https://arxiv.org/abs/2310.08673) | [Paper](https://doi.org/10.1088/1674-4527/ad0499) | ![Python](https://img.shields.io/badge/Python-3.0-green.svg)|[![PyPI version](https://badge.fury.io/py/PyMsOfa.svg)](https://badge.fury.io/py/PyMsOfa)|[![zenodo](https://img.shields.io/badge/zenodo-10052216-blue.svg)](https://zenodo.org/records/10052216)|[![NADC](https://img.shields.io/badge/NADC-101346-3d59ab.svg)](https://nadc.china-vo.org/res/r101346/)|[![ASCL](https://img.shields.io/badge/ASCL-2312.018-262255.svg)](https://ascl.net/2312.018)| 3 | 4 | This package is a Python package for the Standards of Fundamental Astronomy (SOFA) service of the International Astronomical Union (IAU). It implements the python package PyMsOfa for SOFA service in three ways: 5 | 6 | (1) a python wrapper package based on a foreign function library for Python (ctypes), 7 | 8 | (2) a python wrapper package with the foreign function interface for Python calling C code (cffi), 9 | 10 | (3) a python package directly written in pure python codes from SOFA subroutines. 11 | 12 | It implements all 247 functions in the SOFA service and is based on the latest version released on Oct 11, 2023. 13 | 14 | This Python package can be suitable for the astrometric detection of habitable planets of the Closeby Habitable Exoplanet Survey ([CHES](https://doi.org/10.1088/1674-4527/ac77e4)) mission and for the frontier themes of black holes and dark matter related to astrometric calculations and other fields. 15 | 16 | ## Structure 17 | ``` 18 | ├─ C 19 | ├─makefile #makefile 20 | ├─sofa.h #header file 21 | ├─sofa_a.c #integrated all 247 routines in SOFA service 22 | ├─sofam.h #header file 23 | ├─ Example 24 | ├─Application in CHES 25 | ├─Fig4.png #Figure 4 in paper 26 | ├─Fig4.py #Programs to generate Figure 4 27 | ├─input.xls #Input parameters obtained from Gaia DR3 28 | ├─Precession-nutation.py #Programs on precession-nutation 29 | ├─coordinate.py #Programs on coordinate 30 | ├─time.py #Programs on time 31 | ├─ cffi #Cffi version, run with the libsofa_c.so generated in the C folder 32 | ├─PyMsOfa.py #Contains all 247 routines 33 | ├─PyMsOfa_astrometry.py #Astrometry module of PyMsOfa.py 34 | ├─PyMsOfa_basic.py #Basic module of PyMsOfa.py 35 | ├─PyMsOfa_earth_attitude.py #Earth attitude module of PyMsOfa.py 36 | ├─PyMsOfa_t.py #Test file 37 | ├─PyMsOfa_time.py #Time module of PyMsOfa.py 38 | ├─ ctypes #Ctypes version, run with the libsofa_c.so generated in the C folder 39 | ├─PyMsOfa.py #Contains all 247 routines 40 | ├─PyMsOfa_astrometry.py #Astrometry module of PyMsOfa.py 41 | ├─PyMsOfa_basic.py #Basic module of PyMsOfa.py 42 | ├─PyMsOfa_earth_attitude.py #Earth attitude module of PyMsOfa.py 43 | ├─PyMsOfa_t.py #Test file 44 | ├─PyMsOfa_time.py #Time module of PyMsOfa.py 45 | ├─ Python #Python version, pure python codes 46 | ├─PyMsOfa.py #Contains all 247 routines 47 | ├─PyMsOfa_astrometry.py #Astrometry module of PyMsOfa.py 48 | ├─PyMsOfa_basic.py #Basic module of PyMsOfa.py 49 | ├─PyMsOfa_earth_attitude.py #Earth attitude module of PyMsOfa.py 50 | ├─PyMsOfa_t.py #Test file 51 | ├─PyMsOfa_time.py #Time module of PyMsOfa.py 52 | ├─ LICENSE.md 53 | ├─ README.md 54 | ``` 55 | 56 | ## Installation 57 | 58 | Put the files in the C folder in the same directory. 59 | 60 | ### For windows 61 | 62 | Use the following command in CMD. 63 | ``` 64 | mingw32-make 65 | ``` 66 | If this doesn't work, please install [TDM-GCC](https://jmeubank.github.io/tdm-gcc/download/). 67 | 68 | Then put the newly generated libsofa_c.so file in the same directory as PyMsOfa.py in the Python folder. 69 | 70 | ### For macOS 71 | 72 | Use the following command in Terminal. 73 | ``` 74 | make 75 | ``` 76 | Then put the newly generated libsofa_c.so file in the same directory as PyMsOfa.py in the Python folder. 77 | 78 | ### For Linux 79 | Use the following command in Terminal. 80 | ``` 81 | make 82 | ``` 83 | And then 84 | ``` 85 | ln -s libsofa_c.so /usr/lib/libsofa_c.so 86 | ``` 87 | 88 | ## Documentation 89 | 90 | For package documentation please refer to the underlying SOFA documentation at: 91 | [(http://www.iausofa.org/cookbooks.html)](http://www.iausofa.org/cookbooks.html) 92 | 93 | ## Description 94 | 95 | PyMsOfa is a Python module for accessing the [International Astronomical Union](https://www.iau.org/)’s [SOFA library](http://www.iausofa.org/) from Python. SOFA (Standards of Fundamental Astronomy) is a set of algorithms and procedures that implement standard models used in fundamental astronomy. 96 | 97 | PyMsOfa is not a part of SOFA routines but a Python package for the SOFA C library. Thus, no calculations are made into the PyMsOfa package based on ctypes and cffi interface, which are all delegated to the underlying SOFA C library. 98 | 99 | PyMsOfa is neither distributed, supported nor endorsed by the International Astronomical Union. In addition to PyMsOfa’s license, any use of this module should comply with [SOFA’s license and terms of use](http://www.iausofa.org/tandc.html). Especially, but not exclusively, any published work or commercial products including results achieved by using PyMsOfa shall acknowledge that the SOFA software was used to obtain those results. 100 | 101 | 102 | ## Citation 103 | 104 | To cite PyMsOfa in publications use: 105 | 106 | > 1. Ji, Jiang-Hui, Tan, Dong-jie, Bao, Chun-hui, Huang, Xiu-min, Hu, Shoucun, Dong, Yao, Wang, Su. 2023, PyMsOfa: A Python Package for the Standards of Fundamental Astronomy (SOFA) Service, Research in Astronomy and Astrophysics, 23, 125015, doi:[10.1088/1674-4527/ad0499](https://doi.org/10.1088/1674-4527/ad0499) 107 | > 2. Ji, Jiang-Hui, Li, Hai-Tao, Zhang, Jun-Bo, Fang, Liang, Li, Dong, Wang, Su, Cao, Yang, Deng, Lei, Li, Bao-Quan, Xian, Hao, Gao, Xiao-Dong, Zhang, Ang, Li, Fei, Liu, Jia-Cheng, Qi, Zhao-Xiang, Jin, Sheng, Liu, Ya-Ning, Chen, Guo, Li, Ming-Tao, Dong, Yao, Zhu, Zi, and CHES Consortium. 2022, CHES: A Space-borne Astrometric Mission for the Detection of Habitable Planets of the Nearby Solar-type Stars, Research in Astronomy and Astrophysics, 22, 072003, doi:[10.1088/1674-4527/ac77e4](https://doi.org/10.1088/1674-4527/ac77e4) 108 | 109 | 110 | A BibTeX entry for LaTeX users is 111 | ```bibtex 112 | @ARTICLE{2023RAA....23l5015J, 113 | author = {{Ji}, Jianghui and {Tan}, Dongjie and {Bao}, Chunhui and {Huang}, Xiumin and {Hu}, Shoucun and {Dong}, Yao and {Wang}, Su}, 114 | title = "{PyMsOfa: A Python Package for the Standards of Fundamental Astronomy (SOFA) Service}", 115 | journal = {Research in Astronomy and Astrophysics}, 116 | keywords = {Astrometry and Celestial Mechanics, planets and satellites: detection, planets and satellites: terrestrial planets, Astrophysics - Instrumentation and Methods for Astrophysics, Astrophysics - Earth and Planetary Astrophysics, Astrophysics - Astrophysics of Galaxies, Astrophysics - Solar and Stellar Astrophysics}, 117 | year = 2023, 118 | month = dec, 119 | volume = {23}, 120 | number = {12}, 121 | eid = {125015}, 122 | pages = {125015}, 123 | doi = {10.1088/1674-4527/ad0499}, 124 | archivePrefix = {arXiv}, 125 | eprint = {2310.08673}, 126 | primaryClass = {astro-ph.IM}, 127 | adsurl = {https://ui.adsabs.harvard.edu/abs/2023RAA....23l5015J}, 128 | adsnote = {Provided by the SAO/NASA Astrophysics Data System} 129 | } 130 | 131 | @article{2022RAA....22g2003J, 132 | author = {{Ji}, Jiang-Hui and {Li}, Hai-Tao and {Zhang}, Jun-Bo and {Fang}, Liang and {Li}, Dong and {Wang}, Su and {Cao}, Yang and {Deng}, Lei and {Li}, Bao-Quan and {Xian}, Hao and {Gao}, Xiao-Dong and {Zhang}, Ang and {Li}, Fei and {Liu}, Jia-Cheng and {Qi}, Zhao-Xiang and {Jin}, Sheng and {Liu}, Ya-Ning and {Chen}, Guo and {Li}, Ming-Tao and {Dong}, Yao and {Zhu}, Zi and {CHES Consortium}}, 133 | title = "{CHES: A Space-borne Astrometric Mission for the Detection of Habitable Planets of the Nearby Solar-type Stars}", 134 | journal = {Research in Astronomy and Astrophysics}, 135 | keywords = {Astrometry and Celestial Mechanics, planets and satellites: detection, planets and satellites: terrestrial planets, stars: solar-type, Astrophysics - Earth and Planetary Astrophysics, Astrophysics - Astrophysics of Galaxies, Astrophysics - Instrumentation and Methods for Astrophysics, Astrophysics - Solar and Stellar Astrophysics}, 136 | year = 2022, 137 | month = jul, 138 | volume = {22}, 139 | number = {7}, 140 | eid = {072003}, 141 | pages = {072003}, 142 | doi = {10.1088/1674-4527/ac77e4}, 143 | archivePrefix = {arXiv}, 144 | eprint = {2205.05645}, 145 | primaryClass = {astro-ph.EP}, 146 | adsurl = {https://ui.adsabs.harvard.edu/abs/2022RAA....22g2003J}, 147 | adsnote = {Provided by the SAO/NASA Astrophysics Data System} 148 | } 149 | ``` 150 | -------------------------------------------------------------------------------- /ctypes/PyMsOfa_basic.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Tue Feb 28 02:44:08 2023 4 | Done on Mon Jun 5 02:11:37 2023 5 | @author: Dr. Jianghui JI (jijh@pmo.ac.cn) 6 | """ 7 | #from numba import jit 8 | #from __future__ import print_function 9 | import ctypes 10 | from ctypes import * 11 | import numpy as np 12 | import numpy.ctypeslib as nt 13 | import warnings as ws 14 | import os 15 | import sys 16 | import platform as pf 17 | 18 | #dll = ctypes.cdll.LoadLibrary 19 | #lib = dll('./libsofa_c.so') 20 | 21 | #compile sofa_c.c to create libsofa_c.so shared libary 22 | #gcc -shared -fPIC -o libsofa_c.so sofa_a.c 23 | 24 | #path = os.getcwd() 25 | #lib = CDLL(os.path.join(path, 'libsofa_c.so')) 26 | 27 | 28 | ''' 29 | Descr: return file name/path information 30 | # Input: 31 | filepath: full path of a file 32 | 33 | # Return values: 34 | dirname: directory name of a file 35 | fullname: full name of a file 36 | filename: file name of a file 37 | extension: file extension 38 | ''' 39 | def getFileName(filepath): 40 | 41 | __file__ = filepath 42 | 43 | dirname = os.path.dirname(__file__) 44 | fullname = os.path.split(__file__)[-1] 45 | filename = os.path.split(__file__)[-1].split('.')[0] 46 | extension = os.path.split(__file__)[-1].split('.')[1] 47 | 48 | return dirname, fullname, filename, extension 49 | 50 | 51 | def getFilePath(filepath): 52 | 53 | __file__ = filepath 54 | 55 | dirname = os.path.dirname(__file__) 56 | fullname = os.path.split(__file__)[-1] 57 | filename = os.path.split(__file__)[-1].split('.')[0] 58 | extension = os.path.split(__file__)[-1].split('.')[1] 59 | 60 | return dirname 61 | 62 | #place libsofa_c.so in the same directory with PyMsOfa.py 63 | cur_dir = sys.argv[0] 64 | #dirname, fullname, filename, extension = getFileName(cur_dir) 65 | dirname = getFilePath(cur_dir) 66 | libs_file = 'libsofa_c.so' 67 | libs_path = os.path.join(dirname, libs_file) 68 | #lib = CDLL(libs_path) 69 | 70 | 71 | #''' 72 | #for windows 73 | if pf.system().lower() == 'windows': 74 | 75 | #user_path = './' 76 | #libs_file = 'libsofa_c.so' 77 | #libs_path = user_path + libs_file 78 | #print(libs_path) 79 | #lib = CDLL(libs_path) 80 | 81 | #print(libs_path) 82 | lib = CDLL(libs_path) 83 | 84 | #for linux 85 | elif pf.system().lower() == 'linux': 86 | dirname = os.getcwd() 87 | lib = CDLL(os.path.join(dirname, libs_file)) 88 | #lib = CDLL('./libsofa_c.so') 89 | #print(libs_path) 90 | #lib = CDLL(libs_path) 91 | 92 | #for macOS 93 | elif pf.system().lower() == 'darwin': 94 | 95 | lib = CDLL(libs_path) 96 | 97 | #''' 98 | 99 | c_int4 = c_int * 4 100 | 101 | array_1d_double = nt.ndpointer(shape=(1,3), dtype=np.double, flags='C') 102 | vector_double = nt.ndpointer(shape=(1,3), dtype=np.double, flags='C') 103 | array_double_2 = nt.ndpointer(shape=(1,2), dtype=np.double, flags='C') 104 | c_double_p = POINTER(c_double) 105 | 106 | def pymPas(al, ap, bl, bp): 107 | ''' 108 | Position-angle from spherical coordinates. 109 | 110 | Parameters 111 | ---------- 112 | al : float 113 | longitude of point A (e.g. RA) in radians 114 | ap : float 115 | latitude of point A (e.g. Dec) in radians 116 | bl : float 117 | longitude of point B 118 | bp : float 119 | latitude of point B 120 | 121 | Returns 122 | ------- 123 | function value : float 124 | position angle of B with respect to A 125 | 126 | ''' 127 | lib.iauPas.argtypes = [c_double, c_double, c_double, c_double] 128 | lib.iauPas.restype = c_double 129 | 130 | return lib.iauPas(al, ap, bl, bp) 131 | 132 | array_1d_double = nt.ndpointer(shape=(1,3), dtype=np.double, flags='C') 133 | vector_double = nt.ndpointer(shape=(1,3), dtype=np.double, flags='C') 134 | array_double_2 = nt.ndpointer(shape=(1,2), dtype=np.double, flags='C') 135 | 136 | def pymS2c_A(theta, phi, c): 137 | 138 | lib.iauS2c.argtypes = [c_double, c_double, vector_double] 139 | lib.iauS2c.restype = None 140 | lib.iauS2c(theta, phi, c) 141 | return 142 | 143 | def pymS2c(theta, phi): 144 | ''' 145 | Convert spherical coordinates to Cartesian. 146 | 147 | Parameters 148 | ---------- 149 | theta : float 150 | longitude angle (radians) 151 | phi : float 152 | latitude angle (radians) 153 | 154 | Returns 155 | ------- 156 | c : numpy.matrix 157 | direction cosines 158 | 159 | ''' 160 | 161 | lib.iauS2c.argtypes = [c_double, c_double, vector_double] 162 | lib.iauS2c.restype = None 163 | c = np.asmatrix(np.zeros(shape=(1,3), dtype=float, order='C')) 164 | lib.iauS2c(theta, phi, c) 165 | return c 166 | 167 | ###sofa_pn_f.pdf### 168 | 169 | def pymAnp(a): 170 | ''' 171 | Normalize angle into the range 0 <= a < 2pi. 172 | 173 | Parameters 174 | ---------- 175 | a : float 176 | angle (radians) 177 | 178 | Returns 179 | ------- 180 | function value : float 181 | angle in range 0-2pi 182 | 183 | ''' 184 | lib.iauAnp.argtypes = [c_double] 185 | lib.iauAnp.restype = c_double 186 | 187 | return lib.iauAnp(a) 188 | 189 | #2023-05-04 190 | 191 | 192 | #sofa vector_matrix model 193 | 194 | 195 | def pymAnpm(a): 196 | ''' 197 | Normalize angle into the range -pi <= a < +pi. 198 | 199 | Parameters 200 | ---------- 201 | a : float 202 | angle (radians) 203 | 204 | Returns 205 | ------- 206 | function value : float 207 | angle in range +/-pi 208 | 209 | ''' 210 | lib.iauAnpm.argtypes = [c_double] 211 | lib.iauAnpm.restype = c_double 212 | 213 | return lib.iauAnpm(a) 214 | 215 | def pymC2s(p): 216 | ''' 217 | P-vector to spherical coordinates. 218 | 219 | Parameters 220 | ---------- 221 | p : numpy.matrix(1,3) 222 | p-vector 223 | 224 | Returns 225 | ------- 226 | theta : float 227 | longitude angle (radians) 228 | phi : float 229 | latitude angle (radians) 230 | 231 | ''' 232 | lib.iauC2s.argtypes = [vector_double, c_double_p, c_double_p] 233 | lib.iauC2s.restype = None 234 | 235 | theta = c_double() 236 | phi = c_double() 237 | 238 | lib.iauC2s(p, byref(theta), byref(phi)) 239 | 240 | return theta.value, phi.value 241 | 242 | 243 | def pymCp(p): 244 | ''' 245 | Copy a p-vector. 246 | 247 | Parameters 248 | ---------- 249 | p : numpy.matrix(1,3) 250 | p-vector to be copied 251 | 252 | Returns 253 | ------- 254 | c : numpy.matrix(1,3) 255 | copy 256 | 257 | ''' 258 | lib.iauCp.argtypes = [vector_double, vector_double] 259 | lib.iauCp.restype = None 260 | 261 | c = np.asmatrix(np.zeros(shape=(1,3), dtype=float, order='C')) 262 | 263 | lib.iauCp(p, c) 264 | 265 | return c 266 | 267 | def pymCp_A(p): 268 | 269 | return p 270 | 271 | def pymCpv(pv): 272 | ''' 273 | Copy a position/velocity vector. 274 | 275 | Parameters 276 | ---------- 277 | pv : numpy.matrix(2,3) 278 | position/velocity vector to be copied 279 | 280 | Returns 281 | ------- 282 | c : numpy.matrix(2,3) 283 | copy 284 | 285 | ''' 286 | lib.iauCpv.argtypes = [vector_double2, vector_double2] 287 | lib.iauCpv.restype = None 288 | 289 | c = np.asmatrix(np.zeros(shape=(2,3), dtype=float, order='C')) 290 | 291 | lib.iauCpv(pv, c) 292 | 293 | return c 294 | 295 | def pymCpv_A(pv): 296 | 297 | # c = np.asmatrix(np.zeros(shape=(2,3), dtype=float, order='C')) 298 | # c = pv 299 | return pv 300 | 301 | def pymCr(r): 302 | ''' 303 | Copy an r-matrix. 304 | 305 | Parameters 306 | ---------- 307 | r : numpy.matrix(3,3) 308 | r-matrix to be copied 309 | 310 | Returns 311 | ------- 312 | c : numpy.matrix(3,3) 313 | r-matrix to be copied 314 | 315 | ''' 316 | lib.iauCr.argtypes = [vector_double3, vector_double3] 317 | lib.iauCr.restype = None 318 | 319 | c = np.asmatrix(np.zeros(shape=(3,3), dtype=float, order='C')) 320 | 321 | lib.iauCr(r, c) 322 | 323 | return c 324 | 325 | def pymCr_A(r): 326 | return r 327 | 328 | #2023-05-28 329 | ''' 330 | void iauIr(double r[3][3]) 331 | ''' 332 | def pymIr(): 333 | ''' 334 | Initialize an r-matrix to the identity matrix. 335 | 336 | Returns 337 | ------- 338 | r : numpy.matrix(3,3) 339 | r-matrix 340 | 341 | ''' 342 | lib.iauIr.argtypes = [vector_double3] 343 | lib.iauIr.restype = None 344 | 345 | r = np.asmatrix(np.zeros(shape=(3,3), dtype=float, order='C')) 346 | 347 | lib.iauIr(r) 348 | 349 | return r 350 | 351 | def pymP2pv(p): 352 | ''' 353 | Extend a p-vector to a pv-vector by appending a zero velocity. 354 | 355 | Parameters 356 | ---------- 357 | p : numpy.matrix(1,3) 358 | p-vector 359 | 360 | Returns 361 | ------- 362 | pv : numpy.matrix(2,3) 363 | pv-vector 364 | 365 | ''' 366 | lib.iauP2pv.argtypes = [vector_double, vector_double2] 367 | lib.iauP2pv.restype = None 368 | 369 | pv = np.asmatrix(np.zeros(shape=(2,3), dtype=float, order='C')) 370 | 371 | lib.iauP2pv(p, pv) 372 | 373 | return pv 374 | 375 | 376 | def pymP2s(p): 377 | ''' 378 | P-vector to spherical polar coordinates. 379 | 380 | Parameters 381 | ---------- 382 | p : numpy.matrix(1,3) 383 | p-vector 384 | 385 | Returns 386 | ------- 387 | theta : float 388 | longitude angle (radians) 389 | phi : float 390 | latitude angle (radians) 391 | r : float 392 | radial distance 393 | 394 | ''' 395 | lib.iauP2s.argtypes = [vector_double, c_double_p, c_double_p, c_double_p] 396 | lib.iauP2s.restype = None 397 | 398 | theta = c_double() 399 | phi = c_double() 400 | r = c_double() 401 | 402 | lib.iauP2s(p, byref(theta), byref(phi), byref(r)) 403 | 404 | return theta.value, phi.value, r.value 405 | 406 | def pymPap(a, b): 407 | ''' 408 | Position-angle from two p-vectors. 409 | 410 | Parameters 411 | ---------- 412 | a : numpy.matrix(1,3) 413 | direction of reference point 414 | b : numpy.matrix(1,3) 415 | direction of point whose PA is required 416 | 417 | Returns 418 | ------- 419 | function value : float 420 | position angle of b with respect to a (radians) 421 | 422 | ''' 423 | lib.iauPap.argtypes = [vector_double, vector_double] 424 | lib.iauPap.restype = c_double 425 | 426 | return lib.iauPap(a, b) 427 | 428 | #def pymPas(al, ap, bl, bp): Line No. 106 429 | 430 | def pymPdp(a, b): 431 | ''' 432 | p-vector inner (=scalar=dot) product. 433 | 434 | Parameters 435 | ---------- 436 | a : numpy.matrix(1,3) 437 | first p-vector 438 | b : numpy.matrix(1,3) 439 | second p-vector 440 | 441 | Returns 442 | ------- 443 | function value : float 444 | a . b 445 | 446 | ''' 447 | lib.iauPdp.argtypes = [vector_double, vector_double] 448 | lib.iauPdp.restype = c_double 449 | 450 | return lib.iauPdp(a, b) 451 | 452 | #Two vectors dot to have scalar product, using np.dot 453 | def pymPdp_A(a, b): 454 | 455 | return np.dot(a, b) 456 | 457 | def pymPm(p): 458 | ''' 459 | Modulus of p-vector. 460 | 461 | Parameters 462 | ---------- 463 | p : numpy.matrix(1,3) 464 | p-vector 465 | 466 | Returns 467 | ------- 468 | function value : float 469 | modulus 470 | 471 | ''' 472 | lib.iauPm.argtypes = [vector_double] 473 | lib.iauPm.restype = c_double 474 | 475 | return lib.iauPm(p) 476 | 477 | def pymPm_A(p): 478 | 479 | return np.linalg.norm(p, ord=2) 480 | 481 | def pymPmp(a, b): 482 | ''' 483 | P-vector subtraction. 484 | 485 | Parameters 486 | ---------- 487 | a : numpy.matrix(1,3) 488 | first p-vector 489 | b : numpy.matrix(1,3) 490 | second p-vector 491 | 492 | Returns 493 | ------- 494 | amb : numpy.matrix(1,3) 495 | a - b 496 | 497 | ''' 498 | lib.iauPmp.argtypes = [vector_double, vector_double, vector_double] 499 | lib.iauPmp.restype = None 500 | amb = np.asmatrix(np.zeros(shape=(1,3), dtype=float, order='C')) 501 | 502 | lib.iauPmp(a, b, amb) 503 | 504 | return amb 505 | 506 | def pymPmp_A(a, b): 507 | 508 | return a - b 509 | 510 | def pymPn(p): 511 | ''' 512 | Convert a p-vector into modulus and unit vector. 513 | 514 | Parameters 515 | ---------- 516 | p : numpy.matrix(1,3) 517 | p-vector 518 | 519 | Returns 520 | ------- 521 | r : float 522 | modulus 523 | u : numpy.matrix(1,3) 524 | unit vector 525 | 526 | ''' 527 | lib.iauPn.argtypes = [vector_double, c_double_p, vector_double] 528 | lib.iauPn.restype = None 529 | 530 | r = c_double() 531 | u = np.asmatrix(np.zeros(shape=(1,3), dtype=float, order='C')) 532 | 533 | lib.iauPn(p, byref(r), u) 534 | 535 | return r.value, u 536 | 537 | #Python 538 | def pymPn_A(p): 539 | 540 | r = np.linalg.norm(p, ord=2) 541 | u = p/r 542 | 543 | return r, u 544 | 545 | def pymPpp(a, b): 546 | ''' 547 | P-vector addition. 548 | 549 | Parameters 550 | ---------- 551 | a : numpy.matrix(1,3) 552 | first p-vector 553 | b : numpy.matrix(1,3) 554 | second p-vector 555 | 556 | Returns 557 | ------- 558 | apb : numpy.matrix(1,3) 559 | a + b 560 | 561 | ''' 562 | lib.iauPpp.argtypes = [vector_double, vector_double, vector_double] 563 | lib.iauPpp.restype = None 564 | apb = np.asmatrix(np.zeros(shape=(1,3), dtype=float, order='C')) 565 | 566 | lib.iauPpp(a, b, apb) 567 | 568 | return apb 569 | 570 | def pymPpp_A(a, b): 571 | 572 | return a + b 573 | 574 | def pymPpsp(a, s, b): 575 | ''' 576 | P-vector plus scaled p-vector. 577 | 578 | Parameters 579 | ---------- 580 | a : numpy.matrix(1,3) 581 | first p-vector 582 | s : float 583 | scalar (multiplier for b) 584 | b : numpy.matrix(1,3) 585 | second p-vector 586 | 587 | Returns 588 | ------- 589 | apsb : numpy.matrix(1,3) 590 | a + s*b 591 | 592 | ''' 593 | lib.iauPpsp.argtypes = [vector_double, c_double, vector_double, vector_double] 594 | lib.iauPpsp.restype = None 595 | 596 | apsb = np.asmatrix(np.zeros(shape=(1,3), dtype=float, order='C')) 597 | 598 | lib.iauPpsp(a, s, b, apsb) 599 | 600 | return apsb 601 | 602 | def pymPpsp_A(a, s, b): 603 | 604 | return a + s*b 605 | 606 | 607 | def pymPv2p(pv): 608 | ''' 609 | Discard velocity component of a pv-vector. 610 | 611 | Parameters 612 | ---------- 613 | pv : numpy.matrix(2,3) 614 | pv-vector 615 | 616 | Returns 617 | ------- 618 | p : numpy.matrix(1,3) 619 | p-vector 620 | 621 | ''' 622 | lib.iauPv2p.argtypes = [vector_double2, vector_double] 623 | lib.iauPv2p.restype = None 624 | 625 | p = np.asmatrix(np.zeros(shape=(1,3), dtype=float, order='C')) 626 | 627 | lib.iauPv2p(pv, p) 628 | 629 | return p 630 | 631 | def pymPv2s(pv): 632 | ''' 633 | Convert position/velocity from Cartesian to spherical coordinates. 634 | 635 | Parameters 636 | ---------- 637 | pv : numpy.matrix(2,3) 638 | pv-vector 639 | 640 | Returns 641 | ------- 642 | theta : float 643 | longitude angle (radians) 644 | phi : float 645 | latitude angle (radians) 646 | r : float 647 | radial distance 648 | td : float 649 | rate of change of theta 650 | pd : float 651 | rate of change of phi 652 | rd : float 653 | rate of change of r 654 | 655 | ''' 656 | lib.iauPv2s.argtypes = [vector_double2, c_double_p, c_double_p, c_double_p, 657 | c_double_p, c_double_p, c_double_p ] 658 | lib.iauPv2s.restype = None 659 | 660 | 661 | theta = c_double() 662 | phi = c_double() 663 | r = c_double() 664 | 665 | td = c_double() 666 | pd = c_double() 667 | rd = c_double() 668 | 669 | lib.iauPv2s(pv, byref(theta), byref(phi), byref(r), 670 | byref(td), byref(pd), byref(rd)) 671 | 672 | return theta.value, phi.value, r.value, td.value, pd.value, rd.value 673 | 674 | def pymPvdpv(a, b): 675 | ''' 676 | Inner (=scalar=dot) product of two pv-vectors. 677 | 678 | Parameters 679 | ---------- 680 | a : numpy.matrix(2,3) 681 | first pv-vector 682 | b : numpy.matrix(2,3) 683 | second pv-vector 684 | 685 | Returns 686 | ------- 687 | adb : numpy.matrix(1,2) 688 | DESCRIPTION. 689 | 690 | ''' 691 | lib.iauPvdpv.argtypes = [vector_double2, vector_double2, array_double_2] 692 | lib.iauPvdpv.restype = None 693 | 694 | adb = np.asmatrix(np.zeros(shape=(1,2), dtype=float, order='C')) 695 | 696 | lib.iauPvdpv(a, b, adb) 697 | 698 | return adb 699 | 700 | def pymPvm(pv): 701 | ''' 702 | Modulus of pv-vector. 703 | 704 | Parameters 705 | ---------- 706 | pv : numpy.matrix(2,3) 707 | pv-vector 708 | 709 | Returns 710 | ------- 711 | r : float 712 | modulus of position component 713 | s : float 714 | modulus of velocity component 715 | 716 | ''' 717 | lib.iauPvm.argtypes = [vector_double2, c_double_p, c_double_p] 718 | lib.iauPvm.restype = None 719 | 720 | r = c_double() 721 | s = c_double() 722 | 723 | lib.iauPvm(pv, byref(r), byref(s)) 724 | 725 | return r.value, s.value 726 | 727 | def pymPvmpv(a, b): 728 | ''' 729 | Subtract one pv-vector from another. 730 | 731 | Parameters 732 | ---------- 733 | a : numpy.matrix(2,3) 734 | first pv-vector 735 | b : numpy.matrix(2,3) 736 | second pv-vector 737 | 738 | Returns 739 | ------- 740 | amb : numpy.matrix(2,3) 741 | a - b 742 | 743 | ''' 744 | lib.iauPvmpv.argtypes = [vector_double2, vector_double2, vector_double2] 745 | lib.iauPvmpv.restype = None 746 | 747 | amb = np.asmatrix(np.zeros(shape=(2,3), dtype=float, order='C')) 748 | 749 | lib.iauPvmpv(a, b, amb) 750 | 751 | return amb 752 | 753 | def pymPvmpv_A(a, b): 754 | 755 | return a - b 756 | 757 | def pymPvppv(a, b): 758 | ''' 759 | Add one pv-vector to another. 760 | 761 | Parameters 762 | ---------- 763 | a : numpy.matrix(2,3) 764 | first pv-vector 765 | b : numpy.matrix(2,3) 766 | second pv-vector 767 | 768 | Returns 769 | ------- 770 | apb : numpy.matrix(2,3) 771 | a + b 772 | 773 | ''' 774 | lib.iauPvppv.argtypes = [vector_double2, vector_double2, vector_double2] 775 | lib.iauPvppv.restype = None 776 | 777 | apb = np.asmatrix(np.zeros(shape=(2,3), dtype=float, order='C')) 778 | 779 | lib.iauPvppv(a, b, apb) 780 | 781 | return apb 782 | 783 | def pymPvppv_A(a, b): 784 | 785 | return a + b 786 | 787 | #2023-05-30 788 | 789 | def pymPvu(dt, pv): 790 | ''' 791 | Update a pv-vector. 792 | 793 | Parameters 794 | ---------- 795 | dt : float 796 | time interval 797 | pv : numpy.matrix(2,3) 798 | pv-vector 799 | 800 | Returns 801 | ------- 802 | upv : numpy.matrix(2,3) 803 | p updated, v unchanged 804 | 805 | ''' 806 | lib.iauPvu.argtypes = [c_double, vector_double2, vector_double2] 807 | lib.iauPvu.restype = None 808 | 809 | upv = np.asmatrix(np.zeros(shape=(2,3), dtype=float, order='C')) 810 | 811 | lib.iauPvu(dt, pv, upv) 812 | 813 | return upv 814 | 815 | def pymPvup(dt, pv): 816 | ''' 817 | Update a pv-vector, discarding the velocity component. 818 | 819 | Parameters 820 | ---------- 821 | dt : float 822 | time interval 823 | pv : numpy.matrix(2,3) 824 | pv-vector 825 | 826 | Returns 827 | ------- 828 | p : numpy.matrix(1,3) 829 | p-vector 830 | 831 | ''' 832 | lib.iauPvup.argtypes = [c_double, vector_double2, vector_double] 833 | lib.iauPvup.restype = None 834 | 835 | p = np.asmatrix(np.zeros(shape=(1,3), dtype=float, order='C')) 836 | 837 | lib.iauPvup(dt, pv, p) 838 | 839 | return p 840 | 841 | def pymPvxpv(a, b): 842 | ''' 843 | Outer (=vector=cross) product of two pv-vectors. 844 | 845 | Parameters 846 | ---------- 847 | a : numpy.matrix(2,3) 848 | first pv-vector 849 | b : numpy.matrix(2,3) 850 | second pv-vector 851 | 852 | Returns 853 | ------- 854 | axb : numpy.matrix(2,3) 855 | a x b 856 | 857 | ''' 858 | lib.iauPvxpv.argtypes = [vector_double2, vector_double2, vector_double2] 859 | lib.iauPvxpv.restype = None 860 | 861 | axb = np.asmatrix(np.zeros(shape=(2,3), dtype=float, order='C')) 862 | 863 | lib.iauPvxpv(a, b, axb) 864 | 865 | return axb 866 | 867 | 868 | def pymPxp(a, b): 869 | ''' 870 | p-vector outer (=vector=cross) product. 871 | 872 | Parameters 873 | ---------- 874 | a : numpy.matrix(1,3) 875 | first p-vector 876 | b : numpy.matrix(1,3) 877 | second p-vector 878 | 879 | Returns 880 | ------- 881 | axb : numpy.matrix(1,3) 882 | a x b 883 | 884 | ''' 885 | lib.iauPxp.argtypes = [vector_double, vector_double, vector_double] 886 | lib.iauPxp.restype = None 887 | 888 | axb = np.asmatrix(np.zeros(shape=(1,3), dtype=float, order='C')) 889 | 890 | lib.iauPxp(a, b, axb) 891 | 892 | return axb 893 | 894 | def pymPxp_A(a, b): 895 | 896 | return np.cross(a, b) 897 | 898 | #2023-05-31 899 | def pymRm2v(r): 900 | ''' 901 | Express an r-matrix as an r-vector. 902 | 903 | Parameters 904 | ---------- 905 | r : numpy.matrix(3,3) 906 | rotation matrix 907 | 908 | Returns 909 | ------- 910 | w : numpy.matrix(1,3) 911 | rotation vector 912 | 913 | ''' 914 | lib.iauRm2v.argtypes = [vector_double3, vector_double] 915 | lib.iauRm2v.restype = None 916 | 917 | w = np.asmatrix(np.zeros(shape=(1,3), dtype=float, order='C')) 918 | 919 | lib.iauRm2v(r, w) 920 | 921 | return w 922 | 923 | 924 | def pymRv2m(w): 925 | ''' 926 | Form the r-matrix corresponding to a given r-vector. 927 | 928 | Parameters 929 | ---------- 930 | w : numpy.matrix(1,3) 931 | rotation vector 932 | 933 | Returns 934 | ------- 935 | r : numpy.matrix(3,3) 936 | rotation matrix 937 | 938 | ''' 939 | lib.iauRv2m.argtypes = [vector_double, vector_double3] 940 | lib.iauRv2m.restype = None 941 | 942 | r = np.asmatrix(np.zeros(shape=(3,3), dtype=float, order='C')) 943 | 944 | lib.iauRv2m(w, r) 945 | 946 | return r 947 | 948 | 949 | def pymRx(phi, r): 950 | ''' 951 | Rotate an r-matrix about the x-axis. 952 | 953 | Parameters 954 | ---------- 955 | phi : float 956 | angle (radians) 957 | r : numpy.matrix(3,3) 958 | r-matrix 959 | 960 | Returns 961 | ------- 962 | r : numpy.matrix(3,3) 963 | r-matrix, rotated 964 | 965 | ''' 966 | lib.iauRx.argtypes = [c_double, vector_double3] 967 | lib.iauRx.restype = None 968 | 969 | # r = np.asmatrix(np.zeros(shape=(3,3), dtype=float, order='C')) 970 | 971 | lib.iauRx(phi, r) 972 | 973 | return r 974 | 975 | #Python codes for iauRx 976 | def pymRx_A(phi, r): 977 | 978 | cos_phi = np.math.cos(phi) 979 | sin_phi = np.math.sin(phi) 980 | 981 | # to be in accordance with SOFA definition for Rx 982 | mat_rx = np.array( 983 | [ [1, 0, 0], 984 | [0, cos_phi, sin_phi], 985 | [0, -sin_phi, cos_phi] 986 | ]).reshape(3,3) 987 | 988 | return np.dot(mat_rx, r) 989 | 990 | 991 | #2023-06-03 992 | 993 | def pymRxp(r, p): 994 | ''' 995 | Multiply a p-vector by an r-matrix. 996 | 997 | Parameters 998 | ---------- 999 | r : numpy.matrix(3,3) 1000 | r-matrix 1001 | p : numpy.matrix(1,3) 1002 | p-vector 1003 | 1004 | Returns 1005 | ------- 1006 | rp : numpy.matrix(3,3) 1007 | r * p 1008 | 1009 | ''' 1010 | lib.iauRxp.argtypes = [vector_double3, vector_double, vector_double] 1011 | lib.iauRxp.restype = None 1012 | 1013 | rp = np.asmatrix(np.zeros(shape=(1,3), dtype=float, order='C')) 1014 | lib.iauRxp(r, p, rp) 1015 | 1016 | return rp 1017 | 1018 | def pymRxp_A(r, p): 1019 | 1020 | return np.dot(r, p) 1021 | 1022 | 1023 | def pymRxpv(r, pv): 1024 | ''' 1025 | Multiply a pv-vector by an r-matrix. 1026 | 1027 | Parameters 1028 | ---------- 1029 | r : numpy.matrix(3,3) 1030 | r-matrix 1031 | pv : numpy.matrix(2,3) 1032 | pv-vector 1033 | 1034 | Returns 1035 | ------- 1036 | rpv : numpy.matrix(2,3) 1037 | r * pv 1038 | 1039 | ''' 1040 | lib.iauRxpv.argtypes = [vector_double3, vector_double2, vector_double2] 1041 | lib.iauRxpv.restype = None 1042 | 1043 | rpv = np.asmatrix(np.zeros(shape=(2,3), dtype=float, order='C')) 1044 | lib.iauRxpv(r, pv, rpv) 1045 | 1046 | return rpv 1047 | 1048 | def pymRxpv_A(r, pv): 1049 | 1050 | #transpose 3,2 => 2, 3 1051 | 1052 | return np.dot(r, pv).T 1053 | 1054 | 1055 | 1056 | def pymRxr(a, b): 1057 | ''' 1058 | Multiply two r-matrices. 1059 | 1060 | Parameters 1061 | ---------- 1062 | a : numpy.matrix(3,3) 1063 | first r-matrix 1064 | b : numpy.matrix(3,3) 1065 | second r-matrix 1066 | 1067 | Returns 1068 | ------- 1069 | atb : numpy.matrix(3,3) 1070 | a * b 1071 | 1072 | ''' 1073 | lib.iauRxr.argtypes = [vector_double3, vector_double3, vector_double3] 1074 | lib.iauRxr.restype = None 1075 | 1076 | atb = np.asmatrix(np.zeros(shape=(3,3), dtype=float, order='C')) 1077 | lib.iauRxr(a, b, atb) 1078 | 1079 | return atb 1080 | 1081 | def pymRxr_A(a, b): 1082 | 1083 | return np.dot(a, b) 1084 | 1085 | 1086 | 1087 | def pymRy(theta, r): 1088 | ''' 1089 | Rotate an r-matrix about the y-axis. 1090 | 1091 | Parameters 1092 | ---------- 1093 | theta : float 1094 | angle (radians) 1095 | r : numpy.matrix(3,3) 1096 | r-matrix 1097 | 1098 | Returns 1099 | ------- 1100 | r : numpy.matrix(3,3) 1101 | r-matrix, rotated 1102 | 1103 | ''' 1104 | lib.iauRy.argtypes = [c_double, vector_double3] 1105 | lib.iauRy.restype = None 1106 | 1107 | # r = np.asmatrix(np.zeros(shape=(3,3), dtype=float, order='C')) 1108 | 1109 | lib.iauRy(theta, r) 1110 | 1111 | return r 1112 | 1113 | #Python codes for iauRy 1114 | def pymRy_A(theta, r): 1115 | 1116 | cos_theta = np.math.cos(theta) 1117 | sin_theta = np.math.sin(theta) 1118 | 1119 | # to be in accordance with SOFA definition for Ry 1120 | mat_ry = np.array( 1121 | [ [cos_theta, 0, -sin_theta], 1122 | [0, 1, 0 ], 1123 | [sin_theta, 0, cos_theta] 1124 | ]).reshape(3,3) 1125 | 1126 | return np.dot(mat_ry, r) 1127 | 1128 | 1129 | 1130 | def pymRz(psi, r): 1131 | ''' 1132 | Rotate an r-matrix about the z-axis. 1133 | 1134 | Parameters 1135 | ---------- 1136 | psi : float 1137 | angle (radians) 1138 | r : numpy.matrix(3,3) 1139 | r-matrix 1140 | 1141 | Returns 1142 | ------- 1143 | r : numpy.matrix(3,3) 1144 | r-matrix, rotated 1145 | 1146 | ''' 1147 | lib.iauRz.argtypes = [c_double, vector_double3] 1148 | lib.iauRz.restype = None 1149 | 1150 | # r = np.asmatrix(np.zeros(shape=(3,3), dtype=float, order='C')) 1151 | 1152 | lib.iauRz(psi, r) 1153 | 1154 | return r 1155 | 1156 | #Python codes for iauRz 1157 | def pymRz_A(psi, r): 1158 | 1159 | cos_psi = np.math.cos(psi) 1160 | sin_psi = np.math.sin(psi) 1161 | 1162 | # to be in accordance with SOFA definition for Ry 1163 | mat_rz = np.array( 1164 | [ [ cos_psi, sin_psi, 0], 1165 | [-sin_psi, cos_psi, 0], 1166 | [0, 0, 1] 1167 | ]).reshape(3,3) 1168 | 1169 | return np.dot(mat_rz, r) 1170 | 1171 | #def pymS2c(theta, phi): see previously 1172 | 1173 | 1174 | def pymS2p(theta, phi, r): 1175 | ''' 1176 | Convert spherical polar coordinates to p-vector. 1177 | 1178 | Parameters 1179 | ---------- 1180 | theta : float 1181 | longitude angle (radians) 1182 | phi : float 1183 | latitude angle (radians) 1184 | r : float 1185 | radial distance 1186 | 1187 | Returns 1188 | ------- 1189 | p : numpy.matrix(1,3) 1190 | Cartesian coordinates 1191 | 1192 | ''' 1193 | lib.iauS2p.argtypes = [c_double, c_double, c_double, vector_double] 1194 | lib.iauS2p.restype = None 1195 | 1196 | p = np.asmatrix(np.zeros(shape=(1,3), dtype=float, order='C')) 1197 | lib.iauS2p(theta, phi, r, p) 1198 | 1199 | return p 1200 | 1201 | #2023-06-04 1202 | 1203 | def pymS2pv(theta, phi, r, td, pd, rd): 1204 | ''' 1205 | Convert position/velocity from spherical to Cartesian coordinates. 1206 | 1207 | Parameters 1208 | ---------- 1209 | theta : float 1210 | longitude angle (radians) 1211 | phi : float 1212 | latitude angle (radians) 1213 | r : float 1214 | radial distance 1215 | td : float 1216 | rate of change of theta 1217 | pd : float 1218 | rate of change of phi 1219 | rd : float 1220 | rate of change of r 1221 | 1222 | Returns 1223 | ------- 1224 | pv : numpy.matrix(2,3) 1225 | pv-vector 1226 | 1227 | ''' 1228 | lib.iauS2pv.argtypes = [c_double, c_double, c_double, 1229 | c_double, c_double, c_double, 1230 | vector_double2] 1231 | lib.iauS2pv.restype = None 1232 | 1233 | pv = np.asmatrix(np.zeros(shape=(2,3), dtype=float, order='C')) 1234 | lib.iauS2pv(theta, phi, r, td, pd, rd, pv) 1235 | 1236 | return pv 1237 | 1238 | 1239 | def pymS2xpv(s1, s2, pv): 1240 | ''' 1241 | Multiply a pv-vector by two scalars. 1242 | 1243 | Parameters 1244 | ---------- 1245 | s1 : float 1246 | scalar to multiply position component by 1247 | s2 : float 1248 | scalar to multiply velocity component by 1249 | pv : numpy.matrix(2,3) 1250 | pv-vector 1251 | 1252 | Returns 1253 | ------- 1254 | spv : numpy.matrix(2,3) 1255 | pv-vector: p scaled by s1, v scaled by s2 1256 | 1257 | ''' 1258 | lib.iauS2xpv.argtypes = [c_double, c_double, vector_double2, vector_double2] 1259 | lib.iauS2xpv.restype = None 1260 | 1261 | spv = np.asmatrix(np.zeros(shape=(2,3), dtype=float, order='C')) 1262 | lib.iauS2xpv(s1, s2, pv, spv) 1263 | 1264 | return spv 1265 | 1266 | def pymS2xpv_A(s1, s2, pv): 1267 | 1268 | spv = np.asmatrix(np.zeros(shape=(2,3), dtype=float, order='C')) 1269 | spv[0] = s1 * pv[0] 1270 | spv[1] = s2 * pv[1] 1271 | 1272 | return spv 1273 | 1274 | 1275 | def pymSepp(a, b): 1276 | ''' 1277 | Angular separation between two p-vectors. 1278 | 1279 | Parameters 1280 | ---------- 1281 | a : numpy.matrix(1,3) 1282 | first p-vector (not necessarily unit length) 1283 | b : numpy.matrix(1,3) 1284 | second p-vector (not necessarily unit length) 1285 | 1286 | Returns 1287 | ------- 1288 | function value : float 1289 | angular separation (radians, always positive) 1290 | 1291 | ''' 1292 | lib.iauSepp.argtypes = [vector_double, vector_double] 1293 | lib.iauSepp.restype = c_double 1294 | 1295 | return lib.iauSepp(a, b) 1296 | 1297 | #Python codes for iauSepp 1298 | def pymSepp_A(a, b): 1299 | 1300 | axb = np.cross(a, b) 1301 | sin_phi = np.linalg.norm(axb, ord=2) 1302 | cos_phi = np.dot(a, b) 1303 | 1304 | return np.math.atan2(sin_phi, cos_phi) 1305 | 1306 | 1307 | def pymSeps(al, ap, bl, bp): 1308 | ''' 1309 | Angular separation between two sets of spherical coordinates. 1310 | 1311 | Parameters 1312 | ---------- 1313 | al : float 1314 | first longitude (radians) 1315 | ap : float 1316 | first latitude (radians) 1317 | bl : float 1318 | second longitude (radians) 1319 | bp : float 1320 | second latitude (radians) 1321 | 1322 | Returns 1323 | ------- 1324 | function value : float 1325 | angular separation (radians) 1326 | 1327 | ''' 1328 | lib.iauSeps.argtypes = [c_double, c_double, c_double, c_double] 1329 | lib.iauSeps.restype = c_double 1330 | 1331 | return lib.iauSeps(al, ap, bl, bp) 1332 | 1333 | 1334 | def pymSxp(s, p): 1335 | ''' 1336 | Multiply a p-vector by a scalar. 1337 | 1338 | Parameters 1339 | ---------- 1340 | s : float 1341 | scalar 1342 | p : numpy.matrix(1,3) 1343 | p-vector 1344 | 1345 | Returns 1346 | ------- 1347 | sp : numpy.matrix(1,3) 1348 | s * p 1349 | 1350 | ''' 1351 | lib.iauSxp.argtypes = [c_double, vector_double, vector_double] 1352 | lib.iauSxp.restype = None 1353 | 1354 | sp = np.asmatrix(np.zeros(shape=(1,3), dtype=float, order='C')) 1355 | lib.iauSxp(s, p, sp) 1356 | 1357 | return sp 1358 | 1359 | 1360 | def pymSxp_A(s, p): 1361 | 1362 | return np.asmatrix(s*p) 1363 | 1364 | 1365 | def pymSxpv(s, pv): 1366 | ''' 1367 | Multiply a pv-vector by a scalar. 1368 | 1369 | Parameters 1370 | ---------- 1371 | s : float 1372 | scalar 1373 | pv : numpy.matrix(2,3) 1374 | pv-vector 1375 | 1376 | Returns 1377 | ------- 1378 | spv : numpy.matrix(2,3) 1379 | s * pv 1380 | 1381 | ''' 1382 | lib.iauSxpv.argtypes = [c_double, vector_double2, vector_double2] 1383 | lib.iauSxpv.restype = None 1384 | 1385 | spv = np.asmatrix(np.zeros(shape=(2,3), dtype=float, order='C')) 1386 | lib.iauSxpv(s, pv, spv) 1387 | 1388 | return spv 1389 | 1390 | pym_tf2a_msg = { 1391 | 1:'ihour outside range 0-23', 1392 | 2:'imin outside range 0-59', 1393 | 3:'sec outside range 0-59.999...' 1394 | } 1395 | 1396 | 1397 | 1398 | #def pymTf2d(s, ihour, imin, sec): see previously 1399 | 1400 | def pymTr(r): 1401 | ''' 1402 | Transpose an r-matrix. 1403 | 1404 | Parameters 1405 | ---------- 1406 | r : numpy.matrix(3,3) 1407 | r-matrix 1408 | 1409 | Returns 1410 | ------- 1411 | rt : numpy.matrix(3,3) 1412 | transpose 1413 | 1414 | ''' 1415 | lib.iauTr.argtypes = [vector_double3, vector_double3] 1416 | lib.iauTr.restype = None 1417 | 1418 | rt = np.asmatrix(np.zeros(shape=(3,3), dtype=float, order='C')) 1419 | 1420 | lib.iauTr(r, rt) 1421 | 1422 | return rt 1423 | 1424 | def pymTr_A(r): 1425 | 1426 | return r.T 1427 | 1428 | def pymTrxp(r, p): 1429 | ''' 1430 | Multiply a p-vector by the transpose of an r-matrix. 1431 | 1432 | Parameters 1433 | ---------- 1434 | r : numpy.matrix(3,3) 1435 | r-matrix 1436 | p : numpy.matrix(1,3) 1437 | p-vector 1438 | 1439 | Returns 1440 | ------- 1441 | trp : numpy.matrix(1,3) 1442 | r^T * p 1443 | 1444 | ''' 1445 | lib.iauTrxp.argtypes = [vector_double3, vector_double, vector_double] 1446 | lib.iauTrxp.restype = None 1447 | 1448 | trp = np.asmatrix(np.zeros(shape=(1,3), dtype=float, order='C')) 1449 | 1450 | lib.iauTrxp(r, p, trp) 1451 | 1452 | return trp 1453 | 1454 | def pymTrxp_A(r, p): 1455 | 1456 | # trp = np.asmatrix(np.zeros(shape=(1,3), dtype=float, order='C')) 1457 | trp = np.dot(r.T, p) 1458 | 1459 | return np.asmatrix(trp) 1460 | 1461 | def pymTrxpv(r, pv): 1462 | ''' 1463 | Multiply a pv-vector by the transpose of an r-matrix. 1464 | 1465 | Parameters 1466 | ---------- 1467 | r : numpy.matrix(3,3) 1468 | r-matrix 1469 | pv : numpy.matrix(2,3) 1470 | pv-vector 1471 | 1472 | Returns 1473 | ------- 1474 | trpv : numpy.matrix(2,3) 1475 | r^T * pv 1476 | 1477 | ''' 1478 | lib.iauTrxpv.argtypes = [vector_double3, vector_double2, vector_double2] 1479 | lib.iauTrxpv.restype = None 1480 | 1481 | trpv = np.asmatrix(np.zeros(shape=(2,3), dtype=float, order='C')) 1482 | 1483 | lib.iauTrxpv(r, pv, trpv) 1484 | 1485 | return trpv 1486 | 1487 | 1488 | def pymTrxpv_A(r, pv): 1489 | 1490 | return np.dot(r.T, pv.T).T 1491 | 1492 | 1493 | def pymZp(p): 1494 | ''' 1495 | Zero a p-vector 1496 | 1497 | Parameters 1498 | ---------- 1499 | p : numpy.matrix(1,3) 1500 | p-vector 1501 | 1502 | Returns 1503 | ------- 1504 | p : numpy.matrix(1,3) 1505 | zero p-vector 1506 | ''' 1507 | 1508 | lib.iauZp.argtypes = [vector_double] 1509 | lib.iauZp.restype = None 1510 | 1511 | # pr = np.asmatrix(np.zeros(shape=(1,3), dtype=float, order='C')) 1512 | 1513 | lib.iauZp(p) 1514 | 1515 | return p 1516 | 1517 | def pymZp_A(p): 1518 | 1519 | pt = np.asmatrix(np.zeros(shape=(1,3), dtype=float, order='C')) 1520 | 1521 | return pt 1522 | 1523 | def pymZpv(pv): 1524 | ''' 1525 | Zero a pv-vector 1526 | 1527 | Parameters 1528 | ---------- 1529 | pv : numpy.matrix(2,3) 1530 | pv-vector 1531 | 1532 | Returns 1533 | ------- 1534 | pv : numpy.matrix(2,3) 1535 | zero pv-vector 1536 | 1537 | ''' 1538 | lib.iauZpv.argtypes = [vector_double2] 1539 | lib.iauZpv.restype = None 1540 | 1541 | # pr = np.asmatrix(np.zeros(shape=(2,3), dtype=float, order='C')) 1542 | 1543 | lib.iauZpv(pv) 1544 | 1545 | return pv 1546 | 1547 | def pymZpv_A(pv): 1548 | 1549 | pvt = np.asmatrix(np.zeros(shape=(2,3), dtype=float, order='C')) 1550 | 1551 | return pvt 1552 | 1553 | def pymZr(r): 1554 | ''' 1555 | Initialize an r-matrix to the null matrix. 1556 | 1557 | Parameters 1558 | ---------- 1559 | r : numpy.matrix(3,3) 1560 | r-matrix 1561 | 1562 | Returns 1563 | ------- 1564 | r : numpy.matrix(3,3) 1565 | null matrix 1566 | 1567 | ''' 1568 | lib.iauZr.argtypes = [vector_double3] 1569 | lib.iauZr.restype = None 1570 | 1571 | # pr = np.asmatrix(np.zeros(shape=(3,3), dtype=float, order='C')) 1572 | 1573 | lib.iauZr(r) 1574 | 1575 | return r 1576 | 1577 | 1578 | def pymZr_A(r): 1579 | 1580 | rt = np.asmatrix(np.zeros(shape=(3,3), dtype=float, order='C')) 1581 | 1582 | return rt 1583 | 1584 | -------------------------------------------------------------------------------- /ctypes/PyMsOfa_time.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Tue Feb 28 02:44:08 2023 4 | Done on Mon Jun 5 02:11:37 2023 5 | @author: Dr. Jianghui JI (jijh@pmo.ac.cn) 6 | """ 7 | #from numba import jit 8 | #from __future__ import print_function 9 | import ctypes 10 | from ctypes import * 11 | import numpy as np 12 | import numpy.ctypeslib as nt 13 | import warnings as ws 14 | import os 15 | import sys 16 | import platform as pf 17 | 18 | #dll = ctypes.cdll.LoadLibrary 19 | #lib = dll('./libsofa_c.so') 20 | 21 | #compile sofa_c.c to create libsofa_c.so shared libary 22 | #gcc -shared -fPIC -o libsofa_c.so sofa_a.c 23 | 24 | #path = os.getcwd() 25 | #lib = CDLL(os.path.join(path, 'libsofa_c.so')) 26 | 27 | 28 | ''' 29 | Descr: return file name/path information 30 | # Input: 31 | filepath: full path of a file 32 | 33 | # Return values: 34 | dirname: directory name of a file 35 | fullname: full name of a file 36 | filename: file name of a file 37 | extension: file extension 38 | ''' 39 | def getFileName(filepath): 40 | 41 | __file__ = filepath 42 | 43 | dirname = os.path.dirname(__file__) 44 | fullname = os.path.split(__file__)[-1] 45 | filename = os.path.split(__file__)[-1].split('.')[0] 46 | extension = os.path.split(__file__)[-1].split('.')[1] 47 | 48 | return dirname, fullname, filename, extension 49 | 50 | 51 | def getFilePath(filepath): 52 | 53 | __file__ = filepath 54 | 55 | dirname = os.path.dirname(__file__) 56 | fullname = os.path.split(__file__)[-1] 57 | filename = os.path.split(__file__)[-1].split('.')[0] 58 | extension = os.path.split(__file__)[-1].split('.')[1] 59 | 60 | return dirname 61 | 62 | #place libsofa_c.so in the same directory with PyMsOfa.py 63 | cur_dir = sys.argv[0] 64 | #dirname, fullname, filename, extension = getFileName(cur_dir) 65 | dirname = getFilePath(cur_dir) 66 | libs_file = 'libsofa_c.so' 67 | libs_path = os.path.join(dirname, libs_file) 68 | #lib = CDLL(libs_path) 69 | 70 | 71 | #''' 72 | #for windows 73 | if pf.system().lower() == 'windows': 74 | 75 | #user_path = './' 76 | #libs_file = 'libsofa_c.so' 77 | #libs_path = user_path + libs_file 78 | #print(libs_path) 79 | #lib = CDLL(libs_path) 80 | 81 | #print(libs_path) 82 | lib = CDLL(libs_path) 83 | 84 | #for linux 85 | elif pf.system().lower() == 'linux': 86 | dirname = os.getcwd() 87 | lib = CDLL(os.path.join(dirname, libs_file)) 88 | #lib = CDLL('./libsofa_c.so') 89 | #print(libs_path) 90 | #lib = CDLL(libs_path) 91 | 92 | #for macOS 93 | elif pf.system().lower() == 'darwin': 94 | 95 | lib = CDLL(libs_path) 96 | 97 | #''' 98 | 99 | c_int4 = c_int * 4 100 | 101 | array_1d_double = nt.ndpointer(shape=(1,3), dtype=np.double, flags='C') 102 | vector_double = nt.ndpointer(shape=(1,3), dtype=np.double, flags='C') 103 | array_double_2 = nt.ndpointer(shape=(1,2), dtype=np.double, flags='C') 104 | c_double_p = POINTER(c_double) 105 | 106 | def pymGmst00(uta, utb, tta, ttb): 107 | ''' 108 | Greenwich mean sidereal time (model consistent with IAU 2000 109 | resolutions). 110 | 111 | Parameters 112 | ---------- 113 | uta : float 114 | UT1 as a 2-part Julian Date 115 | utb : float 116 | UT1 as a 2-part Julian Date 117 | tta : float 118 | TT as a 2-part Julian Date 119 | ttb : float 120 | TT as a 2-part Julian Date 121 | 122 | Returns 123 | ------- 124 | function value : float 125 | Greenwich mean sidereal time (radians) 126 | 127 | ''' 128 | lib.iauGmst00.argtypes =[c_double, c_double, c_double, c_double] 129 | 130 | lib.iauGmst00.restype = c_double 131 | 132 | return lib.iauGmst00(uta, utb, tta, ttb) 133 | 134 | def pymGmst06(uta, utb, tta, ttb): 135 | ''' 136 | Greenwich mean sidereal time (consistent with IAU 2006 precession). 137 | 138 | Parameters 139 | ---------- 140 | uta : float 141 | UT1 as a 2-part Julian Date 142 | utb : float 143 | UT1 as a 2-part Julian Date 144 | tta : float 145 | TT as a 2-part Julian Date 146 | ttb : float 147 | TT as a 2-part Julian Date 148 | 149 | Returns 150 | ------- 151 | function value : float 152 | Greenwich mean sidereal time (radians) 153 | 154 | ''' 155 | lib.iauGmst06.argtypes =[c_double, c_double, c_double, c_double] 156 | 157 | lib.iauGmst06.restype = c_double 158 | 159 | return lib.iauGmst06(uta, utb, tta, ttb) 160 | 161 | def pymGmst82(dj1, dj2): 162 | ''' 163 | Universal Time to Greenwich mean sidereal time (IAU 1982 model). 164 | 165 | Parameters 166 | ---------- 167 | dj1 : float 168 | UT1 Julian Date 169 | dj2 : float 170 | UT1 Julian Date 171 | 172 | Returns 173 | ------- 174 | function value : float 175 | Greenwich mean sidereal time (radians) 176 | 177 | ''' 178 | lib.iauGmst82.argtypes =[c_double, c_double] 179 | 180 | lib.iauGmst82.restype = c_double 181 | 182 | return lib.iauGmst82(dj1, dj2) 183 | 184 | def pymGst00a(uta, utb, tta, ttb): 185 | ''' 186 | Greenwich apparent sidereal time (consistent with IAU 2000 187 | resolutions). 188 | 189 | Parameters 190 | ---------- 191 | uta : float 192 | UT1 as a 2-part Julian Date 193 | utb : float 194 | UT1 as a 2-part Julian Date 195 | tta : float 196 | TT as a 2-part Julian Date 197 | ttb : float 198 | TT as a 2-part Julian Date 199 | 200 | Returns 201 | ------- 202 | function value : float 203 | Greenwich apparent sidereal time (radians) 204 | 205 | ''' 206 | lib.iauGst00a.argtypes =[c_double, c_double, c_double, c_double] 207 | 208 | lib.iauGst00a.restype = c_double 209 | 210 | return lib.iauGst00a(uta, utb, tta, ttb) 211 | 212 | def pymGst00b(uta, utb): 213 | ''' 214 | Greenwich apparent sidereal time (consistent with IAU 2000 215 | resolutions but using the truncated nutation model IAU 2000B). 216 | 217 | Parameters 218 | ---------- 219 | uta : float 220 | UT1 as a 2-part Julian Date 221 | utb : float 222 | UT1 as a 2-part Julian Date 223 | 224 | Returns 225 | ------- 226 | function value : float 227 | Greenwich apparent sidereal time (radians) 228 | 229 | ''' 230 | lib.iauGst00b.argtypes =[c_double, c_double] 231 | 232 | lib.iauGst00b.restype = c_double 233 | 234 | return lib.iauGst00b(uta, utb) 235 | 236 | def pymGst06(uta, utb, tta, ttb, rnpb): 237 | ''' 238 | Greenwich apparent sidereal time, IAU 2006, given the NPB matrix. 239 | 240 | Parameters 241 | ---------- 242 | uta : float 243 | UT1 as a 2-part Julian Date 244 | utb : float 245 | UT1 as a 2-part Julian Date 246 | tta : float 247 | TT as a 2-part Julian Date 248 | ttb : float 249 | TT as a 2-part Julian Date 250 | rnpb : float 251 | nutation x precession x bias matrix 252 | 253 | Returns 254 | ------- 255 | function value : float 256 | Greenwich apparent sidereal time (radians) 257 | 258 | ''' 259 | lib.iauGst06.argtypes = [c_double, c_double, c_double, c_double, 260 | vector_double3] 261 | lib.iauGst06.restype = c_double 262 | 263 | 264 | return lib.iauGst06(uta, utb, tta, ttb, rnpb) 265 | 266 | def pymGst06a(uta, utb, tta, ttb): 267 | ''' 268 | Greenwich apparent sidereal time (consistent with IAU 2000 and 2006 269 | resolutions). 270 | 271 | Parameters 272 | ---------- 273 | uta : float 274 | UT1 as a 2-part Julian Date 275 | utb : float 276 | UT1 as a 2-part Julian Date 277 | tta : float 278 | TT as a 2-part Julian Date 279 | ttb : float 280 | TT as a 2-part Julian Date 281 | 282 | Returns 283 | ------- 284 | function value : float 285 | Greenwich apparent sidereal time (radians) 286 | 287 | ''' 288 | lib.iauGst06a.argtypes = [c_double, c_double, c_double, c_double] 289 | 290 | lib.iauGst06a.restype = c_double 291 | 292 | 293 | return lib.iauGst06a(uta, utb, tta, ttb) 294 | 295 | def pymGst94(uta, utb): 296 | ''' 297 | Greenwich apparent sidereal time (consistent with IAU 1982/94 298 | resolutions). 299 | 300 | Parameters 301 | ---------- 302 | uta : float 303 | UT1 as a 2-part Julian Date 304 | utb : float 305 | UT1 as a 2-part Julian Date 306 | 307 | Returns 308 | ------- 309 | function value : float 310 | Greenwich apparent sidereal time (radians) 311 | 312 | ''' 313 | lib.iauGst94.argtypes =[c_double, c_double] 314 | 315 | lib.iauGst94.restype = c_double 316 | 317 | return lib.iauGst94(uta, utb) 318 | 319 | #int iauCal2jd(int iy, int im, int id, double *djm0, double *djm) 320 | pym_cal2jd_msg = { 321 | -1: 'bad year, the year is simply valid from -4800 March 1', 322 | -2: 'bad month, the month is not from 1 to 12', 323 | -3: 'bad day, the day is not related to the month' 324 | } 325 | 326 | c_double_p = POINTER(c_double) 327 | def pymCal2jd_A(iyear, imon, iday, djm0, djm): 328 | 329 | lib.iauCal2jd.argtypes = [c_int, c_int, c_int, c_double_p, c_double_p] 330 | lib.iauCal2jd.restype = c_int 331 | 332 | j = lib.iauCal2jd(iyear, imon, iday, byref(djm0), byref(djm)) 333 | if j != 0: 334 | raise ValueError(pym_cal2jd_msg[j]) 335 | return 336 | 337 | def pymCal2jd(iyear, imon, iday): 338 | ''' 339 | Gregorian Calendar to Julian Date. 340 | 341 | Parameters 342 | ---------- 343 | iyear : int 344 | year in Gregorian calendar 345 | imon : int 346 | month in Gregorian calendar 347 | iday : int 348 | day in Gregorian calendar 349 | 350 | Raises 351 | ------ 352 | ValueError 353 | -1: 'bad year, the year is simply valid from -4800 March 1', 354 | -2: 'bad month, the month is not from 1 to 12', 355 | -3: 'bad day, the day is not related to the month' 356 | 357 | Returns 358 | ------- 359 | djm0 : float 360 | MJD zero-point: always 2400000.5 361 | djm : float 362 | Modified Julian Date for 0 hrs 363 | 364 | ''' 365 | lib.iauCal2jd.argtypes = [c_int, c_int, c_int, c_double_p, c_double_p] 366 | lib.iauCal2jd.restype = c_int 367 | djm0 = c_double() 368 | djm = c_double() 369 | j = lib.iauCal2jd(iyear, imon, iday, byref(djm0), byref(djm)) 370 | if j != 0: 371 | raise ValueError(pym_cal2jd_msg[j]) 372 | return djm0.value, djm.value 373 | 374 | c_int_p = POINTER(c_int) 375 | pym_jd2cal_msg ={ 376 | -1: 'The valid date is -68569.5 (-4900 March 1) up to 1e9' 377 | } 378 | 379 | def pymJd2cal(dj1, dj2): 380 | ''' 381 | Julian Date to Gregorian year, month, day, and fraction of a day. 382 | 383 | Parameters 384 | ---------- 385 | dj1 : float 386 | Julian Date 387 | dj2 : float 388 | Julian Date 389 | 390 | Raises 391 | ------ 392 | ValueError 393 | -1: 'The valid date is -68569.5 (-4900 March 1) up to 1e9' 394 | 395 | Returns 396 | ------- 397 | iy : int 398 | yaer 399 | im : int 400 | month 401 | id : int 402 | day 403 | fd : float 404 | fraction of day 405 | 406 | ''' 407 | lib.iauJd2cal.argtypes = [c_double, c_double, c_int_p, 408 | c_int_p, c_int_p, c_double_p ] 409 | lib.iauJd2cal.restype = c_int 410 | iy = c_int() 411 | im = c_int() 412 | iday = c_int() 413 | fday = c_double() 414 | 415 | j = lib.iauJd2cal(dj1, dj2, byref(iy), byref(im), byref(iday), byref(fday)) 416 | if j != 0: 417 | raise ValueError(pym_jd2cal_msg[j]) 418 | return iy.value, im.value, iday.value, fday.value 419 | 420 | #int iauJdcalf(int ndp, double dj1, double dj2, int iymdf[4]) 421 | def pymJdcalf(ndp, dj1, dj2): 422 | ''' 423 | Julian Date to Gregorian Calendar, expressed in a form convenient 424 | for formatting messages: rounded to a specified precision. 425 | 426 | Parameters 427 | ---------- 428 | ndp : int 429 | number of decimal places of days in fraction 430 | dj1 : float 431 | Julian Date 432 | dj2 : float 433 | Julian Date 434 | 435 | Returns 436 | ------- 437 | iymdf : tuple 438 | year, month, day, fraction in Gregorian calendar 439 | 440 | ''' 441 | lib.iauJdcalf.argtypes = [c_int, c_double, c_double] 442 | lib.iauJdcalf.restype = c_int 443 | idmsf = (c_int4)() 444 | 445 | lib.iauJdcalf(ndp, dj1, dj2, idmsf) 446 | return tuple([x for x in idmsf]) 447 | 448 | #void iauD2tf(int ndp, double days, char *sign, int ihmsf[4]) 449 | def pymD2tf(ndp, days): 450 | ''' 451 | Decompose days to hours, minutes, seconds, fraction. 452 | 453 | Parameters 454 | ---------- 455 | ndp : int 456 | resolution 457 | days : float 458 | interval in days 459 | 460 | Returns 461 | ------- 462 | sign : 'bytes' 463 | '+' or '-' 464 | ihmsf : tuple 465 | hours, minutes, seconds, fraction 466 | 467 | NDP resolution 468 | : ...0000 00 00 469 | -7 1000 00 00 470 | -6 100 00 00 471 | -5 10 00 00 472 | -4 1 00 00 473 | -3 0 10 00 474 | -2 0 01 00 475 | -1 0 00 10 476 | 0 0 00 01 477 | 1 0 00 00.1 478 | 2 0 00 00.01 479 | 3 0 00 00.001 480 | : 0 00 00.000... 481 | 482 | ''' 483 | lib.iauD2tf.argtypes = [c_int, c_double, POINTER(c_char), c_int4] 484 | lib.iauD2tf.restype = None 485 | 486 | sign = c_char() 487 | ihmsf = (c_int4)() 488 | 489 | lib.iauD2tf(ndp, float(days), byref(sign), ihmsf) 490 | return sign.value, tuple([x for x in ihmsf]) 491 | 492 | #int iauD2dtf(const char *scale, int ndp, double d1, double d2, 493 | # int *iy, int *im, int *id, int ihmsf[4]) 494 | pym_d2dtf_msg = { 495 | 1: 'dubious year', 496 | -1: 'unacceptable date', 497 | } 498 | 499 | def pymD2dtf(scale, ndp, d1, d2): 500 | ''' 501 | Format for output a 2-part Julian Date (or in the case of UTC a 502 | quasi-JD form that includes special provision for leap seconds). 503 | 504 | Parameters 505 | ---------- 506 | scale : ctypes.c_char_p 507 | time scale ID(Only the value "UTC" is significant) 508 | ndp : int 509 | resolution 510 | d1 : float 511 | time as a 2-part Julian Date 512 | d2 : float 513 | time as a 2-part Julian Date 514 | 515 | Raises 516 | ------ 517 | ValueError 518 | 1: 'dubious year', 519 | -1: 'unacceptable date', 520 | 521 | Returns 522 | ------- 523 | iy,im,id : int 524 | year, month, day in Gregorian calendar 525 | ihmsf : tuple 526 | hours, minutes, seconds, fraction 527 | 528 | NDP resolution 529 | : ...0000 00 00 530 | -7 1000 00 00 531 | -6 100 00 00 532 | -5 10 00 00 533 | -4 1 00 00 534 | -3 0 10 00 535 | -2 0 01 00 536 | -1 0 00 10 537 | 0 0 00 01 538 | 1 0 00 00.1 539 | 2 0 00 00.01 540 | 3 0 00 00.001 541 | : 0 00 00.000... 542 | ''' 543 | 544 | lib.iauD2dtf.argtypes = [c_wchar_p, c_int, c_double, c_double, 545 | c_int_p, c_int_p, c_int_p, c_int4] 546 | lib.iauD2dtf.restype = c_int 547 | 548 | iy = c_int() 549 | im = c_int() 550 | iday = c_int() 551 | ihmsf =(c_int4)() 552 | 553 | j=lib.iauD2dtf(scale, ndp, d1, d2, byref(iy), byref(im), byref(iday), ihmsf) 554 | if j < 0: 555 | raise ValueError(pym_d2dtf_msg[j]) 556 | elif j > 0: 557 | ws.warn(pym_d2dtf_msg[j], UserWarning, 2) 558 | #return iy.value, im.value, iday.value, tuple([x for x in ihmsf]) 559 | return (iy.value, im.value, iday.value) + tuple([x for x in ihmsf]) 560 | 561 | #int iauDat(int iy, int im, int id, double fd, double *deltat) 562 | #Note: current leap second is 2021, this should update and recompile iauDat for new date 563 | pym_dat_msg = { 564 | 1: 'dubious year', 565 | -1: 'bad year, the year is simply valid from -4800 March 1', 566 | -2: 'bad month, the month is not from 1 to 12', 567 | -3: 'bad day, the day is not related to the month', 568 | -4: 'bad fraction of day', 569 | -5: 'internal error', 570 | } 571 | 572 | def pymDat(iy, im, iday, fday): 573 | ''' 574 | For a given UTC date, calculate Delta(AT) = TAI-UTC. 575 | 576 | Parameters 577 | ---------- 578 | iy : int 579 | year 580 | im : int 581 | month 582 | iday : int 583 | day 584 | fday : float 585 | fraction of day 586 | 587 | Raises 588 | ------ 589 | ValueError 590 | 1: 'dubious year', 591 | -1: 'bad year, the year is simply valid from -4800 March 1', 592 | -2: 'bad month, the month is not from 1 to 12', 593 | -3: 'bad day, the day is not related to the month', 594 | -4: 'bad fraction of day', 595 | -5: 'internal error', 596 | 597 | Returns 598 | ------- 599 | deltat : float 600 | TAI minus UTC, seconds 601 | 602 | ''' 603 | lib.iauDat.argtypes = [c_int, c_int, c_int, c_double] 604 | lib.iauDat.restype = c_int 605 | deltat = c_double() 606 | j = lib.iauDat(iy, im, iday, fday, byref(deltat)) 607 | if j < 0: 608 | raise ValueError(pym_dat_msg[j]) 609 | elif j > 0: 610 | ws.warn(pym_dat_msg[j], UserWarning, 2) 611 | return deltat.value 612 | 613 | #double iauDtdb(double date1, double date2, 614 | # double ut, double elong, double u, double v) 615 | 616 | def pymDtdb(date1, date2, ut, elong, u, v): 617 | ''' 618 | An approximation to TDB-TT, the difference between barycentric 619 | dynamical time and terrestrial time, for an observer on the Earth. 620 | 621 | Parameters 622 | ---------- 623 | date1 : float 624 | date, TDB 625 | date2 : float 626 | date, TDB 627 | ut : float 628 | universal time (UT1, fraction of one day) 629 | elong : float 630 | longitude (east positive, radians) 631 | u : float 632 | distance from Earth spin axis (km) 633 | v : float 634 | distance north of equatorial plane (km) 635 | 636 | Returns 637 | ------- 638 | function value : float 639 | TDB-TT (seconds) 640 | 641 | ''' 642 | lib.iauDtdb.argtypes = [c_double, c_double, c_double, 643 | c_double, c_double, c_double] 644 | lib.iauDtdb.restype = c_double 645 | 646 | return lib.iauDtdb(date1, date2, ut, elong, u, v) 647 | 648 | #int iauDtf2d(const char *scale, int iy, int im, int id, 649 | # int ihr, int imn, double sec, double *d1, double *d2) 650 | 651 | pym_dtf2d_msg = { 652 | 3: 'both of next two', 653 | 2: 'time is after end of day', 654 | 1: 'dubious year', 655 | -1: 'bad year, the year is simply valid from -4800 March 1', 656 | -2: 'bad month, the month is not from 1 to 12', 657 | -3: 'bad day, the day is not related to the month', 658 | -4: 'bad hour', 659 | -5: 'bad minute', 660 | -6: 'bad second', 661 | } 662 | 663 | def pymDtf2d(scale, iy, im, id, ihr, imn, sec): 664 | ''' 665 | Encode date and time fields into 2-part Julian Date (or in the case 666 | of UTC a quasi-JD form that includes special provision for leap seconds). 667 | 668 | Parameters 669 | ---------- 670 | scale : ctypes.c_char_p 671 | time scale ID(Only the value "UTC" is significant) 672 | iy : int 673 | year in Gregorian calendar 674 | im : int 675 | month in Gregorian calendar 676 | id : int 677 | day in Gregorian calendar 678 | ihr : int 679 | hour 680 | imn : int 681 | minute 682 | sec : float 683 | seconds 684 | 685 | Raises 686 | ------ 687 | ValueError 688 | 3: 'both of next two', 689 | 2: 'time is after end of day', 690 | 1: 'dubious year', 691 | -1: 'bad year, the year is simply valid from -4800 March 1', 692 | -2: 'bad month, the month is not from 1 to 12', 693 | -3: 'bad day, the day is not related to the month', 694 | -4: 'bad hour', 695 | -5: 'bad minute', 696 | -6: 'bad second', 697 | 698 | Returns 699 | ------- 700 | d1,d2 : float 701 | 2-part Julian Date 702 | 703 | ''' 704 | lib.iauDtf2d.argtypes = [c_wchar_p, c_int, c_int, c_int, 705 | c_int, c_int, c_double, c_double_p , 706 | c_double_p ] 707 | lib.iauDtf2d.restype = c_int 708 | d1 = c_double() 709 | d2 = c_double() 710 | j=lib.iauDtf2d(scale, iy, im, id, ihr, imn, sec, byref(d1), byref(d2)) 711 | if j < 0: 712 | raise ValueError(pym_dtf2d_msg[j]) 713 | elif j > 0: 714 | ws.warn(pym_dtf2d_msg[j], UserWarning, 2) 715 | return d1.value, d2.value 716 | 717 | #double iauEpb(double dj1, double dj2) 718 | def pymEpb(dj1, dj2): 719 | ''' 720 | Julian Date to Besselian Epoch. 721 | 722 | Parameters 723 | ---------- 724 | dj1 : float 725 | Julian Date 726 | dj2 : float 727 | Julian Date 728 | 729 | Returns 730 | ------- 731 | function value : float 732 | Besselian Epoch 733 | 734 | ''' 735 | lib.iauEpb.argtypes = [c_double, c_double] 736 | lib.iauEpb.restype = c_double 737 | 738 | return lib.iauEpb(dj1, dj2) 739 | 740 | #directly calculating for comparison 741 | D1900 = 36524.68648E0 742 | DJ00 = 2451545.0E0 743 | DTY = 365.242198781E0 744 | def pymEpb_A(dj1, dj2): 745 | 746 | return 1900.0E0 + ((dj1 - DJ00) + (dj2 + D1900)) / DTY 747 | 748 | #void iauEpb2jd(double epb, double *djm0, double *djm) 749 | def pymEpb2jd(epb): 750 | ''' 751 | Besselian Epoch to Julian Date 752 | 753 | Parameters 754 | ---------- 755 | epb : float 756 | Besselian Epoch 757 | 758 | Returns 759 | ------- 760 | djm0 : float 761 | MJD zero-point: always 2400000.5 762 | djm : float 763 | Modified Julian Date 764 | 765 | ''' 766 | lib.iauEpb2jd.argtypes = [c_double, c_double_p , c_double_p ] 767 | lib.iauEpb2jd.restype = None 768 | djm0 = c_double() 769 | djm = c_double() 770 | lib.iauEpb2jd(epb, byref(djm0), byref(djm)) 771 | return djm0.value, djm.value 772 | 773 | DJM0 = 2400000.5E0 774 | def pymEpb2jd_A(epb): 775 | 776 | djm0 = DJM0 777 | djm = 15019.81352E0 + (epb - 1900.0E0) * DTY 778 | return djm0, djm 779 | 780 | #double iauEpj(double dj1, double dj2) 781 | def pymEpj(dj1, dj2): 782 | ''' 783 | Julian Date to Julian Epoch 784 | 785 | Parameters 786 | ---------- 787 | dj1 : float 788 | Julian Date 789 | dj2 : float 790 | Julian Date 791 | 792 | Returns 793 | ------- 794 | function value : float 795 | Julian Epoch 796 | 797 | ''' 798 | lib.iauEpj.argtypes = [c_double, c_double] 799 | lib.iauEpj.restype = c_double 800 | 801 | return lib.iauEpj(dj1, dj2) 802 | 803 | DJY = 365.25E0 804 | def pymEpj_A(dj1, dj2): 805 | 806 | epj = 2000.0E0 + ((dj1 - DJ00) + dj2) / DJY 807 | return epj 808 | 809 | def pymEpj2jd(epj): 810 | ''' 811 | Julian Epoch to Julian Date 812 | 813 | Parameters 814 | ---------- 815 | epj : float 816 | Julian Epoch (e.g. 1996.8) 817 | 818 | Returns 819 | ------- 820 | djm0 : float 821 | MJD zero-point: always 2400000.5 822 | djm : float 823 | Modified Julian Date 824 | 825 | ''' 826 | lib.iauEpj2jd.argtypes = [c_double, c_double_p , c_double_p ] 827 | lib.iauEpj2jd.restype = None 828 | djm0 = c_double() 829 | djm = c_double() 830 | lib.iauEpj2jd(epj, byref(djm0), byref(djm)) 831 | 832 | return djm0.value, djm.value 833 | 834 | DJM00 = 51544.5E0 835 | def pymEpj2jd_A(epj): 836 | 837 | djm0 = DJM0 838 | djm = DJM00 + (epj - 2000.0E0) * 365.25E0 839 | return djm0, djm 840 | 841 | #int iauTaitt(double tai1, double tai2, double *tt1, double *tt2) 842 | def pymTaitt(tai1, tai2): 843 | ''' 844 | Time scale transformation: International Atomic Time, TAI, to 845 | Terrestrial Time, TT. 846 | 847 | Parameters 848 | ---------- 849 | tai1 : float 850 | TAI as a 2-part Julian Date 851 | tai2 : float 852 | TAI as a 2-part Julian Date 853 | 854 | Returns 855 | ------- 856 | tt1,tt2 : float 857 | TT as a 2-part Julian Date 858 | 859 | ''' 860 | lib.iauTaitt.argtypes = [c_double, c_double, c_double_p, c_double_p] 861 | lib.iauTaitt.restype = c_int 862 | tt1 = c_double() 863 | tt2 = c_double() 864 | j = lib.iauTaitt(tai1, tai2, byref(tt1), byref(tt2)) 865 | return tt1.value, tt2.value 866 | 867 | #int iauTaiut1(double tai1, double tai2, double dta, 868 | # double *ut11, double *ut12) 869 | 870 | def pymTaiut1(tai1, tai2, dta): 871 | ''' 872 | Time scale transformation: International Atomic Time, TAI, to 873 | Universal Time, UT1. 874 | 875 | Parameters 876 | ---------- 877 | tai1 : float 878 | TAI as a 2-part Julian Date 879 | tai2 : float 880 | TAI as a 2-part Julian Date 881 | dta : float 882 | UT1-TAI in seconds 883 | 884 | Returns 885 | ------- 886 | ut11,ut12 : float 887 | UT1 as a 2-part Julian Date 888 | 889 | ''' 890 | lib.iauTaiut1.argtypes = [c_double, c_double, c_double, c_double_p, c_double_p] 891 | lib.iauTaiut1.restype = c_int 892 | ut11 = c_double() 893 | ut12 = c_double() 894 | j = lib.iauTaiut1(tai1, tai2, dta, byref(ut11), byref(ut12)) 895 | return ut11.value, ut12.value 896 | 897 | #int iauTaiutc(double tai1, double tai2, double *utc1, double *utc2) 898 | pym_taiutc_msg = { 899 | 1: 'dubious year', 900 | -1: 'unacceptable date', 901 | } 902 | def pymTaiutc(tai1, tai2): 903 | ''' 904 | Time scale transformation: International Atomic Time, TAI, to 905 | Coordinated Universal Time, UTC. 906 | 907 | Parameters 908 | ---------- 909 | tai1 : float 910 | TAI as a 2-part Julian Date 911 | tai2 : float 912 | TAI as a 2-part Julian Date 913 | 914 | Raises 915 | ------ 916 | ValueError 917 | 1: 'dubious year', 918 | -1: 'unacceptable date', 919 | 920 | Returns 921 | ------- 922 | utc1 : float 923 | UTC as a 2-part quasi Julian Date 924 | utc2 : float 925 | UTC as a 2-part quasi Julian Date 926 | 927 | ''' 928 | lib.iauTaiutc.argtypes = [c_double, c_double, c_double_p, c_double_p] 929 | lib.iauTaiutc.restype = c_int 930 | utc1 = c_double() 931 | utc2 = c_double() 932 | j = lib.iauTaiutc(tai1, tai2, byref(utc1), byref(utc2)) 933 | if j < 0: 934 | raise ValueError(pym_taiutc_msg[j]) 935 | elif j > 0: 936 | ws.warn(pym_taiutc_msg[j], UserWarning, 2) 937 | return utc1.value, utc2.value 938 | 939 | #int iauTcbtdb(double tcb1, double tcb2, double *tdb1, double *tdb2) 940 | def pymTcbtdb(tcb1, tcb2): 941 | ''' 942 | Time scale transformation: Barycentric Coordinate Time, TCB, to 943 | Barycentric Dynamical Time, TDB. 944 | 945 | Parameters 946 | ---------- 947 | tcb1 : float 948 | TCB as a 2-part Julian Date 949 | tcb2 : float 950 | TCB as a 2-part Julian Date 951 | 952 | Returns 953 | ------- 954 | tdb1 : float 955 | TDB as a 2-part Julian Date 956 | tdb2 :float 957 | TDB as a 2-part Julian Date 958 | 959 | ''' 960 | lib.iauTcbtdb.argtypes = [c_double, c_double, c_double_p, c_double_p] 961 | lib.iauTcbtdb.restype = c_int 962 | tdb1 = c_double() 963 | tdb2 = c_double() 964 | j = lib.iauTcbtdb(tcb1, tcb2, byref(tdb1), byref(tdb2)) 965 | 966 | return tdb1.value, tdb2.value 967 | 968 | #int iauTcgtt(double tcg1, double tcg2, double *tt1, double *tt2) 969 | def pymTcgtt(tcg1, tcg2): 970 | ''' 971 | Time scale transformation: Geocentric Coordinate Time, TCG, to 972 | Terrestrial Time, TT. 973 | 974 | Parameters 975 | ---------- 976 | tcg1 : float 977 | TCG as a 2-part Julian Date 978 | tcg2 : float 979 | TCG as a 2-part Julian Date 980 | 981 | Returns 982 | ------- 983 | tt1 : float 984 | TT as a 2-part Julian Date 985 | tt2 : float 986 | TT as a 2-part Julian Date 987 | 988 | ''' 989 | lib.iauTcgtt.argtypes = [c_double, c_double, c_double_p, c_double_p] 990 | lib.iauTcgtt.restype = c_int 991 | 992 | tt1 = c_double() 993 | tt2 = c_double() 994 | j = lib.iauTcgtt(tcg1, tcg2, byref(tt1), byref(tt2)) 995 | 996 | return tt1.value, tt2.value 997 | 998 | #int iauTdbtcb(double tdb1, double tdb2, double *tcb1, double *tcb2) 999 | def pymTdbtcb(tdb1, tdb2): 1000 | ''' 1001 | Time scale transformation: Barycentric Dynamical Time, TDB, to 1002 | Barycentric Coordinate Time, TCB. 1003 | 1004 | Parameters 1005 | ---------- 1006 | tdb1 : float 1007 | TDB as a 2-part Julian Date 1008 | tdb2 : float 1009 | TDB as a 2-part Julian Date 1010 | 1011 | Returns 1012 | ------- 1013 | tcb1 : float 1014 | TCB as a 2-part Julian Date 1015 | tcb2 : float 1016 | TCB as a 2-part Julian Date 1017 | 1018 | ''' 1019 | lib.iauTdbtcb.argtypes = [c_double, c_double, c_double_p, c_double_p] 1020 | lib.iauTdbtcb.restype = c_int 1021 | 1022 | tcb1 = c_double() 1023 | tcb2 = c_double() 1024 | j = lib.iauTdbtcb(tdb1, tdb2, byref(tcb1), byref(tcb2)) 1025 | 1026 | return tcb1.value, tcb2.value 1027 | 1028 | 1029 | #int iauTdbtt(double tdb1, double tdb2, double dtr, 1030 | # double *tt1, double *tt2 ) 1031 | def pymTdbtt(tdb1, tdb2, dtr): 1032 | ''' 1033 | Time scale transformation: Barycentric Dynamical Time, TDB, to 1034 | Terrestrial Time, TT. 1035 | 1036 | Parameters 1037 | ---------- 1038 | tdb1 : float 1039 | TDB as a 2-part Julian Date 1040 | tdb2 : float 1041 | TDB as a 2-part Julian Date 1042 | dtr : float 1043 | TDB-TT in seconds 1044 | 1045 | Returns 1046 | ------- 1047 | tt1 : float 1048 | TT as a 2-part Julian Date 1049 | tt2 : float 1050 | TT as a 2-part Julian Date 1051 | 1052 | ''' 1053 | lib.iauTdbtt.argtypes = [c_double, c_double, c_double, c_double_p, c_double_p] 1054 | lib.iauTdbtt.restype = c_int 1055 | tt1 = c_double() 1056 | tt2 = c_double() 1057 | j = lib.iauTdbtt(tdb1, tdb2, dtr, byref(tt1), byref(tt2)) 1058 | return tt1.value, tt2.value 1059 | 1060 | #int iauTf2d(char s, int ihour, int imin, double sec, double *days) 1061 | pym_tf2d_msg = { 1062 | 1:'ihour outside range 0-23', 1063 | 2:'imin outside range 0-59', 1064 | 3:'sec outside range 0-59.999...' 1065 | } 1066 | def pymTf2d(s, ihour, imin, sec): 1067 | ''' 1068 | Convert hours, minutes, seconds to days 1069 | 1070 | Parameters 1071 | ---------- 1072 | s : bytes 1073 | sign: '-' = negative, otherwise positive 1074 | ihour : int 1075 | hours 1076 | imin : int 1077 | minutes 1078 | sec : float 1079 | seconds 1080 | 1081 | Raises 1082 | ------ 1083 | ValueError 1084 | 1:'ihour outside range 0-23', 1085 | 2:'imin outside range 0-59', 1086 | 3:'sec outside range 0-59.999...' 1087 | 1088 | Returns 1089 | ------- 1090 | days : float 1091 | interval in days 1092 | 1093 | ''' 1094 | #Note: for single byte s, here using c_wchar that can work. 1095 | lib.iauTf2d.argtypes = [c_wchar, c_int, c_int, c_double, c_double_p] 1096 | lib.iauTf2d.restype = c_int 1097 | days = c_double() 1098 | 1099 | j = lib.iauTf2d(s, ihour, imin, sec, byref(days)) 1100 | if j > 0: 1101 | ws.warn(pym_tf2d_msg[j], UserWarning, 2) 1102 | return days.value 1103 | 1104 | #int iauTttai(double tt1, double tt2, double *tai1, double *tai2) 1105 | def pymTttai(tt1, tt2): 1106 | ''' 1107 | Time scale transformation: Terrestrial Time, TT, to International 1108 | Atomic Time, TAI. 1109 | 1110 | Parameters 1111 | ---------- 1112 | tt1 : float 1113 | TT as a 2-part Julian Date 1114 | tt2 : float 1115 | TT as a 2-part Julian Date 1116 | 1117 | Returns 1118 | ------- 1119 | tai1 : float 1120 | TAI as a 2-part Julian Date 1121 | tai2 : float 1122 | TAI as a 2-part Julian Date 1123 | 1124 | ''' 1125 | lib.iauTttai.argtypes = [c_double, c_double, c_double_p, c_double_p] 1126 | lib.iauTttai.restype = c_int 1127 | tai1 = c_double() 1128 | tai2 = c_double() 1129 | j = lib.iauTttai(tt1, tt2, byref(tai1), byref(tai2)) 1130 | return tai1.value, tai2.value 1131 | 1132 | 1133 | #int iauTttcg(double tt1, double tt2, double *tcg1, double *tcg2) 1134 | def pymTttcg(tt1, tt2): 1135 | ''' 1136 | Time scale transformation: Terrestrial Time, TT, to Geocentric 1137 | Coordinate Time, TCG. 1138 | 1139 | Parameters 1140 | ---------- 1141 | tt1 : float 1142 | TT as a 2-part Julian Date 1143 | tt2 : float 1144 | TT as a 2-part Julian Date 1145 | 1146 | Returns 1147 | ------- 1148 | tcg1 : float 1149 | TCG as a 2-part Julian Date 1150 | tcg2 : float 1151 | TCG as a 2-part Julian Date 1152 | 1153 | ''' 1154 | 1155 | lib.iauTttcg.argtypes = [c_double, c_double, c_double_p, c_double_p] 1156 | lib.iauTttcg.restype = c_int 1157 | 1158 | tcg1 = c_double() 1159 | tcg2 = c_double() 1160 | j = lib.iauTttcg(tt1, tt2, byref(tcg1), byref(tcg2)) 1161 | 1162 | return tcg1.value, tcg2.value 1163 | 1164 | #int iauTttdb(double tt1, double tt2, double dtr, 1165 | # double *tdb1, double *tdb2) 1166 | def pymTttdb(tt1, tt2, dtr): 1167 | ''' 1168 | Time scale transformation: Terrestrial Time, TT, to Barycentric 1169 | Dynamical Time, TDB. 1170 | 1171 | Parameters 1172 | ---------- 1173 | tt1 : float 1174 | TT as a 2-part Julian Date 1175 | tt2 : float 1176 | TT as a 2-part Julian Date 1177 | dtr : float 1178 | TDB-TT in seconds 1179 | 1180 | Returns 1181 | ------- 1182 | tdb1 : float 1183 | TDB as a 2-part Julian Date 1184 | tdb2 : float 1185 | TDB as a 2-part Julian Date 1186 | 1187 | ''' 1188 | lib.iauTttdb.argtypes = [c_double, c_double, c_double, c_double_p, c_double_p] 1189 | lib.iauTttdb.restype = c_int 1190 | 1191 | tdb1 = c_double() 1192 | tdb2 = c_double() 1193 | j = lib.iauTttdb(tt1, tt2, dtr, byref(tdb1), byref(tdb2)) 1194 | 1195 | return tdb1.value, tdb2.value 1196 | 1197 | #int iauTtut1(double tt1, double tt2, double dt, 1198 | # double *ut11, double *ut12) 1199 | def pymTtut1(tt1, tt2, dtr): 1200 | ''' 1201 | Time scale transformation: Terrestrial Time, TT, to Universal Time, 1202 | UT1. 1203 | 1204 | Parameters 1205 | ---------- 1206 | tt1 : float 1207 | TT as a 2-part Julian Date 1208 | tt2 : float 1209 | TT as a 2-part Julian Date 1210 | dtr : float 1211 | TT-UT1 in seconds 1212 | 1213 | Returns 1214 | ------- 1215 | ut11 : float 1216 | UT1 as a 2-part Julian Date 1217 | ut12 : float 1218 | UT1 as a 2-part Julian Date 1219 | 1220 | ''' 1221 | lib.iauTtut1.argtypes = [c_double, c_double, c_double, c_double_p, c_double_p] 1222 | lib.iauTtut1.restype = c_int 1223 | 1224 | ut11 = c_double() 1225 | ut12 = c_double() 1226 | j = lib.iauTtut1(tt1, tt2, dtr, byref(ut11), byref(ut12)) 1227 | 1228 | return ut11.value, ut12.value 1229 | 1230 | #int iauUt1tai(double ut11, double ut12, double dta, 1231 | # double *tai1, double *tai2) 1232 | #The argument dta, i.e. UT1-TAI, is an observed quantity, and is 1233 | # available from IERS tabulations. 1234 | def pymUt1tai(ut11, ut12, dta): 1235 | ''' 1236 | Time scale transformation: Universal Time, UT1, to International 1237 | Atomic Time, TAI. 1238 | 1239 | Parameters 1240 | ---------- 1241 | ut11 : float 1242 | UT1 as a 2-part Julian Date 1243 | ut12 : float 1244 | UT1 as a 2-part Julian Date 1245 | dta : float 1246 | UT1-TAI in seconds 1247 | 1248 | Returns 1249 | ------- 1250 | tai1 : float 1251 | TAI as a 2-part Julian Date 1252 | tai2 : float 1253 | TAI as a 2-part Julian Date 1254 | 1255 | ''' 1256 | lib.iauUt1tai.argtypes = [c_double, c_double, c_double, c_double_p, c_double_p] 1257 | lib.iauUt1tai.restype = c_int 1258 | 1259 | tai1 = c_double() 1260 | tai2 = c_double() 1261 | j = lib.iauUt1tai(ut11, ut12, dta, byref(tai1), byref(tai2)) 1262 | 1263 | return tai1.value, tai2.value 1264 | 1265 | #int iauUt1tt(double ut11, double ut12, double dt, 1266 | # double *tt1, double *tt2) 1267 | def pymUt1tt(ut11, ut12, dt): 1268 | ''' 1269 | Time scale transformation: Universal Time, UT1, to Terrestrial 1270 | Time, TT. 1271 | 1272 | Parameters 1273 | ---------- 1274 | ut11 : float 1275 | UT1 as a 2-part Julian Date 1276 | ut12 : float 1277 | UT1 as a 2-part Julian Date 1278 | dt : float 1279 | TT-UT1 in seconds 1280 | 1281 | Returns 1282 | ------- 1283 | tt1 : float 1284 | TT as a 2-part Julian Date 1285 | tt2 : float 1286 | TT as a 2-part Julian Date 1287 | 1288 | ''' 1289 | lib.iauUt1tt.argtypes = [c_double, c_double, c_double, c_double_p, c_double_p] 1290 | lib.iauUt1tt.restype = c_int 1291 | 1292 | tt1 = c_double() 1293 | tt2 = c_double() 1294 | j = lib.iauUt1tt(ut11, ut12, dt, byref(tt1), byref(tt2)) 1295 | 1296 | return tt1.value, tt2.value 1297 | 1298 | #int iauUt1utc(double ut11, double ut12, double dut1, 1299 | # double *utc1, double *utc2) 1300 | pym_ut1utc_msg = { 1301 | 1: 'dubious year', 1302 | -1: 'unacceptable date', 1303 | } 1304 | def pymUt1utc(ut11, ut12, dut1): 1305 | ''' 1306 | Time scale transformation: Universal Time, UT1, to Coordinated 1307 | Universal Time, UTC. 1308 | 1309 | Parameters 1310 | ---------- 1311 | ut11 : float 1312 | UT1 as a 2-part Julian Date 1313 | ut12 : float 1314 | UT1 as a 2-part Julian Date 1315 | dut1 : float 1316 | Delta UT1: UT1-UTC in seconds 1317 | 1318 | Raises 1319 | ------ 1320 | ValueError 1321 | 1: 'dubious year', 1322 | -1: 'unacceptable date', 1323 | 1324 | Returns 1325 | ------- 1326 | utc1 : float 1327 | UTC as a 2-part quasi Julian Date 1328 | utc2 : float 1329 | UTC as a 2-part quasi Julian Date 1330 | 1331 | ''' 1332 | lib.iauUt1utc.argtypes = [c_double, c_double, c_double, c_double_p, c_double_p] 1333 | lib.iauUt1utc.restype = c_int 1334 | 1335 | utc1 = c_double() 1336 | utc2 = c_double() 1337 | j = lib.iauUt1utc(ut11, ut12, dut1, byref(utc1), byref(utc2)) 1338 | if j < 0: 1339 | raise ValueError(pym_ut1utc_msg[j]) 1340 | elif j > 0: 1341 | ws.warn(pym_ut1utc_msg[j], UserWarning, 2) 1342 | return utc1.value, utc2.value 1343 | 1344 | #int iauUtctai(double utc1, double utc2, double *tai1, double *tai2) 1345 | pym_utctai_msg = { 1346 | 1: 'dubious year', 1347 | -1: 'unacceptable date', 1348 | } 1349 | def pymUtctai(utc1, utc2): 1350 | ''' 1351 | Time scale transformation: Coordinated Universal Time, UTC, to 1352 | International Atomic Time, TAI. 1353 | 1354 | Parameters 1355 | ---------- 1356 | utc1 : float 1357 | UTC as a 2-part quasi Julian Date 1358 | utc2 : float 1359 | UTC as a 2-part quasi Julian Date 1360 | 1361 | Raises 1362 | ------ 1363 | ValueError 1364 | 1: 'dubious year', 1365 | -1: 'unacceptable date', 1366 | 1367 | Returns 1368 | ------- 1369 | tai1 : float 1370 | TAI as a 2-part Julian Date 1371 | tai2 : float 1372 | TAI as a 2-part Julian Date 1373 | 1374 | ''' 1375 | lib.iauUtctai.argtypes = [c_double, c_double, c_double_p, c_double_p] 1376 | lib.iauUtctai.restype = c_int 1377 | tai1 = c_double() 1378 | tai2 = c_double() 1379 | j = lib.iauUtctai(utc1, utc2, byref(tai1), byref(tai2)) 1380 | if j < 0: 1381 | raise ValueError(pym_utctai_msg[j]) 1382 | elif j > 0: 1383 | ws.warn(pym_utctai_msg[j], UserWarning, 2) 1384 | return tai1.value, tai2.value 1385 | 1386 | #int iauUtcut1(double utc1, double utc2, double dut1, 1387 | # double *ut11, double *ut12) 1388 | pym_utcut1_msg = pym_ut1utc_msg 1389 | def pymUtcut1(utc1, utc2, dut1): 1390 | ''' 1391 | Time scale transformation: Coordinated Universal Time, UTC, to 1392 | Universal Time, UT1. 1393 | 1394 | Parameters 1395 | ---------- 1396 | utc1 : float 1397 | UTC as a 2-part quasi Julian Date 1398 | utc2 : float 1399 | UTC as a 2-part quasi Julian Date 1400 | dut1 : float 1401 | Delta UT1 = UT1-UTC in seconds 1402 | 1403 | Raises 1404 | ------ 1405 | ValueError 1406 | 1: 'dubious year', 1407 | -1: 'unacceptable date', 1408 | 1409 | Returns 1410 | ------- 1411 | ut11 : float 1412 | UT1 as a 2-part Julian Date 1413 | ut12 : float 1414 | UT1 as a 2-part Julian Date 1415 | 1416 | ''' 1417 | lib.iauUtcut1.argtypes = [c_double, c_double, c_double, c_double_p, c_double_p] 1418 | lib.iauUtcut1.restype = c_int 1419 | ut11 = c_double() 1420 | ut12 = c_double() 1421 | j = lib.iauUtcut1(utc1, utc2, dut1, byref(ut11), byref(ut12)) 1422 | if j < 0: 1423 | raise ValueError(pym_utcut1_msg[j]) 1424 | elif j > 0: 1425 | ws.warn(pym_utcut1_msg[j], UserWarning, 2) 1426 | return ut11.value, ut12.value 1427 | 1428 | def pymA2af(ndp, angle): 1429 | ''' 1430 | Decompose radians into degrees, arcminutes, arcseconds, fraction. 1431 | 1432 | Parameters 1433 | ---------- 1434 | ndp : int 1435 | resolution 1436 | angle : float 1437 | angle in radians 1438 | 1439 | Returns 1440 | ------- 1441 | sign : bytes 1442 | '+' or '-' 1443 | idmsf : tuple 1444 | degrees, arcminutes, arcseconds, fraction 1445 | 1446 | NDP resolution 1447 | : ...0000 00 00 1448 | -7 1000 00 00 1449 | -6 100 00 00 1450 | -5 10 00 00 1451 | -4 1 00 00 1452 | -3 0 10 00 1453 | -2 0 01 00 1454 | -1 0 00 10 1455 | 0 0 00 01 1456 | 1 0 00 00.1 1457 | 2 0 00 00.01 1458 | 3 0 00 00.001 1459 | : 0 00 00.000... 1460 | ''' 1461 | 1462 | 1463 | lib.iauA2af.argtypes = [c_int, c_double, POINTER(c_char), c_int4] 1464 | lib.iauA2af.restype = None 1465 | 1466 | sign = c_char() 1467 | idmsf = (c_int4)() 1468 | 1469 | lib.iauA2af(ndp, float(angle), byref(sign), idmsf) 1470 | 1471 | return sign.value, tuple([x for x in idmsf]) 1472 | 1473 | 1474 | def pymA2tf(ndp, angle): 1475 | ''' 1476 | Decompose radians into hours, minutes, seconds, fraction. 1477 | 1478 | Parameters 1479 | ---------- 1480 | ndp : int 1481 | resolution 1482 | angle : float 1483 | angle in radians 1484 | 1485 | Returns 1486 | ------- 1487 | sign : bytes 1488 | '+' or '-' 1489 | ihmsf : tuple 1490 | 1491 | NDP resolution 1492 | : ...0000 00 00 1493 | -7 1000 00 00 1494 | -6 100 00 00 1495 | -5 10 00 00 1496 | -4 1 00 00 1497 | -3 0 10 00 1498 | -2 0 01 00 1499 | -1 0 00 10 1500 | 0 0 00 01 1501 | 1 0 00 00.1 1502 | 2 0 00 00.01 1503 | 3 0 00 00.001 1504 | : 0 00 00.000... 1505 | ''' 1506 | 1507 | lib.iauA2tf.argtypes = [c_int, c_double, POINTER(c_char), c_int4] 1508 | lib.iauA2tf.restype = None 1509 | 1510 | sign = c_char() 1511 | idmsf = (c_int4)() 1512 | 1513 | lib.iauA2tf(ndp, float(angle), byref(sign), idmsf) 1514 | return sign.value, tuple([x for x in idmsf]) 1515 | 1516 | 1517 | pym_af2a_msg = { 1518 | 1: 'ideg outside range 0-359', 1519 | 2: 'iamin outside range 0-59', 1520 | 3: 'asec outside range 0-59.999...', 1521 | } 1522 | 1523 | def pymAf2a(s, ideg, iamin, asec): 1524 | ''' 1525 | Convert degrees, arcminutes, arcseconds to radians. 1526 | 1527 | Parameters 1528 | ---------- 1529 | s : bytes 1530 | sign: '-' = negative, otherwise positive 1531 | ideg : int 1532 | degrees 1533 | iamin : int 1534 | arcminutes 1535 | asec : float 1536 | arcseconds 1537 | 1538 | Raises 1539 | ------ 1540 | ValueError 1541 | 1: 'ideg outside range 0-359', 1542 | 2: 'iamin outside range 0-59', 1543 | 3: 'asec outside range 0-59.999...', 1544 | 1545 | Returns 1546 | ------- 1547 | rad : float 1548 | angle in radians 1549 | 1550 | ''' 1551 | lib.iauAf2a.argtypes = [c_char, c_int, c_int, c_double, c_double_p] 1552 | lib.iauAf2a.restype = c_int 1553 | 1554 | rad = c_double() 1555 | 1556 | j = lib.iauAf2a(s, ideg, iamin, asec, byref(rad)) 1557 | if j > 0: 1558 | ws.warn(pym_af2a_msg[j], UserWarning, 2) 1559 | #raise ValueError(pym_af2a_msg[j]) 1560 | 1561 | return rad.value 1562 | 1563 | def pymTf2a(s, ihour, imin, sec): 1564 | ''' 1565 | Convert hours, minutes, seconds to radians. 1566 | 1567 | Parameters 1568 | ---------- 1569 | s : bytes 1570 | sign: '-' = negative, otherwise positive 1571 | ihour : int 1572 | hours 1573 | imin : int 1574 | minutes 1575 | sec : float 1576 | seconds 1577 | 1578 | Raises 1579 | ------ 1580 | ValueError 1581 | 1:'ihour outside range 0-23', 1582 | 2:'imin outside range 0-59', 1583 | 3:'sec outside range 0-59.999...' 1584 | 1585 | Returns 1586 | ------- 1587 | rad : float 1588 | angle in radians 1589 | 1590 | ''' 1591 | #Note: for single byte s(b'+'), here using c_char that can work. 1592 | 1593 | lib.iauTf2a.argtypes = [c_char, c_int, c_int, c_double, c_double_p] 1594 | lib.iauTf2a.restype = c_int 1595 | 1596 | rad = c_double() 1597 | 1598 | j = lib.iauTf2a(s, ihour, imin, sec, byref(rad)) 1599 | if j > 0: 1600 | ws.warn(pym_tf2a_msg[j], UserWarning, 2) 1601 | 1602 | return rad.value 1603 | 1604 | def pymTf2a_A(s, ihour, imin, sec): 1605 | 1606 | #Note: for single byte s('+'), here using c_wchar that can work. 1607 | 1608 | lib.iauTf2a.argtypes = [c_wchar, c_int, c_int, c_double, c_double_p] 1609 | lib.iauTf2a.restype = c_int 1610 | 1611 | rad = c_double() 1612 | 1613 | j = lib.iauTf2a(s, ihour, imin, sec, byref(rad)) 1614 | 1615 | if j > 0: 1616 | ws.warn(pym_tf2a_msg[j], UserWarning, 2) 1617 | 1618 | return rad.value 1619 | 1620 | 1621 | 1622 | 1623 | 1624 | 1625 | 1626 | 1627 | 1628 | 1629 | 1630 | 1631 | 1632 | 1633 | -------------------------------------------------------------------------------- /python/PyMsOfa_basic.py: -------------------------------------------------------------------------------- 1 | import math as ma 2 | import numpy as np 3 | 4 | def pymS2c(THETA,PHI): 5 | ''' 6 | Convert spherical coordinates to Cartesian. 7 | 8 | Parameters 9 | ---------- 10 | theta : float 11 | longitude angle (radians) 12 | phi : float 13 | latitude angle (radians) 14 | 15 | Returns 16 | ------- 17 | c : list(3) 18 | direction cosines 19 | 20 | ''' 21 | C=[0,0,0] 22 | 23 | CP=ma.cos(PHI) 24 | C[0]=ma.cos(THETA)*CP 25 | C[1]=ma.sin(THETA)*CP 26 | C[2]=ma.sin(PHI) 27 | 28 | return(C) 29 | 30 | def pymAnp(A): 31 | ''' 32 | Normalize angle into the range 0 <= a < 2pi. 33 | 34 | Parameters 35 | ---------- 36 | a : float 37 | angle (radians) 38 | 39 | Returns 40 | ------- 41 | function value : float 42 | angle in range 0-2pi 43 | 44 | ''' 45 | W=np.abs(A)%(2*ma.pi) 46 | if A<0: 47 | W=-W 48 | if (W<0.0): 49 | W=W+2*ma.pi 50 | 51 | return(W) 52 | 53 | def pymAnpm(A): 54 | ''' 55 | Normalize angle into the range -pi <= a < +pi. 56 | 57 | Parameters 58 | ---------- 59 | a : float 60 | angle (radians) 61 | 62 | Returns 63 | ------- 64 | function value : float 65 | angle in range +/-pi 66 | 67 | ''' 68 | W=np.abs(A)%(2*ma.pi) 69 | if A<0: 70 | W=-W 71 | if (np.abs(W)>=ma.pi): 72 | if A>=0: 73 | W=W-2*ma.pi 74 | else: 75 | W=W+2*ma.pi 76 | 77 | return(W) 78 | 79 | def pymC2s(P): 80 | ''' 81 | P-vector to spherical coordinates. 82 | 83 | Parameters 84 | ---------- 85 | p : list(3) 86 | p-vector 87 | 88 | Returns 89 | ------- 90 | theta : float 91 | longitude angle (radians) 92 | phi : float 93 | latitude angle (radians) 94 | 95 | ''' 96 | X=P[0] 97 | Y=P[1] 98 | Z=P[2] 99 | D2=X*X+Y*Y 100 | 101 | if (D2==0.0): 102 | THETA=0.0 103 | else: 104 | THETA=ma.atan2(Y,X) 105 | 106 | if (Z==0.0): 107 | PHI=0.0 108 | else: 109 | PHI=ma.atan2(Z,ma.sqrt(D2)) 110 | 111 | return(THETA,PHI) 112 | 113 | def pymCp(P): 114 | ''' 115 | Copy a p-vector. 116 | 117 | Parameters 118 | ---------- 119 | p : list(3) 120 | p-vector to be copied 121 | 122 | Returns 123 | ------- 124 | c : list(3) 125 | copy 126 | 127 | ''' 128 | C=[P[i] for i in range(3)] 129 | 130 | return(C) 131 | 132 | def pymCpv(PV): 133 | ''' 134 | Copy a position/velocity vector. 135 | 136 | Parameters 137 | ---------- 138 | pv : list(2,3) 139 | position/velocity vector to be copied 140 | 141 | Returns 142 | ------- 143 | c : list(2,3) 144 | copy 145 | 146 | ''' 147 | C=[0,0] 148 | 149 | C[0]=pymCp(PV[0]) 150 | C[1]=pymCp(PV[1]) 151 | 152 | return(C) 153 | 154 | def pymCr(R): 155 | ''' 156 | Copy an r-matrix. 157 | 158 | Parameters 159 | ---------- 160 | r : list(3,3) 161 | r-matrix to be copied 162 | 163 | Returns 164 | ------- 165 | c : list(3,3) 166 | r-matrix to be copied 167 | 168 | ''' 169 | C=[0,0,0] 170 | 171 | for k in range(3): 172 | C[k]=pymCp(R[k]) 173 | 174 | return(C) 175 | 176 | def pymIr(): 177 | ''' 178 | Initialize an r-matrix to the identity matrix. 179 | 180 | Returns 181 | ------- 182 | r : list(3,3) 183 | r-matrix 184 | 185 | ''' 186 | 187 | R=[[1,0,0],[0,1,0],[0,0,1]] 188 | 189 | return(R) 190 | 191 | def pymP2pv(P): 192 | ''' 193 | Extend a p-vector to a pv-vector by appending a zero velocity. 194 | 195 | Parameters 196 | ---------- 197 | p : list(3) 198 | p-vector 199 | 200 | Returns 201 | ------- 202 | pv : list(2,3) 203 | pv-vector 204 | 205 | ''' 206 | PV=[0,0] 207 | PV[0]=pymCp(P) 208 | PV[1]=pymZp() 209 | 210 | return(PV) 211 | 212 | def pymP2s(P): 213 | ''' 214 | P-vector to spherical polar coordinates. 215 | 216 | Parameters 217 | ---------- 218 | p : list(3) 219 | p-vector 220 | 221 | Returns 222 | ------- 223 | theta : float 224 | longitude angle (radians) 225 | phi : float 226 | latitude angle (radians) 227 | r : float 228 | radial distance 229 | 230 | ''' 231 | THETA,PHI=pymC2s(P) 232 | R=pymPm(P) 233 | 234 | return(THETA,PHI,R) 235 | 236 | def pymPap(A,B): 237 | ''' 238 | Position-angle from two p-vectors. 239 | 240 | Parameters 241 | ---------- 242 | a : list(3) 243 | direction of reference point 244 | b : list(3) 245 | direction of point whose PA is required 246 | 247 | Returns 248 | ------- 249 | function value : float 250 | position angle of b with respect to a (radians) 251 | 252 | ''' 253 | ETA=[0,0,0] 254 | #A向量的模和方向 255 | AM,AU=pymPn(A) 256 | 257 | #B向量的模 258 | BM=pymPm(B) 259 | 260 | #对空向量进行处理 261 | if (AM==0.0)|(BM==0.0): 262 | ST=0.0 263 | CT=1.0 264 | else: 265 | 266 | #自A点到“北”轴切线(任意长度) 267 | XA=A[0] 268 | YA=A[1] 269 | ZA=A[2] 270 | ETA[0]=-XA*ZA 271 | ETA[1]=-YA*ZA 272 | ETA[2]=XA*XA+YA*YA 273 | 274 | #自A点到“东”轴切线(任意长度)。 275 | XI=pymPxp(ETA,AU) 276 | 277 | #从A到B的向量 278 | A2B=pymPmp(B,A) 279 | 280 | #沿着北轴和东轴分解参数 281 | ST=pymPdp(A2B,XI) 282 | CT=pymPdp(A2B,ETA) 283 | 284 | #处理有误情况 285 | if (ST==0.0)&(CT==0.0): 286 | CT=1.0 287 | 288 | #方位角 289 | THETA=ma.atan2(ST,CT) 290 | 291 | return(THETA) 292 | 293 | def pymPdp(A,B): 294 | ''' 295 | p-vector inner (=scalar=dot) product. 296 | 297 | Parameters 298 | ---------- 299 | a : list(3) 300 | first p-vector 301 | b : list(3) 302 | second p-vector 303 | 304 | Returns 305 | ------- 306 | function value : float 307 | a . b 308 | ''' 309 | W=0.0 310 | for i in range(3): 311 | W=W+A[i]*B[i] 312 | 313 | ADB=W 314 | return(ADB) 315 | 316 | def pymPm(P): 317 | ''' 318 | Modulus of p-vector. 319 | 320 | Parameters 321 | ---------- 322 | p : list(3) 323 | p-vector 324 | 325 | Returns 326 | ------- 327 | function value : float 328 | modulus 329 | 330 | ''' 331 | W=0.0 332 | for i in range(3): 333 | C=P[i] 334 | W+=C**2 335 | R=ma.sqrt(W) 336 | 337 | return(R) 338 | 339 | def pymPmp(A,B): 340 | ''' 341 | P-vector subtraction. 342 | 343 | Parameters 344 | ---------- 345 | a : list(3) 346 | first p-vector 347 | b : list(3) 348 | second p-vector 349 | 350 | Returns 351 | ------- 352 | amb : list(3) 353 | a - b 354 | 355 | ''' 356 | AMB=[0,0,0] 357 | for i in range(3): 358 | AMB[i]=A[i]-B[i] 359 | 360 | return(AMB) 361 | 362 | def pymPn(P): 363 | ''' 364 | Convert a p-vector into modulus and unit vector. 365 | 366 | Parameters 367 | ---------- 368 | p : list(3) 369 | p-vector 370 | 371 | Returns 372 | ------- 373 | r : float 374 | modulus 375 | u : list(3) 376 | unit vector 377 | 378 | ''' 379 | U=[0,0,0] 380 | 381 | #调用pymPm函数获得向量的模,并判断是否为零向量 382 | W=pymPm(P) 383 | if (W==0.0): 384 | 385 | #零向量 386 | U=pymZp() 387 | else: 388 | 389 | #单位向量 390 | U=pymSxp(1.0/W, P) 391 | 392 | R=W 393 | return(R,U) 394 | 395 | def pymPpp(A,B): 396 | ''' 397 | P-vector addition. 398 | 399 | Parameters 400 | ---------- 401 | a : list(3) 402 | first p-vector 403 | b : list(3) 404 | second p-vector 405 | 406 | Returns 407 | ------- 408 | apb : list(3) 409 | a + b 410 | 411 | ''' 412 | APB=[A[0]+B[0],A[1]+B[1],A[2]+B[2]] 413 | 414 | return(APB) 415 | 416 | def pymPpsp (A,S,B): 417 | ''' 418 | P-vector plus scaled p-vector. 419 | 420 | Parameters 421 | ---------- 422 | a : list(3) 423 | first p-vector 424 | s : float 425 | scalar (multiplier for b) 426 | b : list(3) 427 | second p-vector 428 | 429 | Returns 430 | ------- 431 | apsb : list(3) 432 | a + s*b 433 | 434 | ''' 435 | APSB=[0,0,0] 436 | 437 | for i in range(3): 438 | APSB[i]=A[i]+S*B[i] 439 | 440 | return(APSB) 441 | 442 | def pymPv2p(PV): 443 | ''' 444 | Discard velocity component of a pv-vector. 445 | 446 | Parameters 447 | ---------- 448 | pv : list(2,3) 449 | pv-vector 450 | 451 | Returns 452 | ------- 453 | p : list(3) 454 | p-vector 455 | 456 | ''' 457 | P=pymCp(PV[0]) 458 | 459 | return(P) 460 | 461 | def pymPv2s(PV): 462 | ''' 463 | Convert position/velocity from Cartesian to spherical coordinates. 464 | 465 | Parameters 466 | ---------- 467 | pv : list(2,3) 468 | pv-vector 469 | 470 | Returns 471 | ------- 472 | theta : float 473 | longitude angle (radians) 474 | phi : float 475 | latitude angle (radians) 476 | r : float 477 | radial distance 478 | td : float 479 | rate of change of theta 480 | pd : float 481 | rate of change of phi 482 | rd : float 483 | rate of change of r 484 | 485 | ''' 486 | #位置-速度向量的各个分量 487 | X=PV[0][0] 488 | Y=PV[0][1] 489 | Z=PV[0][2] 490 | XD=PV[1][0] 491 | YD=PV[1][1] 492 | ZD=PV[1][2] 493 | 494 | #XY平面的平方和 495 | RXY2=X*X+Y*Y 496 | 497 | #模的平方 498 | R2=RXY2+Z*Z 499 | 500 | #模 501 | RTRUE=ma.sqrt(R2) 502 | 503 | #如果时空向量,沿着运动的方向移动原点 504 | RW=RTRUE 505 | if (RTRUE==0.0): 506 | X=XD 507 | Y=YD 508 | Z=ZD 509 | RXY2=X*X+Y*Y 510 | R2=RXY2+Z*Z 511 | RW=ma.sqrt(R2) 512 | 513 | #在球坐标中的位置和速度向量 514 | RXY=ma.sqrt(RXY2) 515 | XYP=X*XD+Y*YD 516 | if (RXY2!=0.0): 517 | THETA=ma.atan2(Y,X) 518 | PHI=ma.atan2(Z,RXY) 519 | TD=(X*YD-Y*XD)/RXY2 520 | PD=(ZD*RXY2-Z*XYP)/(R2*RXY) 521 | else: 522 | THETA=0.0 523 | if (Z!=0.0): 524 | PHI=ma.atan2(Z,RXY) 525 | else: 526 | PHI=0.0 527 | TD=0.0 528 | PD=0.0 529 | 530 | R=RTRUE 531 | if (RW!=0.0): 532 | RD=(XYP+Z*ZD)/RW 533 | else: 534 | RD=0.0 535 | 536 | return(THETA,PHI,R,TD,PD,RD) 537 | 538 | def pymPvdpv (A,B): 539 | ''' 540 | Inner (=scalar=dot) product of two pv-vectors. 541 | 542 | Parameters 543 | ---------- 544 | a : list(2,3) 545 | first pv-vector 546 | b : list(2,3) 547 | second pv-vector 548 | 549 | Returns 550 | ------- 551 | adb : list(2) 552 | A . B 553 | 554 | ''' 555 | ADB=[0,0] 556 | #位置向量内积 557 | ADB[0]=pymPdp(A[0],B[0]) 558 | 559 | #A位置向量·B速度向量 560 | ADBD=pymPdp(A[0],B[1]) 561 | 562 | #A速度向量·B位置向量 563 | ADDB=pymPdp(A[1],B[0]) 564 | 565 | #速度项 566 | ADB[1]=ADBD+ADDB 567 | 568 | return(ADB) 569 | 570 | def pymPvm(PV): 571 | ''' 572 | Modulus of pv-vector. 573 | 574 | Parameters 575 | ---------- 576 | pv : list(2,3) 577 | pv-vector 578 | 579 | Returns 580 | ------- 581 | r : float 582 | modulus of position component 583 | s : float 584 | modulus of velocity component 585 | 586 | ''' 587 | #距离 588 | R=pymPm(PV[0]) 589 | 590 | #速度 591 | S=pymPm(PV[1]) 592 | 593 | return(R,S) 594 | 595 | def pymPvmpv(A,B): 596 | ''' 597 | Subtract one pv-vector from another. 598 | 599 | Parameters 600 | ---------- 601 | a : list(2,3) 602 | first pv-vector 603 | b : list(2,3) 604 | second pv-vector 605 | 606 | Returns 607 | ------- 608 | amb : list(2,3) 609 | a - b 610 | 611 | ''' 612 | AMB=[0,0] 613 | for i in range(2): 614 | AMB[i]=pymPmp(A[i], B[i]) 615 | 616 | return(AMB) 617 | 618 | def pymPvppv(A,B): 619 | ''' 620 | Add one pv-vector to another. 621 | 622 | Parameters 623 | ---------- 624 | a : list(2,3) 625 | first pv-vector 626 | b : list(2,3) 627 | second pv-vector 628 | 629 | Returns 630 | ------- 631 | apb : list(2,3) 632 | a + b 633 | 634 | ''' 635 | APB=[0,0] 636 | for i in range(2): 637 | APB[i]=pymPpp(A[i], B[i]) 638 | 639 | return(APB) 640 | 641 | def pymPvu(DT,PV): 642 | ''' 643 | Update a pv-vector. 644 | 645 | Parameters 646 | ---------- 647 | dt : float 648 | time interval 649 | pv : list(2,3) 650 | pv-vector 651 | 652 | Returns 653 | ------- 654 | upv : list(2,3) 655 | p updated, v unchanged 656 | 657 | ''' 658 | UPV=[0,0] 659 | UPV[0]=pymPpsp(PV[0],DT,PV[1]) 660 | UPV[1]=PV[1] 661 | 662 | return(UPV) 663 | 664 | def pymPvup(DT,PV): 665 | ''' 666 | Update a pv-vector, discarding the velocity component. 667 | 668 | Parameters 669 | ---------- 670 | dt : float 671 | time interval 672 | pv : list(2,3) 673 | pv-vector 674 | 675 | Returns 676 | ------- 677 | p : list(3) 678 | p-vector 679 | 680 | ''' 681 | P=[0,0,0] 682 | 683 | for i in range(3): 684 | P[i]=PV[0][i]+PV[1][i]*DT 685 | 686 | return(P) 687 | 688 | def pymPvxpv(A,B): 689 | ''' 690 | Outer (=vector=cross) product of two pv-vectors. 691 | 692 | Parameters 693 | ---------- 694 | a : list(2,3) 695 | first pv-vector 696 | b : list(2,3) 697 | second pv-vector 698 | 699 | Returns 700 | ------- 701 | axb : list(2,3) 702 | a x b 703 | 704 | ''' 705 | AXB=[0,0] 706 | #输入向量的副本 707 | WA=pymCpv(A) 708 | WB=pymCpv(B) 709 | 710 | #A x B的位置结果 711 | AXB[0]=pymPxp(WA[0],WB[0]) 712 | 713 | #A x Bdot + Adot x B 的速度结果 714 | AXBD=pymPxp(WA[0],WB[1]) 715 | ADXB=pymPxp(WA[1],WB[0]) 716 | AXB[1]=pymPpp(AXBD,ADXB) 717 | 718 | return(AXB) 719 | 720 | def pymPxp(A,B): 721 | '''' 722 | p-vector outer (=vector=cross) product. 723 | 724 | Parameters 725 | ---------- 726 | a : list(3) 727 | first p-vector 728 | b : list(3) 729 | second p-vector 730 | 731 | Returns 732 | ------- 733 | axb : list(3) 734 | a x b 735 | 736 | ''' 737 | 738 | AXB=[0,0,0] 739 | 740 | XA=A[0] 741 | YA=A[1] 742 | ZA=A[2] 743 | XB=B[0] 744 | YB=B[1] 745 | ZB=B[2] 746 | AXB[0]=YA*ZB-ZA*YB 747 | AXB[1]=ZA*XB-XA*ZB 748 | AXB[2]=XA*YB-YA*XB 749 | 750 | return(AXB) 751 | 752 | def pymRm2v(R): 753 | ''' 754 | Express an r-matrix as an r-vector. 755 | 756 | Parameters 757 | ---------- 758 | r : list(3,3) 759 | rotation matrix 760 | 761 | Returns 762 | ------- 763 | w : list(3) 764 | rotation vector 765 | 766 | ''' 767 | W=[0,0,0] 768 | 769 | X=R[1][2]-R[2][1] 770 | Y=R[2][0]-R[0][2] 771 | Z=R[0][1]-R[1][0] 772 | S2=ma.sqrt(X*X+Y*Y+Z*Z) 773 | if (S2>0.0): 774 | C2=R[0][0]+R[1][1]+R[2][2]-1.0 775 | PHI=ma.atan2(S2,C2) 776 | F=PHI/S2 777 | W[0]=X*F 778 | W[1]=Y*F 779 | W[2]=Z*F 780 | else: 781 | W[0]=0.0 782 | W[1]=0.0 783 | W[2]=0.0 784 | 785 | return(W) 786 | 787 | def pymRv2m(W): 788 | ''' 789 | Form the r-matrix corresponding to a given r-vector. 790 | 791 | Parameters 792 | ---------- 793 | w : list(3) 794 | rotation vector 795 | 796 | Returns 797 | ------- 798 | r : list(3,3) 799 | rotation matrix 800 | 801 | ''' 802 | R=[[0 for i in range(3)] for j in range(3)] 803 | 804 | #欧拉角(即为旋转向量的模) 805 | X=W[0] 806 | Y=W[1] 807 | Z=W[2] 808 | PHI=ma.sqrt(X*X+Y*Y+Z*Z) 809 | S=ma.sin(PHI) 810 | C=ma.cos(PHI) 811 | F=1.0-C 812 | 813 | #欧拉轴(旋转向量的方向), 可能为空值. 814 | if (PHI>0.0): 815 | X=X/PHI 816 | Y=Y/PHI 817 | Z=Z/PHI 818 | 819 | #构建旋转矩阵 820 | R[0][0]=X*X*F+C 821 | R[0][1]=X*Y*F+Z*S 822 | R[0][2]=X*Z*F-Y*S 823 | R[1][0]=Y*X*F-Z*S 824 | R[1][1]=Y*Y*F+C 825 | R[1][2]=Y*Z*F+X*S 826 | R[2][0]=Z*X*F+Y*S 827 | R[2][1]=Z*Y*F-X*S 828 | R[2][2]=Z*Z*F+C 829 | 830 | return(R) 831 | 832 | def pymRx(PHI,R): 833 | ''' 834 | Rotate an r-matrix about the x-axis. 835 | 836 | Parameters 837 | ---------- 838 | phi : float 839 | angle (radians) 840 | r : list(3,3) 841 | r-matrix 842 | 843 | Returns 844 | ------- 845 | r : list(3,3) 846 | r-matrix, rotated 847 | 848 | ''' 849 | S=ma.sin(PHI) 850 | C=ma.cos(PHI) 851 | 852 | A21=C*R[1][0]+S*R[2][0] 853 | A22=C*R[1][1]+S*R[2][1] 854 | A23=C*R[1][2]+S*R[2][2] 855 | A31=-S*R[1][0]+C*R[2][0] 856 | A32=-S*R[1][1]+C*R[2][1] 857 | A33=-S*R[1][2]+C*R[2][2] 858 | 859 | R[1][0]=A21 860 | R[1][1]=A22 861 | R[1][2]=A23 862 | R[2][0]=A31 863 | R[2][1]=A32 864 | R[2][2]=A33 865 | 866 | return(R) 867 | 868 | def pymRxp(R,P): 869 | ''' 870 | Multiply a p-vector by an r-matrix. 871 | 872 | Parameters 873 | ---------- 874 | r : list(3,3) 875 | r-matrix 876 | p : list(3) 877 | p-vector 878 | 879 | Returns 880 | ------- 881 | rp : list(3,3) 882 | r * p 883 | 884 | ''' 885 | WRP=[0,0,0] 886 | 887 | for j in range(3): 888 | W=0.0 889 | for i in range(3): 890 | W=W+R[j][i]*P[i] 891 | WRP[j]=W 892 | RP=pymCp(WRP) 893 | 894 | return(RP) 895 | 896 | def pymRxpv(R,PV): 897 | ''' 898 | Multiply a pv-vector by an r-matrix. 899 | 900 | Parameters 901 | ---------- 902 | r : list(3,3) 903 | r-matrix 904 | pv : list(2,3) 905 | pv-vector 906 | 907 | Returns 908 | ------- 909 | rpv : list(2,3) 910 | r * pv 911 | 912 | ''' 913 | RPV=[0,0] 914 | 915 | RPV[0]=pymRxp(R,PV[0]) 916 | RPV[1]=pymRxp(R,PV[1]) 917 | 918 | return(RPV) 919 | 920 | def pymRxr(A,B): 921 | ''' 922 | Multiply two r-matrices. 923 | 924 | Parameters 925 | ---------- 926 | a : list(3,3) 927 | first r-matrix 928 | b : list(3,3) 929 | second r-matrix 930 | 931 | Returns 932 | ------- 933 | atb : list(3,3) 934 | a * b 935 | 936 | ''' 937 | WM=[[0 for i in range(3)] for j in range(3)] 938 | 939 | for i in range(3): 940 | for j in range(3): 941 | W=0.0 942 | for k in range(3): 943 | W=W+A[i][k]*B[k][j] 944 | WM[i][j]=W 945 | ATB=pymCr(WM) 946 | 947 | return(ATB) 948 | 949 | def pymRy(THETA,R): 950 | ''' 951 | Rotate an r-matrix about the y-axis. 952 | 953 | Parameters 954 | ---------- 955 | theta : float 956 | angle (radians) 957 | r : list(3,3) 958 | r-matrix 959 | 960 | Returns 961 | ------- 962 | r : list(3,3) 963 | r-matrix, rotated 964 | 965 | ''' 966 | S=ma.sin(THETA) 967 | C=ma.cos(THETA) 968 | 969 | A11=C*R[0][0]-S*R[2][0] 970 | A12=C*R[0][1]-S*R[2][1] 971 | A13=C*R[0][2]-S*R[2][2] 972 | A31=S*R[0][0]+C*R[2][0] 973 | A32=S*R[0][1]+C*R[2][1] 974 | A33=S*R[0][2]+C*R[2][2] 975 | 976 | R[0][0]=A11 977 | R[0][1]=A12 978 | R[0][2]=A13 979 | R[2][0]=A31 980 | R[2][1]=A32 981 | R[2][2]=A33 982 | 983 | return(R) 984 | 985 | def pymRz(PSI,R): 986 | ''' 987 | Rotate an r-matrix about the z-axis. 988 | 989 | Parameters 990 | ---------- 991 | psi : float 992 | angle (radians) 993 | r : list(3,3) 994 | r-matrix 995 | 996 | Returns 997 | ------- 998 | r : list(3,3) 999 | r-matrix, rotated 1000 | 1001 | ''' 1002 | S=ma.sin(PSI) 1003 | C=ma.cos(PSI) 1004 | 1005 | A11=C*R[0][0]+S*R[1][0] 1006 | A12=C*R[0][1]+S*R[1][1] 1007 | A13=C*R[0][2]+S*R[1][2] 1008 | A21=-S*R[0][0]+C*R[1][0] 1009 | A22=-S*R[0][1]+C*R[1][1] 1010 | A23=-S*R[0][2]+C*R[1][2] 1011 | 1012 | R[0][0]=A11 1013 | R[0][1]=A12 1014 | R[0][2]=A13 1015 | R[1][0]=A21 1016 | R[1][1]=A22 1017 | R[1][2]=A23 1018 | 1019 | return(R) 1020 | 1021 | def pymS2p(THETA,PHI,R): 1022 | ''' 1023 | Convert spherical polar coordinates to p-vector. 1024 | 1025 | Parameters 1026 | ---------- 1027 | theta : float 1028 | longitude angle (radians) 1029 | phi : float 1030 | latitude angle (radians) 1031 | r : float 1032 | radial distance 1033 | 1034 | Returns 1035 | ------- 1036 | p : list(3) 1037 | Cartesian coordinates 1038 | 1039 | ''' 1040 | U=pymS2c(THETA,PHI) 1041 | P=pymSxp(R,U) 1042 | 1043 | return(P) 1044 | 1045 | def pymS2pv(THETA,PHI,R,TD,PD,RD): 1046 | ''' 1047 | Convert position/velocity from spherical to Cartesian coordinates. 1048 | 1049 | Parameters 1050 | ---------- 1051 | theta : float 1052 | longitude angle (radians) 1053 | phi : float 1054 | latitude angle (radians) 1055 | r : float 1056 | radial distance 1057 | td : float 1058 | rate of change of theta 1059 | pd : float 1060 | rate of change of phi 1061 | rd : float 1062 | rate of change of r 1063 | 1064 | Returns 1065 | ------- 1066 | pv : list(2,3) 1067 | pv-vector 1068 | 1069 | ''' 1070 | PV=[[0 for i in range(3)] for j in range(2)] 1071 | 1072 | ST=ma.sin(THETA) 1073 | CT=ma.cos(THETA) 1074 | SP=ma.sin(PHI) 1075 | CP=ma.cos(PHI) 1076 | RCP=R*CP 1077 | X=RCP*CT 1078 | Y=RCP*ST 1079 | RPD=R*PD 1080 | W=RPD*SP-CP*RD 1081 | 1082 | PV[0][0]=X 1083 | PV[0][1]=Y 1084 | PV[0][2]=R*SP 1085 | PV[1][0]=-Y*TD-W*CT 1086 | PV[1][1]=X*TD-W*ST 1087 | PV[1][2]=RPD*CP+SP*RD 1088 | 1089 | return(PV) 1090 | 1091 | def pymS2xpv(S1,S2,PV): 1092 | ''' 1093 | Multiply a pv-vector by two scalars. 1094 | 1095 | Parameters 1096 | ---------- 1097 | s1 : float 1098 | scalar to multiply position component by 1099 | s2 : float 1100 | scalar to multiply velocity component by 1101 | pv : list(2,3) 1102 | pv-vector 1103 | 1104 | Returns 1105 | ------- 1106 | spv : list(2,3) 1107 | pv-vector: p scaled by s1, v scaled by s2 1108 | 1109 | ''' 1110 | SPV=[0,0] 1111 | SPV[0]=pymSxp(S1,PV[0]) 1112 | SPV[1]=pymSxp(S2,PV[1]) 1113 | 1114 | return(SPV) 1115 | 1116 | def pymSepp (A,B): 1117 | ''' 1118 | Angular separation between two p-vectors. 1119 | 1120 | Parameters 1121 | ---------- 1122 | a : list(3) 1123 | first p-vector (not necessarily unit length) 1124 | b : list(3) 1125 | second p-vector (not necessarily unit length) 1126 | 1127 | Returns 1128 | ------- 1129 | function value : float 1130 | angular separation (radians, always positive) 1131 | 1132 | ''' 1133 | #向量夹角的正弦,乘以两个模 1134 | AXB=pymPxp(A,B) 1135 | SS=pymPm(AXB) 1136 | 1137 | #角的余弦,乘以两个模。 1138 | CS=pymPdp(A,B) 1139 | 1140 | #角度 1141 | if (SS!=0.0)|(CS!=0.0): 1142 | S=ma.atan2(SS,CS) 1143 | else: 1144 | S=0.0 1145 | 1146 | return(S) 1147 | 1148 | def pymSeps(AL,AP,BL,BP): 1149 | ''' 1150 | Angular separation between two sets of spherical coordinates. 1151 | 1152 | Parameters 1153 | ---------- 1154 | al : float 1155 | first longitude (radians) 1156 | ap : float 1157 | first latitude (radians) 1158 | bl : float 1159 | second longitude (radians) 1160 | bp : float 1161 | second latitude (radians) 1162 | 1163 | Returns 1164 | ------- 1165 | function value : float 1166 | angular separation (radians) 1167 | 1168 | ''' 1169 | #球面到笛卡尔 1170 | AC=pymS2c(AL,AP) 1171 | BC=pymS2c(BL,BP) 1172 | 1173 | #两个向量之间的角度差 1174 | S=pymSepp(AC,BC) 1175 | 1176 | return(S) 1177 | 1178 | def pymSxp(S,P): 1179 | ''' 1180 | Multiply a p-vector by a scalar. 1181 | 1182 | Parameters 1183 | ---------- 1184 | s : float 1185 | scalar 1186 | p : list(3) 1187 | p-vector 1188 | 1189 | Returns 1190 | ------- 1191 | sp : list(3) 1192 | s * p 1193 | 1194 | ''' 1195 | SP=[0,0,0] 1196 | 1197 | for i in range(3): 1198 | SP[i]=S*P[i] 1199 | 1200 | return(SP) 1201 | 1202 | def pymSxpv(S,PV): 1203 | ''' 1204 | Multiply a pv-vector by a scalar. 1205 | 1206 | Parameters 1207 | ---------- 1208 | s : float 1209 | scalar 1210 | pv : list(2,3) 1211 | pv-vector 1212 | 1213 | Returns 1214 | ------- 1215 | spv : list(2,3) 1216 | s * pv 1217 | 1218 | ''' 1219 | SPV=pymS2xpv(S,S,PV) 1220 | 1221 | return(SPV) 1222 | 1223 | def pymTr(R): 1224 | ''' 1225 | Transpose an r-matrix. 1226 | 1227 | Parameters 1228 | ---------- 1229 | r : list(3,3) 1230 | r-matrix 1231 | 1232 | Returns 1233 | ------- 1234 | rt : list(3,3) 1235 | transpose 1236 | 1237 | ''' 1238 | WM=[[0 for i in range(3)] for j in range(3)] 1239 | 1240 | for i in range(3): 1241 | for j in range(3): 1242 | WM[i][j]=R[j][i] 1243 | 1244 | RT=pymCr(WM) 1245 | 1246 | return(RT) 1247 | 1248 | def pymTrxp(R,P): 1249 | ''' 1250 | Multiply a p-vector by the transpose of an r-matrix. 1251 | 1252 | Parameters 1253 | ---------- 1254 | r : list(3,3) 1255 | r-matrix 1256 | p : list(3) 1257 | p-vector 1258 | 1259 | Returns 1260 | ------- 1261 | trp : list(3) 1262 | r^T * p 1263 | 1264 | ''' 1265 | RI=pymTr(R) 1266 | 1267 | TRP=pymRxp(RI,P) 1268 | 1269 | return(TRP) 1270 | 1271 | def pymTrxpv(R,PV): 1272 | ''' 1273 | Multiply a pv-vector by the transpose of an r-matrix. 1274 | 1275 | Parameters 1276 | ---------- 1277 | r : list(3,3) 1278 | r-matrix 1279 | pv : list(2,3) 1280 | pv-vector 1281 | 1282 | Returns 1283 | ------- 1284 | trpv : list(2,3) 1285 | r^T * pv 1286 | 1287 | ''' 1288 | RI=pymTr(R) 1289 | 1290 | TRPV=pymRxpv(RI,PV) 1291 | 1292 | return(TRPV) 1293 | 1294 | def pymZp(): 1295 | ''' 1296 | Zero a p-vector 1297 | 1298 | Parameters 1299 | ---------- 1300 | 1301 | Returns 1302 | ------- 1303 | p : list(3) 1304 | zero p-vector 1305 | ''' 1306 | 1307 | P=[0,0,0] 1308 | 1309 | return(P) 1310 | 1311 | def pymZpv(): 1312 | ''' 1313 | Zero a pv-vector 1314 | 1315 | Parameters 1316 | ---------- 1317 | pv : list(2,3) 1318 | pv-vector 1319 | 1320 | Returns 1321 | ------- 1322 | pv : list(2,3) 1323 | zero pv-vector 1324 | 1325 | ''' 1326 | 1327 | PV=[[0,0,0],[0,0,0]] 1328 | 1329 | return(PV) 1330 | 1331 | def pymZr(): 1332 | ''' 1333 | Initialize an r-matrix to the null matrix. 1334 | 1335 | Parameters 1336 | ---------- 1337 | r : list(3,3) 1338 | r-matrix 1339 | 1340 | Returns 1341 | ------- 1342 | r : list(3,3) 1343 | null matrix 1344 | 1345 | ''' 1346 | R=[[0 for i in range(3)] for j in range(3)] 1347 | 1348 | return(R) 1349 | --------------------------------------------------------------------------------