decision-methods 0.1.0__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.
- decision_methods-0.1.0/LICENSE +21 -0
- decision_methods-0.1.0/PKG-INFO +153 -0
- decision_methods-0.1.0/README.md +139 -0
- decision_methods-0.1.0/pyproject.toml +27 -0
- decision_methods-0.1.0/setup.cfg +4 -0
- decision_methods-0.1.0/src/decision_methods/__init__.py +10 -0
- decision_methods-0.1.0/src/decision_methods/threshold.py +342 -0
- decision_methods-0.1.0/src/decision_methods.egg-info/PKG-INFO +153 -0
- decision_methods-0.1.0/src/decision_methods.egg-info/SOURCES.txt +14 -0
- decision_methods-0.1.0/src/decision_methods.egg-info/dependency_links.txt +1 -0
- decision_methods-0.1.0/src/decision_methods.egg-info/requires.txt +3 -0
- decision_methods-0.1.0/src/decision_methods.egg-info/top_level.txt +1 -0
- decision_methods-0.1.0/tests/test_compute_lid.py +30 -0
- decision_methods-0.1.0/tests/test_inputs.py +30 -0
- decision_methods-0.1.0/tests/test_poisson_model.py +9 -0
- decision_methods-0.1.0/tests/test_regression.py +31 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Jose Francisco Benavente, Jose Antonio Suarez
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: decision_methods
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Library for decision threshold and boundary methods
|
|
5
|
+
Author-email: Jose Francisco Benavente Cuevas <jf.benavente@ciemat.es>, Jose Antonio Suarez Navarro <ja.suarez@ciemat.es>, Victor Manuel Exposito Suarez <VictorManuel.Exposito@ciemat.es>
|
|
6
|
+
License: MIT
|
|
7
|
+
Requires-Python: >=3.8
|
|
8
|
+
Description-Content-Type: text/markdown
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Requires-Dist: numpy>=1.20
|
|
11
|
+
Requires-Dist: matplotlib>=3.5
|
|
12
|
+
Requires-Dist: scipy
|
|
13
|
+
Dynamic: license-file
|
|
14
|
+
|
|
15
|
+
# 🚀 decision_methods
|
|
16
|
+
|
|
17
|
+
**A scientific Python library for computing decision thresholds and limits using numerical methods independent of the analytical expression.**
|
|
18
|
+
|
|
19
|
+
Includes advanced implementations such as:
|
|
20
|
+
- **UD** — Decision Threshold
|
|
21
|
+
- **LID** — Decision Limit
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## ✨ Key Features
|
|
26
|
+
|
|
27
|
+
- Numerical methods applicable to **any analytical model**
|
|
28
|
+
- Full **uncertainty propagation**
|
|
29
|
+
- Robust **root-finding algorithms**
|
|
30
|
+
- Scientific computation ready for real-world data
|
|
31
|
+
- Visualization tools for LID analysis
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## ⚙️ Core Function
|
|
36
|
+
|
|
37
|
+
### 🔹 `compute_F_ud_lid`
|
|
38
|
+
|
|
39
|
+
Computes:
|
|
40
|
+
|
|
41
|
+
- Model value
|
|
42
|
+
- Associated uncertainty
|
|
43
|
+
- Decision Threshold (**UD**)
|
|
44
|
+
- Decision Limit (**LID**)
|
|
45
|
+
|
|
46
|
+
#### **Parameters**
|
|
47
|
+
|
|
48
|
+
- `p` *(array-like)* — Model parameter vector
|
|
49
|
+
- `t_m` *(float)* — Measurement time
|
|
50
|
+
- `t_f` *(float)* — Background time
|
|
51
|
+
- `f` *(callable)* — Multivariable function
|
|
52
|
+
- `pderivative` *(callable)* — Partial derivative function
|
|
53
|
+
- `bisection` *(callable)* — Root-finding method
|
|
54
|
+
- `k` *(float, optional)* — Coverage factor *(default: 1.65)*
|
|
55
|
+
- `LID_a` *(float)* — Lower bound for LID search
|
|
56
|
+
- `LID_b` *(float)* — Upper bound for LID search
|
|
57
|
+
- `cpm_min`*(float)* — Lower bound of the count rate (counts per unit time, e.g., minutes or seconds; CPM) used in the LID search
|
|
58
|
+
- `cpm_max`*(float)* — Upper bound of the count rate (counts per unit time, e.g., minutes or seconds; CPM) used in the LID search
|
|
59
|
+
- `cpm_index`*(integer)* — Index of the parameter corresponding to the count rate (CPM) used in the LID search
|
|
60
|
+
- `sample_indices` *(tuple of int, optional)* — Indices of parameters corresponding to sample measurements modeled as Poisson-distributed variables, with expected counts defined as the parameter value scaled by the measurement time t_m *(default: (0,))*
|
|
61
|
+
- `background_indices` *(tuple of int, optional)* — Indices of parameters corresponding to sample measurements modeled as Poisson-distributed variables, with expected counts defined as the parameter value scaled by the measurement time t_f *(default: (1,))*
|
|
62
|
+
- `rel_map` *(tuple of (int, float), optional)* — Relative uncertainty definitions as *(index, relative_error)* pairs
|
|
63
|
+
- `frac_fondo` *(float, optional)* — Relative uncertainty for background when `t_f <= 0`
|
|
64
|
+
|
|
65
|
+
#### **Returns**
|
|
66
|
+
|
|
67
|
+
- `value` *(float)* — Evaluated value of the model function
|
|
68
|
+
- `u_value` *(float)* — Combined uncertainty
|
|
69
|
+
- `UD` *(float)* — Decision threshold
|
|
70
|
+
- `LID` *(float)* — Decision limit
|
|
71
|
+
#### **Returns**
|
|
72
|
+
|
|
73
|
+
- `value` *(float)* — Evaluated value of the model function
|
|
74
|
+
- `u_value` *(float)* — Combined uncertainty
|
|
75
|
+
- `UD` *(float)* — Decision threshold
|
|
76
|
+
- `LID` *(float)* — Decision limit
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## 📊 Visualization
|
|
81
|
+
|
|
82
|
+
### 🔹 `plot_lid_function`
|
|
83
|
+
|
|
84
|
+
Generates plots to analyze LID behavior.
|
|
85
|
+
|
|
86
|
+
#### **Parameters**
|
|
87
|
+
|
|
88
|
+
- `LID_a` *(float)* — Lower bound
|
|
89
|
+
- `LID_b` *(float)* — Upper bound
|
|
90
|
+
- `p` *(array-like)* — Parameters
|
|
91
|
+
- `f` *(callable)* — Function
|
|
92
|
+
- `UD` *(float)* — Decision threshold
|
|
93
|
+
- `t_m` *(float)* — Measurement time
|
|
94
|
+
- `t_f` *(float)* — Background time
|
|
95
|
+
- `pderivative` *(callable)* — Partial derivative function
|
|
96
|
+
- `bisection` *(callable)* — Root-finding method
|
|
97
|
+
- `cpm_min`*(float)* — Lower bound of the count rate (counts per unit time, e.g., minutes or seconds; CPM) used in the LID search
|
|
98
|
+
- `cpm_max`*(float)* — Upper bound of the count rate (counts per unit time, e.g., minutes or seconds; CPM) used in the LID search
|
|
99
|
+
- `n`*(integer)* — Number of samples or observations used in the LID search
|
|
100
|
+
- `cpm_index`*(integer)* — Index of the parameter corresponding to the count rate (CPM) used in the LID search
|
|
101
|
+
- `k` *(float, optional)* — Coverage factor *(default: 1.65)*
|
|
102
|
+
- `rel_map` *(tuple of (int, float), optional)* — Relative uncertainty definitions as *(index, relative_error)* pairs
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
## 🧪 Activity Functions
|
|
107
|
+
|
|
108
|
+
### 🔹 `AT` — Total Alpha
|
|
109
|
+
|
|
110
|
+
Computes total alpha activity.
|
|
111
|
+
|
|
112
|
+
$AT(Bq\cdot m^{3})= \frac{CPM_M-CPM_F}{60 \cdot ɛ \cdot V_{Alicuot}}$
|
|
113
|
+
|
|
114
|
+
#### **Parameters**
|
|
115
|
+
|
|
116
|
+
- `CPM_m` *(float)* — Sample counts
|
|
117
|
+
- `CPM_f` *(float)* — Background counts
|
|
118
|
+
- `Eps` *(float)* — Detection efficiency
|
|
119
|
+
- `V_ali` *(float)* — Aliquot volume
|
|
120
|
+
|
|
121
|
+
#### **Returns**
|
|
122
|
+
|
|
123
|
+
- *(float)* — Activity
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
### 🔹 `BT` — Total Beta
|
|
128
|
+
|
|
129
|
+
Computes total beta activity.
|
|
130
|
+
|
|
131
|
+
$BT(Bq\cdot m^{3})= \frac{CPM_{\beta-M}-CPM_{\beta-F} - γ \cdot(CPM_{α-M}-CPM_{α-F})}{60 \cdot Ef_{Sr} \cdot V_{Alicuot}⋅Fa}$
|
|
132
|
+
|
|
133
|
+
#### **Parameters**
|
|
134
|
+
|
|
135
|
+
- `CPM_b_m` *(float)* — Measured beta counts
|
|
136
|
+
- `CPM_b_f` *(float)* — Background beta counts
|
|
137
|
+
- `CPM_a_m` *(float)* — Measured alpha counts
|
|
138
|
+
- `CPM_a_f` *(float)* — Background alpha counts
|
|
139
|
+
- `Spill` *(float)* — Spillover correction factor
|
|
140
|
+
- `EFSr` *(float)* — Detection efficiency factor
|
|
141
|
+
- `Fa` *(float)* — Correction factor
|
|
142
|
+
- `V_ali` *(float)* — Aliquot volume
|
|
143
|
+
|
|
144
|
+
#### **Returns**
|
|
145
|
+
|
|
146
|
+
- *(float)* — Total beta activity
|
|
147
|
+
|
|
148
|
+
---
|
|
149
|
+
|
|
150
|
+
## 📦 Installation
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
pip install decision_methods
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
# 🚀 decision_methods
|
|
2
|
+
|
|
3
|
+
**A scientific Python library for computing decision thresholds and limits using numerical methods independent of the analytical expression.**
|
|
4
|
+
|
|
5
|
+
Includes advanced implementations such as:
|
|
6
|
+
- **UD** — Decision Threshold
|
|
7
|
+
- **LID** — Decision Limit
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## ✨ Key Features
|
|
12
|
+
|
|
13
|
+
- Numerical methods applicable to **any analytical model**
|
|
14
|
+
- Full **uncertainty propagation**
|
|
15
|
+
- Robust **root-finding algorithms**
|
|
16
|
+
- Scientific computation ready for real-world data
|
|
17
|
+
- Visualization tools for LID analysis
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## ⚙️ Core Function
|
|
22
|
+
|
|
23
|
+
### 🔹 `compute_F_ud_lid`
|
|
24
|
+
|
|
25
|
+
Computes:
|
|
26
|
+
|
|
27
|
+
- Model value
|
|
28
|
+
- Associated uncertainty
|
|
29
|
+
- Decision Threshold (**UD**)
|
|
30
|
+
- Decision Limit (**LID**)
|
|
31
|
+
|
|
32
|
+
#### **Parameters**
|
|
33
|
+
|
|
34
|
+
- `p` *(array-like)* — Model parameter vector
|
|
35
|
+
- `t_m` *(float)* — Measurement time
|
|
36
|
+
- `t_f` *(float)* — Background time
|
|
37
|
+
- `f` *(callable)* — Multivariable function
|
|
38
|
+
- `pderivative` *(callable)* — Partial derivative function
|
|
39
|
+
- `bisection` *(callable)* — Root-finding method
|
|
40
|
+
- `k` *(float, optional)* — Coverage factor *(default: 1.65)*
|
|
41
|
+
- `LID_a` *(float)* — Lower bound for LID search
|
|
42
|
+
- `LID_b` *(float)* — Upper bound for LID search
|
|
43
|
+
- `cpm_min`*(float)* — Lower bound of the count rate (counts per unit time, e.g., minutes or seconds; CPM) used in the LID search
|
|
44
|
+
- `cpm_max`*(float)* — Upper bound of the count rate (counts per unit time, e.g., minutes or seconds; CPM) used in the LID search
|
|
45
|
+
- `cpm_index`*(integer)* — Index of the parameter corresponding to the count rate (CPM) used in the LID search
|
|
46
|
+
- `sample_indices` *(tuple of int, optional)* — Indices of parameters corresponding to sample measurements modeled as Poisson-distributed variables, with expected counts defined as the parameter value scaled by the measurement time t_m *(default: (0,))*
|
|
47
|
+
- `background_indices` *(tuple of int, optional)* — Indices of parameters corresponding to sample measurements modeled as Poisson-distributed variables, with expected counts defined as the parameter value scaled by the measurement time t_f *(default: (1,))*
|
|
48
|
+
- `rel_map` *(tuple of (int, float), optional)* — Relative uncertainty definitions as *(index, relative_error)* pairs
|
|
49
|
+
- `frac_fondo` *(float, optional)* — Relative uncertainty for background when `t_f <= 0`
|
|
50
|
+
|
|
51
|
+
#### **Returns**
|
|
52
|
+
|
|
53
|
+
- `value` *(float)* — Evaluated value of the model function
|
|
54
|
+
- `u_value` *(float)* — Combined uncertainty
|
|
55
|
+
- `UD` *(float)* — Decision threshold
|
|
56
|
+
- `LID` *(float)* — Decision limit
|
|
57
|
+
#### **Returns**
|
|
58
|
+
|
|
59
|
+
- `value` *(float)* — Evaluated value of the model function
|
|
60
|
+
- `u_value` *(float)* — Combined uncertainty
|
|
61
|
+
- `UD` *(float)* — Decision threshold
|
|
62
|
+
- `LID` *(float)* — Decision limit
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## 📊 Visualization
|
|
67
|
+
|
|
68
|
+
### 🔹 `plot_lid_function`
|
|
69
|
+
|
|
70
|
+
Generates plots to analyze LID behavior.
|
|
71
|
+
|
|
72
|
+
#### **Parameters**
|
|
73
|
+
|
|
74
|
+
- `LID_a` *(float)* — Lower bound
|
|
75
|
+
- `LID_b` *(float)* — Upper bound
|
|
76
|
+
- `p` *(array-like)* — Parameters
|
|
77
|
+
- `f` *(callable)* — Function
|
|
78
|
+
- `UD` *(float)* — Decision threshold
|
|
79
|
+
- `t_m` *(float)* — Measurement time
|
|
80
|
+
- `t_f` *(float)* — Background time
|
|
81
|
+
- `pderivative` *(callable)* — Partial derivative function
|
|
82
|
+
- `bisection` *(callable)* — Root-finding method
|
|
83
|
+
- `cpm_min`*(float)* — Lower bound of the count rate (counts per unit time, e.g., minutes or seconds; CPM) used in the LID search
|
|
84
|
+
- `cpm_max`*(float)* — Upper bound of the count rate (counts per unit time, e.g., minutes or seconds; CPM) used in the LID search
|
|
85
|
+
- `n`*(integer)* — Number of samples or observations used in the LID search
|
|
86
|
+
- `cpm_index`*(integer)* — Index of the parameter corresponding to the count rate (CPM) used in the LID search
|
|
87
|
+
- `k` *(float, optional)* — Coverage factor *(default: 1.65)*
|
|
88
|
+
- `rel_map` *(tuple of (int, float), optional)* — Relative uncertainty definitions as *(index, relative_error)* pairs
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
## 🧪 Activity Functions
|
|
93
|
+
|
|
94
|
+
### 🔹 `AT` — Total Alpha
|
|
95
|
+
|
|
96
|
+
Computes total alpha activity.
|
|
97
|
+
|
|
98
|
+
$AT(Bq\cdot m^{3})= \frac{CPM_M-CPM_F}{60 \cdot ɛ \cdot V_{Alicuot}}$
|
|
99
|
+
|
|
100
|
+
#### **Parameters**
|
|
101
|
+
|
|
102
|
+
- `CPM_m` *(float)* — Sample counts
|
|
103
|
+
- `CPM_f` *(float)* — Background counts
|
|
104
|
+
- `Eps` *(float)* — Detection efficiency
|
|
105
|
+
- `V_ali` *(float)* — Aliquot volume
|
|
106
|
+
|
|
107
|
+
#### **Returns**
|
|
108
|
+
|
|
109
|
+
- *(float)* — Activity
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
### 🔹 `BT` — Total Beta
|
|
114
|
+
|
|
115
|
+
Computes total beta activity.
|
|
116
|
+
|
|
117
|
+
$BT(Bq\cdot m^{3})= \frac{CPM_{\beta-M}-CPM_{\beta-F} - γ \cdot(CPM_{α-M}-CPM_{α-F})}{60 \cdot Ef_{Sr} \cdot V_{Alicuot}⋅Fa}$
|
|
118
|
+
|
|
119
|
+
#### **Parameters**
|
|
120
|
+
|
|
121
|
+
- `CPM_b_m` *(float)* — Measured beta counts
|
|
122
|
+
- `CPM_b_f` *(float)* — Background beta counts
|
|
123
|
+
- `CPM_a_m` *(float)* — Measured alpha counts
|
|
124
|
+
- `CPM_a_f` *(float)* — Background alpha counts
|
|
125
|
+
- `Spill` *(float)* — Spillover correction factor
|
|
126
|
+
- `EFSr` *(float)* — Detection efficiency factor
|
|
127
|
+
- `Fa` *(float)* — Correction factor
|
|
128
|
+
- `V_ali` *(float)* — Aliquot volume
|
|
129
|
+
|
|
130
|
+
#### **Returns**
|
|
131
|
+
|
|
132
|
+
- *(float)* — Total beta activity
|
|
133
|
+
|
|
134
|
+
---
|
|
135
|
+
|
|
136
|
+
## 📦 Installation
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
pip install decision_methods
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "decision_methods"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Library for decision threshold and boundary methods"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.8"
|
|
11
|
+
|
|
12
|
+
authors = [
|
|
13
|
+
{ name = "Jose Francisco Benavente Cuevas", email = "jf.benavente@ciemat.es" },
|
|
14
|
+
{ name = "Jose Antonio Suarez Navarro", email = "ja.suarez@ciemat.es" },
|
|
15
|
+
{ name = "Victor Manuel Exposito Suarez", email = "VictorManuel.Exposito@ciemat.es" }
|
|
16
|
+
]
|
|
17
|
+
|
|
18
|
+
license = { text = "MIT" }
|
|
19
|
+
|
|
20
|
+
dependencies = [
|
|
21
|
+
"numpy>=1.20",
|
|
22
|
+
"matplotlib>=3.5",
|
|
23
|
+
"scipy"
|
|
24
|
+
]
|
|
25
|
+
|
|
26
|
+
[tool.setuptools.packages.find]
|
|
27
|
+
where = ["src"]
|
|
@@ -0,0 +1,342 @@
|
|
|
1
|
+
|
|
2
|
+
import numpy as np
|
|
3
|
+
import matplotlib.pyplot as plt
|
|
4
|
+
|
|
5
|
+
def pderivative(f, punto, indice, h=1e-12):
|
|
6
|
+
"""
|
|
7
|
+
Calcula la derivada parcial de f en 'punto'
|
|
8
|
+
respecto a la variable indicada por 'indice'
|
|
9
|
+
usando diferencia finita centrada.
|
|
10
|
+
|
|
11
|
+
Parámetros:
|
|
12
|
+
f : función multivariable
|
|
13
|
+
punto : lista o array con el punto donde evaluar
|
|
14
|
+
indice : índice de la variable respecto a la cual derivar
|
|
15
|
+
h : paso de la diferencia finita
|
|
16
|
+
|
|
17
|
+
Devuelve:
|
|
18
|
+
Aproximación de la derivada parcial
|
|
19
|
+
"""
|
|
20
|
+
punto = np.array(punto, dtype=float)
|
|
21
|
+
|
|
22
|
+
eps = np.finfo(float).eps
|
|
23
|
+
escala = max(abs(punto[indice]), 1.0)
|
|
24
|
+
h = np.sqrt(eps) * escala
|
|
25
|
+
|
|
26
|
+
punto_mas = punto.copy()
|
|
27
|
+
punto_menos = punto.copy()
|
|
28
|
+
|
|
29
|
+
punto_mas[indice] += h
|
|
30
|
+
punto_menos[indice] -= h
|
|
31
|
+
|
|
32
|
+
return (f(*punto_mas) - f(*punto_menos)) / (2 * h)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def bisection(f, a, b, tol=1e-12, max_iter=100):
|
|
36
|
+
"""
|
|
37
|
+
Encuentra una raíz de f en el intervalo [a, b] usando el método de la bisección.
|
|
38
|
+
|
|
39
|
+
Parámetros:
|
|
40
|
+
f : función a evaluar
|
|
41
|
+
a, b : extremos del intervalo (f(a)*f(b) < 0)
|
|
42
|
+
tol : tolerancia para el criterio de parada
|
|
43
|
+
max_iter : máximo número de iteraciones
|
|
44
|
+
|
|
45
|
+
Retorna:
|
|
46
|
+
Aproximación de la raíz
|
|
47
|
+
"""
|
|
48
|
+
|
|
49
|
+
if f(a) * f(b) > 0:
|
|
50
|
+
raise ValueError(f"No hay cambio de signo: a={a}, f(a)={fa}, b={b}, f(b)={fb}")
|
|
51
|
+
#raise ValueError("La función debe cambiar de signo en el intervalo [a, b].")
|
|
52
|
+
|
|
53
|
+
for i in range(max_iter):
|
|
54
|
+
c = (a + b) / 2
|
|
55
|
+
fc = f(c)
|
|
56
|
+
|
|
57
|
+
if abs(fc) < tol or (b - a) / 2 < tol:
|
|
58
|
+
return c
|
|
59
|
+
|
|
60
|
+
if f(a) * fc < 0:
|
|
61
|
+
b = c
|
|
62
|
+
else:
|
|
63
|
+
a = c
|
|
64
|
+
|
|
65
|
+
raise RuntimeError("No se alcanzó la convergencia en el número máximo de iteraciones.")
|
|
66
|
+
|
|
67
|
+
def Funcion_Previa_LID(LID, CPM_m, f, p,cpm_index=1):
|
|
68
|
+
return f(CPM_m, *p[cpm_index:]) - LID
|
|
69
|
+
|
|
70
|
+
def eval_f(f, p):
|
|
71
|
+
return f(*p)
|
|
72
|
+
|
|
73
|
+
def Funcion_LID(LID, CPM_m,UD,f, p_base, t_m=None, t_f=None, poisson_map=((0, "t_m"), (1, "t_f")), rel_map=((2, 0.075), (3, 0.01)),k=1.65, pderivative=None, indices_deriv=None,set_CPM_index=0):
|
|
74
|
+
"""
|
|
75
|
+
Devuelve: LID - (UD + k * u_comb) donde u_comb = sqrt(sum((w_i*u_i)^2))
|
|
76
|
+
"""
|
|
77
|
+
if pderivative is None:
|
|
78
|
+
raise ValueError("Debes pasar la función pderivative(f, p, indice=...).")
|
|
79
|
+
|
|
80
|
+
# Copia de parámetros y fijar CPM_m
|
|
81
|
+
p_eval = np.array(p_base, dtype=float).copy()
|
|
82
|
+
p_eval[set_CPM_index] = CPM_m
|
|
83
|
+
|
|
84
|
+
# Resolver tiempos por nombre
|
|
85
|
+
tiempos = {"t_m": t_m, "t_f": t_f}
|
|
86
|
+
for _, tname in poisson_map:
|
|
87
|
+
if tiempos.get(tname, None) is None:
|
|
88
|
+
raise ValueError(f"Falta el tiempo {tname} (pasa {tname}=...).")
|
|
89
|
+
|
|
90
|
+
# Elegir índices a derivar si no se especifica
|
|
91
|
+
if indices_deriv is None:
|
|
92
|
+
idxs = [i for i, _ in poisson_map] + [i for i, _ in rel_map]
|
|
93
|
+
# quitar duplicados preservando orden
|
|
94
|
+
seen = set()
|
|
95
|
+
indices_deriv = [i for i in idxs if not (i in seen or seen.add(i))]
|
|
96
|
+
|
|
97
|
+
# Construir u_i (incertidumbres estándar) y w_i (sensibilidades)
|
|
98
|
+
u_list = []
|
|
99
|
+
w_list = []
|
|
100
|
+
|
|
101
|
+
# Poisson: sqrt(N*t)/t = sqrt(N*t)/t (tu forma actual)
|
|
102
|
+
for i, tname in poisson_map:
|
|
103
|
+
t = tiempos[tname]
|
|
104
|
+
u_list.append(np.sqrt(p_eval[i] * t) / t)
|
|
105
|
+
w_list.append(pderivative(f, p_eval, indice=i))
|
|
106
|
+
|
|
107
|
+
# Relativas: u = p * frac
|
|
108
|
+
for i, frac in rel_map:
|
|
109
|
+
u_list.append(p_eval[i] * frac)
|
|
110
|
+
w_list.append(pderivative(f, p_eval, indice=i))
|
|
111
|
+
|
|
112
|
+
u = np.array(u_list, dtype=float)
|
|
113
|
+
w = np.array(w_list, dtype=float)
|
|
114
|
+
|
|
115
|
+
u_comb = np.sqrt(np.sum((w**2) * (u**2)))
|
|
116
|
+
return LID - (UD + k * u_comb)
|
|
117
|
+
|
|
118
|
+
def compute_F_ud_lid(
|
|
119
|
+
p, t_m, t_f, f, pderivative, bisection,
|
|
120
|
+
k=1.65,
|
|
121
|
+
LID_a=0.0, LID_b=100.0,
|
|
122
|
+
tol=1e-12, max_iter=100,
|
|
123
|
+
cpm_min_=0.0, cpm_max_=1.0,
|
|
124
|
+
cpm_min=0.0, cpm_max=1.0,
|
|
125
|
+
cpm_index=0,
|
|
126
|
+
sample_indices=(0,), # <- ahora varios
|
|
127
|
+
background_indices=(1,), # <- ahora varios
|
|
128
|
+
rel_map=((2, 0.075), (3, 0.01)),
|
|
129
|
+
frac_fondo=None, # <- NUEVO: error relativo fondo si t_f<=0
|
|
130
|
+
):
|
|
131
|
+
p = np.array(p, dtype=float)
|
|
132
|
+
|
|
133
|
+
# 1) Actividad
|
|
134
|
+
actividad = eval_f(f, p)
|
|
135
|
+
|
|
136
|
+
# 2) Incertidumbre en p
|
|
137
|
+
idx_list = []
|
|
138
|
+
u_list = []
|
|
139
|
+
|
|
140
|
+
for i in sample_indices:
|
|
141
|
+
idx_list.append(i)
|
|
142
|
+
u_list.append(np.sqrt(p[i] * t_m) / t_m)
|
|
143
|
+
|
|
144
|
+
# Fondo: Poisson si t_f>0, si no -> error relativo fijo frac_fondo
|
|
145
|
+
if t_f is not None and t_f > 0:
|
|
146
|
+
for j in background_indices:
|
|
147
|
+
idx_list.append(j)
|
|
148
|
+
u_list.append(np.sqrt(p[j] * t_f) / t_f)
|
|
149
|
+
else:
|
|
150
|
+
if frac_fondo is None:
|
|
151
|
+
raise ValueError("Si t_f <= 0 debes proporcionar frac_fondo (error relativo del fondo).")
|
|
152
|
+
for j in background_indices:
|
|
153
|
+
idx_list.append(j)
|
|
154
|
+
u_list.append(p[j] * frac_fondo)
|
|
155
|
+
|
|
156
|
+
for i, frac in rel_map:
|
|
157
|
+
idx_list.append(i)
|
|
158
|
+
u_list.append(p[i] * frac)
|
|
159
|
+
|
|
160
|
+
u = np.array(u_list, dtype=float)
|
|
161
|
+
w = np.array([pderivative(f, p, indice=i) for i in idx_list], dtype=float)
|
|
162
|
+
|
|
163
|
+
u_act = np.sqrt(np.sum((w**2) * (u**2)))
|
|
164
|
+
|
|
165
|
+
# 3) UD: raíz de f=0 variando p[0]
|
|
166
|
+
raiz = bisection(
|
|
167
|
+
lambda x: eval_f(f, np.array([x if j == 0 else p[j] for j in range(len(p))], dtype=float)),
|
|
168
|
+
cpm_min_, cpm_max_,tol=1e-12, max_iter=400
|
|
169
|
+
)
|
|
170
|
+
|
|
171
|
+
p_UD = p.copy()
|
|
172
|
+
p_UD[0] = raiz
|
|
173
|
+
|
|
174
|
+
# Recalcular incertidumbre en p_UD (mismo criterio)
|
|
175
|
+
u_list_UD = []
|
|
176
|
+
for i in sample_indices:
|
|
177
|
+
u_list_UD.append(np.sqrt(p_UD[i] * t_m) / t_m)
|
|
178
|
+
|
|
179
|
+
if t_f is not None and t_f > 0:
|
|
180
|
+
for j in background_indices:
|
|
181
|
+
u_list_UD.append(np.sqrt(p_UD[j] * t_f) / t_f)
|
|
182
|
+
else:
|
|
183
|
+
if frac_fondo is None:
|
|
184
|
+
raise ValueError("Si t_f <= 0 debes proporcionar frac_fondo (error relativo del fondo).")
|
|
185
|
+
for j in background_indices:
|
|
186
|
+
u_list_UD.append(p_UD[j] * frac_fondo)
|
|
187
|
+
|
|
188
|
+
for i, frac in rel_map:
|
|
189
|
+
u_list_UD.append(p_UD[i] * frac)
|
|
190
|
+
|
|
191
|
+
u_UD = np.array(u_list_UD, dtype=float)
|
|
192
|
+
w_UD = np.array([pderivative(f, p_UD, indice=i) for i in idx_list], dtype=float)
|
|
193
|
+
u_act_UD = np.sqrt(np.sum((w_UD**2) * (u_UD**2)))
|
|
194
|
+
|
|
195
|
+
UD = u_act_UD * k
|
|
196
|
+
|
|
197
|
+
# 4) LID por bisección
|
|
198
|
+
a, b = float(LID_a), float(LID_b)
|
|
199
|
+
|
|
200
|
+
CPM_a = bisection(lambda x: Funcion_Previa_LID(a, x, f, p, cpm_index=cpm_index), cpm_min, cpm_max)
|
|
201
|
+
CPM_b = bisection(lambda x: Funcion_Previa_LID(b, x, f, p, cpm_index=cpm_index), cpm_min, cpm_max)
|
|
202
|
+
poisson_map = tuple((i, "t_m") for i in sample_indices) + tuple((j, "t_f") for j in background_indices)
|
|
203
|
+
|
|
204
|
+
fa = Funcion_LID(a, CPM_a, UD, f, p, t_m, t_f, pderivative=pderivative,
|
|
205
|
+
k=k, poisson_map=poisson_map,rel_map=rel_map)
|
|
206
|
+
fb = Funcion_LID(b, CPM_b, UD, f, p, t_m, t_f, pderivative=pderivative,
|
|
207
|
+
k=k, poisson_map=poisson_map,rel_map=rel_map)
|
|
208
|
+
|
|
209
|
+
LID = None
|
|
210
|
+
for _ in range(max_iter):
|
|
211
|
+
c = (a + b) / 2.0
|
|
212
|
+
CPM_c = bisection(lambda x: Funcion_Previa_LID(c, x, f, p, cpm_index=cpm_index), cpm_min, cpm_max)
|
|
213
|
+
|
|
214
|
+
fc = Funcion_LID(c, CPM_c, UD, f, p, t_m, t_f, poisson_map= poisson_map,pderivative=pderivative,
|
|
215
|
+
k=k, rel_map=rel_map)
|
|
216
|
+
|
|
217
|
+
if abs(fc) < tol or (b - a) / 2.0 < tol:
|
|
218
|
+
LID = c
|
|
219
|
+
break
|
|
220
|
+
|
|
221
|
+
if fa * fc < 0:
|
|
222
|
+
b = c
|
|
223
|
+
fb = fc
|
|
224
|
+
else:
|
|
225
|
+
a = c
|
|
226
|
+
fa = fc
|
|
227
|
+
|
|
228
|
+
if LID is None:
|
|
229
|
+
LID = (a + b) / 2.0
|
|
230
|
+
|
|
231
|
+
return actividad, u_act, UD, LID
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
def plot_lid_function(
|
|
235
|
+
LID_a,
|
|
236
|
+
LID_b,
|
|
237
|
+
p,
|
|
238
|
+
f,
|
|
239
|
+
UD,
|
|
240
|
+
t_m,
|
|
241
|
+
t_f,
|
|
242
|
+
pderivative,
|
|
243
|
+
bisection,
|
|
244
|
+
cpm_min,
|
|
245
|
+
cpm_max,
|
|
246
|
+
n=200,
|
|
247
|
+
cpm_index=0,
|
|
248
|
+
k=1.65,
|
|
249
|
+
rel_map=((2, 0.075), (3, 0.01)),
|
|
250
|
+
LID_objetivo=None, # valor de LID para la segunda gráfica
|
|
251
|
+
n_cpm=200 # número de puntos para la gráfica de Funcion_Previa_LID
|
|
252
|
+
):
|
|
253
|
+
LIDs = np.linspace(LID_a, LID_b, n)
|
|
254
|
+
valores = []
|
|
255
|
+
|
|
256
|
+
for LID in LIDs:
|
|
257
|
+
CPM = bisection(
|
|
258
|
+
lambda x: Funcion_Previa_LID(LID, x, f, p, cpm_index=cpm_index),
|
|
259
|
+
cpm_min,
|
|
260
|
+
cpm_max
|
|
261
|
+
)
|
|
262
|
+
|
|
263
|
+
val = Funcion_LID(
|
|
264
|
+
LID, CPM, UD, f, p, t_m, t_f,
|
|
265
|
+
pderivative=pderivative,
|
|
266
|
+
k=k,
|
|
267
|
+
rel_map=rel_map
|
|
268
|
+
)
|
|
269
|
+
|
|
270
|
+
valores.append(val)
|
|
271
|
+
|
|
272
|
+
valores = np.array(valores)
|
|
273
|
+
|
|
274
|
+
# ---------------------------
|
|
275
|
+
# Gráfica 1: Funcion_LID vs LID
|
|
276
|
+
# ---------------------------
|
|
277
|
+
plt.figure(figsize=(7, 5))
|
|
278
|
+
plt.plot(LIDs, valores, label="Funcion_LID(LID)")
|
|
279
|
+
plt.axhline(0, linestyle="--")
|
|
280
|
+
plt.xlabel("LID")
|
|
281
|
+
plt.ylabel("Funcion_LID")
|
|
282
|
+
plt.title("Curva para encontrar LID")
|
|
283
|
+
plt.grid(True)
|
|
284
|
+
plt.legend()
|
|
285
|
+
plt.show()
|
|
286
|
+
|
|
287
|
+
# -----------------------------------------------
|
|
288
|
+
# Selección del LID para graficar Funcion_Previa_LID
|
|
289
|
+
# -----------------------------------------------
|
|
290
|
+
if LID_objetivo is None:
|
|
291
|
+
# Si no se indica, toma el punto central del intervalo
|
|
292
|
+
LID_objetivo = LIDs[len(LIDs) // 2]
|
|
293
|
+
|
|
294
|
+
# Si el valor no coincide exactamente con la malla, tomamos el más cercano
|
|
295
|
+
idx = np.argmin(np.abs(LIDs - LID_objetivo))
|
|
296
|
+
LID_seleccionado = LIDs[idx]
|
|
297
|
+
|
|
298
|
+
CPMs = np.linspace(cpm_min, cpm_max, n_cpm)
|
|
299
|
+
valores_previos = [
|
|
300
|
+
Funcion_Previa_LID(LID_seleccionado, cpm, f, p, cpm_index=cpm_index)
|
|
301
|
+
for cpm in CPMs
|
|
302
|
+
]
|
|
303
|
+
|
|
304
|
+
# Intentamos calcular también la raíz por bisección para marcarla
|
|
305
|
+
try:
|
|
306
|
+
CPM_raiz = bisection(
|
|
307
|
+
lambda x: Funcion_Previa_LID(LID_seleccionado, x, f, p, cpm_index=cpm_index),
|
|
308
|
+
cpm_min,
|
|
309
|
+
cpm_max
|
|
310
|
+
)
|
|
311
|
+
valor_raiz = Funcion_Previa_LID(LID_seleccionado, CPM_raiz, f, p, cpm_index=cpm_index)
|
|
312
|
+
except Exception:
|
|
313
|
+
CPM_raiz = None
|
|
314
|
+
valor_raiz = None
|
|
315
|
+
|
|
316
|
+
# ---------------------------
|
|
317
|
+
# Gráfica 2: Funcion_Previa_LID vs CPM
|
|
318
|
+
# ---------------------------
|
|
319
|
+
plt.figure(figsize=(7, 5))
|
|
320
|
+
plt.plot(CPMs, valores_previos, label=f"Funcion_Previa_LID para LID={LID_seleccionado:.6g}")
|
|
321
|
+
plt.axhline(0, linestyle="--")
|
|
322
|
+
if CPM_raiz is not None:
|
|
323
|
+
plt.axvline(CPM_raiz, linestyle=":", label=f"Raíz CPM={CPM_raiz:.6g}")
|
|
324
|
+
plt.plot(CPM_raiz, valor_raiz, "o")
|
|
325
|
+
plt.xlabel("CPM")
|
|
326
|
+
plt.ylabel("Funcion_Previa_LID")
|
|
327
|
+
plt.title(f"Evolución de Funcion_Previa_LID para LID={LID_seleccionado:.6g}")
|
|
328
|
+
plt.grid(True)
|
|
329
|
+
plt.legend()
|
|
330
|
+
plt.show()
|
|
331
|
+
|
|
332
|
+
def AT(CPM_m,CPM_f,Eps,V_ali):
|
|
333
|
+
return (CPM_m-CPM_f)/(60*Eps*V_ali)
|
|
334
|
+
|
|
335
|
+
def BT(CPM_b_m,CPM_b_f,CPM_a_m,CPM_a_f,Spill,EFSr,Fa,V_ali):
|
|
336
|
+
return (CPM_b_m-CPM_b_f-Spill*(CPM_a_m-CPM_a_f))/(60*EFSr*V_ali*Fa)
|
|
337
|
+
|
|
338
|
+
def BR(CPM_b_m,CPM_b_f,CPM_a_m,CPM_a_f,Spill,EFSr,Fa,W_k,V_ali):
|
|
339
|
+
return (CPM_b_m-CPM_b_f-Spill*(CPM_a_m-CPM_a_f)-W_k)/(60*EFSr*V_ali*Fa)
|
|
340
|
+
|
|
341
|
+
def W_k(V_ali,A_e,Eps_k,C_k):
|
|
342
|
+
return 60*V_ali*A_e*Eps_k*C_k*1000
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: decision_methods
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Library for decision threshold and boundary methods
|
|
5
|
+
Author-email: Jose Francisco Benavente Cuevas <jf.benavente@ciemat.es>, Jose Antonio Suarez Navarro <ja.suarez@ciemat.es>, Victor Manuel Exposito Suarez <VictorManuel.Exposito@ciemat.es>
|
|
6
|
+
License: MIT
|
|
7
|
+
Requires-Python: >=3.8
|
|
8
|
+
Description-Content-Type: text/markdown
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Requires-Dist: numpy>=1.20
|
|
11
|
+
Requires-Dist: matplotlib>=3.5
|
|
12
|
+
Requires-Dist: scipy
|
|
13
|
+
Dynamic: license-file
|
|
14
|
+
|
|
15
|
+
# 🚀 decision_methods
|
|
16
|
+
|
|
17
|
+
**A scientific Python library for computing decision thresholds and limits using numerical methods independent of the analytical expression.**
|
|
18
|
+
|
|
19
|
+
Includes advanced implementations such as:
|
|
20
|
+
- **UD** — Decision Threshold
|
|
21
|
+
- **LID** — Decision Limit
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## ✨ Key Features
|
|
26
|
+
|
|
27
|
+
- Numerical methods applicable to **any analytical model**
|
|
28
|
+
- Full **uncertainty propagation**
|
|
29
|
+
- Robust **root-finding algorithms**
|
|
30
|
+
- Scientific computation ready for real-world data
|
|
31
|
+
- Visualization tools for LID analysis
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## ⚙️ Core Function
|
|
36
|
+
|
|
37
|
+
### 🔹 `compute_F_ud_lid`
|
|
38
|
+
|
|
39
|
+
Computes:
|
|
40
|
+
|
|
41
|
+
- Model value
|
|
42
|
+
- Associated uncertainty
|
|
43
|
+
- Decision Threshold (**UD**)
|
|
44
|
+
- Decision Limit (**LID**)
|
|
45
|
+
|
|
46
|
+
#### **Parameters**
|
|
47
|
+
|
|
48
|
+
- `p` *(array-like)* — Model parameter vector
|
|
49
|
+
- `t_m` *(float)* — Measurement time
|
|
50
|
+
- `t_f` *(float)* — Background time
|
|
51
|
+
- `f` *(callable)* — Multivariable function
|
|
52
|
+
- `pderivative` *(callable)* — Partial derivative function
|
|
53
|
+
- `bisection` *(callable)* — Root-finding method
|
|
54
|
+
- `k` *(float, optional)* — Coverage factor *(default: 1.65)*
|
|
55
|
+
- `LID_a` *(float)* — Lower bound for LID search
|
|
56
|
+
- `LID_b` *(float)* — Upper bound for LID search
|
|
57
|
+
- `cpm_min`*(float)* — Lower bound of the count rate (counts per unit time, e.g., minutes or seconds; CPM) used in the LID search
|
|
58
|
+
- `cpm_max`*(float)* — Upper bound of the count rate (counts per unit time, e.g., minutes or seconds; CPM) used in the LID search
|
|
59
|
+
- `cpm_index`*(integer)* — Index of the parameter corresponding to the count rate (CPM) used in the LID search
|
|
60
|
+
- `sample_indices` *(tuple of int, optional)* — Indices of parameters corresponding to sample measurements modeled as Poisson-distributed variables, with expected counts defined as the parameter value scaled by the measurement time t_m *(default: (0,))*
|
|
61
|
+
- `background_indices` *(tuple of int, optional)* — Indices of parameters corresponding to sample measurements modeled as Poisson-distributed variables, with expected counts defined as the parameter value scaled by the measurement time t_f *(default: (1,))*
|
|
62
|
+
- `rel_map` *(tuple of (int, float), optional)* — Relative uncertainty definitions as *(index, relative_error)* pairs
|
|
63
|
+
- `frac_fondo` *(float, optional)* — Relative uncertainty for background when `t_f <= 0`
|
|
64
|
+
|
|
65
|
+
#### **Returns**
|
|
66
|
+
|
|
67
|
+
- `value` *(float)* — Evaluated value of the model function
|
|
68
|
+
- `u_value` *(float)* — Combined uncertainty
|
|
69
|
+
- `UD` *(float)* — Decision threshold
|
|
70
|
+
- `LID` *(float)* — Decision limit
|
|
71
|
+
#### **Returns**
|
|
72
|
+
|
|
73
|
+
- `value` *(float)* — Evaluated value of the model function
|
|
74
|
+
- `u_value` *(float)* — Combined uncertainty
|
|
75
|
+
- `UD` *(float)* — Decision threshold
|
|
76
|
+
- `LID` *(float)* — Decision limit
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## 📊 Visualization
|
|
81
|
+
|
|
82
|
+
### 🔹 `plot_lid_function`
|
|
83
|
+
|
|
84
|
+
Generates plots to analyze LID behavior.
|
|
85
|
+
|
|
86
|
+
#### **Parameters**
|
|
87
|
+
|
|
88
|
+
- `LID_a` *(float)* — Lower bound
|
|
89
|
+
- `LID_b` *(float)* — Upper bound
|
|
90
|
+
- `p` *(array-like)* — Parameters
|
|
91
|
+
- `f` *(callable)* — Function
|
|
92
|
+
- `UD` *(float)* — Decision threshold
|
|
93
|
+
- `t_m` *(float)* — Measurement time
|
|
94
|
+
- `t_f` *(float)* — Background time
|
|
95
|
+
- `pderivative` *(callable)* — Partial derivative function
|
|
96
|
+
- `bisection` *(callable)* — Root-finding method
|
|
97
|
+
- `cpm_min`*(float)* — Lower bound of the count rate (counts per unit time, e.g., minutes or seconds; CPM) used in the LID search
|
|
98
|
+
- `cpm_max`*(float)* — Upper bound of the count rate (counts per unit time, e.g., minutes or seconds; CPM) used in the LID search
|
|
99
|
+
- `n`*(integer)* — Number of samples or observations used in the LID search
|
|
100
|
+
- `cpm_index`*(integer)* — Index of the parameter corresponding to the count rate (CPM) used in the LID search
|
|
101
|
+
- `k` *(float, optional)* — Coverage factor *(default: 1.65)*
|
|
102
|
+
- `rel_map` *(tuple of (int, float), optional)* — Relative uncertainty definitions as *(index, relative_error)* pairs
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
## 🧪 Activity Functions
|
|
107
|
+
|
|
108
|
+
### 🔹 `AT` — Total Alpha
|
|
109
|
+
|
|
110
|
+
Computes total alpha activity.
|
|
111
|
+
|
|
112
|
+
$AT(Bq\cdot m^{3})= \frac{CPM_M-CPM_F}{60 \cdot ɛ \cdot V_{Alicuot}}$
|
|
113
|
+
|
|
114
|
+
#### **Parameters**
|
|
115
|
+
|
|
116
|
+
- `CPM_m` *(float)* — Sample counts
|
|
117
|
+
- `CPM_f` *(float)* — Background counts
|
|
118
|
+
- `Eps` *(float)* — Detection efficiency
|
|
119
|
+
- `V_ali` *(float)* — Aliquot volume
|
|
120
|
+
|
|
121
|
+
#### **Returns**
|
|
122
|
+
|
|
123
|
+
- *(float)* — Activity
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
### 🔹 `BT` — Total Beta
|
|
128
|
+
|
|
129
|
+
Computes total beta activity.
|
|
130
|
+
|
|
131
|
+
$BT(Bq\cdot m^{3})= \frac{CPM_{\beta-M}-CPM_{\beta-F} - γ \cdot(CPM_{α-M}-CPM_{α-F})}{60 \cdot Ef_{Sr} \cdot V_{Alicuot}⋅Fa}$
|
|
132
|
+
|
|
133
|
+
#### **Parameters**
|
|
134
|
+
|
|
135
|
+
- `CPM_b_m` *(float)* — Measured beta counts
|
|
136
|
+
- `CPM_b_f` *(float)* — Background beta counts
|
|
137
|
+
- `CPM_a_m` *(float)* — Measured alpha counts
|
|
138
|
+
- `CPM_a_f` *(float)* — Background alpha counts
|
|
139
|
+
- `Spill` *(float)* — Spillover correction factor
|
|
140
|
+
- `EFSr` *(float)* — Detection efficiency factor
|
|
141
|
+
- `Fa` *(float)* — Correction factor
|
|
142
|
+
- `V_ali` *(float)* — Aliquot volume
|
|
143
|
+
|
|
144
|
+
#### **Returns**
|
|
145
|
+
|
|
146
|
+
- *(float)* — Total beta activity
|
|
147
|
+
|
|
148
|
+
---
|
|
149
|
+
|
|
150
|
+
## 📦 Installation
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
pip install decision_methods
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
README.md
|
|
3
|
+
pyproject.toml
|
|
4
|
+
src/decision_methods/__init__.py
|
|
5
|
+
src/decision_methods/threshold.py
|
|
6
|
+
src/decision_methods.egg-info/PKG-INFO
|
|
7
|
+
src/decision_methods.egg-info/SOURCES.txt
|
|
8
|
+
src/decision_methods.egg-info/dependency_links.txt
|
|
9
|
+
src/decision_methods.egg-info/requires.txt
|
|
10
|
+
src/decision_methods.egg-info/top_level.txt
|
|
11
|
+
tests/test_compute_lid.py
|
|
12
|
+
tests/test_inputs.py
|
|
13
|
+
tests/test_poisson_model.py
|
|
14
|
+
tests/test_regression.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
decision_methods
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
import decision_methods.threshold as functions
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def test_compute_F_ud_lid_basic():
|
|
6
|
+
p_BT = [3.163, 0.608, 0.154, 0.03, 0.32, 0.444, 0.932164125607044, 0.000375]
|
|
7
|
+
|
|
8
|
+
BT_, u_BT, u_BT_UD, LID_BT = functions.compute_F_ud_lid(
|
|
9
|
+
p_BT, 1000, 2000, functions.BT, functions.pderivative, functions.bisection,
|
|
10
|
+
k=1.65,
|
|
11
|
+
LID_a=0.0, LID_b=20.0,
|
|
12
|
+
tol=1e-12, max_iter=50,
|
|
13
|
+
cpm_min_=0.0, cpm_max_=0.65,
|
|
14
|
+
cpm_min=0.0, cpm_max=1.5,
|
|
15
|
+
cpm_index=1,
|
|
16
|
+
sample_indices=(0, 2),
|
|
17
|
+
background_indices=(1, 3),
|
|
18
|
+
rel_map=((4, 0.1), (5, 0.025), (6, 0.04), (7, 0.01)),
|
|
19
|
+
frac_fondo=None,
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
assert np.isfinite(BT_)
|
|
23
|
+
assert np.isfinite(u_BT)
|
|
24
|
+
assert np.isfinite(u_BT_UD)
|
|
25
|
+
assert np.isfinite(LID_BT)
|
|
26
|
+
|
|
27
|
+
assert BT_ >= 0
|
|
28
|
+
assert u_BT >= 0
|
|
29
|
+
assert u_BT_UD >= 0
|
|
30
|
+
assert LID_BT >= 0
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
import decision_methods.threshold as functions
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def test_compute_F_ud_lid_basic():
|
|
6
|
+
p_BT = [3.163, 0.608, 0.154, 0.03, 0.32, 0.444, 0.932164125607044, 0.000375]
|
|
7
|
+
|
|
8
|
+
BT_, u_BT, u_BT_UD, LID_BT = functions.compute_F_ud_lid(
|
|
9
|
+
p_BT, 1000, 2000, functions.BT, functions.pderivative, functions.bisection,
|
|
10
|
+
k=1.65,
|
|
11
|
+
LID_a=0.0, LID_b=20.0,
|
|
12
|
+
tol=1e-12, max_iter=50,
|
|
13
|
+
cpm_min_=0.0, cpm_max_=0.65,
|
|
14
|
+
cpm_min=0.0, cpm_max=1.5,
|
|
15
|
+
cpm_index=1,
|
|
16
|
+
sample_indices=(0, 2),
|
|
17
|
+
background_indices=(1, 3),
|
|
18
|
+
rel_map=((4, 0.1), (5, 0.025), (6, 0.04), (7, 0.01)),
|
|
19
|
+
frac_fondo=None,
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
assert np.isfinite(BT_)
|
|
23
|
+
assert np.isfinite(u_BT)
|
|
24
|
+
assert np.isfinite(u_BT_UD)
|
|
25
|
+
assert np.isfinite(LID_BT)
|
|
26
|
+
|
|
27
|
+
assert BT_ >= 0
|
|
28
|
+
assert u_BT >= 0
|
|
29
|
+
assert u_BT_UD >= 0
|
|
30
|
+
assert LID_BT >= 0
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
import decision_methods.threshold as functions
|
|
3
|
+
|
|
4
|
+
EXPECTED_BT = 270.1067085367795
|
|
5
|
+
EXPECTED_U_BT = 14.49093
|
|
6
|
+
EXPECTED_U_BT_UD = 5.56013
|
|
7
|
+
EXPECTED_LID_BT = 11.48531
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def test_compute_F_ud_lid_regression():
|
|
11
|
+
np.random.seed(0)
|
|
12
|
+
p_BT = [3.163, 0.608, 0.154, 0.03, 0.32, 0.444, 0.932164125607044, 0.000375]
|
|
13
|
+
|
|
14
|
+
BT_, u_BT, u_BT_UD, LID_BT = functions.compute_F_ud_lid(
|
|
15
|
+
p_BT, 1000, 2000, functions.BT, functions.pderivative, functions.bisection,
|
|
16
|
+
k=1.65,
|
|
17
|
+
LID_a=0.0, LID_b=20.0,
|
|
18
|
+
tol=1e-12, max_iter=50,
|
|
19
|
+
cpm_min_=0.0, cpm_max_=0.65,
|
|
20
|
+
cpm_min=0.0, cpm_max=1.5,
|
|
21
|
+
cpm_index=1,
|
|
22
|
+
sample_indices=(0, 2),
|
|
23
|
+
background_indices=(1, 3),
|
|
24
|
+
rel_map=((4, 0.1), (5, 0.025), (6, 0.04), (7, 0.01)),
|
|
25
|
+
frac_fondo=None,
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
assert np.isclose(BT_, EXPECTED_BT, rtol=1e-5, atol=1e-6)
|
|
29
|
+
assert np.isclose(u_BT, EXPECTED_U_BT, rtol=1e-5, atol=1e-6)
|
|
30
|
+
assert np.isclose(u_BT_UD, EXPECTED_U_BT_UD, rtol=1e-5, atol=1e-6)
|
|
31
|
+
assert np.isclose(LID_BT, EXPECTED_LID_BT, rtol=1e-5, atol=1e-6)
|