TransitionListener 2.0.0__py3-none-any.whl
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.
- transitionlistener/__init__.py +21 -0
- transitionlistener/bubbledynamics.py +2250 -0
- transitionlistener/bubbledynamics_fixedstep.py +2929 -0
- transitionlistener/check_installation.py +309 -0
- transitionlistener/ckm.py +91 -0
- transitionlistener/colors.py +288 -0
- transitionlistener/config.py +185 -0
- transitionlistener/constants.py +64 -0
- transitionlistener/counterterms/__init__.py +230 -0
- transitionlistener/counterterms/cw.py +298 -0
- transitionlistener/counterterms/tensors.py +343 -0
- transitionlistener/counterterms/twohdm.py +520 -0
- transitionlistener/counterterms/twohdm_solver.py +374 -0
- transitionlistener/errors.py +315 -0
- transitionlistener/examples/bp_et.yaml +64 -0
- transitionlistener/examples/bp_lisa.yaml +70 -0
- transitionlistener/examples/bp_muares.yaml +69 -0
- transitionlistener/examples/bp_pta.yaml +64 -0
- transitionlistener/examples/example_dark_photon.yaml +73 -0
- transitionlistener/examples/example_grid.yaml +55 -0
- transitionlistener/examples/example_line.yaml +51 -0
- transitionlistener/examples/example_point.yaml +73 -0
- transitionlistener/examples/example_random_conformal.yaml +42 -0
- transitionlistener/examples/example_ultranest.yaml +39 -0
- transitionlistener/finiteT.py +468 -0
- transitionlistener/generic_potential.py +1521 -0
- transitionlistener/gridplots.py +592 -0
- transitionlistener/gwfopt.py +604 -0
- transitionlistener/helper_functions.py +843 -0
- transitionlistener/hydrodynamics.py +647 -0
- transitionlistener/interface/__init__.py +95 -0
- transitionlistener/interface/check.py +51 -0
- transitionlistener/interface/cli.py +211 -0
- transitionlistener/interface/config_loader.py +264 -0
- transitionlistener/interface/logging_utils.py +30 -0
- transitionlistener/interface/output_schema.py +296 -0
- transitionlistener/interface/pipeline.py +300 -0
- transitionlistener/interface/samplers.py +565 -0
- transitionlistener/interface/scans.py +468 -0
- transitionlistener/interface/single_point.py +581 -0
- transitionlistener/interface/state.py +61 -0
- transitionlistener/lineplots.py +597 -0
- transitionlistener/logo/TL-logo_large.png +0 -0
- transitionlistener/logo/TL-logo_small.png +0 -0
- transitionlistener/models/TL_2HDM.py +512 -0
- transitionlistener/models/TL_conformal_dark_u1.py +202 -0
- transitionlistener/models/TL_dark_U1.py +198 -0
- transitionlistener/models/TL_dark_U1_g_parameterization.py +198 -0
- transitionlistener/models/TL_dark_flipflop.py +274 -0
- transitionlistener/models/templatePotential.py +260 -0
- transitionlistener/nucleation.py +412 -0
- transitionlistener/observability.py +790 -0
- transitionlistener/particles.py +436 -0
- transitionlistener/pathDeformation.py +1462 -0
- transitionlistener/percolation_adaptive_gridbuilders.py +1385 -0
- transitionlistener/percolation_adaptive_rate.py +1049 -0
- transitionlistener/percolation_adaptivestepsize.py +1632 -0
- transitionlistener/percolation_fixedstepsize.py +618 -0
- transitionlistener/phases.py +1499 -0
- transitionlistener/plot_settings.py +121 -0
- transitionlistener/plots.py +1781 -0
- transitionlistener/runtime_options.py +278 -0
- transitionlistener/tab_data/30f_fs{hd}_100fDMGP_ceffyl/bandwidths.npy +0 -0
- transitionlistener/tab_data/30f_fs{hd}_100fDMGP_ceffyl/density.npy +0 -0
- transitionlistener/tab_data/30f_fs{hd}_100fDMGP_ceffyl/freqs.npy +0 -0
- transitionlistener/tab_data/30f_fs{hd}_100fDMGP_ceffyl/log.txt +16 -0
- transitionlistener/tab_data/30f_fs{hd}_100fDMGP_ceffyl/log10rhogrid.npy +0 -0
- transitionlistener/tab_data/30f_fs{hd}_100fDMGP_ceffyl/log10rholabels.txt +30 -0
- transitionlistener/tab_data/30f_fs{hd}_100fDMGP_ceffyl/pulsar_list.txt +1 -0
- transitionlistener/tab_data/HLV-O2-PLI.csv +82 -0
- transitionlistener/tab_data/HLV-O2-noise.csv +83 -0
- transitionlistener/tab_data/HLVK-design-PLI.csv +61 -0
- transitionlistener/tab_data/HLVK-design-noise.csv +83 -0
- transitionlistener/tab_data/NG15_PLI_hc.csv +31 -0
- transitionlistener/tab_data/NG15_noise_hc.csv +56 -0
- transitionlistener/tab_data/PLI-dataset.csv +327 -0
- transitionlistener/tab_data/energydensities.dat +1001 -0
- transitionlistener/tab_data/finiteT_b.dat.txt +1999 -0
- transitionlistener/tab_data/finiteT_f.dat.txt +1000 -0
- transitionlistener/tab_data/geff_SM.dat +10009 -0
- transitionlistener/tab_data/muAres_f_Hz_PLI_h2OmegaGW.csv +131 -0
- transitionlistener/tab_data/muAres_f_Hz_h2Omega_noise.csv +99 -0
- transitionlistener/tab_data/noise-dataset.csv +327 -0
- transitionlistener/tab_data/numberdensities.dat +1001 -0
- transitionlistener/tab_data/pressures.dat +1001 -0
- transitionlistener/thermodynamics.py +686 -0
- transitionlistener/transitionObservables.py +1199 -0
- transitionlistener/transitionObservables_fixedstep.py +976 -0
- transitionlistener/transitions.py +1000 -0
- transitionlistener/tunneling1D.py +910 -0
- transitionlistener-2.0.0.dist-info/METADATA +817 -0
- transitionlistener-2.0.0.dist-info/RECORD +95 -0
- transitionlistener-2.0.0.dist-info/WHEEL +4 -0
- transitionlistener-2.0.0.dist-info/entry_points.txt +2 -0
- transitionlistener-2.0.0.dist-info/licenses/LICENSE.txt +674 -0
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
"""CSV output shaping utilities for TransitionListener interfaces.
|
|
2
|
+
|
|
3
|
+
Part of TransitionListener v2.0
|
|
4
|
+
Documentation: https://tasillo.de/TransitionListener/
|
|
5
|
+
|
|
6
|
+
Authors:
|
|
7
|
+
Jonas Matuszak <jonas.matuszak@kit.edu>
|
|
8
|
+
Carlo Tasillo <carlo.tasillo@ific.uv.es>
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
import os
|
|
14
|
+
from typing import Iterable, Sequence
|
|
15
|
+
|
|
16
|
+
import numpy as np
|
|
17
|
+
import pandas as pd
|
|
18
|
+
|
|
19
|
+
# Column groups with preferred ordering
|
|
20
|
+
PTA_LABEL_ORDER = ["NG15_14bins", "NG15_5bins", "NG12_5bins", "IPTA2_13bins"]
|
|
21
|
+
PTA_COLUMNS_ORDER = [
|
|
22
|
+
item
|
|
23
|
+
for label in PTA_LABEL_ORDER
|
|
24
|
+
for item in (
|
|
25
|
+
f"lnL_smoothened_{label}",
|
|
26
|
+
f"lnL_PTArcade_{label}",
|
|
27
|
+
f"lnL_mock_{label}",
|
|
28
|
+
)
|
|
29
|
+
]
|
|
30
|
+
BASE_RESULT_COLUMNS = ["smoothened_lnL", "PTArcade_lnL", "mock_lnL", "error", "errormsg"]
|
|
31
|
+
DERIVED_PREFERRED_ORDER = [
|
|
32
|
+
"alpha",
|
|
33
|
+
"alpha_theta",
|
|
34
|
+
"alpha_thetabar",
|
|
35
|
+
"alpha_inf",
|
|
36
|
+
"alpha_eq",
|
|
37
|
+
"betaH_S3",
|
|
38
|
+
"betaH_RH",
|
|
39
|
+
"RH",
|
|
40
|
+
"Treh_SM_GeV",
|
|
41
|
+
"Tperc_SM_GeV",
|
|
42
|
+
"g_eff_tot_reh",
|
|
43
|
+
"h_eff_tot_reh",
|
|
44
|
+
"kappa_phi",
|
|
45
|
+
"kappa_sw",
|
|
46
|
+
"kappa_turb",
|
|
47
|
+
"g0",
|
|
48
|
+
"h0",
|
|
49
|
+
"v_wall",
|
|
50
|
+
"D",
|
|
51
|
+
"c_s",
|
|
52
|
+
"c_s_sym",
|
|
53
|
+
"c_s_bro",
|
|
54
|
+
"step",
|
|
55
|
+
"total_steps",
|
|
56
|
+
"Tnuc_SM_GeV",
|
|
57
|
+
"Tcrit_SM_GeV",
|
|
58
|
+
"Tf_SM_GeV",
|
|
59
|
+
"xi_crit",
|
|
60
|
+
]
|
|
61
|
+
WARNING_COLUMN_ORDER = [
|
|
62
|
+
"WARNING:too_weak_to_compute_perc",
|
|
63
|
+
"WARNING:no_perc_splines",
|
|
64
|
+
"WARNING:betaH_small",
|
|
65
|
+
"WARNING:betaH_very_small",
|
|
66
|
+
"WARNING:betaH_mismatch",
|
|
67
|
+
"WARNING:betaH_nonfinite",
|
|
68
|
+
"WARNING:nucleationRate_nonexponential",
|
|
69
|
+
"WARNING:not_T0_global_min",
|
|
70
|
+
]
|
|
71
|
+
SNR_COLUMN_ORDER = [
|
|
72
|
+
"B-DECIGO_SNR",
|
|
73
|
+
"BBO_SNR",
|
|
74
|
+
"DECIGO_SNR",
|
|
75
|
+
"EPTA_18_yrs_SNR",
|
|
76
|
+
"ET_SNR",
|
|
77
|
+
"HLVK_design_SNR",
|
|
78
|
+
"HLV_O2_SNR",
|
|
79
|
+
"LISA_SNR",
|
|
80
|
+
"NANOGrav_11_yrs_SNR",
|
|
81
|
+
"NANOGrav_15_yrs_SNR",
|
|
82
|
+
"SKA_10_yrs_SNR",
|
|
83
|
+
"SKA_20_yrs_SNR",
|
|
84
|
+
"SKA_5_yrs_SNR",
|
|
85
|
+
"muAres_SNR",
|
|
86
|
+
]
|
|
87
|
+
PEAK_COLUMN_PRIORITY = [
|
|
88
|
+
"f_peak_Hz",
|
|
89
|
+
"h2OmegaGW_peak",
|
|
90
|
+
"f_pivot_Hz",
|
|
91
|
+
"h2OmegaGW_at_pivot",
|
|
92
|
+
"DNeff_GW",
|
|
93
|
+
]
|
|
94
|
+
STATIC_ORDER_GROUPS = (
|
|
95
|
+
WARNING_COLUMN_ORDER,
|
|
96
|
+
PTA_COLUMNS_ORDER,
|
|
97
|
+
SNR_COLUMN_ORDER,
|
|
98
|
+
PEAK_COLUMN_PRIORITY,
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
class OutputRandomscan:
|
|
103
|
+
"""Ouput handler for the randomscan.
|
|
104
|
+
|
|
105
|
+
It opens a file and appends new results as a row to it.
|
|
106
|
+
This is inteded to be used with the listener/worker threads in the randomscan
|
|
107
|
+
module.
|
|
108
|
+
"""
|
|
109
|
+
|
|
110
|
+
def __init__(self, output_file: str):
|
|
111
|
+
"""Open ``output_file`` in append mode and keep the handle alive across writes."""
|
|
112
|
+
self.file = output_file
|
|
113
|
+
|
|
114
|
+
try:
|
|
115
|
+
self.f = open(self.file, 'a')
|
|
116
|
+
except Exception as e:
|
|
117
|
+
print(e)
|
|
118
|
+
|
|
119
|
+
def stop(self):
|
|
120
|
+
"""Stop the output handler and close the file.
|
|
121
|
+
|
|
122
|
+
Parameters
|
|
123
|
+
----------
|
|
124
|
+
None.
|
|
125
|
+
|
|
126
|
+
Returns
|
|
127
|
+
-------
|
|
128
|
+
None."""
|
|
129
|
+
self.f.close()
|
|
130
|
+
|
|
131
|
+
def write_row(self, inp_params: dict, results: dict):
|
|
132
|
+
"""Write a data point to the output file.
|
|
133
|
+
|
|
134
|
+
Parameters
|
|
135
|
+
----------
|
|
136
|
+
inp_params : dict
|
|
137
|
+
The input parameters of the potential.
|
|
138
|
+
results : dict
|
|
139
|
+
The results that should be written to the csv file.
|
|
140
|
+
|
|
141
|
+
Returns
|
|
142
|
+
-------
|
|
143
|
+
None.
|
|
144
|
+
"""
|
|
145
|
+
data = inp_params.copy()
|
|
146
|
+
|
|
147
|
+
if "_meta_mass_columns" in results.keys():
|
|
148
|
+
results.pop("_meta_mass_columns")
|
|
149
|
+
|
|
150
|
+
data.update(results)
|
|
151
|
+
if os.path.getsize(self.file) == 0:
|
|
152
|
+
# write the header:
|
|
153
|
+
header = ','.join(list(data.keys()))
|
|
154
|
+
self.f.write(header + '\n')
|
|
155
|
+
|
|
156
|
+
row = ','.join([str(val) for val in data.values()])
|
|
157
|
+
self.f.write(row + '\n')
|
|
158
|
+
self.f.flush()
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
class OutputSchema:
|
|
162
|
+
"""Manage the CSV schema used for sampler outputs."""
|
|
163
|
+
|
|
164
|
+
def __init__(self, potential: object | None, derived_param_names: Iterable[str]):
|
|
165
|
+
"""Store the optional potential factory and the preferred derived-column order."""
|
|
166
|
+
self.potential = potential
|
|
167
|
+
self.derived_keys = list(derived_param_names)
|
|
168
|
+
|
|
169
|
+
def append_row(self, output_file: str, inputparams_dict: dict, res_params: dict) -> None:
|
|
170
|
+
"""Append a single result row to ``output_file`` using the configured schema."""
|
|
171
|
+
row, column_order = self._prepare_row(inputparams_dict, res_params)
|
|
172
|
+
|
|
173
|
+
file_exists = os.path.exists(output_file)
|
|
174
|
+
file_nonempty = file_exists and os.path.getsize(output_file) > 0
|
|
175
|
+
|
|
176
|
+
if file_nonempty:
|
|
177
|
+
existing_df = pd.read_csv(output_file)
|
|
178
|
+
total_order = list(dict.fromkeys(column_order + list(existing_df.columns)))
|
|
179
|
+
row_data = {col: row.get(col, np.nan) for col in total_order}
|
|
180
|
+
row_df = pd.DataFrame([row_data], columns=total_order)
|
|
181
|
+
existing_df = existing_df.reindex(columns=total_order, fill_value=np.nan)
|
|
182
|
+
combined = pd.concat([existing_df, row_df], ignore_index=True)
|
|
183
|
+
combined.to_csv(output_file, index=False)
|
|
184
|
+
return
|
|
185
|
+
|
|
186
|
+
row_data = {col: row.get(col, np.nan) for col in column_order}
|
|
187
|
+
row_df = pd.DataFrame([row_data], columns=column_order)
|
|
188
|
+
row_df.to_csv(output_file, index=False)
|
|
189
|
+
|
|
190
|
+
def _prepare_row(self, inputparams_dict: dict, res_params: dict) -> tuple[dict, list[str]]:
|
|
191
|
+
"""Merge input/output data and return the normalised row plus its column order."""
|
|
192
|
+
row = {**inputparams_dict}
|
|
193
|
+
row.update(res_params)
|
|
194
|
+
|
|
195
|
+
mass_columns = list(row.pop("_meta_mass_columns", []))
|
|
196
|
+
row.pop("lnL", None)
|
|
197
|
+
|
|
198
|
+
meta_keys = [key for key in row if key.startswith("_meta_")]
|
|
199
|
+
for key in meta_keys:
|
|
200
|
+
row.pop(key, None)
|
|
201
|
+
|
|
202
|
+
error_value = row.get("error")
|
|
203
|
+
if self.potential is not None and error_value not in (0, None):
|
|
204
|
+
for column, value in self._compute_mass_columns(inputparams_dict):
|
|
205
|
+
if column not in mass_columns:
|
|
206
|
+
mass_columns.append(column)
|
|
207
|
+
row[column] = value
|
|
208
|
+
|
|
209
|
+
column_order = _build_column_order(
|
|
210
|
+
inputparams_dict,
|
|
211
|
+
self.derived_keys,
|
|
212
|
+
row.keys(),
|
|
213
|
+
mass_columns,
|
|
214
|
+
)
|
|
215
|
+
return row, column_order
|
|
216
|
+
|
|
217
|
+
def _compute_mass_columns(self, inputparams_dict: dict) -> list[tuple[str, float]]:
|
|
218
|
+
"""Compute fallback zero-temperature mass columns for failed parameter points."""
|
|
219
|
+
if self.potential is None:
|
|
220
|
+
return []
|
|
221
|
+
try:
|
|
222
|
+
potential = self.potential(inputparams_dict, verbose=False) # type: ignore[attr-defined]
|
|
223
|
+
except Exception:
|
|
224
|
+
return []
|
|
225
|
+
|
|
226
|
+
getter = getattr(potential, "get_zero_temperature_mass_spectrum", None)
|
|
227
|
+
if getter is None:
|
|
228
|
+
return []
|
|
229
|
+
|
|
230
|
+
try:
|
|
231
|
+
entries = getter()
|
|
232
|
+
except Exception:
|
|
233
|
+
entries = []
|
|
234
|
+
|
|
235
|
+
used_columns: set[str] = set()
|
|
236
|
+
results: list[tuple[str, float]] = []
|
|
237
|
+
|
|
238
|
+
def _unique_column(base: str) -> str:
|
|
239
|
+
candidate = base or "mass"
|
|
240
|
+
index = 2
|
|
241
|
+
while candidate in used_columns:
|
|
242
|
+
candidate = f"{base}_{index}"
|
|
243
|
+
index += 1
|
|
244
|
+
used_columns.add(candidate)
|
|
245
|
+
return candidate
|
|
246
|
+
|
|
247
|
+
for entry in entries or []:
|
|
248
|
+
text_label = str(entry.get("text", "")).strip()
|
|
249
|
+
kind = entry.get("kind", "boson")
|
|
250
|
+
index = int(entry.get("index", 0))
|
|
251
|
+
base_name = text_label or f"mass_spectrum_T0_{kind}_{index:02d}"
|
|
252
|
+
column = _unique_column(base_name)
|
|
253
|
+
|
|
254
|
+
mass_value = entry.get("mass_GeV", np.nan)
|
|
255
|
+
if isinstance(mass_value, (np.ndarray, list, tuple)):
|
|
256
|
+
mass_value = np.asarray(mass_value).flatten()[0] if np.asarray(mass_value).size else np.nan
|
|
257
|
+
try:
|
|
258
|
+
value = float(mass_value)
|
|
259
|
+
except (TypeError, ValueError):
|
|
260
|
+
value = np.nan
|
|
261
|
+
|
|
262
|
+
if not np.isfinite(value):
|
|
263
|
+
if column.startswith("m_G"):
|
|
264
|
+
value = 0.0
|
|
265
|
+
else:
|
|
266
|
+
value = np.nan
|
|
267
|
+
|
|
268
|
+
results.append((column, value))
|
|
269
|
+
|
|
270
|
+
return results
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
def _build_column_order(
|
|
274
|
+
inputparams_dict: dict,
|
|
275
|
+
derived_keys: Sequence[str],
|
|
276
|
+
row_keys: Iterable[str],
|
|
277
|
+
mass_columns: Sequence[str],
|
|
278
|
+
) -> list[str]:
|
|
279
|
+
"""Construct a stable CSV column order that keeps related observables grouped together."""
|
|
280
|
+
base_order: list[str] = list(inputparams_dict.keys())
|
|
281
|
+
base_order.extend(BASE_RESULT_COLUMNS)
|
|
282
|
+
base_order.extend(
|
|
283
|
+
col for col in DERIVED_PREFERRED_ORDER if col in derived_keys or col in row_keys
|
|
284
|
+
)
|
|
285
|
+
base_order.extend(col for col in derived_keys if col not in DERIVED_PREFERRED_ORDER)
|
|
286
|
+
for group in STATIC_ORDER_GROUPS:
|
|
287
|
+
base_order.extend(group)
|
|
288
|
+
|
|
289
|
+
remaining = sorted(
|
|
290
|
+
col
|
|
291
|
+
for col in row_keys
|
|
292
|
+
if col not in base_order and col not in mass_columns
|
|
293
|
+
)
|
|
294
|
+
base_order.extend(remaining)
|
|
295
|
+
base_order.extend(mass_columns)
|
|
296
|
+
return list(dict.fromkeys(base_order))
|
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
"""Core execution pipeline for evaluating a single parameter point.
|
|
2
|
+
|
|
3
|
+
Part of TransitionListener v2.0
|
|
4
|
+
Documentation: https://tasillo.de/TransitionListener/
|
|
5
|
+
|
|
6
|
+
Authors:
|
|
7
|
+
Jonas Matuszak <jonas.matuszak@kit.edu>
|
|
8
|
+
Carlo Tasillo <carlo.tasillo@ific.uv.es>
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
import signal
|
|
14
|
+
from typing import Callable, Dict, Optional
|
|
15
|
+
|
|
16
|
+
import numpy as np
|
|
17
|
+
|
|
18
|
+
from transitionlistener.phases import Phases
|
|
19
|
+
from transitionlistener.transitions import Transitions
|
|
20
|
+
from transitionlistener.transitionObservables import (
|
|
21
|
+
TransitionObservables as _TransitionObservablesAdaptiveStepSize,
|
|
22
|
+
)
|
|
23
|
+
from transitionlistener.transitionObservables_fixedstep import (
|
|
24
|
+
TransitionObservables as _TransitionObservablesFixedStepSize,
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def _select_observables_class(pot):
|
|
29
|
+
"""Return the TransitionObservables class for the configured algorithm_mode."""
|
|
30
|
+
if pot.config.percolationConf.algorithm_mode == "fixed_step_size":
|
|
31
|
+
return _TransitionObservablesFixedStepSize
|
|
32
|
+
return _TransitionObservablesAdaptiveStepSize
|
|
33
|
+
from transitionlistener.gwfopt import FOPTspectrum
|
|
34
|
+
from transitionlistener.observability import Observability
|
|
35
|
+
|
|
36
|
+
from transitionlistener import console
|
|
37
|
+
from rich.panel import Panel
|
|
38
|
+
|
|
39
|
+
from . import state
|
|
40
|
+
from .logging_utils import Logger
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def _find_strongest_transition(transition_observables: dict) -> dict:
|
|
44
|
+
"""Return the transition entry with the largest alpha among FOPTs."""
|
|
45
|
+
max_alpha = -np.inf
|
|
46
|
+
strongest_transition = None
|
|
47
|
+
fallback_transition = None
|
|
48
|
+
for obs in transition_observables.values():
|
|
49
|
+
if not obs or obs.get("trantype", 1) != 1:
|
|
50
|
+
continue
|
|
51
|
+
if fallback_transition is None and np.isfinite(obs.get("Treh_SM_GeV", np.nan)):
|
|
52
|
+
fallback_transition = obs
|
|
53
|
+
alpha = obs.get("alpha", np.nan)
|
|
54
|
+
if np.isfinite(alpha) and alpha > max_alpha:
|
|
55
|
+
max_alpha = alpha
|
|
56
|
+
strongest_transition = obs
|
|
57
|
+
return strongest_transition or fallback_transition or {}
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def _extract_zero_temperature_mass_spectrum(potential) -> dict:
|
|
61
|
+
"""Return observability-style entries describing the T=0 mass spectrum."""
|
|
62
|
+
|
|
63
|
+
if potential is None or not hasattr(potential, "get_zero_temperature_mass_spectrum"):
|
|
64
|
+
return {}
|
|
65
|
+
|
|
66
|
+
entries = potential.get_zero_temperature_mass_spectrum()
|
|
67
|
+
if not entries:
|
|
68
|
+
return {}
|
|
69
|
+
|
|
70
|
+
spectrum_entries: Dict[str, object] = {}
|
|
71
|
+
for entry in entries:
|
|
72
|
+
kind = entry.get("kind", "boson")
|
|
73
|
+
index = entry.get("index", 0)
|
|
74
|
+
base_name = f"mass_spectrum_T0_{kind}_{index:02d}"
|
|
75
|
+
mass_value = entry.get("mass_GeV", np.nan)
|
|
76
|
+
log_value = entry.get("log10_mass", np.nan)
|
|
77
|
+
latex_label = entry.get("latex")
|
|
78
|
+
text_label = entry.get("text")
|
|
79
|
+
|
|
80
|
+
if isinstance(mass_value, (int, float, np.integer, np.floating)) and np.isfinite(mass_value):
|
|
81
|
+
spectrum_entries[f"{base_name}_lin"] = float(mass_value)
|
|
82
|
+
else:
|
|
83
|
+
spectrum_entries[f"{base_name}_lin"] = np.nan
|
|
84
|
+
if isinstance(log_value, (int, float, np.integer, np.floating)) and np.isfinite(log_value):
|
|
85
|
+
spectrum_entries[f"{base_name}_log10"] = float(log_value)
|
|
86
|
+
else:
|
|
87
|
+
spectrum_entries[f"{base_name}_log10"] = np.nan
|
|
88
|
+
if latex_label is not None:
|
|
89
|
+
spectrum_entries[f"{base_name}_latex"] = latex_label
|
|
90
|
+
if text_label is not None:
|
|
91
|
+
spectrum_entries[f"{base_name}_text"] = text_label
|
|
92
|
+
spectrum_entries[f"{base_name}_kind"] = kind
|
|
93
|
+
|
|
94
|
+
return spectrum_entries
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def _compute_single_point(
|
|
98
|
+
inputparams_dict: dict,
|
|
99
|
+
potential: object,
|
|
100
|
+
timeout: float,
|
|
101
|
+
verbose: bool,
|
|
102
|
+
include_smbhb: bool,
|
|
103
|
+
max_stage: int = 4,
|
|
104
|
+
stage_callback: Optional[Callable[[str, dict], None]] = None,
|
|
105
|
+
):
|
|
106
|
+
"""Execute the single-point pipeline up to ``max_stage`` and optionally
|
|
107
|
+
notify after each stage."""
|
|
108
|
+
|
|
109
|
+
context: Dict[str, object] = {
|
|
110
|
+
"pot": None,
|
|
111
|
+
"phases": None,
|
|
112
|
+
"transitions": None,
|
|
113
|
+
"transition_observables": None,
|
|
114
|
+
"strongest_transition_observables": None,
|
|
115
|
+
"gwspectrum": None,
|
|
116
|
+
"observability": None,
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
def notify(stage_name: str):
|
|
120
|
+
if stage_callback is not None:
|
|
121
|
+
stage_callback(stage_name, context)
|
|
122
|
+
|
|
123
|
+
if include_smbhb:
|
|
124
|
+
A = inputparams_dict.get("A_smbhb", 1e-15)
|
|
125
|
+
gamma = inputparams_dict.get("gamma_smbhb", 2 / 3)
|
|
126
|
+
astroparams_dict = {"A": A, "gamma": gamma}
|
|
127
|
+
else:
|
|
128
|
+
astroparams_dict = {"A": 0, "gamma": 0}
|
|
129
|
+
|
|
130
|
+
if timeout > 0 and not state.DEBUGMODE:
|
|
131
|
+
signal.alarm(timeout)
|
|
132
|
+
try:
|
|
133
|
+
context["pot"] = potential(inputparams_dict, verbose=verbose)
|
|
134
|
+
notify("potential")
|
|
135
|
+
|
|
136
|
+
if max_stage >= 1:
|
|
137
|
+
context["phases"] = Phases(context["pot"], verbose)
|
|
138
|
+
notify("phases")
|
|
139
|
+
|
|
140
|
+
if max_stage >= 2:
|
|
141
|
+
context["transitions"] = Transitions(context["phases"],
|
|
142
|
+
context["pot"], verbose)
|
|
143
|
+
notify("transitions")
|
|
144
|
+
|
|
145
|
+
if max_stage >= 3:
|
|
146
|
+
TransitionObservables = _select_observables_class(context["pot"])
|
|
147
|
+
transition_observables = TransitionObservables(
|
|
148
|
+
context["pot"], context["phases"],
|
|
149
|
+
context["transitions"], verbose
|
|
150
|
+
)
|
|
151
|
+
context["transition_observables"] = transition_observables
|
|
152
|
+
context["strongest_transition_observables"] = _find_strongest_transition(
|
|
153
|
+
transition_observables.transitionObservables
|
|
154
|
+
)
|
|
155
|
+
notify("observables")
|
|
156
|
+
|
|
157
|
+
if max_stage >= 4:
|
|
158
|
+
try:
|
|
159
|
+
gwspectrum = FOPTspectrum(
|
|
160
|
+
context["strongest_transition_observables"],
|
|
161
|
+
astroparams_dict, verbose
|
|
162
|
+
)
|
|
163
|
+
observability = Observability(
|
|
164
|
+
gwspectrum, verbose, include_smbhb=include_smbhb
|
|
165
|
+
)
|
|
166
|
+
context["gwspectrum"] = gwspectrum
|
|
167
|
+
context["observability"] = observability
|
|
168
|
+
notify("gw")
|
|
169
|
+
except Exception as err:
|
|
170
|
+
if context.get("transition_observables") is None:
|
|
171
|
+
raise
|
|
172
|
+
if verbose:
|
|
173
|
+
print(f"Skipping GW observability after transition observables: {err}")
|
|
174
|
+
|
|
175
|
+
signal.alarm(0)
|
|
176
|
+
return context, None
|
|
177
|
+
except Exception as err:
|
|
178
|
+
signal.alarm(0)
|
|
179
|
+
if state.DEBUGMODE:
|
|
180
|
+
raise
|
|
181
|
+
return context, err
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
def _build_result_from_context(context: dict) -> dict:
|
|
185
|
+
"""Construct the result dictionary returned by ``run_TL``
|
|
186
|
+
from the computation context."""
|
|
187
|
+
transition_observables = context.get("transition_observables")
|
|
188
|
+
strongest = context.get("strongest_transition_observables") or {}
|
|
189
|
+
gwspectrum = context.get("gwspectrum")
|
|
190
|
+
observability = context.get("observability")
|
|
191
|
+
potential = context.get("pot")
|
|
192
|
+
|
|
193
|
+
observability_dict = (
|
|
194
|
+
observability.observability_dict.copy()
|
|
195
|
+
if observability is not None
|
|
196
|
+
else {}
|
|
197
|
+
)
|
|
198
|
+
|
|
199
|
+
return {
|
|
200
|
+
"transitionObservables": transition_observables.transitionObservables
|
|
201
|
+
if transition_observables is not None
|
|
202
|
+
else {},
|
|
203
|
+
"strongestTransitionObservables": strongest,
|
|
204
|
+
"gwspectrum": gwspectrum.gwspec_dict if gwspectrum is not None else {},
|
|
205
|
+
"observability": observability_dict,
|
|
206
|
+
"error": np.nan,
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
def _handle_single_point_error(
|
|
211
|
+
error: Exception,
|
|
212
|
+
inputparams_dict: dict,
|
|
213
|
+
errorlogger: Logger,
|
|
214
|
+
context: dict,
|
|
215
|
+
):
|
|
216
|
+
"""Log the error and shape a result dictionary containing
|
|
217
|
+
available partial results."""
|
|
218
|
+
error_code = getattr(error, "errorcode", -1)
|
|
219
|
+
message = getattr(error, "message", str(error))
|
|
220
|
+
line = (
|
|
221
|
+
"ERROR of type "
|
|
222
|
+
+ str(error_code)
|
|
223
|
+
+ " for input parameters "
|
|
224
|
+
+ str(inputparams_dict)
|
|
225
|
+
+ ": "
|
|
226
|
+
+ message
|
|
227
|
+
)
|
|
228
|
+
errorlogger.log(line + "\n")
|
|
229
|
+
console.print(Panel.fit(line, border_style="red"))
|
|
230
|
+
|
|
231
|
+
result = {
|
|
232
|
+
"error": np.array([error_code]),
|
|
233
|
+
}
|
|
234
|
+
transition_observables = context.get("transition_observables")
|
|
235
|
+
if transition_observables is not None:
|
|
236
|
+
result["transitionObservables"] = transition_observables.transitionObservables
|
|
237
|
+
strongest = context.get("strongest_transition_observables")
|
|
238
|
+
if strongest:
|
|
239
|
+
result["strongestTransitionObservables"] = strongest
|
|
240
|
+
gwspectrum = context.get("gwspectrum")
|
|
241
|
+
if gwspectrum is not None:
|
|
242
|
+
result["gwspectrum"] = gwspectrum.gwspec_dict
|
|
243
|
+
observability = context.get("observability")
|
|
244
|
+
potential = context.get("pot")
|
|
245
|
+
observability_dict = (
|
|
246
|
+
observability.observability_dict.copy()
|
|
247
|
+
if observability is not None
|
|
248
|
+
else {}
|
|
249
|
+
)
|
|
250
|
+
spectrum_entries = _extract_zero_temperature_mass_spectrum(potential)
|
|
251
|
+
observability_dict.update(spectrum_entries)
|
|
252
|
+
if observability_dict:
|
|
253
|
+
result["observability"] = observability_dict
|
|
254
|
+
|
|
255
|
+
return result
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
def run_TL(
|
|
259
|
+
inputparams_dict: dict,
|
|
260
|
+
potential: object,
|
|
261
|
+
errorlogger: Logger,
|
|
262
|
+
resultlogger: Logger,
|
|
263
|
+
timeout: float,
|
|
264
|
+
verbose: bool = False,
|
|
265
|
+
call_from_sampler: bool = False,
|
|
266
|
+
include_smbhb: bool = False,
|
|
267
|
+
return_context: bool = False,
|
|
268
|
+
):
|
|
269
|
+
"""Core execution pipeline that evaluates observables for a
|
|
270
|
+
single parameter point."""
|
|
271
|
+
|
|
272
|
+
def return_result(params):
|
|
273
|
+
observability = params.get("observability", {})
|
|
274
|
+
line = str(inputparams_dict) + ":" + str(observability)
|
|
275
|
+
resultlogger.log(line + "\n")
|
|
276
|
+
|
|
277
|
+
context, error = _compute_single_point(
|
|
278
|
+
inputparams_dict,
|
|
279
|
+
potential,
|
|
280
|
+
timeout,
|
|
281
|
+
verbose,
|
|
282
|
+
include_smbhb,
|
|
283
|
+
max_stage=4,
|
|
284
|
+
)
|
|
285
|
+
|
|
286
|
+
if error is not None:
|
|
287
|
+
if call_from_sampler:
|
|
288
|
+
raise error
|
|
289
|
+
result = _handle_single_point_error(error, inputparams_dict,
|
|
290
|
+
errorlogger, context)
|
|
291
|
+
if return_context:
|
|
292
|
+
return result, context
|
|
293
|
+
return result
|
|
294
|
+
|
|
295
|
+
all_params_dict = _build_result_from_context(context)
|
|
296
|
+
if resultlogger is not None:
|
|
297
|
+
return_result(all_params_dict)
|
|
298
|
+
if return_context:
|
|
299
|
+
return all_params_dict, context
|
|
300
|
+
return all_params_dict
|