#!/usr/bin/env python
# -*- coding: utf-8 -*-
# ======================================================================================================
# SLALOM - Open-Source Solar Cell Multivariate Optimizer
# Copyright(C) 2012-2019 Sidi OULD SAAD HAMADY (1,2,*) and 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: slalom.py
# Type: Module
# Purpose: Startup module:
# * set the parameters to optimize
# * set the optimization method
# ------------------------------------------------------------------------------------------------------
from slalomCore import *
from slalomDevice import *
import getopt
print('\nSLALOM - Open-Source Solar Cell Multivariate Optimizer\n'
+ 'Copyright(C) 2012-2019 Sidi OULD SAAD HAMADY (1,2,*), Nicolas FRESSENGEAS (1,2). All rights reserved.\n'
+ '(1) Universite de Lorraine, LMOPS, Metz, F-57070, France\n'
+ '(2) LMOPS, CentraleSupelec, Universite Paris-Saclay, Metz, F-57070, France\n'
+ '(*) sidi.hamady@univ-lorraine.fr\n'
+ slalomVersion + '\n'
+ 'SLALOM source code is available to download here: https://github.com/sidihamady/SLALOM \n'
+ 'Cite as: S Ould Saad Hamady and N Fressengeas, EPJ Photovoltaics, 9:13, 2018. \n'
+ 'See Copyright Notice in COPYRIGHT\n')
# ======================================================================================================
# The device parameters are grouped here
# <START-Parameters>
# the used backend solar cell simulator.
# by default set to "atlas", the simulator from Silvaco(r) company,...
# ... or "tibercad", the simulator from TiberLAB(r)
deviceSimulator = "atlas"
# currentDir is the name of the directory where the simulator input files remain:
# it can be set to a permanent directory name for a specific project.
# the dir name should be ended with the path separator ('/' under Linux)
#currentDir = "/home/sidi/TCAD/SLALOM/Device/Silvaco/"
currentDir = "N:\\TCAD\\SLALOM\\Device\\Silvaco\\"
# remoteDir is the name of the remote directory used when using SSH to connect...
# ...to a remote server where the simulator is installed.
# the dir name should be ended with the path separator ('/' under Linux)
remoteDir = ""#"/home/sidi/SLALOM/Device/Silvaco/"
# the SSH host used to connect to the server where the Silvaco, tiberCAD or other simulator tools are installed
# set remoteSSHhost to None if the Silvaco, tiberCAD or other simulator tools are installed locally...
# ...or something like "user@remoteserver".
# the SSH connexion should use auth keys, not password, for security reasons.
# refer to the guide (Guide/slalom_guide.pdf) on how to configure SSH.
remoteSSHhost = ""#"sidi@efprimix"
# It is useful, for every project, to define a set of devices
# (e.g. "InGaN_PN", CZTS", etc.) for easier and more robust optimization work.
# The devices are defined in the slalomDevice class.
# Set deviceType to a predefined device (included in slalomDevice.py)...
# ...or set it to None and define the parameters in the optimizer GUI.
deviceType = "InGaN_Schottky"
# The optimization mode: "Brute" (brute force), "Optim" (optimization) or "Snap" (one point)
optimType = "Optim"
# The optimization method: "L-BFGS-B", "SLSQP" or "Bayes"
minimizeMethod = "SLSQP"
# The maximum number of iterations
maxIter = 100
# Set to True to start the optimization with a random point
randomInit = False
# Set to True to delete the output directory and all its content before optimization
clearOutputDir = False
# slalomMonitor:
# set monitorRemoteSSHhost to None to monitor locally (client=monitor and server=optimizer on the same machine)...
# ...or something like "user@remoteserver" to monitor remotely (client and server on different machines).
# the ssh connexion should use auth keys, not password, for security reasons.
monitorRemoteSSHhost = None
dirSepChar = '\\' if ('\\' in currentDir) else '/'
# set to True to enable the SLALOM GUI
enableGUI = True
# command line arguments: python slalom.py --enableGUI --currentDir ... --remoteDir ... --remoteSSH ... --deviceType ... --optimType ... --minimizeMethod ...
# examples:
# python slalom.py --enableGUI No
# python slalom.py --currentDir "N:\\TCAD\\SLALOM\\Device\\Silvaco\\" --remoteDir "/home/sidi/SLALOM/Device/Silvaco/" --remoteSSH user@slalom --deviceType InGaN_PN --optimType Optim --minimizeMethod SLSQP
argc = len(sys.argv) - 1
if argc >= 1:
isValid = True
errMsg = None
try:
opts, args = getopt.getopt(sys.argv[1:], None, ["enableGUI=", "deviceSimulator=", "currentDir=", "remoteDir=", "remoteSSH=", "deviceType=", "optimType=", "minimizeMethod="])
print ("\n# ------------------ Command Line Arguments ---------------------")
for opt, arg in opts:
if opt == "--enableGUI":
arg = arg.lower()
enableGUI = False if ((arg == "no") or (arg == "false")) else True
print("# enableGUI: " + str(enableGUI))
elif opt == "--deviceSimulator":
if arg.lower() in ("atlas", "tibercad"):
deviceSimulator = "atlas" if (arg.lower() == "atlas") else "tibercad"
print("deviceSimulator: " + deviceSimulator)
# end if
elif opt == "--currentDir":
if os.path.isdir(arg):
currentDir = arg
dirSepChar = '\\' if ('\\' in currentDir) else '/'
if not currentDir.endswith(dirSepChar):
currentDir += dirSepChar
#end if
print("currentDir: " + currentDir)
else:
isValid = False
errMsg = "currentDir: invalid directory '%s'\n" % arg
# end if
elif opt == "--remoteDir":
# the remote directory should belongs to a user account in the home directory
# the remote server is always under Linux
if arg.startswith("C:/Program Files/Git"):
# gitbash under Windows prepend the local Git dir to the home path. Remove it.
arg = arg[len("C:/Program Files/Git"):]
# end if
if arg.startswith("/home/"):
remoteDir = arg
if not remoteDir.endswith('/'):
remoteDir += '/'
#end if
print("remoteDir " + remoteDir)
else:
isValid = False
errMsg = "remoteDir: invalid directory '%s'\n" % arg
# end if
#end if
elif opt == "--remoteSSH":
if ('@' in arg) and (len(arg) >= 5):
remoteSSHhost = arg
print("remoteSSHhost: " + remoteSSHhost)
else:
isValid = False
errMsg = "remoteDir: invalid host '%s'\n" % arg
# end if
#end if
elif opt == "--deviceType":
deviceType = arg
print("deviceType: " + deviceType)
elif opt == "--optimType":
if arg in ("Brute", "Optim", "Snap"):
optimType = arg
print("optimType: " + optimType)
else:
isValid = False
errMsg = "optimType: invalid option '%s'\n" % arg
# end if
elif opt == "--minimizeMethod":
if arg in ("L-BFGS-B", "SLSQP"):
minimizeMethod = arg
print("minimizeMethod: " + minimizeMethod)
else:
isValid = False
errMsg = "minimizeMethod: invalid option '%s'\n" % arg
# end if
# end if
# end for
print ("# ---------------------------------------------------------------\n")
if not isValid:
raise Exception(errMsg)
# end if
except Exception as excT:
errMsg = str(excT) + '\nSLALOM usage:\n python slalom.py [args]\n Examples:\n' + ' python slalom.py\n python slalom.py --deviceType InGaN_PN --optimType Optim --minimizeMethod SLSQP\n python slalom.py --deviceSimulator atlas --currentDir "N:\\TCAD\\SLALOM\\Device\\Silvaco\\" --remoteDir "/home/sidi/SLALOM/Device/Silvaco/" --remoteSSH sidi@efprimix --deviceType InGaN_PN --optimType Optim --minimizeMethod SLSQP'
dispError(errMsg, doExit = True)
# never reached
pass
# end try
# end if
# Create a new device of type deviceType
# NB: if deviceType is not found, Device.deviceType will be set to None...
# ... and the parameters must be entered below.
Device = slalomDevice(deviceType, currentDir)
# if deviceType set to None, define here the parameters to optimize.
# put always one line per parameter to let the optimizer build the...
# code for the remote server.
if Device.deviceType is None:
# Device type as defined by the user
Device.deviceType = "UserDefined"
# Deckbuild input filename
Device.inputFilename = "InGaN_PN.in"
# Device description
Device.mainTitle = "PN InGaN PV Cell"
# Output directory
Device.outputDir = Device.currentDir + "output" + Device.dirSepChar + Device.deviceType + Device.dirSepChar
# Parameters name, as defined is the Deckbuild input
Device.paramName = ["PLayerThick", "PLayerDop", "NLayerThick", "NLayerDop", "AlloyComp"]
# Parameters unit
Device.paramUnit = ["um", "1/cm3", "um", "1/cm3", ""]
# Parameters format string (e.g. for doping use "%.6e")
Device.paramFormat = ["%.8f", "%.6e", "%.8f", "%.6e", "%.8f"]
# Parameters short format string for console output (e.g. for doping use "%.4e")
Device.paramFormatShort = ["%.6f", "%.4e","%.6f", "%.4e", "%.6f"]
# Normalized parameters format string for console output
Device.paramFormatNormalized = ["%.8f", "%.8f", "%.8f", "%.8f", "%.8f"]
# Normalization value for each parameter
Device.paramNorm = np.array([1.000, 1e17, 1.000, 1e17, 1.00])
# Parameters range limit (Start)
Device.paramStart = np.array([0.001, 1e15, 0.100, 1e15, 0.20])
# Parameters range limit (End)
Device.paramEnd = np.array([1.000, 1e19, 1.000, 1e18, 0.80])
# Parameters initial values (used as a starting point or when optimType is set to "Snap")
# should be in the [paramStart, paramEnd] range
Device.paramInit = np.array([0.100, 1e17, 0.500, 1e15, 0.30])
# Parameters number of points (used as when optimType is set to "Brute")
Device.paramPoints = [1, 1, 1, 1, 1]
# Parameters variation type (True for logarithmic variation (e.g. for doping), and False for linear)
Device.paramLogscale = [False, True, False, True, False]
Device.paramWeight = False
# end if
(bOK, errMsg) = Device.validate()
if not bOK:
dispError(errMsg, doExit = True)
# end if
# </END-Parameters>
# ======================================================================================================
# ======================================================================================================
# <START-DeviceGui>
# the device GUI window is shown, if the solar cell parameters were not defined, to let the user...
# ...define the optimizer parameters in a more easier way.
showDeviceGui = enableGUI
deviceGuiValidated = False
try:
if showDeviceGui and (Device.deviceType is None):
#if Device.deviceType is None:
from slalomDeviceGui import *
# tkinter is not always installed by default (e.g. in RedHat Enterprise Linux 7+ or CentOS 6.x)...
# ...if not installed, the optimizer device GUI cannot be started...
# ...(just (re)install it or install a more recent python/numpy/scipy/matplotlib/tk version...
# ... and restart Optimizer).
if TkFound:
if (not Device.inputFilename) or (not Device.paramName):
Device.reset("InGaN_PN")
# end if
deviceGui = slalomDeviceGui(Device, remoteDir, remoteSSHhost, optimType, minimizeMethod)
deviceGui.show()
deviceGuiValidated = deviceGui.validated
if not deviceGui.validated:
dispError("Optimizer not started (parameters not validated in the GUI)", doExit = True)
# end if
remoteDir = deviceGui.remoteDir
remoteSSHhost = deviceGui.remoteHost
optimType = deviceGui.optimType
minimizeMethod = deviceGui.minimizeMethod
# end if
# end if
except Exception:
# catch only Exception (since sys.exit raise BaseException)
pass
# end try
# </END-DeviceGui>
# ======================================================================================================
# ======================================================================================================
# Woking directory validation
# <START-CurrentDir>
# disable the standard output buffering
sys.stdout = UnbufferedStdout(sys.stdout)
if os.path.isdir(Device.currentDir) == False:
dispError("cannot start the optimizer: Deckbuild input directory not found: " + Device.currentDir, doExit = True)
# end if
if (Device.currentDir.endswith('/') == False) and (Device.currentDir.endswith('\\') == False):
Device.currentDir += dirSepChar
# end if
# <END-CurrentDir>
# ======================================================================================================
# ======================================================================================================
# <START-Output>
if clearOutputDir:
slalomCore.removeOutputFiles(Device.outputDir)
# end if
# <END-Output>
# ======================================================================================================
# ======================================================================================================
# <START-Random>
# Choose randomly a starting point for the optimizer.
# Starting the optimizer with a random point could be a way...
# ...to check the uniqueness of the optimized set of parameters.
if randomInit:
Device.randomInit(printOut = True)
# end if
# <END-Random>
# ======================================================================================================
# ======================================================================================================
# <START-Optimizer>
pythonInterpreter = "python"
def startMonitor(enable = True, dataFilename = None, remoteHost = None, simulator = "atlas"):
""" start the optimizer monitor (only on the client-side) """
if not enable:
return
# end if
try:
import slalomWindow
# tkinter is not always installed by default (e.g. in RedHat Enterprise Linux 7+ or CentOS 6.x)...
# ...if not installed, the optimizer monitor cannot be started...
# ...(just (re)install it or install a more recent python/numpy/scipy/matplotlib/tk version...
# ... and restart OptimizerMonitor).
if not slalomWindow.TkFound:
return
# end if
cmdT = [pythonInterpreter, "slalomMonitor.py"]
if dataFilename is not None:
cmdT.append(dataFilename)
if remoteHost is not None:
cmdT.append(remoteHost)
#end if
#end if
cmdT.append(simulator)
curDir = os.path.dirname(os.path.realpath(__file__))
subprocess.Popen(cmdT, shell=False, cwd=curDir)
except:
pass
# end try
# end startMonitor
# ...and start the optimization
remoteMon = (remoteDir is not None) and (len(remoteDir) > 2) and (remoteSSHhost is not None) and ("@" in remoteSSHhost)
if remoteMon:
# Silvaco, tiberCAD or other simulator tools are installed on a remote server (the most common case)
# copy the needed files and launch the optimizer on the remote server
# Remote dir only used by the optimizer. do not store files there.
try:
tmpDir = os.path.dirname(os.path.realpath(__file__))
if not tmpDir.endswith(dirSepChar):
tmpDir += dirSepChar
# end if
optDir = tmpDir
tmpDir += 'Remote' + dirSepChar
if not os.path.exists(tmpDir):
os.makedirs(tmpDir)
# end if
if not os.path.exists(tmpDir):
dispError("Remote directory not found and cannot be created: " + tmpDir, doExit = True)
# end if
pythonFiles = ['slalom.py', 'slalomCore.py', 'slalomDevice.py', 'slalomSimulator.py']
for fileName in pythonFiles:
shutil.copyfile(optDir + fileName, tmpDir + fileName)
# end if
if Device.modelFilename:
for fileName in Device.modelFilename:
shutil.copyfile(currentDir + fileName, tmpDir + fileName)
# end if
# end if
shutil.copyfile(currentDir + Device.inputFilename, tmpDir + Device.inputFilename)
shutil.copyfile(optDir + 'COPYRIGHT', tmpDir + 'COPYRIGHT')
# build the SLALOM code with the updated device parameters
fileT = open(tmpDir + 'slalom.py', 'r')
fileContent = ""
for lineT in fileT:
lineT = lineT.rstrip("\r\n")
lineX = lineT.lstrip("\t ")
nSpaces = len(lineT) - len(lineX)
prefixT = lineT[0:nSpaces]
if lineX.startswith('currentDir ='):
fileContent += prefixT + 'currentDir = \'' + remoteDir + '\'\n'
continue
elif lineX.startswith('remoteDir ='):
fileContent += prefixT + 'remoteDir = None' + '\n'
continue
elif lineX.startswith('remoteSSHhost ='):
fileContent += prefixT + 'remoteSSHhost = None' + '\n'
continue
elif lineX.startswith('showDeviceGui ='):
fileContent += prefixT + 'showDeviceGui = False' + '\n'
continue
elif lineX.startswith('enableMonitor ='):
fileContent += prefixT + 'enableMonitor = False' + '\n'
continue
# end if
if showDeviceGui and deviceGuiValidated:
if lineX.startswith('deviceType ='):
fileContent += prefixT + 'deviceType = None\n'
continue
elif lineX.startswith('optimType = '):
fileContent += prefixT + 'optimType = ' + '\"' + optimType + '\"\n'
continue
elif lineX.startswith('minimizeMethod = '):
fileContent += prefixT + 'minimizeMethod = ' + '\"' + minimizeMethod + '\"\n'
continue
elif lineX.startswith('Device.'):
if lineX.startswith('Device.inputFilename ='):
fileContent += prefixT + 'Device.deviceType = ' + '\"' + Device.deviceType + '\"\n'
fileContent += prefixT + 'Device.inputFilename = ' + '\"' + Device.inputFilename + '\"\n'
continue
elif lineX.startswith('Device.mainTitle ='):
fileContent += prefixT + 'Device.mainTitle = ' + '\"' + Device.deviceType + '\"\n'
continue
elif lineX.startswith('Device.outputDir ='):
fileContent += prefixT + 'Device.outputDir = currentDir + \"output\" + dirSepChar + \"' + Device.deviceType + '\" + dirSepChar\n'
continue
elif lineX.startswith('Device.modelFilename ='):
if Device.modelFilename:
iCount = len(Device.modelFilename)
if iCount > 0:
fileContent += prefixT + 'Device.modelFilename = ['
for ii in range(0, len(Device.modelFilename)):
fileContent += '\"' + Device.modelFilename[ii] + '\"'
if ii < (iCount - 1):
fileContent += ', '
# end if
# end for
fileContent += ']\n'
# end if
else:
fileContent += prefixT + 'Device.modelFilename = None\n'
# end if
continue
# end if
listName = ['Device.paramName =', 'Device.paramFormat =', 'Device.paramUnit =', 'Device.paramFormatShort =', 'Device.paramFormatNormalized =', 'Device.paramNorm =', 'Device.paramStart =', 'Device.paramEnd =', 'Device.paramInit =', 'Device.paramPoints =', 'Device.paramLogscale =']
listType = ['string', 'string', 'string', 'string', 'string', 'float', 'float', 'float', 'float', 'int', 'bool']
listVal = [Device.paramName, Device.paramFormat, Device.paramUnit, Device.paramFormatShort, Device.paramFormatNormalized, Device.paramNorm, Device.paramStart, Device.paramEnd, Device.paramInit, Device.paramPoints, Device.paramLogscale]
bFound = False
for pp in range(0, len(listName)):
if lineX.startswith(listName[pp]):
fileContent += prefixT + listName[pp]
if listType[pp] == 'float':
fileContent += ' np.array(['
else:
fileContent += ' ['
# end if
iCount = len(listVal[pp])
for ii in range(0, iCount):
if listType[pp] == 'string':
fileContent += '\"' + str(listVal[pp][ii]) + '\"'
else:
fileContent += str(listVal[pp][ii])
# end if
if ii < (iCount - 1):
fileContent += ', '
# end if
# end for
fileContent += ']'
if listType[pp] == 'float':
fileContent += ')'
# end if
fileContent += '\n'
bFound = True
break
# end if
# end for
if bFound:
continue
# end if
# end if
# end if (deviceGui)
fileContent += lineT + '\n'
# end for
fileT.close()
fileT = open(tmpDir + 'slalom.py', 'w')
fileT.write(fileContent)
fileT.close()
print '\nfiles copied to the local directory: ' + tmpDir
STDDEVNULL = open(os.devnull, 'w')
subprocess.check_call(['ssh', remoteSSHhost, 'mkdir', '-p', remoteDir], shell=False, stdout=STDDEVNULL, stderr=STDDEVNULL)
# scp (under Linux) or (under gitbash on Windows): normalize path (but keep an unmodified copy)
tmpDirRaw = tmpDir
if not tmpDir.startswith('/'):
tmpDir = '/' + tmpDir
tmpDir = tmpDir.replace('\\', '/').replace(':', '')
# end if
try:
subprocess.check_call(['scp', '-r', tmpDir + '*', remoteSSHhost + ':' + remoteDir], shell=False, stdout=STDDEVNULL, stderr=STDDEVNULL)
except:
# retry with shell=True (rarely needed, e.g. for some CentOS 6.5 with Python 2.7.12 configs)
try:
subprocess.check_call(['scp -r ' + tmpDir + '* ' + remoteSSHhost + ':' + remoteDir], shell=True, stdout=STDDEVNULL, stderr=STDDEVNULL)
except:
pass
# end try
pass
# end try
print '\nfiles copied to the remote server: ' + remoteSSHhost + ':' + remoteDir
# remove the temporary files
for fileT in os.listdir(tmpDirRaw):
pathT = os.path.join(tmpDirRaw, fileT)
try:
if os.path.isfile(pathT):
os.unlink(pathT)
# end if
except:
pass
# end try
# end for
subprocess.Popen(['ssh', remoteSSHhost, pythonInterpreter, remoteDir + 'slalom.py'], shell=False, stdout=STDDEVNULL, stderr=STDDEVNULL)
bFound = False
for ii in range(0, 5):
time.sleep(0.500)
optimFilename = remoteDir
try:
sshT = subprocess.Popen(['ssh', remoteSSHhost, 'cat', remoteDir + 'ofname.txt'], shell=False, stdout=subprocess.PIPE, stderr=STDDEVNULL)
fileT = sshT.stdout
optimFilename = fileT.read()
bFound = optimFilename and (len(optimFilename) >= 12)
except:
pass
# end try
errMsg = None
try:
sshT = subprocess.Popen(['ssh', remoteSSHhost, 'cat', remoteDir + 'errlog.txt'], shell=False, stdout=subprocess.PIPE, stderr=STDDEVNULL)
fileT = sshT.stdout
errMsg = fileT.read()
except:
pass
# end try
if errMsg and (len(errMsg) > 3):
dispError(errMsg, doExit = True)
# end if
if bFound:
break
# end if
# end for
strT = "\n-------------- SLALOM started on the remote server ------------\n"
strT += "remote SSH host:\n " + remoteSSHhost + "\n"
strT += "remote directory:\n " + remoteDir + "\n"
strT += "remote data filename:\n " + (optimFilename if bFound else "not found (check server status)")
strT += "\n---------------------------------------------------------------\n"
print strT
# set enableMonitor to True to start the optimizer monitor
enableMonitor = enableGUI
if enableMonitor and bFound:
# update the monitor parameters
fileT = open("Settings/slalomMonitor.params", "w")
fileT.write("dataFilename = " + optimFilename)
fileT.write("\nremoteHost = " + remoteSSHhost)
fileT.write("\nremoteHostEnabled = 1")
fileT.write("\nupdateDelay = 30")
fileT.write("\nupdateDelayAuto = 1")
fileT.close()
startMonitor(enable = enableMonitor, dataFilename = optimFilename, remoteHost = remoteSSHhost, simulator=deviceSimulator)
# end if
except Exception as excT:
# catch only Exception (since sys.exit raise BaseException)
dispError("Cannot copy the optimizer files to the remote server: " + str(excT), doExit = True)
pass
else:
# Silvaco, tiberCAD or other simulator tools are installed on this machine
# enable logging for debugging purpose
errFilename = currentDir + 'errlog.txt'
try:
try:
os.unlink(errFilename)
except:
pass
# end try
Optimizer = slalomCore(Device, pythonInterpreter, deviceSimulator)
if optimType == "Optim":
# optimPoints is used to approximate the jacobian. If increased, the optimisation time will dramatically increase. The default value is 21 and the maximum value is 201.
Optimizer.setMinimizeMethod(minimizeMethod, maxIter = maxIter, tolerance = 1e-3, optimPoints = 21)
# end if
# set enableMonitor to True to start the optimizer monitor
enableMonitor = enableGUI
if enableMonitor:
dirSepCharFrom = '/' if ('\\' in currentDir) else '/'
dirSepCharTo = '\\' if ('\\' in currentDir) else '/'
optimizedFilename = Optimizer.getOptimizedFilename()
optimizedFilename = optimizedFilename.replace(dirSepCharFrom, dirSepCharTo)
startMonitor(enable = enableMonitor, dataFilename = optimizedFilename, remoteHost = None, simulator=deviceSimulator)
# end if
# save the current process id...
fileProc = open(Optimizer.getOutputDir() + "proc.txt", "w")
fileProc.write(str(os.getpid()))
fileProc.close()
# ...and start the optimization
Optimizer.start(optimType)
except Exception as excT:
fileErr = open(errFilename, 'w')
fileErr.write(traceback.format_exc())
fileErr.close()
pass
# end try
# end if (remoteMon)
# <END-Optimizer>
# ======================================================================================================