diff --git a/examples/fully_coherent_search_using_MCMC.py b/examples/fully_coherent_search_using_MCMC.py index 82fd4dd37425573a127c03e7580e7a2a2d956d12..72874c74e5b0fdc9270607f7a1a8d1b28f004aed 100644 --- a/examples/fully_coherent_search_using_MCMC.py +++ b/examples/fully_coherent_search_using_MCMC.py @@ -47,8 +47,8 @@ theta_prior = {'F0': {'type': 'unif', 'Delta': Delta } -ntemps = 1 -log10beta_min = -1 +ntemps = 2 +log10beta_min = -0.5 nwalkers = 100 nsteps = [300, 300] @@ -57,6 +57,9 @@ mcmc = pyfstat.MCMCSearch( sftfilepattern='{}/*{}*sft'.format(outdir, label), theta_prior=theta_prior, tref=tref, minStartTime=tstart, maxStartTime=tend, nsteps=nsteps, nwalkers=nwalkers, ntemps=ntemps, log10beta_min=log10beta_min) -mcmc.run(subtractions=[F0, F1]) +mcmc.transform_dictionary = dict( + F0=dict(subtractor=F0, symbol='$f-f^\mathrm{s}$'), + F1=dict(subtractor=F1, symbol='$\dot{f}-\dot{f}^\mathrm{s}$')) +mcmc.run() mcmc.plot_corner(add_prior=True) mcmc.print_summary() diff --git a/examples/grid_examples/grid_F0F1F2.py b/examples/grid_examples/grid_F0F1F2.py index 7456e535a19bf9de2faea5ae348b898f72036cfe..d06775ffd6ec84b54f5a6941b5eae487b4aabd23 100644 --- a/examples/grid_examples/grid_F0F1F2.py +++ b/examples/grid_examples/grid_F0F1F2.py @@ -1,9 +1,13 @@ import pyfstat import numpy as np import matplotlib.pyplot as plt -from projection_matrix import projection_matrix -plt.style.use('paper') +try: + from gridcorner import gridcorner +except ImportError: + raise ImportError( + "Python module 'gridcorner' not found, please install from " + "https://gitlab.aei.uni-hannover.de/GregAshton/gridcorner") F0 = 30.0 F1 = 1e-10 @@ -55,6 +59,6 @@ twoF = search.data[:, -1].reshape((len(F0_vals), len(F1_vals), len(F2_vals))) xyz = [F0_vals, F1_vals, F2_vals] labels = ['$f - f_0$', '$\dot{f} - \dot{f}_0$', '$\ddot{f} - \ddot{f}_0$', '$\widetilde{2\mathcal{F}}$'] -fig, axes = projection_matrix(twoF, xyz, projection='log_mean', labels=labels, - whspace=0.1, factor=1.8) +fig, axes = gridcorner.gridcorner( + twoF, xyz, projection='log_mean', labels=labels, whspace=0.1, factor=1.8) fig.savefig('{}/{}_projection_matrix.png'.format(outdir, label)) diff --git a/examples/grid_examples/grided_frequency_search.py b/examples/grid_examples/grided_frequency_search.py index 5e4a423ce8a080081de364bf058287d184df9b01..e8f5d55f1a362c79bb631d2ea2b5dd428d3550f7 100644 --- a/examples/grid_examples/grided_frequency_search.py +++ b/examples/grid_examples/grided_frequency_search.py @@ -2,8 +2,6 @@ import pyfstat import numpy as np import matplotlib.pyplot as plt -plt.style.use('paper') - F0 = 30.0 F1 = 0 F2 = 0 diff --git a/examples/other_examples/twoF_cumulative.py b/examples/other_examples/twoF_cumulative.py index cd7f0426b7fc92a8244b17958877c3e8a1672d47..760fd23e90068ad589918e6a5694e568b0a31cdf 100644 --- a/examples/other_examples/twoF_cumulative.py +++ b/examples/other_examples/twoF_cumulative.py @@ -56,7 +56,7 @@ mcmc = pyfstat.MCMCSearch( sftfilepattern='data/*'+data_label+'*sft', theta_prior=theta_prior, tref=tref, minStartTime=tstart, maxStartTime=tend, nsteps=nsteps, nwalkers=nwalkers, ntemps=ntemps, log10beta_min=log10beta_min) -mcmc.run(context='paper', subtractions=[30, -1e-10]) +mcmc.run() mcmc.plot_corner(add_prior=True) mcmc.print_summary() diff --git a/examples/semi_coherent_directed_follow_up.py b/examples/semi_coherent_directed_follow_up.py index 1ae81449b1e4c8f171559f73118366f07b485b63..e84976e34b6e28e68e9dcfe04d8067735843ed6e 100644 --- a/examples/semi_coherent_directed_follow_up.py +++ b/examples/semi_coherent_directed_follow_up.py @@ -2,8 +2,6 @@ import pyfstat import numpy as np import matplotlib.pyplot as plt -plt.style.use('./paper-style.mplstyle') - F0 = 30.0 F1 = -1e-10 F2 = 0 @@ -63,8 +61,8 @@ NstarMax = 1000 Nsegs0 = 100 fig, axes = plt.subplots(nrows=2, figsize=(3.4, 3.5)) fig, axes = mcmc.run( - NstarMax=NstarMax, Nsegs0=Nsegs0, subtractions=[F0, F1], labelpad=0.01, - plot_det_stat=False, return_fig=True, context='paper', fig=fig, + NstarMax=NstarMax, Nsegs0=Nsegs0, labelpad=0.01, + plot_det_stat=False, return_fig=True, fig=fig, axes=axes) for ax in axes: ax.grid() diff --git a/examples/semi_coherent_search_using_MCMC.py b/examples/semi_coherent_search_using_MCMC.py index cd8d95acb64775b25a4140760bd3dceb07b3119d..1422fd344ac0191291832f2cd225d6e6eb06eb84 100644 --- a/examples/semi_coherent_search_using_MCMC.py +++ b/examples/semi_coherent_search_using_MCMC.py @@ -58,6 +58,9 @@ mcmc = pyfstat.MCMCSemiCoherentSearch( theta_prior=theta_prior, tref=tref, minStartTime=tstart, maxStartTime=tend, nsteps=nsteps, nwalkers=nwalkers, ntemps=ntemps, log10beta_min=log10beta_min) +mcmc.transform_dictionary = dict( + F0=dict(subtractor=F0, symbol='$f-f^\mathrm{s}$'), + F1=dict(subtractor=F1, symbol='$\dot{f}-\dot{f}^\mathrm{s}$')) mcmc.run() mcmc.plot_corner(add_prior=True) mcmc.print_summary() diff --git a/examples/other_examples/transient_search_using_MCMC.py b/examples/transient_examples/long_transient_search_MCMC.py similarity index 78% rename from examples/other_examples/transient_search_using_MCMC.py rename to examples/transient_examples/long_transient_search_MCMC.py index b70dc3d85c1d17d5ab5906887dfabc4184922f5c..a9255fa63b7b008f70468e86edff0364e11de60a 100644 --- a/examples/other_examples/transient_search_using_MCMC.py +++ b/examples/transient_examples/long_transient_search_MCMC.py @@ -25,9 +25,7 @@ theta_prior = {'F0': {'type': 'unif', 'F2': F2, 'Alpha': Alpha, 'Delta': Delta, - 'transient_tstart': {'type': 'unif', - 'lower': minStartTime, - 'upper': maxStartTime}, + 'transient_tstart': minStartTime, 'transient_duration': {'type': 'halfnorm', 'loc': 0.001*Tspan, 'scale': 0.5*Tspan} @@ -39,11 +37,12 @@ nwalkers = 100 nsteps = [100, 100] mcmc = pyfstat.MCMCTransientSearch( - label='transient_search', outdir='data', - sftfilepattern='data/*simulated_transient_signal*sft', + label='transient_search', outdir='data_l', + sftfilepattern='data_l/*simulated_transient_signal*sft', theta_prior=theta_prior, tref=tref, minStartTime=minStartTime, maxStartTime=maxStartTime, nsteps=nsteps, nwalkers=nwalkers, ntemps=ntemps, - log10beta_min=log10beta_min) + log10beta_min=log10beta_min, + transientWindowType='rect') mcmc.run() mcmc.plot_corner(label_offset=0.7) mcmc.print_summary() diff --git a/examples/other_examples/transient_search_using_MCMC_make_simulated_data.py b/examples/transient_examples/long_transient_search_make_simulated_data.py similarity index 79% rename from examples/other_examples/transient_search_using_MCMC_make_simulated_data.py rename to examples/transient_examples/long_transient_search_make_simulated_data.py index 4fa3dd1d1157446b5de54dfb9b7f3b132889fdc1..de68fccdb40e16063bd870c0b69829b667dc49c3 100644 --- a/examples/other_examples/transient_search_using_MCMC_make_simulated_data.py +++ b/examples/transient_examples/long_transient_search_make_simulated_data.py @@ -19,8 +19,8 @@ h0 = 1e-23 sqrtSX = 1e-22 transient = pyfstat.Writer( - label='simulated_transient_signal', outdir='data', tref=tref, + label='simulated_transient_signal', outdir='data_l', tref=tref, tstart=transient_tstart, F0=F0, F1=F1, F2=F2, duration=transient_duration, Alpha=Alpha, Delta=Delta, h0=h0, sqrtSX=sqrtSX, minStartTime=minStartTime, - maxStartTime=maxStartTime) + maxStartTime=maxStartTime, transientWindowType='rect') transient.make_data() diff --git a/examples/transient_examples/short_transient_search_MCMC.py b/examples/transient_examples/short_transient_search_MCMC.py new file mode 100644 index 0000000000000000000000000000000000000000..1b8f504a074f20372c9142d6d220f0650b0e498b --- /dev/null +++ b/examples/transient_examples/short_transient_search_MCMC.py @@ -0,0 +1,52 @@ +#!/usr/bin/env python + +import pyfstat + +F0 = 30.0 +F1 = -1e-10 +F2 = 0 +Alpha = 0.5 +Delta = 1 + +minStartTime = 1000000000 +maxStartTime = minStartTime + 2*86400 +Tspan = maxStartTime - minStartTime +tref = minStartTime + +Tsft = 1800 + +DeltaF0 = 1e-2 +DeltaF1 = 1e-9 + +theta_prior = {'F0': {'type': 'unif', + 'lower': F0-DeltaF0/2., + 'upper': F0+DeltaF0/2.}, + 'F1': {'type': 'unif', + 'lower': F1-DeltaF1/2., + 'upper': F1+DeltaF1/2.}, + 'F2': F2, + 'Alpha': Alpha, + 'Delta': Delta, + 'transient_tstart': {'type': 'unif', + 'lower': minStartTime, + 'upper': maxStartTime-2*Tsft}, + 'transient_duration': {'type': 'unif', + 'lower': 2*Tsft, + 'upper': Tspan-2*Tsft} + } + +ntemps = 2 +log10beta_min = -1 +nwalkers = 100 +nsteps = [100, 100] + +mcmc = pyfstat.MCMCTransientSearch( + label='transient_search', outdir='data_s', + sftfilepattern='data_s/*simulated_transient_signal*sft', + theta_prior=theta_prior, tref=tref, minStartTime=minStartTime, + maxStartTime=maxStartTime, nsteps=nsteps, nwalkers=nwalkers, ntemps=ntemps, + log10beta_min=log10beta_min, + transientWindowType='rect') +mcmc.run() +mcmc.plot_corner(label_offset=0.7) +mcmc.print_summary() diff --git a/examples/transient_examples/short_transient_search_gridded.py b/examples/transient_examples/short_transient_search_gridded.py new file mode 100644 index 0000000000000000000000000000000000000000..fd9b83b2f85d9e076231042efbe1c0a8b9b495a5 --- /dev/null +++ b/examples/transient_examples/short_transient_search_gridded.py @@ -0,0 +1,57 @@ +#!/usr/bin/env python + +import pyfstat +import os +import numpy as np +import matplotlib.pyplot as plt + +datadir = 'data_s' + +F0 = 30.0 +F1 = -1e-10 +F2 = 0 +Alpha = 0.5 +Delta = 1 + +minStartTime = 1000000000 +maxStartTime = minStartTime + 2*86400 +Tspan = maxStartTime - minStartTime +tref = minStartTime + +Tsft = 1800 + +m = 0.001 +dF0 = np.sqrt(12*m)/(np.pi*Tspan) +DeltaF0 = 100*dF0 +F0s = [F0-DeltaF0/2., F0+DeltaF0/2., dF0] +F1s = [F1] +F2s = [F2] +Alphas = [Alpha] +Deltas = [Delta] + +print('Standard CW search:') +search1 = pyfstat.GridSearch( + label='CW', outdir=datadir, + sftfilepattern=os.path.join(datadir,'*simulated_transient_signal*sft'), + F0s=F0s, F1s=F1s, F2s=F2s, Alphas=Alphas, Deltas=Deltas, tref=tref, + minStartTime=minStartTime, maxStartTime=maxStartTime, + BSGL=False) +search1.run() +search1.print_max_twoF() + +search1.plot_1D(xkey='F0', + xlabel='freq [Hz]', ylabel='$2\mathcal{F}$') + +print('with t0,tau bands:') +search2 = pyfstat.GridSearch( + label='tCW', outdir=datadir, + sftfilepattern=os.path.join(datadir,'*simulated_transient_signal*sft'), + F0s=F0s, F1s=F1s, F2s=F2s, Alphas=Alphas, Deltas=Deltas, tref=tref, + minStartTime=minStartTime, maxStartTime=maxStartTime, + transientWindowType='rect', t0Band=Tspan-2*Tsft, tauBand=Tspan, + BSGL=False) +search2.run() +search2.print_max_twoF() + +search2.plot_1D(xkey='F0', + xlabel='freq [Hz]', ylabel='$2\mathcal{F}$') diff --git a/examples/transient_examples/short_transient_search_make_simulated_data.py b/examples/transient_examples/short_transient_search_make_simulated_data.py new file mode 100644 index 0000000000000000000000000000000000000000..320b4e4eb07dd1fce589156f0e1cfa96ea0b78a6 --- /dev/null +++ b/examples/transient_examples/short_transient_search_make_simulated_data.py @@ -0,0 +1,31 @@ +#!/usr/bin/env python + +import pyfstat + +F0 = 30.0 +F1 = -1e-10 +F2 = 0 +Alpha = 0.5 +Delta = 1 + +minStartTime = 1000000000 +maxStartTime = minStartTime + 2*86400 + +transient_tstart = minStartTime + 0.5*86400 +transient_duration = 1*86400 +tref = minStartTime + +h0 = 1e-23 +sqrtSX = 1e-22 +detectors = 'H1,L1' + +Tsft = 1800 + +transient = pyfstat.Writer( + label='simulated_transient_signal', outdir='data_s', + tref=tref, tstart=transient_tstart, duration=transient_duration, + F0=F0, F1=F1, F2=F2, Alpha=Alpha, Delta=Delta, h0=h0, + detectors=detectors,sqrtSX=sqrtSX, + minStartTime=minStartTime, maxStartTime=maxStartTime, + transientWindowType='rect', Tsft=Tsft) +transient.make_data() diff --git a/examples/using_initialisation.py b/examples/using_initialisation.py index 5e7ea5e019f0d8b3abf155c41d861d6b7a0ad825..efe43364f0ea6ada232d6fbb972b39ad9550aef3 100644 --- a/examples/using_initialisation.py +++ b/examples/using_initialisation.py @@ -59,6 +59,6 @@ mcmc = pyfstat.MCMCSearch( nsteps=nsteps, nwalkers=nwalkers, ntemps=ntemps, log10beta_min=log10beta_min) mcmc.setup_initialisation(100, scatter_val=1e-10) -mcmc.run(subtractions=[F0, F1]) +mcmc.run() mcmc.plot_corner(add_prior=True) mcmc.print_summary() diff --git a/pyfstat/core.py b/pyfstat/core.py index a5087659a588916ea08773d86ed5485e93f532b6..5d06781e156ea0c700fe4561deee3f1da2a122b6 100755 --- a/pyfstat/core.py +++ b/pyfstat/core.py @@ -330,7 +330,8 @@ class ComputeFstat(BaseSearchClass): @helper_functions.initializer def __init__(self, tref, sftfilepattern=None, minStartTime=None, - maxStartTime=None, binary=False, transient=True, BSGL=False, + maxStartTime=None, binary=False, BSGL=False, + transientWindowType=None, t0Band=None, tauBand=None, detectors=None, minCoverFreq=None, maxCoverFreq=None, injectSources=None, injectSqrtSX=None, assumeSqrtSX=None, SSBprec=None): @@ -347,10 +348,18 @@ class ComputeFstat(BaseSearchClass): this epoch binary : bool If true, search of binary parameters. - transient : bool - If true, allow for the Fstat to be computed over a transient range. BSGL : bool If true, compute the BSGL rather than the twoF value. + transientWindowType: str + If 'rect' or 'exp', + allow for the Fstat to be computed over a transient range. + ('none' instead of None explicitly calls the transient-window + function, but with the full range, for debugging) + t0Band, tauBand: int + if >0, search t0 in (minStartTime,minStartTime+t0Band) + and tau in (2*Tsft,2*Tsft+tauBand). + if =0, only compute CW Fstat with t0=minStartTime, + tau=maxStartTime-minStartTime. detectors : str Two character reference to the data to use, specify None for no contraint. If multiple-separate by comma. @@ -477,7 +486,7 @@ class ComputeFstat(BaseSearchClass): logging.info('Initialising FstatInput') dFreq = 0 - if self.transient: + if self.transientWindowType: self.whatToCompute = lalpulsar.FSTATQ_ATOMS_PER_DET else: self.whatToCompute = lalpulsar.FSTATQ_2F @@ -593,14 +602,41 @@ class ComputeFstat(BaseSearchClass): self.whatToCompute = (self.whatToCompute + lalpulsar.FSTATQ_2F_PER_DET) - if self.transient: + if self.transientWindowType: logging.info('Initialising transient parameters') self.windowRange = lalpulsar.transientWindowRange_t() - self.windowRange.type = lalpulsar.TRANSIENT_RECTANGULAR - self.windowRange.t0Band = 0 - self.windowRange.dt0 = 1 - self.windowRange.tauBand = 0 - self.windowRange.dtau = 1 + transientWindowTypes = {'none': lalpulsar.TRANSIENT_NONE, + 'rect': lalpulsar.TRANSIENT_RECTANGULAR, + 'exp': lalpulsar.TRANSIENT_EXPONENTIAL} + if self.transientWindowType in transientWindowTypes: + self.windowRange.type = transientWindowTypes[self.transientWindowType] + else: + raise ValueError( + 'Unknown window-type ({}) passed as input, [{}] allows.' + .format(self.transientWindowType, + ', '.join(transientWindowTypes))) + + self.Tsft = int(1.0/SFTCatalog.data[0].header.deltaF) + if self.t0Band is None: + self.windowRange.t0Band = 0 + self.windowRange.dt0 = 1 + else: + if not isinstance(self.t0Band, int): + logging.warn('Casting non-integer t0Band={} to int...' + .format(self.t0Band)) + self.t0Band = int(self.t0Band) + self.windowRange.t0Band = self.t0Band + self.windowRange.dt0 = self.Tsft + if self.tauBand is None: + self.windowRange.tauBand = 0 + self.windowRange.dtau = 1 + else: + if not isinstance(self.tauBand, int): + logging.warn('Casting non-integer tauBand={} to int...' + .format(self.tauBand)) + self.tauBand = int(self.tauBand) + self.windowRange.tauBand = self.tauBand + self.windowRange.dtau = self.Tsft def get_fullycoherent_twoF(self, tstart, tend, F0, F1, F2, Alpha, Delta, asini=None, period=None, ecc=None, tp=None, @@ -624,7 +660,7 @@ class ComputeFstat(BaseSearchClass): self.whatToCompute ) - if self.transient is False: + if not self.transientWindowType: if self.BSGL is False: return self.FstatResults.twoF[0] @@ -636,13 +672,20 @@ class ComputeFstat(BaseSearchClass): return log10_BSGL/np.log10(np.exp(1)) self.windowRange.t0 = int(tstart) # TYPE UINT4 - self.windowRange.tau = int(tend - tstart) # TYPE UINT4 + if self.windowRange.tauBand == 0: + # true single-template search also in transient params: + # actual (t0,tau) window was set with tstart, tend before + self.windowRange.tau = int(tend - tstart) # TYPE UINT4 + else: + # grid search: start at minimum tau required for nondegenerate + # F-stat computation + self.windowRange.tau = int(2*self.Tsft) FS = lalpulsar.ComputeTransientFstatMap( self.FstatResults.multiFatoms[0], self.windowRange, False) + twoF = 2*np.max(FS.F_mn.data) if self.BSGL is False: - twoF = 2*FS.F_mn.data[0][0] if np.isnan(twoF): return 0 else: @@ -657,10 +700,17 @@ class ComputeFstat(BaseSearchClass): FS1 = lalpulsar.ComputeTransientFstatMap( FstatResults_single.multiFatoms[0], self.windowRange, False) - self.twoFX[0] = 2*FS0.F_mn.data[0][0] - self.twoFX[1] = 2*FS1.F_mn.data[0][0] + # for now, use the Doppler parameter with + # multi-detector F maximised over t0,tau + # to return BSGL + # FIXME: should we instead compute BSGL over the whole F_mn + # and return the maximum of that? + idx_maxTwoF = np.argmax(FS.F_mn.data) + + self.twoFX[0] = 2*FS0.F_mn.data[idx_maxTwoF] + self.twoFX[1] = 2*FS1.F_mn.data[idx_maxTwoF] log10_BSGL = lalpulsar.ComputeBSGL( - 2*FS.F_mn.data[0][0], self.twoFX, self.BSGLSetup) + twoF, self.twoFX, self.BSGLSetup) return log10_BSGL/np.log10(np.exp(1)) @@ -696,8 +746,9 @@ class ComputeFstat(BaseSearchClass): max_tau = SFTmaxStartTime - tstart taus = np.linspace(min_tau, max_tau, npoints) twoFs = [] - if self.transient is False: - self.transient = True + if not self.transientWindowType: + # still call the transient-Fstat-map function, but using the full range + self.transientWindowType = 'none' self.init_computefstatistic_single_point() for tau in taus: twoFs.append(self.get_fullycoherent_twoF( @@ -868,7 +919,9 @@ class SemiCoherentSearch(ComputeFstat): self.fs_file_name = "{}/{}_FS.dat".format(self.outdir, self.label) self.set_ephemeris_files() - self.transient = True + self.transientWindowType = 'rect' + self.t0Band = None + self.tauBand = None self.init_computefstatistic_single_point() self.init_semicoherent_parameters() @@ -876,7 +929,7 @@ class SemiCoherentSearch(ComputeFstat): logging.info(('Initialising semicoherent parameters from {} to {} in' ' {} segments').format( self.minStartTime, self.maxStartTime, self.nsegs)) - self.transient = True + self.transientWindowType = 'rect' self.whatToCompute = lalpulsar.FSTATQ_2F+lalpulsar.FSTATQ_ATOMS_PER_DET self.tboundaries = np.linspace(self.minStartTime, self.maxStartTime, self.nsegs+1) @@ -915,7 +968,7 @@ class SemiCoherentSearch(ComputeFstat): self.whatToCompute ) - #if self.transient is False: + #if not self.transientWindowType: # if self.BSGL is False: # return self.FstatResults.twoF[0] # twoF = np.float(self.FstatResults.twoF[0]) @@ -1005,8 +1058,10 @@ class SemiCoherentGlitchSearch(ComputeFstat): self.fs_file_name = "{}/{}_FS.dat".format(self.outdir, self.label) self.set_ephemeris_files() - self.transient = True - self.binary = False + self.transientWindowType = 'rect' + self.t0Band = None + self.tauBand = None + self.binary = False self.init_computefstatistic_single_point() def get_semicoherent_nglitch_twoF(self, F0, F1, F2, Alpha, Delta, *args): diff --git a/pyfstat/grid_based_searches.py b/pyfstat/grid_based_searches.py index dadb855066df6fd72799d5ac0e3def4f10eb8053..3557bee0b7ff204d801a182033b546c8a04b48aa 100644 --- a/pyfstat/grid_based_searches.py +++ b/pyfstat/grid_based_searches.py @@ -31,7 +31,8 @@ class GridSearch(BaseSearchClass): Deltas, tref=None, minStartTime=None, maxStartTime=None, nsegs=1, BSGL=False, minCoverFreq=None, maxCoverFreq=None, detectors=None, SSBprec=None, injectSources=None, - input_arrays=False, assumeSqrtSX=None): + input_arrays=False, assumeSqrtSX=None, + transientWindowType=None, t0Band=None, tauBand=None): """ Parameters ---------- @@ -48,6 +49,16 @@ class GridSearch(BaseSearchClass): GPS seconds of the reference time, start time and end time input_arrays: bool if true, use the F0s, F1s, etc as is + transientWindowType: str + If 'rect' or 'exp', compute atoms so that a transient (t0,tau) map + can later be computed. ('none' instead of None explicitly calls + the transient-window function, but with the full range, for + debugging). Currently only supported for nsegs=1. + t0Band, tauBand: int + if >0, search t0 in (minStartTime,minStartTime+t0Band) + and tau in (2*Tsft,2*Tsft+tauBand). + if =0, only compute CW Fstat with t0=minStartTime, + tau=maxStartTime-minStartTime. For all other parameters, see `pyfstat.ComputeFStat` for details """ @@ -66,7 +77,9 @@ class GridSearch(BaseSearchClass): self.search = ComputeFstat( tref=self.tref, sftfilepattern=self.sftfilepattern, minCoverFreq=self.minCoverFreq, maxCoverFreq=self.maxCoverFreq, - detectors=self.detectors, transient=False, + detectors=self.detectors, + transientWindowType=self.transientWindowType, + t0Band=self.t0Band, tauBand=self.tauBand, minStartTime=self.minStartTime, maxStartTime=self.maxStartTime, BSGL=self.BSGL, SSBprec=self.SSBprec, injectSources=self.injectSources, @@ -573,7 +586,7 @@ class FrequencySlidingWindow(GridSearch): self.search = ComputeFstat( tref=self.tref, sftfilepattern=self.sftfilepattern, minCoverFreq=self.minCoverFreq, maxCoverFreq=self.maxCoverFreq, - detectors=self.detectors, transient=True, + detectors=self.detectors, transientWindowType=self.transientWindowType, minStartTime=self.minStartTime, maxStartTime=self.maxStartTime, BSGL=self.BSGL, SSBprec=self.SSBprec, injectSources=self.injectSources) @@ -779,10 +792,15 @@ class EarthTest(GridSearch): r'$\Delta P_\mathrm{spin}$ [min]', r'$2\mathcal{F}$'] - from projection_matrix import projection_matrix + try: + from gridcorner import gridcorner + except ImportError: + raise ImportError( + "Python module 'gridcorner' not found, please install from " + "https://gitlab.aei.uni-hannover.de/GregAshton/gridcorner") - fig, axes = projection_matrix(data, xyz, projection=projection, - factor=1.6, labels=labels) + fig, axes = gridcorner(data, xyz, projection=projection, factor=1.6, + labels=labels) axes[-1][-1].axvline((lal.DAYJUL_SI - lal.DAYSID_SI)/60.0, color='C3') plt.suptitle( 'T={:.1f} days, $f$={:.2f} Hz, $\log\mathcal{{B}}_{{S/A}}$={:.1f},' diff --git a/pyfstat/make_sfts.py b/pyfstat/make_sfts.py index bf4e258faafca5a30ed042b1da221de3d4a9a963..5e47b56c6f0a5c56e71697326303cf6307f483cb 100644 --- a/pyfstat/make_sfts.py +++ b/pyfstat/make_sfts.py @@ -25,7 +25,8 @@ class Writer(BaseSearchClass): tref=None, F0=30, F1=1e-10, F2=0, Alpha=5e-3, Delta=6e-2, h0=0.1, cosi=0.0, psi=0.0, phi=0, Tsft=1800, outdir=".", sqrtSX=1, Band=4, detectors='H1', - minStartTime=None, maxStartTime=None, add_noise=True): + minStartTime=None, maxStartTime=None, add_noise=True, + transientWindowType='none'): """ Parameters ---------- @@ -91,9 +92,9 @@ class Writer(BaseSearchClass): self.make_cff() self.run_makefakedata() - def get_single_config_line(self, i, Alpha, Delta, h0, cosi, psi, phi, F0, - F1, F2, tref, tstart, duration_days): - template = ( + def get_base_template(self, i, Alpha, Delta, h0, cosi, psi, phi, F0, + F1, F2, tref): + return ( """[TS{}] Alpha = {:1.18e} Delta = {:1.18e} @@ -104,12 +105,35 @@ phi0 = {:1.18e} Freq = {:1.18e} f1dot = {:1.18e} f2dot = {:1.18e} -refTime = {:10.6f} -transientWindowType=rect -transientStartTime={:10.3f} -transientTauDays={:1.3f}\n""") +refTime = {:10.6f}""") + + def get_single_config_line_cw( + self, i, Alpha, Delta, h0, cosi, psi, phi, F0, F1, F2, tref): + template = (self.get_base_template( + i, Alpha, Delta, h0, cosi, psi, phi, F0, F1, F2, tref) + """\n""") + return template.format( + i, Alpha, Delta, h0, cosi, psi, phi, F0, F1, F2, tref) + + def get_single_config_line_tcw( + self, i, Alpha, Delta, h0, cosi, psi, phi, F0, F1, F2, tref, + window, tstart, duration_days): + template = (self.get_base_template( + i, Alpha, Delta, h0, cosi, psi, phi, F0, F1, F2, tref) + """ +transientWindowType = {:s} +transientStartTime = {:10.3f} +transientTauDays = {:1.3f}\n""") return template.format(i, Alpha, Delta, h0, cosi, psi, phi, F0, F1, - F2, tref, tstart, duration_days) + F2, tref, window, tstart, duration_days) + + def get_single_config_line(self, i, Alpha, Delta, h0, cosi, psi, phi, F0, + F1, F2, tref, window, tstart, duration_days): + if window == 'none': + return self.get_single_config_line_cw( + i, Alpha, Delta, h0, cosi, psi, phi, F0, F1, F2, tref) + else: + return self.get_single_config_line_tcw( + i, Alpha, Delta, h0, cosi, psi, phi, F0, F1, F2, tref, window, + tstart, duration_days) def make_cff(self): """ @@ -119,8 +143,8 @@ transientTauDays={:1.3f}\n""") content = self.get_single_config_line( 0, self.Alpha, self.Delta, self.h0, self.cosi, self.psi, - self.phi, self.F0, self.F1, self.F2, self.tref, self.tstart, - self.duration_days) + self.phi, self.F0, self.F1, self.F2, self.tref, + self.transientWindowType, self.tstart, self.duration_days) if self.check_if_cff_file_needs_rewritting(content): config_file = open(self.config_file_name, "w+") @@ -247,7 +271,8 @@ class GlitchWriter(Writer): delta_F2=0, tref=None, F0=30, F1=1e-10, F2=0, Alpha=5e-3, Delta=6e-2, h0=0.1, cosi=0.0, psi=0.0, phi=0, Tsft=1800, outdir=".", sqrtSX=1, Band=4, detectors='H1', - minStartTime=None, maxStartTime=None, add_noise=True): + minStartTime=None, maxStartTime=None, add_noise=True, + transientWindowType='rect'): """ Parameters ---------- @@ -317,7 +342,8 @@ class GlitchWriter(Writer): self.tbounds[:-1])): line = self.get_single_config_line( i, self.Alpha, self.Delta, self.h0, self.cosi, self.psi, - t[0], t[1], t[2], t[3], self.tref, ts, d) + t[0], t[1], t[2], t[3], self.tref, self.transientWindowType, + ts, d) content += line diff --git a/pyfstat/mcmc_based_searches.py b/pyfstat/mcmc_based_searches.py index 912445e33f2e2846710b8edaf70df7490f262144..3da12b601920b9336acaa6a328664f9808acef8b 100644 --- a/pyfstat/mcmc_based_searches.py +++ b/pyfstat/mcmc_based_searches.py @@ -76,6 +76,12 @@ class MCMCSearch(core.BaseSearchClass): the search assumeSqrtSX: float, optional Don't estimate noise-floors, but assume (stationary) per-IFO sqrt{SX} + transientWindowType: str + If 'rect' or 'exp', + compute atoms so that a transient (t0,tau) map can later be computed. + ('none' instead of None explicitly calls the transient-window function, + but with the full range, for debugging) + Currently only supported for nsegs=1. Attributes ---------- @@ -108,7 +114,8 @@ class MCMCSearch(core.BaseSearchClass): log10beta_min=-5, theta_initial=None, rhohatmax=1000, binary=False, BSGL=False, SSBprec=None, minCoverFreq=None, maxCoverFreq=None, - injectSources=None, assumeSqrtSX=None): + injectSources=None, assumeSqrtSX=None, + transientWindowType=None): if os.path.isdir(outdir) is False: os.mkdir(outdir) @@ -150,7 +157,8 @@ class MCMCSearch(core.BaseSearchClass): self.search = core.ComputeFstat( tref=self.tref, sftfilepattern=self.sftfilepattern, minCoverFreq=self.minCoverFreq, maxCoverFreq=self.maxCoverFreq, - detectors=self.detectors, BSGL=self.BSGL, transient=False, + detectors=self.detectors, BSGL=self.BSGL, + transientWindowType=self.transientWindowType, minStartTime=self.minStartTime, maxStartTime=self.maxStartTime, binary=self.binary, injectSources=self.injectSources, assumeSqrtSX=self.assumeSqrtSX, SSBprec=self.SSBprec) @@ -212,38 +220,39 @@ class MCMCSearch(core.BaseSearchClass): self.theta_symbols = [self.theta_symbols[i] for i in idxs] self.theta_keys = [self.theta_keys[i] for i in idxs] + def _evaluate_logpost(self, p0vec): + init_logp = np.array([ + self.logp(p, self.theta_prior, self.theta_keys, self.search) + for p in p0vec]) + init_logl = np.array([ + self.logl(p, self.search) + for p in p0vec]) + return init_logl + init_logp + def _check_initial_points(self, p0): for nt in range(self.ntemps): logging.info('Checking temperature {} chains'.format(nt)) - initial_priors = np.array([ - self.logp(p, self.theta_prior, self.theta_keys, self.search) - for p in p0[nt]]) - number_of_initial_out_of_bounds = sum(initial_priors == -np.inf) - - if number_of_initial_out_of_bounds > 0: + num = sum(self._evaluate_logpost(p0[nt]) == -np.inf) + if num > 0: logging.warning( 'Of {} initial values, {} are -np.inf due to the prior' - .format(len(initial_priors), - number_of_initial_out_of_bounds)) - + .format(len(p0[0]), num)) p0 = self._generate_new_p0_to_fix_initial_points( - p0, nt, initial_priors) + p0, nt) - def _generate_new_p0_to_fix_initial_points(self, p0, nt, initial_priors): + def _generate_new_p0_to_fix_initial_points(self, p0, nt): logging.info('Attempting to correct intial values') - idxs = np.arange(self.nwalkers)[initial_priors == -np.inf] + init_logpost = self._evaluate_logpost(p0[nt]) + idxs = np.arange(self.nwalkers)[init_logpost == -np.inf] count = 0 - while sum(initial_priors == -np.inf) > 0 and count < 100: + while sum(init_logpost == -np.inf) > 0 and count < 100: for j in idxs: p0[nt][j] = (p0[nt][np.random.randint(0, self.nwalkers)]*( 1+np.random.normal(0, 1e-10, self.ndim))) - initial_priors = np.array([ - self.logp(p, self.theta_prior, self.theta_keys, - self.search) - for p in p0[nt]]) + init_logpost = self._evaluate_logpost(p0[nt]) count += 1 - if sum(initial_priors == -np.inf) > 0: + if sum(init_logpost == -np.inf) > 0: logging.info('Failed to fix initial priors') else: logging.info('Suceeded to fix initial priors') @@ -2194,10 +2203,13 @@ class MCMCTransientSearch(MCMCSearch): def _initiate_search_object(self): logging.info('Setting up search object') + if not self.transientWindowType: + self.transientWindowType = 'rect' self.search = core.ComputeFstat( tref=self.tref, sftfilepattern=self.sftfilepattern, minCoverFreq=self.minCoverFreq, maxCoverFreq=self.maxCoverFreq, - detectors=self.detectors, transient=True, + detectors=self.detectors, + transientWindowType=self.transientWindowType, minStartTime=self.minStartTime, maxStartTime=self.maxStartTime, BSGL=self.BSGL, binary=self.binary, injectSources=self.injectSources)