├── .DS_Store ├── .gitattributes ├── .ipynb_checkpoints ├── Distance and tangential velocity inference-checkpoint.ipynb ├── Distance inference - multiple sources-checkpoint.ipynb └── Distance inference - single source-checkpoint.ipynb ├── Distance and tangential velocity inference.ipynb ├── Distance inference - multiple sources.ipynb ├── Distance inference - single source.ipynb ├── README.md ├── Rcode ├── 3Ddistvel_functions.R ├── constants.R ├── distance_functions.R ├── emcee.R ├── general_functions.R └── metropolis.R ├── data ├── .DS_Store ├── gdr1set01.csv ├── gdr1set02.csv └── gdr1set03.csv ├── install.R ├── resources ├── 3D_astrometry_inference.pdf └── cluster_inference.pdf └── runtime.txt /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bailer-jones/parallax-tutorial-2018/67a26bcf78321088559eaea4e604ba88d1116986/.DS_Store -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Parallax tutorial 2018 2 | 3 | Coryn Bailer-Jones, MPIA Heidelberg (https://mpia.de/homes/calj) 4 | 5 | This tutorial concerns inferring distances and velocities from parallaxes and proper motions using the Bayesian approach. It uses R codes in jupyter notebooks, together with simulated data and data from Gaia-DR1 (TGAS). The tutorial is divided into three parts, each with its own notebook: 6 | 7 | 1. Inference of distance to a single source using its parallax. Includes: simple hierarchical model. 8 | 2. Inference of distance to and size of a cluster using parallax and positions of its members. Includes: naive parallax combination; accommodating correlated measurements; 2D cluster model. See [resources/cluster_inference.pdf](resources/cluster_inference.pdf) for details. 9 | 3. Inference of distance to and 2D tangential velocity on the sky of a single source using its parallax and proper motion. Includes: explicit use of MCMC to sample the posterior. See [resources/3D_astrometry_inference.pdf](resources/3D_astrometry_inference.pdf) for details. 10 | 11 | The more generic functions used the tutorials are in the files in the Rcode/ directory. 12 | 13 | These tutorials assume that you are familiar with the basic idea of Bayesian inference, and inferring a distance given a parallax and a prior, as described in [Bailer-Jones 2015 (paper 1)](http://adsabs.harvard.edu/abs/2015PASP..127..994B). Additional resources and references are provided below. You should do tutorial 1 before tackling 2 or 3. 14 | 15 | The purpose of these tutorials is just to show how to work with astrometric data in inference problems. Sometimes you will have other relevant information (e.g. colour and apparent magnitude) which can also be used to help infer the distance. And sometimes you won't want to infer a distance at all (e.g. as an intermediate measure; or if you are doing model fitting, which is probably better done in the parallax space where the measurement model is simpler). 16 | 17 | Resources and further information: 18 | * [Cluster distance inference](resources/cluster_inference.pdf) 19 | * [Joint inference from parallax and proper motions (CBJ-081)](resources/3D_astrometry_inference.pdf) 20 | * [Bailer-Jones 2015 (paper 1)](http://adsabs.harvard.edu/abs/2015PASP..127..994B) 21 | * [Astraatmadja & Bailer-Jones 2016a (paper 2)](http://adsabs.harvard.edu/abs/2016ApJ...832..137A) 22 | * [Astraatmadja & Bailer-Jones 2016b (paper 3)](http://adsabs.harvard.edu/abs/2016ApJ...833..119A) 23 | * [Bailer-Jones et al. 2018 (paper 4)](http://www.mpia.de/homes/calj/gdr2_distances.html) 24 | * [Gaia Data Release 1](http://adsabs.harvard.edu/abs/2016A%26A...595A...2G) 25 | * [Luri et al. 2018 (tutorial on the use of parallaxes)](https://repos.cosmos.esa.int/socci/projects/GAIA/repos/astrometry-inference-tutorials/browse) 26 | * [Practical Bayesian Inference (PBI)](http://www.cambridge.org/de/academic/subjects/physics/mathematical-methods/practical-bayesian-inference-primer-physical-scientists?format=PB) 27 | 28 | You can also run this code interactively using Binder: [![Binder](https://mybinder.org/badge.svg)](https://mybinder.org/v2/gh/ehalley/parallax-tutorial-2018/master) 29 | -------------------------------------------------------------------------------- /Rcode/3Ddistvel_functions.R: -------------------------------------------------------------------------------- 1 | # CBJ November 2017 (Coryn Bailer-Jones, calj@mpia.de) 2 | # Functions for converting astrometry to phase space 3 | 4 | # source("./metropolis.R") 5 | 6 | library(mvtnorm) 7 | source("constants.R") # only need kf 8 | 9 | # Data model: 10 | # 3D astrometry (astro3d) = c(parallax, pmra, pmdec) in (mas, mas/yr, mas/yr) 11 | # 3D phase space (phase3d) = c(r, v, phi) in (pc, km/s, radians) 12 | # r is distance, v is tangential speed, phi is position angle from North to East 13 | # astro3dCov is 3x3 covariance matrix of astro3d in same units (e.g. made by cov.astro3d) 14 | # rlen is length scale of distance prior; vtmax is maximum tangential speed (parameter of speed prior) 15 | # astromdat: matrix with named columns, from which we require: 16 | # - astro3d 17 | # - standard deviations in astro3d as well as their corresponding correlations. 18 | # (name of which are given in cov.astro3d() below). 19 | 20 | # Transform given astro3d to phase3d 21 | astro3d.to.phase3d <- function(astro3d) { 22 | dist <- 1e3/astro3d[1] 23 | speed <- kf*sqrt(astro3d[2]^2 + astro3d[3]^2)/astro3d[1] 24 | phi <- atan(astro3d[2]/astro3d[3]) # to range -pi/2 to +pi/2 25 | if(astro3d[3]<0) { # quadrant correction, and put in range -pi to +pi 26 | phi <- ifelse(phi<0, phi+pi, phi-pi) 27 | } 28 | return(as.vector(c(dist, speed, phi))) # as.vector to get rid of names 29 | } 30 | 31 | # Evaluate Jacobian matrix |d_phase3d / d_astro3d| at a given astro3d 32 | jac.phase3d.astro3d <- function (astro3d) { 33 | musq <- astro3d[2]^2 + astro3d[3]^2 34 | mu <- sqrt(musq) 35 | J <- matrix(data=c(-1e3/astro3d[1]^2, 0, 0, 36 | -kf*mu/astro3d[1]^2, kf*astro3d[2]/(mu*astro3d[1]), kf*astro3d[3]/(mu*astro3d[1]), 37 | 0, astro3d[3]/musq, -astro3d[2]/musq), 38 | nrow=3, ncol=3, byrow=TRUE) 39 | return(J) 40 | } 41 | 42 | # Make covariance matrix for astro3d from astromdat 43 | cov.astro3d <- function(astromdat) { 44 | # V is upper diagonal of covariance matrix 45 | V <- matrix(data=c(0, 46 | astromdat["parallax_error"]*astromdat["pmra_error"]*astromdat["parallax_pmra_corr"], 47 | astromdat["parallax_error"]*astromdat["pmdec_error"]*astromdat["parallax_pmdec_corr"], 48 | 0, 0, 49 | astromdat["pmra_error"]*astromdat["pmdec_error"]*astromdat["pmra_pmdec_corr"], 50 | 0, 0, 0), 51 | nrow=3, ncol=3, byrow=TRUE) 52 | S <- diag(astromdat[c("parallax_error", "pmra_error", "pmdec_error")])^2 # variances! 53 | return(t(V) + S + V) 54 | } 55 | 56 | # Return log10 (normalized) likelihood: P(3D astrometry | 3D phase space, Covariance) 57 | loglike.astro3d <- function(phase3d, astro3d, astro3dCov) { 58 | a <- phase3d[2]/(kf*phase3d[1]) 59 | pred <- 1e3*c(1/phase3d[1], a*sin(phase3d[3]), a*cos(phase3d[3])) 60 | return( (1/log(10))*dmvnorm(x=astro3d, mean=pred, sigma=astro3dCov, log=TRUE) ) 61 | } 62 | 63 | # Return log10 (unnormalized) prior: P(3D phase space | rlen, vtmax) 64 | logprior.phase3d <- function(phase3d, rlen, vtmax) { 65 | distPrior <- ifelse(phase3d[1]>0, (1/(2*rlen^3))*phase3d[1]^2*exp(-phase3d[1]/rlen), 0) 66 | speedPrior <- dbeta(phase3d[2]/vtmax, shape1=2, shape2=3) 67 | anglePrior <- 1 68 | logPrior <- sum( log10(distPrior), log10(speedPrior), log10(anglePrior) ) 69 | return(logPrior) 70 | } 71 | 72 | # Return log10 (unnormalized) posterior: P(3D phase space | 3D astrometry, Covariance, rlen, vtmax) 73 | logpost.astro3d <- function(phase3d, astro3d, astro3dCov, rlen, vtmax) { 74 | logprior <- logprior.phase3d(phase3d, rlen, vtmax) 75 | if(is.finite(logprior)) { # only evaluate model if parameters are sensible 76 | return( c(logprior, loglike.astro3d(phase3d, astro3d, astro3dCov)) ) 77 | } else { 78 | return( c(-Inf, -Inf) ) 79 | } 80 | } 81 | 82 | # Initialize walkers for emcee by drawing Nwalker numbers independently for the 83 | # three parameters from narrow distributions which respect boundary conditions of priors. 84 | # Return as Nwalker x 3 matrix 85 | init.phase3d <- function(Nwalker, phase3d, vtmax) { 86 | distwidth <- 10 87 | if(phase3d[1]vtmax-speedwidth/2) { 97 | speed <- runif(Nwalker, min=vtmax-speedwidth, max=vtmax) 98 | } 99 | if(phase3d[2]>=speedwidth/2 && phase3d[2]<=vtmax-speedwidth/2) { 100 | speed <- runif(Nwalker, min=phase3d[2]-speedwidth/2, max=phase3d[2]+speedwidth/2) 101 | } 102 | anglewidth <- 10 103 | angle <- runif(Nwalker, min=phase3d[3]-anglewidth/2, max=phase3d[3]+anglewidth/2) 104 | return( cbind(dist, speed, angle) ) 105 | } 106 | 107 | # Given a vector of angles (radian), return the same folded to either: 108 | # range 0 to 2pi, or 109 | # range -pi to +pi if this gives a range less than pi (i.e. is a smaller range) 110 | fold.angular.vector <- function(inphi) { 111 | alphi <- inphi %% (2*pi) # alphi has range 0 to 2pi 112 | bephi <- alphi 113 | sel <- alphi>pi 114 | bephi[sel] <- alphi[sel]-2*pi # bephi has range -pi to +pi 115 | if(diff(range(bephi)) radians 6 | km <- 1e3 # km in SI (m) 7 | 8 | # physical constants 9 | #G <- 6.67428e-11 # gravitational constant 10 | 11 | # solar system constants 12 | sgp <- 1.32712440018e20 # standard gravitational constant in SI (G*Msun) 13 | yr <- 365.25*24*3600 # length of Julian year in SI (s). Tropical year is 365.242190 days 14 | au <- 1.495978701e11 # AU in SI (m) (Hipparcos catalogue documentation p. 25, Table 1.2.2) 15 | pc <- (3600*180/pi)*au # parsec in SI (m) [3.085678e+16] 16 | kf <- au/(yr*km) # 1 AU/yr in km/s. Units: km s^-1 yr [4.740471] 17 | # converts proper motion of 1as/yr at 1pc to velocity in km/s 18 | # year unit here must be same as in PMs 19 | 20 | # Galactic coordinate system constants (l is Galactic longitude) 21 | # theta0, raNGP, decNGP uniquely define the equatorial to Galactic coordinate transformation. 22 | # With the Hipparcos values for these, the matrix trans in eq.to.gal() is equal the transpose 23 | # of the matrix A_G in the Hipparcos catalogue documentation p. 92, eqn. 1.5.11) to 10 dps.] 24 | theta0 <- 90+32.93192 # PA of NGP = l of north celestial pole = 90 + l_omega 25 | # l_omega = l of ascending node of Galactic plane on the equator of ICRS 26 | # (Hipparcos catalogue documentation p. 91, eqn. 1.5.10) (theta0=123 in B1950; Johnson & Soderblom 1987) 27 | raNGP <- 192.85948 # (Hipparcos catalogue documentation p. 91, eqn. 1.5.9) 28 | decNGP <- 27.12825 # (Hipparcos catalogue documentation p. 91, eqn. 1.5.9) 29 | -------------------------------------------------------------------------------- /Rcode/distance_functions.R: -------------------------------------------------------------------------------- 1 | # CBJ November 2017 (Coryn Bailer-Jones, calj@mpia.de) 2 | # Functions for distance and inference 3 | 4 | source("metropolis.R") # for quantiles.distpost3 5 | library(PolynomF) # for mode.distpost3 6 | library(mvtnorm) # for d.likemulti 7 | 8 | ##### Naming conventions 9 | 10 | # w - measured parallax, as 11 | # wsd - uncertainty in w 12 | # r - inferred distance, pc 13 | # rTrue - true distance, pc (if doing simulations) 14 | # fTrue - wsd/w (fractional parallax uncertainty) 15 | # rMean/rMedian/rMode - mean/median/mode of posterior 16 | # d.xxx - density of PDF xxx (normalized) 17 | # ud.xxx - density of PDF xxx (unnormalized) 18 | # r.xxx - random sample from PDF xxx 19 | # like - likelihood PDF 20 | # prior - prior PDF 21 | # post - posterior PDF 22 | # {} - in comments indicates a vector 23 | 24 | ##### General functions 25 | 26 | # Return 1 if rlo <= r <= rhi, otherwise zero. Vectorized in any one parameter. 27 | lim <- function(r, rlo, rhi) ifelse(rrhi, 0, 1) 28 | 29 | # Normalized Gaussian likelihood in w. Vectorized in any one parameter. 30 | d.like <- function(w, r, wsd) dnorm(x=w, mean=1/r, sd=wsd) 31 | 32 | ##### (1) uniform distance prior (between rlo and rhi) 33 | 34 | # Vectorized in any one parameter 35 | d.distprior1 <- function(r, rmax) lim(r, 0, rmax)*1/rmax 36 | r.distprior1 <- function(Nsamp, rmax) runif(Nsamp, min=0, max=rmax) 37 | 38 | # Vectorized in any one parameter 39 | ud.distpost1 <- function(r, w, wsd, rlo, rhi) { 40 | d.like(w, r, wsd)*lim(r, rlo, rhi) 41 | } 42 | 43 | 44 | ##### (2) uniform space density prior (between rlo and rhi) 45 | 46 | d.distprior2 <- function(r, rmax) lim(r, 0, rmax)*(3/rmax^3)*r^2 # Vectorized in r or rmax 47 | r.distprior2 <- function(Nsamp, rmax) { # Vectorized in Nsamp 48 | # Use rejection sampling. Expect 1/3 * Nsamp samples to be returned 49 | r1 <- runif(Nsamp, min=0, max=1) 50 | r2 <- runif(Nsamp, min=0, max=1) 51 | r <- rmax*r1[which(r2<=r1^2)] 52 | return(r) 53 | } 54 | 55 | # Vectorized in any one parameter 56 | ud.distpost2 <- function(r, w, wsd, rlo, rhi) { 57 | d.like(w, r, wsd)*lim(r, rlo, rhi)*r^2 58 | } 59 | 60 | # Define posterior function func() as required by metrop() 61 | func.distpost2 <- function(r, w, wsd, rmax) { 62 | return( c(log10(d.distprior2(r, rmax)), log10(d.like(w, r, wsd))) ) 63 | } 64 | 65 | # The mode of the posterior PDF is its smaller root; undefined when f>1/sqrt(8) (gives NaN) 66 | mode.distpost2 <- function(w, wsd) {(w/(4*wsd^2))*(1 - sqrt(1 - 8*(wsd/w)^2))} 67 | 68 | 69 | ##### (3) exponentially decreasing space density prior (with length scale rlen) 70 | 71 | # Vectorized in r or rlen 72 | d.distprior3 <- function(r, rlen) lim(r,0,Inf)*(1/(2*rlen^3))*r^2*exp(-r/rlen) 73 | 74 | # Cannot use rejection sampling as support of r is semi-infinite. So use MCMC. 75 | # Acceptance rate is around 0.7. I don't deal with correlations, so small Nsamp can and does 76 | # return some identical values. 77 | r.distprior3 <- function(Nsamp, rlen) { 78 | return(metrop(func=func.distprior3, thetaInit=rlen, Nburnin=50, 79 | Nsamp=Nsamp, sampleCov=2*rlen^2, verbose=Inf, rlen=rlen)[,3]) 80 | } 81 | # Test prior sampling by comparing the following 82 | # rlen <- 1e3 83 | # x=seq(from=1,to=(10*rlen),length.out=1e3); plot(x, x^2*exp(-x/rlen), type="l") 84 | # truehist(r.distprior3(1e5, rlen)) 85 | 86 | # Vectorized in any one parameter 87 | ud.distpost3 <- function(r, w, wsd, rlen) { 88 | d.like(w, r, wsd)*exp(-r/rlen)*r^2 89 | } 90 | 91 | # Define M=ud.distpost3(r=rMode) and F(r)=log(ud.distpost3(r) - log(M/2) 92 | # Function returns F(r) which we can use in a root finding algorithm to find r, 93 | # which will gives bound of FWHM. (If wanted x*Max instead of half*Max, 94 | # use x*M instead of M/2 in expression.) 95 | rootfunc.ud.distpost3 <- function(r, w, wsd, rlen, M) { 96 | #return(2*log(r) - r/rlen - (1/(2*wsd^2))*(w-1/r)^2 - log(wsd*M/2) - 0.5*log(2*pi)) 97 | return(log(ud.distpost3(r, w, wsd, rlen))-log(M/2)) 98 | } 99 | 100 | # Define func() as required by metrop() for prior and posterior sampling 101 | func.distprior3 <- function(r, rlen) { 102 | return( c(log10(d.distprior3(r, rlen)), 0) ) 103 | } 104 | func.distpost3 <- function(r, w, wsd, rlen) { 105 | return( c(log10(d.distprior3(r, rlen)), log10(d.like(w, r, wsd))) ) 106 | } 107 | 108 | # Return posterior mode - a single real number (or NA if something is wrong). 109 | # If retall=TRUE, return all three roots of derivative of PDF (default is FALSE). 110 | # Inputs: 111 | # w - parallax, unrestricted 112 | # wsd - parallax uncertainty, must be >0 113 | # rlen - prior length scale, must be >0 and one maxima. Take this as the mode. 116 | # 2. all three roots are real => two maxima. 117 | # if w>=0, take the smallest. 118 | # if w<0 take the positive one (there should be only one). 119 | mode.distpost3 <- function(w, wsd, rlen, retall=FALSE) { 120 | # special cases: 121 | # w<=0 works normally, except for w=-Inf 122 | if(w==-Inf) return(Inf) 123 | if(w==Inf) return(0) 124 | if(wsd==0) return(1/w) 125 | if(wsd==Inf) return(2*rlen) 126 | if(wsd<0) return(NA) # makes no sense 127 | if(rlen<=0) return(NA) # makes no sense 128 | r <- polynom() 129 | p <- r^3/rlen - 2*r^2 + (w/wsd^2)*r - 1/wsd^2 130 | roots <- solve(p) # complex vector of length 3, sorted by increasing size of real part 131 | rMode <- switch(EXPR = toString(length(which(Im(roots)==0))), 132 | "0" = NA, 133 | "1" = Re(roots[which(Im(roots)==0)]), 134 | "2" = NA, 135 | "3" = ifelse(w>0, min(roots), roots[roots>0]) # should be real and unique 136 | ) 137 | if(retall) { 138 | return(roots) 139 | } else { 140 | return(rMode) 141 | } 142 | } 143 | 144 | # Compute bounds of FWHM by root finding. Providing rMode avoids recalculating this. 145 | # rmax is maximum value of upper bound (needed for root finding) 146 | fwhm.distpost3 <- function(w, wsd, rMode=NA, rlen, rmax=1e6) { 147 | if(is.na(rMode)) { 148 | rMode <- mode.distpost3(w, wsd, rlen) 149 | } 150 | M <- ud.distpost3(r=rMode, w, wsd, rlen) 151 | lo <- uniroot(rootfunc.ud.distpost3, interval=c(0, rMode), 152 | w=w, wsd=wsd, rlen=rlen, M=M)$root 153 | hi <- uniroot(rootfunc.ud.distpost3, interval=c(rMode, rmax), 154 | w=w, wsd=wsd, rlen=rlen, M=M)$root 155 | return(c(lo=lo,hi=hi)) 156 | } 157 | 158 | # Return value(s) at quantile(s) specified by probs (default is just median) 159 | # Computed via MCMC, as integral appears to be non-analytic. 160 | # Both Metropolis and HybridMC are slow and sometimes inaccurate. 161 | # If diagnose=TRUE and MCMC is performed, plot histogram of samples (as well as 162 | # posterior PDF Z!=NA), report mid and final acceptance rates and step size. 163 | quantiles.distpost3 <- function(w, wsd, rlen, probs=0.5, Nsamp=1e5, diagnose=FALSE) { 164 | if(diagnose) {cat("Inputs:", w, wsd, rlen, probs, Nsamp, "\n")} 165 | if(wsd<=0) return(NA) # makes no sense 166 | if(rlen<=0) return(NA) # makes no sense 167 | rMode <- mode.distpost3(w, wsd, rlen) 168 | stepSize <- rMode # originally used rSD if it existed, otherwise rMode 169 | verbose <- ifelse(diagnose, Nsamp/2, Inf) 170 | samp <- metrop(func=func.distpost3, thetaInit=rMode, Nburnin=1e-3*Nsamp, Nsamp=Nsamp, 171 | sampleCov=stepSize^2, verbose=verbose, w=w, wsd=wsd, rlen=rlen)[,3] 172 | #samp <- as.vector(hybridMC(y.start=rMode, n.samp=Nsamp, logDens=logDens.post3, 173 | # dLogDens=dLogDens.post3, epsilon=0.1, LFsteps=1, 174 | # w=w, wsd=wsd, rlen=rlen)) 175 | if(diagnose) { 176 | cat("stepSize =", stepSize, "\n") 177 | truehist(samp) 178 | # need to compute normalization constant Z for the following 179 | # if may not exist (see original code) 180 | #Z <- Z.post3(w, wsd, rlen) 181 | #r <- seq(from=min(samp), to=max(samp), length.out=1e4) 182 | #lines(fac*r, d.post3(r, w, wsd, rlen, Z)) 183 | } 184 | return(quantile(samp, probs=probs)) 185 | } 186 | 187 | ##### (3b) - as (3), but with multiple stars and covariance 188 | 189 | # Return correlation coefficient between parallaxes for two 190 | # sources with specified sky positions 191 | # and amplitude amp (0-1) and length scale len (degrees) 192 | # using an exponential correlation model. 193 | # Note that this uses a simplified angular separation computation 194 | # which does not work for large separations or near the poles. 195 | parcor <- function(ra1, dec1, ra2, dec2, amp=0.5, len=0.25) { 196 | sep <- sqrt(((ra1-ra2)*cos(conv*0.5*(dec1+dec2)))^2 + (dec1-dec2)^2) 197 | return( amp*exp(-sep/len)) 198 | } 199 | 200 | # Return covariance matrix between parallaxes for all sources in 201 | # data frame dat, using correlation function parcor. 202 | parcovmat <- function(dat, amp, len) { 203 | V <- matrix(data=0, nrow=nrow(dat), ncol=nrow(dat)) 204 | for(i in 2:nrow(dat)) { 205 | for(j in 1:(i-1)) { 206 | V[i,j] <- dat$parallax_error[i]*dat$parallax_error[j] * 207 | parcor(ra1=dat$ra[i], dec1=dat$dec[i], 208 | ra2=dat$ra[j], dec2=dat$dec[j], amp=amp, len=len) 209 | V[j,i] <- V[i,j] 210 | } 211 | } 212 | return(V + diag(dat$parallax_error^2)) 213 | } 214 | 215 | # Return density of a normalized dim(w) dimensional Gaussian likelihood 216 | # in {w} with mean (1/r)*{1} and covariance matrix parcovmat. 217 | # w and wsd must be vectors of same size, and r a scalar. 218 | # If parcovmat=NULL, then assume product of dim(w) 1D Gaussians. 219 | d.likemulti <- function(w, r, wsd, parcovmat=NULL) { 220 | if(length(w)!=length(wsd)) stop("w and wsd must be same length") 221 | if(length(r)==1) { 222 | if(is.null(parcovmat)) { 223 | return(prod(dnorm(x=w, mean=1/r, sd=wsd))) 224 | } else { 225 | return(dmvnorm(x=w, mean=rep.int(1/r, length(w)), sigma=parcovmat)) 226 | } 227 | } else { 228 | like <- double(length(r)) 229 | for(i in 1:length(r)) { 230 | if(is.null(parcovmat)) { 231 | like[i] <- prod(dnorm(x=w, mean=1/r[i], sd=wsd)) 232 | } else { 233 | like[i] <- dmvnorm(x=w, mean=rep.int(1/r[i], length(w)), sigma=parcovmat) 234 | } 235 | } 236 | return(like) 237 | } 238 | } 239 | 240 | # Requires vector w and wsd, scalar rlen, and scalar or vector r. 241 | # Returns nonormalized posterior values for each r. 242 | ud.distpost3multi <- function(r, w, wsd, parcovmat=NULL, rlen) { 243 | d.likemulti(w, r, wsd, parcovmat)*exp(-r/rlen)*r^2 244 | } 245 | 246 | ##### Likelihood for multiple stars and finite cluster size (no correlations) 247 | 248 | # The functions below compute the product of N 1-dimensional integrals, 249 | # each integral being over the true, unknown distance for each star (likelihood for that star). 250 | # The functions differ in cluster geometry assumptions and how the integral is done, but they 251 | # all compute P({w} | rc, sc, ...) 252 | 253 | # 1. Assume true distances from cluster center are described by a 1D Gaussian 254 | # with mean 0 and stdev sc, along l.o.s: cluster has negligible extent 255 | # transverse to l.o.s. Uses binomial approximation in quadratic expansion 256 | # to make integral a standard one (with error function). 257 | # (It turns out this is quite a bad approximation.) 258 | # Given vectors or scalars {w}, {wsd}, and scalar rc, sc, 259 | # compute (normalized) likelihood P({w} | {wsd}, rc, sc), 260 | # where rc and sc are cluster distance. 261 | d.likecluster1 <- function(w, wsd, rc, sc) { 262 | if(any(wsd<=0) || rc<=0 || sc<=0) stop("wsd, rc, sc must all be positive") 263 | like <- double(length(w)) 264 | for(i in 1:length(w)) { 265 | gg <- (w[i]*rc-1)/(wsd[i]^2*rc^3) 266 | bb <- wsd[i]^2*rc^4/(2*(1+wsd[i]^2*rc^4/sc^2)) 267 | integ <- sqrt(pi*bb)*exp(bb*gg^2)*(1+sqrt(pi)/2-sqrt(pi)*pnorm(gg*sqrt(2*bb))) 268 | like[i] <- integ*exp(-(w[i]*rc-1)^2/(2*wsd[i]^2*rc^2))/(2*pi*wsd[i]*sc) 269 | } 270 | return(prod(like)) 271 | } 272 | 273 | # 2. Assume cluster is spherical, i.e. true distances from cluster centre 274 | # are described by an isotropic 3D Gaussian with mean 0 and stdev sc. 275 | # No other geometric approximation, so each integral is done numerically. 276 | # costheta = cos(theta) where theta is angular separation between assumed 277 | # cluster centre and star (as seen by observer). 278 | # However, if theta<10 deg or so, cos(theta)~1 and can reduce to 1D case 279 | # again, but this time with numerical integral, not binomial approximation. 280 | # In that case no need to pass costheta (as NULL will trigger the 1D case). 281 | # Given vectors or scalars {w}, {wsd}, {costheta}, and scalar rc, sc, 282 | # compute (normalized) likelihood P({w} | {wsd}, {costheta}, rc, sc), 283 | # where rc and sc are cluster distance. 284 | # If retlog=TRUE then return the (natural) log likelihood 285 | d.likecluster2 <- function(w, wsd, costheta=NULL, rc, sc, retlog=TRUE) { 286 | if(any(wsd<=0) || rc<=0 || sc<=0) stop("wsd, rc, sc must all be positive") 287 | # integrand takes a vector r (others all scalar) and returns vector of same length 288 | intFail <- 0 289 | integrand <- function(r, w, wsd, costheta, rc, sc) { 290 | if(is.null(costheta)) { 291 | return( d.like(w=w, r=r, wsd=wsd)*dnorm(x=r, mean=rc, sd=sc) ) 292 | } else { 293 | #stop("unsolved problem for 3D case (costheta=/=NULL): numerical integration often doesn't converge") 294 | x <- sqrt(r^2 + rc^2 - 2*r*rc*costheta) # term in sqrt always non-negative 295 | tl <- double(length(x)) 296 | sel <- which(x/rc<1e-6) # special case to avoid divide by small x (i.e. neglect costheta). 297 | # keep limit very small, or else it introduces artefacts. 298 | tl[sel] <- d.like(w=w, r=r[sel], wsd=wsd)*dnorm(x=r[sel], mean=rc, sd=sc) 299 | sel <- which(x/rc>=1e-6) 300 | tl[sel] <- d.like(w=w, r=r[sel], wsd=wsd)*dnorm(x=x[sel], mean=0, sd=sc)*(r[sel]-rc*costheta)/x[sel] 301 | return(tl) 302 | # The following is the principle, but has no trap for small x. 303 | #return( d.like(w=w, r=r, wsd=wsd)*dnorm(x=x, mean=0, sd=sc)*(r-rc*costheta)/x ) 304 | } 305 | } 306 | like <- double(length(w)) 307 | for(i in 1:length(w)) { 308 | # In principle limits are (0,Inf), but finite ones are faster. 309 | # Also works okay if costheta is NULL. 310 | like[i] <- integrate.func(integrand, lower=max(0,rc-5*sc), upper=rc+5*sc, 311 | w=w[i], wsd=wsd[i], costheta=costheta[i], rc=rc, sc=sc) 312 | if(is.na(like[i])) { # if numerical integral fails, revert to 1D case. 313 | # this may not be valid, but what else can we do? 314 | intFail <- intFail+1 315 | like[i] <- integrate.func(integrand, lower=max(0,rc-5*sc), upper=rc+5*sc, 316 | w=w[i], wsd=wsd[i], costheta=NULL, rc=rc, sc=sc) 317 | } 318 | #cat(like[i], "\n") 319 | } 320 | if(intFail>0) cat("Numerical integration failures:", intFail, "\n") 321 | #cat(intFail, prod(like), "\n") 322 | if(retlog) { 323 | return(sum(log(like))) 324 | } else { 325 | return(prod(like)) 326 | } 327 | } 328 | 329 | -------------------------------------------------------------------------------- /Rcode/emcee.R: -------------------------------------------------------------------------------- 1 | # CBJ November 2017 (Coryn Bailer-Jones, calj@mpia.de) 2 | # Emcee algorithm 3 | 4 | # affine-invariant ensemble sampler (emcee) to sample from func(). 5 | # A set of Nwalker walkers are evolved over Nburnin+Nsamp iterations. (Nwalker>1) 6 | # The initial walkers are passed in as the 2D matrix thetaInit[Nwalker, Ntheta]. 7 | # These must all give finite function values. 8 | # boundaries is either NULL, or a list of length Ntheta, each elements of which is either NULL or a 9 | # two element vectors of form c(lo,hi) with hi>lo which indicate periodic boundaries for that parameter. 10 | # If the latter case, the thetaInit must lie in the range [lo,hi] (is not checked). 11 | # This means that the maximum distance between any two values of theta is (hi-lo)/2. 12 | # If the parameters have been transformed, then we need to supply the function jacobian to 13 | # return the Jacobian (a scalar) of the parameters. (Note that the parameters within 14 | # metrop() are the transformed parameters.) 15 | # Return: funcSamp, which is a 3D array funcSamp[iteration, walker, theta], of size 16 | # (Nburnin+Nsamp) * Nwalker * (2+Ntheta) matrix (no names) 17 | # which is the set of all iterations (including the burn-in) for all walkers. 18 | # funcSamp[,walker,] is a 2D array with and one row per sample and columns 19 | # 1: log10 prior PDF 20 | # 2: log10 likelihood 21 | # 3+: Ntheta parameters 22 | # Note that the walkers are updated asynchronously, i.e. a walker is updated in an iteration 23 | # immediately. Thus the walker w_j used to update walker w_k may already have been updated in this 24 | # iteration. This is required to maintain detailed balance. Note that Algorithm 2 in arXiv:1202.3665v3 25 | # is actually wrong in this respect, as it claims that w_j is only drawn from those at iteration t. 26 | emcee <- function(func, jacobian=NULL, thetaInit, boundaries=NULL, Nburnin, Nsamp, verbose, ...) { 27 | 28 | Nwalker <- nrow(thetaInit) 29 | Ntheta <- ncol(thetaInit) 30 | if(is.finite(verbose)) { 31 | cat("Sampling the posterior with emcee algorithm with", Nwalker, "walkers\n") 32 | cat("iteration # of Nburnin + Nsamp acceptRate\n") 33 | } 34 | 35 | # setup 36 | acon <- 2 # if acceptance rate is too low, increase it by lowering acon (and vice versa) 37 | walker <- thetaInit 38 | walkerFunc <- matrix(data=NA, nrow=Nwalker, ncol=2) # function values of the walkers 39 | walkerLJac <- vector(mode="numeric", length=Nwalker) # log10(Jacobian) of the walkers 40 | funcSamp <- array(data=NA, dim=c(Nsamp+Nburnin, Nwalker, 2+Ntheta)) # this will be filled and returned 41 | if(is.null(jacobian)) { 42 | jacobian <- function(...) { 43 | return(1) 44 | } 45 | } 46 | if(!is.null(boundaries)) { 47 | if(!is.list(boundaries) || length(boundaries)!=Ntheta) { 48 | stop("emcee(): boundaries must be NULL or a list of length equal to number of parameters") 49 | } # if boundaries is NULL, then so are all its elements 50 | } 51 | 52 | # initialize 53 | for(w in 1:Nwalker) { 54 | walkerFunc[w,] <- func(walker[w,], ...) # log10 55 | walkerLJac[w] <- log10(jacobian(walker[w,], ...)) 56 | } 57 | if(!(all(is.finite(walkerFunc)))) { 58 | stop("emcee(): Initialization gives non-finite function values") 59 | } 60 | if(!(all(is.finite(walkerLJac)))) { 61 | stop("emcee(): Initialization gives non-finite Jacobian") 62 | } 63 | thetaProp <- rep(NA, Ntheta) 64 | nAccept <- 0 65 | acceptRate <- 0 66 | startTime=Sys.time() 67 | 68 | # walk 69 | for(n in 1:(Nburnin+Nsamp)) { 70 | 71 | for(w in 1:Nwalker) { 72 | # for(w in sample.int(Nwalker)) { # do this instead to randomly permute order of updates 73 | z <- (1/acon)*(1 + (acon-1)*runif(min=0, max=1, n=1))^2 74 | sel <- sample(x=setdiff(1:Nwalker, w), size=1) # select another walker 75 | for(j in 1:Ntheta) { # Compute proposed step, taking care of periodic boundary conditions per parameter 76 | # Don't need to separately fold distance and final parameter. 77 | # Just compute proposal, then fold. 78 | thetaProp[j] <- walker[sel,j] + z*(walker[w,j] - walker[sel,j]) 79 | if(!is.null(boundaries[[j]])) { 80 | thetaProp[j] <- (thetaProp[j] - boundaries[[j]][1]) %% diff(boundaries[[j]]) + boundaries[[j]][1] 81 | } 82 | } 83 | if(all(is.finite(thetaProp))) { 84 | funcProp <- func(thetaProp, ...) 85 | ljacProp <- log10(jacobian(thetaProp, ...)) 86 | logSR <- (Ntheta-1)*log10(z) + sum(funcProp) - sum(walkerFunc[w,]) + ljacProp - walkerLJac[w] # log10 of selection ratio 87 | } else { 88 | warning("emcee(): thetaProp = ", thetaProp, "\n Not all thetaProp are finite so the proposal is being rejected.\n Probably the theta values are very large (positive or negative), which is not good behaviour") 89 | logSR <- -Inf 90 | } 91 | if(is.nan(logSR)) { # should never occur given other traps 92 | stop("emcee(): logSR=NaN at n=", n, "w=", w, "funcProp=", funcProp, "walkerFunc=", walkerFunc) 93 | } 94 | if(logSR>=0 || logSR>log10(runif(1, min=0, max=1))) { # runif will not generate 0 or 1 exactly 95 | walker[w,] <- thetaProp 96 | walkerFunc[w,] <- funcProp 97 | walkerLJac[w] <- ljacProp 98 | nAccept <- nAccept + 1 99 | } # otherwise walker is unchanged 100 | funcSamp[n,w,1:2] <- walkerFunc[w,] 101 | funcSamp[n,w,3:(2+Ntheta)] <- walker[w,] 102 | } # End of walker loop 103 | acceptRate <- nAccept/(n*Nwalker) 104 | 105 | # diagnostics 106 | if( is.finite(verbose) && (n%%verbose==0 || n==Nburnin+Nsamp) ) { 107 | sdump1 <- noquote( formatC(n, format="d", digits=5, flag="") ) 108 | sdump2 <- noquote( formatC(Nburnin, format="g", digits=5, flag="") ) 109 | sdump3 <- noquote( formatC(Nsamp, format="g", digits=5, flag="") ) 110 | sdump4 <- noquote( formatC(acceptRate, format="f", width=7, digits=4, flag="") ) 111 | cat(sdump1, "of", sdump2, "+", sdump3, sdump4, "\n") 112 | } 113 | 114 | } 115 | 116 | return(funcSamp) 117 | 118 | } 119 | -------------------------------------------------------------------------------- /Rcode/general_functions.R: -------------------------------------------------------------------------------- 1 | # CBJ November 2017 (Coryn Bailer-Jones, calj@mpia.de). Corrected 21 June 2018. 2 | # General functions 3 | 4 | # Return density of a beta function shifted and scaled to lie in range 5 | # specified by xrange (two element vector). 6 | d.betagen <- function(x=NA, xrange=c(0,1), shape1=NA, shape2=NA) { 7 | if(xrange[2]<=xrange[1]) {stop("Need xrange[2]>xrange[1]")} 8 | return( dbeta((x-xrange[1])/(xrange[2]-xrange[1]), shape1=shape1, shape2=shape2)/(xrange[2]-xrange[1]) ) 9 | } 10 | 11 | # Return integral of f over its first argument from lower to upper. 12 | # Returns NA if it cannot be calculated. 13 | integrate.func <- function(f, lower, upper, ..., subdivisions=1e3, rel.tol=1e-6, abs.tol=1e-6) { 14 | integ <- integrate(f=f, lower=lower, upper=upper, ..., subdivisions=subdivisions, 15 | rel.tol=rel.tol, abs.tol=abs.tol, stop.on.error=FALSE) 16 | return( ifelse(integ$message=="OK" && integ$value>0 && integ$abs.error>0, integ$value, NA) ) 17 | } 18 | 19 | # Given a 1D unnormalized posteior PDF "dense" computed on a grid "x", 20 | # return 3-element named list of normalization constant, mean, SD (essentially moments 0,1,2). 21 | # The grid must have sufficient density and span to cover essentially all of the density, 22 | # but it need not be uniform (CHECK) 23 | # See PBI section 5.1.1 for details. 24 | pdfmom <- function(dense, x) { 25 | if(length(x)!=length(x)) stop("dense and x must have same size") 26 | if(length(x)<=1) stop("dense and x must have at least two elements") 27 | deltax <- mean(diff(x)) 28 | xNorm <- deltax*sum(dense) 29 | dense <- dense/xNorm # dense is now normalized 30 | xMean <- deltax*sum(x*dense) 31 | xSD <- sqrt( deltax * sum((x-xMean)^2 * dense) ) 32 | return(list(Z=xNorm, mean=xMean, sd=xSD)) 33 | } 34 | -------------------------------------------------------------------------------- /Rcode/metropolis.R: -------------------------------------------------------------------------------- 1 | # CBJ November 2017 (Coryn Bailer-Jones, calj@mpia.de) 2 | # The Metropolis algorithm 3 | 4 | library(mvtnorm) # for rmvnorm 5 | 6 | # Metropolis (MCMC) algorithm to sample from function func. 7 | # The first argument of func must be a real vector of parameters, 8 | # the initial values of which are provided by the real vector thetaInit. 9 | # func() returns a two-element vector, the logPrior and logLike 10 | # (log base 10), the sum of which is taken to be the log of the density 11 | # function (i.e. unnormalized posterior). If you don't have this separation, 12 | # just set func to return one of them as zero. The MCMC sampling PDF is the 13 | # multivariate Gaussian with fixed covariance, sampleCov. A total of 14 | # Nburnin+Nsamp samples are drawn, of which the last Nsamp are kept. As the 15 | # sampling PDF is symmetric, the Hasting factor cancels, leaving the basic 16 | # Metropolis algorithm. Diagnostics are printed very verbose^th sample: 17 | # sample number, acceptance rate so far. 18 | # ... is used to pass data, prior parameters etc. to func(). 19 | # If demo=FALSE (default), then 20 | # return a Nsamp * (2+Ntheta) matrix (no names), where the columns are 21 | # 1: log10 prior PDF 22 | # 2: log10 likelihood 23 | # 3+: Ntheta parameters 24 | # (The order of the parameters in thetaInit and sampleCov must match.) 25 | # If demo=TRUE, return the above (funcSamp) as well as thetaPropAll, a 26 | # Nsamp * Ntheta matrix of proposed steps, as a two element named list. 27 | metrop <- function(func, thetaInit, Nburnin, Nsamp, sampleCov, verbose, 28 | demo=FALSE, ...) { 29 | 30 | Ntheta <- length(thetaInit) 31 | thetaCur <- thetaInit 32 | funcCur <- func(thetaInit, ...) # log10 33 | funcSamp <- matrix(data=NA, nrow=Nsamp, ncol=2+Ntheta) 34 | # funcSamp will be filled and returned 35 | nAccept <- 0 36 | acceptRate <- 0 37 | if(demo) { 38 | thetaPropAll <- matrix(data=NA, nrow=Nsamp, ncol=Ntheta) 39 | } 40 | 41 | for(n in 1:(Nburnin+Nsamp)) { 42 | 43 | # Metropolis algorithm. No Hastings factor for symmetric proposal 44 | if(is.null(dim(sampleCov))) { # theta and sampleCov are scalars 45 | thetaProp <- rnorm(n=1, mean=thetaCur, sd=sqrt(sampleCov)) 46 | } else { 47 | thetaProp <- rmvnorm(n=1, mean=thetaCur, sigma=sampleCov, 48 | method="eigen") 49 | } 50 | funcProp <- func(thetaProp, ...) 51 | logMR <- sum(funcProp) - sum(funcCur) # log10 of the Metropolis ratio 52 | #cat(n, thetaCur, funcCur, ":", thetaProp, funcProp, "\n") 53 | if(logMR>=0 || logMR>log10(runif(1, min=0, max=1))) { 54 | thetaCur <- thetaProp 55 | funcCur <- funcProp 56 | nAccept <- nAccept + 1 57 | acceptRate <- nAccept/n 58 | } 59 | if(n>Nburnin) { 60 | funcSamp[n-Nburnin,1:2] <- funcCur 61 | funcSamp[n-Nburnin,3:(2+Ntheta)] <- thetaCur 62 | if(demo) { 63 | thetaPropAll[n-Nburnin,1:Ntheta] <- thetaProp 64 | } 65 | } 66 | 67 | # Diagnostics 68 | if( is.finite(verbose) && (n%%verbose==0 || n==Nburnin+Nsamp) ) { 69 | s1 <- noquote(formatC(n, format="d", digits=5, flag="")) 70 | s2 <- noquote(formatC(Nburnin, format="g", digits=5, flag="")) 71 | s3 <- noquote(formatC(Nsamp, format="g", digits=5, flag="")) 72 | s4 <- noquote(formatC(acceptRate, format="f", digits=4, width=7, 73 | flag="")) 74 | cat(s1, "of", s2, "+", s3, s4, "\n") 75 | } 76 | 77 | } 78 | 79 | if(demo) { 80 | return(list(funcSamp=funcSamp, thetaPropAll=thetaPropAll)) 81 | } else { 82 | return(funcSamp) 83 | } 84 | 85 | } 86 | -------------------------------------------------------------------------------- /data/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bailer-jones/parallax-tutorial-2018/67a26bcf78321088559eaea4e604ba88d1116986/data/.DS_Store -------------------------------------------------------------------------------- /data/gdr1set03.csv: -------------------------------------------------------------------------------- 1 | ra,dec,parallax,parallax_error,pmra,pmdec 2 | 55.87979622773264,22.15818737072371,7.418107487122565,0.2404760033793764,19.719670270041995,-45.48120644340972 3 | 54.63701468685745,21.28408849726069,9.081911629729746,0.388544764651025,20.792591401326618,-44.517356544871106 4 | 57.588857743604834,23.09615778371947,7.20000056806556,0.6053114778710087,20.86853454355251,-46.429937974672825 5 | 56.613754045298215,24.254812813824387,7.743383888727891,0.3227961739603352,19.955614502970064,-44.29181300533297 6 | 56.04682707837849,23.37913237989354,7.998247518868542,0.29543224930339024,22.119289009097464,-46.98127127527573 7 | 56.85181539014719,23.91449019267275,7.648680888484211,0.30424445471541306,18.854204773057248,-43.75697548763474 8 | 58.37032007746717,20.907177785847544,7.4847178782849335,0.24735675914502708,19.415576167471265,-44.615109108285615 9 | 56.791982086182486,24.27646605389296,7.14613982210898,0.4299396568513729,20.43234409644272,-43.945524244718605 10 | 57.30086914299302,23.886600265188918,7.836102805006427,0.2930322975427438,19.403250363483025,-44.934905968610565 11 | 56.837753768951494,24.11608006387224,7.8762955633015945,0.4581992547459496,20.889324365850705,-44.68397083378137 12 | 57.056571212583144,24.318224119948468,7.066701274479442,0.4439650883569412,18.638692686820306,-43.49678706951012 13 | 56.666741457268486,23.110137127492774,7.4694221111075105,0.28806685992256026,19.407581096539484,-46.38997446401869 14 | 56.55296583993795,23.12833164638079,12.904004809469223,0.27047224199229164,20.865869110262622,-48.999280494342784 15 | 56.10725292576947,24.394510613184302,8.138967164330523,0.31599329067150633,21.121893828176162,-48.82454850187845 16 | 56.27733220085083,24.263321943172553,8.144555523410178,0.45829511040807436,19.281615911374594,-42.438239012651465 17 | 57.48590348045062,24.348806545500324,7.412980289848248,0.3542352179361268,19.031087803624374,-44.42729038405033 18 | 58.34886570431829,24.064849282609337,7.3330438493994405,0.29686735761632355,19.79238755594364,-45.73547749378371 19 | 57.320101025272756,24.39594578182569,7.023364688368016,0.26655837609421457,19.104860442564707,-43.771851517369306 20 | 59.10925006874755,23.784128132954248,6.635582417660957,0.24366817577072317,22.522699168855326,-41.645509935076234 21 | 57.918609420437505,24.982975909752895,6.930109371732377,0.4169784196069805,20.451873067947254,-46.92950656406419 22 | 56.85035526378721,24.588242153502993,4.173091926702754,0.9057144668566268,21.539273712171664,-45.50211123977324 23 | 57.99245458910868,28.12858412886224,2.8769830923881505,0.23797605723919482,21.74720456818171,-48.72566455180092 24 | 59.313188652592,21.515592805785623,6.882328190492769,0.3089859337480536,23.92565377537014,-43.07923880034118 25 | 59.590161764269965,21.25748144822987,7.272292620527985,0.29520286759979486,17.82723768243683,-45.13329058375526 26 | 58.88317266421276,21.079283216321837,8.179150933495777,0.2995702881684184,21.55210809710046,-50.403756263999156 27 | 56.69617661502748,22.914392280502632,7.480549023524276,0.28613843513610066,18.286218574938957,-44.340288961099034 28 | 56.17998534241226,25.875335177181814,7.259992415245642,0.5074734223925901,20.328379074414855,-46.04070635895817 29 | 56.06412015705236,26.33103336443544,7.41063297420714,0.22776667496100125,20.494496812801575,-44.8692137206606 30 | 58.590034125362926,24.07550107343699,7.710048605082125,0.26282625363237905,19.45776851666526,-45.68560603263397 31 | 57.714435678798694,23.328881725273316,7.0675439778854585,0.2829514809467583,19.514411658787377,-47.27964483215776 32 | 57.989337530021665,25.998678919465085,8.28183675933718,0.5857094552351174,19.052764802879686,-47.349615889518766 33 | 55.53662178578263,28.79677476444053,3.6694943604680303,0.9826047996211167,16.04849061032316,-41.68688447383453 34 | 56.25701688845052,19.5591875867749,7.376466362483358,0.3635347999648656,21.292711346299782,-42.94610525566996 35 | 57.82036504909638,23.826412656462463,7.296993724701877,0.2958851183420799,20.266296566370173,-47.40203914938636 36 | 57.987020548259544,23.901765744591177,8.29209579454844,0.8844518289347366,19.72593924819156,-47.150167460139166 37 | 57.35836218239842,24.247509335369784,7.333403775363733,0.3058268735957174,20.77644386240832,-45.742670853344144 38 | 56.830694692029255,24.13893240340338,7.638867854133873,0.2953310709183144,17.878893921392976,-43.46346980152093 39 | 57.925463609676264,21.668173547524123,7.219196954690684,0.2665934956607739,18.368579415191014,-43.12172563208988 40 | 57.776495836391156,25.594505119112995,7.399922748239183,0.24145442659776375,20.225369956700714,-45.43001531633215 41 | 57.470568328156936,25.64725926749774,7.167963133231572,0.23506105917861933,18.071666689868444,-45.69657791041552 42 | 57.573725678194386,25.379376574947507,7.353731132650526,0.2524970428262021,19.39662894725332,-45.89144370455058 43 | 56.72891296574826,24.796147484157142,8.122372837496219,0.4896883813629167,17.227163053102366,-46.60080080364165 44 | 56.66165308999606,24.959450017557785,7.537582554616035,0.22891136581452595,20.15724338875186,-46.76401801287988 45 | 57.07038674720165,25.214932392686162,7.608686297405253,0.3494709684328047,15.722158412599022,-44.819244448126256 46 | 56.43810936568366,25.595614878928426,6.691009211070397,0.2741900910794531,18.65780965866555,-42.55155790168949 47 | 56.53968109016374,26.13866133473432,7.503216366385533,0.2552057432490282,19.70416353944831,-46.01711807048646 48 | 53.27436594350398,22.1340601258619,7.4366207519047425,0.40540764006896457,22.81278884983726,-46.27778468257231 49 | 53.30799974851298,23.006246195067604,7.8957119502576925,0.25215851357563057,23.33790558897314,-49.10716954736393 50 | 57.58888661828195,27.14418270448686,8.24883251854558,0.23857681555436555,19.60837795896054,-49.556332980387914 51 | 55.9613601380127,24.247305207997854,7.988307387380746,0.3717773651236874,21.533101585881077,-45.149708753590986 52 | 56.09821642264855,24.132451526785484,8.122659245584078,0.2604353598742886,25.616620322008515,-45.52030300875547 53 | 59.01625644216939,22.226761036586627,8.291371827836047,0.2350992831598983,20.20243197336931,-50.241273986748894 54 | 55.99510474461964,23.882539853642427,6.811030435559165,0.6425007448313645,22.730600027001607,-45.66216518361722 55 | 53.74452998340547,23.529967011154124,7.433002743075509,0.3643844719692745,20.86928136479537,-42.80639544917104 56 | 59.04640719616547,22.220996143387197,7.622980524566695,0.2523971501153477,22.326128553215796,-47.267228081750574 57 | 57.29699523315962,22.609271222453597,7.678052208073689,0.3479980773964633,19.48420504121699,-47.53683703966834 58 | 57.16395232884989,21.924763364944397,8.490156272697073,0.2671863478117113,23.71852575043534,-48.518547039215 59 | 56.66005769718739,22.919596395491826,7.303444415423608,0.2522236565936793,19.322580198417864,-43.26727930805109 60 | 56.41632986981657,22.694277503867625,7.796000658215948,0.31494032370118796,19.140605815214148,-43.81362452236076 61 | 54.35029152788823,22.350795240195268,6.38051941478296,0.34900152275656166,20.988267958898756,-46.45487635893015 62 | 56.16535197844927,22.11313892425987,4.8023399013580255,0.935137657183523,24.647468148032612,-41.21216964493002 63 | 56.17434327778129,22.46435867706117,7.28265135413373,0.607131935203769,22.72433598016835,-44.941442220737045 64 | 56.00121508899161,24.556805808960398,7.826572448178263,0.2780092081069501,20.57458036510361,-45.43993554670477 65 | 55.72973938764105,24.492881397533623,7.606759850377855,0.314800934638736,20.48298319729072,-44.83297264284263 66 | 56.01485157793446,24.5040545444407,7.521598312202324,0.2453190265333863,22.22943618732919,-45.602230289942256 67 | 55.1281041509707,24.48712606728849,7.273736744882027,0.4806681448727131,23.27246944435414,-44.393767081972584 68 | 56.05809247639136,24.77920787814176,7.3764839161713445,0.24226254991026858,20.406747788970442,-45.03100877677967 69 | 54.78812567408795,24.36763452932191,7.018303613725367,0.3971459415232566,21.09909801453039,-41.48563313556496 70 | 55.762356579569825,24.669571004774184,7.655184708483124,0.46433668256516764,19.27108860111008,-46.38594949603135 71 | 55.8523402485092,23.22575437419463,7.429187843031009,0.23713095386327931,20.452775572606015,-41.709854794006006 72 | 56.65709076263587,23.78752277457829,7.71470865180844,0.24475852454414224,19.651644844872095,-47.11436454244142 73 | 56.76765178194667,23.99502558409213,7.129821314606202,0.3217477221752237,22.721504735691322,-44.92818436443298 74 | 55.92874559582895,23.5945834340059,9.491130297311868,0.3153966468565623,17.81982471692605,-45.937082760400216 75 | 56.00256713568677,23.54375651663484,7.406013576968653,0.2647452423355847,19.340960363966367,-44.82885730445542 76 | 55.90729497495464,23.5358005192745,7.646264805109491,0.25724102859176706,18.417898796523048,-45.4206773947565 77 | 55.89348538889593,23.76172675872205,7.318142521306534,0.35774930644893144,24.756614191735295,-47.20594131337024 78 | 56.75600424412251,23.49475401908145,7.493272765328515,0.3298636449988294,19.680156729667225,-45.28853640177108 79 | 55.88322959366286,23.67386628561499,6.97209231265322,0.8254785895722287,19.353606759723867,-43.56018287560313 80 | 56.575056115518386,23.48646972435143,6.690775023969853,0.8470131461922833,21.313501559093897,-42.82282446738265 81 | 56.642584166856864,23.62383428444159,7.81029360591557,0.2563161480715678,21.33849472150166,-42.78648679696933 82 | 56.861883649740534,23.678139619898435,7.424082693123619,0.27382091005420156,22.16513515496732,-45.03644623386657 83 | 56.54193892946647,23.339805092346428,8.59660717790387,0.568818279154705,21.022610278712868,-49.872808626925845 84 | 57.4142578098927,23.289920863925484,7.454684307491056,0.2694836801629726,18.46791568172829,-44.31365388435482 85 | 56.950580334306,23.217896592440407,7.353754249970139,0.2531305179333001,20.82796316261432,-45.99357866022715 86 | 57.38644687725685,23.380216608897754,7.395171089601898,0.26937920427802226,19.90770805235147,-43.85714484787617 87 | 57.42059910863255,23.341382243078098,7.212185172141784,0.31051045370609814,19.31847516722552,-44.75972406515754 88 | 57.48548604712846,23.21844348325936,6.605414675248424,0.4034467598275688,20.067077968876454,-42.7964436413031 89 | 57.18298459869003,23.259627553760193,7.010487985962165,0.2974215786172153,19.37608873426798,-44.38624292820036 90 | 56.27210442143282,23.702478882586476,7.406398256836132,0.3041622894884066,19.739170467475397,-45.76020923821747 91 | 56.359021018534456,24.034958045479755,8.23269358139052,0.2998825669486513,21.309708522865606,-46.94723048434731 92 | 56.46523922953419,24.03868902277337,7.413187059745137,0.2473200125083316,19.718916475744116,-44.88146726316421 93 | 55.36603782529099,23.708149870323236,7.723140271028138,0.24301952211591366,20.093189305674784,-45.571337906306965 94 | 56.26374575011429,23.83922208386048,7.468173593228016,0.2931616314275865,20.186181710799726,-45.604178339753034 95 | 55.21027076307838,23.418252276646513,7.658985698496882,0.25418893400704196,22.068501848332016,-45.52297760926387 96 | 56.72403794419928,23.583366502039276,7.2023395286122085,0.5354375337917123,21.846839148876462,-44.28338991956517 97 | 55.02405495960001,26.196166429093346,7.874573643250208,0.24046436664786455,21.916592167216137,-49.3520539034257 98 | 56.837086463916094,25.525651551464556,7.626214726044671,0.29507291891474907,18.48059341922318,-44.97954705336491 99 | 55.86311241934354,25.387399960438298,7.450531530392471,0.33265699188333897,19.768797570735558,-43.88592688787727 100 | 56.18320487385548,25.499102675899742,6.883287990038656,0.2872777665354504,21.935861471513505,-44.34219350565789 101 | 56.22103070373497,26.141810504639377,7.74936808490044,0.2803357961875686,22.856013839336793,-49.42687260077721 102 | 55.149525988078004,26.15122537904332,6.643499109864976,0.25036722551107404,18.568315081396836,-40.56551854498397 103 | 52.40996925616002,24.51034552515337,6.891965357500282,0.2806932567269416,22.23554491082193,-41.94633115643019 104 | 54.03533995627501,27.34277723671434,8.071927403155078,0.2491623161267603,21.034859515557603,-47.33044242184768 105 | 54.96325931906883,25.19467360535354,7.27354760495022,0.3269014840583487,19.143562542136834,-42.367554706920785 106 | 56.61406402524029,25.135343882532663,7.4418571543099175,0.22441739339614503,21.500188962122962,-45.65181208760855 107 | 55.806777932303355,25.26994210680127,7.425041340618137,0.3424909142424917,20.886685303975064,-46.59001882124045 108 | 55.9514763419749,25.004197730221023,7.393607552106318,0.30095537764610825,19.73032749185628,-45.805273174364736 109 | 55.951813167994146,25.189874516622382,7.733943364638917,0.3191526337596634,22.627281957467332,-49.20594093532446 110 | 56.083798915238226,24.795974108161744,7.659553182941336,0.25579093636824907,19.688096517733754,-46.18892606284697 111 | 56.16991625163172,24.818346683622195,7.451793153476707,0.27137029963470266,20.401925869693393,-45.099782293947925 112 | 56.337013653991356,24.921886774224994,7.074196116783792,0.2573110113955826,20.093060781342032,-43.333970428080924 113 | 56.35062330593759,24.885791933929767,7.577336954435934,0.27527487432487874,20.058147130455264,-45.11122989046058 114 | 56.266807188813395,25.2576595458774,6.7686578661557,0.5593755844428132,21.04507253710083,-45.04634453419852 115 | 56.31406123443272,25.289289109417194,7.424009843229654,0.6703917157025742,19.675354825846522,-46.2482309709815 116 | 58.00344388473505,19.596689743359377,6.761100697617316,0.2543746328220523,17.34430324245219,-42.5007017566849 117 | 52.868202625785635,21.8217171596089,7.811757788909104,0.264012673261684,24.116435928432953,-47.109215381851925 118 | 55.519777204025374,22.858370691668092,7.364846831313057,0.24905224883178576,21.048855748981374,-44.652737777511916 119 | 56.837457168445,23.803153904473756,7.1694418609395765,0.3788036332269156,19.078224221007986,-45.46254944789443 120 | 53.5076283919408,24.880718273104133,7.42810860486813,0.2783941279349625,21.267563964353116,-44.70182190854423 121 | 59.50715363952365,20.67659622735874,7.698918001067877,0.4647862645933413,20.719641677612497,-49.47964969325318 122 | 58.61605369429387,21.38954888090565,7.438792051801833,0.2521181131980153,19.204292952060197,-47.142545887100894 123 | 56.383376580489255,21.24649371104764,7.791394781041032,0.35481240233779704,20.553229849329103,-47.725763683851085 124 | 52.81657084409474,25.25527058930287,7.570505587831905,0.336002792242234,22.68732287558923,-46.66563630491608 125 | 56.45348920038742,23.14695614261508,7.834288391373069,0.7707223444269742,20.517994052245236,-45.613754834373296 126 | 55.40076821281033,25.619144640376877,7.662312772032739,0.2892307230550935,16.88161346404666,-43.60388173461879 127 | 56.28428779359732,26.29232452824265,7.582369522804104,0.4811197325071734,19.649770853111423,-45.538980527733564 128 | 54.80622736305712,24.466337185444637,6.873274690386981,0.2524689377935659,19.742628233825112,-44.510368268774705 129 | 59.1172610674568,23.150085808415145,7.53100246877409,0.27368164853610427,18.52593311362311,-45.70654041807583 130 | 58.60524862460393,24.359896567796643,7.454564828231018,0.2480189488709211,18.031722203525906,-45.399066484174995 131 | 60.934124916055495,22.944097769257585,7.23439687495951,0.34385313503016757,17.570338946836003,-44.80914770498825 132 | 56.74757873625992,24.519926574307156,7.578892136582589,0.29094602487114857,20.308306917306496,-46.608272478989534 133 | 53.53056049574791,24.344257579236135,7.219230759949775,0.24238017873319037,21.636512283405423,-45.0508657759094 134 | 54.59417595679654,22.499491718222703,7.4609098149443644,0.26648499317259905,21.39143926084254,-44.816903834208404 135 | 56.8455075529298,22.92192128942229,6.621755412024065,0.6588895922560086,21.620072147777567,-47.038268059222844 136 | 57.40916610036504,22.533298077730734,7.646484733646793,0.3773058832283544,18.17169618521252,-44.549138480160785 137 | 59.5871670434221,24.080932794934967,7.311497746495676,0.42745913517633943,19.0206698790503,-45.22250260294612 138 | 53.88215502661986,22.82339608215243,7.6663867835102115,0.24052538343402155,21.48065145648343,-45.390644040689175 139 | 56.5806765972891,20.8796009823328,7.238031511286713,0.3225325260070118,20.42001856569378,-44.126011827229725 140 | 56.18698336198382,20.747807475616433,7.607637628959163,0.4544220654504135,19.632562394018223,-45.95599015218521 141 | 55.62454049540222,20.149804125909768,7.748778612974864,0.4728024900133652,19.940478281769206,-44.75946778904281 142 | 57.43146283352636,23.711662342369394,7.884243828170889,0.5427060864990135,18.01409713896979,-45.60472965491554 143 | 57.71854709486051,23.96128153347501,3.403235714259196,0.7274333336034041,20.09198836873889,-45.354669650422046 144 | 57.491982320155465,23.848500110278945,7.240680548456045,0.4384451133666922,18.86760734894912,-45.97924763821376 145 | 57.8634836676241,24.51846150169144,7.497368414170279,0.2658151773246964,19.72296940136566,-45.35718508918036 146 | 57.34071122755996,24.38076499375933,7.224737847472554,0.46388052424368087,18.760282017740856,-45.31951529491094 147 | 56.87280843148588,24.288143395343372,7.571462789068685,0.4029145330024222,18.48154885935103,-46.911456723013316 148 | 54.737029424783515,24.569628517781407,7.258486054707135,0.23246909853293635,20.139659314969606,-43.46779802247564 149 | 54.80509842225443,21.843064862043796,7.178530350872914,0.31539976272945724,20.291277710331514,-43.605597474236966 150 | 55.60019114645403,22.42095382414324,7.328286272889863,0.24356206398978641,19.648924602928357,-44.3573606327082 151 | 55.60007290447422,21.473290910836305,7.841371061331015,0.23493059401674118,20.990540082814245,-47.97195786937417 152 | 56.47707834647139,24.554318191940897,7.948528040657269,0.8707212022627372,20.024749749675873,-45.94911065876843 153 | 56.51217436656594,24.527709876169723,7.536833267846605,0.6395402121969032,19.62908692068241,-44.875957287402315 154 | 57.479551921948655,22.243970977748944,7.5239065408351,0.5313170064985325,20.1686562663458,-44.22483758968747 155 | 56.24559499689716,22.032269900157004,6.97804596207892,0.29061246996897944,18.67511364346578,-43.662951327244315 156 | 55.92314424311916,23.6489702224774,8.190500797015298,0.518967879756035,19.034671687497813,-43.90841566161615 157 | 55.34579500690355,23.486747523838527,7.846018197557678,0.24288096629285796,21.50988581797089,-45.24641917146948 158 | 56.21357435478169,23.26873685267679,7.677080452419292,0.28740409870283745,20.520232400273997,-44.27988311049803 159 | 54.92165878278341,23.290699285473636,7.2292547923535,0.23334209989870314,21.24384352645183,-43.68099113882136 160 | 56.945236900669784,25.38550626742002,7.365995413449561,0.276378163179603,19.468905245225656,-45.72361702665931 161 | 55.01294058951401,27.740328891392625,7.127912291071012,0.2566175495905789,21.010751166320418,-44.37078515643849 162 | 56.364845278592284,28.66849773944528,8.4442997476978,0.508478051458781,22.070279050411813,-50.01050626605016 163 | 52.890208130415274,26.26529003133557,7.055644229474087,0.2835159384619453,20.811420580168807,-42.11677855048329 164 | 56.49650892230287,25.398402805562185,7.569175411890825,0.34209177249896583,20.288465349225213,-45.36680245996523 165 | 52.236362800608276,26.30842990580523,7.919410574613621,0.3062326278602819,21.898309312968273,-47.996027884013074 166 | -------------------------------------------------------------------------------- /install.R: -------------------------------------------------------------------------------- 1 | install.packages("PolynomF") 2 | install.packages("MASS") 3 | install.packages("mvtnorm") 4 | install.packages("RColorBrewer") 5 | install.packages("fields") 6 | -------------------------------------------------------------------------------- /resources/3D_astrometry_inference.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bailer-jones/parallax-tutorial-2018/67a26bcf78321088559eaea4e604ba88d1116986/resources/3D_astrometry_inference.pdf -------------------------------------------------------------------------------- /resources/cluster_inference.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bailer-jones/parallax-tutorial-2018/67a26bcf78321088559eaea4e604ba88d1116986/resources/cluster_inference.pdf -------------------------------------------------------------------------------- /runtime.txt: -------------------------------------------------------------------------------- 1 | r-2018-06-20 2 | --------------------------------------------------------------------------------