Skip to content

Commit b0ce876

Browse files
Update detstats.py
modified destats.py to match dev
1 parent c86c455 commit b0ce876

1 file changed

Lines changed: 109 additions & 18 deletions

File tree

holodeck/detstats.py

Lines changed: 109 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -12,16 +12,28 @@
1212
import matplotlib.pyplot as plt
1313
import os
1414
from datetime import datetime
15-
15+
import warnings
1616

1717
import holodeck as holo
1818
from holodeck import utils, cosmo, log, plot, sam_cython
1919
from holodeck.constants import MPC, YR
2020
from holodeck.sams import cyutils as sam_cyutils
2121

22-
import hasasia.sensitivity as hsen
23-
import hasasia.sim as hsim
24-
import hasasia as has
22+
try:
23+
from sympy import nsolve, Symbol
24+
import hasasia.sensitivity as hsen
25+
import hasasia.sim as hsim
26+
# import hasasia as has
27+
except ImportError as err:
28+
SUBMOD = "detstats"
29+
log.error(f"Failed to import some packages used in `{SUBMOD}` submodule!")
30+
log.exception(err)
31+
log.error(
32+
f"Some required packages for `{SUBMOD}` have been temporarily disabled in the "
33+
"global 'requirements.txt' file, so they are not installed by default! Please install "
34+
"the required packages manually for now, and feel free to raise a github issue."
35+
)
36+
raise
2537

2638
GAMMA_RHO_GRID_PATH = '/Users/emigardiner/GWs/holodeck/output/rho_gamma_grids'
2739
HC_REF15_10YR = 11.2*10**-15
@@ -183,7 +195,7 @@ def _white_noise(delta_t, sigma_i):
183195

184196
######################## Power Spectral Density ########################
185197

186-
def _power_spectral_density(hc_bg, freqs):
198+
def _power_spectral_density(hc_bg, freqs, reshape_freqs=True):
187199
""" Calculate the spectral density S_h(f_k) ~ S_h0(f_k) at the kth frequency
188200
189201
Parameters
@@ -202,8 +214,10 @@ def _power_spectral_density(hc_bg, freqs):
202214
203215
Follows Eq. (25) of Rosado et al. 2015
204216
"""
217+
if reshape_freqs:
218+
freqs = freqs[:,np.newaxis]
205219

206-
S_h = hc_bg**2 / (12 * np.pi**2 * freqs[:,np.newaxis]**3)
220+
S_h = hc_bg**2 / (12 * np.pi**2 * freqs**3)
207221
return S_h
208222

209223

@@ -488,8 +502,9 @@ def detect_bg(thetas, phis, sigmas, fobs, cad, hc_bg, alpha_0=0.001, ret = False
488502

489503

490504

491-
def detect_bg_pta(pulsars, fobs, hc_bg, hc_ss, alpha_0=0.001, ret_snr = False,
492-
red_amp=None, red_gamma=None, ss_noise=True):
505+
def detect_bg_pta(pulsars, fobs, hc_bg, hc_ss=None, custom_noise=None,
506+
alpha_0=0.001, ret_snr = False,
507+
red_amp=None, red_gamma=None, ss_noise=False):
493508
""" Calculate the background detection probability, and all the intermediary steps
494509
from a list of hasasia.Pulsar objects.
495510
@@ -538,6 +553,25 @@ def detect_bg_pta(pulsars, fobs, hc_bg, hc_ss, alpha_0=0.001, ret_snr = False,
538553
Sh_bg = _power_spectral_density(hc_bg[:], fobs)
539554
Sh0_bg = Sh_bg # note this refers to same object, not a copy
540555

556+
# noise spectral density
557+
if custom_noise is not None:
558+
if custom_noise.shape != (len(pulsars), len(fobs), len(hc_bg[0])):
559+
err = f"{custom_noise.shape=}, must be shape (P,F,R)=({len(pulsars)}, {len(fobs)}, {len(hc_bg[0])})"
560+
raise ValueError(err)
561+
noise = custom_noise
562+
else:
563+
# calculate white noise
564+
noise = _white_noise(cad, sigmas)[:,np.newaxis] # P,1
565+
566+
# add red noise
567+
if (red_amp is not None) and (red_gamma is not None):
568+
red_noise = _red_noise(red_amp, red_gamma, fobs)[np.newaxis,:] # (1,F,)
569+
noise = noise + red_noise # (P,F,)
570+
571+
# add single source noise
572+
noise = noise[:,:,np.newaxis]
573+
if ss_noise:
574+
noise = noise + _Sh_ss_noise(hc_ss, fobs) # (P, F, R)
541575
# calculate white noise
542576
noise = _white_noise(cad, sigmas)[:,np.newaxis] # P,1
543577

@@ -872,7 +906,7 @@ def _antenna_pattern_functions(m_hat, n_hat, Omega_hat, pi_hat):
872906
######################## Noise Spectral Density ########################
873907

874908

875-
def _Sh_rest_noise(hc_ss, hc_bg, freqs):
909+
def _Sh_rest_noise(hc_ss, hc_bg, freqs, nexcl=0):
876910
""" Calculate the noise spectral density contribution from all but the current single source.
877911
878912
Parameters
@@ -883,6 +917,10 @@ def _Sh_rest_noise(hc_ss, hc_bg, freqs):
883917
Characteristic strain from all but loudest source at each frequency.
884918
freqs : (F,) 1Darray
885919
Frequency bin centers.
920+
exclude_loudest : int
921+
Number of loudest single sources to exclude from hc_rest noise, in addition
922+
to the source in question.
923+
886924
887925
Returns
888926
-------
@@ -891,10 +929,15 @@ def _Sh_rest_noise(hc_ss, hc_bg, freqs):
891929
892930
Follows Eq. (45) in Rosado et al. 2015.
893931
"""
894-
hc2_louds = np.sum(hc_ss**2, axis=2) # (F,R)
895-
# subtract the single source from rest of loud sources and the background, for each single source
896-
hc2_rest = hc_bg[:,:,np.newaxis]**2 + hc2_louds[:,:,np.newaxis] - hc_ss**2 # (F,R,L)
897-
Sh_rest = hc2_rest / freqs[:,np.newaxis,np.newaxis]**3 /(12 * np.pi**2) # (F,R,L)
932+
933+
if nexcl>0:
934+
Sh_rest = cyutils.Sh_rest(hc_ss, hc_bg, freqs, nexcl)
935+
else:
936+
hc2_louds = np.sum(hc_ss**2, axis=2) # (F,R)
937+
# subtract the single source from rest of loud sources and the background, for each single source
938+
hc2_rest = hc_bg[:,:,np.newaxis]**2 + hc2_louds[:,:,np.newaxis] - hc_ss**2 # (F,R,L)
939+
Sh_rest = hc2_rest / freqs[:,np.newaxis,np.newaxis]**3 /(12 * np.pi**2) # (F,R,L)
940+
898941
return Sh_rest
899942

900943

@@ -913,7 +956,7 @@ def _Sh_ss_noise(hc_ss, freqs):
913956
914957
Returns
915958
-------
916-
Sh_ss : (F,R,L) NDarray of scalars
959+
Sh_ss : (F,R,R) NDarray of scalars
917960
The noise in a single pulsar from other GW sources for detecting each single source.
918961
919962
Follows Eq. (45) in Rosado et al. 2015.
@@ -952,7 +995,8 @@ def _red_noise(red_amp, red_gamma, freqs, f_ref=1/YR):
952995

953996

954997

955-
def _total_noise(delta_t, sigmas, hc_ss, hc_bg, freqs, red_amp=None, red_gamma=None):
998+
def _total_noise(delta_t, sigmas, hc_ss, hc_bg, freqs, red_amp=None, red_gamma=None,
999+
nexcl=0):
9561000
""" Calculate the noise spectral density of each pulsar, as it pertains to single
9571001
source detections, i.e., including the background as a noise source.
9581002
@@ -968,6 +1012,9 @@ def _total_noise(delta_t, sigmas, hc_ss, hc_bg, freqs, red_amp=None, red_gamma=N
9681012
Characteristic strain from all but loudest source at each frequency.
9691013
freqs : (F,) 1Darray
9701014
Frequency bin centers.
1015+
exclude_loudest : int
1016+
Number of loudest single sources to exclude from hc_rest noise
1017+
9711018
9721019
Returns
9731020
-------
@@ -978,13 +1025,57 @@ def _total_noise(delta_t, sigmas, hc_ss, hc_bg, freqs, red_amp=None, red_gamma=N
9781025
"""
9791026

9801027
noise = _white_noise(delta_t, sigmas) # (P,)
981-
Sh_rest = _Sh_rest_noise(hc_ss, hc_bg, freqs) # (F,R,L,)
1028+
Sh_rest = _Sh_rest_noise(hc_ss, hc_bg, freqs, nexcl) # (F,R,L,)
9821029
noise = noise[:,np.newaxis,np.newaxis,np.newaxis] + Sh_rest[np.newaxis,:,:,:] # (P,F,R,L)
9831030
if (red_amp is not None) and (red_gamma is not None):
9841031
red_noise = _red_noise(red_amp, red_gamma, freqs) # (F,)
9851032
noise = noise + red_noise[np.newaxis,:,np.newaxis,np.newaxis] # (P,F,R,L)
9861033
return noise
9871034

1035+
def psrs_spectra_gwbnoise(psrs, fobs, nreals, npsrs, divide_flag=False):
1036+
""" Get GWBSensitivityCurve noise and spectra for psrs
1037+
1038+
Returns
1039+
-------
1040+
spectra :
1041+
noise_gsc : (P,F,R)
1042+
"""
1043+
spectra = []
1044+
for psr in psrs:
1045+
sp = hsen.Spectrum(psr, freqs=fobs)
1046+
sp.NcalInv
1047+
spectra.append(sp)
1048+
sc_bg = hsen.GWBSensitivityCurve(spectra).h_c
1049+
noise_gsc = sc_bg**2 / (12 *np.pi**2 *fobs**3)
1050+
noise_gsc = np.repeat(noise_gsc, npsrs*nreals).reshape(len(fobs), npsrs, nreals) # (F,P,R)
1051+
noise_gsc = np.swapaxes(noise_gsc, 0, 1) # (P,F,R)
1052+
1053+
if divide_flag: noise_gsc *= npsrs*(npsrs-1)
1054+
1055+
return spectra, noise_gsc
1056+
1057+
def _dsc_noise(fobs, nreals, npsrs, nloudest, psrs=None, spectra=None, divide_flag=False):
1058+
""" Get DeterSensitivityCurve noise using either psrs or spectra
1059+
1060+
Returns
1061+
-------
1062+
noise_dsc : (P,F,R,L) NDarray
1063+
"""
1064+
1065+
if spectra is None:
1066+
assert psrs is not None, 'Must provide spectra or psrs'
1067+
spectra = []
1068+
for psr in psrs:
1069+
sp = hsen.Spectrum(psr, freqs=fobs)
1070+
sp.NcalInv
1071+
spectra.append(sp)
1072+
sc_ss = hsen.DeterSensitivityCurve(spectra).h_c
1073+
noise_dsc = sc_ss**2 / (12 *np.pi**2 *fobs**3)
1074+
noise_dsc = np.repeat(noise_dsc, npsrs*nreals*nloudest).reshape(len(fobs), npsrs, nreals, nloudest) # (F,P,R,L)
1075+
noise_dsc = np.swapaxes(noise_dsc, 0, 1) # (P,F,R,L)
1076+
1077+
if divide_flag: noise_dsc *= npsrs*(npsrs-1)
1078+
return noise_dsc
9881079

9891080

9901081
################### GW polarization, phase, amplitude ###################
@@ -1191,7 +1282,7 @@ def _Fe_thresh(Num, alpha_0=0.001, guess=15):
11911282
Fe_bar = Symbol('Fe_bar')
11921283
func = 1 - (1 - (1 + Fe_bar)*np.e**(-Fe_bar))**Num - alpha_0
11931284
Fe_bar = nsolve(func, Fe_bar, guess) # mod from
1194-
return(Fe_bar)
1285+
return Fe_bar
11951286

11961287
def _I1_approx(xx):
11971288
""" Modified Bessel Function of the first kind, first order, expansion for large values.
@@ -1354,7 +1445,7 @@ def _gamma_ssi_cython(rho, grid_path):
13541445
# interpolate for gamma in cython
13551446
rho_flat = rho[:,rr].flatten()
13561447
rsort = np.argsort(rho_flat)
1357-
gamma_flat = sam_cyutils.gamma_of_rho_interp(rho_flat, rsort, rho_interp_grid, gamma_interp_grid)
1448+
gamma_flat = cyutils.gamma_of_rho_interp(rho_flat, rsort, rho_interp_grid, gamma_interp_grid)
13581449
gamma_ssi[:,rr] = gamma_flat.reshape(rho[:,rr].shape)
13591450

13601451

0 commit comments

Comments
 (0)