or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

astrophysics.mddetector.mdfrequencyseries.mdindex.mdplotting.mdsegments.mdsignal-processing.mdspectrogram.mdtimeseries.md

astrophysics.mddocs/

0

# Astrophysics Calculations

1

2

Sensitivity and detection range calculations for gravitational-wave sources including binary inspirals and burst sources. These functions provide essential tools for understanding detector performance and planning astrophysical searches.

3

4

## Capabilities

5

6

### Range Calculations

7

8

Functions for calculating detection ranges for different types of gravitational-wave sources.

9

10

```python { .api }

11

from gwpy.astro import (inspiral_range, inspiral_range_psd,

12

burst_range, burst_range_spectrum,

13

sensemon_range, sensemon_range_psd,

14

range_timeseries, range_spectrogram)

15

16

def inspiral_range(psd, mass1=1.4, mass2=1.4, **kwargs):

17

"""

18

Calculate binary inspiral detection range.

19

20

Parameters:

21

- psd: FrequencySeries, detector power spectral density

22

- mass1: float, primary mass in solar masses

23

- mass2: float, secondary mass in solar masses

24

- snr: float, signal-to-noise ratio threshold (default: 8)

25

- fmin: float, minimum frequency for integration (Hz)

26

- fmax: float, maximum frequency for integration (Hz)

27

28

Returns:

29

Quantity, detection range in Mpc

30

"""

31

32

def inspiral_range_psd(psd, **kwargs):

33

"""

34

Calculate inspiral range from PSD (alias for inspiral_range).

35

36

Parameters:

37

- psd: FrequencySeries, power spectral density

38

- **kwargs: additional parameters for inspiral_range

39

40

Returns:

41

Quantity, detection range in Mpc

42

"""

43

44

def burst_range(spectrum, **kwargs):

45

"""

46

Calculate burst detection range.

47

48

Parameters:

49

- spectrum: FrequencySeries, amplitude spectral density

50

- energy: float, gravitational-wave energy (solar masses × c²)

51

- frequency: float, characteristic frequency (Hz)

52

- snr: float, SNR threshold (default: 8)

53

54

Returns:

55

Quantity, detection range in Mpc

56

"""

57

58

def burst_range_spectrum(spectrum, **kwargs):

59

"""

60

Calculate burst range from spectrum (alias for burst_range).

61

62

Parameters:

63

- spectrum: FrequencySeries, amplitude spectral density

64

- **kwargs: additional parameters for burst_range

65

66

Returns:

67

Quantity, detection range in Mpc

68

"""

69

70

def sensemon_range(psd, **kwargs):

71

"""

72

Calculate SenseMon-style detection range.

73

74

Parameters:

75

- psd: FrequencySeries, power spectral density

76

- mass1: float, primary mass (default: 1.4 solar masses)

77

- mass2: float, secondary mass (default: 1.4 solar masses)

78

79

Returns:

80

Quantity, SenseMon range in Mpc

81

"""

82

83

def sensemon_range_psd(psd, **kwargs):

84

"""

85

Calculate SenseMon range from PSD (alias for sensemon_range).

86

87

Parameters:

88

- psd: FrequencySeries, power spectral density

89

- **kwargs: additional parameters for sensemon_range

90

91

Returns:

92

Quantity, SenseMon range in Mpc

93

"""

94

95

def range_timeseries(timeseries, stride, **kwargs):

96

"""

97

Calculate detection range as a time series.

98

99

Parameters:

100

- timeseries: TimeSeries, input strain data

101

- stride: float, time between range calculations (seconds)

102

- fftlength: float, FFT length for PSD calculation

103

- overlap: float, overlap between FFT segments

104

- **kwargs: additional range calculation parameters

105

106

Returns:

107

TimeSeries, detection range over time

108

"""

109

110

def range_spectrogram(timeseries, stride, **kwargs):

111

"""

112

Calculate range as a time-frequency spectrogram.

113

114

Parameters:

115

- timeseries: TimeSeries, input strain data

116

- stride: float, time between calculations

117

- **kwargs: additional parameters

118

119

Returns:

120

Spectrogram, range evolution over time and frequency

121

"""

122

```

123

124

### Usage Examples

125

126

#### Basic Range Calculations

127

128

```python

129

from gwpy.timeseries import TimeSeries

130

from gwpy.astro import inspiral_range, burst_range

131

132

# Read strain data and calculate PSD

133

strain = TimeSeries.fetch_open_data('H1', 1126259446, 1126259478)

134

psd = strain.psd(fftlength=4, overlap=2)

135

136

# Calculate binary neutron star inspiral range

137

bns_range = inspiral_range(psd, mass1=1.4, mass2=1.4, snr=8)

138

print(f"BNS inspiral range: {bns_range:.1f}")

139

140

# Calculate black hole binary range

141

bbh_range = inspiral_range(psd, mass1=30, mass2=30, snr=8)

142

print(f"BBH inspiral range: {bbh_range:.1f}")

143

144

# Calculate burst range for supernova-like sources

145

asd = psd.sqrt()

146

sn_range = burst_range(asd, energy=1e-8, frequency=235, snr=8)

147

print(f"Supernova burst range: {sn_range:.1f}")

148

```

149

150

#### Range Time Series Analysis

151

152

```python

153

from gwpy.astro import range_timeseries

154

import matplotlib.pyplot as plt

155

156

# Calculate range evolution over time

157

range_ts = range_timeseries(strain,

158

stride=60, # 1-minute intervals

159

fftlength=8, # 8-second FFTs

160

overlap=4, # 4-second overlap

161

mass1=1.4, # BNS masses

162

mass2=1.4)

163

164

# Plot range time series

165

plot = range_ts.plot(figsize=(12, 6))

166

plot.set_ylabel('Inspiral Range [Mpc]')

167

plot.set_title('H1 BNS Inspiral Range Evolution')

168

plot.show()

169

170

# Calculate statistics

171

print(f"Mean range: {range_ts.mean():.1f}")

172

print(f"Range std: {range_ts.std():.1f}")

173

print(f"Best range: {range_ts.max():.1f}")

174

print(f"Worst range: {range_ts.min():.1f}")

175

```

176

177

#### Multi-Detector Range Comparison

178

179

```python

180

from gwpy.timeseries import TimeSeriesDict

181

from gwpy.astro import inspiral_range

182

183

# Get data from multiple detectors

184

data = TimeSeriesDict.fetch_open_data(['H1', 'L1'],

185

start=1126259446,

186

end=1126259478)

187

188

# Calculate PSDs and ranges

189

ranges = {}

190

psds = {}

191

192

for ifo, timeseries in data.items():

193

psds[ifo] = timeseries.psd(fftlength=4, overlap=2)

194

ranges[ifo] = inspiral_range(psds[ifo], mass1=1.4, mass2=1.4)

195

196

# Compare detector performance

197

print("BNS Inspiral Ranges:")

198

for ifo, r in ranges.items():

199

print(f" {ifo}: {r:.1f}")

200

201

# Plot PSD comparison

202

plot = psds['H1'].plot(label='H1', alpha=0.8)

203

plot.add_frequencyseries(psds['L1'], label='L1', alpha=0.8)

204

plot.set_xlabel('Frequency [Hz]')

205

plot.set_ylabel('PSD [strain²/Hz]')

206

plot.set_xlim(10, 2000)

207

plot.set_yscale('log')

208

plot.legend()

209

plot.title('Detector Sensitivity Comparison')

210

plot.show()

211

```

212

213

#### Mass-Dependent Range Analysis

214

215

```python

216

import numpy as np

217

218

# Calculate range for different binary masses

219

masses = np.logspace(0, 2, 20) # 1 to 100 solar masses

220

bns_ranges = []

221

bbh_ranges = []

222

223

for mass in masses:

224

# Equal mass binaries

225

bns_range = inspiral_range(psd, mass1=mass, mass2=mass, snr=8)

226

bns_ranges.append(bns_range.value)

227

228

# Convert to arrays for plotting

229

ranges_array = np.array(bns_ranges)

230

231

# Plot mass-range relationship

232

plt.figure(figsize=(10, 6))

233

plt.loglog(masses, ranges_array, 'b-', linewidth=2,

234

label='Equal mass binaries')

235

plt.xlabel('Component Mass [M☉]')

236

plt.ylabel('Inspiral Range [Mpc]')

237

plt.title('Detection Range vs Binary Mass')

238

plt.grid(True, alpha=0.3)

239

plt.legend()

240

241

# Mark interesting mass ranges

242

plt.axvspan(1, 3, alpha=0.2, color='green', label='Neutron Stars')

243

plt.axvspan(5, 50, alpha=0.2, color='red', label='Stellar Black Holes')

244

plt.legend()

245

plt.show()

246

247

# Find optimal masses

248

max_idx = np.argmax(ranges_array)

249

print(f"Best range: {ranges_array[max_idx]:.1f} Mpc at {masses[max_idx]:.1f} M☉")

250

```

251

252

#### SenseMon Range Monitoring

253

254

```python

255

from gwpy.astro import sensemon_range

256

257

# Calculate SenseMon range (standard monitoring metric)

258

sensemon_bns = sensemon_range(psd, mass1=1.4, mass2=1.4)

259

print(f"SenseMon BNS range: {sensemon_bns:.1f}")

260

261

# Compare with standard inspiral range

262

standard_bns = inspiral_range(psd, mass1=1.4, mass2=1.4)

263

print(f"Standard BNS range: {standard_bns:.1f}")

264

print(f"Ratio: {sensemon_bns/standard_bns:.2f}")

265

266

# Calculate range time series for monitoring

267

sensemon_ts = range_timeseries(strain,

268

stride=300, # 5-minute intervals

269

fftlength=32, # Long FFTs for stability

270

range_func=sensemon_range,

271

mass1=1.4, mass2=1.4)

272

273

# Plot for monitoring dashboard

274

plot = sensemon_ts.plot(figsize=(12, 4))

275

plot.set_ylabel('SenseMon Range [Mpc]')

276

plot.set_title('H1 Detector Range Monitor')

277

plot.axhline(sensemon_ts.mean().value, color='red', linestyle='--',

278

label=f'Mean: {sensemon_ts.mean():.1f}')

279

plot.legend()

280

plot.show()

281

```

282

283

#### Burst Source Range Analysis

284

285

```python

286

# Calculate ranges for different burst sources

287

burst_sources = {

288

'Core Collapse Supernova': {'energy': 1e-8, 'frequency': 235},

289

'Stellar Collapse': {'energy': 1e-7, 'frequency': 150},

290

'Cosmic String Cusp': {'energy': 1e-9, 'frequency': 300}

291

}

292

293

asd = psd.sqrt()

294

burst_ranges = {}

295

296

print("Burst Source Detection Ranges:")

297

for source, params in burst_sources.items():

298

range_val = burst_range(asd,

299

energy=params['energy'],

300

frequency=params['frequency'],

301

snr=8)

302

burst_ranges[source] = range_val

303

print(f" {source}: {range_val:.1f}")

304

305

# Plot burst ranges vs frequency

306

frequencies = [params['frequency'] for params in burst_sources.values()]

307

ranges = [burst_ranges[source].value for source in burst_sources.keys()]

308

309

plt.figure(figsize=(10, 6))

310

plt.scatter(frequencies, ranges, s=100, alpha=0.7)

311

for i, source in enumerate(burst_sources.keys()):

312

plt.annotate(source, (frequencies[i], ranges[i]),

313

xytext=(10, 10), textcoords='offset points')

314

315

plt.xlabel('Characteristic Frequency [Hz]')

316

plt.ylabel('Detection Range [Mpc]')

317

plt.title('Burst Source Detection Ranges')

318

plt.grid(True, alpha=0.3)

319

plt.show()

320

```

321

322

#### Range Spectrogram Analysis

323

324

```python

325

from gwpy.astro import range_spectrogram

326

327

# Calculate range evolution in time-frequency

328

# (Note: This is a conceptual example - actual implementation may vary)

329

long_strain = TimeSeries.fetch_open_data('H1', 1126259446, 1126259446+3600)

330

331

# Create range spectrogram

332

range_spec = range_spectrogram(long_strain,

333

stride=60, # 1-minute time bins

334

fftlength=8, # 8-second FFTs

335

mass1=1.4, mass2=1.4)

336

337

# Plot range evolution

338

plot = range_spec.plot(figsize=(12, 8))

339

plot.set_xlabel('Time')

340

plot.set_ylabel('Frequency [Hz]')

341

plot.set_title('BNS Range Evolution')

342

plot.colorbar(label='Range [Mpc]')

343

plot.show()

344

```

345

346

#### Horizon Distance Calculations

347

348

```python

349

# Calculate horizon distances (maximum possible range)

350

def horizon_distance(psd, mass1=1.4, mass2=1.4, **kwargs):

351

"""Calculate horizon distance (SNR=1 threshold)."""

352

return inspiral_range(psd, mass1=mass1, mass2=mass2, snr=1, **kwargs)

353

354

# Calculate horizons for different mass combinations

355

mass_combinations = [

356

(1.4, 1.4), # BNS

357

(10, 10), # Light BBH

358

(30, 30), # Heavy BBH

359

(1.4, 10), # NSBH

360

]

361

362

print("Horizon Distances (SNR=1):")

363

for m1, m2 in mass_combinations:

364

horizon = horizon_distance(psd, mass1=m1, mass2=m2)

365

detection_range = inspiral_range(psd, mass1=m1, mass2=m2, snr=8)

366

367

print(f" {m1:.1f}-{m2:.1f} M☉:")

368

print(f" Horizon: {horizon:.1f}")

369

print(f" Range (SNR=8): {detection_range:.1f}")

370

print(f" Ratio: {detection_range/horizon:.2f}")

371

```

372

373

#### Network Range Analysis

374

375

```python

376

# Calculate network detection capabilities

377

def network_range(ranges):

378

"""Estimate network detection range from individual detector ranges."""

379

# Simple approximation: geometric mean for coincident detection

380

if len(ranges) == 2:

381

return np.sqrt(ranges[0] * ranges[1])

382

elif len(ranges) == 3:

383

return (ranges[0] * ranges[1] * ranges[2])**(1/3)

384

else:

385

return np.mean(ranges)

386

387

# Multi-detector network analysis

388

detectors = ['H1', 'L1', 'V1']

389

individual_ranges = [150, 140, 90] # Example ranges in Mpc

390

391

network_bns_range = network_range(individual_ranges)

392

393

print("Network Analysis:")

394

for ifo, r in zip(detectors, individual_ranges):

395

print(f" {ifo} range: {r} Mpc")

396

print(f" Network range: {network_bns_range:.1f} Mpc")

397

398

# Calculate detection volume (proportional to range³)

399

volumes = [r**3 for r in individual_ranges]

400

network_volume = network_bns_range**3

401

402

print("\nDetection Volumes (relative):")

403

for ifo, v in zip(detectors, volumes):

404

print(f" {ifo}: {v/1000:.1f} (×10³)")

405

print(f" Network: {network_volume/1000:.1f} (×10³)")

406

```