dhavalkadia-fda's picture
Upload 30 files
d0f9f3b verified
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Tue Feb 28 13:21:41 2023
@author: DIDSR
"""
# %% import necessary modules
import argparse
from tkinter import filedialog, Menu, IntVar, W
import customtkinter
import numpy as np
from matplotlib.pyplot import (
style as plt_style,
ioff as plt_ioff,
figure as plt_figure,
rcParams as params,
)
plt_ioff() # suppress pyplot popups
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import tomli
from dose_equations import (
Sarno_mono_dgn,
Sarno_poly_dgn,
sarno_dgnct,
Hernandez_hetero_mono_dgn,
exposure_per_fluence,
Sechopoulos_poly_dgn,
)
# %% to set more appropriate font size for the UI (example, running from container may require UI to have larger font size)
dict_font_size_set = {1: 14, 2: 24}
font_size = None
# %% important functions
# quit me function
def quit_me():
root.quit()
root.destroy()
# calculate polyenergetic normalized glandular dose coefficients (pDgN) from specified breast models
def calculate_pDgNct(*values):
keV = values[2]
I = values[3]
psiE = np.array(list(map(exposure_per_fluence, keV)))
if values[0] == "Sarno Koning":
variables = values[1]
DgNctE = np.array(
list(
map(
sarno_dgnct,
variables[:, 0],
variables[:, 1],
variables[:, 2],
variables[:, 3],
variables[:, 4],
variables[:, 5],
variables[:, 6],
variables[:, 7],
keV,
)
)
)
pDgN = np.sum(I * psiE * DgNctE) / np.sum(I * psiE)
elif values[0] == "Hernandez":
DgN_list = np.array(values[1])
pDgN = np.sum(I * psiE * DgN_list) / (np.sum(I * psiE))
return pDgN
# read method outputs display in GUI specifications for certian methods
with open("method_specific_inputs.toml", "rb") as file_method_specific_inputs:
config_method_specific_inputs = tomli.load(file_method_specific_inputs)
# %%% Main code
class Main_Window:
# %% build the gui frames
def __init__(self, master):
self.master = master
# create the menubar
menubar = Menu(master)
root.config(menu=menubar)
helpmenu = Menu(menubar, tearoff=0)
helpmenu.add_command(label="Quick Start Guide", command=self.help_command)
menubar.add_cascade(label="Help", menu=helpmenu)
menubar.add_command(label="Exit", command=lambda: quit_me())
# create the different frames
self.methods_frame = customtkinter.CTkFrame(master=master)
self.methods_frame.grid(row=0, column=0, ipady=36)
self.inputs_frame = customtkinter.CTkFrame(master=master)
self.inputs_frame.grid(row=0, column=1, padx=10, pady=5, ipadx=6)
self.kerma_spec_frame = customtkinter.CTkFrame(master=master)
self.kerma_spec_frame.grid(row=0, column=2, pady=5, ipady=24, ipadx=4)
self.output_frame = customtkinter.CTkFrame(master=master)
self.output_frame.grid(row=1, column=0, ipady=12)
self.graph_frame = customtkinter.CTkFrame(master=master)
self.graph_frame.grid(row=1, column=1, columnspan=2, padx=4, ipady=14)
# create figure
self.keV = []
self.I = []
self.plot_spectra()
# %% add the different methods
self.method_label = customtkinter.CTkLabel(
master=self.methods_frame,
text="Choose any of the following BCT methods:",
font=("Roman", font_size),
)
self.method_chosen = IntVar(root)
self.method_chosen.set(2)
self.current_method = 1
self.Sarno_radiobutton = customtkinter.CTkRadioButton(
master=self.methods_frame,
text="Sarno 49 kVp W Spectra",
command=lambda: self.change_inputs(),
variable=self.method_chosen,
value=1,
radiobutton_width=14,
radiobutton_height=14,
font=("Roman", font_size),
)
self.Sarno_incident_radiobutton = customtkinter.CTkRadioButton(
master=self.methods_frame,
text="Sarno Any Spectrum",
command=lambda: self.change_inputs(),
variable=self.method_chosen,
value=2,
radiobutton_width=14,
radiobutton_height=14,
font=("Roman", font_size),
)
self.Hernandez_radiobutton = customtkinter.CTkRadioButton(
master=self.methods_frame,
text="Hernandez Any Spectrum",
command=lambda: self.change_inputs(),
variable=self.method_chosen,
value=3,
radiobutton_width=14,
radiobutton_height=14,
font=("Roman", font_size),
)
self.Sechopoulos_radiobutton = customtkinter.CTkRadioButton(
master=self.methods_frame,
text="Sechopoulos 49 kVp W Spectra",
command=lambda: self.change_inputs(),
variable=self.method_chosen,
value=4,
radiobutton_width=14,
radiobutton_height=14,
font=("Roman", font_size),
)
self.method_label.pack(padx=20, pady=5, anchor=W)
self.Sarno_incident_radiobutton.pack(padx=20, pady=5, anchor=W)
self.Hernandez_radiobutton.pack(padx=20, pady=5, anchor=W)
self.Sarno_radiobutton.pack(padx=20, pady=5, anchor=W)
self.Sechopoulos_radiobutton.pack(padx=20, pady=5, anchor=W)
# %% fill in the main input box
self.Breast_diameter_label = customtkinter.CTkLabel(
master=self.inputs_frame,
text="Breast Diameter (cm):",
font=("Roman", font_size),
)
self.Breast_diameter_combo = customtkinter.CTkComboBox(
master=self.inputs_frame,
values=["8", "10", "12", "14", "19", "18"],
width=120,
state="readonly",
font=("Roman", font_size),
)
self.Breast_diameter_combo.set("8")
self.Breast_height_label = customtkinter.CTkLabel(
master=self.inputs_frame, text="Breast Height:", font=("Roman", font_size)
)
self.Breast_height_combo = customtkinter.CTkComboBox(
master=self.inputs_frame,
values=["1 x radius", "1.5 x radius", "2 x radius"],
width=120,
state="readonly",
font=("Roman", font_size),
)
self.Breast_height_combo.set("1 x radius")
self.Breast_glandularity_label = customtkinter.CTkLabel(
master=self.inputs_frame,
text="Breast Glandularity:",
font=("Roman", font_size),
)
self.Breast_glandularity_combo = customtkinter.CTkComboBox(
master=self.inputs_frame,
values=["0.1%", "14.3%", "25%", "50%", "100%"],
width=120,
state="readonly",
font=("Roman", font_size),
)
self.Breast_glandularity_combo.set("0.1%")
self.HVL_label = customtkinter.CTkLabel(
master=self.inputs_frame, text="HVL (mm Al):", font=("Roman", font_size)
)
self.HVL_combo = customtkinter.CTkComboBox(
master=self.inputs_frame,
values=["1.25", "1.30", "1.35", "1.40", "1.45", "1.50"],
width=120,
state="readonly",
font=("Roman", font_size),
)
self.HVL_combo.set("1.25")
self.VGF_label = customtkinter.CTkLabel(
master=self.inputs_frame,
text="Heterogeneous Categories:",
font=("Roman", font_size),
)
self.VGF_combo = customtkinter.CTkComboBox(
master=self.inputs_frame,
values=["V1 = 19.9%", "V3 = 9.5%", "V5 = 3.8%"],
width=120,
state="readonly",
font=("Roman", font_size),
) # V1 = 19.9%, V3 = 9.5%, V5 = 3.8%
self.VGF_combo.set("V1 = 19.9%")
self.input_spectra_button = customtkinter.CTkButton(
master=self.inputs_frame,
fg_color=("black", "lightgray"),
width=100,
border_width=0,
corner_radius=2,
text="Upload Incident Spectrum File",
font=("Roman", font_size),
command=lambda: self.browse_files(),
)
self.Breast_diameter_label.grid(row=0, column=0, pady=5, padx=4, sticky=W)
self.Breast_diameter_combo.grid(row=0, column=1, pady=5, padx=10, sticky=W)
self.Breast_height_label.grid(row=1, column=0, pady=5, padx=4, sticky=W)
self.Breast_height_combo.grid(row=1, column=1, pady=5)
self.Breast_glandularity_label.grid(row=2, column=0, pady=5, padx=4, sticky=W)
self.Breast_glandularity_combo.grid(row=2, column=1, pady=5)
self.HVL_label.grid(row=3, column=0, pady=5, padx=4, sticky=W)
self.HVL_combo.grid(row=3, column=1, pady=5)
self.HVL_combo.configure(state="disabled")
self.VGF_label.grid(row=4, column=0, pady=5, padx=4, sticky=W)
self.VGF_combo.grid(row=4, column=1, pady=5, padx=12, sticky=W)
self.VGF_combo.configure(state="disabled")
self.input_spectra_button.grid(row=5, column=0, pady=5, columnspan=2)
# %% create text box and buttons for output frame
self.output_textbox = customtkinter.CTkTextbox(
self.output_frame, width=285, height=305, font=("Roman", font_size)
)
self.output_textbox.tag_config("green", foreground="green")
self.output_textbox.configure(state="normal")
self.output_textbox.insert(
"end",
f'{"".join(config_method_specific_inputs["method_specific_inputs"]["Sarno_specific_outputs"])}',
"green",
)
self.output_textbox.configure(state="disabled")
self.clear_button = customtkinter.CTkButton(
master=self.output_frame,
width=120,
border_width=0,
corner_radius=8,
text="Clear Text",
font=("Roman", font_size),
command=lambda: self.clear_text(),
)
self.calculate_button = customtkinter.CTkButton(
master=self.output_frame,
width=120,
border_width=0,
corner_radius=8,
text="Calculate Dose",
font=("Roman", font_size),
command=lambda: self.calculate_dose(),
)
self.clear_button.grid(row=1, column=0, pady=5, padx=4)
self.output_textbox.grid(row=0, column=0, columnspan=3)
self.output_textbox.configure(state="disabled") # insert at line 0 character 0
self.calculate_button.grid(row=1, column=1, pady=5, padx=4)
# %% create air kerma inputs
self.mAs_label = customtkinter.CTkLabel(
master=self.kerma_spec_frame,
text="mAs per Projection:",
font=("Roman", font_size),
)
self.mAs_entry = customtkinter.CTkEntry(master=self.kerma_spec_frame, width=80)
self.mAs_units_combo = customtkinter.CTkComboBox(
master=self.kerma_spec_frame,
values=["mAs"],
width=80,
state="readonly",
font=("Roman", font_size),
)
self.air_kerma_label = customtkinter.CTkLabel(
master=self.kerma_spec_frame,
text="Air kerma per Projection:",
font=("Roman", font_size),
)
self.air_kerma_entry = customtkinter.CTkEntry(
master=self.kerma_spec_frame, width=80
)
self.input_label = customtkinter.CTkLabel(
master=self.kerma_spec_frame,
text="Air kerma Units:",
font=("Roman", font_size),
)
self.air_kerma_units_combo = customtkinter.CTkComboBox(
master=self.kerma_spec_frame,
values=["mrad", "mGy", "R", "mR"],
width=80,
state="readonly",
font=("Roman", font_size),
)
self.air_kerma_units_combo.set("R")
self.air_kerma_output_label = customtkinter.CTkLabel(
master=self.kerma_spec_frame,
text="MGD Units:",
anchor=W,
font=("Roman", font_size),
)
self.output_units = customtkinter.CTkComboBox(
master=self.kerma_spec_frame,
values=["mrad", "mGy"],
width=80,
state="readonly",
font=("Roman", font_size),
)
self.output_units.set("mrad")
self.number_projections_label = customtkinter.CTkLabel(
master=self.kerma_spec_frame,
text="Number of Projections: ",
font=("Roman", font_size),
)
self.number_projections_entry = customtkinter.CTkEntry(
master=self.kerma_spec_frame, width=80
)
self.graph_spectra = customtkinter.CTkButton(
master=self.kerma_spec_frame,
width=220,
border_width=1,
corner_radius=10,
text="Graph Spectrum",
font=("Roman", font_size),
command=self.plot_spectra,
)
self.air_kerma_label.grid(row=1, column=0, pady=5, padx=4, sticky=W)
self.air_kerma_entry.grid(row=1, column=1, pady=5, padx=12, sticky=W)
self.number_projections_label.grid(row=2, column=0, pady=5, padx=4, sticky=W)
self.number_projections_entry.grid(row=2, column=1, pady=5, padx=12, sticky=W)
self.mAs_label.grid(row=5, column=0, pady=5, padx=4, sticky=W)
self.mAs_entry.grid(row=5, column=1, pady=5, padx=12, sticky=W)
self.input_label.grid(row=3, column=0, pady=5, padx=4, sticky=W)
self.air_kerma_units_combo.grid(row=3, column=1, pady=5, padx=12, sticky=W)
self.air_kerma_output_label.grid(row=4, column=0, pady=5, padx=4, sticky=W)
self.output_units.grid(row=4, column=1, pady=5, padx=12, sticky=W)
self.graph_spectra.grid(row=6, column=0, pady=5, columnspan=2)
self.graph_spectra.configure(state="disabled")
# %% important functions
# add help command
def help_command(self):
pop_up = customtkinter.CTkToplevel()
textbox = customtkinter.CTkTextbox(master=pop_up, width=800, height=500)
textbox.pack(fill="both")
with open("CT_Dose_Calculate_Quick_Guide.txt", "r") as file:
data = file.read()
textbox.insert("end", f"{data}")
textbox.configure(state="disabled")
# change the method specific inputs based on selection
def change_inputs(self):
current_method = self.method_chosen.get()
if current_method == 1: # Sarno 49 kVp W Spectra
# enable and disable buttons
self.VGF_combo.configure(state="disabled")
self.input_spectra_button.configure(state="disabled")
self.Breast_diameter_combo.configure(state="normal")
self.Breast_height_combo.configure(state="normal")
self.Breast_glandularity_combo.configure(state="normal")
self.HVL_combo.configure(state="normal")
self.graph_spectra.configure(state="disabled")
self.Breast_glandularity_combo.configure(
values=["0.1%", "14.3%", "25%", "50%", "75%", "100%"]
)
self.Breast_glandularity_combo.set("0.1%")
self.Breast_diameter_combo.configure(
values=["8", "10", "12", "14", "19", "18"]
)
self.Breast_diameter_combo.set("8")
self.Breast_height_combo.configure(
values=["1 x radius", "1.5 x radius", "2 x radius"]
)
self.Breast_height_combo.set("1 x radius")
self.output_textbox.configure(state="normal")
self.output_textbox.delete("0.0", "end")
self.output_textbox.configure(state="normal")
self.output_textbox.insert(
"end",
f'{"".join(config_method_specific_inputs["method_specific_inputs"]["Sarno_49_specific_output"])}',
"green",
)
self.output_textbox.configure(state="disabled")
self.keV = []
self.I = []
self.plot_spectra()
elif current_method == 2: # Sarno any spectrum
self.VGF_combo.configure(state="disabled")
self.input_spectra_button.configure(state="normal")
self.Breast_diameter_combo.configure(state="normal")
self.Breast_height_combo.configure(state="normal")
self.Breast_glandularity_combo.configure(state="normal")
self.HVL_combo.configure(state="disabled")
self.graph_spectra.configure(state="disabled")
self.Breast_glandularity_combo.configure(
values=["0.1%", "14.3%", "25%", "50%", "75%", "100%"]
)
self.Breast_glandularity_combo.set("0.1%")
self.Breast_diameter_combo.configure(
values=["8", "10", "12", "14", "19", "18"]
)
self.Breast_diameter_combo.set("8")
self.Breast_height_combo.configure(
values=["1 x radius", "1.5 x radius", "2 x radius"]
)
self.Breast_height_combo.set("1 x radius")
self.output_textbox.configure(state="normal")
self.output_textbox.delete("0.0", "end")
self.output_textbox.insert(
"end",
f'{"".join(config_method_specific_inputs["method_specific_inputs"]["Sarno_specific_outputs"])}',
"green",
)
self.output_textbox.configure(state="disabled")
self.keV = []
self.I = []
self.plot_spectra()
elif current_method == 3: # Hernandez any spectrum
self.VGF_combo.configure(state="normal")
self.input_spectra_button.configure(state="normal")
self.Breast_diameter_combo.configure(state="disabled")
self.Breast_height_combo.configure(state="disabled")
self.Breast_glandularity_combo.configure(state="disabled")
self.HVL_combo.configure(state="disabled")
self.graph_spectra.configure(state="disabled")
self.output_textbox.configure(state="normal")
self.output_textbox.delete("0.0", "end")
self.output_textbox.insert(
"end",
f'{"".join(config_method_specific_inputs["method_specific_inputs"]["Hernandez_specific_output"])}',
"green",
)
self.output_textbox.configure(state="disabled")
self.keV = []
self.I = []
self.plot_spectra()
else: # Sechopoulus method
self.VGF_combo.configure(state="disabled")
self.input_spectra_button.configure(state="disabled")
self.Breast_diameter_combo.configure(state="normal")
self.Breast_height_combo.configure(state="normal")
self.Breast_glandularity_combo.configure(state="normal")
self.HVL_combo.configure(state="disabled")
self.graph_spectra.configure(state="disabled")
self.output_textbox.configure(state="normal")
self.output_textbox.delete("0.0", "end")
self.output_textbox.insert(
"end",
f'{"".join(config_method_specific_inputs["method_specific_inputs"]["Sechopoulos_specific_output"])}',
"green",
)
self.output_textbox.configure(state="disabled")
self.Breast_glandularity_combo.configure(
values=["1%", "14.3%", "25%", "50%", "75%", "100%"]
)
self.Breast_glandularity_combo.set("1%")
self.Breast_diameter_combo.configure(values=["10", "12", "14", "19", "18"])
self.Breast_diameter_combo.set("10")
self.Breast_height_combo.configure(
values=["0.5 x diameter", "0.75 x diameter", "1 x diameter"]
)
self.Breast_height_combo.set("0.5 x diameter")
self.keV = []
self.I = []
self.plot_spectra()
# browse for incident spectrum
def browse_files(self):
# read and output textfile
self.input_txt_file = filedialog.askopenfilename(
initialdir="/", title="Select a File", filetypes=[("all files", "*.*")]
)
self.display_txt_file = self.input_txt_file.split("/")[-1]
self.output_textbox.configure(state="normal")
self.output_textbox.insert(
"end", f"\nInputted incident spectrum: \n{self.display_txt_file}", "\n"
)
self.output_textbox.configure(state="disabled")
try:
# get keV and I
self.keV, self.I = self.read_input_spectra()
self.minimum = min(self.keV)
self.maximum = max(self.keV)
method = self.method_chosen.get()
if method == 3:
if self.minimum < 9 or self.maximum > 70:
raise (ValueError)
elif method == 2:
if self.minimum < 8 or self.maximum > 80:
raise (ValueError)
self.graph_spectra.configure(state="normal")
# account for possible errors
except UnicodeDecodeError:
pop_up = customtkinter.CTkToplevel()
customtkinter.CTkLabel(
pop_up, text="Please enter a valid text file", font=("Roman", font_size)
).pack()
except ValueError:
pop_up = customtkinter.CTkToplevel()
customtkinter.CTkLabel(
pop_up,
text="For Hernadez Any spectrum, please enter spectrum ranging from 9 to 70 keV",
font=("Roman", font_size),
).pack()
customtkinter.CTkLabel(
pop_up,
text="For Sarno Any Spectrum, please enter spectrum ranging from 8 to 80 keV",
font=("Roman", font_size),
).pack()
# read input spectra
def read_input_spectra(self):
with open(self.input_txt_file, "r") as file:
keV = []
I = []
data = file.readlines()
for line in data:
line = line.split()
keV.append(float(line[0]))
I.append(float(line[1]))
return keV, I
# clear text
def clear_text(self):
self.output_textbox.configure(state="normal")
self.output_textbox.delete("0.0", "end")
self.output_textbox.configure(state="disabled")
# update plot
def plot_spectra(self):
try:
y_end = max(self.I) * 1.1
x_end = max(self.keV) * 1.1
file_name = self.display_txt_file
except:
x_end = 5
y_end = 5
file_name = "Input Incident Spectrum"
plt_style.use(["dark_background"])
params["figure.figsize"] = [7.50, 3.50]
params["figure.autolayout"] = True
self.figure = plt_figure(figsize=(7.6, 4.2), dpi=100)
axes = self.figure.add_subplot(111)
axes.plot(self.keV, self.I, "b-")
axes.set_title(f"{file_name}")
axes.set_xlabel("Energy (keV)", fontsize=11)
axes.set_ylabel("Intensity (counts)", fontsize=11)
axes.set_xlim(0, x_end)
axes.set_ylim([0, y_end])
chart = FigureCanvasTkAgg(self.figure, master=self.graph_frame)
chart.get_tk_widget().grid(row=0, column=0, columnspan=2)
# calculate mean glandur dosage from user specificed inputs
def calculate_mgd(
self, air_kerma_input, air_kerma, dgn, output_units, number_of_projections
):
# unit conversions based on user selection
if air_kerma_input != "mGy":
if air_kerma_input == "mrad":
air_kerma = air_kerma * 0.01 # convert from mrad air kerma to mGy
elif air_kerma_input == "R":
air_kerma = air_kerma * 8.77 # convert from R to mGy
elif air_kerma_input == "mR":
air_kerma = air_kerma * 0.00877 # convert from mR to mGy
mgd = air_kerma * dgn * float(number_of_projections) # in mGy/mGy
if output_units == "mrad":
mgd = mgd * 100 # converts mgd to mrad
return mgd
# write inputs to textbox
def output_dose(self, *values):
self.output_textbox.configure(state="normal")
self.output_textbox.insert(
"end", f"\n\nMGD = {self.mgd:.4f} {self.output_units.get()}"
)
self.output_textbox.insert(
"end", f" with {self.number_projections_entry.get()} projections"
)
self.output_textbox.insert("end", f" with {self.mAs_entry.get()} mAs")
for index in range(len(values)):
if index == 0 or index % 2 == 0:
self.output_textbox.insert("end", f"\n{values[index]}")
else:
self.output_textbox.insert("end", f"{values[index]}")
self.output_textbox.configure(state="disabled")
# function to calculate dose
def calculate_dose(self):
# get inputs
current_method = self.method_chosen.get()
air_kerma_input_units = self.air_kerma_units_combo.get()
output_units = self.output_units.get()
air_kerma = self.air_kerma_entry.get()
number_of_projections = self.number_projections_entry.get()
try:
# numbers only
air_kerma_check = len(air_kerma)
number_of_projections_check = len(number_of_projections)
air_kerma = float(air_kerma) # check if only numbers
mAs_per_projection = float(self.mAs_entry.get())
air_kerma = mAs_per_projection * air_kerma
if air_kerma_check == 0 or number_of_projections_check == 0:
raise (ValueError)
elif current_method == 2 or current_method == 3:
kev_check = len(self.keV)
if kev_check == 0:
raise (TypeError)
# calculate mgd based on specified model
if current_method == 1: # Sarno 49 kVp W spectra
# get parameters
HVL = self.HVL_combo.get()
breast_diameter = self.Breast_diameter_combo.get()
breast_glandularity = self.Breast_glandularity_combo.get()
breast_height = "".join(self.Breast_height_combo.get().split(" ")[0:2])
# calculate polyenergetic dgn coefficients
dgn_subtable_breast_height = Sarno_poly_dgn.groupby(
["breast height"]
).get_group(breast_height)
dgn_subtable_glandularity = dgn_subtable_breast_height.groupby(
["Glandularity"]
).get_group(breast_glandularity)
dgn = dgn_subtable_glandularity.loc[float(HVL), str(breast_diameter)]
# calculate mgd based on pdgn and input parameters
self.mgd = self.calculate_mgd(
air_kerma_input_units,
air_kerma,
dgn,
output_units,
number_of_projections,
)
self.output_dose(
"Breast diameter: ",
breast_diameter,
"HVL: ",
HVL,
"Breast_glandularity: ",
breast_glandularity,
"Breast Height: ",
self.Breast_height_combo.get(),
)
elif current_method == 2: # Sarno any spectrum
breast_diameter = self.Breast_diameter_combo.get()
breast_glandularity = self.Breast_glandularity_combo.get()
breast_height = "".join(self.Breast_height_combo.get().split(" ")[0:2])
# get dgn coefficients
dgn_subtable_breast_height = Sarno_mono_dgn.groupby(
["breast height"]
).get_group(breast_height)
dgn_subtable_glandularity = dgn_subtable_breast_height.groupby(
["Glandularity"]
).get_group(breast_glandularity)
values = dgn_subtable_glandularity[str(breast_diameter)].tolist()
variables = np.zeros((len(self.keV), len(values)))
for index in range(0, len(values)):
variables[:, index] = [float(values[index])] # *len(self.keV)
# calulate dgn
dgn = calculate_pDgNct(
"Sarno Koning", variables, self.keV, self.I
) # units of mGy/mGy
self.mgd = self.calculate_mgd(
air_kerma_input_units,
air_kerma,
dgn,
output_units,
number_of_projections,
)
self.output_dose(
"Breast diameter: ",
breast_diameter,
"Breast Glandularity: ",
breast_glandularity,
"Breast Height: ",
self.Breast_height_combo.get(),
)
elif current_method == 3: # Hernandez any spectrum
# get the VGF and DgN list from text file
VGF = self.VGF_combo.get().split("=")[0].strip()
DgN_list = Hernandez_hetero_mono_dgn.loc[:, VGF].tolist()
# index the list to fit keV
start_index = int(abs(self.minimum - 9))
if self.maximum != 70:
end_index = int(abs(self.maximum - 9)) + 1
else:
end_index = -1
# interpolate the DgN list if necessary
Hernandez_keV = list(np.arange(self.minimum, self.maximum + 1))
DgN_list = DgN_list[start_index:end_index]
interp_DgN_list = np.interp(self.keV, Hernandez_keV, DgN_list)
# get the DgN coefficients in mGy/mGy
dgn = calculate_pDgNct("Hernandez", interp_DgN_list, self.keV, self.I)
print(dgn)
# print(dgn)
self.mgd = self.calculate_mgd(
air_kerma_input_units,
air_kerma,
dgn,
output_units,
number_of_projections,
)
self.output_dose("VGF: ", self.VGF_combo.get())
else: # Sechopoulos method
# get parameters
breast_diameter = self.Breast_diameter_combo.get()
breast_glandularity = self.Breast_glandularity_combo.get()
breast_height = float(
self.Breast_height_combo.get().split("x")[0]
) * float(breast_diameter)
# calculate dgn for polyenergetic
dgn_subtable_breast_height = Sechopoulos_poly_dgn.groupby(
["Chest wall-to-nipple distance"]
).get_group(breast_height)
dgn = dgn_subtable_breast_height[breast_glandularity].tolist()[0]
# calculate mgd
self.mgd = self.calculate_mgd(
air_kerma_input_units,
air_kerma,
dgn,
output_units,
number_of_projections,
)
self.output_dose(
"Breast diameter: ",
breast_diameter,
"Breast_glandularity: ",
breast_glandularity,
"Breast Height: ",
self.Breast_height_combo.get(),
)
except ValueError: # error in air kerma inputs
pop_up = customtkinter.CTkToplevel()
if air_kerma_check == 0:
customtkinter.CTkLabel(
pop_up,
text="Please enter a numeric value into the air kerma entry box or into \nthe number of projections box",
font=("Roman", font_size),
).pack()
else:
customtkinter.CTkLabel(
pop_up,
text="Please enter only numbers into the air kerma and ensure \nthat a numeric value is placed into the number of projections",
font=("Roman", font_size),
).pack()
except TypeError: # error in incident spectrum
pop_up = customtkinter.CTkToplevel()
customtkinter.CTkLabel(
pop_up,
text="Please enter an incident spectrum",
font=("Roman", font_size),
).pack()
# %%% Executable Code
parser = argparse.ArgumentParser()
parser.add_argument(
"--font_size_set",
nargs="?",
default=1,
type=int,
help="select the font size set (default=1 is the first set)",
)
args = parser.parse_args()
font_size = dict_font_size_set[args.font_size_set]
font_size = dict_font_size_set[args.font_size_set]
customtkinter.set_appearance_mode("light")
root = customtkinter.CTk()
root.title("BCT Dose Calculator")
CT_dose = Main_Window(root)
root.protocol("WM_DELETE_WINDOW", quit_me)
root.mainloop()