In [8]:
% matplotlib inline
%config InlineBackend.figure_format = 'retina'
from __future__ import division
import numpy as np
import matplotlib.pyplot as plt
from enterprise.pulsar import Pulsar
import enterprise.signals.parameter as parameter
from enterprise.signals import utils
from enterprise.signals import signal_base
from enterprise.signals import selections
from enterprise.signals.selections import Selection
from tests.enterprise_test_data import datadir
from enterprise.signals import white_signals
from enterprise.signals import gp_signals
from enterprise.signals import deterministic_signals
Pulsar
objectenterprise
uses a specific Pulsar
object to store all of the relevant pulsar information (i.e. TOAs, residuals, error bars, flags, etc) from the timing package. Eventually enterprise
will support both PINT
and tempo2
; however, for the moment it only supports tempo2
through the libstempo
package. This object is then used to initalize Signal
s that define the generative model for the pulsar residuals. This is in keeping with the overall enterprise
philosophy that the pulsar data should be as loosley coupled as possible to the pulsar model.
Below we initialize a pulsar class with NANOGrav B1855+09 data by passing it the par and tim file.
In [9]:
# pulsar file information
parfiles = datadir + '/B1855+09_NANOGrav_11yv0.gls.par'
timfiles = datadir + 'data/B1855+09_NANOGrav_11yv0.tim'
psr = Pulsar(parfiles, timfiles)
In [10]:
# lets define an efac parameter with a uniform prior from [0.5, 5]
efac = parameter.Uniform(0.5, 5)
This is an abstract parameter class in that it is not yet intialized. It is equivalent to defining the class via the standard nomenclature class efac(object)...
The parameter is then intialized via a name. This way, a single parameter class can be initialized for multiple signal parameters with different names (i.e. EFAC per observing backend, etc). Once the parameter is initialized then you then have access to many useful methods.
In [13]:
# initialize efac parameter with name "efac_1"
efac1 = efac('efac_1')
# return parameter name
print(efac1.name)
# get pdf at a point (log pdf is access)
print(efac1.get_pdf(1.3), efac1.get_logpdf(1.3))
# return 5 samples from this prior distribution
print(efac1.sample(size=5))
In [14]:
# white and red noise parameters with uniform priors
efac = parameter.Uniform(0.5, 5)
log10_equad = parameter.Uniform(-10, -5)
log10_ecorr = parameter.Uniform(-10, -5)
log10_A = parameter.Uniform(-18, -12)
gamma = parameter.Uniform(1, 7)
In [ ]:
# EFAC, EQUAD, and ECORR signals
ef = ws.MeasurementNoise(efac=efac)
eq = ws.EquadNoise(log10_equad=log10_equad)
ec = gs.EcorrBasisModel(log10_ecorr=log10_ecorr)
Again, these are abstract classes that will be in itialized when passes a Pulsar
object. This, again, makes for ease of use when constucting pulsar signal models in that these classes are created on the fly and can be re-intialized with different pulsars.
Red noise signals are handled somewhat differently than other signals in that we do not create the class by passing the parameters directly. Instead we use the Function
factory (creates a class, not an instance) to set the red noise PSD used (i.e. powerlaw, spectrum, broken, etc). This allows the user to define custom PSDs with no extra coding overhead other than the PSD definition itself.
In [ ]:
# Use Function object to set power-law red noise with uniform priors
pl = Function(utils.powerlaw, log10_A=log10_A, gamma=gamma)
# red noise signal using Fourier GP
rn = gs.FourierBasisGP(spectrum=pl, components=30)
Here we have defined a power-law function class that will be initialized when the red noise class is initialized. The red noise signal model is then a powerlaw red noise process modeled via a Fourier basis Gaussian Process with 30 components.
In [ ]:
# timing model as GP (no parameters)
tm = gs.TimingModel()
In [18]:
# create combined signal class with some metaclass magic
s = ef + ec + eq + rn + tm
# initialize model with pulsar object
pm = s(psr)
# print out the parameter names and priors
pm.params
Out[18]: