2022-05-27

How to compare two double precision real numbers in Fortran?

I wrote a Fortran subroutine to compute the time of flight(TOF) between two points on elliptical orbit. Obviously this TOF has to be a positive number. I tested my subroutine with different data but in some cases I get negative result despite of I coded a possible way to solve this problem.

Here is my subroutine:

!*************************************************************
    subroutine TOF_between_2TA(e,xn,theta1,theta2,delta_t)
!*************************************************************
!  Compute time of flight bewteen two points (point 1 and point 2) on elliptical orbits.
!*************************************************************
!  Input:
!  xn     = mean motion, any units
!  e      = eccentricity
!  theta1 = true anomaly of first point, in interval [0, twopi]
!  theta2 = true anomaly of second point, in interval [0, twopi]
!
!  Output:
!  delta_t = time of flight between two points (same units as given by xn)
!*************************************************************
 
       
        implicit none

        ! Arguments
        double precision, intent(in)  :: e,xn,theta1,theta2
        double precision, intent(out) :: delta_t

        ! Locals
        integer :: i
        double precision               :: xe,sxe,cxe,cth,sth,den,theta
        double precision, dimension(2) :: theta_vec,xm_vec
        
        !! To get positive time intervals, theta_vec must be sorted in ascending order  
        if (theta1 < theta2) then     
           theta_vec = [theta1, theta2]   ! Case theta1 < theta2
        elseif (theta2 < theta1) then 
           theta_vec = [theta2, theta1]  ! Case theta1 > theta2
        endif
        
        do i=1,2          
            theta = theta_vec(i)
            
            cth = cos(theta)
            sth = sin(theta)
            den = 1.0 + e*cth
            cxe = (e + cth)/den
            sxe = sqrt(1.0-e*e)*sth/den 
            xe = atan2(sxe,cxe)
        
            ! atan2 returns angles in interval -pi, +pi, we need angles in interval [0,2pi]
            xe = mod(xe,twopi)
            if (xe .lt. 0.0_pr) xe = xe + twopi 
        
            xm_vec(i) = xe - e*sxe         
            
        enddo
        
        delta_t= (xm_vec(2)-xm_vec(1)) / xn
        
        return
        
    end subroutine TOF_between_2TA

Can you suggest me a way to increase the robustness of my soubrutine and protect me against undesiderable result, i.e. negative numbers? I'm almost pretty sure that the problem is when I try to compare the vatiables theta1 and theta2, what is the smartest way to compare two real numbers?

Edit - After many tests, I report here the working routines:

!*************************************************************
    subroutine TOF_since_pericenter(e,xn,theta,delta_t_peri)
!*************************************************************
!  Time of Flight since pericenter: From true anomaly to time
!*************************************************************
!  Input:  
!  xn    = mean motion, any units
!  e     = eccentricity
!  theta = true anomaly, in interval [0, twopi]
!
!  Output:
!  delta_t_peri = time since pericenter (same units as given by xn)
!*************************************************************
 
        implicit none

        ! Arguments
        double precision, intent(in)  :: e,xn,theta
        double precision, intent(out) :: delta_t_peri

        ! Locals
        double precision :: xe,sxe,cxe,cth,sth,xm,den
        
        cth = cos(theta)
        sth = sin(theta)
        den = 1.d0 + e*cth
        cxe = (e + cth)/den
        sxe = sqrt(1.d0 - e*e)*sth/den 
        xe  = atan2(sxe,cxe)
        ! atan2 returns angles in interval [-pi, +pi], we need angles in interval [0,2pi]
        xe = mod(xe,twopi)
        if (xe .lt. 0.d0) xe = xe + twopi 
        
        xm = xe - e*sxe
        delta_t_peri = xm/xn
        
        return

    end subroutine ToF_since_pericenter
    
    
    
!*************************************************************
    subroutine TOF_between_2TA(e,xn,theta_1,theta_2,delta_t)
!*************************************************************
!  Compute time of flight required by point 1 to reach the point 2 on elliptical orbits.
!  The point 1 is the moving object and it rotates counterclockwise on its orbit 
!*************************************************************
!  Input:
!  xn        = mean motion, any units
!  e         = eccentricity
!  theta_1   = true anomaly of asteroid, in interval [0, twopi]
!  theta_2   = true anomaly of intersection point, in interval [0, twopi]
!
!  Output:
!  delta_t = time of flight between two points (same units as given by xn)
!*************************************************************
 
       
        implicit none

        ! Arguments
        double precision, intent(in)  :: e,xn,theta_1,theta_2
        double precision, intent(out) :: delta_t

        ! Locals
        integer :: i
        double precision               :: T,delta_t1_peri,delta_t2_peri
        double precision, parameter    :: small = 1.d-30
        
        ! Compute orbital period
        T = twopi / xn
        
        call TOF_since_pericenter(e,xn,theta_1,delta_t1_peri)
        call TOF_since_pericenter(e,xn,theta_2,delta_t2_peri)
        
        delta_t = delta_t2_peri - delta_t1_peri
        
        if (delta_t .gt. small) then     
           delta_t = delta_t
        elseif (delta_t .lt. -small) then 
           delta_t = delta_t + T
        endif
           
        return
        
    end subroutine TOF_between_2TA
 
!*************************************************************

Further comments and improvment suggestions are well accepted.



No comments:

Post a Comment