Coverage for pymarsseason/marstime.py: 69%

312 statements  

« prev     ^ index     » next       coverage.py v7.10.7, created at 2025-09-23 10:46 +0000

1"""Mars24 algorithm 

2 

3Mars Calendar and orbit calculation based on Allison and McEwan (2000), Allison (1997) 

4 

5Allison, M., and M. McEwen 2000. A post-Pathfinder evaluation of aerocentric solar coordinates with improved timing recipes for Mars seasonal/diurnal climate studies. Planet. Space Sci. 48, 215-235 

6 

7Allison, M. 1997. Accurate analytic representations of solar time and seasons on Mars with applications to the Pathfinder/Surveyor missions. Geophys. Res. Lett. 24, 1967-1970. 

8 

9http://www.giss.nasa.gov/tools/mars24/ 

10 

11""" 

12 

13version = "0.4.6" 

14 

15import time 

16 

17try: 

18 import numpy as np 

19 

20 use_numpy = True 

21except ImportError: 

22 use_numpy = False 

23 import math as np 

24 

25 

26def west_to_east(west): 

27 """Convert from west longitude to east longitude, 

28 or vice versa.""" 

29 east = 360 - west # + 0.271 

30 # This function used to convert between two coordinate systems at the same time, 

31 # which seems to be wrong, so I've removed that option. 

32 return east % 360.0 

33 

34 

35def east_to_west(east): 

36 """Interface, calls west_to_east to convert longitude""" 

37 return west_to_east(east) 

38 

39 

40def j2000_epoch(): 

41 """Returns the j2000 epoch as a float""" 

42 return 2451545.0 

43 

44 

45def mills(): 

46 """Returns the current time in milliseconds since Jan 1 1970""" 

47 return time.time() * 1000.0 

48 

49 

50def julian(m=None): 

51 """Returns the julian day number given milliseconds since Jan 1 1970""" 

52 if m is None: 

53 m = mills() 

54 return 2440587.5 + (m / 8.64e7) 

55 

56 

57def utc_to_tt_offset(jday=None): 

58 """Returns the offset in seconds from a julian date in Terrestrial Time (TT) 

59 to a Julian day in Coordinated Universal Time (UTC)""" 

60 

61 if use_numpy: 

62 return utc_to_tt_offset_numpy(jday) 

63 else: 

64 return utc_to_tt_offset_math(jday) 

65 

66 

67def utc_to_tt_offset_math(jday=None): 

68 """Returns the offset in seconds from a julian date in Terrestrial Time (TT) 

69 to a Julian day in Coordinated Universal Time (UTC) [MATH]""" 

70 if jday is None: 

71 jday_np = julian() 

72 else: 

73 jday_np = jday 

74 

75 jday_min = 2441317.5 

76 jday_vals = [ 

77 -2441317.5, 

78 0.0, 

79 182.0, 

80 366.0, 

81 731.0, 

82 1096.0, 

83 1461.0, 

84 1827.0, 

85 2192.0, 

86 2557.0, 

87 2922.0, 

88 3469.0, 

89 3834.0, 

90 4199.0, 

91 4930.0, 

92 5844.0, 

93 6575.0, 

94 6940.0, 

95 7487.0, 

96 7852.0, 

97 8217.0, 

98 8766.0, 

99 9313.0, 

100 9862.0, 

101 12419.0, 

102 13515.0, 

103 14792.0, 

104 ] 

105 

106 offset_min = 32.184 

107 offset_vals = [ 

108 -32.184, 

109 10.0, 

110 11.0, 

111 12.0, 

112 13.0, 

113 14.0, 

114 15.0, 

115 16.0, 

116 17.0, 

117 18.0, 

118 19.0, 

119 20.0, 

120 21.0, 

121 22.0, 

122 23.0, 

123 24.0, 

124 25.0, 

125 26.0, 

126 27.0, 

127 28.0, 

128 29.0, 

129 30.0, 

130 31.0, 

131 32.0, 

132 33.0, 

133 34.0, 

134 35.0, 

135 ] 

136 

137 if jday_np <= jday_min + jday_vals[0]: 

138 return offset_min + offset_vals[0] 

139 elif jday_np >= jday_min + jday_vals[-1]: 

140 return offset_min + offset_vals[-1] 

141 else: 

142 for i in range(0, len(offset_vals)): 

143 if (jday_min + jday_vals[i] <= jday_np) and ( 

144 jday_min + jday_vals[i + 1] > jday_np 

145 ): 

146 break 

147 return offset_min + offset_vals[i] 

148 

149 

150def utc_to_tt_offset_numpy(jday=None): 

151 """Returns the offset in seconds from a julian date in Terrestrial Time (TT) 

152 to a Julian day in Coordinated Universal Time (UTC) [NUMPY]""" 

153 if jday is None: 

154 jday_np = julian() 

155 elif type(jday) is not np.ndarray: 

156 jday_np = np.array(jday) 

157 else: 

158 jday_np = jday 

159 

160 # offsets=np.zeros(jday.shape) 

161 

162 jday_vals = 2441317.5 + np.array( 

163 [ 

164 -2441317.5, 

165 0.0, 

166 182.0, 

167 366.0, 

168 731.0, 

169 1096.0, 

170 1461.0, 

171 1827.0, 

172 2192.0, 

173 2557.0, 

174 2922.0, 

175 3469.0, 

176 3834.0, 

177 4199.0, 

178 4930.0, 

179 5844.0, 

180 6575.0, 

181 6940.0, 

182 7487.0, 

183 7852.0, 

184 8217.0, 

185 8766.0, 

186 9313.0, 

187 9862.0, 

188 12419.0, 

189 13515.0, 

190 14792.0, 

191 ] 

192 ) 

193 

194 offset_vals = 32.184 + np.array( 

195 [ 

196 -32.184, 

197 10.0, 

198 11.0, 

199 12.0, 

200 13.0, 

201 14.0, 

202 15.0, 

203 16.0, 

204 17.0, 

205 18.0, 

206 19.0, 

207 20.0, 

208 21.0, 

209 22.0, 

210 23.0, 

211 24.0, 

212 25.0, 

213 26.0, 

214 27.0, 

215 28.0, 

216 29.0, 

217 30.0, 

218 31.0, 

219 32.0, 

220 33.0, 

221 34.0, 

222 35.0, 

223 ] 

224 ) 

225 

226 try: 

227 offset = offset_vals[ 

228 np.clip(np.digitize(jday_np, jday_vals), 1, offset_vals.size) - 1 

229 ] 

230 except TypeError: 

231 offset = offset_vals[ 

232 np.clip(np.digitize([jday_np], jday_vals), 1, offset_vals.size) - 1 

233 ] 

234 offset = offset[0] 

235 

236 return offset # 64.184 

237 

238 

239def julian_tt(jday_utc=None): 

240 """Returns the TT Julian day given a UTC Julian day""" 

241 if jday_utc is None: 

242 jday_utc = julian() 

243 

244 jdtt = jday_utc + utc_to_tt_offset(jday_utc) / 86400.0 

245 return jdtt 

246 

247 

248def j2000_offset_tt(jday_tt=None): 

249 """Returns the julian day offset since the J2000 epoch""" 

250 if jday_tt is None: 

251 jday_tt = julian_tt() 

252 

253 return jday_tt - j2000_epoch() 

254 

255 

256def Mars_Mean_Anomaly(j2000_ott=None): 

257 """Calculates the Mars Mean Anomaly given a j2000 julian day offset""" 

258 if j2000_ott is None: 

259 j2000_ott = j2000_offset_tt() 

260 

261 M = 19.3870 + 0.52402075 * j2000_ott 

262 return M % 360.0 

263 

264 

265def FMS_Angle(j2000_ott=None): 

266 """Returns the Fictional Mean Sun angle""" 

267 if j2000_ott is None: 

268 j2000_ott = j2000_offset_tt() 

269 

270 alpha_fms = 270.3863 + 0.52403840 * j2000_ott 

271 return alpha_fms % 360.0 

272 

273 

274def alpha_perturbs(j2000_ott=None): 

275 """Returns the perturbations to apply to the FMS Angle from orbital perturbations""" 

276 if j2000_ott is None: 

277 j2000_ott = j2000_offset_tt() 

278 

279 array_A = [0.0071, 0.0057, 0.0039, 0.0037, 0.0021, 0.0020, 0.0018] 

280 array_tau = [2.2353, 2.7543, 1.1177, 15.7866, 2.1354, 2.4694, 32.8493] 

281 array_phi = [49.409, 168.173, 191.837, 21.736, 15.704, 95.528, 49.095] 

282 

283 pbs = 0 

284 for A, tau, phi in zip(array_A, array_tau, array_phi): 

285 pbs += A * np.cos(((0.985626 * j2000_ott / tau) + phi) * np.pi / 180.0) 

286 

287 return pbs 

288 

289 

290def equation_of_center(j2000_ott=None): 

291 """The true anomaly (v) - the Mean anomaly (M)""" 

292 if j2000_ott is None: 

293 j2000_ott = j2000_offset_tt() 

294 

295 M = Mars_Mean_Anomaly(j2000_ott) * np.pi / 180.0 

296 pbs = alpha_perturbs(j2000_ott) 

297 

298 val = ( 

299 (10.691 + 3.0e-7 * j2000_ott) * np.sin(M) 

300 + 0.6230 * np.sin(2 * M) 

301 + 0.0500 * np.sin(3 * M) 

302 + 0.0050 * np.sin(4 * M) 

303 + 0.0005 * np.sin(5 * M) 

304 + pbs 

305 ) 

306 

307 return val 

308 

309 

310def Mars_Ls(j2000_ott=None): 

311 """Returns the Areocentric solar longitude (aka Ls)""" 

312 if j2000_ott is None: 

313 j2000_ott = j2000_offset_tt() 

314 

315 alpha = FMS_Angle(j2000_ott) 

316 v_m = equation_of_center(j2000_ott) 

317 

318 ls = alpha + v_m 

319 ls = ls % 360 

320 return ls 

321 

322 

323def equation_of_time(j2000_ott=None): 

324 """Equation of Time, to convert between Local Mean Solar Time 

325 and Local True Solar Time, and make pretty analemma plots""" 

326 if j2000_ott is None: 

327 j2000_ott = j2000_offset_tt() 

328 

329 ls = Mars_Ls(j2000_ott) * np.pi / 180.0 

330 

331 EOT = ( 

332 2.861 * np.sin(2 * ls) 

333 - 0.071 * np.sin(4 * ls) 

334 + 0.002 * np.sin(6 * ls) 

335 - equation_of_center(j2000_ott) 

336 ) 

337 

338 return EOT 

339 

340 

341def j2000_from_Mars_Solar_Date(msd=0): 

342 """Returns j2000 based on MSD""" 

343 j2000_ott = ((msd + 0.00096 - 44796.0) * 1.027491252) + 4.5 

344 return j2000_ott 

345 

346 

347def j2000_ott_from_Mars_Solar_Date(msd=0): 

348 """Returns j2000 offset based on MSD""" 

349 j2000 = j2000_from_Mars_Solar_Date(msd) 

350 j2000_ott = julian_tt(j2000 + j2000_epoch()) 

351 return j2000_ott - j2000_epoch() 

352 

353 

354def Mars_Solar_Date(j2000_ott=None): 

355 """Return the Mars Solar date""" 

356 if j2000_ott is None: 

357 jday_tt = julian_tt() 

358 j2000_ott = j2000_offset_tt(jday_tt) 

359 

360 MSD = ((j2000_ott - 4.5) / 1.027491252) + 44796.0 - 0.00096 

361 return MSD 

362 

363 

364def Clancy_Year(j2000_ott=None): 

365 """Returns the Mars Year date based on the reference date from Clancy(2000): 1955 April 11, 11am""" 

366 if j2000_ott is None: 

367 jday_tt = julian_tt() 

368 j2000_ott = j2000_offset_tt(jday_tt) 

369 ref1955_4_11_11am = -16336.0416 # j2000_offset_tt reference 

370 year = np.floor(1 + (j2000_ott - ref1955_4_11_11am) / (686.978)) 

371 return year 

372 

373 

374def Mars_Year(j2000_ott=None, return_length=False): 

375 """Returns the Mars Year date based on the reference date 1955 April 11, 10:56:31 mtc after finding the j2k offsets of the zeroes of the Mars_Ls function.""" 

376 jday_vals = [ 

377 -16336.044076, 

378 -15649.093471, 

379 -14962.0892946, 

380 -14275.0960023, 

381 -13588.1458658, 

382 -12901.1772635, 

383 -12214.2082215, 

384 -11527.2637345, 

385 -10840.2842249, 

386 -10153.2828749, 

387 -9466.3114025, 

388 -8779.3356111, 

389 -8092.3607738, 

390 -7405.4236452, 

391 -6718.4615347, 

392 -6031.4574604, 

393 -5344.4876509, 

394 -4657.5318339, 

395 -3970.5474528, 

396 -3283.5848372, 

397 -2596.6329362, 

398 -1909.6426682, 

399 -1222.6617049, 

400 -535.7040268, 

401 151.2736522, 

402 838.2369682, 

403 1525.1834712, 

404 2212.1799182, 

405 2899.1848518, 

406 3586.1403058, 

407 4273.1024234, 

408 4960.0765368, 

409 5647.0207838, 

410 6333.986502, 

411 7020.9875066, 

412 7707.9629132, 

413 8394.9318782, 

414 9081.9102062, 

415 9768.8526533, 

416 10455.8028354, 

417 11142.8050514, 

418 11829.7873254, 

419 12516.7417734, 

420 13203.725449, 

421 13890.6991502, 

422 14577.6484912, 

423 15264.6324865, 

424 15951.6217969, 

425 16638.5798914, 

426 17325.5517216, 

427 18012.5209097, 

428 18699.4628887, 

429 19386.4443201, 

430 20073.4534421, 

431 20760.4152811, 

432 21447.3696661, 

433 22134.3466251, 

434 22821.2966642, 

435 23508.2529432, 

436 24195.2539572, 

437 24882.2400506, 

438 25569.2081296, 

439 26256.1902459, 

440 26943.1429481, 

441 27630.0847446, 

442 28317.0793316, 

443 29004.0710936, 

444 29691.0238241, 

445 30377.9991486, 

446 31064.9784277, 

447 31751.9249377, 

448 32438.896907, 

449 33125.8902412, 

450 33812.8520242, 

451 34499.8183442, 

452 35186.7944595, 

453 35873.740573, 

454 36560.7112423, 

455 37247.7247318, 

456 ] 

457 

458 year_vals = [ 

459 1, 

460 2, 

461 3, 

462 4, 

463 5, 

464 6, 

465 7, 

466 8, 

467 9, 

468 10, 

469 11, 

470 12, 

471 13, 

472 14, 

473 15, 

474 16, 

475 17, 

476 18, 

477 19, 

478 20, 

479 21, 

480 22, 

481 23, 

482 24, 

483 25, 

484 26, 

485 27, 

486 28, 

487 29, 

488 30, 

489 31, 

490 32, 

491 33, 

492 34, 

493 35, 

494 36, 

495 37, 

496 38, 

497 39, 

498 40, 

499 41, 

500 42, 

501 43, 

502 44, 

503 45, 

504 46, 

505 47, 

506 48, 

507 49, 

508 50, 

509 51, 

510 52, 

511 53, 

512 54, 

513 55, 

514 56, 

515 57, 

516 58, 

517 59, 

518 60, 

519 61, 

520 62, 

521 63, 

522 64, 

523 65, 

524 66, 

525 67, 

526 68, 

527 69, 

528 70, 

529 71, 

530 72, 

531 73, 

532 74, 

533 75, 

534 76, 

535 77, 

536 78, 

537 79, 

538 ] 

539 

540 year_length = [ 

541 686.95252, 

542 686.950605, 

543 687.0041764, 

544 686.9932923, 

545 686.9501365, 

546 686.9686023, 

547 686.969042, 

548 686.944487, 

549 686.9795096, 

550 687.00135, 

551 686.9714724, 

552 686.9757914, 

553 686.9748373, 

554 686.9371286, 

555 686.9621105, 

556 687.0040743, 

557 686.9698095, 

558 686.955817, 

559 686.9843811, 

560 686.9626156, 

561 686.951901, 

562 686.990268, 

563 686.9809633, 

564 686.9576781, 

565 686.977679, 

566 686.963316, 

567 686.946503, 

568 686.996447, 

569 687.0049336, 

570 686.955454, 

571 686.9621176, 

572 686.9741134, 

573 686.944247, 

574 686.9657182, 

575 687.0010046, 

576 686.9754066, 

577 686.968965, 

578 686.978328, 

579 686.9424471, 

580 686.9501821, 

581 687.002216, 

582 686.982274, 

583 686.954448, 

584 686.9836756, 

585 686.9737012, 

586 686.949341, 

587 686.9839953, 

588 686.9893104, 

589 686.9580945, 

590 686.9718302, 

591 686.9691881, 

592 686.941979, 

593 686.9814314, 

594 687.009122, 

595 686.961839, 

596 686.954385, 

597 686.976959, 

598 686.9500391, 

599 686.956279, 

600 687.001014, 

601 686.9860934, 

602 686.968079, 

603 686.9821163, 

604 686.9527022, 

605 686.9417965, 

606 686.994587, 

607 686.991762, 

608 686.9527305, 

609 686.9753245, 

610 686.9792791, 

611 686.94651, 

612 686.9719693, 

613 686.9933342, 

614 686.961783, 

615 686.96632, 

616 686.9761153, 

617 686.9461135, 

618 686.9706693, 

619 687.0134895, 

620 ] 

621 

622 if use_numpy: 

623 return Mars_Year_np( 

624 j2000_ott, jday_vals, year_vals, year_length, return_length 

625 ) 

626 else: 

627 return Mars_Year_math( 

628 j2000_ott, jday_vals, year_vals, year_length, return_length 

629 ) 

630 

631 

632def Mars_Year_math( 

633 j2k_math, jday_vals, year_vals, year_length, return_length=False 

634): 

635 

636 if j2k_math < jday_vals[0]: 

637 return np.floor(1 + (j2k_math - jday_vals[0]) / year_length[0]) 

638 elif j2k_math >= jday_vals[-1]: 

639 return np.floor(1 + (j2k_math - jday_vals[-1]) / year_length[-1]) 

640 else: 

641 for i in range(0, len(year_vals) - 1): 

642 if (jday_vals[i] <= j2k_math) and (jday_vals[i + 1] > j2k_math): 

643 break 

644 y = year_vals[i] 

645 length_year = year_length[i] 

646 

647 if return_length: 

648 return (y, length_year) 

649 else: 

650 return y 

651 

652 

653def Mars_Year_np( 

654 j2k_np, jday_vals, year_vals, year_length, return_length=False 

655): 

656 jday_vals = np.array(jday_vals) 

657 

658 year_vals = np.array(year_vals) 

659 

660 year_length = np.array(year_length) 

661 

662 if j2k_np < jday_vals[0]: 

663 return np.floor(1 + (j2k_np - jday_vals[0]) / year_length[0]) 

664 elif j2k_np >= jday_vals[-1]: 

665 return np.floor(1 + (j2k_np - jday_vals[-1]) / year_length[-1]) 

666 else: 

667 try: 

668 v = np.clip(np.digitize(j2k_np, jday_vals), 1, jday_vals.size) - 1 

669 y = year_vals[v] 

670 length_year = year_length[v] 

671 except TypeError: 

672 v = ( 

673 np.clip(np.digitize([j2k_np], jday_vals), 1, jday_vals.size) 

674 - 1 

675 ) 

676 y = year_vals[v][0] 

677 length_year = year_length[v][0] 

678 

679 if return_length: 

680 return (y * 1.0, length_year) 

681 else: 

682 return y * 1.0 

683 

684 

685def Coordinated_Mars_Time(j2000_ott=None): 

686 """The Mean Solar Time at the Prime Meridian""" 

687 if j2000_ott is None: 

688 jday_tt = julian_tt() 

689 j2000_ott = j2000_offset_tt(jday_tt) 

690 

691 MTC = 24 * (((j2000_ott - 4.5) / 1.027491252) + 44796.0 - 0.00096) 

692 MTC = MTC % 24 

693 return MTC 

694 

695 

696def Local_Mean_Solar_Time(longitude=0, j2000_ott=None): 

697 """The Local Mean Solar Time given a planetographic longitude""" 

698 if j2000_ott is None: 

699 jday_tt = julian_tt() 

700 j2000_ott = j2000_offset_tt(jday_tt) 

701 

702 MTC = Coordinated_Mars_Time(j2000_ott) 

703 LMST = MTC - longitude * (24 / 360.0) 

704 LMST = LMST % 24 

705 return LMST 

706 

707 

708def Local_True_Solar_Time(longitude=0, j2000_ott=None): 

709 """Local true solar time is the Mean solar time + equation of time perturbation""" 

710 if j2000_ott is None: 

711 jday_tt = julian_tt() 

712 j2000_ott = j2000_offset_tt(jday_tt) 

713 

714 eot = equation_of_time(j2000_ott) 

715 lmst = Local_Mean_Solar_Time(longitude, j2000_ott) 

716 ltst = lmst + eot * (24 / 360.0) 

717 ltst = ltst % 24 

718 return ltst 

719 

720 

721def subsolar_longitude(j2000_ott=None): 

722 """returns the longitude of the subsolar point for a given julian day.""" 

723 if j2000_ott is None: 

724 jday_tt = julian_tt() 

725 j2000_ott = j2000_offset_tt(jday_tt) 

726 

727 MTC = Coordinated_Mars_Time(j2000_ott) 

728 EOT = equation_of_time(j2000_ott) * 24 / 360.0 

729 subsol = (MTC + EOT) * (360 / 24.0) + 180.0 

730 return subsol % 360.0 

731 

732 

733def solar_declination(ls=None): 

734 """Returns the solar declination""" 

735 if ls is None: 

736 ls = Mars_Ls() 

737 ls1 = ls * np.pi / 180.0 

738 

739 if use_numpy: 

740 dec = np.arcsin(0.42565 * np.sin(ls1)) + 0.25 * (np.pi / 180) * np.sin( 

741 ls1 

742 ) 

743 else: 

744 dec = np.asin(0.42565 * np.sin(ls1)) + 0.25 * (np.pi / 180) * np.sin( 

745 ls1 

746 ) 

747 dec = dec * 180.0 / np.pi 

748 return dec 

749 

750 

751def heliocentric_distance(j2000_ott=None): 

752 """Instantaneous orbital radius""" 

753 if j2000_ott is None: 

754 j2000_ott = j2000_offset_tt() 

755 

756 M = Mars_Mean_Anomaly(j2000_ott) * np.pi / 180.0 

757 

758 rm = 1.523679 * ( 

759 1.00436 

760 - 0.09309 * np.cos(M) 

761 - 0.004336 * np.cos(2 * M) 

762 - 0.00031 * np.cos(3 * M) 

763 - 0.00003 * np.cos(4 * M) 

764 ) 

765 

766 return rm 

767 

768 

769def heliocentric_longitude(j2000_ott=None): 

770 """Heliocentric longitude, which is not Ls (offsets are different)""" 

771 if j2000_ott is None: 

772 j2000_ott = j2000_offset_tt() 

773 ls = Mars_Ls(j2000_ott) 

774 

775 im = ( 

776 ls 

777 + 85.061 

778 - 0.015 * np.sin((71 + 2 * ls) * np.pi / 180.0) 

779 - 5.5e-6 * j2000_ott 

780 ) 

781 

782 return im % 360.0 

783 

784 

785def heliocentric_latitude(j2000_ott=None): 

786 """Heliocentric Latitude, which is not Ls""" 

787 if j2000_ott is None: 

788 j2000_ott = j2000_offset_tt() 

789 

790 ls = Mars_Ls(j2000_ott) 

791 

792 bm = -(1.8497 - 2.23e-5 * j2000_ott) * np.sin( 

793 (ls - 144.50 + 2.57e-6 * j2000_ott) * np.pi / 180.0 

794 ) 

795 

796 return bm 

797 

798 

799def hourangle(longitude=0, j2000_ott=None): 

800 """Hourangle is the longitude - subsolar longitude""" 

801 if j2000_ott is None: 

802 # jday_tt = julian_tt() 

803 j2000_ott = j2000_offset_tt() 

804 

805 subsol = subsolar_longitude(j2000_ott) * np.pi / 180.0 

806 hourangle = longitude * np.pi / 180.0 - subsol 

807 return hourangle 

808 

809 

810def solar_zenith(longitude=0, latitude=0, j2000_ott=None): 

811 """Zenith Angle, angle between sun and nadir""" 

812 

813 if latitude > 90 or latitude < -90: 

814 raise ValueError("Latitude out of Bounds: {}".format(latitude)) 

815 if j2000_ott is None: 

816 # jday_tt = julian_tt() 

817 j2000_ott = j2000_offset_tt() 

818 

819 ha = hourangle(longitude, j2000_ott) 

820 ls = Mars_Ls(j2000_ott) 

821 dec = solar_declination(ls) * np.pi / 180 

822 

823 cosZ = np.sin(dec) * np.sin(latitude * np.pi / 180) + np.cos(dec) * np.cos( 

824 latitude * np.pi / 180.0 

825 ) * np.cos(ha) 

826 

827 if use_numpy: 

828 Z = np.arccos(cosZ) * 180.0 / np.pi 

829 else: 

830 Z = np.acos(cosZ) * 180.0 / np.pi 

831 return Z 

832 

833 

834def solar_elevation(longitude=0, latitude=0, j2000_ott=None): 

835 """Elevation = 90-Zenith, angle between sun and flat surface""" 

836 if j2000_ott is None: 

837 jday_tt = julian_tt() 

838 j2000_ott = j2000_offset_tt(jday_tt) 

839 

840 Z = solar_zenith(longitude, latitude, j2000_ott) 

841 return 90 - Z 

842 

843 

844def solar_azimuth(longitude=0, latitude=0, j2000_ott=None): 

845 """Azimuth Angle, between sun and north pole""" 

846 if j2000_ott is None: 

847 jday_tt = julian_tt() 

848 j2000_ott = j2000_offset_tt(jday_tt) 

849 

850 ha = hourangle(longitude, j2000_ott) 

851 ls = Mars_Ls(j2000_ott) 

852 dec = solar_declination(ls) * np.pi / 180.0 

853 denom = np.cos(latitude) * np.tan(dec) - np.sin(latitude) * np.cos(ha) 

854 

855 num = np.sin(ha) 

856 

857 if use_numpy: 

858 az = (360 + np.arctan2(num, denom) * 180.0 / np.pi) % 360.0 

859 else: 

860 az = (360 + np.atan2(num, denom) * 180.0 / np.pi) % 360.0 

861 return az 

862 

863 

864if __name__ == "__main__": 

865 

866 mils = [947116800000, 1073137591000] 

867 longitudes = [0.0, 184.702] 

868 latitudes = [0.0, -14.640] 

869 

870 for i in range(2): 

871 mil = mils[i] 

872 longitude = longitudes[i] 

873 latitude = latitudes[i] 

874 print("latitude = ", latitude) 

875 print("longitude = ", longitude) 

876 print("a1 = ", mil) 

877 jdut = julian(mil) 

878 print("a2 = ", jdut) 

879 tt_utc = utc_to_tt_offset(jdut) 

880 print("a4 = ", tt_utc) 

881 jday_tt = julian_tt(jdut) 

882 print("a5 = ", jday_tt) 

883 j2000_ott = j2000_offset_tt(jday_tt) 

884 print("a6 = ", j2000_ott) 

885 m = Mars_Mean_Anomaly(j2000_ott) 

886 print("b1 = ", m) 

887 alpha = FMS_Angle(j2000_ott) 

888 print("b2 = ", alpha) 

889 pbs = alpha_perturbs(j2000_ott) 

890 print("b3 = ", pbs) 

891 v_m = equation_of_center(j2000_ott) 

892 print("b4 = ", v_m) 

893 ls = Mars_Ls(j2000_ott) 

894 print("b5 = ", ls) 

895 eot = equation_of_time(j2000_ott) 

896 print("c1 = ", eot) 

897 mtc = Coordinated_Mars_Time(j2000_ott) 

898 print("c2 = ", mtc) 

899 lmst = Local_Mean_Solar_Time(longitude, j2000_ott) 

900 print("c3 = ", lmst) 

901 ltst = Local_True_Solar_Time(longitude, j2000_ott) 

902 print("c4 = ", ltst) 

903 subsol = subsolar_longitude(j2000_ott) 

904 print("c5 = ", subsol) 

905 dec = solar_declination(ls) 

906 print("d1 = ", dec) 

907 rm = heliocentric_distance(j2000_ott) 

908 print("d2 = ", rm) 

909 im = heliocentric_longitude(j2000_ott) 

910 print("d3 = ", im) 

911 bm = heliocentric_latitude(j2000_ott) 

912 print("d4 = ", bm) 

913 sz = solar_zenith(longitude, latitude, j2000_ott) 

914 print("d5 = ", sz) 

915 sz = solar_azimuth(longitude, latitude, j2000_ott) 

916 print("d6 = ", sz)