海上保安庁海洋情報部-続・天体の位置計算式をコード化してみた

前記事「海上保安庁海洋情報部-天体の位置計算式をコード化してみた」では、位置を求める係数をプログラム中に記述していました。今回は、前記事「海上保安庁海洋情報部-天体の位置計算データファイルの作成」で作成したデータファイルを利用して、日付と惑星番号を選択するだけで位置を求めるようにコードを変更しました。なお、恒星については対応していません。近日中に公開する予定です。

CSVファイルについての注意
データファイルはCSV形式で保存したものを読み込んでいます。ですので、あらかじめ表計算のワークシートごとにCSV形式で出力して保存しておく必要があります。このとき、1行目には、ダミーデータとして0を追加してください(見やすいように加工をしています)。

0,0,0
22.714111, -5.77971,  0.993148
 3.895588, 20.02854,  0.012659
-0.102703,  1.72530,  0.002294
 0.034943, -0.98556, -0.000642
 0.006578,  0.01260, -0.000037
-0.002269,  0.00796,  0.000013
 0.00009,  -0.00351,  0.000009
 0.00009,   0.00081,  0.000005
-0.000024,  0.00022, -0.000007
 0.000024,  0.00010,  0.000002
 0.000022,  0.00009, -0.000014
-0.000066, -0.00033, -0.000006
-0.000019, -0.00024,  0.000014
 0.00004,   0.00022,  0.000004
 0.000006,  0.00014, -0.000006
-0.000014, -0.00008, -0.000001
 0.000004, -0.00003,  0.000002
 0.000002,  0.00003,  0.000000

CSV形式のファイル名は以下の形式になるようにします。

惑星名-data-番号.csv

たとえば、太陽でしたら1月0日から5月1日の係数データのファイル名は、sun-data-01.csvになります。次はsun-data-02.csv、sun-data-03となります。この形式はプログラム中でも利用していますので、変更する際はコードを書き換えてください。月は一月ごとになりますので、moon-data-01.csvからmoon-data-12.csvまでとなります。

CSVファイルを保管するフォルダ名とディレクトリ
CSVファイルを格納するディレクトリ構造は以下の図のとおりです。よけいなファイルがありますが気にしないでください。必要なのは、pcob_main.f90とpcob_sub.f90だけです。

親ディレクトリ名は何でも構いませんが、data、2022と各惑星名のフォルダ名は変更しないようにしてください。大文字小文字混在もNGです。ディレクトリ構造も変更しないでください。もし変更する場合は、コードも対応したものに書き換えてください。

Fortranによるコード

▶ サブルーチン pcob_sub.f90

前記事「海上保安庁海洋情報部-天体の位置計算式をコード化してみた」で作成したファイルの名前を変更したものです。ですが、コードは削除と追加を行っています。言うまでもないことですが、係数データは、その年で有効なものです。過去や未来の日付を入力しても正しく求めることができません。計算する日付(年)の係数データを用意する必要があります。

subroutine getPlanetaryPosition(planet_number, year, month, day, hour, minute, second, pos)
! 視赤経・視赤緯・地心距離および視半径の計算
! 海上保安庁 海洋情報部による略算式
! https:!www1.kaiho.mlit.go.jp/KOHO/index.html
!
! 引 数:  観測年月日+時分秒(日本標準時)
!          year        : 年
!          month       : 月
!          day         : 日
!          hour        : 時
!          minute      : 分
!          second      : 秒
! 戻り値:  視赤経・視赤緯・地心距離・視半径を返す
!          pos(1): 視赤経
!          pos(2): 視赤緯
!          pos(3): 地心距離
!          pos(4): 視半径
!          pos(5): R
!          pos(6): 平均黄道傾斜角
!
! 計算精度について:
! 略算式とはいえ、精度は国立天文台天文情報センター暦計算室の値と較べても
! 非常に高い一致をみる。ただ、使用にあたっては、係数の桁数の関係で視赤経
! および視赤緯、地心距離は小数点以下5-6桁までにとどめる。
    implicit none

    double precision, parameter :: PI = 3.141592653589793d0
    double precision, parameter :: RAD = 180.0d0 / PI
    double precision, parameter :: DELTAT = 70.0d0
    double precision, dimension(6), parameter :: SO = (/0.0d0, 16.02d0, 0.1383d0, 0.078d0, 1.535d0, 1.23d0/) ! ベースとなる太陽の視半径
    character(7), parameter :: CELESTIA(6) = (/'moon   ', 'sun    ', 'venus  ', 'mars   ', 'jupiter', 'saturn '/)
    
    double precision, intent(in) :: year, month, day
    double precision, intent(in) :: hour, minute, second
    double precision, intent(out) :: pos(6)
    integer, intent(in) :: planet_number

    double precision, dimension(12, 2) :: check = 0.0d0
    double precision, dimension(0:30, 1:3) :: x = 0.0d0
    double precision, dimension(0:10, 1:2) :: r = 0.0d0
    double precision :: f, tp, theta, rr
    double precision :: ra ! 赤経
    double precision :: dc ! 赤緯
    double precision :: ds ! 地心距離
    double precision :: ec ! 黄道傾斜角
    integer :: i, n, a, b, p, q, y, s, t
    character(20) :: path
    character(19) :: filename, rfilename
    character(2) :: filenumber
    character(4) :: syear

    ! 各種引数の計算
    p = int(month) - 1
    q = int((month + 7) / 10)
    y = int((year / 4) - int(year / 4) + 0.77)
    s = int(p * 0.55 - 0.33)
    t = int(30 * p + q * (s - y) + p * (1 - q) + day)
    f = (hour - 9.0d0) / 24.0d0 + minute / 1440.0d0 + second / 86400.0d0
    tp = t + f + DELTAT / 86400.0d0

    ! 惑星番号によって読み込むファイル名を構成する
    write(syear, '(i4)') int(year)
    path = './data/'//syear//'/'//trim(CELESTIA(planet_number))//'/'

    select case(planet_number)
    case(1) ! 月
        n = 30
        check( 1, 1:2) = (/  0.0d0,  32.0d0/)
        check( 2, 1:2) = (/ 31.0d0,  60.0d0/)
        check( 3, 1:2) = (/ 59.0d0,  91.0d0/)
        check( 4, 1:2) = (/ 90.0d0, 121.0d0/)
        check( 5, 1:2) = (/120.0d0, 152.0d0/)
        check( 6, 1:2) = (/151.0d0, 182.0d0/)
        check( 7, 1:2) = (/181.0d0, 213.0d0/)
        check( 8, 1:2) = (/212.0d0, 244.0d0/)
        check( 9, 1:2) = (/243.0d0, 274.0d0/)
        check(10, 1:2) = (/273.0d0, 305.0d0/)
        check(11, 1:2) = (/304.0d0, 335.0d0/)
        check(12, 1:2) = (/334.0d0, 366.0d0/)
        do i = 1, 12
            if ((check(i, 1) <= tp) .and. (tp <= check(i, 2))) then
                a = int(check(i,1))
                b = int(check(i, 2))
                write(filenumber, '(i2.2)') i
                filename = trim(CELESTIA(planet_number))//'-data-'//filenumber//'.csv'
                exit
            end if
        end do
    case(2:6) ! 太陽・金星・火星・木星・土星
        n = 18
        check(1, 1:2) = (/  0.0d0, 121.0d0/)
        check(2, 1:2) = (/120.0d0, 244.0d0/)
        check(3, 1:2) = (/243.0d0, 366.0d0/)
        do i = 1, 3
            if ((check(i, 1) <= tp) .and. (tp <= check(i, 2))) then
                a = int(check(i,1))
                b = int(check(i, 2))
                write(filenumber, '(i2.2)') i
                filename = trim(CELESTIA(planet_number))//'-data-'//filenumber//'.csv'
                rfilename = 'r-data-'//filenumber//'.csv'
                exit
            end if
        end do
    end select

    ! 構成されたファイル名から係数データを読み込む
    write(*, *) 
    open(10, file=trim(path)//trim(filename), status="old")
    do i = 0, n
        read(10, *) x(i, 1:3)
    end do
    close(10)
    write(*, *)

    ! Rおよび黄道傾斜角の係数を読み込む(太陽・金星・火星・木星・土星)
    if ((2 <= planet_number) .and. (planet_number <= 6)) then
        open(20, file='./data/'//syear//'/R/'//trim(rfilename), status="old")
        do i = 0, 8
            read(20, *) r(i, 1:2)
        end do
        close(20)
    end if
    write(*, *)

    ! 視赤経・視赤緯および地心距離の計算
    theta = acos((2.0d0 * tp - (a + b)) / (b - a)) * RAD
    ra = 0.0d0
    dc = 0.0d0
    ds = 0.0d0
    do i = 0, n
        ra = ra + (x(i + 1, 1) * cos(mod((theta * i), 360.0d0) / RAD))
        dc = dc + (x(i + 1, 2) * cos(mod((theta * i), 360.0d0) / RAD))
        ds = ds + (x(i + 1, 3) * cos(mod((theta * i), 360.0d0) / RAD)) ! 月の場合はH.P.
    end do

    if (int(ra) >= 24) then
        ra = ra - 24
    else
        if (ra < 0) then
            ra = ra + 24
        end if
    end if

    pos(1) = ra
    pos(2) = dc
    pos(3) = ds

    ! Rと黄道傾斜角の計算(太陽・金星・火星・木星・土星)
    if ((2 <= planet_number) .and. (planet_number <= 6)) then
        theta = acos((2.0d0 * (t + f) - (a + b)) / (b - a)) * RAD
        rr = 0.0d0
        ec = 0.0d0
        do i = 0, 7
            rr = rr + (r(i + 1, 1) * cos(mod((theta * i), 360.0d0) / RAD))        
            ec = ec + (r(i + 1, 2) * cos(mod((theta * i), 360.0d0) / RAD))        
        end do

        ra = rr - ra
        pos(4) = SO(planet_number) / ds
        pos(5) = ra ! Rを考慮した赤経
        pos(6) = ec ! 黄道傾斜角
    else
        ! 月のときは0が入る
        pos(3) = ds
        ds = sin(ds / RAD)
        ds = 0.2725d0 * ds
        ds = asin(ds) * RAD
        pos(4) = ds * 60.0d0
        pos(5) = 0.0d0
        pos(6) = 0.0d0
    end if

    return
end subroutine getPlanetaryPosition

▶ メインルーチン pcob_main.f90

program pcob_main
! 天体の視位置を求める

    implicit none
    
    character(7), parameter :: CELESTIA(6) = (/'Moon   ', 'Sun    ', 'Venus  ', 'Mars   ', 'Jupiter', 'Saturn '/)

    double precision, dimension(6) :: pos
    double precision :: year, month, day, hour, minute, second
    double precision :: rs, ds, ss
    integer :: rh, rm, dh, dm, sm
    character(1) :: sign
    character(132) :: sfmt

    double precision :: dy = 0.0d0
    double precision :: dt = 0.0d0
    integer :: planet_number = 0

    write(*, *)
    write(*, fmt='(a)', advance='no') 'DATE AND TIME(JST) ? '
    read(*, *) dy, dt
    write(*, fmt='(a)', advance='no') '(1: Moon, 2: Sun, 3:Venus, 4: Mars, 5: Jupiter, 6: Saturn) ? '
    read(*, *) planet_number

    if ((planet_number < 1) .or. (planet_number > 6)) then
        stop 'Bad Planet Number!'
    end if

    ! 年月日および時刻を抽出する
    year = int(dy / 10000.0d0)
    month = mod(int(dy / 100.0d0), 100)
    day = mod(dy, 100.0d0)
    hour = int(dt / 10000.0d0)
    minute = mod(int(dt / 100.0d0), 100)
    second = mod(dt, 100.0d0)

    call getPlanetaryPosition(planet_number, year, month, day, hour, minute, second, pos)

    rh = int(pos(1))
    rs = 60.0d0 * (pos(1) - rh)
    rm = int(rs)
    rs = 60.0d0 * (rs - rm)

    sign = '+'
    if (pos(2) < 0) then
        sign = '-'
    end if

    dh = abs(int(pos(2)))
    ds = 60.0d0 * (abs(pos(2)) - dh)
    dm = int(ds)
    ds = 60.0d0 * (ds - dm)

    write(*, '(i5, "年 ", i2, "月 ", i2, "日 ", i2, "時 ", i2, "分 ", i2, "秒")') &
    int(year), int(month), int(day), int(hour), int(minute), int(second)
    write(*, *)
    write(*, '(a, "の視位置")') trim(CELESTIA(planet_number))
    write(*, *)
    if (planet_number == 1) then
        ! 月の場合は黄道傾斜角を表示しない
        sm = int(pos(4))
        ss = 60.0d0 * (pos(4) - sm)    
        sfmt = '(i2, " ", i2, " ", f6.3, "    ", a1, i2, " ", i2, " ", f5.2, "   ", f9.7, "    ", i3, " ", f5.2)'
        write(*, *) '    赤経            赤緯         H.P.     視半径'
        write(*, *) ' h  m  s          。 ,                        ,  ,,'
        write(*, sfmt) rh, rm, rs, sign, dh, dm, ds, pos(3), sm, ss       
    else
        sm = int(pos(4))
        ss = 60.0d0 * (pos(4) - sm)    
        sfmt = '(i2, " ", i2, " ", f6.3, "    ", a1, i2, " ", i2, " ", f5.2, "   ", f9.7, "    ", i2, " ", f5.2, "     ", f10.7)'
        write(*, '("")')
        write(*, *) '    赤経            赤緯       地心距離     視半径      黄道傾斜角'
        write(*, *) ' h  m  s          。 ,               AU      ,  ,,        。'
        write(*, sfmt) rh, rm, rs, sign, dh, dm, ds, pos(3), sm, ss, pos(6)
    end if
    write(*, *)
    
    stop
end program pcob_main

コンパイル

gfortran pcob_main.f90 pcob_sub.f90

実行

./a.out

実行結果

2022年5月24日9時00分00秒における視位置を求めてみました。

太陽

DATE AND TIME(JST) ? 20220524,090000
(1: Moon, 2: Sun, 3:Venus, 4: Mars, 5: Jupiter, 6: Saturn) ? 2


 2022年  5月 24日  9時  0分  0秒

Sunの視位置

     赤経            赤緯       地心距離     視半径      黄道傾斜角
  h  m  s          。 ,               AU      ,  ,,        。
 4  3  6.284    +20 43 25.32   1.0125655    15 49.27     23.4378669

Moonの視位置

     赤経            赤緯         H.P.        視半径
  h  m  s          。 ,                        ,  ,,
23 23 53.038    - 9  4 32.02   0.9561266     15 37.92

金星

Venusの視位置

     赤経            赤緯       地心距離     視半径      黄道傾斜角
  h  m  s          。 ,               AU      ,  ,,        。
 1 34  4.675    + 7 41 57.77   1.1649751     0  7.12     23.4378669

火星

Marsの視位置

     赤経            赤緯       地心距離     視半径      黄道傾斜角
  h  m  s          。 ,               AU      ,  ,,        。
 0  0  3.800    - 1 51 22.71   1.5005738     0  3.12     23.4378669

木星

Jupiterの視位置

     赤経            赤緯       地心距離     視半径      黄道傾斜角
  h  m  s          。 ,               AU      ,  ,,        。
 0 10 38.521    - 0  5 17.56   5.3888037     0 17.09     23.4378669

土星

Saturnの視位置

     赤経            赤緯       地心距離     視半径      黄道傾斜角
  h  m  s          。 ,               AU      ,  ,,        。
21 51  9.696    -14 10  5.64   9.7020342     0  7.61     23.4378669