#!/usr/bin/env ruby
#      19/Apr/2004         by Yoshiki Tsunesada
#
#   This is an example to calculate the orbital evolution of
# a double neutron star (binary) system. General relativity predicts 
# that the binary orbital decays by radiating gravitational waves, 
# and the two stars will coalesce in time scale of 100-1000 Mega-years. 
#   The values used here are of the binary system J0730-3039 discovered 
# in 2003 (Burgay et al., Nature 2003). The result shows that the two 
# neutron stars will merge after about 83 Mega-years. From the age of 
# the system 100 Mega-year, the lifetime of the system is estimated 
# about 183 Mega-years.
#
# References:
#   1. Burgay et al., Nature 426, 531 (2003)
#   2. Shapiro & Teukolsky, "Black holes, white dwarfs and neutron stars"
#        John Wiley and Sans (1983)
#
require("gnuplot")
require("gsl")
include Math

class BinarySystem
  def initialize(m1, m2)
    @m1 = m1
    @m2 = m2
  end
  attr_reader :m1
  attr_reader :m2
end

GMsolarC3 = 4.925490947e-6
MegaYear = 3600*24*365*1e6

# Time evolution of the binary orbital period and the eccentricity
# due to gravitational radiation. 
# The calculation is based on general relativity (See e.g. Ref.2).
#     y[0]: orbital period (pb)
#     y[1]: eccentricity (e)
#  dydt[0]: time derivative of pb
#  dydt[1]: time derivative of e

deriv = Proc.new { |t, y, dydt, binary|
  pb = y[0]            # orbital period
  e = y[1]             # eccentricity
  m1 = binary.m1       # neutron star masses
  m2 = binary.m2
  totalM = m1 + m2     # total mass                           
  mu = m1*m2/totalM    # reduced mass
  mm = mu*pow(totalM, 2.0/3.0)
  f_e = pow(1.0 - e*e, -3.5)*(1.0 + (73.0/24.0 + 37.0/96.0*e*e)*e*e);
  h_e = (1.0 + 121.0/304.0*e*e)*pow(1.0 - e*e, -2.5)
  tmp = pow(GMsolarC3*2.0*PI/pb, 5.0/3.0)
  dydt[0] = -192.0*PI/5.0*f_e*tmp*mm              # dP/dt
  dydt[1] = -304.0/15.0*e*h_e*tmp*(2.0*PI/pb)     # de/dt
}

# Neutron star masses in solar-mass unit.
# The values are of the binary system J0730-3039 discoverd in 2003.
# See Burgay et al., Nature 426, 531 (2003)
m1 = 1.35
m2 = 1.24
binary = BinarySystem.new(m1, m2)

# Initial data: the present values
pb = 2.4*3600        # orbital period: 2.4 hours at present
ecc = 0.008          # eccentricity
y = GSL::Vector[pb, ecc]

# ODE solver using RKF45 algorithm
solver = Odeiv::Solver.new(Odeiv::Step::RKF45, [1e-6, 0.0], deriv, 2)
solver.set_params(binary)

# the age of the binary system from birth
t = 100*MegaYear
tend = 1000*MegaYear

# initial time step
h = 1.0*MegaYear

vtime = []
vperiod = []
vecc = []
while t < tend 
  t, h, status = solver.apply(t, tend, h, y)
  break if status != GSL::SUCCESS
  break if isnan?(y[0])
  vtime << t/MegaYear
  vperiod << y[0]/3600
  vecc << y[1]
end

Gnuplot.open do |gp|
  Gnuplot::Plot.new(gp) do |plot|
    plot.set("title", "Orbital decay of the binary system J0730-3039")
    plot.set("xrange", "[90:200]")
    plot.set("yrange", "[1e-2:10]")
    plot.set("y2range", "[1e-4:1e-2]")
    plot.set("ytics", "nomirror")
    plot.set("y2tics")
    plot.set("xlabel", "Time since birth [Myr]")
    plot.set("ylabel", "Orbital Period [Hr]")
    plot.set("y2label", "Eccentricity")
    plot.set("grid")
    plot.set("logscale", "y")
    plot.set("logscale", "y2")
    plot.set("pointsize", "1")
    plot.set("label", "1 'Present' at first 96, 0.04")
    plot.set("label", "2 'Plunge!' at first 150, 0.04")
    plot.set("arrow", "from 100,0.03 to 100,0.013 lw 2 lt 3")
    plot.set("arrow", "from 160, 0.035 to 182, 0.011 lw 2 lt 4")
    plot.data = [
      Gnuplot::DataSet.new( [vtime, vperiod]) { |ds|
        ds.title = "Orbital period"
        ds.with = "lp"
      },
      Gnuplot::DataSet.new( [vtime, vecc]) { |ds|
        ds.title = "Eccentricity"
        ds.with = "lp"
        ds.axes = "x1y2"
      }
    ]
  end
end

__END__


