dgm-dayabay-dev 0.2__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.
Files changed (49) hide show
  1. dgm_dayabay_dev/__init__.py +0 -0
  2. dgm_dayabay_dev/bundles/__init__.py +0 -0
  3. dgm_dayabay_dev/bundles/cross_check_refine_lsnl_data.py +77 -0
  4. dgm_dayabay_dev/bundles/refine_detector_data.py +46 -0
  5. dgm_dayabay_dev/bundles/refine_lsnl_data.py +161 -0
  6. dgm_dayabay_dev/bundles/refine_reactor_data.py +304 -0
  7. dgm_dayabay_dev/bundles/sync_reactor_detector_data.py +39 -0
  8. dgm_dayabay_dev/models/__init__.py +64 -0
  9. dgm_dayabay_dev/models/dayabay_labels.py +102 -0
  10. dgm_dayabay_dev/models/dayabay_v0.py +1689 -0
  11. dgm_dayabay_dev/models/dayabay_v0_labels.yaml +635 -0
  12. dgm_dayabay_dev/models/dayabay_v0b.py +1841 -0
  13. dgm_dayabay_dev/models/dayabay_v0b_labels.yaml +644 -0
  14. dgm_dayabay_dev/models/dayabay_v0c.py +2130 -0
  15. dgm_dayabay_dev/models/dayabay_v0c_labels.yaml +644 -0
  16. dgm_dayabay_dev/models/dayabay_v0d.py +2781 -0
  17. dgm_dayabay_dev/models/dayabay_v0d_labels.yaml +773 -0
  18. dgm_dayabay_dev/models/dayabay_v0e.py +3748 -0
  19. dgm_dayabay_dev/models/dayabay_v0e_labels.yaml +1284 -0
  20. dgm_dayabay_dev/nodes/AxisDistortionMatrixLinearLegacy.py +191 -0
  21. dgm_dayabay_dev/nodes/Monotonize.py +172 -0
  22. dgm_dayabay_dev/nodes/__init__.py +0 -0
  23. dgm_dayabay_dev/scripts/__init__.py +662 -0
  24. dgm_dayabay_dev/scripts/check_global_normalization.py +198 -0
  25. dgm_dayabay_dev/scripts/cmp_models_v0.py +266 -0
  26. dgm_dayabay_dev/scripts/covmatrix_dayabay_v0.py +142 -0
  27. dgm_dayabay_dev/scripts/covmatrix_mc.py +391 -0
  28. dgm_dayabay_dev/scripts/covmatrix_plot.py +621 -0
  29. dgm_dayabay_dev/scripts/cross_fit_config.yaml +12 -0
  30. dgm_dayabay_dev/scripts/crosscheck_dayabay_nuisance_v0.py +627 -0
  31. dgm_dayabay_dev/scripts/crosscheck_dayabay_v0.py +596 -0
  32. dgm_dayabay_dev/scripts/fit_dayabay_contour.py +374 -0
  33. dgm_dayabay_dev/scripts/fit_dayabay_cross_model.py +260 -0
  34. dgm_dayabay_dev/scripts/fit_dayabay_model.py +225 -0
  35. dgm_dayabay_dev/scripts/fit_dayabay_v0.py +273 -0
  36. dgm_dayabay_dev/scripts/plot_dayabay_v0_data_detector_time_dependent.py +207 -0
  37. dgm_dayabay_dev/scripts/plot_dayabay_v0_data_reactor_time_dependent.py +196 -0
  38. dgm_dayabay_dev/scripts/plot_fit_2d.py +124 -0
  39. dgm_dayabay_dev/scripts/plot_fit_article.py +324 -0
  40. dgm_dayabay_dev/scripts/plot_fit_dayabay.py +345 -0
  41. dgm_dayabay_dev/scripts/run_dayabay_v0.py +419 -0
  42. dgm_dayabay_dev/scripts/run_profiling_v0.py +365 -0
  43. dgm_dayabay_dev/scripts/run_profiling_v0e.py +288 -0
  44. dgm_dayabay_dev/scripts/test_lsnl_curves.py +230 -0
  45. dgm_dayabay_dev-0.2.dist-info/METADATA +49 -0
  46. dgm_dayabay_dev-0.2.dist-info/RECORD +49 -0
  47. dgm_dayabay_dev-0.2.dist-info/WHEEL +5 -0
  48. dgm_dayabay_dev-0.2.dist-info/licenses/LICENSE +21 -0
  49. dgm_dayabay_dev-0.2.dist-info/top_level.txt +1 -0
File without changes
File without changes
@@ -0,0 +1,77 @@
1
+ from numpy import arange
2
+ from numpy.typing import NDArray
3
+ from scipy.interpolate import interp1d
4
+
5
+ from nested_mapping.nested_mapping import NestedMapping
6
+
7
+
8
+ def cross_check_refine_lsnl_data(
9
+ storage: NestedMapping, *, xname: str, nominalname: str, **kwargs
10
+ ) -> None:
11
+ xcoarse = storage[xname]
12
+
13
+ refiner = RefineGraph(xcoarse, **kwargs)
14
+
15
+ for key, ycoarse in storage.walkitems():
16
+ if ycoarse is xcoarse:
17
+ continue
18
+
19
+ nominal = storage[nominalname]
20
+ storage[key] = refiner.process(ycoarse, nominal)
21
+
22
+ storage[xname] = refiner.xfine
23
+
24
+
25
+ class RefineGraph:
26
+ __slots__ = (
27
+ "xcoarse",
28
+ "xfine",
29
+ "newmin",
30
+ "newmax",
31
+ )
32
+ xcoarse: NDArray
33
+ xfine: NDArray
34
+ newmin: float
35
+ newmax: float
36
+
37
+ def __init__(
38
+ self,
39
+ xcoarse: NDArray,
40
+ *,
41
+ newmin: float,
42
+ newmax: float,
43
+ ):
44
+ self.xcoarse = xcoarse
45
+ self.newmin = newmin
46
+ self.newmax = newmax
47
+
48
+ self._process_x()
49
+
50
+ def make_x(self) -> None:
51
+ self.xfine = arange(0.0, 12.0000001, 0.05)
52
+
53
+ def _process_x(self) -> None:
54
+ self.make_x()
55
+
56
+ def process(self, y: NDArray, nominal: NDArray) -> NDArray:
57
+ skip_diff = y is nominal
58
+ yfine = self._method_interpolate(y)
59
+ yabs = self._method_reltoabs(yfine)
60
+
61
+ return yabs if skip_diff else self._method_diff(nominal, yabs)
62
+
63
+ def _method_reltoabs(self, yrel: NDArray) -> NDArray:
64
+ return yrel * self.xfine
65
+
66
+ def _method_interpolate(self, ycoarse) -> NDArray:
67
+ fcn = interp1d(
68
+ self.xcoarse,
69
+ ycoarse,
70
+ kind="linear",
71
+ bounds_error=False,
72
+ fill_value="extrapolate",
73
+ )
74
+ return fcn(self.xfine)
75
+
76
+ def _method_diff(self, nominal: NDArray, y: NDArray) -> NDArray:
77
+ return nominal if nominal is y else y - nominal
@@ -0,0 +1,46 @@
1
+ from collections.abc import Sequence
2
+
3
+ from nested_mapping import NestedMapping
4
+
5
+
6
+ def refine_detector_data(
7
+ source: NestedMapping,
8
+ target: NestedMapping,
9
+ *,
10
+ detectors: Sequence[str],
11
+ periods: Sequence[str] = ("6AD", "8AD", "7AD"),
12
+ clean_source: bool = True,
13
+ columns=("livetime", "eff", "efflivetime"),
14
+ skip: Sequence[set[str]] | None = None,
15
+ ) -> None:
16
+ """Read arrays with detector data for the whole data taking period, write detector
17
+ data for each period in separate array.
18
+ """
19
+ target["days"] = (days_storage := {})
20
+ for det in detectors:
21
+ day = source["day", det]
22
+ step = day[1:] - day[:-1]
23
+ assert (step == 1).all(), "Expect detector data for each day"
24
+
25
+ ndet = source["ndet", det]
26
+ for periodname in periods:
27
+ period_ndet = int(periodname[0])
28
+ mask_period = ndet == period_ndet
29
+
30
+ for field in columns:
31
+ data = source[field, det]
32
+
33
+ key = (field, periodname, det)
34
+ if skip is not None and any(skipkey.issubset(key) for skipkey in skip):
35
+ continue
36
+
37
+ target[key] = data[mask_period]
38
+
39
+ days = source["day", det][mask_period]
40
+ days_stored = days_storage.setdefault(periodname, days)
41
+ if days is not days_stored:
42
+ assert all(days == days_stored)
43
+
44
+ if clean_source:
45
+ for key in tuple(source.walkkeys()):
46
+ source.delete_with_parents(key)
@@ -0,0 +1,161 @@
1
+ from numpy import arange, concatenate, linspace
2
+ from numpy.typing import NDArray
3
+ from scipy.interpolate import interp1d
4
+
5
+ from nested_mapping.nested_mapping import NestedMapping
6
+
7
+
8
+ def refine_lsnl_data(
9
+ storage: NestedMapping, *, xname: str, nominalname: str, **kwargs
10
+ ) -> None:
11
+ xcoarse = storage[xname]
12
+
13
+ refiner = RefineGraph(xcoarse, **kwargs)
14
+
15
+ for key, ycoarse in storage.walkitems():
16
+ if ycoarse is xcoarse:
17
+ continue
18
+
19
+ nominal = storage[nominalname]
20
+ storage[key] = refiner.process(ycoarse, nominal)
21
+
22
+ storage[xname] = refiner.xfine_extended
23
+
24
+
25
+ class RefineGraph:
26
+ __slots__ = (
27
+ "xcoarse",
28
+ "xfine_bound",
29
+ "xfine_extended",
30
+ "xfine_extended_stack",
31
+ "refine_times",
32
+ "newmin",
33
+ "newmax",
34
+ "savgol_filter_smoothen",
35
+ )
36
+ xcoarse: NDArray
37
+ xfine_bound: NDArray
38
+ xfine_extended: NDArray
39
+ xfine_extended_stack: tuple[NDArray | None, NDArray | None, NDArray | None]
40
+ refine_times: int
41
+ newmin: float
42
+ newmax: float
43
+ savgol_filter_smoothen: tuple[int, int] | None
44
+
45
+ def __init__(
46
+ self,
47
+ xcoarse: NDArray,
48
+ *,
49
+ refine_times: int,
50
+ newmin: float,
51
+ newmax: float,
52
+ savgol_filter_smoothen: tuple[int, int] | None = None,
53
+ ):
54
+ self.xcoarse = xcoarse
55
+ self.refine_times = refine_times
56
+ self.newmin = newmin
57
+ self.newmax = newmax
58
+ self.savgol_filter_smoothen = savgol_filter_smoothen
59
+
60
+ self._process_x()
61
+
62
+ def make_finer_x(self) -> None:
63
+ assert self.refine_times % 1 == 0 and self.refine_times > 0
64
+
65
+ if self.refine_times == 1:
66
+ self.xfine_bound = self.xcoarse.copy()
67
+ return
68
+
69
+ shape_fine = (self.xcoarse.size - 1) * self.refine_times + 1
70
+ self.xfine_bound = linspace(self.xcoarse[0], self.xcoarse[-1], shape_fine)
71
+
72
+ def make_extended_x(self):
73
+ if self.newmin is None and self.newmax is None:
74
+ return
75
+
76
+ xstack = [None, self.xfine_bound, None]
77
+ if self.newmin is not None:
78
+ xstack[0] = arange(
79
+ self.newmin,
80
+ self.xfine_bound[0],
81
+ self.xfine_bound[1] - self.xfine_bound[0],
82
+ )
83
+
84
+ if self.newmax is not None:
85
+ stepright = self.xfine_bound[-1] - self.xfine_bound[-2]
86
+ xstack[-1] = arange(
87
+ self.xfine_bound[-1], self.newmax + stepright * 1.0e-6, stepright
88
+ )[1:]
89
+
90
+ self.xfine_extended = concatenate(xstack)
91
+ self.xfine_extended_stack = tuple(xstack)
92
+
93
+ def _process_x(self):
94
+ self.make_finer_x()
95
+ self.make_extended_x()
96
+
97
+ def process(
98
+ self,
99
+ y: NDArray,
100
+ nominal: NDArray,
101
+ ) -> NDArray:
102
+ skip_diff = y is nominal
103
+ yabs = self._method_reltoabs(y)
104
+ yfine = self._method_interpolate(yabs)
105
+ yunbound = self._method_extrapolate(yfine)
106
+
107
+ if skip_diff:
108
+ return yunbound
109
+
110
+ ydiff = self._method_diff(nominal, yunbound)
111
+ if self.savgol_filter_smoothen is None:
112
+ return ydiff
113
+
114
+ ydiff_smooth = self._method_filter(ydiff)
115
+ return ydiff_smooth
116
+
117
+ def _method_reltoabs(self, yrel: NDArray) -> NDArray:
118
+ return yrel * self.xcoarse
119
+
120
+ def _method_interpolate(self, ycoarse) -> NDArray:
121
+ if self.refine_times == 1:
122
+ return ycoarse.copy()
123
+
124
+ fcn = interp1d(
125
+ self.xcoarse,
126
+ ycoarse,
127
+ kind="cubic",
128
+ bounds_error=False,
129
+ fill_value="extrapolate",
130
+ )
131
+ return fcn(self.xfine_bound)
132
+
133
+ def _method_extrapolate(self, ybound: NDArray) -> NDArray:
134
+ fcn = interp1d(
135
+ self.xfine_bound,
136
+ ybound,
137
+ kind="linear",
138
+ bounds_error=False,
139
+ fill_value="extrapolate",
140
+ )
141
+
142
+ xleft, _, xright = self.xfine_extended_stack
143
+ ystack = [None, ybound, None]
144
+ if xleft is not None:
145
+ ystack[0] = fcn(xleft)
146
+ if xright is not None:
147
+ ystack[-1] = fcn(xright)
148
+
149
+ return concatenate(ystack)
150
+
151
+ def _method_diff(self, nominal: NDArray, y: NDArray) -> NDArray:
152
+ return nominal if nominal is y else y - nominal
153
+
154
+ def _method_filter(self, y: NDArray) -> NDArray:
155
+ if self.savgol_filter_smoothen is None:
156
+ return y.copy()
157
+
158
+ from scipy.signal import savgol_filter
159
+
160
+ npoints_coarse, deg = self.savgol_filter_smoothen
161
+ return savgol_filter(y, npoints_coarse * self.refine_times, deg)
@@ -0,0 +1,304 @@
1
+ from collections.abc import Sequence
2
+
3
+ from numba import njit
4
+ from numpy import empty, isnan
5
+ from numpy.typing import NDArray
6
+
7
+ from nested_mapping import NestedMapping
8
+
9
+
10
+ @njit
11
+ def weekly_to_daily(array: NDArray) -> NDArray:
12
+ ret = empty(array.shape[0] * 7)
13
+
14
+ for i in range(7):
15
+ ret[i::7] = array
16
+
17
+ return ret
18
+
19
+
20
+ @njit
21
+ def inperiod_to_daily(array: NDArray, ndays: int) -> NDArray:
22
+ ret = empty(array.shape[0] * ndays)
23
+
24
+ for i in range(ndays):
25
+ ret[i::ndays] = array
26
+
27
+ return ret
28
+
29
+
30
+ @njit
31
+ def periods_to_days(array: NDArray, ndays: int) -> NDArray:
32
+ ret = empty(array.shape[0] * ndays)
33
+
34
+ for i in range(ndays):
35
+ ret[i::ndays] = array
36
+ ret[i::ndays] += i
37
+
38
+ return ret
39
+
40
+
41
+ @njit
42
+ def weeks_to_days(array: NDArray) -> NDArray:
43
+ ret = empty(array.shape[0] * 7)
44
+
45
+ for i in range(7):
46
+ ret[i::7] = array
47
+ ret[i::7] += i
48
+
49
+ return ret
50
+
51
+
52
+ def refine_reactor_data(
53
+ source: NestedMapping,
54
+ target: NestedMapping,
55
+ *,
56
+ reactors: Sequence[str],
57
+ isotopes: Sequence[str],
58
+ periods: Sequence[int] = (6, 8, 7),
59
+ clean_source: bool = True,
60
+ ) -> None:
61
+ """Refine reactor reactor data.
62
+
63
+ Does the following items:
64
+ - checks input consistency
65
+ - split arrays based on isotope number and period name
66
+ - provides similar data on a daily basis
67
+ - splits into multiple arrays based on the reactor index
68
+
69
+ Source should contain the following fields:
70
+ - period : int
71
+ period number
72
+ - day : int
73
+ number of the first day of the period, relative to some common day.
74
+ - ndays : int
75
+ length of the period in days. This function can deal only with periods of
76
+ equal length and with no gaps.
77
+ - core : int
78
+ number of the current reactor (1 to 6).
79
+ - ndet : int
80
+ number of active detectors during the period (6, 8 or 7).
81
+ - power : dict[str, NDArray]
82
+ thermal power as a fraction to nominal value (0 to 1) for each reactor
83
+ core.
84
+ - u235 : dict[str, NDArray]
85
+ fission fraction for the ²³⁵U ("U235" should be contained in isotopes) for
86
+ each reactor core.
87
+ - <isotope> : dict[str, NDArray]
88
+ fission fraction for the <isotope> according to isotopes for each reactor
89
+ core.
90
+
91
+ The target dictionary will be populated as follows:
92
+ ```python
93
+ target = {
94
+ "days": array(),
95
+ "power": {
96
+ "period_name": {
97
+ "reactor_name": array(),
98
+ ...
99
+ },
100
+ ...
101
+ },
102
+ "fission_fraction": {
103
+ "isotope_name": {
104
+ "period_name": {
105
+ "reactor_name": array(),
106
+ ...
107
+ },
108
+ ...
109
+ },
110
+ }
111
+ }
112
+ ```
113
+ with all the arrays of same lengths.
114
+
115
+ Parameters
116
+ ----------
117
+ source : NestedMapping
118
+ storage/record/mapping with source data.
119
+ target : NestedMapping
120
+ storage to write target arrays to.
121
+ reactors : Sequence[str]
122
+ reactor names to use when writing data.
123
+ isotopes : Sequence[str]
124
+ names of the isotopes to read and write fission fractions.
125
+ periods : Sequence[int], default=(6, 8, 7)
126
+ periods (number of active detectors) to select.
127
+ clean_source : bool, default=True
128
+ if True, remove used data from source.
129
+ """
130
+ for corename in reactors:
131
+ period = source["period", corename]
132
+ day = source["day", corename]
133
+ ndays = source["ndays", corename]
134
+ ndet = source["ndet", corename]
135
+
136
+ ndays0 = ndays[0]
137
+ if not (ndays[:-1] == ndays0).all():
138
+ raise ValueError(
139
+ "refine_reactor_data expects information with constant periodicity"
140
+ )
141
+
142
+ power = source["power"][corename]
143
+ fission_fractions = {key: source[key.lower(), corename] for key in isotopes}
144
+
145
+ step = period[1:] - period[:-1]
146
+ assert (
147
+ step == 1
148
+ ).all(), "Expect reactor data for with distinct period, no gaps"
149
+
150
+ target["days"] = (days_storage := {})
151
+ for period in periods:
152
+ mask_period = ndet == period
153
+ periodname = f"{period}AD"
154
+
155
+ mask = mask_period
156
+ key = (
157
+ periodname,
158
+ corename,
159
+ )
160
+ target[("power",) + key] = inperiod_to_daily(power[mask], ndays0)
161
+ for isotope in isotopes:
162
+ target[("fission_fraction",) + key + (isotope,)] = inperiod_to_daily(
163
+ fission_fractions[isotope][mask], ndays0
164
+ )
165
+
166
+ days = periods_to_days(day[mask], ndays0)
167
+ days_stored = days_storage.setdefault(periodname, days)
168
+ if days is not days_stored:
169
+ assert all(days == days_stored)
170
+
171
+ for key, array in target.walkjoineditems():
172
+ if isnan(array).any():
173
+ raise ValueError(f"Invalid refined reactor data for {key}")
174
+
175
+ if clean_source:
176
+ for key in tuple(source.walkkeys()):
177
+ source.delete_with_parents(key)
178
+
179
+
180
+ def split_refine_reactor_data(
181
+ source: NestedMapping,
182
+ target: NestedMapping,
183
+ *,
184
+ reactors: Sequence[str],
185
+ isotopes: Sequence[str],
186
+ periods: Sequence[int] = (6, 8, 7),
187
+ reactor_number_start: int = 1,
188
+ clean_source: bool = True,
189
+ ) -> None:
190
+ """Filter/split and refine reactor reactor data.
191
+
192
+ Does the following items:
193
+ - checks input consistency
194
+ - split arrays based on reactor number, isotope number and period name
195
+ - provides similar data on a daily basis
196
+ - splits into multiple arrays based on the reactor index
197
+
198
+ Source should contain the following fields:
199
+ - week : int
200
+ week/period number
201
+ - day : int
202
+ number of the first day of the period, relative to some common day.
203
+ - ndays : int
204
+ length of the period in days. This function can deal only with periods of
205
+ equal length and with no gaps.
206
+ - core : int
207
+ number of the current reactor (1 to 6).
208
+ - ndet : int
209
+ number of active detectors during the period (6, 8 or 7).
210
+ - power : float
211
+ thermal power as a fraction to nominal value (0 to 1).
212
+ - u235 : float
213
+ fission fraction for the ²³⁵U ("U235" should be contained in isotopes).
214
+ - <isotope> : float
215
+ fission fraction for the <isotope> according to isotopes.
216
+
217
+ The target dictionary will be populated as follows:
218
+ ```python
219
+ target = {
220
+ "days": array(),
221
+ "power": {
222
+ "period_name": {
223
+ "reactor_name": array(),
224
+ ...
225
+ },
226
+ ...
227
+ },
228
+ "fission_fraction": {
229
+ "isotope_name": {
230
+ "period_name": {
231
+ "reactor_name": array(),
232
+ ...
233
+ },
234
+ ...
235
+ },
236
+ }
237
+ }
238
+ ```
239
+ with all the arrays of same lengths.
240
+
241
+ Parameters
242
+ ----------
243
+ source : NestedMapping
244
+ storage/record/mapping with source data.
245
+ target : NestedMapping
246
+ storage to write target arrays to.
247
+ reactors : Sequence[str]
248
+ reactor names to use when writing data.
249
+ isotopes : Sequence[str]
250
+ names of the isotopes to read and write fission fractions.
251
+ periods : Sequence[int], default=(6, 8, 7)
252
+ periods (number of active detectors) to select.
253
+ reactor_number_start : int, default=1
254
+ number of the first reactor in the input data.
255
+ clean_source : bool, default=True
256
+ if True, remove used data from source.
257
+ """
258
+ week = source["week"]
259
+ day = source["day"]
260
+ ndays = source["ndays"]
261
+ core = source["core"]
262
+ ndet = source["ndet"]
263
+
264
+ if not (ndays == 7).all():
265
+ raise ValueError("refine_reactor_data expects weekly information")
266
+
267
+ power = source["power"]
268
+ fission_fractions = {key: source[key.lower()] for key in isotopes}
269
+
270
+ ncores = 6
271
+ for i in range(ncores):
272
+ rweek = week[i::ncores]
273
+ step = rweek[1:] - rweek[:-1]
274
+ assert (step == 1).all(), "Expect reactor data for each week, no gaps"
275
+
276
+ target["days"] = (days_storage := {})
277
+ for period in periods:
278
+ mask_period = ndet == period
279
+ periodname = f"{period}AD"
280
+
281
+ for icore, corename in enumerate(reactors, reactor_number_start):
282
+ mask = mask_period * (core == icore)
283
+ key = (
284
+ periodname,
285
+ corename,
286
+ )
287
+ target[("power",) + key] = weekly_to_daily(power[mask])
288
+ for isotope in isotopes:
289
+ target[("fission_fraction",) + key + (isotope,)] = weekly_to_daily(
290
+ fission_fractions[isotope][mask]
291
+ )
292
+
293
+ days = weeks_to_days(day[mask])
294
+ days_stored = days_storage.setdefault(periodname, days)
295
+ if days is not days_stored:
296
+ assert all(days == days_stored)
297
+
298
+ for key, array in target.walkjoineditems():
299
+ if isnan(array).any():
300
+ raise ValueError(f"Invalid refined reactor data for {key}")
301
+
302
+ if clean_source:
303
+ for key in tuple(source.walkkeys()):
304
+ source.delete_with_parents(key)
@@ -0,0 +1,39 @@
1
+ from nested_mapping import NestedMapping
2
+
3
+
4
+ def sync_reactor_detector_data(
5
+ reactor_data: NestedMapping,
6
+ detector_data: NestedMapping,
7
+ ) -> None:
8
+ reactor_day = reactor_data("days")
9
+ detector_day = detector_data("days")
10
+
11
+ for period, detector_day_p in detector_day.items():
12
+ reactor_day_p = reactor_day[period]
13
+
14
+ offset1 = int(detector_day_p[0] - reactor_day_p[0])
15
+ offset2 = int(detector_day_p[-1] - reactor_day_p[-1])
16
+ if offset1 < 0 or offset2 > 0:
17
+ raise RuntimeError(
18
+ "Reactor data is expected to start not later and end later then detector data. "
19
+ f"{period} got start/end for reactor ({reactor_day_p[0]:.0f}, {reactor_day_p[-1]:.0f})"
20
+ f" and detector ({detector_day_p[0]:.0f}, {detector_day_p[-1]:.0f})"
21
+ )
22
+ if offset2 == 0:
23
+ offset2 = None
24
+
25
+ slc = slice(offset1, offset2)
26
+ reactor_day_p_new = reactor_day_p[slc]
27
+ assert (
28
+ reactor_day_p_new == detector_day_p
29
+ ).all(), f"Unable to synchronize reactor and detector data for {period}"
30
+
31
+ reactor_day[period] = reactor_day_p_new
32
+
33
+ for key, data in reactor_data.walkitems():
34
+ if key[0] == "days":
35
+ continue
36
+ if not period in key:
37
+ continue
38
+
39
+ reactor_data[key] = data[slc]
@@ -0,0 +1,64 @@
1
+ from typing import Mapping
2
+
3
+ from dag_modelling.tools.logger import logger
4
+
5
+ from .dayabay_v0 import model_dayabay_v0
6
+ from .dayabay_v0b import model_dayabay_v0b
7
+ from .dayabay_v0c import model_dayabay_v0c
8
+ from .dayabay_v0d import model_dayabay_v0d
9
+ from .dayabay_v0e import model_dayabay_v0e
10
+
11
+ from .dayabay_labels import LATEX_SYMBOLS
12
+
13
+
14
+ AD_TO_EH = {
15
+ "AD11": "EH1",
16
+ "AD12": "EH1",
17
+ "AD21": "EH2",
18
+ "AD22": "EH2",
19
+ "AD31": "EH3",
20
+ "AD32": "EH3",
21
+ "AD33": "EH3",
22
+ "AD34": "EH3",
23
+ }
24
+
25
+ _dayabay_models = {
26
+ "v0": model_dayabay_v0,
27
+ "v0b": model_dayabay_v0b,
28
+ "v0c": model_dayabay_v0c,
29
+ "v0d": model_dayabay_v0d,
30
+ "v0e": model_dayabay_v0e,
31
+ }
32
+ _dayabay_models["latest"] = _dayabay_models["v0e"]
33
+
34
+ _available_sources = ("tsv", "hdf5", "root", "npz")
35
+
36
+
37
+ def available_models() -> tuple[str, ...]:
38
+ return tuple(_dayabay_models.keys())
39
+
40
+ def available_sources() -> tuple[str, ...]:
41
+ return _available_sources
42
+
43
+ def load_model(version, model_options: Mapping | str = {}, **kwargs):
44
+ if isinstance(model_options, str):
45
+ from yaml import Loader, load
46
+
47
+ model_options = load(model_options, Loader)
48
+
49
+ if not isinstance(model_options, dict):
50
+ raise RuntimeError(
51
+ "model_options expects a python dictionary or yaml dictionary"
52
+ )
53
+
54
+ model_options = dict(model_options, **kwargs)
55
+
56
+ logger.info(f"Execute Daya Bay model {version}")
57
+ try:
58
+ cls = _dayabay_models[version]
59
+ except KeyError:
60
+ raise RuntimeError(
61
+ f"Invalid model version {version}. Available models: {', '.join(sorted(_dayabay_models.keys()))}"
62
+ )
63
+
64
+ return cls(**model_options)