Fortran - 日・月の出・南中・入時刻の計算!
Updated:
Fortran 95 で、日・月の出・南中・入時刻を計算してみました。(出・入はその時の方位角、南中はその時の高度も)
過去に Ruby で行ったことはありましたが。
0. 前提条件
- LMDE 3 (Linux Mint Debian Edition 3; 64bit) での作業を想定。
- GCC 6.3.0 (GFortran 6.3.0) でのコンパイルを想定。
1. 計算方法について
計算アルゴリズムは「日の出・日の入りの計算―天体の出没時刻の求め方」によるもの。
2. ソースコードの作成
以下は実行部分。
File: sun_moon.f95
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
!*******************************************************************************
! 日・月の出・南中・入時刻、日・月の出・入方位角、日・月の南中高度の計算
!
! date name version
! 2018.11.11 mk-mode.com 1.00 新規作成
!
! Copyright(C) 2018 mk-mode.com All Rights Reserved.
! ---
! 引数 : 99999999 [+-]999.99 [+-]999.99 [+]9999.99
! 第1: 日付 [必須]
! 計算対象の日付(グレゴリオ暦)を半角8桁数字で指定
! 第2: 緯度 [必須]
! 緯度を 度 で指定(度・分・秒は度に換算して指定すること)
! (北緯はプラス、南緯はマイナス。桁数は特に制限なし)
! 第3: 経度 [必須]
! 経度を 度 で指定(度・分・秒は度に換算して指定すること)
! (東経はプラス、西経はマイナス。桁数は特に制限なし)
! 第4: 標高 [必須]
! 標高をメートルで指定(マイナス値は指定不可)
! (桁数は特に制限なし)
!*******************************************************************************
!
program sun_moon
use const, only : SP, DP, SEC_DAY
use time
use delta_t
use calc
implicit none
type(t_time) :: jst, utc
type(t_time) :: tm_sr, tm_ss, tm_sm, tm_mr, tm_ms, tm_mm
integer(SP) :: utc_tai
real(DP) :: lat, lon, ht, dut1, dt, dt_d, dip, day_p
real(DP) :: ang_sr, ang_ss, ang_mr, ang_ms, ht_sm, ht_mm
! コマンドライン引数取得
call get_arg(jst, lat, lon, ht)
! 初期処理
call jst2utc(jst, utc) ! JST -> UTC
call utc2utc_tai(utc, utc_tai) ! UTC -> UTC - TAI
call utc2dut1(utc, dut1) ! UTC -> DUT1
call utc2dt(utc, utc_tai, dut1, dt) ! UTC -> delta T
dt_d = dt / SEC_DAY ! ΔTを日換算
dip = 0.0353333_DP * sqrt(ht) ! 地平線伏角
day_p = day_progress(jst) ! 2000年1月1日力学時正午からの経過日数(日)
! 各種計算
call calc_sun_sr( 0, lon, lat, day_p, dt_d, dip, tm_sr, ang_sr) ! 日の出
call calc_sun_sr( 1, lon, lat, day_p, dt_d, dip, tm_ss, ang_ss) ! 日の入
call calc_sun_m( lon, lat, day_p, dt_d, dip, tm_sm, ht_sm ) ! 日の南中
call calc_moon_sr(0, lon, lat, day_p, dt_d, dip, tm_mr, ang_mr) ! 月の出
call calc_moon_sr(1, lon, lat, day_p, dt_d, dip, tm_ms, ang_ms) ! 月の入
call calc_moon_m( lon, lat, day_p, dt_d, dip, tm_mm, ht_mm ) ! 月の南中
! 結果出力
call display
stop
contains
! コマンドライン引数取得
!
! :param(out) type(t_time) jst: 日付
! :param(out) real(8) lat: 緯度
! :param(out) real(8) lon: 経度
! :param(out) real(8) ht: 標高
subroutine get_arg(jst, lat, lon ,ht)
implicit none
type(t_time), intent(out) :: jst
real(DP), intent(out) :: lat, lon ,ht
character(32) :: buf
integer(SP) :: dt(8), ios, y, m, d
if (iargc() /= 4) then
print *, "Arguments: YYYYMMDD LATITUDE LONGITUDE HEIGHT"
stop
end if
call getarg(1, buf)
read (buf, '(I4I2I2)', iostat=ios) y, m, d
if (ios /= 0) then
print *, "DATE is invalid!"
stop
end if
jst = t_time(y, m, d, 0, 0, 0)
call getarg(2, buf)
read (buf, *, iostat=ios) lat
if (ios /= 0) then
print *, "LATITUDE is invalid!"
stop
end if
call getarg(3, buf)
read (buf, *, iostat=ios) lon
if (ios /= 0) then
print *, "LONGITUDE is invalid!"
stop
end if
call getarg(4, buf)
read (buf, *, iostat=ios) ht
if (ios /= 0) then
print *, "HEIGHT is invalid!"
stop
end if
if (ht < 0.0_DP) then
print *, "HEIGHT is invalid!"
stop
end if
end subroutine get_arg
! 結果出力
subroutine display
implicit none
character(1) :: s_lat, s_lon
s_lat = "N"
s_lon = "E"
if (lat < 0.0_DP) then
s_lat = "S"
lat = dsign(lat, 1.0_DP)
end if
if (lon < 0.0_DP) then
s_lon = "W"
lon = dsign(lon, 1.0_DP)
end if
print '("[", I4, "-", I0.2, "-", I0.2, "JST ", &
& F0.4, A, X, F0.4, A, X, F0.2, "m]")', &
& jst%year, jst%month, jst%day, lat, s_lat, lon, s_lon, ht
print '("日の出 ", I0.2, ":", I0.2, ":", I0.2, &
& " (方位角 ", F6.2, ")")', &
& tm_sr%hour, tm_sr%minute, tm_sr%second, ang_sr
print '("日南中 ", I0.2, ":", I0.2, ":", I0.2, &
& " ( 高度 ", F6.2, ")")', &
& tm_sm%hour, tm_sm%minute, tm_sm%second, ht_sm
print '("日の入 ", I0.2, ":", I0.2, ":", I0.2, &
& " (方位角 ", F6.2, ")")', &
& tm_ss%hour, tm_ss%minute, tm_ss%second, ang_ss
if (ang_mr < 0.0_DP) then
print '(A)', "月の出 --:--:-- (方位角 ---.--)"
else
print '("月の出 ", I0.2, ":", I0.2, ":", I0.2, &
& " (方位角 ", F6.2, ")")', &
& tm_mr%hour, tm_mr%minute, tm_mr%second, ang_mr
end if
if (ht_mm < 0.0_DP) then
print '(A)', "月南中 --:--:-- ( 高度 ---.--)"
else
print '("月南中 ", I0.2, ":", I0.2, ":", I0.2, &
& " ( 高度 ", F6.2, ")")', &
& tm_mm%hour, tm_mm%minute, tm_mm%second, ht_mm
end if
if (ang_ms < 0.0_DP) then
print '(A)', "月の入 --:--:-- (方位角 ---.--)"
else
print '("月の入 ", I0.2, ":", I0.2, ":", I0.2, &
& " (方位角 ", F6.2, ")")', &
& tm_ms%hour, tm_ms%minute, tm_ms%second, ang_ms
end if
end subroutine display
end program sun_moon
モジュールや定数ファイルを含めた全てのファイルは GitHub にアップしている。(当然ながら、モジュール部分の方が計算の本質となっている)
3. ソースコードのビルド
全てのファイルを用意してから、以下を実行。
$ make
- やり直す場合は、
make clean
してから。
4. 準備
- うるう年ファイル
LEAP_SEC.txt
, DUT1 ファイルDUT1.txt
は適宜最新のものに更新すること。
5. 実行方法
日付、緯度、経度、標高を 99999999 [+-]999.99 [+-]999.99 [+]9999.99
形式指定して実行。
$ .sun_moon 99999999 [+-]999.99 [+-]999.99 [+]9999.99
- 第1: 日付 [必須]
計算対象の日付(グレゴリオ暦)を半角8桁数字で指定 - 第2: 緯度 [必須]
緯度を 度 で指定(度・分・秒は度に換算して指定すること)
(北緯はプラス、南緯はマイナス。桁数は特に制限なし) - 第3: 経度 [必須]
経度を 度 で指定(度・分・秒は度に換算して指定すること)
(東経はプラス、西経はマイナス。桁数は特に制限なし) - 第4: 標高 [必須]
標高をメートルで指定(マイナス値は指定不可)
(桁数は特に制限なし)
以下、実行例。(2019年1月24日、松江市役所の緯度・経度、標高0m で計算)
$ ./sun_moon 20190124 35.4681 133.0486 0
[2019-01-24JST 35.4681N 133.0486E .00m]
日の出 07:13:01 (方位角 113.34)
日南中 12:19:43 ( 高度 35.26)
日の入 17:26:45 (方位角 246.79)
月の出 21:04:39 (方位角 80.76)
月南中 02:44:31 ( 高度 66.04)
月の入 09:26:40 (方位角 282.21)
以上。
Comments