archeo 2.0.0.dev2__tar.gz → 2.0.0.dev4__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.
- {archeo-2.0.0.dev2 → archeo-2.0.0.dev4}/PKG-INFO +1 -19
- {archeo-2.0.0.dev2 → archeo-2.0.0.dev4}/README.md +0 -14
- {archeo-2.0.0.dev2 → archeo-2.0.0.dev4}/archeo/bayesian/importance_sampling/resampler/assume_independence.py +8 -17
- {archeo-2.0.0.dev2 → archeo-2.0.0.dev4}/archeo/bayesian/importance_sampling/resampler/base.py +5 -7
- {archeo-2.0.0.dev2 → archeo-2.0.0.dev4}/archeo/bayesian/importance_sampling/resampler/generic.py +8 -11
- {archeo-2.0.0.dev2 → archeo-2.0.0.dev4}/archeo/bayesian/importance_sampling/resampler/interface.py +14 -22
- {archeo-2.0.0.dev2 → archeo-2.0.0.dev4}/archeo/data_structures/physics/binary.py +5 -5
- {archeo-2.0.0.dev2 → archeo-2.0.0.dev4}/archeo/data_structures/physics/black_hole.py +6 -3
- {archeo-2.0.0.dev2 → archeo-2.0.0.dev4}/archeo/data_structures/physics/mahapatra.py +2 -2
- {archeo-2.0.0.dev2 → archeo-2.0.0.dev4}/archeo.egg-info/PKG-INFO +1 -19
- {archeo-2.0.0.dev2 → archeo-2.0.0.dev4}/archeo.egg-info/SOURCES.txt +0 -3
- {archeo-2.0.0.dev2 → archeo-2.0.0.dev4}/archeo.egg-info/requires.txt +0 -5
- {archeo-2.0.0.dev2 → archeo-2.0.0.dev4}/pyproject.toml +3 -13
- archeo-2.0.0.dev2/archeo/ui/__init__.py +0 -8
- archeo-2.0.0.dev2/archeo/ui/app.py +0 -123
- archeo-2.0.0.dev2/archeo/ui/visualization.py +0 -15
- {archeo-2.0.0.dev2 → archeo-2.0.0.dev4}/LICENSE +0 -0
- {archeo-2.0.0.dev2 → archeo-2.0.0.dev4}/archeo/__init__.py +0 -0
- {archeo-2.0.0.dev2 → archeo-2.0.0.dev4}/archeo/__main__.py +0 -0
- {archeo-2.0.0.dev2 → archeo-2.0.0.dev4}/archeo/bayesian/__init__.py +0 -0
- {archeo-2.0.0.dev2 → archeo-2.0.0.dev4}/archeo/bayesian/ancestral_posterior.py +0 -0
- {archeo-2.0.0.dev2 → archeo-2.0.0.dev4}/archeo/bayesian/importance_sampling/__init__.py +0 -0
- {archeo-2.0.0.dev2 → archeo-2.0.0.dev4}/archeo/bayesian/importance_sampling/bayes_factor_curve.py +0 -0
- {archeo-2.0.0.dev2 → archeo-2.0.0.dev4}/archeo/bayesian/importance_sampling/resampler/__init__.py +0 -0
- {archeo-2.0.0.dev2 → archeo-2.0.0.dev4}/archeo/constants/__init__.py +0 -0
- {archeo-2.0.0.dev2 → archeo-2.0.0.dev4}/archeo/constants/enum.py +0 -0
- {archeo-2.0.0.dev2 → archeo-2.0.0.dev4}/archeo/constants/physics.py +0 -0
- {archeo-2.0.0.dev2 → archeo-2.0.0.dev4}/archeo/data_structures/__init__.py +0 -0
- {archeo-2.0.0.dev2 → archeo-2.0.0.dev4}/archeo/data_structures/annotation.py +0 -0
- {archeo-2.0.0.dev2 → archeo-2.0.0.dev4}/archeo/data_structures/bayesian/bayes_factor.py +0 -0
- {archeo-2.0.0.dev2 → archeo-2.0.0.dev4}/archeo/data_structures/distribution.py +0 -0
- {archeo-2.0.0.dev2 → archeo-2.0.0.dev4}/archeo/data_structures/math.py +0 -0
- {archeo-2.0.0.dev2 → archeo-2.0.0.dev4}/archeo/data_structures/physics/__init__.py +0 -0
- {archeo-2.0.0.dev2 → archeo-2.0.0.dev4}/archeo/data_structures/physics/simulation.py +0 -0
- {archeo-2.0.0.dev2 → archeo-2.0.0.dev4}/archeo/data_structures/visualization.py +0 -0
- {archeo-2.0.0.dev2 → archeo-2.0.0.dev4}/archeo/postprocessing/__init__.py +0 -0
- {archeo-2.0.0.dev2 → archeo-2.0.0.dev4}/archeo/postprocessing/dataframe.py +0 -0
- {archeo-2.0.0.dev2 → archeo-2.0.0.dev4}/archeo/preset/__init__.py +0 -0
- {archeo-2.0.0.dev2 → archeo-2.0.0.dev4}/archeo/preset/cli.py +0 -0
- {archeo-2.0.0.dev2 → archeo-2.0.0.dev4}/archeo/preset/forward/__init__.py +0 -0
- {archeo-2.0.0.dev2 → archeo-2.0.0.dev4}/archeo/preset/forward/compute_bayes_factor_curve.py +0 -0
- {archeo-2.0.0.dev2 → archeo-2.0.0.dev4}/archeo/preset/simulation/__init__.py +0 -0
- {archeo-2.0.0.dev2 → archeo-2.0.0.dev4}/archeo/preset/simulation/agnostic.py +0 -0
- {archeo-2.0.0.dev2 → archeo-2.0.0.dev4}/archeo/preset/simulation/n_generation.py +0 -0
- {archeo-2.0.0.dev2 → archeo-2.0.0.dev4}/archeo/preset/simulation/second_generation.py +0 -0
- {archeo-2.0.0.dev2 → archeo-2.0.0.dev4}/archeo/py.typed +0 -0
- {archeo-2.0.0.dev2 → archeo-2.0.0.dev4}/archeo/simulation/__init__.py +0 -0
- {archeo-2.0.0.dev2 → archeo-2.0.0.dev4}/archeo/simulation/simulate_merger.py +0 -0
- {archeo-2.0.0.dev2 → archeo-2.0.0.dev4}/archeo/utils/__init__.py +0 -0
- {archeo-2.0.0.dev2 → archeo-2.0.0.dev4}/archeo/utils/decorator.py +0 -0
- {archeo-2.0.0.dev2 → archeo-2.0.0.dev4}/archeo/utils/env.py +0 -0
- {archeo-2.0.0.dev2 → archeo-2.0.0.dev4}/archeo/utils/fs.py +0 -0
- {archeo-2.0.0.dev2 → archeo-2.0.0.dev4}/archeo/utils/logger.py +0 -0
- {archeo-2.0.0.dev2 → archeo-2.0.0.dev4}/archeo/utils/parallel.py +0 -0
- {archeo-2.0.0.dev2 → archeo-2.0.0.dev4}/archeo/version.py +0 -0
- {archeo-2.0.0.dev2 → archeo-2.0.0.dev4}/archeo/visualization/__init__.py +0 -0
- {archeo-2.0.0.dev2 → archeo-2.0.0.dev4}/archeo/visualization/animation.py +0 -0
- {archeo-2.0.0.dev2 → archeo-2.0.0.dev4}/archeo/visualization/base.py +0 -0
- {archeo-2.0.0.dev2 → archeo-2.0.0.dev4}/archeo/visualization/distribution.py +0 -0
- {archeo-2.0.0.dev2 → archeo-2.0.0.dev4}/archeo/visualization/estimation.py +0 -0
- {archeo-2.0.0.dev2 → archeo-2.0.0.dev4}/archeo.egg-info/dependency_links.txt +0 -0
- {archeo-2.0.0.dev2 → archeo-2.0.0.dev4}/archeo.egg-info/top_level.txt +0 -0
- {archeo-2.0.0.dev2 → archeo-2.0.0.dev4}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: archeo
|
|
3
|
-
Version: 2.0.0.
|
|
3
|
+
Version: 2.0.0.dev4
|
|
4
4
|
Summary: Bayesian framework for inferring natal kick, ancestral masses and spins of black holes.
|
|
5
5
|
Author-email: wyhwong <wyhwong@link.cuhk.edu.hk>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -33,10 +33,6 @@ Requires-Dist: seaborn>=0.13.2
|
|
|
33
33
|
Requires-Dist: surfinbh>=1.2.7
|
|
34
34
|
Requires-Dist: tabulate>=0.10.0
|
|
35
35
|
Requires-Dist: tqdm>=4.67.3
|
|
36
|
-
Provides-Extra: ui
|
|
37
|
-
Requires-Dist: nbformat>=5.10.4; extra == "ui"
|
|
38
|
-
Requires-Dist: plotly>=6.6.0; extra == "ui"
|
|
39
|
-
Requires-Dist: streamlit>=1.55.0; extra == "ui"
|
|
40
36
|
Dynamic: license-file
|
|
41
37
|
|
|
42
38
|
# ARCHEO (V2)
|
|
@@ -196,20 +192,6 @@ archeo.visualize_posterior_estimation({"GW190521": df_posterior}, output_dir="./
|
|
|
196
192
|
|
|
197
193
|
To import archeo in your Python code, please refer to the documentation page at [https://wyhwong.github.io/archeo/](https://wyhwong.github.io/archeo/).
|
|
198
194
|
|
|
199
|
-
## Try our UI
|
|
200
|
-
|
|
201
|
-
Archeo also provides a simple web-based user interface to visualize the distributions of remnant properties.
|
|
202
|
-
To run the UI locally, simply run the following command:
|
|
203
|
-
|
|
204
|
-
```bash
|
|
205
|
-
pip3 install archeo[ui]
|
|
206
|
-
python3 -m archeo.ui
|
|
207
|
-
```
|
|
208
|
-
|
|
209
|
-
Then the UI will be available at [localhost:8501](http://localhost:8501).
|
|
210
|
-
|
|
211
|
-
You may also try our [demo version](https://archeo.streamlit.app/) online, which is hosted on Streamlit Community Cloud.
|
|
212
|
-
|
|
213
195
|
## Getting Help
|
|
214
196
|
|
|
215
197
|
The code is maintained by [Henry Wong](https://github.com/wyhwong) under [Juan Calderon Bustillo](https://git.ligo.org/juan.calderonbustillo)'s supervision. You can find the [list of contributors](https://github.com/wyhwong/archeo/graphs/contributors) here. Please report bugs by raising an issue on our [GitHub](https://github.com/wyhwong/archeo) repository.
|
|
@@ -155,20 +155,6 @@ archeo.visualize_posterior_estimation({"GW190521": df_posterior}, output_dir="./
|
|
|
155
155
|
|
|
156
156
|
To import archeo in your Python code, please refer to the documentation page at [https://wyhwong.github.io/archeo/](https://wyhwong.github.io/archeo/).
|
|
157
157
|
|
|
158
|
-
## Try our UI
|
|
159
|
-
|
|
160
|
-
Archeo also provides a simple web-based user interface to visualize the distributions of remnant properties.
|
|
161
|
-
To run the UI locally, simply run the following command:
|
|
162
|
-
|
|
163
|
-
```bash
|
|
164
|
-
pip3 install archeo[ui]
|
|
165
|
-
python3 -m archeo.ui
|
|
166
|
-
```
|
|
167
|
-
|
|
168
|
-
Then the UI will be available at [localhost:8501](http://localhost:8501).
|
|
169
|
-
|
|
170
|
-
You may also try our [demo version](https://archeo.streamlit.app/) online, which is hosted on Streamlit Community Cloud.
|
|
171
|
-
|
|
172
158
|
## Getting Help
|
|
173
159
|
|
|
174
160
|
The code is maintained by [Henry Wong](https://github.com/wyhwong) under [Juan Calderon Bustillo](https://git.ligo.org/juan.calderonbustillo)'s supervision. You can find the [list of contributors](https://github.com/wyhwong/archeo/graphs/contributors) here. Please report bugs by raising an issue on our [GitHub](https://github.com/wyhwong/archeo) repository.
|
|
@@ -33,7 +33,7 @@ class ISDataAssumeIndependence(ImportanceSamplingDataBase):
|
|
|
33
33
|
nbins = self.get_nbins(samples.name)
|
|
34
34
|
return get_histogram_1d(samples, nbins=nbins, bounds=self.bounds[samples.name])
|
|
35
35
|
|
|
36
|
-
def get_likelihood_samples_1d(self, random_state=42
|
|
36
|
+
def get_likelihood_samples_1d(self, random_state=42) -> np.ndarray:
|
|
37
37
|
"""Get samples for likelihood function"""
|
|
38
38
|
|
|
39
39
|
weights = np.ones(len(self.posterior_samples))
|
|
@@ -42,7 +42,7 @@ class ISDataAssumeIndependence(ImportanceSamplingDataBase):
|
|
|
42
42
|
prior_hist = self._get_hist_1d(self.prior_samples[col])
|
|
43
43
|
rv = rv_histogram(
|
|
44
44
|
(
|
|
45
|
-
self._safe_divide(1.0, prior_hist
|
|
45
|
+
self._safe_divide(1.0, prior_hist),
|
|
46
46
|
self.get_edges(col_name=col),
|
|
47
47
|
)
|
|
48
48
|
)
|
|
@@ -55,7 +55,7 @@ class ISDataAssumeIndependence(ImportanceSamplingDataBase):
|
|
|
55
55
|
random_state=random_state,
|
|
56
56
|
)
|
|
57
57
|
|
|
58
|
-
def _get_posterior_sample_weights_1d(self, col_name: str
|
|
58
|
+
def _get_posterior_sample_weights_1d(self, col_name: str) -> np.ndarray:
|
|
59
59
|
"""Get the weights for the importance sampling"""
|
|
60
60
|
|
|
61
61
|
weights = np.ones(len(self.posterior_samples))
|
|
@@ -63,17 +63,13 @@ class ISDataAssumeIndependence(ImportanceSamplingDataBase):
|
|
|
63
63
|
prior_hist = self._get_hist_1d(self.prior_samples[col_name])
|
|
64
64
|
new_prior_hist = self._get_hist_1d(self.new_prior_samples[col_name])
|
|
65
65
|
# Avoid division by zero
|
|
66
|
-
ratio = self._safe_divide(new_prior_hist, prior_hist
|
|
66
|
+
ratio = self._safe_divide(new_prior_hist, prior_hist)
|
|
67
67
|
rv = rv_histogram((ratio, self.get_edges(col_name)))
|
|
68
68
|
weights *= rv.pdf(self.posterior_samples[col_name])
|
|
69
69
|
|
|
70
70
|
return weights
|
|
71
71
|
|
|
72
|
-
def get_bayes_factor_1d(
|
|
73
|
-
self,
|
|
74
|
-
bootstrapping: bool = False,
|
|
75
|
-
ztol=1e-8,
|
|
76
|
-
) -> float:
|
|
72
|
+
def get_bayes_factor_1d(self, bootstrapping: bool = False) -> float:
|
|
77
73
|
"""Compute the Bayes factor between two models"""
|
|
78
74
|
|
|
79
75
|
if bootstrapping:
|
|
@@ -81,14 +77,12 @@ class ISDataAssumeIndependence(ImportanceSamplingDataBase):
|
|
|
81
77
|
prior_samples=self.prior_samples.sample(n=len(self.prior_samples), replace=True),
|
|
82
78
|
posterior_samples=self.posterior_samples.sample(n=len(self.posterior_samples), replace=True),
|
|
83
79
|
new_prior_samples=self.new_prior_samples.sample(n=len(self.new_prior_samples), replace=True),
|
|
84
|
-
ztol=ztol,
|
|
85
80
|
)
|
|
86
81
|
|
|
87
82
|
return self._get_bayes_factor_1d(
|
|
88
83
|
prior_samples=self.prior_samples,
|
|
89
84
|
posterior_samples=self.posterior_samples,
|
|
90
85
|
new_prior_samples=self.new_prior_samples,
|
|
91
|
-
ztol=ztol,
|
|
92
86
|
)
|
|
93
87
|
|
|
94
88
|
def _get_bayes_factor_1d(
|
|
@@ -96,7 +90,6 @@ class ISDataAssumeIndependence(ImportanceSamplingDataBase):
|
|
|
96
90
|
prior_samples: pd.DataFrame,
|
|
97
91
|
posterior_samples: pd.DataFrame,
|
|
98
92
|
new_prior_samples: pd.DataFrame,
|
|
99
|
-
ztol=1e-8,
|
|
100
93
|
) -> float:
|
|
101
94
|
"""Compute the Bayes factor between two models
|
|
102
95
|
|
|
@@ -111,19 +104,17 @@ class ISDataAssumeIndependence(ImportanceSamplingDataBase):
|
|
|
111
104
|
prior_hist = self._get_hist_1d(prior_samples[col])
|
|
112
105
|
posterior_hist = self._get_hist_1d(posterior_samples[col])
|
|
113
106
|
new_prior_hist = self._get_hist_1d(new_prior_samples[col])
|
|
114
|
-
bf *= np.sum(posterior_hist * self._safe_divide(new_prior_hist, prior_hist
|
|
115
|
-
col
|
|
116
|
-
)
|
|
107
|
+
bf *= np.sum(posterior_hist * self._safe_divide(new_prior_hist, prior_hist)) * self.get_binwidth(col)
|
|
117
108
|
|
|
118
109
|
return bf
|
|
119
110
|
|
|
120
|
-
def get_reweighted_samples_1d(self,
|
|
111
|
+
def get_reweighted_samples_1d(self, random_state=42) -> pd.DataFrame:
|
|
121
112
|
"""Get the reweighted samples for the importance sampling"""
|
|
122
113
|
|
|
123
114
|
weights = np.ones(len(self.posterior_samples))
|
|
124
115
|
|
|
125
116
|
for col in self.common_columns:
|
|
126
|
-
weights *= self._get_posterior_sample_weights_1d(col_name=col
|
|
117
|
+
weights *= self._get_posterior_sample_weights_1d(col_name=col)
|
|
127
118
|
|
|
128
119
|
reweighted_samples = self.posterior_samples.sample(
|
|
129
120
|
n=len(self.posterior_samples),
|
{archeo-2.0.0.dev2 → archeo-2.0.0.dev4}/archeo/bayesian/importance_sampling/resampler/base.py
RENAMED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
from typing import Optional
|
|
2
|
-
|
|
3
1
|
import numpy as np
|
|
4
2
|
import pandas as pd
|
|
5
3
|
from pydantic import BaseModel, ConfigDict
|
|
@@ -21,6 +19,7 @@ class ImportanceSamplingDataBase(BaseModel, frozen=True):
|
|
|
21
19
|
new_prior_samples: pd.DataFrame
|
|
22
20
|
binsize_spin: float = 0.05
|
|
23
21
|
binsize_mass: float = 1.0
|
|
22
|
+
ztol: float = 1e-8
|
|
24
23
|
|
|
25
24
|
@property
|
|
26
25
|
def common_columns(self) -> list[str]:
|
|
@@ -53,7 +52,7 @@ class ImportanceSamplingDataBase(BaseModel, frozen=True):
|
|
|
53
52
|
|
|
54
53
|
return bounds
|
|
55
54
|
|
|
56
|
-
def get_binsize(self, col_name: str) ->
|
|
55
|
+
def get_binsize(self, col_name: str) -> float:
|
|
57
56
|
|
|
58
57
|
if col_name.startswith("a"):
|
|
59
58
|
return self.binsize_spin
|
|
@@ -63,7 +62,7 @@ class ImportanceSamplingDataBase(BaseModel, frozen=True):
|
|
|
63
62
|
|
|
64
63
|
raise ValueError(f"Unknown column name {col_name}")
|
|
65
64
|
|
|
66
|
-
def get_nbins(self, col_name: str) ->
|
|
65
|
+
def get_nbins(self, col_name: str) -> int:
|
|
67
66
|
"""Get the number of bins for a given column name"""
|
|
68
67
|
|
|
69
68
|
binsize = self.get_binsize(col_name)
|
|
@@ -83,8 +82,7 @@ class ImportanceSamplingDataBase(BaseModel, frozen=True):
|
|
|
83
82
|
edges = self.get_edges(col_name)
|
|
84
83
|
return edges[1] - edges[0]
|
|
85
84
|
|
|
86
|
-
|
|
87
|
-
def _safe_divide(a: np.ndarray, b: np.ndarray, ztol: float = 1e-8) -> np.ndarray:
|
|
85
|
+
def _safe_divide(self, a: np.ndarray, b: np.ndarray) -> np.ndarray:
|
|
88
86
|
"""Safe division to avoid division by zero"""
|
|
89
87
|
|
|
90
|
-
return np.where(b > ztol, np.exp(np.log(a) - np.log(b)), 0.0)
|
|
88
|
+
return np.where(b > self.ztol, np.exp(np.log(a) - np.log(b)), 0.0)
|
{archeo-2.0.0.dev2 → archeo-2.0.0.dev4}/archeo/bayesian/importance_sampling/resampler/generic.py
RENAMED
|
@@ -37,7 +37,7 @@ class ISDataGeneric(ImportanceSamplingDataBase):
|
|
|
37
37
|
samples_array = df_samples.to_numpy()
|
|
38
38
|
return get_histogram_dd(samples_array, nbins=nbins, bounds=bounds)
|
|
39
39
|
|
|
40
|
-
def get_likelihood_samples_dd(self, random_state=42
|
|
40
|
+
def get_likelihood_samples_dd(self, random_state=42) -> np.ndarray:
|
|
41
41
|
"""Get samples for likelihood function"""
|
|
42
42
|
|
|
43
43
|
edges = {}
|
|
@@ -45,7 +45,7 @@ class ISDataGeneric(ImportanceSamplingDataBase):
|
|
|
45
45
|
edges[col] = self.get_edges(col)
|
|
46
46
|
|
|
47
47
|
prior_hist = self._get_hist_dd(self.prior_samples[self.common_columns])
|
|
48
|
-
weights_matrix = self._safe_divide(1.0, prior_hist
|
|
48
|
+
weights_matrix = self._safe_divide(1.0, prior_hist)
|
|
49
49
|
|
|
50
50
|
def _get_pdf(row: pd.Series):
|
|
51
51
|
idx = tuple(np.searchsorted(edges[col], row[col], side="right") - 1 for col in self.common_columns)
|
|
@@ -60,7 +60,7 @@ class ISDataGeneric(ImportanceSamplingDataBase):
|
|
|
60
60
|
random_state=random_state,
|
|
61
61
|
)
|
|
62
62
|
|
|
63
|
-
def _get_posterior_sample_weights_dd(self
|
|
63
|
+
def _get_posterior_sample_weights_dd(self) -> pd.Series:
|
|
64
64
|
"""Get the weights for the importance sampling"""
|
|
65
65
|
|
|
66
66
|
edges = {}
|
|
@@ -70,7 +70,7 @@ class ISDataGeneric(ImportanceSamplingDataBase):
|
|
|
70
70
|
prior_hist = self._get_hist_dd(self.prior_samples[self.common_columns])
|
|
71
71
|
new_prior_hist = self._get_hist_dd(self.new_prior_samples[self.common_columns])
|
|
72
72
|
# Avoid division by zero
|
|
73
|
-
weights_matrix = self._safe_divide(new_prior_hist, prior_hist
|
|
73
|
+
weights_matrix = self._safe_divide(new_prior_hist, prior_hist)
|
|
74
74
|
|
|
75
75
|
def _get_pdf(row: pd.Series):
|
|
76
76
|
idx = tuple(np.searchsorted(edges[col], row[col], side="right") - 1 for col in self.common_columns)
|
|
@@ -78,7 +78,7 @@ class ISDataGeneric(ImportanceSamplingDataBase):
|
|
|
78
78
|
|
|
79
79
|
return self.posterior_samples.apply(_get_pdf, axis=1)
|
|
80
80
|
|
|
81
|
-
def get_bayes_factor_dd(self, bootstrapping: bool = False
|
|
81
|
+
def get_bayes_factor_dd(self, bootstrapping: bool = False) -> float:
|
|
82
82
|
"""Compute the Bayes factor between two models"""
|
|
83
83
|
|
|
84
84
|
if bootstrapping:
|
|
@@ -86,14 +86,12 @@ class ISDataGeneric(ImportanceSamplingDataBase):
|
|
|
86
86
|
prior_samples=self.prior_samples.sample(n=len(self.prior_samples), replace=True),
|
|
87
87
|
posterior_samples=self.posterior_samples.sample(n=len(self.posterior_samples), replace=True),
|
|
88
88
|
new_prior_samples=self.new_prior_samples.sample(n=len(self.new_prior_samples), replace=True),
|
|
89
|
-
ztol=ztol,
|
|
90
89
|
)
|
|
91
90
|
|
|
92
91
|
return self._get_bayes_factor_dd(
|
|
93
92
|
prior_samples=self.prior_samples,
|
|
94
93
|
posterior_samples=self.posterior_samples,
|
|
95
94
|
new_prior_samples=self.new_prior_samples,
|
|
96
|
-
ztol=ztol,
|
|
97
95
|
)
|
|
98
96
|
|
|
99
97
|
def _get_bayes_factor_dd(
|
|
@@ -101,7 +99,6 @@ class ISDataGeneric(ImportanceSamplingDataBase):
|
|
|
101
99
|
prior_samples: pd.DataFrame,
|
|
102
100
|
posterior_samples: pd.DataFrame,
|
|
103
101
|
new_prior_samples: pd.DataFrame,
|
|
104
|
-
ztol=1e-8,
|
|
105
102
|
) -> float:
|
|
106
103
|
"""Compute the Bayes factor between two models
|
|
107
104
|
|
|
@@ -116,14 +113,14 @@ class ISDataGeneric(ImportanceSamplingDataBase):
|
|
|
116
113
|
new_prior_hist_bh = self._get_hist_dd(new_prior_samples[[c for c in self.common_columns]])
|
|
117
114
|
prior_hist_bh = self._get_hist_dd(prior_samples[[c for c in self.common_columns]])
|
|
118
115
|
posterior_hist_bh = self._get_hist_dd(posterior_samples[[c for c in self.common_columns]])
|
|
119
|
-
bf *= np.sum(posterior_hist_bh * self._safe_divide(new_prior_hist_bh, prior_hist_bh
|
|
116
|
+
bf *= np.sum(posterior_hist_bh * self._safe_divide(new_prior_hist_bh, prior_hist_bh)) * bin_auc
|
|
120
117
|
|
|
121
118
|
return bf
|
|
122
119
|
|
|
123
|
-
def get_reweighted_samples_dd(self,
|
|
120
|
+
def get_reweighted_samples_dd(self, random_state=42) -> pd.DataFrame:
|
|
124
121
|
"""Get the reweighted samples for the importance sampling"""
|
|
125
122
|
|
|
126
|
-
weights = self._get_posterior_sample_weights_dd(
|
|
123
|
+
weights = self._get_posterior_sample_weights_dd()
|
|
127
124
|
|
|
128
125
|
return self.posterior_samples.sample(
|
|
129
126
|
n=len(self.posterior_samples),
|
{archeo-2.0.0.dev2 → archeo-2.0.0.dev4}/archeo/bayesian/importance_sampling/resampler/interface.py
RENAMED
|
@@ -20,16 +20,16 @@ class ImportanceSamplingData(ISDataGeneric, ISDataAssumeIndependence, Interface)
|
|
|
20
20
|
assume_parameter_independence: bool = False
|
|
21
21
|
|
|
22
22
|
@pre_release
|
|
23
|
-
def get_likelihood_samples(self, random_state=42
|
|
23
|
+
def get_likelihood_samples(self, random_state=42) -> np.ndarray:
|
|
24
24
|
"""Get samples for likelihood function"""
|
|
25
25
|
|
|
26
26
|
if self.assume_parameter_independence:
|
|
27
|
-
return self.get_likelihood_samples_1d(random_state=random_state
|
|
27
|
+
return self.get_likelihood_samples_1d(random_state=random_state)
|
|
28
28
|
|
|
29
|
-
return self.get_likelihood_samples_dd(random_state=random_state
|
|
29
|
+
return self.get_likelihood_samples_dd(random_state=random_state)
|
|
30
30
|
|
|
31
31
|
@pre_release
|
|
32
|
-
def get_bayes_factor(self, bootstrapping: bool = False
|
|
32
|
+
def get_bayes_factor(self, bootstrapping: bool = False) -> float:
|
|
33
33
|
"""Compute the Bayes factor between two models
|
|
34
34
|
|
|
35
35
|
NOTE: In this implementation, the likelihood function remains untouched.
|
|
@@ -41,18 +41,12 @@ class ImportanceSamplingData(ISDataGeneric, ISDataAssumeIndependence, Interface)
|
|
|
41
41
|
return 0.0
|
|
42
42
|
|
|
43
43
|
if self.assume_parameter_independence:
|
|
44
|
-
return self.get_bayes_factor_1d(bootstrapping=bootstrapping
|
|
44
|
+
return self.get_bayes_factor_1d(bootstrapping=bootstrapping)
|
|
45
45
|
|
|
46
|
-
return self.get_bayes_factor_dd(bootstrapping=bootstrapping
|
|
46
|
+
return self.get_bayes_factor_dd(bootstrapping=bootstrapping)
|
|
47
47
|
|
|
48
48
|
@pre_release
|
|
49
|
-
def sample_bayes_factor(
|
|
50
|
-
self,
|
|
51
|
-
n: int,
|
|
52
|
-
ztol=1e-8,
|
|
53
|
-
is_parallel: bool = False,
|
|
54
|
-
n_threads: int | None = None,
|
|
55
|
-
) -> BayesFactor:
|
|
49
|
+
def sample_bayes_factor(self, n: int, is_parallel: bool = False, n_threads: int | None = None) -> BayesFactor:
|
|
56
50
|
"""Sample the Bayes factor for the importance sampling"""
|
|
57
51
|
|
|
58
52
|
if self.new_prior_samples.empty:
|
|
@@ -63,29 +57,27 @@ class ImportanceSamplingData(ISDataGeneric, ISDataAssumeIndependence, Interface)
|
|
|
63
57
|
return BayesFactor(
|
|
64
58
|
samples=multithread_run(
|
|
65
59
|
func=self.get_bayes_factor_1d,
|
|
66
|
-
input_kwargs=[{"bootstrapping": True
|
|
60
|
+
input_kwargs=[{"bootstrapping": True} for _ in range(n)],
|
|
67
61
|
n_threads=n_threads,
|
|
68
62
|
)
|
|
69
63
|
)
|
|
70
|
-
return BayesFactor(
|
|
71
|
-
samples=[self.get_bayes_factor_1d(bootstrapping=True, ztol=ztol) for _ in tqdm(range(n))]
|
|
72
|
-
)
|
|
64
|
+
return BayesFactor(samples=[self.get_bayes_factor_1d(bootstrapping=True) for _ in tqdm(range(n))])
|
|
73
65
|
|
|
74
66
|
if is_parallel:
|
|
75
67
|
return BayesFactor(
|
|
76
68
|
samples=multithread_run(
|
|
77
69
|
func=self.get_bayes_factor_dd,
|
|
78
|
-
input_kwargs=[{"bootstrapping": True
|
|
70
|
+
input_kwargs=[{"bootstrapping": True} for _ in range(n)],
|
|
79
71
|
n_threads=n_threads,
|
|
80
72
|
)
|
|
81
73
|
)
|
|
82
|
-
return BayesFactor(samples=[self.get_bayes_factor_dd(bootstrapping=True
|
|
74
|
+
return BayesFactor(samples=[self.get_bayes_factor_dd(bootstrapping=True) for _ in tqdm(range(n))])
|
|
83
75
|
|
|
84
76
|
@pre_release
|
|
85
|
-
def get_reweighted_samples(self,
|
|
77
|
+
def get_reweighted_samples(self, random_state=42) -> pd.DataFrame:
|
|
86
78
|
"""Get the reweighted samples for the importance sampling"""
|
|
87
79
|
|
|
88
80
|
if self.assume_parameter_independence:
|
|
89
|
-
return self.get_reweighted_samples_1d(
|
|
81
|
+
return self.get_reweighted_samples_1d(random_state=random_state)
|
|
90
82
|
|
|
91
|
-
return self.get_reweighted_samples_dd(
|
|
83
|
+
return self.get_reweighted_samples_dd(random_state=random_state)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
from typing import TypeAlias
|
|
2
2
|
|
|
3
3
|
import numpy as np
|
|
4
|
-
from pydantic import BaseModel
|
|
4
|
+
from pydantic import BaseModel, NonNegativeFloat, PositiveFloat
|
|
5
5
|
|
|
6
6
|
from archeo.data_structures.math import Domain
|
|
7
7
|
from archeo.data_structures.physics.black_hole import BlackHole, BlackHoleSource
|
|
@@ -18,13 +18,13 @@ class Binary(BaseModel, frozen=True):
|
|
|
18
18
|
secondary_black_hole: BlackHole
|
|
19
19
|
|
|
20
20
|
@property
|
|
21
|
-
def mass_ratio(self) ->
|
|
21
|
+
def mass_ratio(self) -> PositiveFloat:
|
|
22
22
|
"""Calculate the mass ratio (q) for the binary."""
|
|
23
23
|
|
|
24
24
|
return self.primary_black_hole.mass / self.secondary_black_hole.mass
|
|
25
25
|
|
|
26
26
|
@property
|
|
27
|
-
def precession_spin(self) ->
|
|
27
|
+
def precession_spin(self) -> NonNegativeFloat:
|
|
28
28
|
"""Calculate the precession spin parameter (chi_p) for the binary."""
|
|
29
29
|
|
|
30
30
|
q = self.primary_black_hole.mass / self.secondary_black_hole.mass
|
|
@@ -33,7 +33,7 @@ class Binary(BaseModel, frozen=True):
|
|
|
33
33
|
return np.maximum(a1h, (4 / q + 3) / (3 / q + 4) / q * a2h)
|
|
34
34
|
|
|
35
35
|
@property
|
|
36
|
-
def effective_spin(self) ->
|
|
36
|
+
def effective_spin(self) -> NonNegativeFloat:
|
|
37
37
|
"""Calculate the effective spin parameter (chi_eff) for the binary."""
|
|
38
38
|
|
|
39
39
|
m1 = self.primary_black_hole.mass
|
|
@@ -55,7 +55,7 @@ class BinaryGenerator(BaseModel, frozen=True):
|
|
|
55
55
|
is_aligned_spin: bool = False
|
|
56
56
|
enforce_source_binding: bool = False
|
|
57
57
|
|
|
58
|
-
def draw(self, size: int = 1) ->
|
|
58
|
+
def draw(self, size: int = 1) -> Binaries:
|
|
59
59
|
"""Generate a list of binaries based on the specified sources and mass ratio domain."""
|
|
60
60
|
|
|
61
61
|
binaries = []
|
|
@@ -101,12 +101,15 @@ class BlackHolePopulation(BaseModel, frozen=True):
|
|
|
101
101
|
return np.random.choice(self.black_holes, size=size, replace=True).tolist()
|
|
102
102
|
|
|
103
103
|
@classmethod
|
|
104
|
-
def from_simulation_results(
|
|
104
|
+
def from_simulation_results(
|
|
105
|
+
cls,
|
|
106
|
+
df: pd.DataFrame,
|
|
107
|
+
phi_distribution: Distribution = Uniform(low=0, high=2 * np.pi),
|
|
108
|
+
theta_distribution: Distribution = Uniform(low=0, high=np.pi),
|
|
109
|
+
) -> "BlackHolePopulation":
|
|
105
110
|
"""Create a black hole population from simulation results."""
|
|
106
111
|
|
|
107
|
-
phi_distribution = Uniform(low=0, high=2 * np.pi)
|
|
108
112
|
phis = phi_distribution.draw(size=len(df))
|
|
109
|
-
theta_distribution = Uniform(low=0, high=np.pi)
|
|
110
113
|
thetas = theta_distribution.draw(size=len(df))
|
|
111
114
|
|
|
112
115
|
return cls(
|
|
@@ -33,7 +33,7 @@ class MahapatraMassFunction(BaseModel, DistributionBase, frozen=True):
|
|
|
33
33
|
def probis(self) -> np.ndarray:
|
|
34
34
|
"""Probabilities of the masses."""
|
|
35
35
|
|
|
36
|
-
probis = self.
|
|
36
|
+
probis = self._smoothing_func(self.masses)
|
|
37
37
|
probis /= probis.sum()
|
|
38
38
|
return probis
|
|
39
39
|
|
|
@@ -43,7 +43,7 @@ class MahapatraMassFunction(BaseModel, DistributionBase, frozen=True):
|
|
|
43
43
|
mp = masses - self.mass.low
|
|
44
44
|
return np.exp(self.dm / mp + self.dm / (mp - self.dm))
|
|
45
45
|
|
|
46
|
-
def
|
|
46
|
+
def _smoothing_func(self, masses: np.ndarray) -> np.ndarray:
|
|
47
47
|
"""Smoothing function."""
|
|
48
48
|
|
|
49
49
|
probis = masses.copy()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: archeo
|
|
3
|
-
Version: 2.0.0.
|
|
3
|
+
Version: 2.0.0.dev4
|
|
4
4
|
Summary: Bayesian framework for inferring natal kick, ancestral masses and spins of black holes.
|
|
5
5
|
Author-email: wyhwong <wyhwong@link.cuhk.edu.hk>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -33,10 +33,6 @@ Requires-Dist: seaborn>=0.13.2
|
|
|
33
33
|
Requires-Dist: surfinbh>=1.2.7
|
|
34
34
|
Requires-Dist: tabulate>=0.10.0
|
|
35
35
|
Requires-Dist: tqdm>=4.67.3
|
|
36
|
-
Provides-Extra: ui
|
|
37
|
-
Requires-Dist: nbformat>=5.10.4; extra == "ui"
|
|
38
|
-
Requires-Dist: plotly>=6.6.0; extra == "ui"
|
|
39
|
-
Requires-Dist: streamlit>=1.55.0; extra == "ui"
|
|
40
36
|
Dynamic: license-file
|
|
41
37
|
|
|
42
38
|
# ARCHEO (V2)
|
|
@@ -196,20 +192,6 @@ archeo.visualize_posterior_estimation({"GW190521": df_posterior}, output_dir="./
|
|
|
196
192
|
|
|
197
193
|
To import archeo in your Python code, please refer to the documentation page at [https://wyhwong.github.io/archeo/](https://wyhwong.github.io/archeo/).
|
|
198
194
|
|
|
199
|
-
## Try our UI
|
|
200
|
-
|
|
201
|
-
Archeo also provides a simple web-based user interface to visualize the distributions of remnant properties.
|
|
202
|
-
To run the UI locally, simply run the following command:
|
|
203
|
-
|
|
204
|
-
```bash
|
|
205
|
-
pip3 install archeo[ui]
|
|
206
|
-
python3 -m archeo.ui
|
|
207
|
-
```
|
|
208
|
-
|
|
209
|
-
Then the UI will be available at [localhost:8501](http://localhost:8501).
|
|
210
|
-
|
|
211
|
-
You may also try our [demo version](https://archeo.streamlit.app/) online, which is hosted on Streamlit Community Cloud.
|
|
212
|
-
|
|
213
195
|
## Getting Help
|
|
214
196
|
|
|
215
197
|
The code is maintained by [Henry Wong](https://github.com/wyhwong) under [Juan Calderon Bustillo](https://git.ligo.org/juan.calderonbustillo)'s supervision. You can find the [list of contributors](https://github.com/wyhwong/archeo/graphs/contributors) here. Please report bugs by raising an issue on our [GitHub](https://github.com/wyhwong/archeo) repository.
|
|
@@ -45,9 +45,6 @@ archeo/preset/simulation/n_generation.py
|
|
|
45
45
|
archeo/preset/simulation/second_generation.py
|
|
46
46
|
archeo/simulation/__init__.py
|
|
47
47
|
archeo/simulation/simulate_merger.py
|
|
48
|
-
archeo/ui/__init__.py
|
|
49
|
-
archeo/ui/app.py
|
|
50
|
-
archeo/ui/visualization.py
|
|
51
48
|
archeo/utils/__init__.py
|
|
52
49
|
archeo/utils/decorator.py
|
|
53
50
|
archeo/utils/env.py
|
|
@@ -16,7 +16,7 @@ classifiers = [
|
|
|
16
16
|
"Operating System :: OS Independent"
|
|
17
17
|
]
|
|
18
18
|
keywords = ["black-holes", "gravitational-waves", "black-hole-archeology"]
|
|
19
|
-
version = "2.0.0.
|
|
19
|
+
version = "2.0.0.dev4"
|
|
20
20
|
readme = "README.md"
|
|
21
21
|
requires-python = ">=3.11,<3.14"
|
|
22
22
|
dependencies = [
|
|
@@ -35,13 +35,6 @@ dependencies = [
|
|
|
35
35
|
"tqdm>=4.67.3",
|
|
36
36
|
]
|
|
37
37
|
|
|
38
|
-
[project.optional-dependencies]
|
|
39
|
-
ui = [
|
|
40
|
-
"nbformat>=5.10.4",
|
|
41
|
-
"plotly>=6.6.0",
|
|
42
|
-
"streamlit>=1.55.0",
|
|
43
|
-
]
|
|
44
|
-
|
|
45
38
|
[project.urls]
|
|
46
39
|
homepage = "https://pypi.org/project/archeo/"
|
|
47
40
|
repository = "https://github.com/wyhwong/archeo"
|
|
@@ -52,6 +45,8 @@ dev = [
|
|
|
52
45
|
"ipykernel>=6.9.2, <7.0.0",
|
|
53
46
|
"pre-commit>=4.5.1",
|
|
54
47
|
"pyarrow>=23.0.1",
|
|
48
|
+
"pyinstrument>=5.1.2",
|
|
49
|
+
"pylint>=4.0.5",
|
|
55
50
|
"pytest>=9.0.2",
|
|
56
51
|
"pytest-cov>=7.0.0",
|
|
57
52
|
]
|
|
@@ -60,11 +55,6 @@ mkdocs = [
|
|
|
60
55
|
"mkdocs-jupyter>=0.25.1",
|
|
61
56
|
"mkdocs-mermaid2-plugin>=1.2.3",
|
|
62
57
|
]
|
|
63
|
-
ui = [
|
|
64
|
-
"nbformat>=5.10.4",
|
|
65
|
-
"plotly>=6.6.0",
|
|
66
|
-
"streamlit>=1.55.0",
|
|
67
|
-
]
|
|
68
58
|
|
|
69
59
|
[tool.black]
|
|
70
60
|
line-length = 120
|
|
@@ -1,123 +0,0 @@
|
|
|
1
|
-
import plotly.graph_objects as go
|
|
2
|
-
import streamlit as st
|
|
3
|
-
|
|
4
|
-
from archeo.constants.enum import Fits
|
|
5
|
-
from archeo.data_structures.distribution import Uniform
|
|
6
|
-
from archeo.data_structures.math import Domain
|
|
7
|
-
from archeo.data_structures.physics.binary import BinaryGenerator
|
|
8
|
-
from archeo.data_structures.physics.black_hole import BlackHoleGenerator
|
|
9
|
-
from archeo.postprocessing.dataframe import convert_simulated_binaries_to_dataframe
|
|
10
|
-
from archeo.simulation.simulate_merger import simulate_black_hole_mergers
|
|
11
|
-
from archeo.ui.visualization import add_pdf
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
st.set_page_config(page_title="Exploring Distribution of Remnant Properties", layout="wide")
|
|
15
|
-
|
|
16
|
-
###############################################
|
|
17
|
-
# Sidebar Content #
|
|
18
|
-
###############################################
|
|
19
|
-
|
|
20
|
-
st.sidebar.markdown("## Configure Your Ancestral Priors")
|
|
21
|
-
|
|
22
|
-
# Store slider values in session state
|
|
23
|
-
prior_name = st.sidebar.text_input("Name of the prior", "My prior")
|
|
24
|
-
spin_setting = st.sidebar.selectbox("Spin setting", ["Aligned spin", "Precession spin"])
|
|
25
|
-
n_samples = st.sidebar.slider("Number of samples", min_value=1000, max_value=10000, value=1000)
|
|
26
|
-
n_workers = st.sidebar.slider("Number of workers", min_value=1, max_value=16, value=1)
|
|
27
|
-
q_range = st.sidebar.slider("Mass ratio $q$", min_value=1.0, max_value=6.0, value=(1.0, 6.0))
|
|
28
|
-
|
|
29
|
-
st.sidebar.markdown("#### Primary Black Hole Settings")
|
|
30
|
-
m1_range = st.sidebar.slider("Mass $m_1$", min_value=5.0, max_value=200.0, value=(5.0, 200.0))
|
|
31
|
-
a1_range = st.sidebar.slider("Spin $\\chi_1$", min_value=0.0, max_value=0.99, value=(0.0, 0.99))
|
|
32
|
-
|
|
33
|
-
if spin_setting == "Precession spin":
|
|
34
|
-
phi1_range = st.sidebar.slider("Azimuthal angle $\\phi_1$", min_value=0.0, max_value=2.0, value=(0.0, 2.0))
|
|
35
|
-
theta1_range = st.sidebar.slider("Polar angle $\\theta_1$", min_value=0.0, max_value=1.0, value=(0.0, 1.0))
|
|
36
|
-
else:
|
|
37
|
-
phi1_range = theta1_range = (0.0, 0.0)
|
|
38
|
-
|
|
39
|
-
st.sidebar.markdown("#### Secondary Black Hole Settings")
|
|
40
|
-
m2_range = st.sidebar.slider("Mass $m_2$", min_value=5.0, max_value=200.0, value=(5.0, 200.0))
|
|
41
|
-
a2_range = st.sidebar.slider("Spin $\\chi_2$", min_value=0.0, max_value=0.99, value=(0.0, 0.99))
|
|
42
|
-
|
|
43
|
-
if spin_setting == "Precession spin":
|
|
44
|
-
phi2_range = st.sidebar.slider("Azimuthal angle $\\phi_2$", min_value=0.0, max_value=2.0, value=(0.0, 2.0))
|
|
45
|
-
theta2_range = st.sidebar.slider("Polar angle $\\theta_2$", min_value=0.0, max_value=1.0, value=(0.0, 1.0))
|
|
46
|
-
else:
|
|
47
|
-
phi2_range = theta2_range = (0.0, 0.0)
|
|
48
|
-
|
|
49
|
-
###############################################
|
|
50
|
-
# Main Content #
|
|
51
|
-
###############################################
|
|
52
|
-
|
|
53
|
-
st.markdown(
|
|
54
|
-
"""
|
|
55
|
-
# Exploring Distribution of Remnant Properties
|
|
56
|
-
|
|
57
|
-
## Introduction
|
|
58
|
-
|
|
59
|
-
This application allows users to configure the distributions for properties
|
|
60
|
-
of black hole binaries and visualize the distribution of their remnant
|
|
61
|
-
properties. By adjusting mass, spin, and alignment settings, users can generate
|
|
62
|
-
samples and study the properties of remnant black holes.
|
|
63
|
-
|
|
64
|
-
If you found hierarchical formation of black holes interesting and want to learn more,
|
|
65
|
-
please refer to our paper:
|
|
66
|
-
|
|
67
|
-
[1] Carlos Araújo Álvarez, Henry W. Y. Wong, Juan Calderón Bustillo. "Kicking Time
|
|
68
|
-
Back in Black Hole Mergers: Ancestral Masses, Spins, Birth Recoils, and
|
|
69
|
-
Hierarchical-formation Viability of GW190521." The Astrophysical Journal
|
|
70
|
-
977.2 (2024): 220.
|
|
71
|
-
"""
|
|
72
|
-
)
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
if "figs" not in st.session_state:
|
|
76
|
-
st.session_state["figs"] = {}
|
|
77
|
-
for col, label in {
|
|
78
|
-
"k_f": "Birth Recoil k<sub>f</sub> [km s<sup>-1</sup>]",
|
|
79
|
-
"a_f": "Spin χ<sub>f</sub> [-]",
|
|
80
|
-
"m_f": "Mass m<sub>f</sub> [M<sub>Sun</sub>]",
|
|
81
|
-
}.items():
|
|
82
|
-
st.session_state.figs[col] = go.Figure()
|
|
83
|
-
st.session_state.figs[col].update_layout(
|
|
84
|
-
title="Probability Density Function",
|
|
85
|
-
xaxis_title=label,
|
|
86
|
-
yaxis_title="Density",
|
|
87
|
-
showlegend=True,
|
|
88
|
-
barmode="overlay",
|
|
89
|
-
)
|
|
90
|
-
|
|
91
|
-
if st.sidebar.button("Run"):
|
|
92
|
-
|
|
93
|
-
fits = Fits.NRSUR7DQ4REMNANT if spin_setting == "Precession spin" else Fits.NRSUR3DQ8REMNANT
|
|
94
|
-
generator_bh1 = BlackHoleGenerator(
|
|
95
|
-
mass_distribution=Uniform(low=m1_range[0], high=m1_range[1]),
|
|
96
|
-
spin_magnitude_distribution=Uniform(low=a1_range[0], high=a1_range[1]),
|
|
97
|
-
phi_distribution=Uniform(low=phi1_range[0], high=phi1_range[1]),
|
|
98
|
-
theta_distribution=Uniform(low=theta1_range[0], high=theta1_range[1]),
|
|
99
|
-
)
|
|
100
|
-
generator_bh2 = BlackHoleGenerator(
|
|
101
|
-
mass_distribution=Uniform(low=m2_range[0], high=m2_range[1]),
|
|
102
|
-
spin_magnitude_distribution=Uniform(low=a2_range[0], high=a2_range[1]),
|
|
103
|
-
phi_distribution=Uniform(low=phi2_range[0], high=phi2_range[1]),
|
|
104
|
-
theta_distribution=Uniform(low=theta2_range[0], high=theta2_range[1]),
|
|
105
|
-
)
|
|
106
|
-
binary_generator = BinaryGenerator(
|
|
107
|
-
primary_black_hole_source=generator_bh1,
|
|
108
|
-
secondary_black_hole_source=generator_bh2,
|
|
109
|
-
mass_ratio_domain=Domain(low=q_range[0], high=q_range[1]),
|
|
110
|
-
is_aligned_spin=(spin_setting == "Aligned spin"),
|
|
111
|
-
)
|
|
112
|
-
|
|
113
|
-
with st.spinner("Running simulation... Please wait..."):
|
|
114
|
-
|
|
115
|
-
black_hole_mergers = simulate_black_hole_mergers(binary_generator, fits, n_samples, n_workers)
|
|
116
|
-
df = convert_simulated_binaries_to_dataframe(black_hole_mergers)
|
|
117
|
-
|
|
118
|
-
st.write("## Visualization of Remnant Properties")
|
|
119
|
-
for col in ["k_f", "a_f", "m_f"]:
|
|
120
|
-
add_pdf(st.session_state.figs[col], df[col], prior_name)
|
|
121
|
-
st.plotly_chart(st.session_state.figs[col])
|
|
122
|
-
|
|
123
|
-
st.success("Simulation completed!")
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import pandas as pd
|
|
2
|
-
import plotly.graph_objects as go
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
def add_pdf(fig: go.Figure, series: pd.Series, label: str) -> None:
|
|
6
|
-
"""Plot the distribution of a column in a dataframe."""
|
|
7
|
-
|
|
8
|
-
fig.add_trace(
|
|
9
|
-
go.Histogram(
|
|
10
|
-
x=series,
|
|
11
|
-
histnorm="probability density",
|
|
12
|
-
opacity=0.75,
|
|
13
|
-
name=label,
|
|
14
|
-
)
|
|
15
|
-
)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{archeo-2.0.0.dev2 → archeo-2.0.0.dev4}/archeo/bayesian/importance_sampling/bayes_factor_curve.py
RENAMED
|
File without changes
|
{archeo-2.0.0.dev2 → archeo-2.0.0.dev4}/archeo/bayesian/importance_sampling/resampler/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|