unfortunately due to limits on SO I am unable to provide full scripts but this should be enough to illustrate the issue..
Main.py
import tkinter as tk
from tkinter import ttk, messagebox
import numpy as np
from model_5_inhalation_exposure_to_spray_spraying import create_parameter_frame as create_model5_frame, ExposureParameters as ExposureParametersModel5
class MainApplication:
def __init__(self, root):
self.root = root
self.root.title("Main Application")
# Create a canvas to hold the main frame and a scrollbar
self.canvas = tk.Canvas(self.root)
self.canvas.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
self.scrollbar = ttk.Scrollbar(self.root, orient=tk.VERTICAL, command=self.canvas.yview)
self.scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
self.canvas.configure(yscrollcommand=self.scrollbar.set)
self.canvas.bind('<Configure>', lambda e: self.canvas.configure(scrollregion=self.canvas.bbox("all")))
self.main_frame = ttk.Frame(self.canvas)
self.canvas.create_window((0, 0), window=self.main_frame, anchor="nw")
# Add Frequency and Body Weight entries
self.add_custom_parameters(self.main_frame)
# Create and display the Run Model button
self.run_model_button = ttk.Button(self.main_frame, text="Run Model", command=self.run_model)
self.run_model_button.pack(pady=10)
# Create a notebook (tabbed interface)
self.notebook = ttk.Notebook(self.main_frame)
self.notebook.pack(padx=10, pady=10, fill=tk.BOTH, expand=True)
# Create the Inhalation tab
self.inhalation_tab = ttk.Frame(self.notebook)
self.notebook.add(self.inhalation_tab, text="Inhalation")
# Create the exposure parameters frame
self.exposure_frame = ttk.Frame(self.inhalation_tab)
self.exposure_frame.pack(padx=10, pady=10, fill=tk.BOTH, expand=True)
self.ui_instance = create_model5_frame(self.exposure_frame, standalone=False, run_model_callback=self.run_model)
def add_custom_parameters(self, parent):
self.custom_params_frame = ttk.Frame(parent)
self.custom_params_frame.pack(pady=10, fill=tk.X)
# Frequency parameter
self.frequency_label = ttk.Label(self.custom_params_frame, text="Frequency")
self.frequency_label.grid(row=0, column=0, padx=5, pady=5, sticky=tk.W)
self.frequency_var = tk.StringVar(value="1")
self.frequency_entry = ttk.Entry(self.custom_params_frame, textvariable=self.frequency_var)
self.frequency_entry.grid(row=0, column=1, padx=5, pady=5, sticky=tk.EW)
self.frequency_unit_var = tk.StringVar(value="per year")
self.frequency_unit_dropdown = ttk.Combobox(self.custom_params_frame, textvariable=self.frequency_unit_var, state='readonly', width=15)
self.frequency_unit_dropdown['values'] = ["per year", "per day", "per week", "per month"]
self.frequency_unit_dropdown.grid(row=0, column=2, padx=5, pady=5, sticky=tk.EW)
# Body Weight parameter
self.bodyweight_label = ttk.Label(self.custom_params_frame, text="Body weight")
self.bodyweight_label.grid(row=1, column=0, padx=5, pady=5, sticky=tk.W)
self.bodyweight_var = tk.StringVar(value="70")
self.bodyweight_entry = ttk.Entry(self.custom_params_frame, textvariable=self.bodyweight_var)
self.bodyweight_entry.grid(row=1, column=1, padx=5, pady=5, sticky=tk.EW)
self.bodyweight_unit_var = tk.StringVar(value="kg")
self.bodyweight_unit_dropdown = ttk.Combobox(self.custom_params_frame, textvariable=self.bodyweight_unit_var, state='readonly', width=15)
self.bodyweight_unit_dropdown['values'] = ["kg"]
self.bodyweight_unit_dropdown.grid(row=1, column=2, padx=5, pady=5, sticky=tk.EW)
def run_model(self, params=None):
if params is None:
params = self.collect_parameters()
try:
frequency = float(self.frequency_entry.get())
body_weight = float(self.bodyweight_entry.get())
except ValueError:
print("Error: Invalid frequency or body weight value.")
return
try:
aerosol_diameter_mode = params.get("Aerosol diameter mode")
if aerosol_diameter_mode == "Log-normal":
if "Arithmetic coefficient of variation" not in params or params["Arithmetic coefficient of variation"] is None:
raise ValueError("Arithmetic coefficient of variation is not set for Log-normal mode.")
elif aerosol_diameter_mode == "Normal":
if "Standard deviation" not in params or params["Standard deviation"] is None:
raise ValueError("Standard deviation is not set for Normal mode.")
exposure_params = ExposureParametersModel5(
frequency=(frequency, self.frequency_unit_var.get()),
body_weight=(body_weight, self.bodyweight_unit_var.get()),
spray_duration=params["Spray duration"],
exposure_duration=params["Exposure duration"],
weight_fraction_substance=params["Weight fraction substance"],
room_volume=params["Room volume"],
room_height=params["Room height"],
ventilation_rate=params["Ventilation rate"],
inhalation_rate=params["Inhalation rate"],
spraying_towards_person=params["Spraying towards person"],
cloud_volume=params.get("Cloud volume"),
mass_generation_rate=params["Mass generation rate"],
airborne_fraction=params["Airborne fraction"],
density_non_volatile=params["Density non volatile"],
inhalation_cutoff_diameter=params["Inhalation cut off diameter"],
aerosol_diameter_mode=aerosol_diameter_mode,
median_diameter=params.get("Median diameter"),
arithmetic_coefficient_of_variation=params.get("Arithmetic coefficient of variation"),
mean_diameter=params.get("Mean diameter"),
standard_deviation=params.get("Standard deviation"),
maximum_diameter=params["Maximum diameter"]
)
self.display_final_results(exposure_params)
exposure_params.plot_results()
except KeyError as e:
print(f"Error: Missing parameter {e}")
print("Current parameter values:")
for key, value in params.items():
print(f"{key}: {value}")
except Exception as e:
print(f"An error occurred: {e}")
import traceback
traceback.print_exc()
def collect_parameters(self):
params = {}
if self.ui_instance and hasattr(self.ui_instance, 'widgets'):
for key, widget_info in self.ui_instance.widgets.items():
if isinstance(widget_info, dict) and 'entry' in widget_info:
value = widget_info['entry'].get()
unit = widget_info.get('unit')
if unit:
unit = unit.get()
if isinstance(value, str) and value.strip() and value.replace('.', '', 1).isdigit():
params[key] = (float(value), unit) if unit else float(value)
elif not value.strip(): # If the value is an empty string
params[key] = None
else:
params[key] = (value, unit) if unit else value
elif isinstance(widget_info, tk.BooleanVar):
params[key] = widget_info.get()
elif isinstance(widget_info, ttk.Combobox): # For dropdown menus
params[key] = widget_info.get()
# Add Aerosol diameter mode
if hasattr(self.ui_instance, 'aerosol_diameter_mode_var'):
params['Aerosol diameter mode'] = self.ui_instance.aerosol_diameter_mode_var.get()
print("Collected parameters:", params) # Debug statement
# Ensure Arithmetic coefficient of variation or Standard deviation is set
if params.get('Aerosol diameter mode') == 'Log-normal':
acv_widget = self.ui_instance.widgets.get('Arithmetic coefficient of variation')
if acv_widget and isinstance(acv_widget, dict) and 'entry' in acv_widget:
acv_value = acv_widget['entry'].get()
params['Arithmetic coefficient of variation'] = float(acv_value) if acv_value else None
elif params.get('Aerosol diameter mode') == 'Normal':
sd_widget = self.ui_instance.widgets.get('Standard deviation')
if sd_widget and isinstance(sd_widget, dict) and 'entry' in sd_widget:
sd_value = sd_widget['entry'].get()
params['Standard deviation'] = float(sd_value) if sd_value else None
print("Parameters after setting ACV/SD:", params) # Debug statement
return params
def display_final_results(self, exposure_params):
# Calculate and display results
mean_event_concentration = exposure_params.calculate_mean_event_concentration()
peak_concentration = exposure_params.calculate_peak_concentration()
mean_concentration_on_day_of_exposure = exposure_params.calculate_mean_concentration_on_day_of_exposure()
year_average_concentration = exposure_params.calculate_year_average_concentration()
external_event_dose = exposure_params.calculate_external_event_dose()
external_dose_on_day_of_exposure = exposure_params.calculate_external_dose_on_day_of_exposure()
print(f"Mean Event Concentration: {mean_event_concentration:.1e} mg/m³")
print(f"Peak Concentration (TWA 15 min): {peak_concentration:.1e} mg/m³")
print(f"Mean Concentration on Day of Exposure: {mean_concentration_on_day_of_exposure:.1e} mg/m³")
print(f"Year Average Concentration: {year_average_concentration:.1e} mg/m³")
print(f"External Event Dose: {external_event_dose:.1e} mg/kg bw")
print(f"External Dose on Day of Exposure: {external_dose_on_day_of_exposure:.1e} mg/kg bw")
if __name__ == "__main__":
root = tk.Tk()
app = MainApplication(root)
root.mainloop()
model_5_inhalation_exposure_to_spray_spraying.py
import tkinter as tk
from tkinter import ttk, messagebox
class ExposureParameters:
def __init__(self, frequency, body_weight, spray_duration, exposure_duration, weight_fraction_substance, room_volume, room_height, ventilation_rate, inhalation_rate, spraying_towards_person, cloud_volume, mass_generation_rate, airborne_fraction, density_non_volatile, inhalation_cutoff_diameter, aerosol_diameter_mode, median_diameter=None, arithmetic_coefficient_of_variation=None, mean_diameter=None, standard_deviation=None, maximum_diameter=None):
self.frequency = frequency
self.body_weight = body_weight
self.spray_duration = spray_duration
self.exposure_duration = exposure_duration
self.weight_fraction_substance = weight_fraction_substance
self.room_volume = room_volume
self.room_height = room_height
self.ventilation_rate = ventilation_rate
self.inhalation_rate = inhalation_rate
self.spraying_towards_person = spraying_towards_person
self.cloud_volume = cloud_volume
self.mass_generation_rate = mass_generation_rate
self.airborne_fraction = airborne_fraction
self.density_non_volatile = density_non_volatile
self.inhalation_cutoff_diameter = inhalation_cutoff_diameter
self.aerosol_diameter_mode = aerosol_diameter_mode
self.median_diameter = median_diameter
self.arithmetic_coefficient_of_variation = arithmetic_coefficient_of_variation
self.mean_diameter = mean_diameter
self.standard_deviation = standard_deviation
self.maximum_diameter = maximum_diameter
self.display_parameters()
def display_parameters(self):
params = {
"Frequency": self.frequency,
"Body weight": self.body_weight,
"Spray duration": self.spray_duration,
"Exposure duration": self.exposure_duration,
"Weight fraction substance": self.weight_fraction_substance,
"Room volume": self.room_volume,
"Room height": self.room_height,
"Ventilation rate": self.ventilation_rate,
"Inhalation rate": self.inhalation_rate,
"Spraying towards person": self.spraying_towards_person,
"Cloud volume": self.cloud_volume,
"Mass generation rate": self.mass_generation_rate,
"Airborne fraction": self.airborne_fraction,
"Density non volatile": self.density_non_volatile,
"Inhalation cut off diameter": self.inhalation_cutoff_diameter,
"Aerosol diameter mode": self.aerosol_diameter_mode,
"Median diameter": self.median_diameter,
"Arithmetic coefficient of variation": self.arithmetic_coefficient_of_variation,
"Mean diameter": self.mean_diameter,
"Standard deviation": self.standard_deviation,
"Maximum diameter": self.maximum_diameter
}
for key, value in params.items():
print(f"{key}: {value}")
class ExposureUI:
def __init__(self, root, standalone=True, run_model_callback=None, external_params=None):
self.root = root
self.run_model_callback = run_model_callback
self.standalone = standalone
self.external_params = external_params if external_params else {}
if standalone:
self.root.title("Exposure Parameters - Spraying")
self.units = {
"frequency": ["per year"],
"body_weight": ["kg"],
"duration": ["minute"],
"weight_fraction": ["(fraction)"],
"room_volume": ["m³"],
"room_height": ["m"],
"ventilation_rate": ["per hour"],
"inhalation_rate": ["l/min"],
"mass_generation_rate": ["g/s"],
"airborne_fraction": ["(fraction)"],
"density_non_volatile": ["g/cm³"],
"inhalation_cutoff_diameter": ["μm"],
"cloud_volume": ["m³"],
"aerosol_diameter_mode": ["Log-normal", "Normal"]
}
self.widgets = {}
start_row = 0
if self.standalone:
self.create_label_entry_dropdown("Frequency", "1", self.units["frequency"], start_row)
start_row += 1
self.create_label_entry_dropdown("Body weight", "65", self.units["body_weight"], start_row)
start_row += 1
self.create_label_entry_dropdown("Spray duration", "11.1", self.units["duration"], start_row)
start_row += 1
self.create_label_entry_dropdown("Exposure duration", "13", self.units["duration"], start_row)
start_row += 1
self.create_label_entry_dropdown("Weight fraction substance", "0.6", self.units["weight_fraction"], start_row)
start_row += 1
self.create_label_entry_dropdown("Room volume", "10", self.units["room_volume"], start_row)
start_row += 1
self.create_label_entry_dropdown("Room height", "2.5", self.units["room_height"], start_row)
start_row += 1
self.create_label_entry_dropdown("Ventilation rate", "2", self.units["ventilation_rate"], start_row)
start_row += 1
self.create_label_entry_dropdown("Inhalation rate", "24.1", self.units["inhalation_rate"], start_row)
start_row += 1
self.create_boolean_checkbox("Spraying towards person", False, start_row)
start_row += 1
self.optional_frame_cloud_volume = tk.Frame(self.root)
self.create_label_entry_dropdown("Cloud volume", "10", self.units["cloud_volume"], 0, self.optional_frame_cloud_volume)
self.optional_frame_cloud_volume.grid(row=start_row, columnspan=3, pady=5)
start_row += 1
self.create_label_entry_dropdown("Mass generation rate", "0.8", self.units["mass_generation_rate"], start_row)
start_row += 1
self.create_label_entry_dropdown("Airborne fraction", "0.008", self.units["airborne_fraction"], start_row)
start_row += 1
self.create_label_entry_dropdown("Density non volatile", "1.8", self.units["density_non_volatile"], start_row)
start_row += 1
self.create_label_entry_dropdown("Inhalation cut off diameter", "15", self.units["inhalation_cutoff_diameter"], start_row)
start_row += 1
self.aerosol_diameter_mode_var = tk.StringVar(value="Log-normal")
self.create_radio_buttons("Aerosol diameter mode", self.units["aerosol_diameter_mode"], self.aerosol_diameter_mode_var, start_row)
start_row += 1
self.aerosol_diameter_frame = tk.Frame(self.root)
self.create_label_entry_dropdown("Median diameter", "7.7", ["μm"], 0, self.aerosol_diameter_frame)
self.create_label_entry_entry("Arithmetic coefficient of variation", "1.9", 1, self.aerosol_diameter_frame)
self.create_label_entry_dropdown("Maximum diameter", "50", ["μm"], 2, self.aerosol_diameter_frame)
self.aerosol_diameter_frame.grid(row=start_row, columnspan=3, pady=5)
self.toggle_optional_parameters()
self.toggle_aerosol_diameter_mode()
if standalone:
self.run_model_button = ttk.Button(self.root, text="Run Model", command=self.run_model)
self.run_model_button.grid(row=start_row + 1, columnspan=3, pady=10)
def create_label_entry_dropdown(self, text, default_value, unit_options, row, parent=None):
if parent is None:
parent = self.root
label = ttk.Label(parent, text=text)
label.grid(row=row, column=0, padx=5, pady=5, sticky=tk.W)
entry = ttk.Entry(parent)
entry.insert(0, default_value)
entry.grid(row=row, column=1, padx=5, pady=5)
unit_dropdown = ttk.Combobox(parent, values=unit_options, state='readonly')
unit_dropdown.set(unit_options[0])
unit_dropdown.grid(row=row, column=2, padx=5, pady=5)
self.widgets[text] = {'entry': entry, 'unit': unit_dropdown}
def create_label_entry_entry(self, text, default_value, row, parent=None):
if parent is None:
parent = self.root
label = ttk.Label(parent, text=text)
label.grid(row=row, column=0, padx=5, pady=5, sticky=tk.W)
entry = ttk.Entry(parent)
entry.insert(0, default_value)
entry.grid(row=row, column=1, padx=5, pady=5)
self.widgets[text] = entry
def create_boolean_checkbox(self, text, default_value, row, parent=None):
if parent is None:
parent = self.root
var = tk.BooleanVar(value=default_value)
checkbox = ttk.Checkbutton(parent, text=text, variable=var, command=self.toggle_optional_parameters)
checkbox.grid(row=row, columnspan=3, sticky=tk.W, pady=5)
self.widgets[text] = var
def create_radio_buttons(self, text, options, variable, row, parent=None):
if parent is None:
parent = self.root
label = ttk.Label(parent, text=text)
label.grid(row=row, column=0, padx=5, pady=5, sticky=tk.W)
frame = tk.Frame(parent)
for option in options:
button = ttk.Radiobutton(frame, text=option, variable=variable, value=option, command=self.toggle_aerosol_diameter_mode)
button.pack(side=tk.LEFT)
frame.grid(row=row, column=1, columnspan=2, pady=5)
def toggle_optional_parameters(self):
spraying_towards_person = self.widgets["Spraying towards person"].get()
if spraying_towards_person:
self.optional_frame_cloud_volume.grid()
else:
self.optional_frame_cloud_volume.grid_remove()
def toggle_aerosol_diameter_mode(self):
mode = self.aerosol_diameter_mode_var.get()
for widget in self.aerosol_diameter_frame.winfo_children():
widget.destroy()
if mode == "Log-normal":
self.create_label_entry_dropdown("Median diameter", "7.7", ["μm"], 0, self.aerosol_diameter_frame)
self.create_label_entry_entry("Arithmetic coefficient of variation", "1.9", 1, self.aerosol_diameter_frame)
else:
self.create_label_entry_dropdown("Mean diameter", "7.7", ["μm"], 0, self.aerosol_diameter_frame)
self.create_label_entry_entry("Standard deviation", "0.5", 1, self.aerosol_diameter_frame)
self.create_label_entry_dropdown("Maximum diameter", "50", ["μm"], 2, self.aerosol_diameter_frame)
self.aerosol_diameter_frame.grid()
def run_model(self):
parameters = self.get_parameters()
try:
exposure_params = ExposureParameters(
frequency=parameters["Frequency"],
body_weight=parameters["Body weight"],
spray_duration=parameters["Spray duration"],
exposure_duration=parameters["Exposure duration"],
weight_fraction_substance=parameters["Weight fraction substance"],
room_volume=parameters["Room volume"],
room_height=parameters["Room height"],
ventilation_rate=parameters["Ventilation rate"],
inhalation_rate=parameters["Inhalation rate"],
spraying_towards_person=parameters["Spraying towards person"],
cloud_volume=parameters.get("Cloud volume"),
mass_generation_rate=parameters["Mass generation rate"],
airborne_fraction=parameters["Airborne fraction"],
density_non_volatile=parameters["Density non volatile"],
inhalation_cutoff_diameter=parameters["Inhalation cut off diameter"],
aerosol_diameter_mode=parameters["Aerosol diameter mode"],
median_diameter=parameters.get("Median diameter"),
arithmetic_coefficient_of_variation=parameters.get("Arithmetic coefficient of variation"),
mean_diameter=parameters.get("Mean diameter"),
standard_deviation=parameters.get("Standard deviation"),
maximum_diameter=parameters["Maximum diameter"]
)
except ValueError as e:
messagebox.showerror("Input Error", str(e))
def get_parameters(self):
params = {}
for key, widget_info in self.widgets.items():
if isinstance(widget_info, dict):
value = widget_info['entry'].get()
unit = widget_info['unit'].get()
if isinstance(value, str) and value.replace('.', '', 1).isdigit():
params[key] = (float(value), unit)
else:
params[key] = (value, unit)
elif isinstance(widget_info, tk.BooleanVar):
params[key] = widget_info.get()
elif isinstance(widget_info, ttk.Entry):
params[key] = float(widget_info.get())
params["Aerosol diameter mode"] = self.aerosol_diameter_mode_var.get()
if params["Aerosol diameter mode"] == "Log-normal":
acv_widget = self.widgets.get("Arithmetic coefficient of variation")
if acv_widget:
acv_value = acv_widget.get()
params["Arithmetic coefficient of variation"] = float(acv_value) if acv_value else None
else:
sd_widget = self.widgets.get("Standard deviation")
if sd_widget:
sd_value = sd_widget.get()
params["Standard deviation"] = float(sd_value) if sd_value else None
return params
def create_parameter_frame(parent, standalone=False, run_model_callback=None, external_params=None):
return ExposureUI(parent, standalone, run_model_callback, external_params)
if __name__ == "__main__":
root = tk.Tk()
app = ExposureUI(root, standalone=True)
root.mainloop()
this stripped back version is simply a UI and instead of functionality just prints the values passed to it.
However when I do I am getting the following error:
An error occurred: Arithmetic coefficient of variation is not set for Log-normal mode.
Traceback (most recent call last):
File “/Users/coding/Documents/Python/Work/NEW/testmini3.py”, line 86, in run_model
raise ValueError(“Arithmetic coefficient of variation is not set for Log-normal mode.”)
ValueError: Arithmetic coefficient of variation is not set for Log-normal mode.
My original question showed other models that worked just fine but im unable to show them here.
However effectively I just want to be able to pass the values from mainscript (which displays model5 in a frame) and have it run (print).