def create_waveform_generator(variable_params, data, recalibration=None, gates=None, **static_params): """Creates a waveform generator for use with a model. Parameters ---------- variable_params : list of str The names of the parameters varied. data : dict Dictionary mapping detector names to either a :py:class:`<pycbc.types.TimeSeries TimeSeries>` or :py:class:`<pycbc.types.FrequencySeries FrequencySeries>`. recalibration : dict, optional Dictionary mapping detector names to :py:class:`<pycbc.calibration.Recalibrate>` instances for recalibrating data. gates : dict of tuples, optional Dictionary of detectors -> tuples of specifying gate times. The sort of thing returned by :py:func:`pycbc.gate.gates_from_cli`. Returns ------- pycbc.waveform.FDomainDetFrameGenerator A waveform generator for frequency domain generation. """ # figure out what generator to use based on the approximant try: approximant = static_params['approximant'] except KeyError: raise ValueError("no approximant provided in the static args") generator_function = generator.select_waveform_generator(approximant) # get data parameters; we'll just use one of the data to get the # values, then check that all the others are the same delta_f = None for d in data.values(): if delta_f is None: delta_f = d.delta_f delta_t = d.delta_t start_time = d.start_time else: if not all([ d.delta_f == delta_f, d.delta_t == delta_t, d.start_time == start_time ]): raise ValueError("data must all have the same delta_t, " "delta_f, and start_time") waveform_generator = generator.FDomainDetFrameGenerator( generator_function, epoch=start_time, variable_args=variable_params, detectors=list(data.keys()), delta_f=delta_f, delta_t=delta_t, recalib=recalibration, gates=gates, **static_params) return waveform_generator
def waveform_generator(self, request): return generator.FDomainDetFrameGenerator( generator.FDomainCBCGenerator, self.epoch, variable_args=list(CBC_TEST_PARAMETERS.keys()), detectors=self.ifos, delta_f=self.delta_f, f_lower=self.fmin, approximant=request.param, )
def from_config(cls, cp, data=None, delta_f=None, delta_t=None, gates=None, recalibration=None, **kwargs): """Initializes an instance of this class from the given config file. Parameters ---------- cp : WorkflowConfigParser Config file parser to read. data : dict A dictionary of data, in which the keys are the detector names and the values are the data. This is not retrieved from the config file, and so must be provided. delta_f : float The frequency spacing of the data; needed for waveform generation. delta_t : float The time spacing of the data; needed for time-domain waveform generators. recalibration : dict of pycbc.calibration.Recalibrate, optional Dictionary of detectors -> recalibration class instances for recalibrating data. gates : dict of tuples, optional Dictionary of detectors -> tuples of specifying gate times. The sort of thing returned by `pycbc.gate.gates_from_cli`. \**kwargs : All additional keyword arguments are passed to the class. Any provided keyword will over ride what is in the config file. """ if data is None: raise ValueError("must provide data") args = cls._init_args_from_config(cp) args['data'] = data args.update(kwargs) variable_params = args['variable_params'] try: static_params = args['static_params'] except KeyError: static_params = {} # set up waveform generator try: approximant = static_params['approximant'] except KeyError: raise ValueError("no approximant provided in the static args") generator_function = generator.select_waveform_generator(approximant) waveform_generator = generator.FDomainDetFrameGenerator( generator_function, epoch=data.values()[0].start_time, variable_args=variable_params, detectors=data.keys(), delta_f=delta_f, delta_t=delta_t, recalib=recalibration, gates=gates, **static_params) args['waveform_generator'] = waveform_generator return cls(**args)
def get_cbc_fdomain_generator(self, approximant="IMRPhenomPv2", f_lower=30.0): """ Returns the waveform generator class for a CBC signal in the detector frame. """ waveform_gen = generator.FDomainDetFrameGenerator( generator.FDomainCBCGenerator, self.epoch, variable_args=self.parameters, detectors=self.ifos, delta_f=self.delta_f, f_lower=f_lower, approximant=approximant) return waveform_gen
def test_likelihood_evaluator_init(self): # data args seglen = 4 sample_rate = 2048 N = seglen * sample_rate / 2 + 1 fmin = 30. # setup waveform generator and signal parameters m1, m2, s1z, s2z, tsig = 38.6, 29.3, 0., 0., 3.1 ra, dec, pol, dist = 1.37, -1.26, 2.76, 3 * 500. gen = generator.FDomainDetFrameGenerator(generator.FDomainCBCGenerator, 0., variable_args=["tc"], detectors=["H1", "L1"], delta_f=1. / seglen, f_lower=fmin, approximant="TaylorF2", mass1=m1, mass2=m2, spin1z=s1z, spin2z=s2z, ra=ra, dec=dec, polarization=pol, distance=dist) signal = gen.generate(tc=tsig) # get PSDs psd = pypsd.aLIGOZeroDetHighPower(N, 1. / seglen, 20.) psds = {"H1": psd, "L1": psd} # get a prior evaluator uniform_prior = distributions.Uniform(tc=(tsig - 0.2, tsig + 0.2)) prior_eval = inference.prior.PriorEvaluator(["tc"], uniform_prior) # setup likelihood evaluator likelihood_eval = inference.GaussianLikelihood(gen, signal, fmin, psds=psds, prior=prior_eval, return_meta=False)
def from_config(cls, cp, data=None, delta_f=None, delta_t=None, gates=None, recalibration=None, **kwargs): """Initializes an instance of this class from the given config file. Parameters ---------- cp : WorkflowConfigParser Config file parser to read. data : dict A dictionary of data, in which the keys are the detector names and the values are the data. This is not retrieved from the config file, and so must be provided. delta_f : float The frequency spacing of the data; needed for waveform generation. delta_t : float The time spacing of the data; needed for time-domain waveform generators. recalibration : dict of pycbc.calibration.Recalibrate, optional Dictionary of detectors -> recalibration class instances for recalibrating data. gates : dict of tuples, optional Dictionary of detectors -> tuples of specifying gate times. The sort of thing returned by `pycbc.gate.gates_from_cli`. \**kwargs : All additional keyword arguments are passed to the class. Any provided keyword will over ride what is in the config file. """ prior_section = "marginalized_prior" args = cls._init_args_from_config(cp) marg_prior = read_distributions_from_config(cp, prior_section) if len(marg_prior) == 0: raise AttributeError("No priors are specified for the " "marginalization. Please specify this in a " "section in the config file with heading " "{}-variable".format(prior_section)) params = [i.params[0] for i in marg_prior] marg_args = [k for k, v in args.items() if "_marginalization" in k] if len(marg_args) != len(params): raise ValueError("There is not a prior for each keyword argument") kwargs['marg_prior'] = marg_prior for i in params: kwargs[i + "_marginalization"] = True args.update(kwargs) variable_params = args['variable_params'] args["data"] = data try: static_params = args['static_params'] except KeyError: static_params = {} # set up waveform generator try: approximant = static_params['approximant'] except KeyError: raise ValueError("no approximant provided in the static args") generator_function = generator.select_waveform_generator(approximant) waveform_generator = generator.FDomainDetFrameGenerator( generator_function, epoch=data.values()[0].start_time, variable_args=variable_params, detectors=data.keys(), delta_f=delta_f, delta_t=delta_t, recalib=recalibration, gates=gates, **static_params) args['waveform_generator'] = waveform_generator args["f_lower"] = static_params["f_lower"] return cls(**args)
def calculate_faithfulness(m1, m2, s1x=0, s1y=0, s1z=0, s2x=0, s2y=0, s2z=0, tc=0, phic=0, ra=0, dec=0, polarization=0, signal_approx='IMRPhenomD', signal_file=None, tmplt_approx='IMRPhenomC', tmplt_file=None, aligned_spin_tmplt_only=True, non_spin_tmplt_only=False, f_lower=15.0, sample_rate=4096, signal_duration=256, psd_string='aLIGOZeroDetHighPower', verbose=True, debug=False): """ Calculates the match for a signal of given physical parameters, as modelled by a given signal approximant, against templates of another approximant. This function allows turning off x,y components of spin for templates. IN PROGRESS: Adding facility to use "FromDataFile" waveforms """ # {{{ # 0) OPTION CHECKING if aligned_spin_tmplt_only: print( "WARNING: Spin components parallel to L allowed, others set to 0 in templates.") # 1) GENERATE FILTERING META-PARAMETERS filter_N = signal_duration * sample_rate filter_n = filter_N / 2 + 1 delta_t = 1./sample_rate delta_f = 1./signal_duration # LIGO Noise PSD psd = from_string(psd_string, filter_n, delta_f, f_lower) # 2) GENERATE THE TARGET SIGNAL # Get the signal waveform first if signal_approx in pywf.fd_approximants(): generator = pywfg.FDomainDetFrameGenerator(pywfg.FDomainCBCGenerator, 0, variable_args=['mass1', 'mass2', 'spin1x', 'spin1y', 'spin1z', 'spin2x', 'spin2y', 'spin2z', 'coa_phase', 'tc', 'ra', 'dec', 'polarization'], detectors=['H1'], delta_f=delta_f, f_lower=f_lower, approximant=signal_approx) elif signal_approx in pywf.td_approximants(): generator = pywfg.TDomainDetFrameGenerator(pywfg.TDomainCBCGenerator, 0, variable_args=['mass1', 'mass2', 'spin1x', 'spin1y', 'spin1z', 'spin2x', 'spin2y', 'spin2z', 'coa_phase', 'tc', 'ra', 'dec', 'polarization'], detectors=['H1'], delta_t=delta_t, f_lower=f_lower, approximant=signal_approx) elif 'FromDataFile' in signal_approx: if os.path.getsize(signal_file) == 0: raise RuntimeError( " ERROR:...OOPS. Waveform file %s empty!!" % signal_file) try: _ = np.loadtxt(signal_file) except: raise RuntimeError( " WARNING: FAILURE READING DATA FROM %s.." % signal_file) waveform_params = lsctables.SimInspiral() waveform_params.latitude = 0 waveform_params.longitude = 0 waveform_params.polarization = 0 waveform_params.spin1x = 0 waveform_params.spin1y = 0 waveform_params.spin1z = 0 waveform_params.spin2x = 0 waveform_params.spin2y = 0 waveform_params.spin2z = 0 # try: if True: if verbose: print(".. generating signal waveform ") signal_htilde, _params = get_waveform(signal_approx, -1, -1, -1, waveform_params, f_lower, sample_rate, filter_N, datafile=signal_file) print(".. generated signal waveform ") m1, m2, w_value, _ = _params waveform_params.mass1 = m1 waveform_params.mass2 = m2 signal_h = make_frequency_series(signal_htilde) signal_h = extend_waveform_FrequencySeries(signal_h, filter_n) # except: raise IOError("Approximant %s not found.." % signal_approx) else: raise IOError("Signal Approximant %s not found.." % signal_approx) if verbose: print("..Generating signal with masses = %3f, %.3f, spin1 = (%.3f, %.3f, %.3f), and spin2 = (%.3f, %.3f, %.3f)" % (m1, m2, s1x, s1y, s1z, s2x, s2y, s2z)) sys.stdout.flush() if signal_approx in pywf.fd_approximants(): signal = generator.generate_from_args(m1, m2, s1x, s1y, s1z, s2x, s2y, s2z, phic, tc, ra, dec, polarization) # NOTE: SEOBNRv4 has extra high frequency content, it seems.. if 'SEOBNRv4_ROM' in signal_approx or 'SEOBNRv2_ROM' in signal_approx: signal_h = extend_waveform_FrequencySeries( signal['H1'], filter_n, force_fit=True) else: signal_h = extend_waveform_FrequencySeries(signal['H1'], filter_n) elif signal_approx in pywf.td_approximants(): signal = generator.generate_from_args(m1, m2, s1x, s1y, s1z, s2x, s2y, s2z, phic, tc, ra, dec, polarization) signal_h = make_frequency_series(signal['H1']) signal_h = extend_waveform_FrequencySeries(signal_h, filter_n) elif 'FromDataFile' in signal_approx: pass else: raise IOError("Signal Approximant %s not found.." % signal_approx) # 3) GENERATE THE TARGET TEMPLATE # Get the signal waveform first if tmplt_approx in pywf.fd_approximants(): generator = pywfg.FDomainDetFrameGenerator(pywfg.FDomainCBCGenerator, 0, variable_args=['mass1', 'mass2', 'spin1x', 'spin1y', 'spin1z', 'spin2x', 'spin2y', 'spin2z', 'coa_phase', 'tc', 'ra', 'dec', 'polarization'], detectors=['H1'], delta_f=delta_f, f_lower=f_lower, approximant=tmplt_approx) elif tmplt_approx in pywf.td_approximants(): generator = pywfg.TDomainDetFrameGenerator(pywfg.TDomainCBCGenerator, 0, variable_args=['mass1', 'mass2', 'spin1x', 'spin1y', 'spin1z', 'spin2x', 'spin2y', 'spin2z', 'coa_phase', 'tc', 'ra', 'dec', 'polarization'], detectors=['H1'], delta_t=delta_t, f_lower=f_lower, approximant=tmplt_approx) elif 'FromDataFile' in tmplt_approx: if os.path.getsize(tmplt_file) == 0: raise RuntimeError( " ERROR:...OOPS. Waveform file %s empty!!" % tmplt_file) try: _ = np.loadtxt(tmplt_file) except: raise RuntimeError( " WARNING: FAILURE READING DATA FROM %s.." % tmplt_file) waveform_params = lsctables.SimInspiral() waveform_params.latitude = 0 waveform_params.longitude = 0 waveform_params.polarization = 0 waveform_params.spin1x = 0 waveform_params.spin1y = 0 waveform_params.spin1z = 0 waveform_params.spin2x = 0 waveform_params.spin2y = 0 waveform_params.spin2z = 0 # try: if True: if verbose: print(".. generating signal waveform ") tmplt_htilde, _params = get_waveform(tmplt_approx, -1, -1, -1, waveform_params, f_lower, 1./delta_t, filter_N, datafile=tmplt_file) print(".. generated signal waveform ") m1, m2, w_value, _ = _params waveform_params.mass1 = m1 waveform_params.mass2 = m2 tmplt_h = make_frequency_series(tmplt_htilde) tmplt_h = extend_waveform_FrequencySeries(tmplt_h, filter_n) # except: raise IOError("Approximant %s not found.." % tmplt_approx) else: raise IOError("Template Approximant %s not found.." % tmplt_approx) # if aligned_spin_tmplt_only: _m1, _m2, _s1x, _s1y, _s1z, _s2x, _s2y, _s2z = m1, m2, 0, 0, s1z, 0, 0, s2z elif non_spin_tmplt_only: _m1, _m2, _s1x, _s1y, _s1z, _s2x, _s2y, _s2z = m1, m2, 0, 0, 0, 0, 0, 0 else: _m1, _m2, _s1x, _s1y, _s1z, _s2x, _s2y, _s2z = m1, m2, s1x, s1y, s1z, s2x, s2y, s2z # # template = generator.generate_from_args(_m1, _m2, _s1x, _s1y, _s1z, _s2x, _s2y, _s2z,\ # phic, tc, ra, dec, polarization) # if verbose: print( "..Generating template with masses = %3f, %.3f, spin1 = (%.3f, %.3f, %.3f), and spin2 = (%.3f, %.3f, %.3f)" % (_m1, _m2, _s1x, _s1y, _s1z, _s2x, _s2y, _s2z)) sys.stdout.flush() if tmplt_approx in pywf.fd_approximants(): try: template = generator.generate_from_args(_m1, _m2, _s1x, _s1y, _s1z, _s2x, _s2y, _s2z, phic, tc, ra, dec, polarization) except RuntimeError as rerr: print("""FAILED TO GENERATE %s waveform for masses = %.3f, %.3f spins = (%.3f, %.3f, %.3f), (%.3f, %.3f, %.3f) phic, tc, ra, dec, pol = (%.3f, %.3f, %.3f, %.3f, %.3f)""" % (tmplt_approx, _m1, _m2, _s1x, _s1y, _s1z, _s2x, _s2y, _s2z, phic, tc, ra, dec, polarization)) raise RuntimeError(rerr) # NOTE: SEOBNRv4 has extra high frequency content, it seems.. if 'SEOBNRv4_ROM' in tmplt_approx or 'SEOBNRv2_ROM' in tmplt_approx: template_h = extend_waveform_FrequencySeries( template['H1'], filter_n, force_fit=True) else: template_h = extend_waveform_FrequencySeries( template['H1'], filter_n) elif tmplt_approx in pywf.td_approximants(): try: template = generator.generate_from_args(_m1, _m2, _s1x, _s1y, _s1z, _s2x, _s2y, _s2z, phic, tc, ra, dec, polarization) except RuntimeError as rerr: print("""FAILED TO GENERATE %s waveform for masses = %.3f, %.3f spins = (%.3f, %.3f, %.3f), (%.3f, %.3f, %.3f) phic, tc, ra, dec, pol = (%.3f, %.3f, %.3f, %.3f, %.3f)""" % (tmplt_approx, _m1, _m2, _s1x, _s1y, _s1z, _s2x, _s2y, _s2z, phic, tc, ra, dec, polarization)) raise RuntimeError(rerr) template_h = make_frequency_series(template['H1']) template_h = extend_waveform_FrequencySeries(template_h, filter_n) elif 'FromDataFile' in tmplt_approx: pass else: raise IOError("Template Approximant %s not found.." % tmplt_approx) # 4) COMPUTE MATCH m, idx = match(signal_h, template_h, psd=psd, low_frequency_cutoff=f_lower) if debug: print( "MATCH IS %.6f for parameters" % m, m1, m2, _s1x, _s1y, _s1z, _s2x, _s2y, _s2z) sys.stderr.flush() # # 5) RETURN OPTIMIZED MATCH return m, idx
def calculate_fitting_factor(m1, m2, s1x=0, s1y=0, s1z=0, s2x=0, s2y=0, s2z=0, tc=0, phic=0, ra=0, dec=0, polarization=0, signal_approx='IMRPhenomD', signal_file=None, tmplt_approx='IMRPhenomC', vary_masses_only=True, vary_masses_and_aligned_spin_only=False, chirp_mass_window=0.1, effective_spin_window=0.5, num_retries=4, f_lower=15.0, sample_rate=4096, signal_duration=256, psd_string='aLIGOZeroDetHighPower', pso_swarm_size=500, pso_omega=0.5, pso_phip=0.5, pso_phig=0.25, pso_minfunc=1e-8, verbose=True, debug=False): """ Calculates the fitting factor for a signal of given physical parameters, as modelled by a given signal approximant, against templates of another approximant. This function uses a particle swarm optimization to maximize the overlaps between signal and templates. Algorithm parameters are tunable, depending on how many dimensions we are optimizing over. IN PROGRESS: Adding facility to use "FromDataFile" waveforms """ # {{{ # 0) OPTION CHECKING if vary_masses_only: print("WARNING: Only component masses are allowed to be varied in templates. Setting the rest to signal values.") if vary_masses_and_aligned_spin_only: print("WARNING: Only component masses and spin components parallel to L allowed to be varied in templates. Setting the rest to signal values.") if vary_masses_only and vary_masses_and_aligned_spin_only: raise IOError( "Inconsistent options: vary_masses_only and vary_masses_and_aligned_spin_only") if (not vary_masses_only) and (not vary_masses_and_aligned_spin_only): print("WARNING: All mass and spin components varied in templates. Sky parameters still fixed to signal values.") # 1) GENERATE FILTERING META-PARAMETERS signal_duration = int(signal_duration) sample_rate = int(sample_rate) filter_N = signal_duration * sample_rate filter_n = filter_N / 2 + 1 delta_t = 1./sample_rate delta_f = 1./signal_duration if verbose: print("signal_duration = %d, sample_rate = %d, filter_N = %d, filter_n = %d" % ( signal_duration, sample_rate, filter_N, filter_n)) print("deltaT = %f, deltaF = %f" % (delta_t, delta_f)) # LIGO Noise PSD psd = from_string(psd_string, filter_n, delta_f, f_lower) # 2) GENERATE THE TARGET SIGNAL # PREPARATORY: Get the signal generator if signal_approx in pywf.fd_approximants(): generator = pywfg.FDomainDetFrameGenerator(pywfg.FDomainCBCGenerator, 0, variable_args=['mass1', 'mass2', 'spin1x', 'spin1y', 'spin1z', 'spin2x', 'spin2y', 'spin2z', 'coa_phase', 'tc', 'ra', 'dec', 'polarization'], detectors=['H1'], delta_f=delta_f, f_lower=f_lower, approximant=signal_approx) elif signal_approx in pywf.td_approximants(): generator = pywfg.TDomainDetFrameGenerator(pywfg.TDomainCBCGenerator, 0, variable_args=['mass1', 'mass2', 'spin1x', 'spin1y', 'spin1z', 'spin2x', 'spin2y', 'spin2z', 'coa_phase', 'tc', 'ra', 'dec', 'polarization'], detectors=['H1'], delta_t=delta_t, f_lower=f_lower, approximant=signal_approx) elif 'FromDataFile' in signal_approx: if os.path.getsize(signal_file) == 0: raise RuntimeError( " ERROR:...OOPS. Waveform file %s empty!!" % signal_file) try: _ = np.loadtxt(signal_file) except: raise RuntimeError( " WARNING: FAILURE READING DATA FROM %s.." % signal_file) waveform_params = lsctables.SimInspiral() waveform_params.latitude = 0 waveform_params.longitude = 0 waveform_params.polarization = 0 waveform_params.spin1x = 0 waveform_params.spin1y = 0 waveform_params.spin1z = 0 waveform_params.spin2x = 0 waveform_params.spin2y = 0 waveform_params.spin2z = 0 # try: if True: if verbose: print(".. generating signal waveform ") signal_htilde, _params = get_waveform(signal_approx, -1, -1, -1, waveform_params, f_lower, sample_rate, filter_N, datafile=signal_file) print(".. generated signal waveform ") m1, m2, w_value, _ = _params waveform_params.mass1 = m1 waveform_params.mass2 = m2 signal_h = make_frequency_series(signal_htilde) signal_h = extend_waveform_FrequencySeries(signal_h, filter_n) # except: raise IOError("Approximant %s not found.." % signal_approx) else: raise IOError("Approximant %s not found.." % signal_approx) if verbose: print( "\nGenerating signal with masses = %3f, %.3f, spin1 = (%.3f, %.3f, %.3f), and spin2 = (%.3f, %.3f, %.3f)" % (m1, m2, s1x, s1y, s1z, s2x, s2y, s2z)) sys.stdout.flush() # Actually GENERATE THE SIGNAL if signal_approx in pywf.fd_approximants(): signal = generator.generate_from_args(m1, m2, s1x, s1y, s1z, s2x, s2y, s2z, phic, tc, ra, dec, polarization) signal_h = extend_waveform_FrequencySeries(signal['H1'], filter_n) elif signal_approx in pywf.td_approximants(): signal = generator.generate_from_args(m1, m2, s1x, s1y, s1z, s2x, s2y, s2z, phic, tc, ra, dec, polarization) signal_h = make_frequency_series(signal['H1']) signal_h = extend_waveform_FrequencySeries(signal_h, filter_n) elif 'FromDataFile' in signal_approx: pass else: raise IOError("Approximant %s not found.." % signal_approx) ### # NOW : Set up PSO calculation of the optimal overlap parameter set, i.e. \theta(FF) ### # 3) INITIALIZE THE WAVEFORM GENERATOR FOR TEMPLATES # We allow all intrinsic parameters to vary, and fix them to the signal # values, in case only masses or only mass+aligned-spin components are # requested to be varied. This fixing is done inside the objective function. if tmplt_approx in pywf.fd_approximants(): generator_tmplt = pywfg.FDomainDetFrameGenerator(pywfg.FDomainCBCGenerator, 0, variable_args=['mass1', 'mass2', 'spin1x', 'spin1y', 'spin1z', 'spin2x', 'spin2y', 'spin2z' ], detectors=['H1'], coa_phase=phic, tc=tc, ra=ra, dec=dec, polarization=polarization, delta_f=delta_f, f_lower=f_lower, approximant=tmplt_approx) elif tmplt_approx in pywf.td_approximants(): raise IOError( "Time-domain templates not supported yet (TDomainDetFrameGenerator doesn't exist)") generator_tmplt = pywfg.TDomainDetFrameGenerator(pywfg.TDomainCBCGenerator, 0, variable_args=['mass1', 'mass2', 'spin1x', 'spin1y', 'spin1z', 'spin2x', 'spin2y', 'spin2z' ], detectors=['H1'], coa_phase=phic, tc=tc, ra=ra, dec=dec, polarization=polarization, delta_t=delta_t, f_lower=f_lower, approximant=tmplt_approx) elif 'FromDataFile' in tmplt_approx: raise RuntimeError( "Using **templates** from data files is not implemented yet") else: raise IOError("Approximant %s not found.." % tmplt_approx) # 4) DEFINE AN OBJECTIVE FUNCTION FOR PSO TO MINIMIZE def objective_function_fitting_factor(x, *args): """ This function is to be minimized if the fitting factor is to be found """ objective_function_fitting_factor.counter += 1 # 1) OBTAIN THE TEMPLATE PARAMETERS FROM X. ASSUME THAT ONLY # THOSE ARE PASSED THAT ARE NEEDED BY THE GENERATOR if len(x) == 2: m1, m2 = x if vary_masses_only: _s1x = _s1y = _s1z = _s2x = _s2y = _s2z = 0 else: _s1x, _s1y, _s1z = s1x, s1y, s1z _s2x, _s2y, _s2z = s2x, s2y, s2z elif len(x) == 4: m1, m2, _s1z, _s2z = x if vary_masses_and_aligned_spin_only: _s1x = _s1y = _s2x = _s2y = 0 else: _s1x, _s1y = s1x, s1y _s2x, _s2y = s2x, s2y elif len(x) == 8: m1, m2, _s1x, _s1y, _s1z, _s2x, _s2y, _s2z = x else: raise IOError( "No of vars %d not supported (should be 2 or 4 or 8)" % len(x)) # 2) CHECK FOR CONSISTENCY if (_s1x**2 + _s1y**2 + _s1z**2) > s_max or (_s2x**2 + _s2y**2 + _s2z**2) > s_max: return 1e99 # 2) ASSUME THAT signal_h, tmplt_generator = args tmplt = tmplt_generator.generate_from_args( m1, m2, _s1x, _s1y, _s1z, _s2x, _s2y, _s2z) tmplt_h = make_frequency_series(tmplt['H1']) if debug: print("IN FF Objective-> for parameters:", m1, m2, _s1x, _s1y, _s1z, _s2x, _s2y, _s2z) if debug: print("IN FF Objective-> Length(tmplt) = %d, making it %d" % (len(tmplt['H1']), filter_n)) # NOTE: SEOBNRv4 has extra high frequency content, it seems.. if 'SEOBNRv4_ROM' in tmplt_approx or 'SEOBNRv2_ROM' in tmplt_approx: tmplt_h = extend_waveform_FrequencySeries( tmplt_h, filter_n, force_fit=True) else: tmplt_h = extend_waveform_FrequencySeries(tmplt_h, filter_n) # 3) COMPUTE MATCH m, _ = match(signal_h, tmplt_h, psd=psd, low_frequency_cutoff=f_lower) if debug: print("MATCH IS %.6f for parameters:" % m, m1, m2, _s1x, _s1y, _s1z, _s2x, _s2y, _s2z) retval = np.log10(1. - m) # We do not want PSO to go berserk, so we stop when FF = 0.999999 if retval <= -6.0: retval = -6.0 return retval objective_function_fitting_factor.counter = 0 # 5) DEFINE A CONSTRAINT FUNCTION FOR PSO TO RESPECT def constraint_function_fitting_factor(x, *args): """ This function implements constraints on the optimization of fitting factors: 1) spin magnitudes on both holes should be <= 1 """ if len(x) == 2: m1, m2 = x s1x = s1y = s1z = s2x = s2y = s2z = 0 elif len(x) == 4: m1, m2, s1z, s2z = x s1x = s1y = s2x = s2y = 0 elif len(x) == 8: m1, m2, s1x, s1y, s1z, s2x, s2y, s2z = x # 1) Constraint on spin magnitudes s1_mag = (s1x**2 + s1y**2 + s1z**2)**0.5 s2_mag = (s2x**2 + s2y**2 + s2z**2)**0.5 ## if (s1_mag > s_max) or (s2_mag > s_max): return -1 # 2) Constraint on effective spin s_eff = (s1z * m1 + s2z * m2) / (m1 + m2) ## if (s_eff > s_eff_max) or (s_eff < s_eff_min): return -1 # FINALLY) DEFAULT return 1 # 6) FINALLY, CALL THE PSO TO COMPUTE THE FITTING FACTOR # 6a) FIRST CONSTRUCT THE FIXED ARGUMENTS FOR THE PSO's OBJECTIVE FUNCTION pso_args = (signal_h, generator_tmplt) # 6b) NOW SET THE RANGE OF PARAMETERS TO BE PROBED mt = m1 + m2 * 1.0 et = m1 * m2 / mt / mt mc = mt * et**0.6 mc_min = mc * (1.0 - chirp_mass_window) mc_max = mc * (1.0 + chirp_mass_window) et_max = 0.25 et_min = 10. / 121. # Lets say we trust waveform models up to q = 10 m1_max, _ = pnutils.mchirp_eta_to_mass1_mass2(mc_max, et_min) m1_min, _ = pnutils.mchirp_eta_to_mass1_mass2(mc_min, et_max) _, m2_max = pnutils.mchirp_eta_to_mass1_mass2(mc_max, et_max) _, m2_min = pnutils.mchirp_eta_to_mass1_mass2(mc_min, et_min) s_min = -0.99 s_max = +0.99 s_eff = (s1z * m1 + s2z * m2) / (m1 + m2) s_eff_min = s_eff - effective_spin_window s_eff_max = s_eff + effective_spin_window if verbose: print(m1, m2, mt, et, mc, mc_min, mc_max, et_min, et_max, m1_min, m1_max, m2_min, m2_max) if vary_masses_only: low_lim = [m1_min, m2_min] high_lim = [m1_max, m2_max] elif vary_masses_and_aligned_spin_only: low_lim = [m1_min, m2_min, s_min, s_min] high_lim = [m1_max, m2_max, s_max, s_max] else: low_lim = [m1_min, m2_min, s_min, s_min, s_min, s_min, s_min, s_min] high_lim = [m1_max, m2_max, s_max, s_max, s_max, s_max, s_max, s_max] # if verbose: print("\nSearching within limits:\n", low_lim, " and \n", high_lim) print("\nCalculating overlap now..") sys.stdout.flush() olap, idx = calculate_faithfulness(m1, m2, s1x, s1y, s1z, s2x, s2y, s2z, tc=tc, phic=phic, ra=ra, dec=dec, polarization=polarization, signal_approx=signal_approx, signal_file=signal_file, tmplt_approx=tmplt_approx, tmplt_file=None, aligned_spin_tmplt_only=vary_masses_and_aligned_spin_only, non_spin_tmplt_only=vary_masses_only, f_lower=f_lower, sample_rate=sample_rate, signal_duration=signal_duration, verbose=verbose, debug=debug) # if verbose: print("Overlap with aligned_spin_tmplt_only = ", vary_masses_and_aligned_spin_only, " and non_spin_tmplt_only = ", vary_masses_only, ": ", olap, np.log10( 1. - olap)) sys.stdout.flush() # idx = 1 ff = 0.0 while ff < olap: if idx and idx % 2 == 0: pso_minfunc *= 0.1 pso_phig *= 1.1 if idx > num_retries: print( "WARNING: Failed to improve on overlap in %d iterations. Set ff = olap now" % num_retries) ff = olap break if verbose: print("\nTry %d to compute fitting factor" % idx) sys.stdout.flush() params, ff = pso(objective_function_fitting_factor, low_lim, high_lim, f_ieqcons=constraint_function_fitting_factor, args=pso_args, swarmsize=pso_swarm_size, omega=pso_omega, phip=pso_phip, phig=pso_phig, minfunc=pso_minfunc, maxiter=500, debug=verbose) # Restore fitting factor from 1-ff ff = 1.0 - 10**ff if verbose: print("\nLoop will continue till %.12f < %.12f" % (ff, olap)) sys.stdout.flush() idx += 1 if verbose: print("optimization took %d objective func evals" % objective_function_fitting_factor.counter) sys.stdout.flush() # # 7) RETURN OPTIMIZED PARAMETERS return [params, olap, ff]
llrs = fp.read_likelihood_stats(iteration=opts.iteration, thin_start=opts.thin_start, thin_end=opts.thin_end, thin_interval=opts.thin_interval) map_idx = (llrs.loglr + llrs.prior).argmax() map_values = samples[map_idx] varargs = fp.variable_args sargs = fp.static_args print "generating injected waveforms" genclass = generator.select_waveform_generator( fp.static_args['approximant']) gen = generator.FDomainDetFrameGenerator(genclass, detectors=['H1', 'L1'], epoch=stilde.epoch, variable_args=varargs, **sargs) fis = gen.generate(tc=injvals[0], mass1=injvals[1], mass2=injvals[2], spin1_a=injvals[3], spin1_azimuthal=injvals[4], spin1_polar=injvals[5], spin2_a=injvals[6], spin2_azimuthal=injvals[7], spin2_polar=injvals[8], distance=injvals[9], coa_phase=injvals[10], inclination=injvals[11], polarization=injvals[12],