def update_params_norm_hoff(P, IP, param_names, vals, verbose=False): """ Update the values of 1 or more member of P and recompute norm_hoff(P). Inputs: - P: A ChooseWaveformParams object - IP: An InnerProduct object - param_names: An array of strings of parameters to be updated. e.g. [ 'm1', 'm2', 'incl' ] - vals: update P to have these parameter values. Must be array-like with same length as param_names, ordered the same way Outputs: - A COMPLEX16FrequencySeries, same as norm_hoff(P, IP) """ special_params = [] special_vals = [] assert len(param_names) == len(vals) for i, val in enumerate(vals): if hasattr(P, param_names[i]): # Update an attribute of P... setattr(P, param_names[i], val) else: # Either an incorrect param name, or a special case... special_params.append(param_names[i]) special_vals.append(val) # Check allowed special cases of params not in P, e.g. Mc and eta if special_params == ['Mc', 'eta']: m1, m2 = lsu.m1m2(special_vals[0], lsu.sanitize_eta( special_vals[1])) # m1,m2 = m1m2(Mc,eta) setattr(P, 'm1', m1) setattr(P, 'm2', m2) elif special_params == ['eta', 'Mc']: m1, m2 = lsu.m1m2(lsu.sanitize_eta(special_vals[1]), special_vals[0]) setattr(P, 'm1', m1) setattr(P, 'm2', m2) elif special_params == ['Mc']: eta = lsu.sanitize_eta(lsu.symRatio(P.m1, P.m2)) m1, m2 = lsu.m1m2(special_vals[0], eta) setattr(P, 'm1', m1) setattr(P, 'm2', m2) elif special_params == ['eta']: Mc = lsu.mchirp(P.m1, P.m2) m1, m2 = lsu.m1m2(Mc, lsu.sanitize_eta(special_vals[0])) setattr(P, 'm1', m1) setattr(P, 'm2', m2) elif special_params != []: print(special_params) raise Exception if verbose == True: # for debugging - make sure params change properly P.print_params() return lsu.norm_hoff(P, IP)
def extract_combination_from_LI(samples_LI, p): """ extract_combination_from_LI - reads in known columns from posterior samples - for selected known combinations not always available, it will compute them from standard quantities Unike version in ConstructIntrinsicPosterior, this code does not rely on ChooseWaveformParams to perform coordinate changes... """ if p in samples_LI.dtype.names: # e.g., we have precomputed it return samples_LI[p] if p in remap_ILE_2_LI.keys(): if remap_ILE_2_LI[p] in samples_LI.dtype.names: return samples_LI[remap_ILE_2_LI[p]] # Return cartesian components of spin1, spin2. NOTE: I may already populate these quantities in 'Add important quantities' if (p == 'chi_eff' or p == 'xi') and 'a1z' in samples_LI.dtype.names: m1 = samples_LI['m1'] m2 = samples_LI['m2'] a1z = samples_LI['a1z'] a2z = samples_LI['a2z'] return (m1 * a1z + m2 * a2z) / (m1 + m2) if p == 'chiz_plus': print(" Transforming ") if 'a1z' in samples_LI.dtype.names: return (samples_LI['a1z'] + samples_LI['a2z']) / 2. if 'theta1' in samples_LI.dtype.names: return (samples_LI['a1'] * np.cos(samples_LI['theta1']) + samples_LI['a2'] * np.cos(samples_LI['theta2'])) / 2. # return (samples_LI['a1']+ samples_LI['a2'])/2. if p == 'chiz_minus': print(" Transforming ") if 'a1z' in samples_LI.dtype.names: return (samples_LI['a1z'] - samples_LI['a2z']) / 2. if 'theta1' in samples_LI.dtype.names: return (samples_LI['a1'] * np.cos(samples_LI['theta1']) - samples_LI['a2'] * np.cos(samples_LI['theta2'])) / 2. # return (samples_LI['a1']- samples_LI['a2'])/2. if 'theta1' in samples_LI.dtype.names: if p == 's1x': return samples_LI["a1"] * np.sin(samples_LI['theta1']) * np.cos( samples_LI['phi1']) if p == 's1y': return samples_LI["a1"] * np.sin(samples_LI['theta1']) * np.sin( samples_LI['phi1']) if p == 's2x': return samples_LI["a2"] * np.sin(samples_LI['theta2']) * np.cos( samples_LI['phi2']) if p == 's2y': return samples_LI["a2"] * np.sin(samples_LI['theta2']) * np.sin( samples_LI['phi2']) if p == 'chi1_perp': return samples_LI["a1"] * np.sin(samples_LI['theta1']) if p == 'chi2_perp': return samples_LI["a2"] * np.sin(samples_LI['theta2']) elif 'tilt1' in samples_LI.dtype.names: if p == 'chi1_perp': return samples_LI["a1"] * np.sin(samples_LI['tilt1']) if p == 'chi2_perp': return samples_LI["a2"] * np.sin(samples_LI['tilt2']) else: # aligned if p == 'chi1_perp': return np.zeros(len(samples_LI["m1"])) if p == 'chi2_perp': return np.zeros(len(samples_LI["m1"])) if 'lambdat' in samples_LI.dtype.names: # LI does sampling in these tidal coordinates lambda1, lambda2 = lalsimutils.tidal_lambda_from_tilde( samples_LI["m1"], samples_LI["m2"], samples_LI["lambdat"], samples_LI["dlambdat"]) if p == "lambda1": return lambda1 if p == "lambda2": return lambda2 if p == 'delta' or p == 'delta_mc': return (samples_LI['m1'] - samples_LI['m2']) / ( (samples_LI['m1'] + samples_LI['m2'])) # Return cartesian components of Lhat if p == 'product(sin_beta,sin_phiJL)': return np.sin(samples_LI[remap_ILE_2_LI['beta']]) * np.sin( samples_LI['phi_jl']) if p == 'product(sin_beta,cos_phiJL)': return np.sin(samples_LI[remap_ILE_2_LI['beta']]) * np.cos( samples_LI['phi_jl']) if p == 'mc': m1v = samples["m1"] m2v = samples["m2"] return lalsimutils.mchirp(m1v, m2v) if p == 'eta': m1v = samples["m1"] m2v = samples["m2"] return lalsimutils.symRatio(m1v, m2v) # Backup : access lambdat if not present if (p == 'lambdat' or p == 'dlambdat') and 'lambda1' in samples.dtype.names: Lt, dLt = lalsimutils.tidal_lambda_tilde(samples['m1'], samples['m2'], samples['lambda1'], samples['lambda2']) if p == 'lambdat': return Lt if p == 'dlambdat': return dLt if p == "q" and 'm1' in samples.dtype.names: return samples["m2"] / samples["m1"] print(" No access for parameter ", p, " in ", samples.dtype.names) return np.zeros(len(samples_LI['m1'])) # to avoid causing a hard failure
npts_out = np.sum(indx_ok) new_samples = np.recarray((npts_out, ), dtype=samples.dtype) for name in samples.dtype.names: new_samples[name] = samples[name][indx_ok] samples = new_samples # samples = np.recarray(samples.T,names=field_names,dtype=field_formats) #,formats=field_formats) # If no record names # Add mtotal, q, samples = add_field(samples, [('mtotal', float)]) samples["mtotal"] = samples["m1"] + samples["m2"] samples = add_field(samples, [('q', float)]) samples["q"] = samples["m2"] / samples["m1"] samples = add_field(samples, [('mc', float)]) samples["mc"] = lalsimutils.mchirp(samples["m1"], samples["m2"]) samples = add_field(samples, [('eta', float)]) samples["eta"] = lalsimutils.symRatio(samples["m1"], samples["m2"]) samples = add_field(samples, [('chi_eff', float)]) samples["chi_eff"] = (samples["m1"] * samples["a1z"] + samples["m2"] * samples["a2z"]) / (samples["mtotal"]) chi1_perp = np.sqrt(samples['a1x'] * samples["a1x"] + samples['a1y']**2) chi2_perp = np.sqrt(samples['a2x']**2 + samples['a2y']**2) samples = add_field(samples, [('chi1_perp', float)]) samples['chi1_perp'] = chi1_perp samples = add_field(samples, [('chi2_perp', float)]) samples['chi2_perp'] = chi2_perp if ('lambda1' in samples.dtype.names): Lt, dLt = lalsimutils.tidal_lambda_tilde(samples['m1'], samples['m2'], samples['lambda1'],
def calc_eta(red_data): return lalsimutils.symRatio(red_data[:, 1], red_data[:, 2])
def find_effective_Fisher_region(P, IP, target_match, param_names, param_bounds): """ Example Usage: find_effective_Fisher_region(P, IP, 0.9, ['Mc', 'eta'], [[mchirp(P.m1,P.m2)-lal.LAL_MSUN_SI,mchirp(P.m1,P.m2)+lal.LAL_MSUN_SI], [0.05, 0.25]]) Arguments: - P: a ChooseWaveformParams object describing a target signal - IP: An inner product class to compute overlaps. Should have deltaF and length consistent with P - target_match: find parameter variation where overlap is target_match. Should be a real number in [0,1] - param_names: array of string names for members of P to vary. Should have length N for N params to be varied e.g. ['Mc', 'eta'] - param_bounds: array of max variations of each param in param_names Should be an Nx2 array for N params to be varied Returns: Array of boundaries of a hypercube meant to encompass region where match is >= target_match. e.g. [ [3.12,3.16] , [0.12, 0.18] ] N.B. Only checks variations along parameter axes. If params are correlated, may get better matches off-axis, and the hypercube won't fully encompass region where target_match is achieved. Therefore, allow a generous safety factor in your value of 'target_match'. """ TOL = 1.e-3 # Don't need to be very precise for this... Nparams = len(param_names) assert len(param_bounds) == Nparams param_cube = [] hfSIG = lsu.norm_hoff(P, IP) for i, param in enumerate(param_names): PT = P.copy() if param == 'Mc': param_peak = lsu.mchirp(P.m1, P.m2) elif param == 'eta': param_peak = lsu.symRatio(P.m1, P.m2) else: param_peak = getattr(P, param) func = lambda x: update_params_ip(hfSIG, PT, IP, [param], [x] ) - target_match try: min_param = brentq(func, param_peak, param_bounds[i][0], xtol=TOL) except ValueError: print("\nWarning! Value", param_bounds[i][0], "of", param,\ "did not bound target match", target_match, ". Using",\ param_bounds[i][0], "as the lower bound of", param,\ "range for the effective Fisher region.\n") min_param = param_bounds[i][0] try: max_param = brentq(func, param_peak, param_bounds[i][1], xtol=TOL) except ValueError: print("\nWarning! Value", param_bounds[i][1], "of", param,\ "did not bound target match", target_match, ". Using",\ param_bounds[i][1], "as the upper bound of", param,\ "range for the effective Fisher region.\n") max_param = param_bounds[i][1] param_cube.append([min_param, max_param]) return param_cube