https://hal.archives-ouvertes.fr/hal-01897934
Raw File
Tip revision: f370e484d8579b4ccc863d1c2a2f10decad21914 authored by Software Heritage on 27 July 2018, 00:00:00 UTC
hal: Deposit 299 in collection hal
Tip revision: f370e48
slalomDeviceGui.py
# -*- coding: utf-8 -*-

# ======================================================================================================
# SLALOM - Open-Source Solar Cell Multivariate Optimizer
# Copyright(C) 2012-2019 Sidi OULD SAAD HAMADY (1,2,*), Nicolas FRESSENGEAS (1,2). All rights reserved.
# (1) Université de Lorraine, Laboratoire Matériaux Optiques, Photonique et Systèmes, Metz, F-57070, France
# (2) Laboratoire Matériaux Optiques, Photonique et Systèmes, CentraleSupélec, Université Paris-Saclay, Metz, F-57070, France
# (*) sidi.hamady@univ-lorraine.fr
# SLALOM source code is available to download from:
# https://github.com/sidihamady/SLALOM
# https://hal.archives-ouvertes.fr/hal-01897934
# http://www.hamady.org/photovoltaics/slalom_source.zip
# Cite as: S Ould Saad Hamady and N Fressengeas, EPJ Photovoltaics, 9:13, 2018.
# See Copyright Notice in COPYRIGHT
# ======================================================================================================

# ------------------------------------------------------------------------------------------------------
# File:           slalomDeviceGui.py
# Type:           Class
# Use:            The slalomDeviceGui class is used by the SLALOM module.
#                 slalomDeviceGui provides a useful interface to select one of the...
#                  ...predefined devices.
#                  slalomDeviceGui uses tkinter that is already installed on the client...
#                  (this is generally the case, except for some CentOS or RedHat machines)
# ------------------------------------------------------------------------------------------------------

from slalomCore import *
from slalomDevice import *
import re

TkFound = False

try:
    if sys.version_info[0] < 3:
        import Tkinter as Tk
        import ttk
    else:
        import tkinter as Tk
        import tkinter.ttk as ttk
    # end if
    from ttk import *
    import tkMessageBox
    import tkFileDialog
    TkFound = True
except ImportError as ierr:
    # tkinter related modules not found. Just warn and skip this part.
    # just install or update python/numpy/scipy/matplotlib/tk modules
    dispError("{0}".format(ierr), doExit = False)
    # catch only Exception (since sys.exit raise BaseException)
    pass
except:
    pass
# end try

try:

    class slalomDeviceGui(object):

        def __init__(self, device, remoteDir, remoteHost, optimType, minimizeMethod, *args, **kwargs):

            self.__version__ = slalomVersion

            self.device = device
            self.device.deviceType = 'User'

            self.parcount = 6
            self.rowcount = 8

            self.remoteDir = remoteDir
            self.remoteHost = remoteHost

            self.optimType = optimType
            self.minimizeMethod = minimizeMethod

            self.validated = False

        # end __init__

        def show(self):

            self.root = Tk.Tk()
            self.root.withdraw()
            self.root.wm_title("SLALOM - Device Parameters")
            self.root.protocol("WM_DELETE_WINDOW", self.onClose)

            self.frame = Tk.Frame(self.root)
            self.frame.pack(expand=1, fill="both", padx=10, pady=10)

            irow = 0
            ipadx = 5
            ipady = 5

            validateDirname = (self.frame.register(self.onEntryValidateDirname), '%P')
            validateFilename = (self.frame.register(self.onEntryValidateFilename), '%P')
            validateHostname = (self.frame.register(self.onEntryValidateHostname), '%P')

            Tk.Label(self.frame, text='Current Dir:', justify=Tk.RIGHT).grid(row=irow, column=0, sticky=Tk.E, padx=ipadx, pady=ipady)
            self.currentDirWidget = Tk.Entry(self.frame, validate="key", vcmd=validateDirname)
            self.currentDirWidget.grid(row=irow, column=1, columnspan=4, sticky=Tk.W+Tk.E, padx=ipadx, pady=ipady)
            Tk.Label(self.frame, text='Input file:', justify=Tk.RIGHT).grid(row=irow, column=5, sticky=Tk.E, padx=ipadx, pady=ipady)
            self.inputFilenameWidget = Tk.Entry(self.frame, validate="key", vcmd=validateFilename)
            self.inputFilenameWidget.grid(row=irow, column=6, sticky=Tk.W+Tk.E, padx=ipadx, pady=ipady)
            irow += 1

            Tk.Label(self.frame, text='Remote Dir:', justify=Tk.RIGHT).grid(row=irow, column=0, sticky=Tk.E, padx=ipadx, pady=ipady)
            self.remoteDirWidget = Tk.Entry(self.frame, validate="key", vcmd=validateDirname)
            self.remoteDirWidget.grid(row=irow, column=1, columnspan=4, sticky=Tk.W+Tk.E, padx=ipadx, pady=ipady)
            Tk.Label(self.frame, text='SSH host:', justify=Tk.RIGHT).grid(row=irow, column=5, sticky=Tk.E, padx=ipadx, pady=ipady)
            self.remoteHostWidget = Tk.Entry(self.frame, validate="key", vcmd=validateHostname)
            self.remoteHostWidget.grid(row=irow, column=6, sticky=Tk.W+Tk.E, padx=ipadx, pady=ipady)
            irow += 1

            Tk.Label(self.frame, text='Device type:', justify=Tk.RIGHT).grid(row=irow, column=0, sticky=Tk.E, padx=ipadx, pady=ipady)
            validateParam = (self.frame.register(self.onEntryValidateParam), '%P')
            self.deviceTypeWidget = Tk.Entry(self.frame, validate="key", vcmd=validateParam)
            self.deviceTypeWidget.grid(row=irow, column=1, sticky=Tk.W+Tk.E, padx=ipadx, pady=ipady)

            validateOptim = (self.frame.register(self.onEntryValidateOptim), '%P')
            validateMethod = (self.frame.register(self.onEntryValidateMethod), '%P')
            Tk.Label(self.frame, text='Optimization:', justify=Tk.RIGHT).grid(row=irow, column=3, sticky=Tk.E, padx=ipadx, pady=ipady)
            self.optimWidget = Tk.Entry(self.frame, validate="key", vcmd=validateOptim)
            self.optimWidget.grid(row=irow, column=4, sticky=Tk.W+Tk.E, padx=ipadx, pady=ipady)
            Tk.Label(self.frame, text='Method:', justify=Tk.RIGHT).grid(row=irow, column=5, sticky=Tk.E, padx=ipadx, pady=ipady)
            self.methodWidget = Tk.Entry(self.frame, validate="key", vcmd=validateMethod)
            self.methodWidget.grid(row=irow, column=6, sticky=Tk.W+Tk.E, padx=ipadx, pady=ipady)
            irow += 1

            Tk.Label(self.frame, text='Models:', justify=Tk.RIGHT).grid(row=irow, column=0, sticky=Tk.E, padx=ipadx, pady=ipady)
            self.modelWidget = list()
            for ii in range(0, 2):
                for jj in range(0, self.parcount):
                    self.modelWidget.append(Tk.Entry(self.frame, validate="key", vcmd=validateFilename))
                    self.modelWidget[(ii * self.parcount) + jj].grid(row=irow, column=1+jj, sticky=Tk.W+Tk.E, padx=ipadx, pady=ipady)
                # end for
                irow += 1
            # end for

            self.paramWidget = [ list(), list(), list(), list(),
                                 list(), list(), list(), list() ]
            self.label = ['Parameter:', 'Format:', 'Norm:', 'Start:',
                          'End:', 'Init:', 'Points:', 'LogScale:']
            self.type = ['string', 'format', 'float', 'float',
                         'float', 'float', 'int', 'bool']
            self.deviceparam = [ self.device.paramName, self.device.paramFormat, self.device.paramNorm, self.device.paramStart,
                                 self.device.paramEnd, self.device.paramInit, self.device.paramPoints, self.device.paramLogscale ]
            validateFormat = (self.frame.register(self.onEntryValidateFormat), '%P')
            validateFloat = (self.frame.register(self.onEntryValidateFloat), '%P')
            validateInteger = (self.frame.register(self.onEntryValidateInteger), '%P')
            validateBoolean = (self.frame.register(self.onEntryValidateBoolean), '%P')
            self.paramvalidator = [validateParam, validateFormat, validateFloat, validateFloat,
                                   validateFloat, validateFloat, validateInteger, validateBoolean]

            for ii in range(0, self.rowcount):
                Tk.Label(self.frame, text=self.label[ii], justify=Tk.RIGHT).grid(row=irow+ii, column=0, sticky=Tk.E, padx=ipadx, pady=ipady)
                for jj in range(0, self.parcount):
                    self.paramWidget[ii].append(Tk.Entry(self.frame, validate="key", vcmd=self.paramvalidator[ii]) if (self.paramvalidator[ii] is not None) else Tk.Entry(self.frame))
                    self.paramWidget[ii][jj].grid(row=irow+ii, column=1+jj, padx=ipadx, pady=ipady)
                # end for
            # end for
            irow += self.rowcount

            ttk.Button(self.frame, text="Optimize", command=self.onOptimize).grid(row=irow, column=self.parcount-1, sticky=Tk.W+Tk.E, padx=ipadx, pady=ipady)
            ttk.Button(self.frame, text="Cancel", command=self.onCancel).grid(row=irow, column=self.parcount, sticky=Tk.W+Tk.E, padx=ipadx, pady=ipady)

            self.root.deiconify()

            if (os.name == "nt"):
                self.root.iconbitmap(r'Images/slalomg.ico')
            else:
                iconSlalom = Tk.PhotoImage(file='Images/slalomg.gif')
                self.root.tk.call('wm', 'iconphoto', self.root._w, iconSlalom)
            # end if

            self.updateGui()

            self.root.mainloop()

        # end __init__

        def onEntryValidateDirname(self, sp):
            try:
                if (not sp) or (len(sp) <= 255):
                    return True
                # end if
                return False
            except:
                return True
            # end try
        # end onEntryValidateDirname

        def onEntryValidateFilename(self, sp):
            try:
                if (not sp) or (len(sp) <= 63):
                    return True
                # end if
                return False
            except:
                return True
            # end try
        # end onEntryValidateFilename

        def onEntryValidateHostname(self, sp):
            try:
                if (not sp) or (len(sp) <= 63):
                    return True
                # end if
                return False
            except:
                return True
            # end try
        # end onEntryValidateHostname

        def onEntryValidateParam(self, sp):
            try:
                if (not sp) or ((len(sp) <= 31) and (re.match(r'^\w+$', sp))):
                    return True
                # end if
                return False
            except:
                return True
            # end try
        # end onEntryValidateParam

        def onEntryValidateFormat(self, sp):
            try:
                if (not sp) or ((len(sp) <= 7) and (re.match(r'^[0-9\%\.efgd]*$', sp))):
                    return True
                # end if
                return False
            except:
                return True
            # end try
        # end onEntryValidateFormat

        def onEntryValidateFloat(self, sp):
            try:
                if (not sp) or ((len(sp) <= 15) and (re.match(r'[+-]?(\d+(\.\d*)?|\.\d+)([eE][+-]?\d+)?', sp))):
                    return True
                # end if
                return False
            except:
                return True
            # end try
        # end onEntryValidateFloat

        def onEntryValidateInteger(self, sp):
            try:
                if (not sp) or ((len(sp) <= 3) and (re.match('^\d+$', sp))):
                    return True
                # end if
                return False
            except:
                return True
            # end try
        # end onEntryValidateInteger

        def onEntryValidateBoolean(self, sp):
            try:
                if (not sp) or ((len(sp) <= 5) and ('True'.startswith(sp) or 'False'.startswith(sp))):
                    return True
                # end if
                return False
            except:
                return True
            # end try
        # end onEntryValidateBoolean

        def onEntryValidateOptim(self, sp):
            try:
                if (not sp) or ((len(sp) <= 5) and ('Brute'.startswith(sp) or 'Snap'.startswith(sp) or 'Optim'.startswith(sp))):
                    return True
                # end if
                return False
            except:
                return True
            # end try
        # end onEntryValidateOptim

        def onEntryValidateMethod(self, sp):
            try:
                if (not sp) or ((len(sp) <= 8) and ('L-BFGS-B'.startswith(sp) or 'SLSQP'.startswith(sp))):
                    return True
                # end if
                return False
            except:
                return True
            # end try
        # end onEntryValidateOptim

        def updateGui(self):

            try:

                self.currentDirWidget.delete(0, Tk.END)
                self.currentDirWidget.insert(0, self.device.currentDir)
                self.inputFilenameWidget.delete(0, Tk.END)
                self.inputFilenameWidget.insert(0, self.device.inputFilename)

                self.remoteDirWidget.delete(0, Tk.END)
                self.remoteDirWidget.insert(0, self.remoteDir)
                self.remoteHostWidget.delete(0, Tk.END)
                if self.remoteHost is not None:
                    self.remoteHostWidget.insert(0, self.remoteHost)
                # end if

                self.deviceTypeWidget.delete(0, Tk.END)
                self.deviceTypeWidget.insert(0, self.device.deviceType)

                self.optimWidget.delete(0, Tk.END)
                self.optimWidget.insert(0, self.optimType)
                self.methodWidget.delete(0, Tk.END)
                self.methodWidget.insert(0, self.minimizeMethod)

                if self.device.modelFilename:
                    iCnt = len(self.device.modelFilename)
                    for ii in range(0, 2):
                        for jj in range(0, self.parcount):
                            self.modelWidget[(ii * self.parcount) + jj].delete(0, Tk.END)
                            if (((ii * self.parcount) + jj) < iCnt):
                                self.modelWidget[(ii * self.parcount) + jj].insert(0, self.device.modelFilename[jj])
                            # end if
                        # end for
                    # end for
                 # end if

                paramCount = len(self.deviceparam[0])
                for ii in range(0, self.rowcount):
                    for jj in range(0, self.parcount):
                        self.paramWidget[ii][jj].delete(0, Tk.END)
                        self.paramWidget[ii][jj].insert(0, str(self.deviceparam[ii][jj]) if (jj < paramCount) else '')
                    # end for
                # end for

            except:
               pass
            # end try

        # end updateGui

        def updateDevice(self):

            try:

                self.device.currentDir = self.currentDirWidget.get()
                self.device.inputFilename = self.inputFilenameWidget.get()

                self.remoteDir = self.remoteDirWidget.get()
                self.remoteHost = self.remoteHostWidget.get()
                if len(self.remoteHost) < 3:
                    self.remoteHost = None
                # end if

                self.device.deviceType = self.deviceTypeWidget.get()

                self.optimType = self.optimWidget.get()
                self.minimizeMethod = self.methodWidget.get()

                bFlag = False

                if self.device.modelFilename:
                    iCnt = len(self.device.modelFilename)
                    for ii in range(0, 2):
                        for jj in range(0, self.parcount):
                            modelT = self.modelWidget[(ii * self.parcount) + jj].get()
                            if (not modelT) or (len(modelT) < 3):
                                break
                            # end if
                            if (((ii * self.parcount) + jj) < iCnt):
                                self.device.modelFilename[jj] = modelT
                            else:
                                if modelT not in self.device.modelFilename:
                                    self.device.modelFilename.append(modelT)
                                # end if
                            # end if
                        # end for
                    # end for
                # end if

                iCnt = len(self.deviceparam[0])
                for ii in range(0, self.rowcount):
                    for jj in range(0, self.parcount):
                        paramT = self.paramWidget[ii][jj].get()
                        if (not paramT) or (len(paramT) < 1):
                            break
                        # end if
                        if self.type[ii] == 'string' or self.type[ii] == 'format':
                            if (jj < iCnt):
                                self.deviceparam[ii][jj] = paramT
                            else:
                                self.deviceparam[ii].append(paramT)
                            # end if
                        elif self.type[ii] == 'float':
                            if (jj < iCnt):
                                self.deviceparam[ii][jj] = float(paramT)
                            else:
                                self.deviceparam[ii] = np.append(self.deviceparam[ii], float(paramT))
                            # end if
                        elif self.type[ii] == 'int':
                            if (jj < iCnt):
                                self.deviceparam[ii][jj] = int(paramT)
                            else:
                                self.deviceparam[ii].append(int(paramT))
                            # end if
                        elif self.type[ii] == 'bool':
                            if (jj < iCnt):
                                self.deviceparam[ii][jj] = True if (paramT == 'True') else False
                            else:
                                self.deviceparam[ii].append(True if (paramT == 'True') else False)
                            # end if
                        # end if
                    # end for
                # end for

                (self.validated, message) = self.device.validate()
                if not self.validated:
                    tkMessageBox.showwarning("SLALOM", message, parent=self.root)
                # end if

            except Exception as excT:
               tkMessageBox.showwarning("SLALOM", "Device data not valid: " + str(excT), parent=self.root)
               pass
            # end try

        # end updateDevice

        def onOptimize(self):
            self.updateDevice()
            self.onClose()
        # end onOptimize

        def onCancel(self):
            self.validated = False
            self.onClose()
        # end onCancel

        def onClose(self):
            if self.root is not None:
                self.root.quit()
                self.root.destroy()
                self.root = None
            # end if
        # end onClose

        # end onDevicelistBox

    # end slalomDeviceGui

except Exception as excT:

    excType, excObj, excTb = sys.exc_info()
    excFile = os.path.split(excTb.tb_frame.f_code.co_filename)[1]
    strErr  = "\n! cannot initialize GUI:\n  %s\n  in %s (line %d)\n" % (str(excT), excFile, excTb.tb_lineno)
    print(strErr)
    os._exit(1)
    # never reached
    pass

# end try
back to top