cows3 0.0.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- cows3-0.0.1/.github/workflows/pypi.yml +118 -0
- cows3-0.0.1/.github/workflows/pytest.yml +31 -0
- cows3-0.0.1/.gitignore +2 -0
- cows3-0.0.1/LICENSE.md +10 -0
- cows3-0.0.1/PKG-INFO +76 -0
- cows3-0.0.1/README.md +42 -0
- cows3-0.0.1/pyproject.toml +50 -0
- cows3-0.0.1/setup.cfg +4 -0
- cows3-0.0.1/setup.py +4 -0
- cows3-0.0.1/src/cows3/__init__.py +0 -0
- cows3-0.0.1/src/cows3/detectorstates.py +143 -0
- cows3-0.0.1/src/cows3/ephemeris.py +10 -0
- cows3-0.0.1/src/cows3/sensitivity.py +38 -0
- cows3-0.0.1/src/cows3/snr.py +190 -0
- cows3-0.0.1/src/cows3.egg-info/PKG-INFO +76 -0
- cows3-0.0.1/src/cows3.egg-info/SOURCES.txt +20 -0
- cows3-0.0.1/src/cows3.egg-info/dependency_links.txt +1 -0
- cows3-0.0.1/src/cows3.egg-info/requires.txt +9 -0
- cows3-0.0.1/src/cows3.egg-info/top_level.txt +1 -0
- cows3-0.0.1/tests/test_detectorstates.py +65 -0
- cows3-0.0.1/tests/test_sensitivity.py +21 -0
- cows3-0.0.1/tests/test_snr.py +51 -0
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
# Taken from https://packaging.python.org/en/latest/tutorials/packaging-projects/
|
|
2
|
+
name: Publish Python 🐍 distribution 📦 to PyPI and TestPyPI
|
|
3
|
+
|
|
4
|
+
on: workflow_dispatch
|
|
5
|
+
|
|
6
|
+
jobs:
|
|
7
|
+
build:
|
|
8
|
+
name: Build distribution 📦
|
|
9
|
+
runs-on: ubuntu-latest
|
|
10
|
+
|
|
11
|
+
steps:
|
|
12
|
+
- uses: actions/checkout@v4
|
|
13
|
+
- name: Set up Python
|
|
14
|
+
uses: actions/setup-python@v5
|
|
15
|
+
with:
|
|
16
|
+
python-version: "3.11"
|
|
17
|
+
- name: Install pypa/build
|
|
18
|
+
run: >-
|
|
19
|
+
python3 -m
|
|
20
|
+
pip install
|
|
21
|
+
build
|
|
22
|
+
--user
|
|
23
|
+
- name: Build a binary wheel and a source tarball
|
|
24
|
+
run: python3 -m build
|
|
25
|
+
- name: Store the distribution packages
|
|
26
|
+
uses: actions/upload-artifact@v4
|
|
27
|
+
with:
|
|
28
|
+
name: python-package-distributions
|
|
29
|
+
path: dist/
|
|
30
|
+
|
|
31
|
+
publish-to-pypi:
|
|
32
|
+
name: >-
|
|
33
|
+
Publish Python 🐍 distribution 📦 to PyPI
|
|
34
|
+
if: startsWith(github.ref, 'refs/tags/') # only publish to PyPI on tag pushes
|
|
35
|
+
needs:
|
|
36
|
+
- build
|
|
37
|
+
runs-on: ubuntu-latest
|
|
38
|
+
environment:
|
|
39
|
+
name: pypi
|
|
40
|
+
url: https://pypi.org/p/foutstep # Replace <package-name> with your PyPI project name
|
|
41
|
+
permissions:
|
|
42
|
+
id-token: write # IMPORTANT: mandatory for trusted publishing
|
|
43
|
+
|
|
44
|
+
steps:
|
|
45
|
+
- name: Download all the dists
|
|
46
|
+
uses: actions/download-artifact@v4
|
|
47
|
+
with:
|
|
48
|
+
name: python-package-distributions
|
|
49
|
+
path: dist/
|
|
50
|
+
- name: Publish distribution 📦 to PyPI
|
|
51
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
52
|
+
|
|
53
|
+
github-release:
|
|
54
|
+
name: >-
|
|
55
|
+
Sign the Python 🐍 distribution 📦 with Sigstore
|
|
56
|
+
and upload them to GitHub Release
|
|
57
|
+
needs:
|
|
58
|
+
- publish-to-pypi
|
|
59
|
+
runs-on: ubuntu-latest
|
|
60
|
+
|
|
61
|
+
permissions:
|
|
62
|
+
contents: write # IMPORTANT: mandatory for making GitHub Releases
|
|
63
|
+
id-token: write # IMPORTANT: mandatory for sigstore
|
|
64
|
+
|
|
65
|
+
steps:
|
|
66
|
+
- name: Download all the dists
|
|
67
|
+
uses: actions/download-artifact@v4
|
|
68
|
+
with:
|
|
69
|
+
name: python-package-distributions
|
|
70
|
+
path: dist/
|
|
71
|
+
- name: Sign the dists with Sigstore
|
|
72
|
+
uses: sigstore/gh-action-sigstore-python@v2.1.1
|
|
73
|
+
with:
|
|
74
|
+
inputs: >-
|
|
75
|
+
./dist/*.tar.gz
|
|
76
|
+
./dist/*.whl
|
|
77
|
+
- name: Create GitHub Release
|
|
78
|
+
env:
|
|
79
|
+
GITHUB_TOKEN: ${{ github.token }}
|
|
80
|
+
run: >-
|
|
81
|
+
gh release create
|
|
82
|
+
'${{ github.ref_name }}'
|
|
83
|
+
--repo '${{ github.repository }}'
|
|
84
|
+
--notes ""
|
|
85
|
+
- name: Upload artifact signatures to GitHub Release
|
|
86
|
+
env:
|
|
87
|
+
GITHUB_TOKEN: ${{ github.token }}
|
|
88
|
+
# Upload to GitHub Release using the `gh` CLI.
|
|
89
|
+
# `dist/` contains the built packages, and the
|
|
90
|
+
# sigstore-produced signatures and certificates.
|
|
91
|
+
run: >-
|
|
92
|
+
gh release upload
|
|
93
|
+
'${{ github.ref_name }}' dist/**
|
|
94
|
+
--repo '${{ github.repository }}'
|
|
95
|
+
|
|
96
|
+
publish-to-testpypi:
|
|
97
|
+
name: Publish Python 🐍 distribution 📦 to TestPyPI
|
|
98
|
+
needs:
|
|
99
|
+
- build
|
|
100
|
+
runs-on: ubuntu-latest
|
|
101
|
+
|
|
102
|
+
environment:
|
|
103
|
+
name: testpypi
|
|
104
|
+
url: https://test.pypi.org/p/foutstep
|
|
105
|
+
|
|
106
|
+
permissions:
|
|
107
|
+
id-token: write # IMPORTANT: mandatory for trusted publishing
|
|
108
|
+
|
|
109
|
+
steps:
|
|
110
|
+
- name: Download all the dists
|
|
111
|
+
uses: actions/download-artifact@v4
|
|
112
|
+
with:
|
|
113
|
+
name: python-package-distributions
|
|
114
|
+
path: dist/
|
|
115
|
+
- name: Publish distribution 📦 to TestPyPI
|
|
116
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
117
|
+
with:
|
|
118
|
+
repository-url: https://test.pypi.org/legacy/
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
|
|
2
|
+
name: Run pytest
|
|
3
|
+
|
|
4
|
+
on:
|
|
5
|
+
push:
|
|
6
|
+
branches: [ "main" ]
|
|
7
|
+
pull_request:
|
|
8
|
+
branches: [ "main" ]
|
|
9
|
+
|
|
10
|
+
permissions:
|
|
11
|
+
contents: read
|
|
12
|
+
|
|
13
|
+
jobs:
|
|
14
|
+
build:
|
|
15
|
+
|
|
16
|
+
runs-on: ubuntu-latest
|
|
17
|
+
|
|
18
|
+
steps:
|
|
19
|
+
- uses: actions/checkout@v4
|
|
20
|
+
- name: Set up Python 3.11
|
|
21
|
+
uses: actions/setup-python@v3
|
|
22
|
+
with:
|
|
23
|
+
python-version: "3.11"
|
|
24
|
+
- name: Install dependencies
|
|
25
|
+
run: |
|
|
26
|
+
python -m pip install --upgrade pip
|
|
27
|
+
pip install pytest .
|
|
28
|
+
- name: Test with pytest
|
|
29
|
+
run: |
|
|
30
|
+
pytest
|
|
31
|
+
|
cows3-0.0.1/.gitignore
ADDED
cows3-0.0.1/LICENSE.md
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Rodrigo Tenorio, Lorenzo Mirasola
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
6
|
+
|
|
7
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
10
|
+
|
cows3-0.0.1/PKG-INFO
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: cows3
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: Continuous-wave search sensitivity simulator
|
|
5
|
+
Author-email: Rodrigo Tenorio <rodrigo.tenorio.marquez@gmail.com>, Lorenzo Mirasola <lorenzo.mirasola@ca.infn.it>
|
|
6
|
+
License: MIT License
|
|
7
|
+
|
|
8
|
+
Copyright (c) 2024 Rodrigo Tenorio, Lorenzo Mirasola
|
|
9
|
+
|
|
10
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
13
|
+
|
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
Project-URL: Homepage, https://github.com/Rodrigo-Tenorio/cows3
|
|
18
|
+
Project-URL: Issues, https://github.com/Rodrigo-Tenorio/cows3/issues
|
|
19
|
+
Classifier: Programming Language :: Python :: 3
|
|
20
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
21
|
+
Classifier: Topic :: Scientific/Engineering :: Astronomy
|
|
22
|
+
Classifier: Topic :: Scientific/Engineering :: Physics
|
|
23
|
+
Requires-Python: >=3.11
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
License-File: LICENSE.md
|
|
26
|
+
Requires-Dist: lalsuite
|
|
27
|
+
Requires-Dist: numpy
|
|
28
|
+
Requires-Dist: scipy
|
|
29
|
+
Requires-Dist: solar_system_ephemerides
|
|
30
|
+
Provides-Extra: dev
|
|
31
|
+
Requires-Dist: black; extra == "dev"
|
|
32
|
+
Requires-Dist: flake8; extra == "dev"
|
|
33
|
+
Requires-Dist: pytest; extra == "dev"
|
|
34
|
+
|
|
35
|
+
# Continuous-wave search sensitivity simulator (COWS3)
|
|
36
|
+
|
|
37
|
+
A Python package to estimate the sensitivity of general
|
|
38
|
+
continuous gravitational-wave searches.
|
|
39
|
+
|
|
40
|
+
The method should be equivalent to the semi-analytical approach derived in
|
|
41
|
+
[Dreissigacker, Prix, Wette (2018)](https://arxiv.org/abs/1808.02459) and
|
|
42
|
+
implemented in [Octapps](https://github.com/octapps/octapps), but here we
|
|
43
|
+
implement it in Python to make it more convenient to use.
|
|
44
|
+
|
|
45
|
+
## Citing this work
|
|
46
|
+
|
|
47
|
+
If COWS3 was useful to your research, we would appreciate if you cited
|
|
48
|
+
[Mirasola & Tenorio (2024)](https://arxiv.org/abs/2405.18934) where this
|
|
49
|
+
implementation was first presented:
|
|
50
|
+
```
|
|
51
|
+
@article{Mirasola:2024lcq,
|
|
52
|
+
author = "Mirasola, Lorenzo and Tenorio, Rodrigo",
|
|
53
|
+
title = "{Towards a computationally-efficient follow-up pipeline for blind continuous gravitational-wave searches}",
|
|
54
|
+
eprint = "2405.18934",
|
|
55
|
+
archivePrefix = "arXiv",
|
|
56
|
+
primaryClass = "gr-qc",
|
|
57
|
+
reportNumber = "LIGO-P2400221",
|
|
58
|
+
month = "5",
|
|
59
|
+
year = "2024",
|
|
60
|
+
journal = "arXiv e-prints"
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
as well as a Zenodo release of this software.
|
|
64
|
+
|
|
65
|
+
For the semi-analytical sensitivity estimation method you should also cite
|
|
66
|
+
[Wette (2012)](https://arxiv.org/abs/1111.5650) and
|
|
67
|
+
[Dreissigacker, Prix, Wette (2018)](https://arxiv.org/abs/1808.02459). Also,
|
|
68
|
+
this package makes extensive use of SWIG bindings, so please cite
|
|
69
|
+
[Wette (2021)](https://arxiv.org/abs/2012.09552) as well.
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
## Authors
|
|
73
|
+
- Rodrigo Tenorio
|
|
74
|
+
- Lorenzo Mirasola
|
|
75
|
+
|
|
76
|
+
|
cows3-0.0.1/README.md
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# Continuous-wave search sensitivity simulator (COWS3)
|
|
2
|
+
|
|
3
|
+
A Python package to estimate the sensitivity of general
|
|
4
|
+
continuous gravitational-wave searches.
|
|
5
|
+
|
|
6
|
+
The method should be equivalent to the semi-analytical approach derived in
|
|
7
|
+
[Dreissigacker, Prix, Wette (2018)](https://arxiv.org/abs/1808.02459) and
|
|
8
|
+
implemented in [Octapps](https://github.com/octapps/octapps), but here we
|
|
9
|
+
implement it in Python to make it more convenient to use.
|
|
10
|
+
|
|
11
|
+
## Citing this work
|
|
12
|
+
|
|
13
|
+
If COWS3 was useful to your research, we would appreciate if you cited
|
|
14
|
+
[Mirasola & Tenorio (2024)](https://arxiv.org/abs/2405.18934) where this
|
|
15
|
+
implementation was first presented:
|
|
16
|
+
```
|
|
17
|
+
@article{Mirasola:2024lcq,
|
|
18
|
+
author = "Mirasola, Lorenzo and Tenorio, Rodrigo",
|
|
19
|
+
title = "{Towards a computationally-efficient follow-up pipeline for blind continuous gravitational-wave searches}",
|
|
20
|
+
eprint = "2405.18934",
|
|
21
|
+
archivePrefix = "arXiv",
|
|
22
|
+
primaryClass = "gr-qc",
|
|
23
|
+
reportNumber = "LIGO-P2400221",
|
|
24
|
+
month = "5",
|
|
25
|
+
year = "2024",
|
|
26
|
+
journal = "arXiv e-prints"
|
|
27
|
+
}
|
|
28
|
+
```
|
|
29
|
+
as well as a Zenodo release of this software.
|
|
30
|
+
|
|
31
|
+
For the semi-analytical sensitivity estimation method you should also cite
|
|
32
|
+
[Wette (2012)](https://arxiv.org/abs/1111.5650) and
|
|
33
|
+
[Dreissigacker, Prix, Wette (2018)](https://arxiv.org/abs/1808.02459). Also,
|
|
34
|
+
this package makes extensive use of SWIG bindings, so please cite
|
|
35
|
+
[Wette (2021)](https://arxiv.org/abs/2012.09552) as well.
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
## Authors
|
|
39
|
+
- Rodrigo Tenorio
|
|
40
|
+
- Lorenzo Mirasola
|
|
41
|
+
|
|
42
|
+
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=64", "setuptools_scm>=8"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
authors = [
|
|
7
|
+
{name = "Rodrigo Tenorio", email = "rodrigo.tenorio.marquez@gmail.com"},
|
|
8
|
+
{name = "Lorenzo Mirasola", email = "lorenzo.mirasola@ca.infn.it"},
|
|
9
|
+
]
|
|
10
|
+
classifiers = [
|
|
11
|
+
"Programming Language :: Python :: 3",
|
|
12
|
+
"License :: OSI Approved :: MIT License",
|
|
13
|
+
"Topic :: Scientific/Engineering :: Astronomy",
|
|
14
|
+
"Topic :: Scientific/Engineering :: Physics"
|
|
15
|
+
]
|
|
16
|
+
dependencies = [
|
|
17
|
+
"lalsuite",
|
|
18
|
+
"numpy",
|
|
19
|
+
"scipy",
|
|
20
|
+
"solar_system_ephemerides",
|
|
21
|
+
]
|
|
22
|
+
description = "Continuous-wave search sensitivity simulator"
|
|
23
|
+
dynamic = ["version"]
|
|
24
|
+
license = {file = "LICENSE.md"}
|
|
25
|
+
name = "cows3"
|
|
26
|
+
readme = "README.md"
|
|
27
|
+
requires-python = ">=3.11"
|
|
28
|
+
|
|
29
|
+
[project.optional-dependencies]
|
|
30
|
+
dev = [
|
|
31
|
+
"black",
|
|
32
|
+
"flake8",
|
|
33
|
+
"pytest"
|
|
34
|
+
]
|
|
35
|
+
|
|
36
|
+
[project.urls]
|
|
37
|
+
Homepage = "https://github.com/Rodrigo-Tenorio/cows3"
|
|
38
|
+
Issues = "https://github.com/Rodrigo-Tenorio/cows3/issues"
|
|
39
|
+
|
|
40
|
+
[tool.setuptools.packages.find]
|
|
41
|
+
where = ["src"]
|
|
42
|
+
include = ["cows3"]
|
|
43
|
+
|
|
44
|
+
[tool.setuptools_scm]
|
|
45
|
+
|
|
46
|
+
[tool.pytest.ini_options]
|
|
47
|
+
log_cli = true
|
|
48
|
+
log_cli_level = "DEBUG"
|
|
49
|
+
log_file_level = "DEBUG"
|
|
50
|
+
|
cows3-0.0.1/setup.cfg
ADDED
cows3-0.0.1/setup.py
ADDED
|
File without changes
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
|
|
3
|
+
import lal
|
|
4
|
+
import lalpulsar
|
|
5
|
+
import numpy as np
|
|
6
|
+
|
|
7
|
+
from .ephemeris import DEFAULT_EPHEMERIS
|
|
8
|
+
|
|
9
|
+
logger = logging.getLogger(__name__)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class MultiDetectorStates:
|
|
13
|
+
"""
|
|
14
|
+
Python interface to `XLALGetMultiDetectorStates` and
|
|
15
|
+
`XLALGetMultiDetectorStatesFromMultiSFTs`.
|
|
16
|
+
|
|
17
|
+
Parameters
|
|
18
|
+
----------
|
|
19
|
+
timestamps:
|
|
20
|
+
Dictionary containing the GPS timestamps at which detector
|
|
21
|
+
states will be retrieved.
|
|
22
|
+
Keys MUST be two-character detector names as described in LALSuite;
|
|
23
|
+
values MUST be numpy arrays containing the timestamps.
|
|
24
|
+
E.g. for an observing run from GPS 1 to GPS 5 using LIGO Hanford
|
|
25
|
+
and LIGO Livingston:
|
|
26
|
+
```
|
|
27
|
+
timestamps = {
|
|
28
|
+
"H1": np.array([1, 2, 3, 4, 5]),
|
|
29
|
+
"L1": np.array([1, 2, 3, 4, 5])
|
|
30
|
+
}
|
|
31
|
+
```
|
|
32
|
+
T_sft:
|
|
33
|
+
Time period covered for each timestamp. Does not need to coincide
|
|
34
|
+
with the separation between consecutive timestamps. It will be floored
|
|
35
|
+
using `int`.
|
|
36
|
+
t_offset:
|
|
37
|
+
Time offset with respect to the timestamp at which the detector
|
|
38
|
+
state will be retrieved. Defaults to LALSuite's behaviour.
|
|
39
|
+
ephemeris:
|
|
40
|
+
Default uses `solar_system_ephemerides` to get lalsuite's default.
|
|
41
|
+
"""
|
|
42
|
+
|
|
43
|
+
def __init__(
|
|
44
|
+
self,
|
|
45
|
+
timestamps: dict[str, np.array],
|
|
46
|
+
T_sft: int,
|
|
47
|
+
t_offset: int | None = None,
|
|
48
|
+
ephemeris: lalpulsar.EphemerisData = DEFAULT_EPHEMERIS,
|
|
49
|
+
):
|
|
50
|
+
self.timestamps = timestamps
|
|
51
|
+
self.T_sft = T_sft
|
|
52
|
+
self.t_offset = t_offset
|
|
53
|
+
self.ephemeris = ephemeris
|
|
54
|
+
|
|
55
|
+
@property
|
|
56
|
+
def Series(self) -> lalpulsar.MultiDetectorStateSeries:
|
|
57
|
+
"""
|
|
58
|
+
Return lalpulsar.MultiDetectorStateSeries constructed using the instance's attributes.
|
|
59
|
+
"""
|
|
60
|
+
return lalpulsar.GetMultiDetectorStates(
|
|
61
|
+
multiTS=self.multi_timestamps,
|
|
62
|
+
multiIFO=self.multi_lal_detector,
|
|
63
|
+
edat=self.ephemeris,
|
|
64
|
+
tOffset=self.t_offset,
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
@property
|
|
68
|
+
def velocities(self) -> dict[str, np.ndarray]:
|
|
69
|
+
"""
|
|
70
|
+
Extracts detector velocity vectors into numpy arrays.
|
|
71
|
+
|
|
72
|
+
Returns
|
|
73
|
+
-------
|
|
74
|
+
velocities:
|
|
75
|
+
Dictionary. Keys refer to detector's 2-character prefix,
|
|
76
|
+
values are (3, num_timestamps) numpy arrays.
|
|
77
|
+
"""
|
|
78
|
+
|
|
79
|
+
mdss = self.Series
|
|
80
|
+
|
|
81
|
+
velocities = {}
|
|
82
|
+
|
|
83
|
+
for ifo_ind in range(mdss.length):
|
|
84
|
+
ifo_name = mdss.data[ifo_ind].detector.frDetector.prefix
|
|
85
|
+
velocities[ifo_name] = np.vstack(
|
|
86
|
+
[data.vDetector for data in mdss.data[ifo_ind].data]
|
|
87
|
+
).T
|
|
88
|
+
|
|
89
|
+
return velocities
|
|
90
|
+
|
|
91
|
+
@property
|
|
92
|
+
def timestamps(self) -> dict[str, np.ndarray]:
|
|
93
|
+
return self._timestamps
|
|
94
|
+
|
|
95
|
+
@property
|
|
96
|
+
def T_sft(self) -> int:
|
|
97
|
+
return self._T_sft
|
|
98
|
+
|
|
99
|
+
@property
|
|
100
|
+
def t_offset(self) -> int | float:
|
|
101
|
+
return self._t_offset
|
|
102
|
+
|
|
103
|
+
@property
|
|
104
|
+
def multi_lal_detector(self) -> lalpulsar.MultiLALDetector:
|
|
105
|
+
return self._multi_lal_detector
|
|
106
|
+
|
|
107
|
+
@property
|
|
108
|
+
def multi_timestamps(self) -> lalpulsar.MultiLIGOTimeGPSVector:
|
|
109
|
+
return self._multi_timestamps
|
|
110
|
+
|
|
111
|
+
@timestamps.setter
|
|
112
|
+
def timestamps(self, new_timestamps: dict):
|
|
113
|
+
|
|
114
|
+
self._timestamps = new_timestamps
|
|
115
|
+
|
|
116
|
+
self._multi_lal_detector = lalpulsar.MultiLALDetector()
|
|
117
|
+
lalpulsar.ParseMultiLALDetector(self._multi_lal_detector, [*self._timestamps])
|
|
118
|
+
|
|
119
|
+
self._multi_timestamps = lalpulsar.CreateMultiLIGOTimeGPSVector(
|
|
120
|
+
self._multi_lal_detector.length
|
|
121
|
+
)
|
|
122
|
+
for ind, ifo in enumerate(new_timestamps):
|
|
123
|
+
seconds_array = np.floor(new_timestamps[ifo])
|
|
124
|
+
nanoseconds_array = np.floor(1e9 * (new_timestamps[ifo] - seconds_array))
|
|
125
|
+
|
|
126
|
+
self._multi_timestamps.data[ind] = lalpulsar.CreateTimestampVector(
|
|
127
|
+
seconds_array.shape[0]
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
for ts_ind in range(self._multi_timestamps.data[ind].length):
|
|
131
|
+
self._multi_timestamps.data[ind].data[ts_ind] = lal.LIGOTimeGPS(
|
|
132
|
+
int(seconds_array[ts_ind]), int(nanoseconds_array[ts_ind])
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
@T_sft.setter
|
|
136
|
+
def T_sft(self, new_T_sft: int):
|
|
137
|
+
self._T_sft = int(new_T_sft)
|
|
138
|
+
for ifo_ind in range(self.multi_timestamps.length):
|
|
139
|
+
self._multi_timestamps.data[ifo_ind].deltaT = self._T_sft
|
|
140
|
+
|
|
141
|
+
@t_offset.setter
|
|
142
|
+
def t_offset(self, new_t_offset: int | None):
|
|
143
|
+
self._t_offset = new_t_offset if new_t_offset is not None else 0.5 * self.T_sft
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
from scipy import integrate, stats
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def pfd_Fstatistic(
|
|
6
|
+
twoF_threshold: float | np.ndarray,
|
|
7
|
+
depth: float | np.ndarray,
|
|
8
|
+
num_segments: int | np.ndarray,
|
|
9
|
+
unitD_rho2_bins: np.ndarray,
|
|
10
|
+
unitD_rho2_pdf: np.ndarray,
|
|
11
|
+
):
|
|
12
|
+
"""
|
|
13
|
+
Compute the false-dismissal probability for a semicoherent F-statistic
|
|
14
|
+
for a population of signals at a sensitivity depth `depth` given
|
|
15
|
+
a unit-depth SNR^2 `unitD_rho2_pdf`.
|
|
16
|
+
Integration is performed across the last axis of the arrays.
|
|
17
|
+
|
|
18
|
+
twoF_threshold:
|
|
19
|
+
Threshold at which the false-dismissal probability will be computed.
|
|
20
|
+
This threshold corresponds to the semicoherent twoF statistic,
|
|
21
|
+
which is distributed as a chi-squared distribution with `4 * num_segments`
|
|
22
|
+
degrees of freedom in Gaussian noise.
|
|
23
|
+
depth:
|
|
24
|
+
Depth of the signal population.
|
|
25
|
+
num_segments:
|
|
26
|
+
Number of segments over which the semicoherent F-statistic is computed.
|
|
27
|
+
unitD_rho2_bins:
|
|
28
|
+
Values at which the unit-depth SNR^2 pdf is evaluated
|
|
29
|
+
unitD_rho2_pdf:
|
|
30
|
+
PDF of the unitary-depth signal distribution. This is the
|
|
31
|
+
``geometric factor'' R in Dreissigacker+ arXiv:1808.024
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
cdf_2F_rho2 = stats.ncx2(df=4 * num_segments, nc=unitD_rho2_bins).cdf(
|
|
35
|
+
twoF_threshold
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
return integrate.simpson(y=unitD_rho2_pdf * cdf_2F_rho2, x=unitD_rho2_pdf)
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
from functools import cache
|
|
2
|
+
import logging
|
|
3
|
+
|
|
4
|
+
import lal
|
|
5
|
+
import lalpulsar
|
|
6
|
+
import numpy as np
|
|
7
|
+
|
|
8
|
+
logger = logging.getLogger(__name__)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class SignalToNoiseRatio:
|
|
12
|
+
r"""Compute the optimal SNR of a CW signal as expected in Gaussian noise.
|
|
13
|
+
|
|
14
|
+
The definition of SNR (shortcut for "optimal signal-to-noise ratio")
|
|
15
|
+
is taken from Eq. (76) of https://dcc.ligo.org/T0900149-v6/public and is
|
|
16
|
+
such that :math:`\langle 2\mathcal{F}\rangle = 4 + \textrm{SNR}^2`,
|
|
17
|
+
where :math:`\langle 2\mathcal{F}\rangle` represents the expected
|
|
18
|
+
value over noise realizations of twice the F-statistic of a template
|
|
19
|
+
perfectly matched to an existing signal in the data.
|
|
20
|
+
|
|
21
|
+
Computing :math:`\textrm{SNR}^2` requires two quantities:
|
|
22
|
+
|
|
23
|
+
* | The antenna pattern matrix :math:`\mathcal{M}`, which depends on the sky position :math:`\vec{n}`
|
|
24
|
+
| and polarization angle :math:`\psi` and encodes the effect of the detector's antenna pattern response
|
|
25
|
+
| over the course of the observing run.
|
|
26
|
+
* | The JKS amplitude parameters :math:`(\mathcal{A}^0, \mathcal{A}^1, \mathcal{A}^2, \mathcal{A}^3)`
|
|
27
|
+
| [JKS1998]_ which are functions of the CW's amplitude parameters :math:`(h_0,\cos\iota, \psi, \phi_0)` or,
|
|
28
|
+
| alternatively, :math:`(A_{+}, A_{\times}, \psi, \phi_0)`.
|
|
29
|
+
|
|
30
|
+
.. [JKS1998] `Jaranowski, Krolak, Schuz Phys. Rev. D58 063001, 1998 <https://arxiv.org/abs/gr-qc/9804014>`_
|
|
31
|
+
|
|
32
|
+
Parameters
|
|
33
|
+
----------
|
|
34
|
+
mdss: lalpulsar.MultiDetectorStateSeries
|
|
35
|
+
MultiDetectorStateSeries as produced by DetectorStates.
|
|
36
|
+
Provides the required information to compute the antenna pattern contribution.
|
|
37
|
+
noise_weights: Union[lalpulsar.MultiNoiseWeights, None]
|
|
38
|
+
Optional, incompatible with `assumeSqrtSX`.
|
|
39
|
+
Can be computed from SFTs using `SignalToNoiseRatio.from_sfts`.
|
|
40
|
+
Noise weights to account for a varying noise floor or unequal noise
|
|
41
|
+
floors in different detectors.
|
|
42
|
+
assumeSqrtSX: float
|
|
43
|
+
Optional, incompatible with `noise_weights`.
|
|
44
|
+
Single-sided amplitude spectral density (ASD) of the detector noise.
|
|
45
|
+
This value is used for all detectors, meaning it's not currently possible to manually
|
|
46
|
+
specify different noise floors without creating SFT files.
|
|
47
|
+
(To be improved in the future; developer note:
|
|
48
|
+
will require SWIG constructor for MultiNoiseWeights.)
|
|
49
|
+
|
|
50
|
+
This code is a subset of that under `snr.py` in [PyFstat](https://github.com/PyFstat/PyFstat).
|
|
51
|
+
|
|
52
|
+
"""
|
|
53
|
+
|
|
54
|
+
def __init__(
|
|
55
|
+
self,
|
|
56
|
+
mdss: lalpulsar.MultiDetectorStateSeries,
|
|
57
|
+
noise_weights: lalpulsar.MultiNoiseWeights | None = None,
|
|
58
|
+
assumeSqrtSX: float | None = None,
|
|
59
|
+
):
|
|
60
|
+
|
|
61
|
+
self.mdss = mdss
|
|
62
|
+
self.noise_weights = noise_weights
|
|
63
|
+
self.assumeSqrtSX = assumeSqrtSX
|
|
64
|
+
|
|
65
|
+
@property
|
|
66
|
+
def mdss(self) -> lalpulsar.MultiDetectorStateSeries:
|
|
67
|
+
return self._mdss
|
|
68
|
+
|
|
69
|
+
@property
|
|
70
|
+
def noise_weights(self) -> lalpulsar.MultiNoiseWeights:
|
|
71
|
+
return self._noise_weights
|
|
72
|
+
|
|
73
|
+
@property
|
|
74
|
+
def assumeSqrtSX(self) -> float | None:
|
|
75
|
+
return self._assumeSqrtSX
|
|
76
|
+
|
|
77
|
+
@mdss.setter
|
|
78
|
+
def mdss(self, new_mdss: lalpulsar.MultiDetectorStateSeries):
|
|
79
|
+
self._mdss = new_mdss
|
|
80
|
+
self._T_sft = new_mdss.data[0].deltaT
|
|
81
|
+
|
|
82
|
+
@noise_weights.setter
|
|
83
|
+
def noise_weights(self, new_weights: lalpulsar.MultiNoiseWeights):
|
|
84
|
+
if (new_weights is not None) and (
|
|
85
|
+
getattr(self, "assumeSqrtSX", None) is not None
|
|
86
|
+
):
|
|
87
|
+
raise ValueError(
|
|
88
|
+
"Cannot set `noise_weights` if `assumeSqrtSX is already set!"
|
|
89
|
+
)
|
|
90
|
+
self._noise_weights = new_weights
|
|
91
|
+
self._Sinv_Tsft = None
|
|
92
|
+
|
|
93
|
+
@assumeSqrtSX.setter
|
|
94
|
+
def assumeSqrtSX(self, new_sqrtSX: float):
|
|
95
|
+
if getattr(self, "noise_weights", None) is not None:
|
|
96
|
+
raise ValueError(
|
|
97
|
+
"Cannot set `assumeSqrtSX' if `noise_weights` is already set!"
|
|
98
|
+
)
|
|
99
|
+
self._assumeSqrtSX = new_sqrtSX
|
|
100
|
+
self._T_sft = self.mdss.data[0].deltaT
|
|
101
|
+
self._Sinv_Tsft = self._T_sft / new_sqrtSX**2
|
|
102
|
+
|
|
103
|
+
def compute_snr2(
|
|
104
|
+
self,
|
|
105
|
+
Alpha: float,
|
|
106
|
+
Delta: float,
|
|
107
|
+
psi: float,
|
|
108
|
+
phi0: float,
|
|
109
|
+
aPlus: float,
|
|
110
|
+
aCross: float,
|
|
111
|
+
) -> float:
|
|
112
|
+
r"""
|
|
113
|
+
Compute the :math:`\textrm{SNR}^2` of a CW signal using XLALComputeOptimalSNR2FromMmunu.
|
|
114
|
+
Parameters correspond to the standard ones used to describe a CW
|
|
115
|
+
(see e.g. Eqs. (16), (26), (30) of https://dcc.ligo.org/T0900149-v6/public ).
|
|
116
|
+
|
|
117
|
+
Mind that this function returns *squared* SNR
|
|
118
|
+
(Eq. (76) of https://dcc.ligo.org/T0900149-v6/public ),
|
|
119
|
+
which can be directly related to the expected F-statistic as
|
|
120
|
+
:math:`\langle 2\mathcal{F}\rangle = 4 + \textrm{SNR}^2`.
|
|
121
|
+
|
|
122
|
+
Parameters
|
|
123
|
+
----------
|
|
124
|
+
Alpha: float
|
|
125
|
+
Right ascension (equatorial longitude) of the signal in radians.
|
|
126
|
+
Delta: float
|
|
127
|
+
Declination (equatorial latitude) of the signal in radians.
|
|
128
|
+
psi: float
|
|
129
|
+
Polarization angle.
|
|
130
|
+
phi0: float
|
|
131
|
+
Initial phase.
|
|
132
|
+
aPlus: float
|
|
133
|
+
Plus polarization amplitude, equal to `0.5 * h0 (1 + cosi^2)`.
|
|
134
|
+
aCross: float
|
|
135
|
+
Cross polarization amplitude, equal to `h0 * cosi`.
|
|
136
|
+
|
|
137
|
+
Returns
|
|
138
|
+
-------
|
|
139
|
+
SNR^2: float
|
|
140
|
+
Squared signal-to-noise ratio of a CW signal consistent
|
|
141
|
+
with the specified parameters in the specified detector
|
|
142
|
+
network.
|
|
143
|
+
"""
|
|
144
|
+
|
|
145
|
+
Aphys = lalpulsar.PulsarAmplitudeParams()
|
|
146
|
+
Aphys.psi = psi
|
|
147
|
+
Aphys.phi0 = phi0
|
|
148
|
+
Aphys.aPlus = aPlus
|
|
149
|
+
Aphys.aCross = aCross
|
|
150
|
+
|
|
151
|
+
M = self.compute_Mmunu(Alpha=Alpha, Delta=Delta)
|
|
152
|
+
|
|
153
|
+
return lalpulsar.ComputeOptimalSNR2FromMmunu(Aphys, M)
|
|
154
|
+
|
|
155
|
+
def compute_Mmunu(self, Alpha: float, Delta: float) -> float:
|
|
156
|
+
"""
|
|
157
|
+
Compute Mmunu matrix at a specific sky position using the detector states
|
|
158
|
+
(and possible noise weights) given at initialization time.
|
|
159
|
+
If no noise weights were given, unit weights are assumed.
|
|
160
|
+
|
|
161
|
+
Parameters
|
|
162
|
+
----------
|
|
163
|
+
Alpha: float
|
|
164
|
+
Right ascension (equatorial longitude) of the signal in radians.
|
|
165
|
+
Delta: float
|
|
166
|
+
Declination (equatorial latitude) of the signal in radians.
|
|
167
|
+
|
|
168
|
+
Returns
|
|
169
|
+
-------
|
|
170
|
+
Mmunu: lalpulsar.AntennaPatternMatrix
|
|
171
|
+
Mmunu matrix encoding the response of the given detector network
|
|
172
|
+
to a CW at the specified sky position.
|
|
173
|
+
"""
|
|
174
|
+
|
|
175
|
+
sky = lal.SkyPosition()
|
|
176
|
+
sky.longitude = Alpha
|
|
177
|
+
sky.latitude = Delta
|
|
178
|
+
sky.system = lal.COORDINATESYSTEM_EQUATORIAL
|
|
179
|
+
lal.NormalizeSkyPosition(sky.longitude, sky.latitude)
|
|
180
|
+
|
|
181
|
+
Mmunu = lalpulsar.ComputeMultiAMCoeffs(
|
|
182
|
+
multiDetStates=self.mdss,
|
|
183
|
+
multiWeights=self.noise_weights,
|
|
184
|
+
skypos=sky,
|
|
185
|
+
).Mmunu
|
|
186
|
+
|
|
187
|
+
if self.noise_weights is None:
|
|
188
|
+
Mmunu.Sinv_Tsft = self._Sinv_Tsft
|
|
189
|
+
|
|
190
|
+
return Mmunu
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: cows3
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: Continuous-wave search sensitivity simulator
|
|
5
|
+
Author-email: Rodrigo Tenorio <rodrigo.tenorio.marquez@gmail.com>, Lorenzo Mirasola <lorenzo.mirasola@ca.infn.it>
|
|
6
|
+
License: MIT License
|
|
7
|
+
|
|
8
|
+
Copyright (c) 2024 Rodrigo Tenorio, Lorenzo Mirasola
|
|
9
|
+
|
|
10
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
13
|
+
|
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
Project-URL: Homepage, https://github.com/Rodrigo-Tenorio/cows3
|
|
18
|
+
Project-URL: Issues, https://github.com/Rodrigo-Tenorio/cows3/issues
|
|
19
|
+
Classifier: Programming Language :: Python :: 3
|
|
20
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
21
|
+
Classifier: Topic :: Scientific/Engineering :: Astronomy
|
|
22
|
+
Classifier: Topic :: Scientific/Engineering :: Physics
|
|
23
|
+
Requires-Python: >=3.11
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
License-File: LICENSE.md
|
|
26
|
+
Requires-Dist: lalsuite
|
|
27
|
+
Requires-Dist: numpy
|
|
28
|
+
Requires-Dist: scipy
|
|
29
|
+
Requires-Dist: solar_system_ephemerides
|
|
30
|
+
Provides-Extra: dev
|
|
31
|
+
Requires-Dist: black; extra == "dev"
|
|
32
|
+
Requires-Dist: flake8; extra == "dev"
|
|
33
|
+
Requires-Dist: pytest; extra == "dev"
|
|
34
|
+
|
|
35
|
+
# Continuous-wave search sensitivity simulator (COWS3)
|
|
36
|
+
|
|
37
|
+
A Python package to estimate the sensitivity of general
|
|
38
|
+
continuous gravitational-wave searches.
|
|
39
|
+
|
|
40
|
+
The method should be equivalent to the semi-analytical approach derived in
|
|
41
|
+
[Dreissigacker, Prix, Wette (2018)](https://arxiv.org/abs/1808.02459) and
|
|
42
|
+
implemented in [Octapps](https://github.com/octapps/octapps), but here we
|
|
43
|
+
implement it in Python to make it more convenient to use.
|
|
44
|
+
|
|
45
|
+
## Citing this work
|
|
46
|
+
|
|
47
|
+
If COWS3 was useful to your research, we would appreciate if you cited
|
|
48
|
+
[Mirasola & Tenorio (2024)](https://arxiv.org/abs/2405.18934) where this
|
|
49
|
+
implementation was first presented:
|
|
50
|
+
```
|
|
51
|
+
@article{Mirasola:2024lcq,
|
|
52
|
+
author = "Mirasola, Lorenzo and Tenorio, Rodrigo",
|
|
53
|
+
title = "{Towards a computationally-efficient follow-up pipeline for blind continuous gravitational-wave searches}",
|
|
54
|
+
eprint = "2405.18934",
|
|
55
|
+
archivePrefix = "arXiv",
|
|
56
|
+
primaryClass = "gr-qc",
|
|
57
|
+
reportNumber = "LIGO-P2400221",
|
|
58
|
+
month = "5",
|
|
59
|
+
year = "2024",
|
|
60
|
+
journal = "arXiv e-prints"
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
as well as a Zenodo release of this software.
|
|
64
|
+
|
|
65
|
+
For the semi-analytical sensitivity estimation method you should also cite
|
|
66
|
+
[Wette (2012)](https://arxiv.org/abs/1111.5650) and
|
|
67
|
+
[Dreissigacker, Prix, Wette (2018)](https://arxiv.org/abs/1808.02459). Also,
|
|
68
|
+
this package makes extensive use of SWIG bindings, so please cite
|
|
69
|
+
[Wette (2021)](https://arxiv.org/abs/2012.09552) as well.
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
## Authors
|
|
73
|
+
- Rodrigo Tenorio
|
|
74
|
+
- Lorenzo Mirasola
|
|
75
|
+
|
|
76
|
+
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
.gitignore
|
|
2
|
+
LICENSE.md
|
|
3
|
+
README.md
|
|
4
|
+
pyproject.toml
|
|
5
|
+
setup.py
|
|
6
|
+
.github/workflows/pypi.yml
|
|
7
|
+
.github/workflows/pytest.yml
|
|
8
|
+
src/cows3/__init__.py
|
|
9
|
+
src/cows3/detectorstates.py
|
|
10
|
+
src/cows3/ephemeris.py
|
|
11
|
+
src/cows3/sensitivity.py
|
|
12
|
+
src/cows3/snr.py
|
|
13
|
+
src/cows3.egg-info/PKG-INFO
|
|
14
|
+
src/cows3.egg-info/SOURCES.txt
|
|
15
|
+
src/cows3.egg-info/dependency_links.txt
|
|
16
|
+
src/cows3.egg-info/requires.txt
|
|
17
|
+
src/cows3.egg-info/top_level.txt
|
|
18
|
+
tests/test_detectorstates.py
|
|
19
|
+
tests/test_sensitivity.py
|
|
20
|
+
tests/test_snr.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
cows3
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
import numpy as np
|
|
3
|
+
|
|
4
|
+
from cows3.detectorstates import MultiDetectorStates
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@pytest.fixture
|
|
8
|
+
def timestamps():
|
|
9
|
+
return {
|
|
10
|
+
"L1": 1238166018 + np.arange(0, 10, 3),
|
|
11
|
+
"H1": 1238166018 + np.arange(0, 10, 2),
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@pytest.fixture
|
|
16
|
+
def wrong_timestamps():
|
|
17
|
+
return {
|
|
18
|
+
"AB": 1238166018 + np.arange(0, 10, 3),
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@pytest.fixture
|
|
23
|
+
def Tsft():
|
|
24
|
+
return 1800
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@pytest.fixture
|
|
28
|
+
def time_offset():
|
|
29
|
+
return 0.0
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def test_get_multi_detector_states(timestamps, Tsft, time_offset):
|
|
33
|
+
mdss = MultiDetectorStates(
|
|
34
|
+
timestamps=timestamps, T_sft=Tsft, t_offset=time_offset
|
|
35
|
+
).Series
|
|
36
|
+
|
|
37
|
+
assert mdss.length == len(timestamps)
|
|
38
|
+
for ind, ifo in enumerate(timestamps):
|
|
39
|
+
assert mdss.data[ind].length == timestamps[ifo].size
|
|
40
|
+
assert mdss.data[ind].detector.frDetector.prefix == ifo
|
|
41
|
+
assert mdss.data[ind].deltaT == Tsft
|
|
42
|
+
|
|
43
|
+
for gps_ind in range(mdss.data[ind].length):
|
|
44
|
+
mdss.data[ind].data[gps_ind].tGPS.gpsSeconds == timestamps[ifo][gps_ind]
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def test_wrong_timestamps(wrong_timestamps, Tsft, time_offset):
|
|
48
|
+
with pytest.raises(RuntimeError) as e_info:
|
|
49
|
+
mds = MultiDetectorStates(
|
|
50
|
+
timestamps=wrong_timestamps, T_sft=Tsft, t_offset=time_offset
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def test_extract_detector_velocities(timestamps, Tsft, time_offset):
|
|
55
|
+
mds = MultiDetectorStates(timestamps=timestamps, T_sft=Tsft, t_offset=time_offset)
|
|
56
|
+
|
|
57
|
+
velocities = mds.velocities
|
|
58
|
+
mdss = mds.Series
|
|
59
|
+
|
|
60
|
+
assert len(velocities) == len(timestamps)
|
|
61
|
+
assert all(key in velocities for key in timestamps)
|
|
62
|
+
for ifo_ind in range(len(timestamps)):
|
|
63
|
+
shape_to_test = velocities[mdss.data[ifo_ind].detector.frDetector.prefix].shape
|
|
64
|
+
assert shape_to_test[0] == 3
|
|
65
|
+
assert shape_to_test[1] == mdss.data[ifo_ind].length
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
from cows3.sensitivity import pfd_Fstatistic
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@pytest.fixture
|
|
8
|
+
def unitD_rho2():
|
|
9
|
+
bins = np.arange(1, 11)
|
|
10
|
+
pdf = np.ones(bins.size) / bins.size
|
|
11
|
+
return bins, pdf
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def test_pfd_Fstatistic(unitD_rho2):
|
|
15
|
+
pfd_Fstatistic(
|
|
16
|
+
twoF_threshold=100,
|
|
17
|
+
depth=10,
|
|
18
|
+
num_segments=25,
|
|
19
|
+
unitD_rho2_bins=unitD_rho2[0],
|
|
20
|
+
unitD_rho2_pdf=unitD_rho2[1],
|
|
21
|
+
)
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
import pytest
|
|
3
|
+
|
|
4
|
+
from cows3.detectorstates import MultiDetectorStates
|
|
5
|
+
from cows3.snr import SignalToNoiseRatio
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@pytest.fixture
|
|
9
|
+
def signal_params():
|
|
10
|
+
return {
|
|
11
|
+
"aPlus": 0.5 * 1e-23,
|
|
12
|
+
"aCross": 1e-23,
|
|
13
|
+
"psi": 0,
|
|
14
|
+
"phi0": 0,
|
|
15
|
+
"Alpha": 0,
|
|
16
|
+
"Delta": 0,
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@pytest.fixture
|
|
21
|
+
def mds():
|
|
22
|
+
|
|
23
|
+
Tsft = 1_800
|
|
24
|
+
tstart = 700_000_000
|
|
25
|
+
ts = np.arange(tstart, tstart + 4 * Tsft, Tsft)
|
|
26
|
+
|
|
27
|
+
return MultiDetectorStates(
|
|
28
|
+
timestamps={detector: ts for detector in ["H1", "L1"]},
|
|
29
|
+
T_sft=Tsft,
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@pytest.fixture
|
|
34
|
+
def snr_object(mds):
|
|
35
|
+
return SignalToNoiseRatio(
|
|
36
|
+
mdss=mds.Series,
|
|
37
|
+
assumeSqrtSX=1e-23,
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def test_SignalToNoiseRatio(signal_params, snr_object):
|
|
42
|
+
params = {
|
|
43
|
+
"aPlus": 0.5 * 1e-23,
|
|
44
|
+
"aCross": 1e-23,
|
|
45
|
+
"psi": 0,
|
|
46
|
+
"phi0": 0,
|
|
47
|
+
"Alpha": 0,
|
|
48
|
+
"Delta": 0,
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
snr_object.compute_snr2(**signal_params)
|