天体の位置計算 – 共通サブルーチン

「天体の位置計算 増補版」で使用する共通サブルーチンを掲載します。グリニッジ平均恒星時や固有運動といった部分については、その都度紹介していきますが、時分秒から角度、象限、ベッセル年初からの経過年数などは、よく使われるので共通サブルーチンの中に組み入れました。一部のサブルーチンを「マイコン宇宙講座」からFortranに書き換えたものを使用しています。

サブルーチンは、関数として宣言し直しましたので、コンパイル時には、注意が必要です。また、今後は共通サブルーチンに追加していく形になります。

コンパイル

コンパイルすると、pcc_lib.oとpcclib.modファイルが作成されます。コンパイルは新しく追加するたびに行ってください。エラーなどでコンパイル失敗すると、すでにpcclib.modがあると削除されますので、注意してください。削除された場合は、再度コンパイルして作成します。

gfortran -c pcc_lib.f90

共通サブルーチン pcc_lib.f90

module pcclib
    implicit none
contains
    function Frc(x) result(val)
    ! 小数部を返す

        double precision, intent(in) :: x
        double precision :: val

        val = x - int(x);
    end Function Frc

    function Mla(x) result(val)
    ! 360°の整数倍を返す
    
        double precision, parameter :: PI = 3.141592653589793238462643d0
        double precision, parameter :: PI2 = 6.283185307179586476925287d0

        double precision, intent(in) :: x
        double precision :: val

        val = PI2 * (x / 360d0 - int(x / 360d0));
    end function Mla

    function Mla2(x) result(val)
    ! 360°の整数倍を返す

        double precision, intent(in) :: x
        double precision :: val

        val = 360d0 * frc(x / 360d0)
        if (val < 0) then
            val = val + 360d0;
        end if
    end function Mla2

    function Sgn(x) result(flg)
    ! 正負の符号を返す

        double precision, intent(in) :: x
        integer ::  flg

        flg = 1
        if (x < 0) then
            flg = -1
        end if
    end function Sgn

    function hms2deg(rh, rm, rs) result(deg)
    ! 時分秒を角度に換算して返す

        double precision, intent(in) :: rh, rm, rs
        double precision :: deg

        deg = 15.0d0 * (abs(rh) + rm / 60d0 +rs / 3600d0)
    end function hms2deg

    function dms2deg(dh, dm, ds) result(deg)
    ! 度分秒を角度に換算して返す

        double precision, intent(in) :: dh, dm, ds
        double precision :: deg

        deg = Sgn(dh) * (abs(dh) + dm / 60d0 + ds / 3600d0)
    end function dms2deg

    function deg2hms(deg) result(ra)
    ! 角度から時分秒を返す

        double precision, intent(in) :: deg
        double precision :: degree
        double precision :: rh, rm, rs, ra(3)

        degree = abs(deg) / 15.0d0
        rh = int(degree)
        rs = 60.0d0 * (degree - int(degree))
        rm = int(rs)
        rs = 60.0d0 * (rs-rm)

        ra(1) = rh
        ra(2) = rm
        ra(3) = rs
    end function deg2hms

    function deg2dms(degree) result(dc)
    ! 角度から度分秒を返す

        double precision, intent(in) :: degree
        double precision :: dh, dm, ds, dc(3)
        integer :: sg

        sg = Sgn(degree)
        dh = int(abs(degree))
        ds = 60.0d0 * (abs(degree) - int(abs(degree)))
        dm = int(ds)
        ds = 60.0d0 * (ds-dm)

        dc(1) = sg * dh
        dc(2) = dm
        dc(3) = ds
    end function deg2dms

    function deg2rad(x) result(radian)
    ! 角度をラジアンに換算する

        double precision, parameter :: PI = 3.141592653589793238462643d0
        double precision, parameter :: RAD = 180d0 / PI
    
        double precision, intent(in) :: x
        double precision :: radian

        radian = x / RAD
    end function deg2rad

    function rad2deg(x) result(degree)
    ! ラジアンを角度に換算する

        double precision, parameter :: PI = 3.141592653589793238462643d0
        double precision, parameter :: RAD = 180d0 / PI
    
        double precision, intent(in) :: x
        double precision :: degree

        degree = x * RAD
    end function rad2deg

    function Quadrant(ss, cc) result(tt)
    ! 象限の判断 
    !「マイコン宇宙講座」79頁 リスト3-13

        double precision, parameter :: PI = 3.141592653589793238462643d0
        double precision, parameter :: PI2 = 6.283185307179586476925287d0

        double precision, intent(in) :: ss, cc
        double precision :: tt

        tt = atan(ss / cc)

        if (cc < 0) then
            tt = tt + PI
        else if (ss < 0) then
                tt = tt + PI2
        end if
    end function Quadrant  
    
    function ModifiedJulianDay(year, month, day, hour, minute, second) result(mjd)
    ! 修正ユリウス日

        double precision, intent(in) :: year, month, day, hour, minute, second

        double precision :: jd, mjd

        jd = JulianDay(year, month, day)
        jd = jd + (hour / 24d0 + minute / 1440d0 + second / 86400d0)
        jd = jd - 0.375d0
        mjd = jd - 2400000.5d0
    end function ModifiedJulianDay

    function JulianDay(year, month, day) result(julian)
    ! ユリウス日(0 UTC) 
    !「マイコン天文学Ⅰ」20-22頁

        double precision, intent(in) :: year, month, day

        double precision :: julian
        double precision :: yy, mm, dd, branch

        yy = year
        mm = month
        dd = day

        branch = yy + (mm - 1d0) / 12d0 + dd / 365.25d0

        if (int(mm) < 3d0) then
            mm = mm + 12d0
            yy = yy - 1d0
        end if

        if (branch >= 1582.78d0) then
            julian = int(yy * 365.25d0) + int(yy / 400d0) - int(yy / 100d0) + int(30.59d0 * (mm - 2d0)) + dd + 1721088.5d0
        else if (branch >= 0d0) then
            julian = int(yy * 365.25d0) + int(30.59d0 * (mm - 2d0)) + dd + 1721086.5d0
        else if (year < 0d0) then
            julian = Sgn(year) * int(abs(yy) * 365.25d0) + int(30.59d0 * (mm - 2d0)) + dd + 1721085.5d0
        end if
    end function JulianDay

    function Julian2date(julian) result(dt)
    ! ユリウス日から年月日
    ! 「マイコン宇宙講座」サブルーチン JDATE リスト2-2

        integer, dimension(1:12) :: T = (/31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31/)

        double precision, intent(in) :: julian
        double precision :: dt(3), year, month, day
        double precision :: jj, jd, r1, r2
        integer :: m

        jj = julian - 2400000.5d0
        year = int(2.7379093d-03 * (julian - 2400000.5d0) + 1858.877d0)
        month = 1.0d0
        day = 0.0d0

        jd = JulianDay(year, month, day)

        r2 = jj - (jd - 2400000.5d0)
        if (mod(year, 4d0) == 0d0 .and. mod(year, 100d0) /= 0d0 .or. mod(year, 400d0) == 0d0) then
            T(2) = 29
        end if

        r1 = 0d0
        m = 1
        do while (m < 13)
            if (int(r2) - r1 - T(m) <= 0) then
                exit
            end if
            r1 = r1 + T(m)
            m = m + 1
        end do

        month = m
        day = r2 - r1
        T(2) = 28
    
        if (month == 13d0) then
            year = year + 1d0
            month = month - 12d0
        end if

        dt(1) = year
        dt(2) = month
        dt(3) = day
    end function Julian2date

    function BesselianYear(julian) result(t)
        ! 1950のベッセル年初からの経過日数
        ! 「マイコン宇宙講座」31頁 式(2.3.1)
    
        double precision, parameter :: JDBEPOCH = 2433282.42346d0
    
        double precision, intent(in) :: julian
        double precision :: t
    
        t = julian - JDBEPOCH
        t = t * (0.00002737909288d0 + 1.25013d-17 * t)
    end function BesselianYear

    ! ここに新しい関数(サブルーチン)を記述する
    ! end module pcclibより後ろに記述しないこと!

end module pcclib