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.
- dgm_dayabay_dev/__init__.py +0 -0
- dgm_dayabay_dev/bundles/__init__.py +0 -0
- dgm_dayabay_dev/bundles/cross_check_refine_lsnl_data.py +77 -0
- dgm_dayabay_dev/bundles/refine_detector_data.py +46 -0
- dgm_dayabay_dev/bundles/refine_lsnl_data.py +161 -0
- dgm_dayabay_dev/bundles/refine_reactor_data.py +304 -0
- dgm_dayabay_dev/bundles/sync_reactor_detector_data.py +39 -0
- dgm_dayabay_dev/models/__init__.py +64 -0
- dgm_dayabay_dev/models/dayabay_labels.py +102 -0
- dgm_dayabay_dev/models/dayabay_v0.py +1689 -0
- dgm_dayabay_dev/models/dayabay_v0_labels.yaml +635 -0
- dgm_dayabay_dev/models/dayabay_v0b.py +1841 -0
- dgm_dayabay_dev/models/dayabay_v0b_labels.yaml +644 -0
- dgm_dayabay_dev/models/dayabay_v0c.py +2130 -0
- dgm_dayabay_dev/models/dayabay_v0c_labels.yaml +644 -0
- dgm_dayabay_dev/models/dayabay_v0d.py +2781 -0
- dgm_dayabay_dev/models/dayabay_v0d_labels.yaml +773 -0
- dgm_dayabay_dev/models/dayabay_v0e.py +3748 -0
- dgm_dayabay_dev/models/dayabay_v0e_labels.yaml +1284 -0
- dgm_dayabay_dev/nodes/AxisDistortionMatrixLinearLegacy.py +191 -0
- dgm_dayabay_dev/nodes/Monotonize.py +172 -0
- dgm_dayabay_dev/nodes/__init__.py +0 -0
- dgm_dayabay_dev/scripts/__init__.py +662 -0
- dgm_dayabay_dev/scripts/check_global_normalization.py +198 -0
- dgm_dayabay_dev/scripts/cmp_models_v0.py +266 -0
- dgm_dayabay_dev/scripts/covmatrix_dayabay_v0.py +142 -0
- dgm_dayabay_dev/scripts/covmatrix_mc.py +391 -0
- dgm_dayabay_dev/scripts/covmatrix_plot.py +621 -0
- dgm_dayabay_dev/scripts/cross_fit_config.yaml +12 -0
- dgm_dayabay_dev/scripts/crosscheck_dayabay_nuisance_v0.py +627 -0
- dgm_dayabay_dev/scripts/crosscheck_dayabay_v0.py +596 -0
- dgm_dayabay_dev/scripts/fit_dayabay_contour.py +374 -0
- dgm_dayabay_dev/scripts/fit_dayabay_cross_model.py +260 -0
- dgm_dayabay_dev/scripts/fit_dayabay_model.py +225 -0
- dgm_dayabay_dev/scripts/fit_dayabay_v0.py +273 -0
- dgm_dayabay_dev/scripts/plot_dayabay_v0_data_detector_time_dependent.py +207 -0
- dgm_dayabay_dev/scripts/plot_dayabay_v0_data_reactor_time_dependent.py +196 -0
- dgm_dayabay_dev/scripts/plot_fit_2d.py +124 -0
- dgm_dayabay_dev/scripts/plot_fit_article.py +324 -0
- dgm_dayabay_dev/scripts/plot_fit_dayabay.py +345 -0
- dgm_dayabay_dev/scripts/run_dayabay_v0.py +419 -0
- dgm_dayabay_dev/scripts/run_profiling_v0.py +365 -0
- dgm_dayabay_dev/scripts/run_profiling_v0e.py +288 -0
- dgm_dayabay_dev/scripts/test_lsnl_curves.py +230 -0
- dgm_dayabay_dev-0.2.dist-info/METADATA +49 -0
- dgm_dayabay_dev-0.2.dist-info/RECORD +49 -0
- dgm_dayabay_dev-0.2.dist-info/WHEEL +5 -0
- dgm_dayabay_dev-0.2.dist-info/licenses/LICENSE +21 -0
- 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)
|