Fit Radial Velocity and Astrometry

You can use Octofitter to jointly fit relative astrometry data and radial velocity data. Below is an example. For more information on these functions, see previous guides.

Import required packages

using Octofitter
using OctofitterRadialVelocity
using CairoMakie
using PairPlots
using Distributions
using PlanetOrbits

We now use PlanetOrbits.jl to create sample data. We start with a template orbit and record it's positon and velocity at a few epochs.

orb_template = orbit(
    a = 1.0,
    e = 0.7,
    i= pi/4,
    Ω = 0.1,
    ω = 1π/4,
    M = 1.0,
    plx=100.0,
    m =0,
    tp =58829-40
)
Makie.lines(orb_template,axis=(;autolimitaspect=1))
Example block output

Sample position and store as relative astrometry measurements:

epochs = [58849,58852,58858,58890]
astrom = PlanetRelAstromLikelihood(Table(
    epoch=epochs,
    ra=raoff.(orb_template, epochs),
    dec=decoff.(orb_template, epochs),
    σ_ra=fill(1.0, size(epochs)),
    σ_dec=fill(1.0, size(epochs)),
))
PlanetRelAstromLikelihood Table with 5 columns and 4 rows:
     epoch  ra        dec       σ_ra  σ_dec
   ┌───────────────────────────────────────
 1 │ 58849  -18.3017  -108.907  1.0   1.0
 2 │ 58852  -21.1181  -111.432  1.0   1.0
 3 │ 58858  -26.6349  -115.889  1.0   1.0
 4 │ 58890  -53.1334  -129.043  1.0   1.0

And plot our simulated astrometry measurments:

fig = Makie.lines(orb_template,axis=(;autolimitaspect=1))
Makie.scatter!(astrom.table.ra, astrom.table.dec)
fig
Example block output

Generate a simulated RV curve from the same orbit:

using Random
Random.seed!(1)

epochs = 58849 .+ range(0,step=1.5, length=20)
planet_sim_mass = 0.001 # solar masses here


rvlike = MarginalizedStarAbsoluteRVLikelihood(
    Table(
        epoch=epochs,
        rv=radvel.(orb_template, epochs, planet_sim_mass) .+ 150,
        σ_rv=fill(5.0, size(epochs)),
    ),
    jitter=:jitter1,
    instrument_name="inst1"
)

epochs = 58949 .+ range(0,step=1.5, length=20)

rvlike2 = MarginalizedStarAbsoluteRVLikelihood(
    Table(
        epoch=epochs,
        rv=radvel.(orb_template, epochs, planet_sim_mass) .- 150,
        σ_rv=fill(5.0, size(epochs)),
    ),
    jitter=:jitter1,
    instrument_name="inst2"
)

fap = Makie.scatter(rvlike.table.epoch[:], rvlike.table.rv[:])
Makie.scatter!(rvlike2.table.epoch[:], rvlike2.table.rv[:])
fap
Example block output

Now specify model and fit it:

@planet b Visual{KepOrbit} begin
    e ~ Uniform(0,0.999999)
    a ~ truncated(Normal(1, 1),lower=0.1)
    mass ~ truncated(Normal(1, 1), lower=0.)
    i ~ Sine()
    Ω ~ UniformCircular()
    ω ~ UniformCircular()
    θ ~ UniformCircular()
    tp = θ_at_epoch_to_tperi(system,b,58849.0)  # reference epoch for θ. Choose an MJD date near your data.
end astrom

@system test begin
    M ~ truncated(Normal(1, 0.04),lower=0.1) # (Baines & Armstrong 2011).
    plx = 100.0
    jitter1 ~ truncated(Normal(0,10),lower=0)
end rvlike rvlike2 b

model = Octofitter.LogDensityModel(test)

using Random
rng = Xoshiro(0) # seed the random number generator for reproducible results

results = octofit(rng, model, max_depth=9, adaptation=300, iterations=400)
Chains MCMC chain (400×30×1 Array{Float64, 3}):

Iterations        = 1:1:400
Number of chains  = 1
Samples per chain = 400
Wall duration     = 5.06 seconds
Compute duration  = 5.06 seconds
parameters        = M, jitter1, plx, b_e, b_a, b_mass, b_i, b_Ωy, b_Ωx, b_ωy, b_ωx, b_θy, b_θx, b_Ω, b_ω, b_θ, b_tp
internals         = n_steps, is_accept, acceptance_rate, hamiltonian_energy, hamiltonian_energy_error, max_hamiltonian_energy_error, tree_depth, numerical_error, step_size, nom_step_size, is_adapt, loglike, logpost, tree_depth, numerical_error

Summary Statistics
  parameters         mean        std       mcse   ess_bulk   ess_tail      rha ⋯
      Symbol      Float64    Float64    Float64    Float64    Float64   Float6 ⋯

           M       0.9980     0.0344     0.0029   140.8501   141.8130    1.060 ⋯
     jitter1       0.3978     0.3506     0.0372   122.2376   150.0601    1.129 ⋯
         plx     100.0000     0.0000        NaN        NaN        NaN       Na ⋯
         b_e       0.2124     0.1683     0.1387     1.7236    21.3676    1.648 ⋯
         b_a       1.6877     0.4728     0.2844     2.5675    34.2740    1.346 ⋯
      b_mass       1.0804     0.6152     0.1825     8.3551    28.3530    1.101 ⋯
         b_i       1.1418     0.0841     0.0617     2.3690    17.9170    1.395 ⋯
        b_Ωy      -0.7224     0.1113     0.0184    40.0639    61.2438    1.113 ⋯
        b_Ωx      -0.7043     0.0988     0.0339     8.3159    73.3527    1.152 ⋯
        b_ωy      -0.2579     0.7626     0.5505     2.4402    46.4968    1.403 ⋯
        b_ωx       0.3651     0.5004     0.0763    52.7406    57.7689    1.381 ⋯
        b_θy      -0.9621     0.0845     0.0105    69.8198   154.9883    1.016 ⋯
        b_θx      -0.1624     0.0145     0.0013   112.9723   181.9498    1.132 ⋯
         b_Ω      -2.3678     0.1174     0.0323    13.3347    64.4314    1.121 ⋯
         b_ω       1.5183     1.4815     1.0531     2.0058   130.5647    1.512 ⋯
         b_θ      -2.9742     0.0056     0.0009    38.9323    84.7630    1.023 ⋯
        b_tp   58414.5495   344.4624   206.8557     4.4497    28.3333    1.200 ⋯
                                                               2 columns omitted

Quantiles
  parameters         2.5%        25.0%        50.0%        75.0%        97.5%
      Symbol      Float64      Float64      Float64      Float64      Float64

           M       0.9309       0.9822       0.9950       1.0173       1.0700
     jitter1       0.0163       0.1908       0.2674       0.5425       1.3958
         plx     100.0000     100.0000     100.0000     100.0000     100.0000
         b_e       0.0026       0.0656       0.1509       0.3922       0.5052
         b_a       1.1107       1.2274       1.6192       1.9671       2.6967
      b_mass       0.0662       0.6536       1.0328       1.4675       2.1889
         b_i       1.0157       1.0374       1.1649       1.2068       1.2755
        b_Ωy      -0.9750      -0.7839      -0.7084      -0.6618      -0.5248
        b_Ωx      -0.9044      -0.7477      -0.7182      -0.6447      -0.4934
        b_ωy      -1.0753      -0.8903      -0.7264       0.4727       1.0898
        b_ωx      -0.9741       0.2861       0.3939       0.6595       1.0637
        b_θy      -1.1618      -1.0114      -0.9594      -0.9132      -0.8109
        b_θx      -0.1965      -0.1704      -0.1614      -0.1541      -0.1365
         b_Ω      -2.6156      -2.4350      -2.3562      -2.2966      -2.1440
         b_ω      -2.1649       0.4877       2.2542       2.7343       2.9034
         b_θ      -2.9864      -2.9778      -2.9738      -2.9696      -2.9647
        b_tp   57559.8493   58222.8478   58536.6641   58697.0249   58791.5400

Display results as a corner plot:

octocorner(model,results, small=true)
Example block output

Plot RV curve, phase folded curve, and binned residuals:

Octofitter.rvpostplot(model, results)
Example block output

Display RV, PMA, astrometry, relative separation, position angle, and 3D projected views:

octoplot(model, results)
Example block output