From d84f880c331f1ed3851afe392f758ae47cc171c3 Mon Sep 17 00:00:00 2001
From: Wojciech Wojnowski <wojciech.wojnowski@pg.edu.pl>
Date: Thu, 14 Oct 2021 09:43:29 +0000
Subject: [PATCH] Update main.py

---
 main.py | 386 +++++++++++++++++++++++++++++++-------------------------
 1 file changed, 214 insertions(+), 172 deletions(-)

diff --git a/main.py b/main.py
index 6e62803..8772888 100644
--- a/main.py
+++ b/main.py
@@ -2,6 +2,7 @@
 W.Wojnowski 2021
 '''
 # imports:
+import ast
 import tkinter as tk
 from tkinter import ttk
 from tkinter import messagebox
@@ -28,7 +29,7 @@ colors = {
     'background': '#dfe4ea',
     'accent': '#70a1ff',
     'text': 'black'
-    }
+}
 
 # configure the background:
 root.configure(bg=colors['background'], padx=8, pady=8)
@@ -95,6 +96,19 @@ s.theme_create("AGREE_2.0_theme", parent="alt", settings={
             "foreground": [("active", colors['text'])],
             'indicatorcolor': [('selected', colors['accent'])]
         }},
+    'TCheckbutton': {
+        'configure': {
+            'focuscolor': colors['foreground'],
+            'background': colors['foreground'],
+            'foreground': colors['text'],
+            'indicatorcolor': colors['background']},
+        "map": {
+            "background": [("active", colors['accent']),
+                           ("pressed", colors['accent']),
+                           ("disabled", colors['accent'])],
+            "foreground": [("active", colors['text'])],
+            'indicatorcolor': [('selected', colors['accent'])]
+        }},
     'TMenubutton': {
         'configure': {
             'background': colors['accent'],
@@ -171,13 +185,13 @@ def reset_scores():
         criterion.optionvar_b.set('Select')
 
     criteria[0].radiovar.set(1)
-    criteria[1].radiovar.set(4)
-    criteria[2].radiovar.set(5)
-    criteria[3].radiovar.set(2)
+    criteria[1].radiovar.set(5)
+    criteria[2].radiovar.set(2)
+    criteria[3].radiovar.set(4)
     criteria[4].radiovar.set(4)
-    criteria[5].radiovar.set(4)
-    criteria[6].radiovar.set(3)
-    criteria[7].radiovar.set(1)
+    criteria[5].radiovar.set(3)
+    criteria[6].radiovar.set(1)
+    criteria[7].radiovar.set(4)
     criteria[8].radiovar.set(3)
     criteria[9].radiovar.set(4)
 
@@ -307,13 +321,13 @@ for i in range(1, 11):
 # assign the default weights (this could be done using itemgetter or itertools.compress, but
 # that would require importing additional packages):
 criteria[0].radiovar.set(1)
-criteria[1].radiovar.set(4)
-criteria[2].radiovar.set(5)
-criteria[3].radiovar.set(2)
+criteria[1].radiovar.set(5)
+criteria[2].radiovar.set(2)
+criteria[3].radiovar.set(4)
 criteria[4].radiovar.set(4)
-criteria[5].radiovar.set(4)
-criteria[6].radiovar.set(3)
-criteria[7].radiovar.set(1)
+criteria[5].radiovar.set(3)
+criteria[6].radiovar.set(1)
+criteria[7].radiovar.set(4)
 criteria[8].radiovar.set(3)
 criteria[9].radiovar.set(4)
 
@@ -335,7 +349,6 @@ def clear_frame(frame):
     global right_frame
     right_frame = tk.Frame(root, bd=1, padx=2, pady=2, width=500, height=500, bg=colors['foreground'])
     right_frame.pack(side='right', anchor='n')
-    print('clear frame done')
 
 
 # connect a float in range 0.0 : 1.0 to a colour in a spectrum from red to yellow to green
@@ -419,7 +432,7 @@ def create_plot(event=None):
     plot_widget = canvas.get_tk_widget()
     plot_widget.pack(side='top')
 
-    print('final score: %s' % calculate_score())
+    # print('final score: %s' % calculate_score())
 
 
 # start the GUI with a default plot
@@ -454,13 +467,11 @@ class Report:
         self.pdf.cell(100, 12, datetime.now().strftime("%d/%m/%Y %H:%M:%S"))
         self.pdf.ln(30)
 
-
         def fieldColor(score):
             x = colorMapper(score)[0] * 255
             y = colorMapper(score)[1] * 255
             z = colorMapper(score)[2] * 255
             self.pdf.set_fill_color(x, y, z)
-            print(x, y, z)
 
         def create_header():
             self.pdf.set_font('Helvetica', 'B', 10)
@@ -498,26 +509,27 @@ class Report:
                             ('Sample preparation placement: ' + self.criteria[0].optionvar.get()))
 
         create_report_field('2.', self.tabs[1], self.criteria[1],
-                            ('Mass [g] or volume [mL] of waste: ' + self.criteria[1].valuevar.get()))
+                            ('Mass [g] or volume [mL] of problematic materials: ' + self.criteria[1].valuevar.get()))
 
         create_report_field('3.', self.tabs[2], self.criteria[2],
-                            ('Mass [g] or volume [mL] of problematic materials: ' + self.criteria[2].valuevar.get()))
+                            (self.criteria[2].optionvar.get()))
 
         create_report_field('4.', self.tabs[3], self.criteria[3],
-                            (self.criteria[3].optionvar.get()))
+                            ('Mass [g] or volume [mL] of waste: ' + self.criteria[3].valuevar.get()))
 
         create_report_field('5.', self.tabs[4], self.criteria[4],
                             ('Mass [g] or volume [mL] of the sample: ' + self.criteria[4].valuevar.get()))
 
         create_report_field('6.', self.tabs[5], self.criteria[5],
-                            ('Approximate energy consumption per analysis [W]: ' + self.criteria[5].valuevar.get()))
+                            ('Hourly sample throughput: ' + self.criteria[5].valuevar.get()))
 
         create_report_field('7.', self.tabs[6], self.criteria[6],
-                            ('Hourly sample throughput: ' + self.criteria[6].valuevar.get()))
+                            ('No. of sample prep. steps: ' + self.criteria[6].optionvar_a.get() +
+                             '; degree if automation: ' + self.criteria[6].optionvar_b.get()))
 
         create_report_field('8.', self.tabs[7], self.criteria[7],
-                            ('No. of sample prep. steps: ' + self.criteria[7].optionvar_a.get() +
-                             '; degree if automation: ' + self.criteria[7].optionvar_b.get()))
+                            ('Approximate energy consumption per analysis [W]: ' +
+                             str(round(float(self.criteria[7].valuevar.get()), 2))))
 
         create_report_field('9.', self.tabs[8], self.criteria[8],
                             (self.criteria[8].optionvar.get()))
@@ -559,11 +571,19 @@ dropdown1['menu'].config(background=colors['background'],
 
 dropdown1.grid(column=0, row=3, padx=8, pady=8, sticky='w')
 
-# # --------------------------- TAB2 ---------------------------
-tab2 = Tab(tab_no='2', title='Waste',
-           text1='In analytical chemistry, all material inputs, including '
-                 'the sample preparation stage, can be treated as waste.',
-           text2='Input mass [g] or volume [mL] of waste:', criterion=criteria[1])
+# --------------------------- TAB2 ---------------------------
+tab2 = Tab(tab_no='2', title='Hazardous materials',
+           text1='The use of toxic materials, including the use of acids and bases '
+                 'for derivatization and digestion, should be avoided.',
+           text2='Input mass [g] or volume [mL] of problematic substances:',
+           criterion=criteria[1])
+
+label_tab2 = ttk.Label(tab2.frame, text='Include substances that are toxic via one of exposure pathways or '
+                                        'labeled as bioaccumulative, persistent, highly flammable, highly '
+                                        'oxidizable, explosive, or corrosive.',
+                       wraplength=280)
+label_tab2.grid(column=0, row=4, sticky='w')
+
 # create a frame to pack the entry into in order to get a border for the entry:
 f2 = tk.Frame(tab2.frame, border=2, background=colors['accent'])
 f2.grid(column=0, row=3, padx=8, pady=8, sticky='w')
@@ -576,13 +596,13 @@ def calc_crit_2(event=None):
     try:
         if criteria[1].valuevar.get() == 'Input':
             criteria[1].textvar.set(1.0)
-        elif float(criteria[1].valuevar.get()) >= 50:
+        elif float(criteria[1].valuevar.get()) >= 10:
             criteria[1].textvar.set(0)
-        elif float(criteria[1].valuevar.get()) <= 0.1:
+        elif float(criteria[1].valuevar.get()) <= 0.01:
             criteria[1].textvar.set(1.0)
         else:
             criteria[1].textvar.set(
-                abs(-0.174 * log(float(criteria[1].valuevar.get())) + 0.6125))
+                abs(-0.147 * log(float(criteria[1].valuevar.get())) + 0.3299))
     except ValueError:
         messagebox.showerror(title='Value error',
                              message='The amount has to be a float or an integer, e.g. 0.14 or 21.')
@@ -593,71 +613,63 @@ entry2.bind('<Return>', calc_crit_2)
 ttk.Button(tab2.frame, text='Set', command=calc_crit_2, width=8).grid(column=0, row=3, padx=80, pady=8, sticky='w')
 
 # --------------------------- TAB3 ---------------------------
-tab3 = Tab(tab_no='3', title='Hazardous materials',
-           text1='The use of toxic materials, including the use of acids and bases '
-                 'for derivatization and digestion, should be avoided.',
-           text2='Input mass [g] or volume [mL] of problematic substances:',
-           criterion=criteria[2])
-
-label_tab3 = ttk.Label(tab3.frame, text='Include substances that are toxic via one of exposure pathways or '
-                                        'labeled as bioaccumulative, persistent, highly flammable, highly '
-                                        'oxidizable, explosive, or corrosive.',
-                       wraplength=280)
-label_tab3.grid(column=0, row=4, sticky='w')
-
-# create a frame to pack the entry into in order to get a border for the entry:
-f3 = tk.Frame(tab3.frame, border=2, background=colors['accent'])
-f3.grid(column=0, row=3, padx=8, pady=8, sticky='w')
-# create the entry and pack it in the frame
-entry3 = ttk.Entry(f3, textvariable=criteria[2].valuevar, width=10, style='AGREE_2.0_theme')
-entry3.pack()
-
-
-def calc_crit_3(event=None):
-    try:
-        if criteria[2].valuevar.get() == 'Input':
-            criteria[2].textvar.set(1.0)
-        elif float(criteria[2].valuevar.get()) >= 10:
-            criteria[2].textvar.set(0)
-        elif float(criteria[2].valuevar.get()) <= 0.01:
-            criteria[2].textvar.set(1.0)
-        else:
-            criteria[2].textvar.set(
-                abs(-0.147 * log(float(criteria[2].valuevar.get())) + 0.3299))
-    except ValueError:
-        messagebox.showerror(title='Value error',
-                             message='The amount has to be a float or an integer, e.g. 0.14 or 21.')
-    create_plot()
-
-
-entry3.bind('<Return>', calc_crit_3)
-ttk.Button(tab3.frame, text='Set', command=calc_crit_3, width=8).grid(column=0, row=3, padx=80, pady=8, sticky='w')
-
-# --------------------------- TAB4 ---------------------------
-tab4 = Tab(tab_no='4', title='Sustainability and renewability of materials',
+tab3 = Tab(tab_no='3', title='Sustainability and renewability of materials',
            text1='The application of materials from sustainable or renewable sources '
                  'should be prioritized.',
            text2='Ratio of the mass of sustainable and renewable materials to the total '
-                 'mass of materials used:', criterion=criteria[3])
+                 'mass of materials used:', criterion=criteria[2])
 
-tab4_choices = {'No reagents or only sustainable and renewable materials are used': 1.0,
+tab3_choices = {'No reagents or only sustainable and renewable materials are used': 1.0,
                 '> 75% of reagents and materials are sustainable or renewable': 0.75,
                 '50-75% of reagents and materials are sustainable or renewable': 0.50,
                 '25-50% of reagents and materials are sustainable or renewable': 0.25,
                 '< 25% of reagents and materials are sustainable or renewable': 0}
-dropdown4 = ttk.OptionMenu(tab4.frame, criteria[3].optionvar, criteria[3].optionvar.get(), *tab4_choices.keys(),
-                           command=lambda x: change_dropdown(criteria[3], tab4_choices))
+dropdown3 = ttk.OptionMenu(tab3.frame, criteria[2].optionvar, criteria[2].optionvar.get(), *tab3_choices.keys(),
+                           command=lambda x: change_dropdown(criteria[2], tab3_choices))
 # the ttk style for OptionMenu does not include a style for the tk dropdown menu,
 # so this has to be configured separately:
-dropdown4['menu'].config(background=colors['background'],
+dropdown3['menu'].config(background=colors['background'],
                          activeborderwidth=5,
                          activebackground=colors['accent'],
                          activeforeground=colors['text'],
                          foreground=colors['text'])
 
-dropdown4.grid(column=0, row=3, padx=8, pady=8, sticky='w')
+dropdown3.grid(column=0, row=3, padx=8, pady=8, sticky='w')
+
+# --------------------------- TAB4 ---------------------------
+tab4 = Tab(tab_no='4', title='Waste',
+           text1='In analytical chemistry, all material inputs, including '
+                 'the sample preparation stage, can be treated as waste.',
+           text2='Input mass [g] or volume [mL] of waste:', criterion=criteria[3])
+# create a frame to pack the entry into in order to get a border for the entry:
+f4 = tk.Frame(tab4.frame, border=2, background=colors['accent'])
+f4.grid(column=0, row=3, padx=8, pady=8, sticky='w')
+# create the entry and pack it in the frame
+entry4 = ttk.Entry(f4, textvariable=criteria[3].valuevar, width=10, style='AGREE_2.0_theme')
+entry4.pack()
 
-# # --------------------------- TAB5 ---------------------------
+
+def calc_crit_4(event=None):
+    try:
+        if criteria[3].valuevar.get() == 'Input':
+            criteria[3].textvar.set(1.0)
+        elif float(criteria[3].valuevar.get()) >= 50:
+            criteria[3].textvar.set(0)
+        elif float(criteria[3].valuevar.get()) <= 0.1:
+            criteria[3].textvar.set(1.0)
+        else:
+            criteria[3].textvar.set(
+                abs(-0.174 * log(float(criteria[3].valuevar.get())) + 0.6125))
+    except ValueError:
+        messagebox.showerror(title='Value error',
+                             message='The amount has to be a float or an integer, e.g. 0.14 or 21.')
+    create_plot()
+
+
+entry4.bind('<Return>', calc_crit_4)
+ttk.Button(tab4.frame, text='Set', command=calc_crit_4, width=8).grid(column=0, row=3, padx=80, pady=8, sticky='w')
+
+# --------------------------- TAB5 ---------------------------
 tab5 = Tab(tab_no='5', title='Size economy of the sample',
            text1='Smaller sample sizes should be favoured, as long as sample representativeness is assured',
            text2='Input mass [g] or volume [mL] of the sample:',
@@ -690,10 +702,9 @@ entry5.bind('<Return>', calc_crit_5)
 ttk.Button(tab5.frame, text='Set', command=calc_crit_5, width=8).grid(column=0, row=3, padx=80, pady=8, sticky='w')
 
 # --------------------------- TAB6 ---------------------------
-# remember to include a drop-down list of generic requirements for typical devices!
-tab6 = Tab(tab_no='6', title='Energy consumption',
-           text1='The power consumption per analysis should be minimized.',
-           text2='Input the energy consumption [W] per analysis:',
+tab6 = Tab(tab_no='6', title='Smaple throughput',
+           text1='Sample throughput determines the overall duration of the sample preparation stage.',
+           text2='Input the number of samples that can be prepared in one hour:',
            criterion=criteria[5])
 
 f6 = tk.Frame(tab6.frame, border=2, background=colors['accent'])
@@ -706,13 +717,13 @@ def calc_crit_6(event=None):
     try:
         if criteria[5].valuevar.get() == 'Input':
             criteria[5].textvar.set(1.0)
-        elif float(criteria[5].valuevar.get()) / 1000 >= 0.5:  # /1000 to input W instead of kW
-            criteria[5].textvar.set(0)
-        elif float(criteria[5].valuevar.get()) / 1000 <= 0.01:
+        elif float(criteria[5].valuevar.get()) >= 70:
             criteria[5].textvar.set(1.0)
+        elif float(criteria[5].valuevar.get()) <= 1.0:
+            criteria[5].textvar.set(0.0)
         else:
             criteria[5].textvar.set(
-                abs(-0.264 * log(float(criteria[5].valuevar.get()) / 1000) + 0.1606))
+                abs(0.2361 * log(float(criteria[5].valuevar.get())) - 0.0068))
     except ValueError:
         messagebox.showerror(title='Value error',
                              message='The amount has to be a float or an integer, e.g. 0.14 or 21.')
@@ -722,80 +733,20 @@ def calc_crit_6(event=None):
 entry6.bind('<Return>', calc_crit_6)
 ttk.Button(tab6.frame, text='Set', command=calc_crit_6, width=8).grid(column=0, row=3, padx=80, pady=8, sticky='w')
 
-label_tab6 = ttk.Label(tab6.frame, text='If more than one sample is prepared with the sample preparation '
-                                        'device, the energetic requirement for the device is divided '
-                                        'by the number of samples.',
-                       wraplength=280)
-label_tab6.grid(column=0, row=4, sticky='w')
-
-label_tab6_2 = ttk.Label(tab6.frame, text='Alternatively, select one of the listed generic devices for '
-                                          'a coarse estimate:',
-                         wraplength=280)
-label_tab6_2.grid(column=0, row=5, sticky='w')
-
-tab6_choices = {'A': 1.0,
-                'B': 0.75,
-                'C': 0.50,
-                'D': 0.25,
-                'E': 0}
-dropdown6 = ttk.OptionMenu(tab6.frame, criteria[5].optionvar, criteria[5].optionvar.get(), *tab6_choices.keys(),
-                           command=lambda x: change_dropdown(criteria[5], tab6_choices))
-# the ttk style for OptionMenu does not include a style for the tk dropdown menu,
-# so this has to be configured separately:
-dropdown6['menu'].config(background=colors['background'],
-                         activeborderwidth=5,
-                         activebackground=colors['accent'],
-                         activeforeground=colors['text'],
-                         foreground=colors['text'])
-
-dropdown6.grid(column=0, row=6, padx=8, pady=8, sticky='w')
-
 # --------------------------- TAB7 ---------------------------
-tab7 = Tab(tab_no='7', title='Smaple throughput',
-           text1='Sample throughput determines the overall duration of the sample preparation stage.',
-           text2='Input the number of samples that can be prepared in one hour:',
-           criterion=criteria[6])
-
-f7 = tk.Frame(tab7.frame, border=2, background=colors['accent'])
-f7.grid(column=0, row=3, padx=8, pady=8, sticky='w')
-entry7 = ttk.Entry(f7, textvariable=criteria[6].valuevar, width=10, style='AGREE_2.0_theme')
-entry7.pack()
-
-
-def calc_crit_7(event=None):
-    try:
-        if criteria[6].valuevar.get() == 'Input':
-            criteria[6].textvar.set(1.0)
-        elif float(criteria[6].valuevar.get()) >= 70:
-            criteria[6].textvar.set(1.0)
-        elif float(criteria[6].valuevar.get()) <= 1.0:
-            criteria[6].textvar.set(0.0)
-        else:
-            criteria[6].textvar.set(
-                abs(0.2361 * log(float(criteria[6].valuevar.get())) - 0.0068))
-    except ValueError:
-        messagebox.showerror(title='Value error',
-                             message='The amount has to be a float or an integer, e.g. 0.14 or 21.')
-    create_plot()
-
-
-entry7.bind('<Return>', calc_crit_7)
-ttk.Button(tab7.frame, text='Set', command=calc_crit_7, width=8).grid(column=0, row=3, padx=80, pady=8, sticky='w')
-
-# --------------------------- TAB8 ---------------------------
-tab8 = Tab(tab_no='8', title='Automation',
+tab7 = Tab(tab_no='7', title='Integration and automation',
            text1='Sample preparation should be simplified and automated if possible.',
            text2='1. Select the number of discrete steps in the sample preparation procedure:',
-           criterion=criteria[7])
+           criterion=criteria[6])
 
-tab8a_choices = {'2 steps or fewer': 1.0,
+tab7a_choices = {'2 steps or fewer': 1.0,
                  '3 steps': 0.75,
                  '4 steps': 0.50,
                  '5 steps': 0.25,
                  '6 steps or more': 0}
 
 
-def calc_crit_8(event=None):
+def calc_crit_7(event=None):
     # create temporary variables for each dropdown:
     a = tk.StringVar()
     b = tk.StringVar()
@@ -803,51 +754,143 @@ def calc_crit_8(event=None):
     a.set('1.0')
     b.set('1.0')
 
-    if criteria[7].optionvar_a.get() != 'Select':
-        a.set(tab8a_choices[criteria[7].optionvar_a.get()])
+    if criteria[6].optionvar_a.get() != 'Select':
+        a.set(tab7a_choices[criteria[6].optionvar_a.get()])
 
-    if criteria[7].optionvar_b.get() != 'Select':
-        b.set(tab8b_choices[criteria[7].optionvar_b.get()])
+    if criteria[6].optionvar_b.get() != 'Select':
+        b.set(tab7b_choices[criteria[6].optionvar_b.get()])
 
-    criteria[7].textvar.set(str(float(a.get()) * float(b.get())))
-    print(a.get(), b.get(), criteria[7].textvar.get())
+    criteria[6].textvar.set(str(float(a.get()) * float(b.get())))
     create_plot()
 
 
-dropdown8a = ttk.OptionMenu(tab8.frame, criteria[7].optionvar_a, criteria[7].optionvar_a.get(), *tab8a_choices.keys(),
-                            command=calc_crit_8)
+dropdown7a = ttk.OptionMenu(tab7.frame, criteria[6].optionvar_a, criteria[6].optionvar_a.get(), *tab7a_choices.keys(),
+                            command=calc_crit_7)
 
 # the ttk style for OptionMenu does not include a style for the tk dropdown menu,
 # so this has to be configured separately:
-dropdown8a['menu'].config(background=colors['background'],
+dropdown7a['menu'].config(background=colors['background'],
                           activeborderwidth=5,
                           activebackground=colors['accent'],
                           activeforeground=colors['text'],
                           foreground=colors['text'])
 
-dropdown8a.grid(column=0, row=3, padx=8, pady=8, sticky='w')
+dropdown7a.grid(column=0, row=3, padx=8, pady=8, sticky='w')
 
-label_tab8 = ttk.Label(tab8.frame, text='2. Select the degree of automation:',
+label_tab7 = ttk.Label(tab7.frame, text='2. Select the degree of automation:',
                        wraplength=280)
-label_tab8.grid(column=0, row=4, sticky='w')
+label_tab7.grid(column=0, row=4, sticky='w')
 
-tab8b_choices = {'Fully automated systems': 1.0,
+tab7b_choices = {'Fully automated systems': 1.0,
                  'Semi-automated systems': 0.50,
                  'Manual systems': 0.25}
 
-dropdown8b = ttk.OptionMenu(tab8.frame, criteria[7].optionvar_b, criteria[7].optionvar_b.get(), *tab8b_choices.keys(),
-                            command=calc_crit_8)
+dropdown7b = ttk.OptionMenu(tab7.frame, criteria[6].optionvar_b, criteria[6].optionvar_b.get(), *tab7b_choices.keys(),
+                            command=calc_crit_7)
 
-dropdown8b['menu'].config(background=colors['background'],
+dropdown7b['menu'].config(background=colors['background'],
                           activeborderwidth=5,
                           activebackground=colors['accent'],
                           activeforeground=colors['text'],
                           foreground=colors['text'])
 
-dropdown8b.grid(column=0, row=5, padx=8, pady=8, sticky='w')
+dropdown7b.grid(column=0, row=5, padx=8, pady=8, sticky='w')
+
+# --------------------------- TAB8 ---------------------------
+# remember to include a drop-down list of generic requirements for typical devices!
+tab8 = Tab(tab_no='8', title='Energy consumption',
+           text1='The power consumption per analysis should be minimized.',
+           text2='Input the energy consumption [W] per sample, accounting for the sample throughput:',
+           criterion=criteria[7])
+
+f8 = tk.Frame(tab8.frame, border=2, background=colors['accent'])
+f8.grid(column=0, row=3, padx=8, pady=8, sticky='w')
+entry8 = ttk.Entry(f8, textvariable=criteria[7].valuevar, width=10, style='AGREE_2.0_theme')
+entry8.pack()
+
+
+def calc_crit_8(event=None):
+    try:
+        if criteria[7].valuevar.get() == 'Input':
+            criteria[7].textvar.set(1.0)
+        elif float(criteria[7].valuevar.get()) / 1000 >= 0.5:  # /1000 to input W instead of kW
+            criteria[7].textvar.set(0)
+        elif float(criteria[7].valuevar.get()) / 1000 <= 0.01:
+            criteria[7].textvar.set(1.0)
+        else:
+            criteria[7].textvar.set(
+                abs(-0.264 * log(float(criteria[7].valuevar.get()) / 1000) + 0.1606))
+    except ValueError:
+        messagebox.showerror(title='Value error',
+                             message='The amount has to be a float or an integer, e.g. 0.14 or 21.')
+    create_plot()
+
+
+entry8.bind('<Return>', calc_crit_8)
+ttk.Button(tab8.frame, text='Set', command=calc_crit_8, width=8).grid(column=0, row=3, padx=80, pady=8, sticky='w')
+
+# label_tab8 = ttk.Label(tab8.frame, text='If more than one sample is prepared with the sample preparation '
+#                                         'device, the energetic requirement for the device is divided '
+#                                         'by the number of samples.',
+#                        wraplength=280)
+# label_tab8.grid(column=0, row=4, sticky='w')
+
+label_tab8_2 = ttk.Label(tab8.frame, text='Alternatively, select one or several generic devices for '
+                                          'a rough estimate based on the throughput provided in Criterion #6:',
+                         wraplength=280)
+label_tab8_2.grid(column=0, row=5, sticky='w')
+
+multiselect_menu8 = ttk.Menubutton(tab8.frame, text='Select used devices')
+multiselect_menu8.grid(column=0, row=6, padx=8, pady=8, sticky='w')
+
+
+class Device:
+    def __init__(self, name, wattage):
+        self.name = name
+        self.wattage = wattage
+        self.state = tk.IntVar()
+
+
+# Modify this function to calculate the score:
+def crit_8_rough_estimate():
+    comb_wattage = 0
+    for instrument in instruments:
+        if instrument.state.get():
+            comb_wattage += instrument.wattage
+        else:
+            pass
+    if criteria[5].valuevar.get() == 'Input':
+        messagebox.showerror(title='Value error',
+                             message='Please fill in the throughput value in Criterion #6.')
+    else:
+        criteria[7].valuevar.set(comb_wattage / float(criteria[5].valuevar.get()))
+        calc_crit_8()
+
+
+# open an external list of sample prep instruments and corresponding wattage {'Freeze dryer: 1000,}
+def load_dict():
+    dict_of_devices = open('list_of_devices.config', 'r').read()
+    dvcs = ast.literal_eval(dict_of_devices)
+    return dvcs
+
+
+devices = load_dict()
+
+# create a list of objects of the Devices class from the external dictionary
+instruments = []
+for device in devices:
+    instruments.append(Device(name=device, wattage=devices[device]))
+
+multiselect_menu8.menu = tk.Menu(multiselect_menu8, tearoff=0)
+multiselect_menu8['menu'] = multiselect_menu8.menu
+
+for instrument in instruments:
+    multiselect_menu8.menu.add_checkbutton(label=instrument.name, variable=instrument.state,
+                                           command=crit_8_rough_estimate,
+                                           background=colors['background'], activebackground=colors['accent'])
 
 # --------------------------- TAB9 ---------------------------
-tab9 = Tab(tab_no='9', title='Analytical instrumentation for final determination',
+tab9 = Tab(tab_no='9', title='Post-sample preparation configuration for analysis',
            text1='The prepared sample matrix should be compatible with the analytical instrument, '
                  'which in turn affects the overall environmental impact of the procedure.',
            text2='Select the final determination technique or its closest analogue:',
@@ -910,4 +953,3 @@ def main():
 
 
 main()
-
-- 
GitLab