dhavalkadia-fda commited on
Commit
d0f9f3b
1 Parent(s): 26438a8

Upload 30 files

Browse files
PyBDC/.readthedocs.yaml ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # .readthedocs.yaml
2
+ # Read the Docs configuration file
3
+ # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
4
+
5
+ # Required
6
+ version: 2
7
+
8
+ # Set the version of Python and other tools you might need
9
+ build:
10
+ os: ubuntu-22.04
11
+ tools:
12
+ python: "3.10"
13
+ # You can also specify other tool versions:
14
+ # nodejs: "19"
15
+ # rust: "1.64"
16
+ # golang: "1.19"
17
+
18
+
PyBDC/CT_Dose_Calculate_Quick_Guide.txt ADDED
@@ -0,0 +1,56 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Quick Start Guide
2
+
3
+ 1. To begin start by choosing a method: Sarno Koning, Sarno Incident Spectrum, or Hernandez Heterogeneous BCT
4
+
5
+ a) Each method can be selected by selecting the radio button next to the method
6
+
7
+ i) the default is Sarno Incident Spectrum
8
+
9
+ c) Selecting the Sarno Koning BCT will lead to an output in the text box stating a description of Koning
10
+ BCT apparatus
11
+
12
+ b) Selecting the Hernandez Heterogeneous BCT method will lead to the text box on the bottom corner being
13
+ filled with the a description for each of the heterogeneous categories
14
+
15
+ 2. After selecting a method, choose your parameters in the box next over
16
+
17
+ a) Sample parameters include breast diameter, breast height, etc.
18
+
19
+ b) Simply click on the downward arrow and choose the parameter of your choice
20
+
21
+ c) You'll notice some parameters are deactivated and this is due to the method of your choice. Each method
22
+ uses different sets of parameters. As such, the parameters necessary for the method will remain active
23
+ and those not necessary will remain inactive
24
+
25
+ 3. After choosing parameters, enter your air KERMA along with the input units and the desired output units.
26
+
27
+ a) Simply enter your air KERMA into the air KERMA box and like before choose the input units in Air KERMA
28
+ Units and output units via MGD Units by pressing the downward arrow
29
+
30
+ 4. Depending on the method of your choice, you will have the option to input an incident spectrum and graph that
31
+ spectrum
32
+
33
+ a) If you have chosen either Sarno Incident Spectrum or Hernandez Heterogeneous BCT, the option the input an
34
+ incident spectrum will be available to you.
35
+
36
+ i) This is not optional; you must enter an incident spectrum for the method to work
37
+
38
+ b) Simply press the Input Incident Spectrum Button and a popup will appear prompting you to choose a file.
39
+ Please select an appropriate text file following the format outlined in the complete user guide.
40
+
41
+ i) Once an acceptable file has been chosen, a shortened file name will appear in the text box found on
42
+ the bottom left
43
+
44
+ c) After inputting the file, the Graph Spectrum button will activate. You can then press the Graph Spectrum
45
+ button which will display your incident spectrum on the graph
46
+
47
+ 5. Once you are satisfied with all your inputs, you can press the Calculate Dose button found at the bottom left corner
48
+ next to the Clear Text button
49
+
50
+ a) Pressing the Calculate Dose button will lead to an output in the text box of your mean glandular dose value
51
+ and your chosen parameters.
52
+
53
+ b) The text will remain in the box unless you elect to clear the box. The box can be easily cleared by pressing
54
+ the Clear Text button. Do note that your previous values will be cleared and cannot be retrieved.
55
+
56
+ 6. For a complete user guide refer to the user guide
PyBDC/Doc/GUI_Example_PyBDC.PNG ADDED
PyBDC/Doc/Makefile ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Minimal makefile for Sphinx documentation
2
+ #
3
+
4
+ # You can set these variables from the command line, and also
5
+ # from the environment for the first two.
6
+ SPHINXOPTS ?=
7
+ SPHINXBUILD ?= sphinx-build
8
+ SOURCEDIR = source
9
+ BUILDDIR = build
10
+
11
+ # Put it first so that "make" without argument is like "make help".
12
+ help:
13
+ @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
14
+
15
+ .PHONY: help Makefile
16
+
17
+ # Catch-all target: route all unknown targets to Sphinx using the new
18
+ # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
19
+ %: Makefile
20
+ @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
PyBDC/Doc/conf.py ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Configuration file for the Sphinx documentation builder.
2
+
3
+ # -- Project information
4
+ project = 'PyBDC'
5
+ copyright = '2023, Marupudi'
6
+ author = 'Harsha Marupudi'
7
+ release = '0.1'
8
+ version = '0.1.0'
9
+
10
+ # -- General configuration
11
+ extensions = [
12
+ 'sphinx.ext.duration',
13
+ 'sphinx.ext.doctest',
14
+ 'sphinx.ext.autodoc',
15
+ 'sphinx.ext.autosummary',
16
+ 'sphinx.ext.intersphinx',
17
+ ]
18
+
19
+ intersphinx_mapping = {
20
+ 'python': ('https://docs.python.org/3/', None),
21
+ 'sphinx': ('https://www.sphinx-doc.org/en/master/', None),
22
+ }
23
+ intersphinx_disabled_domains = ['std']
24
+
25
+ templates_path = ['_templates']
PyBDC/Doc/gui.rst ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ GUI Overview
2
+ ============
3
+
4
+ The Python GUI runs on Windows, Mac, and Linux. All inputs and buttons are shown in the screenshots of the interface below.
5
+
6
+
7
+ .. image:: GUI_Example_PyBDC.PNG
8
+
9
+
10
+ Figure 1: Screen captures of PyBDC program. The image shows example inputs used by the GUI to compute the mean glandular dose. The provided example is for the Sarno method with an incident spectrum measured at 55 kVp, with 2 mm of aluminum filtration. The incident spectrum is also plotted in the figure.
11
+
12
+ Data Files
13
+ ==========
14
+ The program requires several data files found within the program directory. These data files consist of the dose tables necessary for dose calculations and a python file to read the text files and convert them to a pandas data frame which can be easily accessed. The following are the necessary data files:
15
+
16
+ Dose tables:
17
+
18
+ * Hernandez_heterogeneous_dgn
19
+
20
+ * Sarno_mono_dgn
21
+
22
+ * Sarno_poly_dgn
23
+
24
+ * Sechopoulos_dgn
25
+
26
+ The Hernandez heterogeneous text file contains columns for the photon energy values, and the different volume glandular fractions (V1, V3, and V5). The coefficients range are in units of mGy/mGy and range from 9 to 70 keV with a step size of 1.
27
+
28
+ The Sarno monoergentic DgN text file contains columns for the different breast diameters, the glandularity, and the breast height value. The DgN coefficients are in units of mGy/mGy. Lastly, the Sarno polyenergetic DgN text file contains columns for the HVL lengths, the different breast diameters, the glandularity, and the breast heights.
29
+
30
+ The Sechopoulos DgN text file contains a column for the breast diameter, breast length, and the different glandularities. The coefficients are in units of mGy/mGy.
31
+
32
+ Python file for dose equations:
33
+ dose_equations.py
34
+
35
+ This file simply reads the different tables mentioned above and converts them into a pandas data frame. The file further contains the necessary equations for calculating mean glandular dose values.
36
+
37
+
PyBDC/Doc/index.rst ADDED
@@ -0,0 +1,73 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Welcome to PyBDC Documentation!
2
+ =====================================
3
+
4
+ Python toolkit for calculating dosage for breast CT.\
5
+ The following software enables accurate dose estimation for one or various breast exposures specifically for breast CT. The software can be used on Windows and Mac operating systems and using a graphical user interface. The mode is further explained below along with an overview of the methods, how to choose a method, the program inputs and buttons, the incident spectrum format, images of the GUI, and the accompanying data files.
6
+
7
+
8
+ Table of Contents
9
+ ==================
10
+ .. toctree::
11
+ :hidden:
12
+
13
+ Home <self>
14
+
15
+ .. toctree::
16
+ :maxdepth: 2
17
+
18
+ install
19
+ methods
20
+ gui
21
+
22
+ examples
23
+
24
+ Methods Overview
25
+ ==================
26
+
27
+ Currently supports the following plugins:
28
+
29
+ * Sarno Any Spectrum
30
+ * Hernandez Any Spectrum
31
+ * Sarno 49 kVp W Spectra
32
+ * Sechopoulus 49 kvP W Spectra
33
+
34
+ Detailed descriptions on individual methods are provided in section :ref:`Methods Overview`.
35
+
36
+ Installation
37
+ ==================
38
+ **Clone PyBDC repository**
39
+
40
+ git clone https://github.com/harshamarupudi56/PyBDC.git
41
+
42
+ **Run the following commands to install required dependencies**
43
+
44
+ apt-get -y install python3.11-tk
45
+ apt-get -y install pip
46
+ cd PyBDC
47
+ pip install -r requirements.txt
48
+
49
+ **The required dependencies located in requirements.txt**
50
+
51
+ customtkinter==5.2.2
52
+
53
+ matplotlib==3.8.0
54
+
55
+ numpy==1.26.0
56
+
57
+ pandas==1.3.4
58
+
59
+ **Run PyBDC**
60
+
61
+ python3 PyBDC.py
62
+
63
+
64
+ **PyBDC Team:**
65
+ Harsha Marupudi, Jospeh Manus, Bahaa Ghammraoui
66
+
67
+ **Citations:**
68
+
69
+ Sarno, A., Mettivier, G., Di Lillo, F., & Russo, P. (2017). A Monte Carlo study of monoenergetic and polyenergetic normalized glandular dose (DgN) coefficients in mammography. Physics in medicine and biology, 62(1), 306–325. https://doi.org/10.1088/1361-6560/62/1/306
70
+
71
+ Hernandez, A. M., Becker, A. E., & Boone, J. M. (2019). Updated breast CT dose coefficients (DgNCT ) using patient-derived breast shapes and heterogeneous fibroglandular distributions. Medical physics, 46(3), 1455–1466. https://doi.org/10.1002/mp.13391
72
+
73
+ Sechopoulos, I., Feng, S. S., & D'Orsi, C. J. (2010). Dosimetric characterization of a dedicated breast computed tomography clinical prototype. Medical physics, 37(8), 4110–4120. https://doi.org/10.1118/1.3457331
PyBDC/Doc/install.rst ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Installation
2
+ ==================
3
+ **Clone PyBDC repository**
4
+
5
+ .. code-block:: shell
6
+
7
+ git clone https://github.com/DIDSR/PyBDC.git
8
+
9
+ **Run the following commands to install required dependencies**
10
+
11
+ .. code-block:: shell
12
+
13
+ apt-get -y install python3.11-tk
14
+ apt-get -y install pip
15
+ cd PyBDC
16
+ pip install -r requirements.txt
17
+
18
+ **The required dependencies located in requirements.txt**
19
+
20
+ * customtkinter==5.2.2
21
+
22
+ * matplotlib==3.8.0
23
+
24
+ * numpy==1.26.0
25
+
26
+ * pandas==1.3.4
27
+
28
+
29
+ **Run PyBDC**
30
+
31
+ .. code-block:: shell
32
+
33
+ python3 PyBDC.py
PyBDC/Doc/make.bat ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ @ECHO OFF
2
+
3
+ pushd %~dp0
4
+
5
+ REM Command file for Sphinx documentation
6
+
7
+ if "%SPHINXBUILD%" == "" (
8
+ set SPHINXBUILD=sphinx-build
9
+ )
10
+ set SOURCEDIR=source
11
+ set BUILDDIR=build
12
+
13
+ if "%1" == "" goto help
14
+
15
+ %SPHINXBUILD% >NUL 2>NUL
16
+ if errorlevel 9009 (
17
+ echo.
18
+ echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
19
+ echo.installed, then set the SPHINXBUILD environment variable to point
20
+ echo.to the full path of the 'sphinx-build' executable. Alternatively you
21
+ echo.may add the Sphinx directory to PATH.
22
+ echo.
23
+ echo.If you don't have Sphinx installed, grab it from
24
+ echo.http://sphinx-doc.org/
25
+ exit /b 1
26
+ )
27
+
28
+ %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
29
+ goto end
30
+
31
+ :help
32
+ %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
33
+
34
+ :end
35
+ popd
PyBDC/Doc/methods.rst ADDED
@@ -0,0 +1,130 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Methods Overview
2
+ ==================
3
+
4
+ There are 4 methods available in PyBCD:
5
+
6
+ * Sarno 49 kVp W Spectra (Sarno Koning BCT)
7
+
8
+ * Sechopoulos 49 kVp Any Spectra (Sechopoulos Koning BCT)
9
+
10
+ * Sarno Any Specturm
11
+
12
+ * Hernandez Any Spectrum (Hernandez Heterogeneous BCT)
13
+
14
+
15
+ The Sarno Koning BCT method utilizes the Koning BCT apparatus which houses a 49 kVp W-anode with 1.40 mm Al. Other values are included because of possible variations in Al filter length. Sarno Any Spectrum on the other hand makes use of an incident X-ray spectrum input by the user. The Sarno model represents the breast as a cylinder with a homogoneous mixture of glandular and adipose tisssue. Additonally the model assumes a 1.45 mm thick skin layer and a radiation source placed 650 mm from the isocenter.
16
+
17
+ Sechopolous method also uses the Koning BCT apparatus. However, the method uses a single HVL value of 1.32 mm Al and models the breast as a semi-ellipsoid with a homogeneous mixture of adipose and glandular tissue.
18
+
19
+ The Hernandez Heterogeneous BCT method compared to the Sarno methods, models the breast as a heterogeneous mixture of adipose and glandular tissue where the individual tissues voxels are either 100% adipose or 100% glandular. The skin thickness is assumed to be 1.5 mm and the radiation source is placed 650 mm from the isocenter. Rather than being characterized by breast glandularity, this method uses volume glandular fraction or VGF for short. The heterogeneous categories, V1, V3, and V5 are characterized as follows:
20
+
21
+ V1: Volume Glandular Fraction (VGF) = 19.9%, median volume of 276 cm3, median diameter through the center of 87 mm, and median diameter at the chest wall of 103.4 mm
22
+
23
+ V3: Volume Glandular Fraction (VGF) = 9.5%, median volume of 616 cm3, median diameter through the center of 106.6 mm, and median diameter at the chest wall of 125.2 mm
24
+
25
+ V5: Volume Glandular Fraction (VGF) = 3.8%, median volume of 1174 cm3, median diameter through the center of 124.4 mm, and median diameter at the chest wall of 150.4 mm
26
+
27
+
28
+ Choosing a Method
29
+ ==================
30
+ The GUI offers three methods the user can choose from which are Sarno Koning BCT, Sarno Incident Spectrum, and Hernandez Heterogeneous BCT via radio button selection. Next to each method, a radio button can be found that if pressed selects the method. You will note that once pressed, certain buttons and parameters are activated, and others are deactivated. What is activated and deactivated is as follows:
31
+
32
+ Sarno 49 kVp W Spectra (Sarno Koning BCT)
33
+
34
+ * Activated: Breast Diameter, Breast Height, Breast Glandularity, HVL, Air Kerma, Air Kerma units, MGD units, Clear Text, and Calculate Dose
35
+
36
+ * Deactivated: Heterogeneous Categories, Input Incident Spectrum, and Graph Spectrum
37
+
38
+ * Assumptions: Cylindrical breats of homogenous composition. Skin layer of 1.45 cm. 65 cm radiation source to isocenter distance.
39
+
40
+ Sechopoulos 49 kVp Any Spectra (Sechopoulos Koning BCT)
41
+
42
+ * Activated: Breast Diameter, Breast Height, Breast Glandularity, HVL, Air Kerma, Air Kerma units, MGD units, Clear Text, and Calculate Dose
43
+
44
+ * Deactivated: Heterogeneous Categories, Input Incident Spectrum, and Graph Spectrum
45
+
46
+ * Assumptions: Semi-ellipsoidal breast of homogeneous composition. Skin layer of 1.45 mm. 65 cm radiation source to isocenter distance.
47
+
48
+ Sarno Any Specturm
49
+
50
+ * Activated: Breast Diameter, Breast Height, Breast Glandularity, Air Kerma, Air Kerma units, MGD units, Input Incident Spectrum, Graph Spectrum*, Clear Text, and Calculate Dose
51
+
52
+ * Deactivated: HVL, Heterogeneous Categories
53
+
54
+ * Assumptions: Cylindircal brast of homogenous compositon. 65 cm radiatoin source to isocenter distance.
55
+
56
+ Hernandez Any Spectrum (Hernandez Heterogeneous BCT)
57
+
58
+ * Activated: Heterogeneous Categories, Air Kerma, Air Kerma units, MGD units, Input Incident Spectrum, Graph Spectrum, Clear Text, and Calculate Dose
59
+
60
+ * Deactivated: Breast Diameter, Breast Height, Breast Glandularity, HVL
61
+
62
+ * Assumptions: Real CT breast images were grouped into three volume glandular fraction categories V1, V2, and V3. Each category of breast assumes a heterogeneous composition. Skin layer of 1.50 mm. 65 cm radiation source to isocenter distance
63
+
64
+ Graph spectrum will be activated after a valid text file is entered. If an invalid text file is entered, a popup will appear prompting you to make the necessary changes.
65
+ Program Inputs and Buttons
66
+
67
+
68
+ Program Inputs and Buttons
69
+ ==========================
70
+ Table 1 shows summarizes all the inputs into the program, the format, and the valid ranges. For the program inputs, the parameters other than BCT methods and the Air Kerma can be chosen using the downward arrow button. After clicking the downward arrow, a dropdown menu will appear where you can choose the option of your choice. The BCT method can be chosen via the radio buttons found to the left of the button and the Air Kerma can be manually entered in the box to the right of the parameter. Table 2 summarizes the different buttons and their purpose. These buttons can be simply pressed and the outlined effect in the table will occur. As mentioned above, in the Choosing a Method section, certain buttons will be active and inactive depending on the method chosen.
71
+
72
+ +---------------------------+-----------------------------------------------------+
73
+ | Parameter name | Input |
74
+ +===========================+=====================================================+
75
+ | BCT methods | Sarno Koning BCT |
76
+ | | Sarno Incident Spectrum |
77
+ | | Hernandez Heterogeneous BCT |
78
+ +---------------------------+-----------------------------------------------------+
79
+ | Breast Diameter (cm) | 8, 10, 12, 14, 16, 18 (Sarno method) |
80
+ | | 10, 12, 14, 16, 18 (Sechopoulos method) |
81
+ +---------------------------+-----------------------------------------------------+
82
+ | Breast Height | 1 x radius |
83
+ | | 1.5 x radius |
84
+ | | 2 x radius |
85
+ +---------------------------+-----------------------------------------------------+
86
+ | Breast Glandularity | 0.1%, 14.3%, 25%, 50%, 100% (Sarno method) |
87
+ | | 1%, 14.3%, 25%, 50%, 100% (Sechopoulos method) |
88
+ +---------------------------+-----------------------------------------------------+
89
+ | HVL (mm Al) | 1.25, 1.30, 1.35, 1.40, 1.45, 1.50 |
90
+ +---------------------------+-----------------------------------------------------+
91
+ | Heterogeneous Categories | V1, V3, V5 |
92
+ +---------------------------+-----------------------------------------------------+
93
+ | Air Kerma | any numerical value |
94
+ +---------------------------+-----------------------------------------------------+
95
+ | Air Kerma Units | R, mGy, mrad |
96
+ +---------------------------+-----------------------------------------------------+
97
+ | MGD Units | mGy, mrad |
98
+ +---------------------------+-----------------------------------------------------+
99
+
100
+
101
+ Table 1. Summary of parameters and their inputs.
102
+
103
+
104
+ +----------------------+------------------------------------------------------------------+
105
+ | Button | Function |
106
+ +======================+==================================================================+
107
+ | Input Incident | Opens file prompt where you select your input incident file. |
108
+ | Spectrum | The GUI will then read the input file and pull the keV and |
109
+ | | counts from the file. It further prints the shortened file onto |
110
+ | | the text box. |
111
+ +----------------------+------------------------------------------------------------------+
112
+ | Graph Spectrum | Graphs the inputted spectrum. |
113
+ +----------------------+------------------------------------------------------------------+
114
+ | Clear Text | Clears the text box. |
115
+ +----------------------+------------------------------------------------------------------+
116
+ | Calculate Dose | After filling all the necessary parameters, pressing this |
117
+ | | button will calculate and display the estimated mean glandular |
118
+ | | dose along with the selected values of the parameters. |
119
+ +----------------------+------------------------------------------------------------------+
120
+
121
+ Table 2. Summary of Buttons and their functions.
122
+
123
+ The chosen incident spectrum file must have a specific format which differs for the method chosen. This format is further elucidated in the Incident Spectrum Format section found below.
124
+
125
+ Incident Spectrum Format
126
+ ========================
127
+
128
+ First, the incident spectrum must be saved in a text file (typically a ‘.txt’ file but any text file format is accepted) and it can have any name (there is no naming convention). Next, the text file inputs must be in the form of two columns where the keV is the first column and the counts is the second column. It should be noted that keV uses a step size of 0.5. Any step size can be used. The Hernandez Heterogeneous BCT DgN coefficients are interpolated to fit any step size.
129
+
130
+ Furthermore, Sarno Incident Spectrum and Hernandez Heterogeneous BCT take different ranges of values. Sarno Incident Spectrum uses a keV range of 8-80 keV inclusive. Hernandez Heterogeneous BCT, on the other hand, uses a range of 7-90 keV inclusive.
PyBDC/Doc/requirements.txt ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ sphinx
2
+ sphinx_rtd_theme
PyBDC/Dosage_Test_Case_spectrum_55kVp2mmAl.xlsx ADDED
Binary file (9.33 kB). View file
 
PyBDC/License ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ BSD 3-Clause License
2
+
3
+ Copyright (c) 2024, Harsha Marupudi, Joseph Manus, Bahaa Ghammraoui
4
+ All rights reserved.
5
+
6
+ Redistribution and use in source and binary forms, with or without
7
+ modification, are permitted provided that the following conditions are met:
8
+
9
+ 1. Redistributions of source code must retain the above copyright notice, this
10
+ list of conditions and the following disclaimer.
11
+
12
+ 2. Redistributions in binary form must reproduce the above copyright notice,
13
+ this list of conditions and the following disclaimer in the documentation
14
+ and/or other materials provided with the distribution.
15
+
16
+ 3. Neither the name of the copyright holder nor the names of its
17
+ contributors may be used to endorse or promote products derived from
18
+ this software without specific prior written permission.
19
+
20
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
PyBDC/Paper citations.txt ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Paper citations:
2
+
3
+ Sechopoulos, I., Feng, S. S., & D'Orsi, C. J. (2010). Dosimetric characterization of a dedicated breast computed
4
+ tomography clinical prototype. Medical physics, 37(8), 4110–4120. https://doi.org/10.1118/1.3457331
5
+
6
+ Sarno, A., Mettivier, G., Tucciariello, R. M., Bliznakova, K., Boone, J. M., Sechopoulos, I., Di Lillo, F., & Russo, P. (2018).
7
+ Monte Carlo evaluation of glandular dose in cone-beam X-ray computed tomography dedicated to the breast: Homogeneous and
8
+ heterogeneous breast models. Physica medica : PM : an international journal devoted to the applications of physics to medicine
9
+ and biology : official journal of the Italian Association of Biomedical Physics (AIFB), 51, 99–107.
10
+ https://doi.org/10.1016/j.ejmp.2018.05.021
11
+
12
+ Hernandez, A. M., & Boone, J. M. (2017). Average glandular dose coefficients for pendant-geometry breast CT using
13
+ realistic breast phantoms. Medical physics, 44(10), 5096–5105. https://doi.org/10.1002/mp.12477
PyBDC/PyBDC.py ADDED
@@ -0,0 +1,859 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """
4
+ Created on Tue Feb 28 13:21:41 2023
5
+
6
+ @author: DIDSR
7
+ """
8
+
9
+ # %% import necessary modules
10
+ import argparse
11
+ from tkinter import filedialog, Menu, IntVar, W
12
+ import customtkinter
13
+ import numpy as np
14
+ from matplotlib.pyplot import (
15
+ style as plt_style,
16
+ ioff as plt_ioff,
17
+ figure as plt_figure,
18
+ rcParams as params,
19
+ )
20
+
21
+ plt_ioff() # suppress pyplot popups
22
+ from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
23
+ import tomli
24
+ from dose_equations import (
25
+ Sarno_mono_dgn,
26
+ Sarno_poly_dgn,
27
+ sarno_dgnct,
28
+ Hernandez_hetero_mono_dgn,
29
+ exposure_per_fluence,
30
+ Sechopoulos_poly_dgn,
31
+ )
32
+
33
+ # %% to set more appropriate font size for the UI (example, running from container may require UI to have larger font size)
34
+ dict_font_size_set = {1: 14, 2: 24}
35
+
36
+ font_size = None
37
+
38
+
39
+ # %% important functions
40
+ # quit me function
41
+ def quit_me():
42
+ root.quit()
43
+ root.destroy()
44
+
45
+
46
+ # calculate polyenergetic normalized glandular dose coefficients (pDgN) from specified breast models
47
+ def calculate_pDgNct(*values):
48
+ keV = values[2]
49
+ I = values[3]
50
+ psiE = np.array(list(map(exposure_per_fluence, keV)))
51
+
52
+ if values[0] == "Sarno Koning":
53
+ variables = values[1]
54
+ DgNctE = np.array(
55
+ list(
56
+ map(
57
+ sarno_dgnct,
58
+ variables[:, 0],
59
+ variables[:, 1],
60
+ variables[:, 2],
61
+ variables[:, 3],
62
+ variables[:, 4],
63
+ variables[:, 5],
64
+ variables[:, 6],
65
+ variables[:, 7],
66
+ keV,
67
+ )
68
+ )
69
+ )
70
+ pDgN = np.sum(I * psiE * DgNctE) / np.sum(I * psiE)
71
+ elif values[0] == "Hernandez":
72
+ DgN_list = np.array(values[1])
73
+ pDgN = np.sum(I * psiE * DgN_list) / (np.sum(I * psiE))
74
+
75
+ return pDgN
76
+
77
+
78
+ # read method outputs display in GUI specifications for certian methods
79
+ with open("method_specific_inputs.toml", "rb") as file_method_specific_inputs:
80
+ config_method_specific_inputs = tomli.load(file_method_specific_inputs)
81
+
82
+
83
+ # %%% Main code
84
+
85
+
86
+ class Main_Window:
87
+ # %% build the gui frames
88
+ def __init__(self, master):
89
+ self.master = master
90
+ # create the menubar
91
+ menubar = Menu(master)
92
+ root.config(menu=menubar)
93
+ helpmenu = Menu(menubar, tearoff=0)
94
+ helpmenu.add_command(label="Quick Start Guide", command=self.help_command)
95
+ menubar.add_cascade(label="Help", menu=helpmenu)
96
+ menubar.add_command(label="Exit", command=lambda: quit_me())
97
+
98
+ # create the different frames
99
+ self.methods_frame = customtkinter.CTkFrame(master=master)
100
+ self.methods_frame.grid(row=0, column=0, ipady=36)
101
+ self.inputs_frame = customtkinter.CTkFrame(master=master)
102
+ self.inputs_frame.grid(row=0, column=1, padx=10, pady=5, ipadx=6)
103
+ self.kerma_spec_frame = customtkinter.CTkFrame(master=master)
104
+ self.kerma_spec_frame.grid(row=0, column=2, pady=5, ipady=24, ipadx=4)
105
+ self.output_frame = customtkinter.CTkFrame(master=master)
106
+ self.output_frame.grid(row=1, column=0, ipady=12)
107
+ self.graph_frame = customtkinter.CTkFrame(master=master)
108
+ self.graph_frame.grid(row=1, column=1, columnspan=2, padx=4, ipady=14)
109
+ # create figure
110
+ self.keV = []
111
+ self.I = []
112
+ self.plot_spectra()
113
+
114
+ # %% add the different methods
115
+ self.method_label = customtkinter.CTkLabel(
116
+ master=self.methods_frame,
117
+ text="Choose any of the following BCT methods:",
118
+ font=("Roman", font_size),
119
+ )
120
+ self.method_chosen = IntVar(root)
121
+ self.method_chosen.set(2)
122
+ self.current_method = 1
123
+ self.Sarno_radiobutton = customtkinter.CTkRadioButton(
124
+ master=self.methods_frame,
125
+ text="Sarno 49 kVp W Spectra",
126
+ command=lambda: self.change_inputs(),
127
+ variable=self.method_chosen,
128
+ value=1,
129
+ radiobutton_width=14,
130
+ radiobutton_height=14,
131
+ font=("Roman", font_size),
132
+ )
133
+
134
+ self.Sarno_incident_radiobutton = customtkinter.CTkRadioButton(
135
+ master=self.methods_frame,
136
+ text="Sarno Any Spectrum",
137
+ command=lambda: self.change_inputs(),
138
+ variable=self.method_chosen,
139
+ value=2,
140
+ radiobutton_width=14,
141
+ radiobutton_height=14,
142
+ font=("Roman", font_size),
143
+ )
144
+
145
+ self.Hernandez_radiobutton = customtkinter.CTkRadioButton(
146
+ master=self.methods_frame,
147
+ text="Hernandez Any Spectrum",
148
+ command=lambda: self.change_inputs(),
149
+ variable=self.method_chosen,
150
+ value=3,
151
+ radiobutton_width=14,
152
+ radiobutton_height=14,
153
+ font=("Roman", font_size),
154
+ )
155
+
156
+ self.Sechopoulos_radiobutton = customtkinter.CTkRadioButton(
157
+ master=self.methods_frame,
158
+ text="Sechopoulos 49 kVp W Spectra",
159
+ command=lambda: self.change_inputs(),
160
+ variable=self.method_chosen,
161
+ value=4,
162
+ radiobutton_width=14,
163
+ radiobutton_height=14,
164
+ font=("Roman", font_size),
165
+ )
166
+
167
+ self.method_label.pack(padx=20, pady=5, anchor=W)
168
+ self.Sarno_incident_radiobutton.pack(padx=20, pady=5, anchor=W)
169
+ self.Hernandez_radiobutton.pack(padx=20, pady=5, anchor=W)
170
+ self.Sarno_radiobutton.pack(padx=20, pady=5, anchor=W)
171
+ self.Sechopoulos_radiobutton.pack(padx=20, pady=5, anchor=W)
172
+
173
+ # %% fill in the main input box
174
+ self.Breast_diameter_label = customtkinter.CTkLabel(
175
+ master=self.inputs_frame,
176
+ text="Breast Diameter (cm):",
177
+ font=("Roman", font_size),
178
+ )
179
+ self.Breast_diameter_combo = customtkinter.CTkComboBox(
180
+ master=self.inputs_frame,
181
+ values=["8", "10", "12", "14", "19", "18"],
182
+ width=120,
183
+ state="readonly",
184
+ font=("Roman", font_size),
185
+ )
186
+ self.Breast_diameter_combo.set("8")
187
+
188
+ self.Breast_height_label = customtkinter.CTkLabel(
189
+ master=self.inputs_frame, text="Breast Height:", font=("Roman", font_size)
190
+ )
191
+ self.Breast_height_combo = customtkinter.CTkComboBox(
192
+ master=self.inputs_frame,
193
+ values=["1 x radius", "1.5 x radius", "2 x radius"],
194
+ width=120,
195
+ state="readonly",
196
+ font=("Roman", font_size),
197
+ )
198
+ self.Breast_height_combo.set("1 x radius")
199
+ self.Breast_glandularity_label = customtkinter.CTkLabel(
200
+ master=self.inputs_frame,
201
+ text="Breast Glandularity:",
202
+ font=("Roman", font_size),
203
+ )
204
+ self.Breast_glandularity_combo = customtkinter.CTkComboBox(
205
+ master=self.inputs_frame,
206
+ values=["0.1%", "14.3%", "25%", "50%", "100%"],
207
+ width=120,
208
+ state="readonly",
209
+ font=("Roman", font_size),
210
+ )
211
+ self.Breast_glandularity_combo.set("0.1%")
212
+
213
+ self.HVL_label = customtkinter.CTkLabel(
214
+ master=self.inputs_frame, text="HVL (mm Al):", font=("Roman", font_size)
215
+ )
216
+ self.HVL_combo = customtkinter.CTkComboBox(
217
+ master=self.inputs_frame,
218
+ values=["1.25", "1.30", "1.35", "1.40", "1.45", "1.50"],
219
+ width=120,
220
+ state="readonly",
221
+ font=("Roman", font_size),
222
+ )
223
+ self.HVL_combo.set("1.25")
224
+
225
+ self.VGF_label = customtkinter.CTkLabel(
226
+ master=self.inputs_frame,
227
+ text="Heterogeneous Categories:",
228
+ font=("Roman", font_size),
229
+ )
230
+ self.VGF_combo = customtkinter.CTkComboBox(
231
+ master=self.inputs_frame,
232
+ values=["V1 = 19.9%", "V3 = 9.5%", "V5 = 3.8%"],
233
+ width=120,
234
+ state="readonly",
235
+ font=("Roman", font_size),
236
+ ) # V1 = 19.9%, V3 = 9.5%, V5 = 3.8%
237
+ self.VGF_combo.set("V1 = 19.9%")
238
+ self.input_spectra_button = customtkinter.CTkButton(
239
+ master=self.inputs_frame,
240
+ fg_color=("black", "lightgray"),
241
+ width=100,
242
+ border_width=0,
243
+ corner_radius=2,
244
+ text="Upload Incident Spectrum File",
245
+ font=("Roman", font_size),
246
+ command=lambda: self.browse_files(),
247
+ )
248
+ self.Breast_diameter_label.grid(row=0, column=0, pady=5, padx=4, sticky=W)
249
+ self.Breast_diameter_combo.grid(row=0, column=1, pady=5, padx=10, sticky=W)
250
+ self.Breast_height_label.grid(row=1, column=0, pady=5, padx=4, sticky=W)
251
+ self.Breast_height_combo.grid(row=1, column=1, pady=5)
252
+ self.Breast_glandularity_label.grid(row=2, column=0, pady=5, padx=4, sticky=W)
253
+ self.Breast_glandularity_combo.grid(row=2, column=1, pady=5)
254
+ self.HVL_label.grid(row=3, column=0, pady=5, padx=4, sticky=W)
255
+ self.HVL_combo.grid(row=3, column=1, pady=5)
256
+ self.HVL_combo.configure(state="disabled")
257
+ self.VGF_label.grid(row=4, column=0, pady=5, padx=4, sticky=W)
258
+ self.VGF_combo.grid(row=4, column=1, pady=5, padx=12, sticky=W)
259
+ self.VGF_combo.configure(state="disabled")
260
+ self.input_spectra_button.grid(row=5, column=0, pady=5, columnspan=2)
261
+
262
+ # %% create text box and buttons for output frame
263
+ self.output_textbox = customtkinter.CTkTextbox(
264
+ self.output_frame, width=285, height=305, font=("Roman", font_size)
265
+ )
266
+ self.output_textbox.tag_config("green", foreground="green")
267
+ self.output_textbox.configure(state="normal")
268
+ self.output_textbox.insert(
269
+ "end",
270
+ f'{"".join(config_method_specific_inputs["method_specific_inputs"]["Sarno_specific_outputs"])}',
271
+ "green",
272
+ )
273
+ self.output_textbox.configure(state="disabled")
274
+ self.clear_button = customtkinter.CTkButton(
275
+ master=self.output_frame,
276
+ width=120,
277
+ border_width=0,
278
+ corner_radius=8,
279
+ text="Clear Text",
280
+ font=("Roman", font_size),
281
+ command=lambda: self.clear_text(),
282
+ )
283
+ self.calculate_button = customtkinter.CTkButton(
284
+ master=self.output_frame,
285
+ width=120,
286
+ border_width=0,
287
+ corner_radius=8,
288
+ text="Calculate Dose",
289
+ font=("Roman", font_size),
290
+ command=lambda: self.calculate_dose(),
291
+ )
292
+
293
+ self.clear_button.grid(row=1, column=0, pady=5, padx=4)
294
+ self.output_textbox.grid(row=0, column=0, columnspan=3)
295
+ self.output_textbox.configure(state="disabled") # insert at line 0 character 0
296
+ self.calculate_button.grid(row=1, column=1, pady=5, padx=4)
297
+
298
+ # %% create air kerma inputs
299
+
300
+ self.mAs_label = customtkinter.CTkLabel(
301
+ master=self.kerma_spec_frame,
302
+ text="mAs per Projection:",
303
+ font=("Roman", font_size),
304
+ )
305
+ self.mAs_entry = customtkinter.CTkEntry(master=self.kerma_spec_frame, width=80)
306
+ self.mAs_units_combo = customtkinter.CTkComboBox(
307
+ master=self.kerma_spec_frame,
308
+ values=["mAs"],
309
+ width=80,
310
+ state="readonly",
311
+ font=("Roman", font_size),
312
+ )
313
+
314
+ self.air_kerma_label = customtkinter.CTkLabel(
315
+ master=self.kerma_spec_frame,
316
+ text="Air kerma per Projection:",
317
+ font=("Roman", font_size),
318
+ )
319
+ self.air_kerma_entry = customtkinter.CTkEntry(
320
+ master=self.kerma_spec_frame, width=80
321
+ )
322
+ self.input_label = customtkinter.CTkLabel(
323
+ master=self.kerma_spec_frame,
324
+ text="Air kerma Units:",
325
+ font=("Roman", font_size),
326
+ )
327
+ self.air_kerma_units_combo = customtkinter.CTkComboBox(
328
+ master=self.kerma_spec_frame,
329
+ values=["mrad", "mGy", "R", "mR"],
330
+ width=80,
331
+ state="readonly",
332
+ font=("Roman", font_size),
333
+ )
334
+ self.air_kerma_units_combo.set("R")
335
+ self.air_kerma_output_label = customtkinter.CTkLabel(
336
+ master=self.kerma_spec_frame,
337
+ text="MGD Units:",
338
+ anchor=W,
339
+ font=("Roman", font_size),
340
+ )
341
+ self.output_units = customtkinter.CTkComboBox(
342
+ master=self.kerma_spec_frame,
343
+ values=["mrad", "mGy"],
344
+ width=80,
345
+ state="readonly",
346
+ font=("Roman", font_size),
347
+ )
348
+ self.output_units.set("mrad")
349
+
350
+ self.number_projections_label = customtkinter.CTkLabel(
351
+ master=self.kerma_spec_frame,
352
+ text="Number of Projections: ",
353
+ font=("Roman", font_size),
354
+ )
355
+ self.number_projections_entry = customtkinter.CTkEntry(
356
+ master=self.kerma_spec_frame, width=80
357
+ )
358
+
359
+ self.graph_spectra = customtkinter.CTkButton(
360
+ master=self.kerma_spec_frame,
361
+ width=220,
362
+ border_width=1,
363
+ corner_radius=10,
364
+ text="Graph Spectrum",
365
+ font=("Roman", font_size),
366
+ command=self.plot_spectra,
367
+ )
368
+
369
+ self.air_kerma_label.grid(row=1, column=0, pady=5, padx=4, sticky=W)
370
+ self.air_kerma_entry.grid(row=1, column=1, pady=5, padx=12, sticky=W)
371
+ self.number_projections_label.grid(row=2, column=0, pady=5, padx=4, sticky=W)
372
+ self.number_projections_entry.grid(row=2, column=1, pady=5, padx=12, sticky=W)
373
+ self.mAs_label.grid(row=5, column=0, pady=5, padx=4, sticky=W)
374
+ self.mAs_entry.grid(row=5, column=1, pady=5, padx=12, sticky=W)
375
+ self.input_label.grid(row=3, column=0, pady=5, padx=4, sticky=W)
376
+ self.air_kerma_units_combo.grid(row=3, column=1, pady=5, padx=12, sticky=W)
377
+ self.air_kerma_output_label.grid(row=4, column=0, pady=5, padx=4, sticky=W)
378
+ self.output_units.grid(row=4, column=1, pady=5, padx=12, sticky=W)
379
+ self.graph_spectra.grid(row=6, column=0, pady=5, columnspan=2)
380
+ self.graph_spectra.configure(state="disabled")
381
+
382
+ # %% important functions
383
+ # add help command
384
+ def help_command(self):
385
+ pop_up = customtkinter.CTkToplevel()
386
+ textbox = customtkinter.CTkTextbox(master=pop_up, width=800, height=500)
387
+ textbox.pack(fill="both")
388
+
389
+ with open("CT_Dose_Calculate_Quick_Guide.txt", "r") as file:
390
+ data = file.read()
391
+
392
+ textbox.insert("end", f"{data}")
393
+ textbox.configure(state="disabled")
394
+
395
+ # change the method specific inputs based on selection
396
+ def change_inputs(self):
397
+ current_method = self.method_chosen.get()
398
+
399
+ if current_method == 1: # Sarno 49 kVp W Spectra
400
+ # enable and disable buttons
401
+ self.VGF_combo.configure(state="disabled")
402
+ self.input_spectra_button.configure(state="disabled")
403
+ self.Breast_diameter_combo.configure(state="normal")
404
+ self.Breast_height_combo.configure(state="normal")
405
+ self.Breast_glandularity_combo.configure(state="normal")
406
+ self.HVL_combo.configure(state="normal")
407
+ self.graph_spectra.configure(state="disabled")
408
+ self.Breast_glandularity_combo.configure(
409
+ values=["0.1%", "14.3%", "25%", "50%", "75%", "100%"]
410
+ )
411
+ self.Breast_glandularity_combo.set("0.1%")
412
+ self.Breast_diameter_combo.configure(
413
+ values=["8", "10", "12", "14", "19", "18"]
414
+ )
415
+ self.Breast_diameter_combo.set("8")
416
+ self.Breast_height_combo.configure(
417
+ values=["1 x radius", "1.5 x radius", "2 x radius"]
418
+ )
419
+ self.Breast_height_combo.set("1 x radius")
420
+ self.output_textbox.configure(state="normal")
421
+ self.output_textbox.delete("0.0", "end")
422
+ self.output_textbox.configure(state="normal")
423
+ self.output_textbox.insert(
424
+ "end",
425
+ f'{"".join(config_method_specific_inputs["method_specific_inputs"]["Sarno_49_specific_output"])}',
426
+ "green",
427
+ )
428
+ self.output_textbox.configure(state="disabled")
429
+ self.keV = []
430
+ self.I = []
431
+ self.plot_spectra()
432
+
433
+ elif current_method == 2: # Sarno any spectrum
434
+ self.VGF_combo.configure(state="disabled")
435
+ self.input_spectra_button.configure(state="normal")
436
+ self.Breast_diameter_combo.configure(state="normal")
437
+ self.Breast_height_combo.configure(state="normal")
438
+ self.Breast_glandularity_combo.configure(state="normal")
439
+ self.HVL_combo.configure(state="disabled")
440
+ self.graph_spectra.configure(state="disabled")
441
+ self.Breast_glandularity_combo.configure(
442
+ values=["0.1%", "14.3%", "25%", "50%", "75%", "100%"]
443
+ )
444
+ self.Breast_glandularity_combo.set("0.1%")
445
+ self.Breast_diameter_combo.configure(
446
+ values=["8", "10", "12", "14", "19", "18"]
447
+ )
448
+ self.Breast_diameter_combo.set("8")
449
+ self.Breast_height_combo.configure(
450
+ values=["1 x radius", "1.5 x radius", "2 x radius"]
451
+ )
452
+ self.Breast_height_combo.set("1 x radius")
453
+ self.output_textbox.configure(state="normal")
454
+ self.output_textbox.delete("0.0", "end")
455
+ self.output_textbox.insert(
456
+ "end",
457
+ f'{"".join(config_method_specific_inputs["method_specific_inputs"]["Sarno_specific_outputs"])}',
458
+ "green",
459
+ )
460
+ self.output_textbox.configure(state="disabled")
461
+ self.keV = []
462
+ self.I = []
463
+ self.plot_spectra()
464
+
465
+ elif current_method == 3: # Hernandez any spectrum
466
+ self.VGF_combo.configure(state="normal")
467
+ self.input_spectra_button.configure(state="normal")
468
+ self.Breast_diameter_combo.configure(state="disabled")
469
+ self.Breast_height_combo.configure(state="disabled")
470
+ self.Breast_glandularity_combo.configure(state="disabled")
471
+ self.HVL_combo.configure(state="disabled")
472
+ self.graph_spectra.configure(state="disabled")
473
+ self.output_textbox.configure(state="normal")
474
+ self.output_textbox.delete("0.0", "end")
475
+ self.output_textbox.insert(
476
+ "end",
477
+ f'{"".join(config_method_specific_inputs["method_specific_inputs"]["Hernandez_specific_output"])}',
478
+ "green",
479
+ )
480
+ self.output_textbox.configure(state="disabled")
481
+ self.keV = []
482
+ self.I = []
483
+ self.plot_spectra()
484
+
485
+ else: # Sechopoulus method
486
+ self.VGF_combo.configure(state="disabled")
487
+ self.input_spectra_button.configure(state="disabled")
488
+ self.Breast_diameter_combo.configure(state="normal")
489
+ self.Breast_height_combo.configure(state="normal")
490
+ self.Breast_glandularity_combo.configure(state="normal")
491
+ self.HVL_combo.configure(state="disabled")
492
+ self.graph_spectra.configure(state="disabled")
493
+ self.output_textbox.configure(state="normal")
494
+ self.output_textbox.delete("0.0", "end")
495
+ self.output_textbox.insert(
496
+ "end",
497
+ f'{"".join(config_method_specific_inputs["method_specific_inputs"]["Sechopoulos_specific_output"])}',
498
+ "green",
499
+ )
500
+ self.output_textbox.configure(state="disabled")
501
+ self.Breast_glandularity_combo.configure(
502
+ values=["1%", "14.3%", "25%", "50%", "75%", "100%"]
503
+ )
504
+ self.Breast_glandularity_combo.set("1%")
505
+ self.Breast_diameter_combo.configure(values=["10", "12", "14", "19", "18"])
506
+ self.Breast_diameter_combo.set("10")
507
+ self.Breast_height_combo.configure(
508
+ values=["0.5 x diameter", "0.75 x diameter", "1 x diameter"]
509
+ )
510
+ self.Breast_height_combo.set("0.5 x diameter")
511
+ self.keV = []
512
+ self.I = []
513
+ self.plot_spectra()
514
+
515
+ # browse for incident spectrum
516
+ def browse_files(self):
517
+ # read and output textfile
518
+ self.input_txt_file = filedialog.askopenfilename(
519
+ initialdir="/", title="Select a File", filetypes=[("all files", "*.*")]
520
+ )
521
+ self.display_txt_file = self.input_txt_file.split("/")[-1]
522
+ self.output_textbox.configure(state="normal")
523
+ self.output_textbox.insert(
524
+ "end", f"\nInputted incident spectrum: \n{self.display_txt_file}", "\n"
525
+ )
526
+ self.output_textbox.configure(state="disabled")
527
+
528
+ try:
529
+ # get keV and I
530
+ self.keV, self.I = self.read_input_spectra()
531
+ self.minimum = min(self.keV)
532
+ self.maximum = max(self.keV)
533
+ method = self.method_chosen.get()
534
+
535
+ if method == 3:
536
+ if self.minimum < 9 or self.maximum > 70:
537
+ raise (ValueError)
538
+ elif method == 2:
539
+ if self.minimum < 8 or self.maximum > 80:
540
+ raise (ValueError)
541
+
542
+ self.graph_spectra.configure(state="normal")
543
+
544
+ # account for possible errors
545
+ except UnicodeDecodeError:
546
+ pop_up = customtkinter.CTkToplevel()
547
+ customtkinter.CTkLabel(
548
+ pop_up, text="Please enter a valid text file", font=("Roman", font_size)
549
+ ).pack()
550
+
551
+ except ValueError:
552
+ pop_up = customtkinter.CTkToplevel()
553
+ customtkinter.CTkLabel(
554
+ pop_up,
555
+ text="For Hernadez Any spectrum, please enter spectrum ranging from 9 to 70 keV",
556
+ font=("Roman", font_size),
557
+ ).pack()
558
+ customtkinter.CTkLabel(
559
+ pop_up,
560
+ text="For Sarno Any Spectrum, please enter spectrum ranging from 8 to 80 keV",
561
+ font=("Roman", font_size),
562
+ ).pack()
563
+
564
+ # read input spectra
565
+ def read_input_spectra(self):
566
+ with open(self.input_txt_file, "r") as file:
567
+ keV = []
568
+ I = []
569
+ data = file.readlines()
570
+ for line in data:
571
+ line = line.split()
572
+ keV.append(float(line[0]))
573
+ I.append(float(line[1]))
574
+
575
+ return keV, I
576
+
577
+ # clear text
578
+ def clear_text(self):
579
+ self.output_textbox.configure(state="normal")
580
+ self.output_textbox.delete("0.0", "end")
581
+ self.output_textbox.configure(state="disabled")
582
+
583
+ # update plot
584
+ def plot_spectra(self):
585
+ try:
586
+ y_end = max(self.I) * 1.1
587
+ x_end = max(self.keV) * 1.1
588
+ file_name = self.display_txt_file
589
+ except:
590
+ x_end = 5
591
+ y_end = 5
592
+ file_name = "Input Incident Spectrum"
593
+
594
+ plt_style.use(["dark_background"])
595
+ params["figure.figsize"] = [7.50, 3.50]
596
+ params["figure.autolayout"] = True
597
+ self.figure = plt_figure(figsize=(7.6, 4.2), dpi=100)
598
+ axes = self.figure.add_subplot(111)
599
+ axes.plot(self.keV, self.I, "b-")
600
+ axes.set_title(f"{file_name}")
601
+ axes.set_xlabel("Energy (keV)", fontsize=11)
602
+ axes.set_ylabel("Intensity (counts)", fontsize=11)
603
+ axes.set_xlim(0, x_end)
604
+ axes.set_ylim([0, y_end])
605
+ chart = FigureCanvasTkAgg(self.figure, master=self.graph_frame)
606
+ chart.get_tk_widget().grid(row=0, column=0, columnspan=2)
607
+
608
+ # calculate mean glandur dosage from user specificed inputs
609
+ def calculate_mgd(
610
+ self, air_kerma_input, air_kerma, dgn, output_units, number_of_projections
611
+ ):
612
+ # unit conversions based on user selection
613
+ if air_kerma_input != "mGy":
614
+ if air_kerma_input == "mrad":
615
+ air_kerma = air_kerma * 0.01 # convert from mrad air kerma to mGy
616
+ elif air_kerma_input == "R":
617
+ air_kerma = air_kerma * 8.77 # convert from R to mGy
618
+ elif air_kerma_input == "mR":
619
+ air_kerma = air_kerma * 0.00877 # convert from mR to mGy
620
+
621
+ mgd = air_kerma * dgn * float(number_of_projections) # in mGy/mGy
622
+
623
+ if output_units == "mrad":
624
+ mgd = mgd * 100 # converts mgd to mrad
625
+
626
+ return mgd
627
+
628
+ # write inputs to textbox
629
+ def output_dose(self, *values):
630
+ self.output_textbox.configure(state="normal")
631
+ self.output_textbox.insert(
632
+ "end", f"\n\nMGD = {self.mgd:.4f} {self.output_units.get()}"
633
+ )
634
+ self.output_textbox.insert(
635
+ "end", f" with {self.number_projections_entry.get()} projections"
636
+ )
637
+ self.output_textbox.insert("end", f" with {self.mAs_entry.get()} mAs")
638
+
639
+ for index in range(len(values)):
640
+ if index == 0 or index % 2 == 0:
641
+ self.output_textbox.insert("end", f"\n{values[index]}")
642
+ else:
643
+ self.output_textbox.insert("end", f"{values[index]}")
644
+
645
+ self.output_textbox.configure(state="disabled")
646
+
647
+ # function to calculate dose
648
+ def calculate_dose(self):
649
+ # get inputs
650
+ current_method = self.method_chosen.get()
651
+ air_kerma_input_units = self.air_kerma_units_combo.get()
652
+ output_units = self.output_units.get()
653
+ air_kerma = self.air_kerma_entry.get()
654
+ number_of_projections = self.number_projections_entry.get()
655
+
656
+ try:
657
+ # numbers only
658
+ air_kerma_check = len(air_kerma)
659
+ number_of_projections_check = len(number_of_projections)
660
+ air_kerma = float(air_kerma) # check if only numbers
661
+ mAs_per_projection = float(self.mAs_entry.get())
662
+ air_kerma = mAs_per_projection * air_kerma
663
+
664
+ if air_kerma_check == 0 or number_of_projections_check == 0:
665
+ raise (ValueError)
666
+
667
+ elif current_method == 2 or current_method == 3:
668
+ kev_check = len(self.keV)
669
+ if kev_check == 0:
670
+ raise (TypeError)
671
+
672
+ # calculate mgd based on specified model
673
+ if current_method == 1: # Sarno 49 kVp W spectra
674
+ # get parameters
675
+ HVL = self.HVL_combo.get()
676
+ breast_diameter = self.Breast_diameter_combo.get()
677
+ breast_glandularity = self.Breast_glandularity_combo.get()
678
+ breast_height = "".join(self.Breast_height_combo.get().split(" ")[0:2])
679
+
680
+ # calculate polyenergetic dgn coefficients
681
+ dgn_subtable_breast_height = Sarno_poly_dgn.groupby(
682
+ ["breast height"]
683
+ ).get_group(breast_height)
684
+ dgn_subtable_glandularity = dgn_subtable_breast_height.groupby(
685
+ ["Glandularity"]
686
+ ).get_group(breast_glandularity)
687
+ dgn = dgn_subtable_glandularity.loc[float(HVL), str(breast_diameter)]
688
+
689
+ # calculate mgd based on pdgn and input parameters
690
+ self.mgd = self.calculate_mgd(
691
+ air_kerma_input_units,
692
+ air_kerma,
693
+ dgn,
694
+ output_units,
695
+ number_of_projections,
696
+ )
697
+
698
+ self.output_dose(
699
+ "Breast diameter: ",
700
+ breast_diameter,
701
+ "HVL: ",
702
+ HVL,
703
+ "Breast_glandularity: ",
704
+ breast_glandularity,
705
+ "Breast Height: ",
706
+ self.Breast_height_combo.get(),
707
+ )
708
+
709
+ elif current_method == 2: # Sarno any spectrum
710
+ breast_diameter = self.Breast_diameter_combo.get()
711
+ breast_glandularity = self.Breast_glandularity_combo.get()
712
+ breast_height = "".join(self.Breast_height_combo.get().split(" ")[0:2])
713
+
714
+ # get dgn coefficients
715
+ dgn_subtable_breast_height = Sarno_mono_dgn.groupby(
716
+ ["breast height"]
717
+ ).get_group(breast_height)
718
+ dgn_subtable_glandularity = dgn_subtable_breast_height.groupby(
719
+ ["Glandularity"]
720
+ ).get_group(breast_glandularity)
721
+ values = dgn_subtable_glandularity[str(breast_diameter)].tolist()
722
+ variables = np.zeros((len(self.keV), len(values)))
723
+
724
+ for index in range(0, len(values)):
725
+ variables[:, index] = [float(values[index])] # *len(self.keV)
726
+
727
+ # calulate dgn
728
+ dgn = calculate_pDgNct(
729
+ "Sarno Koning", variables, self.keV, self.I
730
+ ) # units of mGy/mGy
731
+
732
+ self.mgd = self.calculate_mgd(
733
+ air_kerma_input_units,
734
+ air_kerma,
735
+ dgn,
736
+ output_units,
737
+ number_of_projections,
738
+ )
739
+
740
+ self.output_dose(
741
+ "Breast diameter: ",
742
+ breast_diameter,
743
+ "Breast Glandularity: ",
744
+ breast_glandularity,
745
+ "Breast Height: ",
746
+ self.Breast_height_combo.get(),
747
+ )
748
+
749
+ elif current_method == 3: # Hernandez any spectrum
750
+ # get the VGF and DgN list from text file
751
+ VGF = self.VGF_combo.get().split("=")[0].strip()
752
+ DgN_list = Hernandez_hetero_mono_dgn.loc[:, VGF].tolist()
753
+
754
+ # index the list to fit keV
755
+ start_index = int(abs(self.minimum - 9))
756
+ if self.maximum != 70:
757
+ end_index = int(abs(self.maximum - 9)) + 1
758
+ else:
759
+ end_index = -1
760
+
761
+ # interpolate the DgN list if necessary
762
+ Hernandez_keV = list(np.arange(self.minimum, self.maximum + 1))
763
+ DgN_list = DgN_list[start_index:end_index]
764
+ interp_DgN_list = np.interp(self.keV, Hernandez_keV, DgN_list)
765
+
766
+ # get the DgN coefficients in mGy/mGy
767
+ dgn = calculate_pDgNct("Hernandez", interp_DgN_list, self.keV, self.I)
768
+
769
+ print(dgn)
770
+
771
+ # print(dgn)
772
+ self.mgd = self.calculate_mgd(
773
+ air_kerma_input_units,
774
+ air_kerma,
775
+ dgn,
776
+ output_units,
777
+ number_of_projections,
778
+ )
779
+
780
+ self.output_dose("VGF: ", self.VGF_combo.get())
781
+
782
+ else: # Sechopoulos method
783
+ # get parameters
784
+ breast_diameter = self.Breast_diameter_combo.get()
785
+ breast_glandularity = self.Breast_glandularity_combo.get()
786
+ breast_height = float(
787
+ self.Breast_height_combo.get().split("x")[0]
788
+ ) * float(breast_diameter)
789
+
790
+ # calculate dgn for polyenergetic
791
+ dgn_subtable_breast_height = Sechopoulos_poly_dgn.groupby(
792
+ ["Chest wall-to-nipple distance"]
793
+ ).get_group(breast_height)
794
+ dgn = dgn_subtable_breast_height[breast_glandularity].tolist()[0]
795
+
796
+ # calculate mgd
797
+ self.mgd = self.calculate_mgd(
798
+ air_kerma_input_units,
799
+ air_kerma,
800
+ dgn,
801
+ output_units,
802
+ number_of_projections,
803
+ )
804
+
805
+ self.output_dose(
806
+ "Breast diameter: ",
807
+ breast_diameter,
808
+ "Breast_glandularity: ",
809
+ breast_glandularity,
810
+ "Breast Height: ",
811
+ self.Breast_height_combo.get(),
812
+ )
813
+
814
+ except ValueError: # error in air kerma inputs
815
+ pop_up = customtkinter.CTkToplevel()
816
+
817
+ if air_kerma_check == 0:
818
+ customtkinter.CTkLabel(
819
+ pop_up,
820
+ text="Please enter a numeric value into the air kerma entry box or into \nthe number of projections box",
821
+ font=("Roman", font_size),
822
+ ).pack()
823
+
824
+ else:
825
+ customtkinter.CTkLabel(
826
+ pop_up,
827
+ text="Please enter only numbers into the air kerma and ensure \nthat a numeric value is placed into the number of projections",
828
+ font=("Roman", font_size),
829
+ ).pack()
830
+
831
+ except TypeError: # error in incident spectrum
832
+ pop_up = customtkinter.CTkToplevel()
833
+
834
+ customtkinter.CTkLabel(
835
+ pop_up,
836
+ text="Please enter an incident spectrum",
837
+ font=("Roman", font_size),
838
+ ).pack()
839
+
840
+
841
+ # %%% Executable Code
842
+ parser = argparse.ArgumentParser()
843
+ parser.add_argument(
844
+ "--font_size_set",
845
+ nargs="?",
846
+ default=1,
847
+ type=int,
848
+ help="select the font size set (default=1 is the first set)",
849
+ )
850
+ args = parser.parse_args()
851
+ font_size = dict_font_size_set[args.font_size_set]
852
+ font_size = dict_font_size_set[args.font_size_set]
853
+
854
+ customtkinter.set_appearance_mode("light")
855
+ root = customtkinter.CTk()
856
+ root.title("BCT Dose Calculator")
857
+ CT_dose = Main_Window(root)
858
+ root.protocol("WM_DELETE_WINDOW", quit_me)
859
+ root.mainloop()
PyBDC/README.md ADDED
@@ -0,0 +1,56 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Python Breast Dosage Calculator: PyBDC
2
+ Python toolkit for calculating dosage for breast CT.\
3
+ The following software enables accurate dose estimation for one or various breast exposures specifically for breast CT. This tool is a GUI software that can be used on Windows, Mac, and Linux operating systems. The mode is further explained below along with an overview of the methods, how to choose a method, the program inputs and buttons, the incident spectrum format, images of the GUI, and the accompanying data files.
4
+
5
+ Code execution
6
+ ----------
7
+ Clone PyBDC repository.
8
+ ```
9
+ git clone https://github.com/harshamarupudi56/PyBDC.git
10
+ ```
11
+
12
+ Run the following commands to install required dependencies.
13
+ ```
14
+ apt-get -y install python3.11-tk
15
+ apt-get -y install pip
16
+ cd PyBDC
17
+ pip install -r requirements.txt
18
+ ```
19
+
20
+ The required dependencies in [requirements.txt](requirements.txt).
21
+ ```
22
+ customtkinter==5.2.2
23
+ matplotlib==3.8.0
24
+ numpy==1.26.0
25
+ pandas==1.3.4
26
+ ```
27
+
28
+ Run PyBDC.
29
+ ```
30
+ python3 PyBDC.py
31
+ ```
32
+
33
+ PyBDC can also be run through its container available at https://huggingface.co/didsr/PyBDC-Container
34
+
35
+ User guide
36
+ ----------
37
+ Please refer to the technical documentation https://pybdc.readthedocs.io/en/latest/
38
+
39
+ Disclaimer
40
+ ----------
41
+
42
+ This software and documentation was developed at the Food and Drug Administration (FDA) by employees of the Federal Government in the course of their official duties. Pursuant to Title 17, Section 105 of the United States Code, this work is not subject to copyright protection and is in the public domain. Permission is hereby granted, free of charge, to any person obtaining a copy of the Software, to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, or sell copies of the Software or derivatives, and to permit persons to whom the Software is furnished to do so. FDA assumes no responsibility whatsoever for use by other parties of the Software, its source code, documentation or compiled executables, and makes no guarantees, expressed or implied, about its quality, reliability, or any other characteristic. Further, use of this code in no way implies endorsement by the FDA or confers any advantage in regulatory decisions. Although this software can be redistributed and/or modified freely, we ask that any derivative works bear some notice that they are derived from it, and any modified versions bear some notice that they have been modified.
43
+
44
+
45
+ PyBDC: Harsha Marupudi, M.Eng., Joseph Manus B.S., Bahaa Ghammraoui, Ph.D. US Food and Drug Administration, Center for Devices and Radiological Health, Office of Science and Engineering Labs, Division of Imaging, Diagnostics, and Software Reliability.
46
+
47
+
48
+
49
+
50
+ References
51
+ ----------
52
+ 1. Sarno, A., Mettivier, G., Di Lillo, F., & Russo, P. (2017). A Monte Carlo study of monoenergetic and polyenergetic normalized glandular dose (DgN) coefficients in mammography. Physics in medicine and biology, 62(1), 306–325. https://doi.org/10.1088/1361-6560/62/1/306
53
+ 2. Hernandez, A. M., Becker, A. E., & Boone, J. M. (2019). Updated breast CT dose coefficients (DgNCT ) using patient-derived breast shapes and heterogeneous fibroglandular distributions. Medical physics, 46(3), 1455–1466. https://doi.org/10.1002/mp.13391
54
+ 3. Sechopoulos, I., Feng, S. S., & D'Orsi, C. J. (2010). Dosimetric characterization of a dedicated breast computed tomography clinical prototype. Medical physics, 37(8), 4110–4120. https://doi.org/10.1118/1.3457331
55
+
56
+
PyBDC/User_Guide.md ADDED
@@ -0,0 +1,57 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Quick Start Guide for PyBDC 1.0
2
+
3
+ 1. To begin start by choosing a method: Sarno Koning, Sarno Incident Spectrum, or Hernandez Heterogeneous BCT
4
+
5
+ 1. Each method can be selected by selecting the radio button next to the method
6
+
7
+ 1. the default is Sarno Incident Spectrum
8
+
9
+ 2. Selecting the Sarno Koning BCT will lead to an output in the text box stating a description of Koning
10
+ BCT apparatus
11
+
12
+ 3. Selecting the Hernandez Heterogeneous BCT method will lead to the text box on the bottom corner being
13
+ filled with the a description for each of the heterogeneous categories
14
+
15
+ 2. After selecting a method, choose your parameters in the box next over
16
+
17
+ 1. Sample parameters include breast diameter, breast height, etc.
18
+
19
+ 2. Simply click on the downward arrow and choose the parameter of your choice
20
+
21
+ 3. You'll notice some parameters are deactivated and this is due to the method of your choice. Each method
22
+ uses different sets of parameters. As such, the parameters necessary for the method will remain active
23
+ and those not necessary will remain inactive
24
+
25
+ 3. After choosing parameters, enter your Air Kerma along with the input units and the desired output units. Air kerma is defined as the amount of energy deposited into the air when a photon passes through it. The number of projections should also
26
+ be added. This is defined as the number of individual X-ray measurements taken during the initial scan.
27
+
28
+ 1. Simply enter your Air Kerma into the Air Kerma box and like before choose the input units in Air Kerma
29
+ Units and output units via MGD Units by pressing the downward arrow
30
+
31
+ 4. Depending on the method of your choice, you will have the option to input an incident spectrum and graph that
32
+ spectrum
33
+
34
+ 1. If you have chosen either Sarno Incident Spectrum or Hernandez Heterogeneous BCT, the option the input an
35
+ incident spectrum will be available to you.
36
+
37
+ 1. This is not optional; you must enter an incident spectrum for the method to work
38
+
39
+ 2. Simply press the Input Incident Spectrum Button and a popup will appear prompting you to choose a file.
40
+ Please select an appropriate text file following the format outlined in the complete user guide.
41
+
42
+ 1. Once an acceptable file has been chosen, a shortened file name will appear in the text box found on
43
+ the bottom left
44
+
45
+ 3. After inputting the file, the Graph Spectrum button will activate. You can then press the Graph Spectrum
46
+ button which will display your incident spectrum on the graph
47
+
48
+ 5. Once you are satisfied with all your inputs, you can press the Calculate Dose button found at the bottom left corner
49
+ next to the Clear Text button
50
+
51
+ 1. Pressing the Calculate Dose button will lead to an output in the text box of your mean glandular dose value
52
+ and your chosen parameters.
53
+
54
+ 2. The text will remain in the box unless you elect to clear the box. The box can be easily cleared by pressing
55
+ the Clear Text button. Do note that your previous values will be cleared and cannot be retrieved.
56
+
57
+ 6. [method_specific_inputs.toml](method_specific_inputs.toml) has method specific outputs given assumptions of homogenous or heterogenous composition
PyBDC/Verification.py ADDED
@@ -0,0 +1,168 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+
4
+ """
5
+ Verification code using Sarno any spectrum for a breast with a diamter 16 cm, radius of 2xradius, and glandularity of 50%. Using the defined keV, I, and coefficients the normalized glandular dose can be computed. The correct value for these parameters
6
+ is 0.03614995451146596. The mean glandular dose was computed using the parameters of 300 projections, 0.5 mAs, and an input air kerma of 5 mR.
7
+
8
+ """
9
+
10
+ import sys
11
+ import numpy as np
12
+ from dose_equations import (
13
+ Sarno_mono_dgn,
14
+ Sarno_poly_dgn,
15
+ sarno_dgnct,
16
+ Hernandez_hetero_mono_dgn,
17
+ exposure_per_fluence,
18
+ Sechopoulos_poly_dgn,
19
+ )
20
+
21
+
22
+ def exposure_per_fluence(E):
23
+ exposure = np.zeros(len(E))
24
+ for i in range(len(exposure)):
25
+ keV = E[i]
26
+ temp = (
27
+ (
28
+ (
29
+ -5.023290717769674e-6
30
+ + 1.810595449064631e-7
31
+ + np.sqrt(keV)
32
+ + np.log(keV)
33
+ + 0.008838658459816926 / keV**2
34
+ )
35
+ ** (10**-3)
36
+ )
37
+ / 1000
38
+ * 0.1145
39
+ )
40
+ exposure[i] = temp
41
+ return exposure
42
+
43
+
44
+ def dgn_calculate(a, b, c, d, e, f, g, h, keVs):
45
+ dgn = np.zeros(len(keVs))
46
+ for i in range(len(keVs)):
47
+ E = keVs[i]
48
+ temp = (
49
+ a * 10 ** (-14) * E**8
50
+ + b * 10 ** (-12) * E**7
51
+ + c * 10 ** (-10) * E**6
52
+ + d * 10 ** (-8) * E**5
53
+ + e * 10 ** (-6) * E**4
54
+ + f * 10 ** (-4) * E**3
55
+ + g * 10 ** (-3) * E**2
56
+ + h * 10 ** (-2) * E
57
+ )
58
+ dgn[i] = temp
59
+ return dgn
60
+
61
+
62
+ def pDgN_calculate_denominator(I, exposure):
63
+ total = I * exposure
64
+ pDgN_denom = np.sum(total)
65
+
66
+ return pDgN_denom
67
+
68
+
69
+ def pDgN_calculate_numerator(I, dgn, exposure):
70
+ total = I * exposure * dgn
71
+ pDgN_num = sum(total)
72
+ return pDgN_num
73
+
74
+
75
+ def calculate_pDgNct(*values):
76
+ keV = values[2]
77
+ I = values[3]
78
+ psiE = np.array(list(map(exposure_per_fluence, keV)))
79
+
80
+ if values[0] == "Sarno Koning":
81
+ variables = values[1]
82
+ DgNctE = np.array(
83
+ list(
84
+ map(
85
+ sarno_dgnct,
86
+ variables[:, 0],
87
+ variables[:, 1],
88
+ variables[:, 2],
89
+ variables[:, 3],
90
+ variables[:, 4],
91
+ variables[:, 5],
92
+ variables[:, 6],
93
+ variables[:, 7],
94
+ keV,
95
+ )
96
+ )
97
+ )
98
+ pDgN = np.sum(I * psiE * DgNctE) / np.sum(I * psiE)
99
+ elif values[0] == "Hernandez":
100
+ DgN_list = np.array(values[1])
101
+ pDgN = np.sum(I * psiE * DgN_list) / (np.sum(I * psiE))
102
+
103
+ return pDgN
104
+
105
+
106
+ # calculate mgd input air kerma for 1 projection
107
+ def calculate_mgd(
108
+ air_KERMA, dgn, number_of_projections, mAs, air_KERMA_input_units, output_units
109
+ ):
110
+ # Convert air kerma input to mGy if it is not already in mGy
111
+ if air_KERMA_input_units != "mGy":
112
+ if air_KERMA_input_units == "mrad":
113
+ air_KERMA = air_KERMA * 0.01 # convert from mrad air kerma to mGy
114
+ elif air_KERMA_input_units == "R":
115
+ air_KERMA = air_KERMA * 8.77 # convert from R to mGy
116
+ elif air_KERMA_input_units == "mR":
117
+ air_KERMA = air_KERMA * 0.00877 # convert from mR to mGy
118
+
119
+ # Calculate MGD in mGy/mGy
120
+ mgd = air_KERMA * dgn * float(number_of_projections) * mAs
121
+
122
+ # Convert MGD to mrad if output units are mrad
123
+ if output_units == "mrad":
124
+ mgd = mgd * 100 # converts mgd to mrad
125
+
126
+ return mgd
127
+
128
+
129
+ a = -0.41324119391158
130
+ b = 4.88540710576677
131
+ c = -13.0460380815292
132
+ d = 15.3913804609064
133
+ e = -9.19621868949206
134
+ f = 2.66123817129083
135
+ g = -2.67974610124986
136
+ h = 0.883219836298924
137
+
138
+ air_KERMA = 5.0 # mR
139
+ number_of_projections = 300
140
+ mAs = 0.5
141
+
142
+ keV = np.array([10, 10.5, 11, 11.5, 12, 12.5, 13, 13.5, 14])
143
+ I = np.array(
144
+ [
145
+ 6.20275e2,
146
+ 2.26229e2,
147
+ 5.25667e2,
148
+ 2.39324e3,
149
+ 1.45979e3,
150
+ 2.17293e3,
151
+ 3.36611e3,
152
+ 4.89394e3,
153
+ 6.61405e3,
154
+ ]
155
+ )
156
+
157
+ exposure = exposure_per_fluence(keV)
158
+ dgn = dgn_calculate(a, b, c, d, e, f, g, h, keV)
159
+
160
+ pDgN_num = pDgN_calculate_numerator(I, dgn, exposure)
161
+ pDgN_denom = pDgN_calculate_denominator(I, exposure)
162
+ pDgN = pDgN_num / pDgN_denom
163
+
164
+ print("pDgN =", pDgN)
165
+
166
+ mgd = calculate_mgd(air_KERMA, pDgN, number_of_projections, mAs, "mR", "mGy")
167
+
168
+ print("mgd =", mgd)
PyBDC/dose_equations.py ADDED
@@ -0,0 +1,68 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """
4
+ Created on Tue Dec 13 14:54:18 2022
5
+
6
+ Equations and dgn values for tkinter
7
+
8
+ @author: DIDSR
9
+ """
10
+
11
+ import numpy as np
12
+ import pandas as pd
13
+
14
+ import os
15
+
16
+ # Sarno polyenergetic and monoenergetic tables from published papers
17
+ Sarno_mono_dgn = pd.read_csv(
18
+ os.path.join(os.getcwd(), "dose_table", "Sarno_mono_dgn.txt"), sep=" "
19
+ )
20
+
21
+ Sarno_poly_dgn = pd.read_csv(
22
+ os.path.join(os.getcwd(), "dose_table", "Sarno_poly_dgn.txt"),
23
+ sep=" ",
24
+ index_col="HVL",
25
+ )
26
+
27
+ # monoenergetic dgnct equation 8th degree polynomial fitting
28
+ sarno_dgnct = (
29
+ lambda a, b, c, d, e, f, g, h, E: (a * 10**-14) * E**8
30
+ + (b * 10**-12) * E**7
31
+ + (c * 10**-10) * E**6
32
+ + (d * 10**-8) * E**5
33
+ + (e * 10**-6) * E**4
34
+ + (f * 10**-4) * E**3
35
+ + (g * 10**-3) * E**2
36
+ + (h * 10**-2) * E
37
+ )
38
+ # define equation for exposure per fluence
39
+ aa = -5.023290717769674e-6
40
+ bb = 1.810595449064631e-7
41
+ cc = 0.008838658459816926
42
+ exposure_per_fluence = (
43
+ lambda E: (aa + bb * np.log(E) * np.log(E) + cc / E**2) ** (-1) / 1000 * 0.1145
44
+ )
45
+
46
+ # Hernandez_hetero_dgn table
47
+ Hernandez_hetero_mono_dgn = pd.read_csv(
48
+ os.path.join(os.getcwd(), "dose_table", "Hernandez_heterogeneous_dgn.txt"),
49
+ sep=",",
50
+ header=0,
51
+ )
52
+
53
+ # Sechopoulos dgn
54
+ Sechopoulos_poly_dgn = pd.read_csv(
55
+ os.path.join(os.getcwd(), "dose_table", "Sechopoulos_dgn.txt"),
56
+ sep=" ",
57
+ header=None,
58
+ index_col=0,
59
+ ) # index is diameter at chest wall (breast diameter)
60
+ Sechopoulos_poly_dgn.columns = [
61
+ "Chest wall-to-nipple distance",
62
+ "1%",
63
+ "14.3%",
64
+ "25%",
65
+ "50%",
66
+ "75%",
67
+ "100%",
68
+ ]
PyBDC/dose_table/Hernandez_heterogeneous_dgn.txt ADDED
@@ -0,0 +1,63 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Photon Energy,V1,V3,V5
2
+ 9,0.00083583,2.6404e-05,0.00041403
3
+ 10,0.0021143,0.00011412,0.00077867
4
+ 11,0.0047645,0.00042776,0.0015428
5
+ 12,0.0097646,0.0014649,0.0029913
6
+ 13,0.01824,0.0041467,0.0058035
7
+ 14,0.031113,0.0097186,0.010832
8
+ 15,0.049135,0.01983,0.019086
9
+ 16,0.072678,0.035183,0.031512
10
+ 17,0.10108,0.056164,0.048909
11
+ 18,0.13452,0.083415,0.071591
12
+ 19,0.1708,0.1159,0.098474
13
+ 20,0.20919,0.15217,0.12885
14
+ 21,0.24939,0.19137,0.16349
15
+ 22,0.29167,0.23385,0.20084
16
+ 23,0.33322,0.27748,0.24088
17
+ 24,0.37348,0.32097,0.28171
18
+ 25,0.41337,0.3639,0.32233
19
+ 26,0.45222,0.4078,0.36434
20
+ 27,0.48875,0.45082,0.40399
21
+ 28,0.52471,0.48937,0.44384
22
+ 29,0.55386,0.52752,0.48112
23
+ 30,0.58406,0.56409,0.51679
24
+ 31,0.61198,0.59943,0.55391
25
+ 32,0.63962,0.63189,0.58705
26
+ 33,0.66629,0.66392,0.61871
27
+ 34,0.69148,0.6944,0.65311
28
+ 35,0.71432,0.71936,0.68272
29
+ 36,0.73564,0.74955,0.71284
30
+ 37,0.7574,0.77381,0.73847
31
+ 38,0.77718,0.7986,0.76403
32
+ 39,0.79363,0.81897,0.78669
33
+ 40,0.81075,0.83792,0.80639
34
+ 41,0.82391,0.85488,0.82719
35
+ 42,0.83935,0.87258,0.84885
36
+ 43,0.84975,0.88682,0.86454
37
+ 44,0.86338,0.90121,0.88299
38
+ 45,0.8771,0.91859,0.90091
39
+ 46,0.8857,0.93117,0.91449
40
+ 47,0.89767,0.94599,0.92882
41
+ 48,0.90676,0.95653,0.94479
42
+ 49,0.91719,0.9684,0.95507
43
+ 50,0.9253,0.98087,0.96429
44
+ 51,0.93172,0.9872,0.97324
45
+ 52,0.9368,0.99436,0.98302
46
+ 53,0.9457,1.0031,0.99217
47
+ 54,0.95372,1.0111,1.0018
48
+ 55,0.95872,1.0143,1.0076
49
+ 56,0.96344,1.0203,1.0153
50
+ 57,0.9704,1.0285,1.0216
51
+ 58,0.97136,1.0334,1.0247
52
+ 59,0.97525,1.0335,1.0254
53
+ 60,0.97436,1.0337,1.0287
54
+ 61,0.9734,1.0338,1.0298
55
+ 62,0.9747,1.0356,1.0265
56
+ 63,0.97796,1.0383,1.0298
57
+ 64,0.97861,1.0382,1.0331
58
+ 65,0.98172,1.037,1.0309
59
+ 66,0.98315,1.0392,1.0363
60
+ 67,0.98622,1.0408,1.0401
61
+ 68,0.9875,1.0402,1.0402
62
+ 69,0.98744,1.0412,1.0393
63
+ 70,0.99011,1.0423,1.0394
PyBDC/dose_table/Sarno_mono_dgn.txt ADDED
@@ -0,0 +1,122 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ 8 10 12 14 16 18 Glandularity "breast height"
2
+ -20.5892189574262 -16.2549875815176 -13.0105252240121 -8.69823775324488 -6.2626374180787 -4.11905486084258 0.1% 1x
3
+ 73.1896769700967 58.9667571016743 48.2473118933221 33.7059595402125 25.2453958389843 17.607318355718 0.1% 1x
4
+ -106.257384254468 -87.6793954179481 -73.5109692475839 -53.6746702293416 -41.7447427763885 -30.6679485592535 0.1% 1x
5
+ 80.2630529832939 68.1574607426119 58.7507718113977 44.8431928067761 36.1746085960411 27.852800959409 0.1% 1x
6
+ -32.9588597556987 -29.0022142048811 -25.8364371052747 -20.6148436051423 -17.2415925802501 -13.8531069455155 0.1% 1x
7
+ 6.80939523347842 6.28437360736677 5.84159353470471 4.8660681546934 4.21785343604026 3.51504057484829 0.1% 1x
8
+ -5.10495486459641 -5.12103368116827 -5.11264758335616 -4.40730096137731 -3.94413870954404 -3.34153429589538 0.1% 1x
9
+ 1.16791414363473 1.32805221986491 1.48251939370311 1.32767184556531 1.23707123663961 1.0630020174972 0.1% 1x
10
+ -18.8614633901972 -14.4873821970602 -10.2748774672606 -6.78097602091439 -4.13790052150762 -2.42034880680238 14.3% 1x
11
+ 67.9966324124675 53.051921818743 39.1167547568082 27.1740161529563 17.8421648486217 11.6054724812263 14.3% 1x
12
+ -100.407920059751 -79.7473049402957 -61.2089746714773 -44.6288811500868 -31.2618830095452 -22.0128547562243 14.3% 1x
13
+ 77.4646880984559 62.7877857350058 50.2583040410241 38.3812938657821 28.4970859206457 21.3667008430265 14.3% 1x
14
+ -32.7118714494535 -27.1316880770574 -22.7142258479208 -18.1428642950792 -14.1994217090572 -11.2098957904762 14.3% 1x
15
+ 7.05148339891376 5.99583796759882 5.27779613294281 4.40051727688339 3.6052960442998 2.96427653092378 14.3% 1x
16
+ -5.8124256458628 -5.03917259213266 -4.73697579359378 -4.08636716334962 -3.43716045376484 -2.86390931824229 14.3% 1x
17
+ 1.52100591467739 1.36870948902565 1.41534753702737 1.26955853801553 1.09732746342247 0.91873965627105 14.3% 1x
18
+ -16.8109585387878 -13.4465156748677 -9.68833762741007 -6.11601383659056 -2.92884201402284 -1.53088670677826 25% 1x
19
+ 61.3203591886266 49.7095250445647 36.9239879441541 24.6505665685653 13.5410368798031 8.3108080532326 25% 1x
20
+ -91.6911532064717 -75.4763433076621 -57.9584838150434 -40.8387218553826 -25.0348913031681 -17.0693179966546 25% 1x
21
+ 71.6959740699239 60.0841512514733 47.8600943957251 35.531212234849 23.828597628169 17.5426167439385 25% 1x
22
+ -30.7168317330683 -26.3004505311856 -21.8254023885068 -17.0415200305136 -12.3041451569027 -9.61554981309142 25% 1x
23
+ 6.72567964692271 5.91091438532735 5.14127031813 4.20804051821994 3.21372277739241 2.62809073905998 25% 1x
24
+ -5.63828047974027 -5.11810659952038 -4.72745621155995 -4.004296872229 -3.10100905160595 -2.57337899355731 25% 1x
25
+ 1.50003590490319 1.45160407675241 1.46418012347419 1.28725871761359 0.996805062601169 0.832057685964819 25% 1x
26
+ -14.4194331182086 -10.8013579981451 -6.67686602053368 -3.11421837779407 -1.22498409810941 0.61754643044812 50% 1x
27
+ 53.0306863858881 40.7664766098944 26.5964760912995 14.064290973413 7.18311145227733 0.63986401441522 50% 1x
28
+ -80.0309463075534 -63.3428246480193 -43.6147787221285 -25.6397183986664 -15.3938194860164 -5.85258938919576 50% 1x
29
+ 63.2268264701365 51.7603488938994 37.6221703887495 24.220214659282 16.2748654253439 8.98151812732922 50% 1x
30
+ -27.392640232255 -23.3534316236867 -17.9249758239639 -12.4734711979282 -9.11208621648777 -6.04156955084438 50% 1x
31
+ 6.06179050145871 5.44477936882484 4.41096349260873 3.26463727780154 2.53337970511689 1.8589587987115 50% 1x
32
+ -5.09150623907318 -4.97005206070813 -4.22456914511412 -3.18593036465252 -2.51531508838942 -1.87490493956134 50% 1x
33
+ 1.37869788875488 1.51816787446659 1.37145898722699 1.03904920464228 0.82404206681742 0.60958394158242 50% 1x
34
+ -10.1369427582467 -5.63727868846832 -0.88311260146176 1.3795739987699 2.20432277915504 3.13772472668648 100% 1x
35
+ 38.4916378213188 22.8313076887658 6.42256273905311 -1.91415256450575 -5.27730445856237 -8.85706254067506 100% 1x
36
+ -60.268970721968 -38.0934542891817 -14.9728122886743 -2.39054694621721 3.17566459288785 8.8141166190236 100% 1x
37
+ 49.7035461656967 33.4640292295369 16.4885254072397 6.57088059398393 1.80601760172866 -2.84985255659296 100% 1x
38
+ -22.6653251627581 -16.2521610655177 -9.42615905692364 -5.14067240355409 -2.931935421163 -0.81563772315493 100% 1x
39
+ 5.34921612065528 4.07667335668397 2.6501127782798 1.68787028401425 1.16685383674954 0.66637150773542 100% 1x
40
+ -4.95938165842527 -3.95923738240158 -2.66824289994019 -1.73234383603109 -1.22630669106474 -0.72087477313467 100% 1x
41
+ 1.54193691681923 1.28936502049872 0.88710294094141 0.56677661922357 0.39681132630782 0.21888243481137 100% 1x
42
+ -19.1645671809949 -16.8147836393425 -11.2842175549556 -7.36010377719434 -4.57868618758555 -2.47868929641614 0.1% 1.5x
43
+ 69.1642550506839 61.2714924441808 42.9395827146565 29.4256514966446 19.6579289087392 11.9981028018794 0.1% 1.5x
44
+ -101.965119136956 -91.6144471733953 -67.1718980141002 -48.3350823642992 -34.3571345072815 -22.9686778874197 0.1% 1.5x
45
+ 78.2354620498176 71.7362807421884 55.1555652655511 41.6575332103183 31.2933265356589 22.5028832092703 0.1% 1.5x
46
+ -32.6441079147333 -30.8365367945318 -24.9383780491408 -19.7612508863289 -15.6064942173144 -11.9172614942877 0.1% 1.5x
47
+ 6.85235717685667 6.78822530725787 5.79998592988430 4.81380972545511 3.97289833000403 3.17917768091892 0.1% 1.5x
48
+ -5.20255134178982 -5.72186953226948 -5.21751943901165 -4.49305343499093 -3.80832311270289 -3.08782804193953 0.1% 1.5x
49
+ 1.19982076353667 1.56076060188167 1.56492881077813 1.40461534333983 1.22337348295479 0.99454595304800 0.1% 1.5x
50
+ -18.9368374169727 -14.2466856768054 -9.67658919212705 -5.83550670894167 -3.17399694212437 -0.58313311347465 14.3% 1.5x
51
+ 68.1975916819477 52.7885545642611 37.3521099989829 24.0144522955238 14.4152951488294 5.37200133816344 14.3% 1.5x
52
+ -100.584799434600 -80.3481396379044 -59.3364845238459 -40.5256897723847 -26.4182683111730 -13.4764271582640 14.3% 1.5x
53
+ 77.4683655140414 64.1380253288522 49.5508760618772 35.8474373511219 25.0842774943437 15.3944811970640 14.3% 1.5x
54
+ -32.6054812956868 -28.1650488977722 -22.8333936929596 -17.4504776200432 -12.9832144755277 -8.99760803321632 14.3% 1.5x
55
+ 6.96791822084179 6.35507060426797 5.42897605516953 4.36315569635605 3.41068862131482 2.55787568692749 14.3% 1.5x
56
+ -5.55480011203282 -5.53744406808503 -5.02555151475395 -4.17552960525184 -3.31257426365004 -2.52428449248738 14.3% 1.5x
57
+ 1.38818732958602 1.58680153397930 1.56543387188259 1.34653090032133 1.07202357452204 0.81469244777539 14.3% 1.5x
58
+ -17.1884488866233 -12.4648977730464 -7.86447485868652 -4.26857559197584 -1.59017706091734 0.33534587896044 25% 1.5x
59
+ 62.6110514618001 46.8351785403993 31.0816414513323 18.5353908511224 8.96204984806396 1.94796923562449 25% 1.5x
60
+ -93.4549995471558 -72.3737978055242 -50.5591679805397 -32.7364823535155 -18.7564942690574 -8.26799153644478 25% 1.5x
61
+ 72.9082591782242 58.7281602761448 43.2352293155123 30.1173389665102 19.4879066305298 11.2810730591863 25% 1.5x
62
+ -31.1311975822105 -26.2535622724901 -20.3962428657680 -15.1685102551698 -10.7570129309277 -7.23294941203410 25% 1.5x
63
+ 6.76954513778785 6.04121564868853 4.95723130361156 3.90023164701591 2.95603290328365 2.17053554755444 25% 1.5x
64
+ -5.54329792737660 -5.38824302422911 -4.65680239689631 -3.78329792777939 -2.92101412636709 -2.16681828800954 25% 1.5x
65
+ 1.44343752532824 1.58994822097885 1.46794142071639 1.23092057141398 0.95398101969790 0.69923122392582 25% 1.5x
66
+ -15.1880781026812 -9.41627204366998 -4.86316066577117 -1.90660502160902 0.800916034431646 2.20897796113271 50% 1.5x
67
+ 55.8853162629730 36.4768579416517 20.6104067446398 10.0460003667955 0.222936691687627 -4.99674714943268 50% 1.5x
68
+ -84.4950820333717 -58.1819978050464 -35.7045638888039 -20.2855203226159 -5.71448741769510 2.25268262092014 50% 1.5x
69
+ 67.0207373868516 48.8178052252957 32.3448679025270 20.6381923159504 9.35813357471496 2.97361078801558 50% 1.5x
70
+ -29.2560945234631 -22.6244423618499 -16.0962713530783 -11.2553171293301 -6.46242636201031 -3.64639846320904 50% 1.5x
71
+ 6.56732896400909 5.41934758149813 4.10705395092666 3.07980853984166 2.01643120903275 1.37126471303537 50% 1.5x
72
+ -5.71161373701105 -5.08117559441464 -3.99860089133949 -3.07983057699189 -2.04287106983903 -1.41142550858313 50% 1.5x
73
+ 1.62883231176140 1.60555739426190 1.31021175203602 1.02309697001406 0.665251808238488 0.448949271362092 50% 1.5x
74
+ -9.08985806284783 -4.24472253222862 -0.76984500543629 1.79755857225210 3.86063705017426 3.61533168777020 100% 1.5x
75
+ 35.1556369384749 18.1509079784559 5.68125150161062 -3.63463909599484 -11.0205284735661 -10.7181951668970 100% 1.5x
76
+ -56.0978712690103 -31.8072030795209 -13.4899048502527 0.37105862852171 11.2896086675581 11.7593837388993 100% 1.5x
77
+ 47.1824896624291 29.2211378862523 15.1812213039088 4.38409501074898 -4.13536381059572 -5.23682533548250 100% 1.5x
78
+ -21.9600453686823 -14.7826330542632 -8.89402113581299 -4.26541028396866 -0.57333179461705 0.20490475866474 100% 1.5x
79
+ 5.29110896452988 3.84173121313000 2.56370945818317 1.52747236803440 0.68342584907207 0.45306012392519 100% 1.5x
80
+ -4.99601003982595 -3.81155649463395 -2.61967825700806 -1.60906764897764 -0.75979279134353 -0.52275565616072 100% 1.5x
81
+ 1.58931930382548 1.27244560068908 0.88101681882966 0.53367982394117 0.23266989613221 0.15329649678692 100% 1.5x
82
+ -20.3453500911976 -15.3818577673824 -10.2085381494137 -5.82733246008717 -2.78095953625346 -1.00389834939120 0.1% 2x
83
+ 73.2554361668989 56.8975786879096 39.4790873074193 24.4770521135583 13.5516022229364 6.99553918152219 0.1% 2x
84
+ -107.907465783956 -86.3983958268832 -62.7696059405248 -41.9387164948392 -25.9817373190385 -16.0778723477594 0.1% 2x
85
+ 82.8941858466593 68.7388013299305 52.3929631099517 37.4873989211601 25.4008522980169 17.6058512760968 0.1% 2x
86
+ -34.7383808303456 -30.0397325611327 -24.0835770063152 -18.3565316136584 -13.3842908993097 -10.0427005745298 0.1% 2x
87
+ 7.37059912539802 6.72678820985405 5.69120903653127 4.59330932164656 3.54545622880765 2.81284017168739 0.1% 2x
88
+ -5.79085861396574 -5.77337642017993 -5.18014471288083 -4.36215752364718 -3.42862300765967 -2.76054480158645 0.1% 2x
89
+ 1.42058778605767 1.61983265007594 1.56888397920142 1.39101720599815 1.09953698599335 0.88760904291828 0.1% 2x
90
+ -19.1170265427664 -13.3058327996024 -8.35415941456442 -4.32615232196170 -1.49402451660712 0.92582907692514 14.3% 2x
91
+ 69.0682816801379 49.8512852808101 33.0164364994159 19.0260534814189 8.87201415208120 0.22795992937770 14.3% 2x
92
+ -102.273279944056 -76.8017166510144 -53.6738836474383 -33.8699323355993 -19.0072269586949 -6.35662104463300 14.3% 2x
93
+ 79.1707537558980 62.1205210589987 45.8434996421431 31.3032852217140 19.9876960727833 10.3055289159243 14.3% 2x
94
+ -33.5531941732455 -27.6710886601089 -21.5879390791509 -15.7999411755434 -11.1043742252699 -7.03216813741396 14.3% 2x
95
+ 7.24589514523948 6.33987779688810 5.23439691510269 4.06255248392697 3.06013445568943 2.16764654523321 14.3% 2x
96
+ -5.90694530032777 -5.61697437182332 -4.90249004225999 -3.92493786069026 -3.01592608192114 -2.16739081871729 14.3% 2x
97
+ 1.53372047301056 1.64617724031139 1.54078564885475 1.26945781266833 0.98029000820539 0.69537688160476 14.3% 2x
98
+ -17.7151618872944 -11.6762048587017 -6.83745246835591 -2.90772507473843 -0.00419777322261 1.31047973560291 25% 2x
99
+ 64.5369249289555 44.4778685756716 27.8004533042877 13.9526793178979 3.54650464094095 -1.45485333819163 25% 2x
100
+ -96.4580997536959 -69.6893797342646 -46.3956009946817 -26.5054598331460 -11.2558621390243 -3.44916912000035 25% 2x
101
+ 75.4750033870382 57.3560133542242 40.6176184430994 25.7822935056240 14.1278292266742 7.76486282215846 25% 2x
102
+ -32.4016083956099 -26.0210770204408 -19.5854473368220 -13.5637597038356 -8.68766438071822 -5.85550080302071 25% 2x
103
+ 7.11588245353662 6.08362435654798 4.85856066823430 3.60217344742505 2.54429602167510 1.89745882642963 25% 2x
104
+ -5.97146437712964 -5.53397984775321 -4.64693238651176 -3.53068332340179 -2.53948610150421 -1.92285998024494 25% 2x
105
+ 1.62192409374839 1.68095232949207 1.50086947203183 1.15229206241631 0.824476989727103 0.620000821622919 25% 2x
106
+ -13.7459716968014 -8.56380090371856 -4.28979969759713 -0.41324119391158 1.69230593550597 3.12544003276511 50% 2x
107
+ 51.3376932532365 33.5719543961296 18.5529027571888 4.88540710576677 -2.88906422288599 -8.20020118784173 50% 2x
108
+ -78.7924495926802 -54.2608149912678 -32.7829108215061 -13.0460380815292 -1.28533369822837 6.83585315159465 50% 2x
109
+ 63.4438541963516 46.1872198129110 30.2860417495202 15.3913804609064 6.09630272285736 -0.43863485493705 50% 2x
110
+ -28.1067595151831 -21.7329803636913 -15.3666388517613 -9.19621868949206 -5.16812566573774 -2.26596700372391 50% 2x
111
+ 6.39451896430322 5.28357128464266 3.99295077756319 2.66123817129083 1.75541962408278 1.08403562001326 50% 2x
112
+ -5.59927627057295 -5.00124388885343 -3.93535686016687 -2.67974610124986 -1.80301650295393 -1.13828192939998 50% 2x
113
+ 1.60310974735945 1.59173238124724 1.30285446626893 0.883219836298924 0.585083299976351 0.354872662135623 50% 2x
114
+
115
+ 8.19501354358143 -3.43233929966256 1.06854465027246 2.69788034635764 3.99696833004187 3.61541032645446 100% 2x
116
+ 32.3339621213143 15.4258208938566 -0.46194442378509 -6.80072235828109 -11.7370374938090 -10.9518596915828 100% 2x
117
+ -52.5743897761552 -28.1495435012571 -5.14993172462760 4.91883675862664 12.6606188617394 12.4397898399456 100% 2x
118
+ 45.0099868190053 26.7488349477012 9.31794639978741 0.99324724634839 -5.39867149276577 -5.99288165168819 100% 2x
119
+ -21.3014430876912 -13.9225108347228 -6.65074765969073 -2.89482853763288 0.019070454024008 0.59618625122408 100% 2x
120
+ 5.21105850309460 3.70302309527900 2.11518866240840 1.24232141816806 0.550066476635071 0.36163013483674 100% 2x
121
+ -4.97500545277725 -3.72233756306733 -2.19384386035287 -1.33366860960407 -0.63011980792665 -0.43734635307982 100% 2x
122
+ 1.59722116812876 1.25463523341077 0.73278989126218 0.43715460733195 0.188038328621894 0.12613288060321 100% 2x
PyBDC/dose_table/Sarno_poly_dgn.txt ADDED
@@ -0,0 +1,91 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ HVL 8 10 12 14 16 18 Glandularity "breast height"
2
+ 1.25 0.509 0.464 0.426 0.394 0.367 0.343 0.1% 1x
3
+ 1.30 0.518 0.473 0.435 0.403 0.375 0.352 0.1% 1x
4
+ 1.35 0.528 0.483 0.445 0.412 0.384 0.36 0.1% 1x
5
+ 1.40 0.537 0.492 0.454 0.421 0.393 0.369 0.1% 1x
6
+ 1.45 0.546 0.501 0.463 0.429 0.401 0.377 0.1% 1x
7
+ 1.50 0.554 0.509 0.471 0.437 0.409 0.384 0.1% 1x
8
+ 1.25 0.49 0.444 0.406 0.374 0.347 0.324 14.3% 1x
9
+ 1.30 0.5 0.454 0.415 0.383 0.356 0.333 14.3% 1x
10
+ 1.35 0.51 0.463 0.425 0.392 0.365 0.341 14.3% 1x
11
+ 1.40 0.519 0.473 0.433 0.401 0.373 0.349 14.3% 1x
12
+ 1.45 0.528 0.481 0.442 0.409 0.381 0.357 14.3% 1x
13
+ 1.50 0.536 0.489 0.45 0.417 0.388 0.364 14.3% 1x
14
+ 1.25 0.479 0.432 0.393 0.361 0.335 0.312 25% 1x
15
+ 1.30 0.488 0.441 0.402 0.37 0.343 0.32 25% 1x
16
+ 1.35 0.498 0.451 0.412 0.379 0.352 0.329 25% 1x
17
+ 1.40 0.508 0.46 0.42 0.388 0.36 0.336 25% 1x
18
+ 1.45 0.516 0.468 0.429 0.396 0.368 0.344 25% 1x
19
+ 1.50 0.525 0.477 0.437 0.404 0.375 0.351 25% 1x
20
+ 1.25 0.45 0.402 0.364 0.333 0.307 0.285 50% 1x
21
+ 1.30 0.46 0.411 0.373 0.341 0.315 0.293 50% 1x
22
+ 1.35 0.47 0.421 0.382 0.35 0.323 0.301 50% 1x
23
+ 1.40 0.479 0.43 0.391 0.358 0.331 0.308 50% 1x
24
+ 1.45 0.488 0.438 0.399 0.366 0.338 0.315 50% 1x
25
+ 1.50 0.496 0.446 0.407 0.373 0.346 0.322 50% 1x
26
+ 1.25 0.397 0.35 0.314 0.284 0.26 0.24 100% 1x
27
+ 1.30 0.406 0.359 0.322 0.292 0.267 0.247 100% 1x
28
+ 1.35 0.416 0.368 0.33 0.299 0.274 0.253 100% 1x
29
+ 1.40 0.425 0.377 0.338 0.307 0.281 0.26 100% 1x
30
+ 1.45 0.433 0.385 0.346 0.314 0.288 0.267 100% 1x
31
+ 1.50 0.441 0.392 0.353 0.321 0.295 0.273 100% 1x
32
+ 1.25 0.532 0.486 0.445 0.411 0.381 0.355 0.1% 1.5x
33
+ 1.30 0.542 0.496 0.455 0.421 0.391 0.364 0.1% 1.5x
34
+ 1.35 0.553 0.507 0.465 0.431 0.4 0.374 0.1% 1.5x
35
+ 1.40 0.563 0.517 0.475 0.44 0.41 0.383 0.1% 1.5x
36
+ 1.45 0.572 0.526 0.484 0.449 0.418 0.391 0.1% 1.5x
37
+ 1.50 0.581 0.535 0.493 0.458 0.427 0.399 0.1% 1.5x
38
+ 1.25 0.511 0.464 0.423 0.389 0.36 0.335 14.3% 1.5x
39
+ 1.30 0.521 0.474 0.433 0.399 0.369 0.344 14.3% 1.5x
40
+ 1.35 0.532 0.484 0.443 0.409 0.379 0.353 14.3% 1.5x
41
+ 1.40 0.542 0.494 0.453 0.418 0.388 0.361 14.3% 1.5x
42
+ 1.45 0.551 0.504 0.462 0.427 0.396 0.369 14.3% 1.5x
43
+ 1.50 0.56 0.512 0.471 0.435 0.404 0.377 14.3% 1.5x
44
+ 1.25 0.498 0.45 0.409 0.376 0.347 0.322 25% 1.5x
45
+ 1.30 0.509 0.46 0.419 0.385 0.356 0.33 25% 1.5x
46
+ 1.35 0.519 0.47 0.429 0.395 0.365 0.339 25% 1.5x
47
+ 1.40 0.529 0.48 0.439 0.404 0.374 0.347 25% 1.5x
48
+ 1.45 0.539 0.49 0.448 0.413 0.382 0.355 25% 1.5x
49
+ 1.50 0.547 0.498 0.456 0.421 0.39 0.363 25% 1.5x
50
+ 1.25 0.467 0.418 0.378 0.345 0.316 0.293 50% 1.5x
51
+ 1.30 0.478 0.428 0.387 0.354 0.325 0.3 50% 1.5x
52
+ 1.35 0.488 0.438 0.397 0.363 0.334 0.309 50% 1.5x
53
+ 1.40 0.498 0.447 0.406 0.372 0.342 0.317 50% 1.5x
54
+ 1.45 0.507 0.457 0.415 0.38 0.35 0.324 50% 1.5x
55
+ 1.50 0.516 0.465 0.423 0.388 0.357 0.331 50% 1.5x
56
+ 1.25 0.411 0.362 0.324 0.292 0.266 0.245 100% 1.5x
57
+ 1.30 0.421 0.371 0.332 0.3 0.274 0.252 100% 1.5x
58
+ 1.35 0.431 0.381 0.341 0.309 0.281 0.259 100% 1.5x
59
+ 1.40 0.44 0.39 0.35 0.317 0.289 0.266 100% 1.5x
60
+ 1.45 0.449 0.399 0.358 0.324 0.296 0.272 100% 1.5x
61
+ 1.50 0.458 0.407 0.366 0.331 0.303 0.279 100% 1.5x
62
+ 1.25 0.545 0.496 0.454 0.418 0.386 0.358 0.1% 2x
63
+ 1.30 0.555 0.507 0.464 0.428 0.396 0.367 0.1% 2x
64
+ 1.35 0.566 0.518 0.475 0.438 0.406 0.377 0.1% 2x
65
+ 1.40 0.577 0.528 0.485 0.448 0.415 0.386 0.1% 2x
66
+ 1.45 0.587 0.538 0.495 0.458 0.424 0.395 0.1% 2x
67
+ 1.50 0.596 0.547 0.504 0.466 0.433 0.403 0.1% 2x
68
+ 1.25 0.523 0.473 0.431 0.395 0.364 0.337 14.3% 2x
69
+ 1.30 0.534 0.484 0.442 0.405 0.373 0.346 14.3% 2x
70
+ 1.35 0.545 0.495 0.452 0.415 0.383 0.355 14.3% 2x
71
+ 1.40 0.555 0.505 0.462 0.425 0.392 0.364 14.3% 2x
72
+ 1.45 0.565 0.515 0.472 0.434 0.401 0.372 14.3% 2x
73
+ 1.50 0.574 0.524 0.481 0.443 0.41 0.38 14.3% 2x
74
+ 1.25 0.51 0.459 0.417 0.381 0.35 0.323 25% 2x
75
+ 1.30 0.52 0.47 0.427 0.391 0.359 0.332 25% 2x
76
+ 1.35 0.531 0.481 0.437 0.401 0.369 0.341 25% 2x
77
+ 1.40 0.542 0.491 0.447 0.41 0.378 0.35 25% 2x
78
+ 1.45 0.552 0.5 0.457 0.419 0.386 0.358 25% 2x
79
+ 1.50 0.561 0.51 0.466 0.428 0.395 0.366 25% 2x
80
+ 1.25 0.477 0.425 0.384 0.348 0.319 0.293 50% 2x
81
+ 1.30 0.487 0.436 0.393 0.358 0.327 0.301 50% 2x
82
+ 1.35 0.498 0.446 0.403 0.367 0.336 0.31 50% 2x
83
+ 1.40 0.509 0.456 0.413 0.376 0.345 0.318 50% 2x
84
+ 1.45 0.518 0.466 0.422 0.385 0.353 0.325 50% 2x
85
+ 1.50 0.527 0.475 0.431 0.393 0.361 0.333 50% 2x
86
+ 1.25 0.418 0.368 0.328 0.295 0.267 0.244 100% 2x
87
+ 1.30 0.429 0.377 0.336 0.303 0.275 0.251 100% 2x
88
+ 1.35 0.439 0.387 0.346 0.311 0.283 0.259 100% 2x
89
+ 1.40 0.449 0.397 0.354 0.319 0.29 0.266 100% 2x
90
+ 1.45 0.458 0.405 0.363 0.327 0.298 0.273 100% 2x
91
+ 1.50 0.467 0.414 0.371 0.335 0.304 0.279 100% 2x
PyBDC/dose_table/Sechopoulos_dgn.txt ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ 10 5.0 0.537 0.517 0.502 0.469 0.438 0.41
2
+ 10 7.5 0.566 0.544 0.527 0.49 0.457 0.427
3
+ 10 10.0 0.582 0.559 0.541 0.503 0.468 0.436
4
+ 12 6.0 0.494 0.474 0.458 0.424 0.395 0.367
5
+ 12 9.0 0.521 0.499 0.482 0.445 0.412 0.382
6
+ 12 12.0 0.536 0.512 0.493 0.455 0.42 0.389
7
+ 14 7.0 0.458 0.437 0.421 0.388 0.358 0.331
8
+ 14 10.5 0.482 0.459 0.442 0.406 0.374 0.345
9
+ 14 14.0 0.494 0.47 0.452 0.414 0.381 0.35
10
+ 16 8.0 0.425 0.404 0.389 0.357 0.328 0.302
11
+ 16 12.0 0.448 0.425 0.408 0.373 0.341 0.314
12
+ 16 16.0 0.458 0.434 0.416 0.379 0.346 0.318
13
+ 18 9.0 0.397 0.376 0.361 0.33 0.302 0.278
14
+ 18 13.5 0.417 0.395 0.378 0.343 0.313 0.287
15
+ 18 18.0 0.425 0.402 0.384 0.348 0.317 0.29
PyBDC/incident_spectrum/49kVp_1.5_Al.txt ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ 10 0.000005
2
+ 11 0.000052
3
+ 12 0.000270
4
+ 13 0.000919
5
+ 14 0.002455
6
+ 15 0.005140
7
+ 16 0.009001
8
+ 17 0.013873
9
+ 18 0.019268
10
+ 19 0.024749
11
+ 20 0.029985
12
+ 21 0.034657
13
+ 22 0.038581
14
+ 23 0.041978
15
+ 24 0.044421
16
+ 25 0.046029
17
+ 26 0.046957
18
+ 27 0.047134
19
+ 28 0.047439
20
+ 29 0.046707
21
+ 30 0.044716
22
+ 31 0.043817
23
+ 32 0.043078
24
+ 33 0.041237
25
+ 34 0.039047
26
+ 35 0.036766
27
+ 36 0.034587
28
+ 37 0.032140
29
+ 38 0.029969
30
+ 39 0.027359
31
+ 40 0.024556
32
+ 41 0.022268
33
+ 42 0.019361
34
+ 43 0.016677
35
+ 44 0.014424
36
+ 45 0.011703
37
+ 46 0.008915
38
+ 47 0.006223
39
+ 48 0.003539
40
+ 49 0.000000
PyBDC/incident_spectrum/55kVp1and5mmAl.txt ADDED
@@ -0,0 +1,110 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ 0.5 0.00000E+00
2
+ 1.0 0.00000E+00
3
+ 1.5 0.00000E+00
4
+ 2.0 0.00000E+00
5
+ 2.5 0.00000E+00
6
+ 3.0 0.00000E+00
7
+ 3.5 0.00000E+00
8
+ 4.0 0.00000E+00
9
+ 4.5 0.00000E+00
10
+ 5.0 9.63242E-75
11
+ 5.5 3.22230E-56
12
+ 6.0 1.30434E-42
13
+ 6.5 5.38684E-33
14
+ 7.0 9.92189E-26
15
+ 7.5 3.42140E-20
16
+ 8.0 6.54579E-16
17
+ 8.5 1.54663E-11
18
+ 9.0 6.91632E-10
19
+ 9.5 5.26105E-07
20
+ 10.0 2.55618E-05
21
+ 10.5 7.40239E-05
22
+ 11.0 1.18932E-03
23
+ 11.5 3.03248E-02
24
+ 12.0 6.34224E-02
25
+ 12.5 2.89203E-01
26
+ 13.0 1.22809E+00
27
+ 13.5 4.28942E+00
28
+ 14.0 1.18624E+01
29
+ 14.5 2.94770E+01
30
+ 15.0 6.49330E+01
31
+ 15.5 1.29553E+02
32
+ 16.0 2.38366E+02
33
+ 16.5 4.01789E+02
34
+ 17.0 6.45077E+02
35
+ 17.5 9.66325E+02
36
+ 18.0 1.38945E+03
37
+ 18.5 1.91821E+03
38
+ 19.0 2.54336E+03
39
+ 19.5 3.27831E+03
40
+ 20.0 4.09872E+03
41
+ 20.5 4.97673E+03
42
+ 21.0 5.97946E+03
43
+ 21.5 6.97690E+03
44
+ 22.0 8.05762E+03
45
+ 22.5 9.12192E+03
46
+ 23.0 1.02271E+04
47
+ 23.5 1.12456E+04
48
+ 24.0 1.23600E+04
49
+ 24.5 1.33254E+04
50
+ 25.0 1.42262E+04
51
+ 25.5 1.51835E+04
52
+ 26.0 1.60487E+04
53
+ 26.5 1.67997E+04
54
+ 27.0 1.75761E+04
55
+ 27.5 1.82184E+04
56
+ 28.0 1.88808E+04
57
+ 28.5 1.93798E+04
58
+ 29.0 1.98888E+04
59
+ 29.5 2.02157E+04
60
+ 30.0 2.05444E+04
61
+ 30.5 2.08746E+04
62
+ 31.0 2.10066E+04
63
+ 31.5 2.12165E+04
64
+ 32.0 2.12967E+04
65
+ 32.5 2.13570E+04
66
+ 33.0 2.13518E+04
67
+ 33.5 2.12957E+04
68
+ 34.0 2.11958E+04
69
+ 34.5 2.10743E+04
70
+ 35.0 2.08796E+04
71
+ 35.5 2.06780E+04
72
+ 36.0 2.04332E+04
73
+ 36.5 2.01390E+04
74
+ 37.0 1.98382E+04
75
+ 37.5 1.94961E+04
76
+ 38.0 1.91477E+04
77
+ 38.5 1.87594E+04
78
+ 39.0 1.83457E+04
79
+ 39.5 1.79263E+04
80
+ 40.0 1.74824E+04
81
+ 40.5 1.70148E+04
82
+ 41.0 1.65306E+04
83
+ 41.5 1.60247E+04
84
+ 42.0 1.55146E+04
85
+ 42.5 1.50000E+04
86
+ 43.0 1.44553E+04
87
+ 43.5 1.39219E+04
88
+ 44.0 1.33557E+04
89
+ 44.5 1.27960E+04
90
+ 45.0 1.22155E+04
91
+ 45.5 1.16409E+04
92
+ 46.0 1.10515E+04
93
+ 46.5 1.04489E+04
94
+ 47.0 9.85904E+03
95
+ 47.5 9.25338E+03
96
+ 48.0 8.64038E+03
97
+ 48.5 8.03533E+03
98
+ 49.0 7.42064E+03
99
+ 49.5 6.79816E+03
100
+ 50.0 6.18239E+03
101
+ 50.5 5.56100E+03
102
+ 51.0 4.94017E+03
103
+ 51.5 4.31978E+03
104
+ 52.0 3.69670E+03
105
+ 52.5 3.07839E+03
106
+ 53.0 2.45851E+03
107
+ 53.5 1.84066E+03
108
+ 54.0 1.22494E+03
109
+ 54.5 6.10877E+02
110
+ 55.0 5.09474E+01
PyBDC/incident_spectrum/60kV_0.2_Cu.txt ADDED
@@ -0,0 +1,51 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ 10 2.17528E-22
2
+ 11 8.14884E-18
3
+ 12 1.18017E-14
4
+ 13 4.01619E-12
5
+ 14 3.10445E-10
6
+ 15 1.10769E-8
7
+ 16 1.7833E-7
8
+ 17 1.78574E-6
9
+ 18 1.08941E-5
10
+ 19 4.29721E-5
11
+ 20 0.00013648
12
+ 21 0.000352846
13
+ 22 0.000795833
14
+ 23 0.00154393
15
+ 24 0.00274503
16
+ 25 0.0044029
17
+ 26 0.00659502
18
+ 27 0.00925285
19
+ 28 0.0124491
20
+ 29 0.0156588
21
+ 30 0.0191672
22
+ 31 0.0226594
23
+ 32 0.026303
24
+ 33 0.0295566
25
+ 34 0.0326895
26
+ 35 0.0355168
27
+ 36 0.0380014
28
+ 37 0.0400384
29
+ 38 0.0417079
30
+ 39 0.0430091
31
+ 40 0.0438818
32
+ 41 0.0446358
33
+ 42 0.0448787
34
+ 43 0.0438065
35
+ 44 0.0424666
36
+ 45 0.0419685
37
+ 46 0.0411065
38
+ 47 0.0389167
39
+ 48 0.0364259
40
+ 49 0.0349405
41
+ 50 0.0331506
42
+ 51 0.031304
43
+ 52 0.0285168
44
+ 53 0.0258341
45
+ 54 0.0229194
46
+ 55 0.0197738
47
+ 56 0.0166468
48
+ 57 0.0122853
49
+ 58 0.00856324
50
+ 59 0.00534053
51
+ 60 0
PyBDC/incident_spectrum/spectrum_45kVp_1mm.txt ADDED
@@ -0,0 +1,71 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ 10.0 6.20275E+02
2
+ 10.5 2.26229E+02
3
+ 11.0 5.25667E+02
4
+ 11.5 2.39324E+03
5
+ 12.0 1.45979E+03
6
+ 12.5 2.17293E+03
7
+ 13.0 3.36611E+03
8
+ 13.5 4.89394E+03
9
+ 14.0 6.61405E+03
10
+ 14.5 8.62495E+03
11
+ 15.0 1.08154E+04
12
+ 15.5 1.31267E+04
13
+ 16.0 1.55160E+04
14
+ 16.5 1.78455E+04
15
+ 17.0 2.01852E+04
16
+ 17.5 2.23424E+04
17
+ 18.0 2.44012E+04
18
+ 18.5 2.63015E+04
19
+ 19.0 2.79851E+04
20
+ 19.5 2.95090E+04
21
+ 20.0 3.08127E+04
22
+ 20.5 3.18808E+04
23
+ 21.0 3.28623E+04
24
+ 21.5 3.35728E+04
25
+ 22.0 3.41728E+04
26
+ 22.5 3.45705E+04
27
+ 23.0 3.48584E+04
28
+ 23.5 3.49344E+04
29
+ 24.0 3.49933E+04
30
+ 24.5 3.48417E+04
31
+ 25.0 3.45781E+04
32
+ 25.5 3.42969E+04
33
+ 26.0 3.39089E+04
34
+ 26.5 3.34169E+04
35
+ 27.0 3.29077E+04
36
+ 27.5 3.23026E+04
37
+ 28.0 3.16857E+04
38
+ 28.5 3.09750E+04
39
+ 29.0 3.02595E+04
40
+ 29.5 2.94586E+04
41
+ 30.0 2.86493E+04
42
+ 30.5 2.78391E+04
43
+ 31.0 2.69503E+04
44
+ 31.5 2.60902E+04
45
+ 32.0 2.51812E+04
46
+ 32.5 2.42670E+04
47
+ 33.0 2.33337E+04
48
+ 33.5 2.23855E+04
49
+ 34.0 2.14273E+04
50
+ 34.5 2.04647E+04
51
+ 35.0 1.94856E+04
52
+ 35.5 1.85087E+04
53
+ 36.0 1.75235E+04
54
+ 36.5 1.65319E+04
55
+ 37.0 1.55422E+04
56
+ 37.5 1.45481E+04
57
+ 38.0 1.35556E+04
58
+ 38.5 1.25620E+04
59
+ 39.0 1.15682E+04
60
+ 39.5 1.05783E+04
61
+ 40.0 9.59146E+03
62
+ 40.5 8.60563E+03
63
+ 41.0 7.62402E+03
64
+ 41.5 6.64697E+03
65
+ 42.0 5.67573E+03
66
+ 42.5 4.71213E+03
67
+ 43.0 3.75295E+03
68
+ 43.5 2.80302E+03
69
+ 44.0 1.85971E+03
70
+ 44.5 9.25674E+02
71
+ 45.0 7.69817E+01
PyBDC/incident_spectrum/spectrum_55kVp2mmAl.txt ADDED
@@ -0,0 +1,91 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ 10.0 1.03261E+00
2
+ 10.5 7.25697E-01
3
+ 11.0 3.60250E+00
4
+ 11.5 3.47511E+01
5
+ 12.0 3.10489E+01
6
+ 12.5 7.12270E+01
7
+ 13.0 1.64755E+02
8
+ 13.5 3.39900E+02
9
+ 14.0 6.12087E+02
10
+ 14.5 1.03443E+03
11
+ 15.0 1.62840E+03
12
+ 15.5 2.41775E+03
13
+ 16.0 3.42141E+03
14
+ 16.5 4.59823E+03
15
+ 17.0 6.00213E+03
16
+ 17.5 7.52135E+03
17
+ 18.0 9.19726E+03
18
+ 18.5 1.09780E+04
19
+ 19.0 1.27941E+04
20
+ 19.5 1.46615E+04
21
+ 20.0 1.65011E+04
22
+ 20.5 1.82538E+04
23
+ 21.0 2.00621E+04
24
+ 21.5 2.16749E+04
25
+ 22.0 2.32724E+04
26
+ 22.5 2.46970E+04
27
+ 23.0 2.60571E+04
28
+ 23.5 2.71826E+04
29
+ 24.0 2.83441E+04
30
+ 24.5 2.92264E+04
31
+ 25.0 2.99637E+04
32
+ 25.5 3.07107E+04
33
+ 26.0 3.12987E+04
34
+ 26.5 3.17189E+04
35
+ 27.0 3.21317E+04
36
+ 27.5 3.23749E+04
37
+ 28.0 3.26141E+04
38
+ 28.5 3.26725E+04
39
+ 29.0 3.27255E+04
40
+ 29.5 3.25966E+04
41
+ 30.0 3.24626E+04
42
+ 30.5 3.23231E+04
43
+ 31.0 3.20048E+04
44
+ 31.5 3.17528E+04
45
+ 32.0 3.13888E+04
46
+ 32.5 3.10090E+04
47
+ 33.0 3.05767E+04
48
+ 33.5 3.01054E+04
49
+ 34.0 2.96024E+04
50
+ 34.5 2.90859E+04
51
+ 35.0 2.85162E+04
52
+ 35.5 2.79459E+04
53
+ 36.0 2.73471E+04
54
+ 36.5 2.67159E+04
55
+ 37.0 2.60849E+04
56
+ 37.5 2.54284E+04
57
+ 38.0 2.47724E+04
58
+ 38.5 2.40924E+04
59
+ 39.0 2.33991E+04
60
+ 39.5 2.27069E+04
61
+ 40.0 2.20023E+04
62
+ 40.5 2.12857E+04
63
+ 41.0 2.05624E+04
64
+ 41.5 1.98287E+04
65
+ 42.0 1.90970E+04
66
+ 42.5 1.83669E+04
67
+ 43.0 1.76205E+04
68
+ 43.5 1.68865E+04
69
+ 44.0 1.61343E+04
70
+ 44.5 1.53910E+04
71
+ 45.0 1.46378E+04
72
+ 45.5 1.38928E+04
73
+ 46.0 1.31420E+04
74
+ 46.5 1.23864E+04
75
+ 47.0 1.16434E+04
76
+ 47.5 1.08937E+04
77
+ 48.0 1.01431E+04
78
+ 48.5 9.40177E+03
79
+ 49.0 8.65784E+03
80
+ 49.5 7.91256E+03
81
+ 50.0 7.17559E+03
82
+ 50.5 6.43871E+03
83
+ 51.0 5.70601E+03
84
+ 51.5 4.97741E+03
85
+ 52.0 4.25085E+03
86
+ 52.5 3.53126E+03
87
+ 53.0 2.81449E+03
88
+ 53.5 2.10291E+03
89
+ 54.0 1.39664E+03
90
+ 54.5 6.95374E+02
91
+ 55.0 5.78772E+01
PyBDC/method_specific_inputs.toml ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # method_specific_inputs.toml
2
+
3
+ [method_specific_inputs]
4
+ Sarno_49_specific_output = "This method assumes a cylindrical breast shape of homogeneous mixture where air kerma is measured from the radiation source. The method further provides different Al filtrations."
5
+
6
+ Sarno_specific_outputs = """
7
+ Any spectrum can be used as long as radiation source to isocenter distance is 65 cm.
8
+
9
+ It assumes heterogeneous composition."""
10
+
11
+ Hernandez_specific_output = """
12
+ Any spectrum can be used as long as radiation source to isocenter distance is 65 cm.
13
+
14
+ It assumes heterogeneous composition.
15
+
16
+ Hernandez VGF median specifications:
17
+ V1:
18
+ - volume of 276 cm^3
19
+ - center of mass diameter of 87 mm
20
+ - chest wall diameter of 103.4 mm
21
+ V3:
22
+ - volume of 616 cm^3
23
+ - center of mass diameter of 106.6 mm
24
+ - chest wall diameter of 125.2
25
+ V5:
26
+ - volume of 1174 cm^3
27
+ - center of mass diameter of 124.4 mm
28
+ - chest wall diameter of 150.4 mm"""
29
+
30
+ Sechopoulos_specific_output = "It assumes a semi-ellipsoidal breast shape of homogeneous mixture where air kerma is measured 65 cm from radiation source."
PyBDC/requirements.txt ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ customtkinter==5.2.2
2
+ matplotlib==3.8.0
3
+ numpy==1.26.0
4
+ pandas==1.3.4
5
+ tomli