accord-rt 0.2__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.
- accord_rt-0.2/LICENSE +21 -0
- accord_rt-0.2/PKG-INFO +22 -0
- accord_rt-0.2/accord/__init__.py +2 -0
- accord_rt-0.2/accord/__main__.py +7 -0
- accord_rt-0.2/accord/core/__init__.py +0 -0
- accord_rt-0.2/accord/core/corrections.py +82 -0
- accord_rt-0.2/accord/core/customSim.py +12 -0
- accord_rt-0.2/accord/core/metrology.py +73 -0
- accord_rt-0.2/accord/core/nel_aux.py +201 -0
- accord_rt-0.2/accord/formats/fileFormats.json +67 -0
- accord_rt-0.2/accord/formats/quantities.json +22 -0
- accord_rt-0.2/accord/interfaces/cli_click/__init__.py +0 -0
- accord_rt-0.2/accord/interfaces/cli_click/commands.py +539 -0
- accord_rt-0.2/accord/interfaces/gui_kivy/__init__.py +0 -0
- accord_rt-0.2/accord/models/__init__.py +0 -0
- accord_rt-0.2/accord/models/annotatedTypes.py +74 -0
- accord_rt-0.2/accord/models/params.py +168 -0
- accord_rt-0.2/accord/models/trs398.py +45 -0
- accord_rt-0.2/accord/sampleFiles/calibration.toml +22 -0
- accord_rt-0.2/accord/sampleFiles/config.toml +33 -0
- accord_rt-0.2/accord/sampleFiles/devices.toml +11 -0
- accord_rt-0.2/accord/sampleFiles/preliminary_0.csv +9 -0
- accord_rt-0.2/accord/sampleFiles/preliminary_1.csv +9 -0
- accord_rt-0.2/accord/sampleFiles/preliminary_2.csv +9 -0
- accord_rt-0.2/pyproject.toml +37 -0
accord_rt-0.2/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Nelson Sandoval Puente
|
|
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
|
|
13
|
+
all 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
|
|
21
|
+
THE SOFTWARE.
|
accord_rt-0.2/PKG-INFO
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: accord-rt
|
|
3
|
+
Version: 0.2
|
|
4
|
+
Summary: accord: Calculator for TRS-398 calibration.
|
|
5
|
+
Author: jonjon-el
|
|
6
|
+
Requires-Python: >=3.8
|
|
7
|
+
License-Expression: MIT
|
|
8
|
+
Classifier: Development Status :: 2 - Pre-Alpha
|
|
9
|
+
Classifier: Intended Audience :: Healthcare Industry
|
|
10
|
+
Classifier: Intended Audience :: Science/Research
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
12
|
+
Classifier: Operating System :: OS Independent
|
|
13
|
+
Classifier: Topic :: Scientific/Engineering :: Medical Science Apps.
|
|
14
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
15
|
+
License-File: LICENSE
|
|
16
|
+
Requires-Dist: click>=8.0
|
|
17
|
+
Requires-Dist: pylinac>=3.43.2,<4.0.0
|
|
18
|
+
Requires-Dist: numpy
|
|
19
|
+
Requires-Dist: scipy
|
|
20
|
+
Project-URL: Homepage, https://github.com/jonjon-el/accord
|
|
21
|
+
Project-URL: Issues, https://github.com/jonjon-el/accord/issues
|
|
22
|
+
Project-URL: Source, https://github.com/jonjon-el/accord
|
|
File without changes
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
from pylinac import ct
|
|
2
|
+
from scipy import constants
|
|
3
|
+
import numpy as np
|
|
4
|
+
|
|
5
|
+
def calc_c_T(P_expected_value: float, T_ref: float, P_ref: float) -> float:
|
|
6
|
+
"""
|
|
7
|
+
Calculate the sensitivity of temperature.
|
|
8
|
+
|
|
9
|
+
Args:
|
|
10
|
+
P_expected_value (float): The expected value of the measurand. (e.g., the expected pressure)
|
|
11
|
+
T_ref (float): The reference temperature.
|
|
12
|
+
P_ref (float): The reference pressure.
|
|
13
|
+
Returns:
|
|
14
|
+
float: The sensitivity of temperature.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
# Check values
|
|
18
|
+
if P_expected_value <= 0:
|
|
19
|
+
raise ValueError("Expected value must be greater than zero.")
|
|
20
|
+
if P_ref <= 0:
|
|
21
|
+
raise ValueError("Reference pressure must be greater than zero.")
|
|
22
|
+
if T_ref <= -constants.zero_Celsius:
|
|
23
|
+
raise ValueError("Reference temperature must be greater than absolute zero.")
|
|
24
|
+
|
|
25
|
+
# Calculate the sensitivity of temperature
|
|
26
|
+
c_T = abs( P_ref / ((constants.zero_Celsius + T_ref)*P_expected_value))
|
|
27
|
+
return c_T
|
|
28
|
+
|
|
29
|
+
def calc_c_P(L_expected_value: float, T_expected_value: float, P_expected_value: float, T_ref: float, P_ref: float) -> float:
|
|
30
|
+
"""
|
|
31
|
+
Calculate the sensitivity of pressure.
|
|
32
|
+
|
|
33
|
+
Args:
|
|
34
|
+
L_expected_value (float): The expected value of the measurand. (e.g., the expected crude lecture)
|
|
35
|
+
T_expected_value (float): The expected value of the measurand. (e.g., the expected temperature)
|
|
36
|
+
P_expected_value (float): The expected value of the measurand. (e.g., the expected pressure)
|
|
37
|
+
T_ref (float): The reference temperature.
|
|
38
|
+
P_ref (float): The reference pressure.
|
|
39
|
+
Returns:
|
|
40
|
+
float: The sensitivity of pressure.
|
|
41
|
+
"""
|
|
42
|
+
|
|
43
|
+
# Check values
|
|
44
|
+
if T_expected_value <= -constants.zero_Celsius:
|
|
45
|
+
raise ValueError("Expected temperature must be greater than absolute zero.")
|
|
46
|
+
if P_expected_value <= 0:
|
|
47
|
+
raise ValueError("Expected value must be greater than zero.")
|
|
48
|
+
if P_ref <= 0:
|
|
49
|
+
raise ValueError("Reference pressure must be greater than zero.")
|
|
50
|
+
if T_ref <= -constants.zero_Celsius:
|
|
51
|
+
raise ValueError("Reference temperature must be greater than absolute zero.")
|
|
52
|
+
|
|
53
|
+
# Calculate the sensitivity of pressure
|
|
54
|
+
c_P = abs(((constants.zero_Celsius + T_expected_value)*P_ref*L_expected_value) / ((constants.zero_Celsius + T_ref)*np.power(P_expected_value, 2)))
|
|
55
|
+
return c_P
|
|
56
|
+
|
|
57
|
+
def calc_c_L(T_expected_value: float, P_expected_value: float, T_ref: float, P_ref: float) -> float:
|
|
58
|
+
"""
|
|
59
|
+
Calculate the sensitivity of crude lecture.
|
|
60
|
+
|
|
61
|
+
Args:
|
|
62
|
+
T_expected_value (float): The expected value of the measurand. (e.g., the expected temperature)
|
|
63
|
+
P_expected_value (float): The expected value of the measurand. (e.g., the expected pressure)
|
|
64
|
+
T_ref (float): The reference temperature.
|
|
65
|
+
P_ref (float): The reference pressure.
|
|
66
|
+
Returns:
|
|
67
|
+
float: The sensitivity of crude lecture.
|
|
68
|
+
"""
|
|
69
|
+
|
|
70
|
+
# Check values
|
|
71
|
+
if T_expected_value <= -constants.zero_Celsius:
|
|
72
|
+
raise ValueError("Expected temperature must be greater than absolute zero.")
|
|
73
|
+
if P_expected_value <= 0:
|
|
74
|
+
raise ValueError("Expected value must be greater than zero.")
|
|
75
|
+
if P_ref <= 0:
|
|
76
|
+
raise ValueError("Reference pressure must be greater than zero.")
|
|
77
|
+
if T_ref <= -constants.zero_Celsius:
|
|
78
|
+
raise ValueError("Reference temperature must be greater than absolute zero.")
|
|
79
|
+
|
|
80
|
+
# Calculate the sensitivity of crude lecture
|
|
81
|
+
c_L = abs(((constants.zero_Celsius + T_expected_value)*P_ref) / ((constants.zero_Celsius + T_ref)*P_expected_value))
|
|
82
|
+
return c_L
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
import functools
|
|
3
|
+
|
|
4
|
+
def calc_U (u: float, k: float) -> float:
|
|
5
|
+
"""
|
|
6
|
+
Calculate the combined uncertainty.
|
|
7
|
+
|
|
8
|
+
Args:
|
|
9
|
+
u (float): The combined standard uncertainty.
|
|
10
|
+
k (float): The coverage factor.
|
|
11
|
+
|
|
12
|
+
Returns:
|
|
13
|
+
float: The combined uncertainty.
|
|
14
|
+
"""
|
|
15
|
+
return u * k
|
|
16
|
+
|
|
17
|
+
def calc_u_c (*u_i) -> float:
|
|
18
|
+
"""
|
|
19
|
+
Calculate the combined standard uncertainty.
|
|
20
|
+
|
|
21
|
+
Args:
|
|
22
|
+
*u_i (float): Variable number of standard uncertainties.
|
|
23
|
+
Returns:
|
|
24
|
+
float: The combined standard uncertainty.
|
|
25
|
+
"""
|
|
26
|
+
return functools.reduce(np.hypot, u_i)
|
|
27
|
+
|
|
28
|
+
def calc_u_A (*measurand_values) -> float:
|
|
29
|
+
"""
|
|
30
|
+
Calculate Type A standard uncertainty.
|
|
31
|
+
|
|
32
|
+
Args:
|
|
33
|
+
*measurand_values (float): Variable number of the mean values for each series.
|
|
34
|
+
Returns:
|
|
35
|
+
float: The Type A uncertainty.
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
n = len(measurand_values)
|
|
39
|
+
|
|
40
|
+
# Calculate the sample standard deviation. (n-1 Bessel's correction)
|
|
41
|
+
std_dev = np.std(measurand_values, ddof=1)
|
|
42
|
+
|
|
43
|
+
# Calculate the standard uncertainty of the mean
|
|
44
|
+
u_A = std_dev / np.sqrt(n)
|
|
45
|
+
|
|
46
|
+
return u_A
|
|
47
|
+
|
|
48
|
+
def calc_u_B(error_value: float, distribution: str, k: float|None = None) -> float:
|
|
49
|
+
"""
|
|
50
|
+
Calculate Type B standard uncertainty.
|
|
51
|
+
|
|
52
|
+
Args:
|
|
53
|
+
error_value (float): The value of the error.
|
|
54
|
+
distribution (str): The type of uncertainty. ("rectangular" , "triangular", "normal" distributions are supported)
|
|
55
|
+
k (float): The coverage factor for normal distribution. (ignored for other distributions)
|
|
56
|
+
Returns:
|
|
57
|
+
float: The standard uncertainty.
|
|
58
|
+
"""
|
|
59
|
+
|
|
60
|
+
if distribution == "rectangular":
|
|
61
|
+
u_B = error_value / np.sqrt(3)
|
|
62
|
+
elif distribution == "triangular":
|
|
63
|
+
u_B = error_value / np.sqrt(6)
|
|
64
|
+
elif distribution == "normal":
|
|
65
|
+
if k is None:
|
|
66
|
+
raise ValueError("Coverage factor 'k' is required for normal distribution.")
|
|
67
|
+
if k <= 0:
|
|
68
|
+
raise ValueError("Coverage factor 'k' must be a positive number.")
|
|
69
|
+
u_B = error_value / k
|
|
70
|
+
else:
|
|
71
|
+
raise ValueError("Unsupported distribution type. Supported types are: 'rectangular', 'triangular', 'normal'.")
|
|
72
|
+
|
|
73
|
+
return u_B
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import importlib.resources
|
|
2
|
+
import pathlib
|
|
3
|
+
import shutil
|
|
4
|
+
|
|
5
|
+
import pylinac.calibration.trs398
|
|
6
|
+
import tomllib
|
|
7
|
+
|
|
8
|
+
# This file contains auxiliary functions for the NEL calibration process.
|
|
9
|
+
|
|
10
|
+
# Copy sample files.
|
|
11
|
+
def copy_sample_files(path: pathlib.Path, file_class: str):
|
|
12
|
+
configTraversable_list = list()
|
|
13
|
+
if file_class == "config":
|
|
14
|
+
configTraversable_list.append(importlib.resources.files("accord").joinpath("sampleFiles/config.toml"))
|
|
15
|
+
elif file_class == "calibration":
|
|
16
|
+
configTraversable_list.append(importlib.resources.files("accord").joinpath("sampleFiles/calibration.toml"))
|
|
17
|
+
# TODO: make file_class a list of paths to work with the three preliminary.csv original files.
|
|
18
|
+
elif file_class == "preliminary":
|
|
19
|
+
configTraversable_list.append(importlib.resources.files("accord").joinpath("sampleFiles/preliminary_0.csv"))
|
|
20
|
+
configTraversable_list.append(importlib.resources.files("accord").joinpath("sampleFiles/preliminary_1.csv"))
|
|
21
|
+
configTraversable_list.append(importlib.resources.files("accord").joinpath("sampleFiles/preliminary_2.csv"))
|
|
22
|
+
elif file_class == "devices":
|
|
23
|
+
configTraversable_list.append(importlib.resources.files("accord").joinpath("sampleFiles/devices.toml"))
|
|
24
|
+
else:
|
|
25
|
+
raise ValueError("Invalid file type. Please choose 'config', 'calibration', 'preliminary', or 'devices'.")
|
|
26
|
+
|
|
27
|
+
try:
|
|
28
|
+
for configTraversable in configTraversable_list:
|
|
29
|
+
with importlib.resources.as_file(configTraversable) as configPath:
|
|
30
|
+
shutil.copy(configPath, path)
|
|
31
|
+
print(f"File copied.")
|
|
32
|
+
except FileNotFoundError:
|
|
33
|
+
raise ValueError(f"Sample file not found in {configPath}.")
|
|
34
|
+
except PermissionError:
|
|
35
|
+
raise ValueError(f"Permission denied when copying file.")
|
|
36
|
+
except shutil.SameFileError:
|
|
37
|
+
raise ValueError(f"Source and destination represents the same file.")
|
|
38
|
+
except OSError as e:
|
|
39
|
+
raise ValueError(f"Error copying file: {e.strerror}.")
|
|
40
|
+
|
|
41
|
+
# Load a TOML file
|
|
42
|
+
def load_toml_file(path: pathlib.Path) -> dict[str, object]:
|
|
43
|
+
with open(path, "rb") as f:
|
|
44
|
+
return tomllib.load(f)
|
|
45
|
+
|
|
46
|
+
# Get a nested value in a dictionary
|
|
47
|
+
def get_nested(dictObj, *keys, default=None):
|
|
48
|
+
for key in keys:
|
|
49
|
+
if isinstance(dictObj, dict):
|
|
50
|
+
dictObj = dictObj.get(key)
|
|
51
|
+
else:
|
|
52
|
+
return default
|
|
53
|
+
return dictObj if dictObj is not None else default
|
|
54
|
+
|
|
55
|
+
# Validate option helper.
|
|
56
|
+
def resolve_option2(cli_value, config, key_path):
|
|
57
|
+
keys = key_path.split(".")
|
|
58
|
+
value = cli_value or get_nested(config, *keys)
|
|
59
|
+
|
|
60
|
+
# if value is None:
|
|
61
|
+
# raise ValueError(f"Missing required option: --{keys[-1]} or '{key_path}' in config.")
|
|
62
|
+
return value
|
|
63
|
+
|
|
64
|
+
# Example calibration data structure used in the calibration file.
|
|
65
|
+
calibration_data = {
|
|
66
|
+
"chamber":"30013",
|
|
67
|
+
"clinical_pdd_zref": 66.5,
|
|
68
|
+
"energy": 6,
|
|
69
|
+
"fff": False,
|
|
70
|
+
"institution": "Your institution here",
|
|
71
|
+
"k_elec": 1.000,
|
|
72
|
+
"m_opposite": [25.64, 25.65, 25.65],
|
|
73
|
+
"m_reference": [25.65, 25.66, 25.65],
|
|
74
|
+
"m_reduced": [25.64, 25.63, 25.63],
|
|
75
|
+
"measurement_date": "2025-05-16",
|
|
76
|
+
"mu": 200,
|
|
77
|
+
"n_dw": 5.443,
|
|
78
|
+
"physicist": "Person realizing the calibration",
|
|
79
|
+
"press": 100.65839,
|
|
80
|
+
"setup": "SSD",
|
|
81
|
+
"temp": 22.1,
|
|
82
|
+
"tissue_correction": 1.0,
|
|
83
|
+
"tpr2010": 0.573573574,
|
|
84
|
+
"unit": "Unit employed",
|
|
85
|
+
"voltage_reduced": -150,
|
|
86
|
+
"voltage_reference": -300,
|
|
87
|
+
"notes": "Sample note."
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
def GetBaseTypes(config_quantities: dict) -> dict:
|
|
91
|
+
"""
|
|
92
|
+
Get the base types of the quantities from the config file.
|
|
93
|
+
"""
|
|
94
|
+
baseTypes = dict()
|
|
95
|
+
for key in config_quantities:
|
|
96
|
+
baseTypes[key] = config_quantities[key]["baseType"]
|
|
97
|
+
return baseTypes
|
|
98
|
+
|
|
99
|
+
def Row2Measurement(row: dict, baseTypes: dict) -> dict:
|
|
100
|
+
"""
|
|
101
|
+
Convert a row from the CSV file into a measurement dictionary.
|
|
102
|
+
"""
|
|
103
|
+
measurement = dict()
|
|
104
|
+
for key in row:
|
|
105
|
+
if baseTypes[key] == "int":
|
|
106
|
+
measurement[key] = int(row[key])
|
|
107
|
+
elif baseTypes[key] == "float":
|
|
108
|
+
measurement[key] = float(row[key])
|
|
109
|
+
|
|
110
|
+
return measurement
|
|
111
|
+
|
|
112
|
+
def Row2Measurement2(row: dict, quantities: dict) -> dict:
|
|
113
|
+
"""
|
|
114
|
+
Convert a dictionary containing a row from the CSV file to a dictionary containing the same values but with the correct base types.
|
|
115
|
+
Base types are obtained from the quantities dictionary in the json file.
|
|
116
|
+
"""
|
|
117
|
+
measurement = dict()
|
|
118
|
+
for key in row:
|
|
119
|
+
if quantities[key]["baseType"] == "int":
|
|
120
|
+
measurement[key] = int(row[key])
|
|
121
|
+
elif quantities[key]["baseType"] == "float":
|
|
122
|
+
measurement[key] = float(row[key])
|
|
123
|
+
elif quantities[key]["baseType"] == "str":
|
|
124
|
+
measurement[key] = row[key]
|
|
125
|
+
elif quantities[key]["baseType"] == "bool":
|
|
126
|
+
measurement[key] = row[key].lower() in ("true")
|
|
127
|
+
|
|
128
|
+
return measurement
|
|
129
|
+
|
|
130
|
+
def ConvertMeasurement(rawMeasurement: dict, oldUnits: dict, newUnits: dict) -> dict:
|
|
131
|
+
"""
|
|
132
|
+
Converts raw measurement in old units to new units.
|
|
133
|
+
"""
|
|
134
|
+
measurement = rawMeasurement.copy()
|
|
135
|
+
for key in rawMeasurement:
|
|
136
|
+
if oldUnits[key] != newUnits[key]:
|
|
137
|
+
if key == "T":
|
|
138
|
+
# measurement[key] = trs398.convert_temperature(rawMeasurement[key], oldUnits[key], newUnits[key])
|
|
139
|
+
if oldUnits[key] == "°F":
|
|
140
|
+
measurement[key] = pylinac.calibration.trs398.fahrenheit2celsius(rawMeasurement[key])
|
|
141
|
+
elif oldUnits[key] == "K":
|
|
142
|
+
measurement[key] = rawMeasurement[key] + 273
|
|
143
|
+
elif key == "P":
|
|
144
|
+
# measurement[key] = trs398.convert_pressure(rawMeasurement[key], oldUnits[key], newUnits[key])
|
|
145
|
+
if oldUnits[key] == "mbar":
|
|
146
|
+
measurement[key] = pylinac.calibration.trs398.mbar2kPa(rawMeasurement[key])
|
|
147
|
+
elif oldUnits[key] == "mmHg":
|
|
148
|
+
measurement[key] = pylinac.calibration.trs398.mmHg2kPa(rawMeasurement[key])
|
|
149
|
+
# elif key == "m":
|
|
150
|
+
# measurement[key] = trs398.convert_charge(rawMeasurement[key], oldUnits[key], newUnits[key])
|
|
151
|
+
# elif key == "k_TP":
|
|
152
|
+
# measurement[key] = trs398.convert_temperature_pressure_correction_factor(rawMeasurement["T"], rawMeasurement["P"], oldUnits["T"], oldUnits["P"], newUnits["T"], newUnits["P"])
|
|
153
|
+
# elif key == "m_corrected":
|
|
154
|
+
# measurement[key] = trs398.convert_charge(rawMeasurement[key], oldUnits[key], newUnits[key])
|
|
155
|
+
return measurement
|
|
156
|
+
|
|
157
|
+
def Convert_measurement_to_pylinac_units(measurement: dict, oldUnits: dict) -> dict:
|
|
158
|
+
converted_measurement = measurement.copy()
|
|
159
|
+
for key in converted_measurement:
|
|
160
|
+
if key == "T":
|
|
161
|
+
if oldUnits[key] == "°F":
|
|
162
|
+
converted_measurement[key] = pylinac.calibration.trs398.fahrenheit2celsius(converted_measurement[key])
|
|
163
|
+
elif oldUnits[key] == "°C":
|
|
164
|
+
pass
|
|
165
|
+
else:
|
|
166
|
+
raise ValueError(f"Invalid temperature unit: {oldUnits[key]}")
|
|
167
|
+
elif key == "P":
|
|
168
|
+
if oldUnits[key] == "mbar":
|
|
169
|
+
converted_measurement[key] = pylinac.calibration.trs398.mbar2kPa(converted_measurement[key])
|
|
170
|
+
elif oldUnits[key] == "mmHg":
|
|
171
|
+
converted_measurement[key] = pylinac.calibration.trs398.mmHg2kPa(converted_measurement[key])
|
|
172
|
+
elif oldUnits[key] == "kPa":
|
|
173
|
+
pass
|
|
174
|
+
else:
|
|
175
|
+
raise ValueError(f"Invalid pressure unit: {oldUnits[key]}")
|
|
176
|
+
|
|
177
|
+
return converted_measurement
|
|
178
|
+
|
|
179
|
+
def FindAverage(numberList: list) -> float:
|
|
180
|
+
acum = 0
|
|
181
|
+
for number in numberList:
|
|
182
|
+
acum = acum + number
|
|
183
|
+
# DEBUG: FAIL. With empty value .csv input files.
|
|
184
|
+
return acum / len(numberList)
|
|
185
|
+
|
|
186
|
+
def FindStdDev(numberList: list) -> float:
|
|
187
|
+
average = FindAverage(numberList)
|
|
188
|
+
acum = 0
|
|
189
|
+
for number in numberList:
|
|
190
|
+
acum = acum + (number - average) ** 2
|
|
191
|
+
return (acum / (len(numberList)-1)) ** 0.5
|
|
192
|
+
|
|
193
|
+
def FindExpectedValue(numberList: list) -> float:
|
|
194
|
+
return FindAverage(numberList)
|
|
195
|
+
|
|
196
|
+
def main():
|
|
197
|
+
return 0
|
|
198
|
+
|
|
199
|
+
if __name__ == "__main__":
|
|
200
|
+
errorCode = main()
|
|
201
|
+
print(f"Program terminated with errorCode: {errorCode}")
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
{
|
|
2
|
+
"input_preliminary": {
|
|
3
|
+
"type:": "csv",
|
|
4
|
+
"description": "Preliminary input file with raw readings of the electrometer and the temperature and pressure values.",
|
|
5
|
+
"column_delimiter": ";",
|
|
6
|
+
"columns": {
|
|
7
|
+
"index": {
|
|
8
|
+
"name": "Index",
|
|
9
|
+
"unit": "",
|
|
10
|
+
"description": "Index"
|
|
11
|
+
},
|
|
12
|
+
"T": {
|
|
13
|
+
"name": "T",
|
|
14
|
+
"unit": "°C",
|
|
15
|
+
"description": "Temperature"
|
|
16
|
+
},
|
|
17
|
+
"P": {
|
|
18
|
+
"name": "P",
|
|
19
|
+
"unit": "kPa",
|
|
20
|
+
"description": "Pressure"
|
|
21
|
+
},
|
|
22
|
+
"m": {
|
|
23
|
+
"name": "m",
|
|
24
|
+
"unit": "nC",
|
|
25
|
+
"description": "Raw reading of the electrometer"
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
,
|
|
30
|
+
"output_preliminary": {
|
|
31
|
+
"type:": "csv",
|
|
32
|
+
"description": "Preliminary output file with corrected readings of the electrometer and the correction factor for temperature and pressure.",
|
|
33
|
+
"column_delimiter": ";",
|
|
34
|
+
"columns": {
|
|
35
|
+
"index": {
|
|
36
|
+
"name": "Index",
|
|
37
|
+
"unit": "",
|
|
38
|
+
"description": "Index"
|
|
39
|
+
},
|
|
40
|
+
"T": {
|
|
41
|
+
"name": "T",
|
|
42
|
+
"unit": "°C",
|
|
43
|
+
"description": "Temperature"
|
|
44
|
+
},
|
|
45
|
+
"P": {
|
|
46
|
+
"name": "P",
|
|
47
|
+
"unit": "kPa",
|
|
48
|
+
"description": "Pressure"
|
|
49
|
+
},
|
|
50
|
+
"m": {
|
|
51
|
+
"name": "m",
|
|
52
|
+
"unit": "nC",
|
|
53
|
+
"description": "Raw reading of the electrometer"
|
|
54
|
+
},
|
|
55
|
+
"k_TP": {
|
|
56
|
+
"name": "k_TP",
|
|
57
|
+
"unit": "",
|
|
58
|
+
"description": "Correction factor for temperature and pressure"
|
|
59
|
+
},
|
|
60
|
+
"m_corrected": {
|
|
61
|
+
"name": "m_corrected",
|
|
62
|
+
"unit": "nC",
|
|
63
|
+
"description": "Corrected reading of electrometer"
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"index": {
|
|
3
|
+
"description": "Index of the quantity",
|
|
4
|
+
"unit": null,
|
|
5
|
+
"baseType": "int"
|
|
6
|
+
},
|
|
7
|
+
"T": {
|
|
8
|
+
"description": "Temperature",
|
|
9
|
+
"unit": "K",
|
|
10
|
+
"baseType": "float"
|
|
11
|
+
},
|
|
12
|
+
"P": {
|
|
13
|
+
"description": "Pressure",
|
|
14
|
+
"unit": "Pa",
|
|
15
|
+
"baseType": "float"
|
|
16
|
+
},
|
|
17
|
+
"m": {
|
|
18
|
+
"description": "Electrometer reading",
|
|
19
|
+
"unit": "nC",
|
|
20
|
+
"baseType": "float"
|
|
21
|
+
}
|
|
22
|
+
}
|
|
File without changes
|