2 Code to read in LALInference HDF5 posterior samples, evolve the spins up to a specified value (default: Schwarzschild ISCO), and write the resulting evolved spin samples to the HDF5 file.
5 python lalinference_evolve_spins_and_append_samples.py --sample_file <directory path to the posterior samples> [--vfinal <final orbital velocity>]
11 import lalsimulation
as lalsim
14 from numpy.linalg
import norm
15 from lal
import MSUN_SI, MTSUN_SI
21 from astropy.table
import Column, Table, hstack
29 chi1_v_norm =
norm(chi1_v)
30 chi2_v_norm =
norm(chi2_v)
35 chi1dL_v = np.dot(chi1_v, Ln_v)
36 chi2dL_v = np.dot(chi2_v, Ln_v)
40 chi1inplane = chi1_v - chi1dL_v*Ln_v
41 chi2inplane = chi2_v - chi2dL_v*Ln_v
44 cos_tilt1 = chi1dL_v/chi1_v_norm
45 cos_tilt2 = chi2dL_v/chi2_v_norm
46 cos_phi12 = np.dot(chi1inplane,chi2inplane)/(
norm(chi1inplane)*
norm(chi2inplane))
49 phi12_evol_i = np.arccos(cos_phi12)
50 if np.sign(np.dot(Ln_v,np.cross(chi1_v, chi2_v))) < 0:
51 phi12_evol_i = 2.*np.pi - phi12_evol_i
53 return np.arccos(cos_tilt1), np.arccos(cos_tilt2), phi12_evol_i
59 approx = lalsim.GetApproximantFromString(
"SpinTaylorT5")
62 parser = argparse.ArgumentParser(description =
'Evolve the LALInference posterior samples of spins and append to HDF5 file of samples')
63 parser.add_argument(
"--sample_file", help =
"path to the HDF5 posterior samples file", required=
True)
64 parser.add_argument(
"--vfinal", help =
"final orbital velocity for the evolution (default is the Schwarzschild ISCO velocity 6**-0.5 ~= 0.408)", type=str, default=
"ISCO")
65 args = parser.parse_args()
67 hdf_pos_file = args.sample_file
69 if args.vfinal==
'ISCO':
74 v_final = float(args.vfinal)
76 raise ValueError(
"vfinal has to either be ISCO or a fraction of the speed of light")
77 label =
'_evol_vfinal'
84 _colname_map = ((
'tilt_spin1' + label,
'tilt1' + label, _identity),
85 (
'tilt_spin2' + label,
'tilt2' + label, _identity))
87 def _remap_colnames(table):
88 for old_name, new_name, func
in _colname_map:
89 if old_name
in table.colnames:
90 table[new_name] =
func(table.columns.pop(old_name))
98 if (
'mc' in data.dtype.names)
and (
'q' in data.dtype.names):
99 q = np.atleast_1d(data[
'q'])
100 eta = q/(1. + q)/(1. + q)
101 m1, m2 =
mc2ms(np.atleast_1d(data[
'mc']), eta)
103 raise ValueError(
"Chirp mass and mass ratio are not found in %s. There is likely something wrong with this posterior file."%hdf_pos_file)
104 if (
'a1' in data.dtype.names)
and (
'a2' in data.dtype.names):
105 chi1, chi2 = np.atleast_1d(data[
'a1']), np.atleast_1d(data[
'a2'])
107 raise ValueError(
"No spin magnitude samples were found in %s. There are no spins to evolve."%hdf_pos_file)
108 if (
'tilt1' in data.dtype.names)
and (
'tilt2' in data.dtype.names):
109 tilt1, tilt2 = np.atleast_1d(data[
'tilt1']), np.atleast_1d(data[
'tilt2'])
111 raise ValueError(
"No tilt angle samples were found in %s; cannot evolve spins."%hdf_pos_file)
112 if 'phi12' in data.dtype.names:
113 phi12 = np.atleast_1d(data[
'phi12'])
115 raise ValueError(
"No phi12 samples were found in %s; cannot evolve spins."%hdf_pos_file)
119 if 'LAL_APPROXIMANT' not in data.dtype.names:
120 raise ValueError(
'LAL_APPROXIMANT is missing--unable to determine which waveform was used to obtain the samples.')
122 spinfreq_enum = np.array([lalsim.SimInspiralGetSpinFreqFromApproximant(
int(lal_approx))
for lal_approx
in data[
'LAL_APPROXIMANT']])
124 if len(np.where(spinfreq_enum == lalsim.SIM_INSPIRAL_SPINS_CASEBYCASE)[0]) > 0:
125 raise ValueError(
'Unable to evolve spins since approximant does not have a set frequency at which the spins are defined.')
127 f_start = np.where(np.array(spinfreq_enum == lalsim.SIM_INSPIRAL_SPINS_FLOW), data[
'flow'], data[
'f_ref'])
130 tilt1_evol = np.zeros_like(m1)
131 tilt2_evol = np.zeros_like(m1)
132 phi12_evol = np.zeros_like(m1)
134 for i, _
in enumerate(m1):
136 if np.logical_or(chi1[i] > 1e-3, chi2[i] > 1e-3):
137 mtot_s = (m1[i] + m2[i])*MTSUN_SI
138 f_final = v_final*v_final*v_final/(mtot_s*np.pi)
140 _, _, chi1x_v_data, chi1y_v_data, chi1z_v_data, chi2x_v_data, chi2y_v_data, chi2z_v_data, Lnx_v_data, Lny_v_data, Lnz_v_data, _, _, _ = lalsim.SimInspiralSpinTaylorPNEvolveOrbit(deltaT=dt*mtot_s, m1=m1[i]*MSUN_SI, m2=m2[i]*MSUN_SI, fStart=f_start[i], fEnd=f_final, s1x=chi1[i]*np.sin(tilt1[i]), s1y=0., s1z=chi1[i]*np.cos(tilt1[i]), s2x=chi2[i]*np.sin(tilt2[i])*np.cos(phi12[i]), s2y=chi2[i]*np.sin(tilt2[i])*np.sin(phi12[i]), s2z=chi2[i]*np.cos(tilt2[i]), lnhatx=0., lnhaty=0., lnhatz=1., e1x=1., e1y=0., e1z=0., lambda1=0., lambda2=0., quadparam1=1., quadparam2=1., spinO=6, tideO=0, phaseO=7, lscorr=0, approx=approx)
143 if f_start[i] <= f_final:
148 chi1_v = np.array([chi1x_v_data.data.data[idx_use], chi1y_v_data.data.data[idx_use], chi1z_v_data.data.data[idx_use]])
149 chi2_v = np.array([chi2x_v_data.data.data[idx_use], chi2y_v_data.data.data[idx_use], chi2z_v_data.data.data[idx_use]])
151 Ln_v = np.array([Lnx_v_data.data.data[idx_use], Lny_v_data.data.data[idx_use], Lnz_v_data.data.data[idx_use]])
155 tilt1_evol[i], tilt2_evol[i], phi12_evol[i] = tilt1[i], tilt2[i], phi12[i]
160 colnames = np.array(data.colnames)
162 tilt1_id = np.where(colnames==
'tilt1')[0][0]
163 tilt2_id = np.where(colnames==
'tilt2')[0][0]
164 phi12_id = np.where(colnames==
'phi12')[0][0]
165 f_ref_id = np.where(colnames==
'f_ref')[0][0]
168 meta_tilt1 = tuple(data.columns.items())[tilt1_id][1].meta
169 meta_tilt2 = tuple(data.columns.items())[tilt2_id][1].meta
170 meta_phi12 = tuple(data.columns.items())[phi12_id][1].meta
171 meta_f_ref = tuple(data.columns.items())[f_ref_id][1].meta
174 tilts_evol = Table([Column(tilt1_evol, name=
'tilt1' + label, meta=meta_tilt1), Column(tilt2_evol, name=
'tilt2' + label, meta=meta_tilt2), Column(phi12_evol, name=
'phi12' + label, meta=meta_phi12)])
177 data_joined = hstack([data, tilts_evol])
179 if v_final !=
"ISCO":
180 vfinal_col = Table([Column(v_final*np.ones_like(tilt1_evol), name=
'vfinal', meta=meta_f_ref)])
181 data_joined = hstack([data_joined, vfinal_col])
183 _remap_colnames(data_joined)
185 f = h5py.File(hdf_pos_file,
'r')
186 path =
'/lalinference/'+run_identifier+
'/posterior_samples'
189 names = np.array([list(arrt.items())[i][0]
for i
in range(len(list(arrt.items())))])
196 metadata[path][
'FIELD_{0}_NAME'.format(num_names+1)]=
'tilt_spin1' + label
197 metadata[path][
'FIELD_{0}_NAME'.format(num_names+2)]=
'tilt_spin2' + label
198 metadata[path][
'FIELD_{0}_NAME'.format(num_names+3)]=
'phi12' + label
201 write_samples(data_joined, hdf_pos_file, path=path, metadata=metadata, overwrite=
True)
static REAL8 norm(const REAL8 x[3])
def mc2ms(mc, eta)
Utility function for converting mchirp,eta to component masses.
def extract_metadata(filename, metadata, log_noise_evidences=[], log_max_likelihoods=[], nlive=[], dset_name=None, nest=False, strict_versions=True)
Extract metadata from HDF5 sample chain file.
def write_samples(table, filename, metadata=None, **kwargs)
Write an HDF5 sample chain file.
def read_samples(filename, path=None, tablename=POSTERIOR_SAMPLES)
Read an HDF5 sample chain file.
def tilts_and_phi12_from_Cartesian_spins_and_L(chi1_v, chi2_v, Ln_v)