diff --git a/config/config.properties b/config/config.properties index 42fc15d..a684fa5 100644 --- a/config/config.properties +++ b/config/config.properties @@ -1,34 +1,45 @@ -#Thu Feb 13 11:01:45 CET 2020 -autoSaveScanData=true -simulation=false -commandExecutionEvents=false -logDaysToLive=7 -userAuthenticator= -logLevelConsole=Off -scanStreamerPort=-1 -parallelInitialization=false -versionTrackingManual=true +#Thu May 20 15:37:42 CEST 2021 hostName=null userManagement=false instanceName=MicroXAS +disableEmbeddedAttributes=true +autoSaveScanData=true +simulation=false dataServerPort=-1 serverPort=8080 hideServerMessages=false versionTrackingEnabled=true dataPath={data}/{year}_{month}/{date}/{date}{time}_{name} serverEnabled=false +commandExecutionEvents=false +logDaysToLive=7 dataScanReleaseRecords=false depthDimension=0 dataScanPreserveTypes=false +dataScanSaveOutput=false logLevel=Info dataScanFlushRecords=true logPath={logs}/{date}_{time} dataLayout=fda +disableDataFileLogs=false +sessionHandling=On terminalEnabled=false notificationLevel=Off +userAuthenticator= +logLevelConsole=Off terminalPort=3579 +scanStreamerPort=-1 +dataScanSaveScript=false +dataTransferUser= +dataScanSaveSetpoints=false +notifiedTasks=null +parallelInitialization=false +dataTransferPath= createSessionFiles=false +saveConsoleSessionFiles=false versionTrackingLogin={context}/svcusr-hlapp_robot +versionTrackingManual=true versionTrackingRemote=git@git.psi.ch\:pshell_config/x05la.git dataProvider=fda +dataTransferMode=Off saveCommandStatistics=false diff --git a/config/scicat.properties b/config/scicat.properties new file mode 100644 index 0000000..90a2237 --- /dev/null +++ b/config/scicat.properties @@ -0,0 +1,11 @@ +#Thu May 20 14:49:07 CEST 2021 +environment=prod +testParameters=-testenv -user slssim\:slssim +sourceFolder=. +prodParameters=\ -user slssim\:slssim +devParameters=-devenv -user slssim\:slssim +ownerGroup= +type=raw +parameters=-ingest -allowexistingsource -noninteractive -autoarchive +creationLocation=/PSI +principalInvestigator= diff --git a/config/session_metadata.properties b/config/session_metadata.properties new file mode 100644 index 0000000..94ee69b --- /dev/null +++ b/config/session_metadata.properties @@ -0,0 +1,3 @@ +#Thu May 20 15:32:22 CEST 2021 +Energy=Double +Sample=String diff --git a/config/sessions.properties b/config/sessions.properties new file mode 100644 index 0000000..2449eb5 --- /dev/null +++ b/config/sessions.properties @@ -0,0 +1,3 @@ +#Thu May 20 14:45:31 CEST 2021 +SessionCounter=1 +CurrentSession=1 diff --git a/config/settings.properties b/config/settings.properties index e70b363..6961aa6 100644 --- a/config/settings.properties +++ b/config/settings.properties @@ -1,2 +1,2 @@ -#Tue Jul 28 09:52:01 CEST 2020 +#Thu May 20 14:45:13 CEST 2021 FdaBrowser=true diff --git a/config/setup.properties b/config/setup.properties index e9a0b7e..908429e 100644 --- a/config/setup.properties +++ b/config/setup.properties @@ -1,13 +1,16 @@ -#Thu Feb 13 10:13:17 CET 2020 -scriptPath={home}/script +#Wed May 19 14:57:57 CEST 2021 sessionsPath={outp}/sessions +scriptPath={home}/script pluginsPath={home}/plugins configFileDevices={config}/devices.properties +consoleSessionsPath={sessions}/console libraryPath={script}; {script}/Lib configFilePlugins={config}/plugins.properties contextPath={outp}/context extensionsPath={home}/extensions configPath={home}/config +configFileSessions={config}/sessions.properties +userSessionsPath={sessions}/user dataPath={outp}/data devicesPath={home}/devices configFileVariables={config}/variables.properties diff --git a/config/tasks.properties b/config/tasks.properties new file mode 100644 index 0000000..56e5a2f --- /dev/null +++ b/config/tasks.properties @@ -0,0 +1 @@ +Tasks/DetectorsCheck=10.0 diff --git a/config/variables.properties b/config/variables.properties index c2abe18..ed4a0ba 100644 --- a/config/variables.properties +++ b/config/variables.properties @@ -1,2 +1,3 @@ -#Thu Feb 27 09:28:05 CET 2020 -FileSequentialNumber=20 +#Thu May 20 15:37:42 CEST 2021 +FileSequentialNumber=24 +DaySequentialNumber=0 diff --git a/script/Devices/Eiger.py b/script/Devices/Eiger.py new file mode 100644 index 0000000..6fbdbad --- /dev/null +++ b/script/Devices/Eiger.py @@ -0,0 +1,515 @@ +""" +class DEigerClient provides an interface to the EIGER API + +Author: Volker Pilipp +Contact: support@dectris.com +Version: 1.0 +Date: 13/11/2014 +Copyright See General Terms and Conditions (GTC) on http://www.dectris.com + +""" + +import base64 +import os.path +import httplib +import json +import re +import sys +import socket +import fnmatch + +Version = '1.6.0' + +class DEigerClient(object): + """ + class DEigerClient provides a low level interface to the EIGER API + """ + + def __init__(self, host = '127.0.0.1', port = 80, verbose = False, urlPrefix = None, user = None): + """ + Create a client object to talk to the EIGER API. + Args: + host: hostname of the detector computer + port: port usually 80 (http) + verbose: bool value + urlPrefix: String prepended to the urls. Should be None. + user: "username:password". Should be None. + """ + super(DEigerClient,self).__init__() + self._host = host + self._port = port + self._version = Version + self._verbose = verbose + self._urlPrefix = "" + self._user = None + self._connectionTimeout = 900 + self._connection = httplib.HTTPConnection(self._host,self._port, timeout = self._connectionTimeout) + + self.setUrlPrefix(urlPrefix) + self.setUser(user) + + def setVerbose(self,verbose): + """ Switch verbose mode on and off. + Args: + verbose: bool value + """ + self._verbose = bool(verbose) + + def setConnectionTimeout(self, timeout): + """ + If DEigerClient has not received an reply from EIGER after + timeout seconds, the request is aborted. timeout should be at + least as long as the triggering command takes. + Args: + timeout timeout in seconds + """ + self._connectionTimeout = timeout + + def setUrlPrefix(self, urlPrefix): + """Set url prefix, which is the string that is prepended to the + urls. There is usually no need to call the command explicitly. + Args: + urlPrefix: String + """ + if urlPrefix is None: + self._urlPrefix = "" + else: + self._urlPrefix = str(urlPrefix) + if len(self._urlPrefix) > 0 and self._urlPrefix[-1] != "/": + self._urlPrefix += "/" + + def setUser(self, user): + """ + Set username and password for basic authentication. + There is usually no need to call the command explicitly. + Args: + user: String of the form username:password + """ + if user is None: + self._user = None + else: + self._user = base64.encodestring(user).replace('\n', '') + + + + def version(self,module = 'detector'): + """Get version of a api module (i.e. 'detector', 'filewriter') + Args: + module: 'detector' or 'filewriter' + """ + return self._getRequest(url = '/{0}{1}/api/version/'.format(self._urlPrefix,module)) + + def listDetectorConfigParams(self): + """Get list of all detector configuration parameters (param arg of configuration() and setConfiguration()). + Convenience function, that does detectorConfig(param = 'keys') + Returns: + List of parameters. + """ + return self.detectorConfig('keys') + + def detectorConfig(self,param = None, dataType = None): + """Get detector configuration parameter + Args: + param: query the configuration parameter param, if None get full configuration, if 'keys' get all configuration parameters. + dataType: None (= 'native'), 'native' ( return native python object) or 'tif' (return tif data). + Returns: + If param is None get configuration, if param is 'keys' return list of all parameters, else return the value of + the parameter. If dataType is 'native' a dictionary is returned that may contain the keys: value, min, max, + allowed_values, unit, value_type and access_mode. If dataType is 'tif', tiff formated data is returned as a python + string. + """ + return self._getRequest(self._url('detector','config',param),dataType) + + def setDetectorConfig(self, param, value, dataType = None): + """ + Set detector configuration parameter param. + Args: + param: Parameter + value: Value to set. If dataType is 'tif' value may be a string containing the tiff data or + a file object pointing to a tiff file. + dataType: None, 'native' or 'tif'. If None, the data type is auto determined. If 'native' value + may be a native python object (e.g. int, float, str), if 'tif' value shell contain a + tif file (python string or file object to tif file). + Returns: + List of changed parameters. + """ + return self._putRequest(self._url('detector','config',param), dataType, value) + + def setDetectorConfigMultiple(self,*params): + """ + Convenience function that calls setDetectorConfig(param,value,dataType = None) for + every pair param, value in *params. + Args: + *params: List of successive params of the form param0, value0, param1, value1, ... + The parameters are set in the same order they appear in *params. + Returns: + List of changed parameters. + """ + changeList = [] + p = None + for x in params: + if p is None: + p = x + else: + data = x + changeList += self.setDetectorConfig(param = p, value = data, dataType = None) + p = None + return list(set(changeList)) + + def listDetectorCommands(self): + """ + Get list of all commands that may be sent to Eiger via command(). + Returns: + List of commands + """ + return self._getRequest(self._url('detector','command','keys')) + + def sendDetectorCommand(self, command, parameter = None): + """ + Send command to Eiger. The list of all available commands is obtained via listCommands(). + Args: + command: Detector command + parameter: Call command with parameter. If command = "trigger" a float parameter may be passed + Returns: + The commands 'arm' and 'trigger' return a dictionary containing 'sequence id'. + """ + return self._putRequest(self._url('detector','command',command), dataType = 'native', data = parameter) + + + def detectorStatus(self, param = 'keys'): + """Get detector status information + Args: + param: query the status parameter param, if 'keys' get all status parameters. + Returns: + If param is None get configuration, if param is 'keys' return list of all parameters, else return dictionary + that may contain the keys: value, value_type, unit, time, state, critical_limits, critical_values + """ + return self._getRequest(self._url('detector','status',parameter = param)) + + + def fileWriterConfig(self,param = 'keys'): + """Get filewriter configuration parameter + Args: + param: query the configuration parameter param, if 'keys' get all configuration parameters. + Returns: + If param is None get configuration, if param is 'keys' return list of all parameters, else return dictionary + that may contain the keys: value, min, max, allowed_values, unit, value_type and access_mode + """ + return self._getRequest(self._url('filewriter','config',parameter = param)) + + def setFileWriterConfig(self,param,value): + """ + Set file writer configuration parameter param. + Args: + param: parameter + value: value to set + Returns: + List of changed parameters. + """ + return self._putRequest(self._url('filewriter','config',parameter = param), dataType = 'native', data = value) + + def sendFileWriterCommand(self, command): + """ + Send filewriter command to Eiger. + Args: + command: Command to send (up to now only "clear") + Returns: + Empty string + """ + return self._putRequest(self._url("filewriter","command",parameter = command), dataType = "native") + + + def fileWriterStatus(self,param = 'keys'): + """Get filewriter status information + Args: + param: query the status parameter param, if 'keys' get all status parameters. + Returns: + If param is None get configuration, if param is 'keys' return list of all parameters, else return dictionary + that may contain the keys: value, value_type, unit, time, state, critical_limits, critical_values + """ + return self._getRequest(self._url('filewriter','status',parameter = param)) + + def fileWriterFiles(self, filename = None, method = 'GET'): + """ + Obtain file from detector. + Args: + filename: Name of file on the detector side. If None return list of available files + method: Eiger 'GET' (get the content of the file) or 'DELETE' (delete file from server) + Returns: + List of available files if 'filename' is None, + else if method is 'GET' the content of the file. + """ + if method == 'GET': + if filename is None: + return self._getRequest(self._url('filewriter','files')) + else: + return self._getRequest(url = '/{0}data/{1}'.format(self._urlPrefix, filename), dataType = 'hdf5') + elif method == 'DELETE': + return self._delRequest(url = '/{0}data/{1}'.format(self._urlPrefix,filename)) + else: + raise RuntimeError('Unknown method {0}'.format(method)) + + def fileWriterSave(self,filename,targetDir,regex = False): + """ + Saves filename in targetDir. If regex is True, filename is considered to be a regular expression. + Save all files that match filename + Args: + filename: Name of source file, evtl. regular expression + targetDir: Directory, where to store the files + """ + if regex: + pattern = re.compile(filename) + [ self.fileWriterSave(f,targetDir) for f in self.fileWriterFiles() if pattern.match(f) ] + elif any([ c in filename for c in ['*','?','[',']'] ] ): + # for f in self.fileWriterFiles(): + # self._log('DEBUG ', f, ' ', fnmatch.fnmatch(f,filename)) + [ self.fileWriterSave(f,targetDir) for f in self.fileWriterFiles() if fnmatch.fnmatch(f,filename) ] + else: + targetPath = os.path.join(targetDir,filename) + with open(targetPath,'wb') as targetFile: + self._log('Writing ', targetPath) + self._getRequest(url = '/{0}data/{1}'.format(self._urlPrefix, filename), dataType = 'hdf5',fileId = targetFile) + # targetFile.write(self.fileWriterFiles(filename)) + assert os.access(targetPath,os.R_OK) + return + + def monitorConfig(self,param = 'keys'): + """Get monitor configuration parameter + Args: + param: query the configuration parameter param, if 'keys' get all configuration parameters. + Returns: + If param is 'keys' return list of all parameters, else return dictionary + that may contain the keys: value, min, max, allowed_values, unit, value_type and access_mode + """ + return self._getRequest(self._url('monitor','config',parameter = param)) + + def setMonitorConfig(self,param,value): + """ + Set monitor configuration parameter param. + Args: + param: parameter + value: value to set + Returns: + List of changed parameters. + """ + return self._putRequest(self._url('monitor','config',parameter = param), dataType = 'native', data = value) + + def monitorImages(self, param = None): + """ + Obtain file from detector. + Args: + param: Either None (return list of available frames) or "monitor" (return latest frame), + "next" (next image from buffer) or tuple(sequence id, image id) (return specific image) + Returns: + List of available frames (param = None) or tiff content of image file (param = "next", "monitor", (seqId,imgId)) + """ + if param is None: + return self._getRequest(self._url('monitor','images',parameter = None) ) + elif param == "next": + return self._getRequest(self._url('monitor',"images", parameter = "next"), dataType = "tif") + elif param == "monitor": + return self._getRequest(self._url('monitor','images',parameter = "monitor"), dataType = "tif") + else: + try: + seqId = int(param[0]) + imgId = int(param[1]) + return self._getRequest(self._url('monitor',"images", parameter = "{0}/{1}".format(seqId,imgId) ), dataType = 'tif') + except (TypeError, ValueError): + pass + raise RuntimeError('Invalid parameter {0}'.format(param)) + + def monitorSave(self, param, path): + """ + Save frame to path as tiff file. + Args: + param: same as monitorImages() + Returns: + None + """ + data = None + if param in ["next","monitor"]: + data = self.monitorImages(param) + else : + try: + int(param[0]) + int(param[1]) + data = self.monitorImages(param) + except (TypeError, ValueError): + pass + if data is None: + raise RuntimeError('Invalid parameter {0}'.format(param)) + else: + with open(path,'wb') as f: + self._log('Writing ', path) + f.write(data) + assert os.access(path,os.R_OK) + return + + def monitorStatus(self, param): + """Get monitor status information + Args: + param: query the status parameter param, if 'keys' get all status parameters. + Returns: + Dictionary that may contain the keys: value, value_type, unit, time, state, + critical_limits, critical_values + """ + return self._getRequest(self._url('monitor','status',parameter = param)) + + def sendMonitorCommand(self, command): + """ + Send monitor command to Eiger. + Args: + command: Command to send (up to now only "clear") + Returns: + Empty string + """ + return self._putRequest(self._url("monitor","command",parameter = command), dataType = "native") + + def streamConfig(self,param = 'keys'): + """Get stream configuration parameter + Args: + param: query the configuration parameter param, if 'keys' get all configuration parameters. + Returns: + If param is 'keys' return list of all parameters, else return dictionary + that may contain the keys: value, min, max, allowed_values, unit, value_type and access_mode + """ + return self._getRequest(self._url('stream','config',parameter = param)) + + + def setStreamConfig(self,param,value): + """ + Set stream configuration parameter param. + Args: + param: parameter + value: value to set + Returns: + List of changed parameters. + """ + return self._putRequest(self._url('stream','config',parameter = param), dataType = 'native', data = value) + + def streamStatus(self, param): + """Get stream status information + Args: + param: query the status parameter param, if 'keys' get all status parameters. + Returns: + Dictionary that may contain the keys: value, value_type, unit, time, state, + critical_limits, critical_values + """ + return self._getRequest(self._url('stream','status',parameter = param)) + + + + + # + # + # Private Methods + # + # + + def _log(self,*args): + if self._verbose: + print ' '.join([ str(elem) for elem in args ]) + + def _url(self,module,task,parameter = None): + url = "/{0}{1}/api/{2}/{3}/".format(self._urlPrefix, module, self._version, task) + if not parameter is None: + url += '{0}'.format(parameter) + return url + + def _getRequest(self,url,dataType = 'native', fileId = None): + if dataType is None: + dataType = 'native' + if dataType == 'native': + mimeType = 'application/json; charset=utf-8' + elif dataType == 'tif': + mimeType = 'application/tiff' + elif dataType == 'hdf5': + mimeType = 'application/hdf5' + return self._request(url,'GET',mimeType, fileId = fileId) + + def _putRequest(self,url,dataType,data = None): + data, mimeType = self._prepareData(data,dataType) + return self._request(url,'PUT',mimeType, data) + + def _delRequest(self,url): + self._request(url,'DELETE',mimeType = None) + return None + + def _request(self, url, method, mimeType, data = None, fileId = None): + if data is None: + body = '' + else: + body = data + headers = {} + if method == 'GET': + headers['Accept'] = mimeType + elif method == 'PUT': + headers['Content-type'] = mimeType + if not self._user is None: + headers["Authorization"] = "Basic {0}".format(self._user) + + self._log('sending request to {0}'.format(url)) + numberOfTries = 0 + response = None + while response is None: + try: + self._connection.request(method,url, body = data, headers = headers) + response = self._connection.getresponse() + except Exception as e: + numberOfTries += 1 + if numberOfTries == 50: + self._log("Terminate after {0} tries\n".format(numberOfTries)) + raise e + self._log("Failed to connect to host. Retrying\n") + self._connection = httplib.HTTPConnection(self._host,self._port, timeout = self._connectionTimeout) + continue + + + status = response.status + reason = response.reason + if fileId is None: + data = response.read() + else: + bufferSize = 8*1024 + while True: + data = response.read(bufferSize) + if len(data) > 0: + fileId.write(data) + else: + break + + mimeType = response.getheader('content-type','text/plain') + self._log('Return status: ', status, reason) + if not response.status in range(200,300): + raise RuntimeError((reason,data)) + if 'json' in mimeType: + return json.loads(data) + else: + return data + + def _prepareData(self,data, dataType): + if data is None: + return '', 'text/html' + if dataType != 'native': + if type(data) == file: + data = data.read() + if dataType is None: + mimeType = self._guessMimeType(data) + if not mimeType is None: + return data, mimeType + elif dataType == 'tif': + return data, 'application/tiff' + mimeType = 'application/json; charset=utf-8' + return json.dumps({'value':data}), mimeType + + def _guessMimeType(self,data): + if type(data) == str: + if data.startswith('\x49\x49\x2A\x00') or data.startswith('\x4D\x4D\x00\x2A'): + self._log('Determined mimetype: tiff') + return 'application/tiff' + if data.startswith('\x89\x48\x44\x46\x0d\x0a\x1a\x0a'): + self._log('Determined mimetype: hdf5') + return 'application/hdf5' + return None + + diff --git a/script/Devices/EigerTest.py b/script/Devices/EigerTest.py new file mode 100644 index 0000000..e524d88 --- /dev/null +++ b/script/Devices/EigerTest.py @@ -0,0 +1,508 @@ +""" +EigerTest extends the functionality of DEigerClient for convenient +interactive work in a python shell. It should be used only for this +intended purpose or as an example how to use DEigerClient in your own +code. The ipython shell is highly recommended. + +!Do NOT use this code in non-interactive scripts, python modules +or subclasses! Kittens will die and the detector may behave erratic! +For such purposes, please use DEigerClient or EIGER's REST API directly. + +This code is +- NOT official DECTRIS code but written for personal use by the author +- NOT part of the software of EIGER detector systems. +- NOT well tested. +- only provided as is. Do not expect bug fixes, new features or any + support or maintanence by DECTRIS. +- NOT to be distributed without consent of the author! +- not particularly well documented. Be prepared to read the code + and simply try things out. + +Modified: SteB +Version: 20150131 + +Author: Marcus Mueller +Contact: marcus.mueller@dectris.com +Version: 20140922 +""" + +import os +import re +import sys +import time, datetime + +sys.path.insert(0,"/usr/local/dectris/python") +from eigerclient import DEigerClient +try: + import dectris.albula + from quickstart import Monitor + MONITOR_AVAILABLE = True +except ImportError: + MONITOR_AVAILABLE = False + +############################################################# +### Configure IP and PORT of the EIGER system that you are +### accessing with this code below. +# DMZ system +#~ IP = "62.12.129.162" +#~ PORT = "4010" +#~ +# fixed IP, direct connection +try: + IP = sys.argv[1] +except: + IP = "129.129.106.139" +#print "IP", IP +PORT = "80" + +# for printing detector config and values +LISTED_DETECTOR_PARAMS = [ + u'description', + u'detector_number', + u'data_collection_date', + u'frame_time', + u'nimages', + u'ntrigger', + u'trigger_mode', + u'photon_energy', + u'threshold_energy', + u'element', + u'count_time', + u'detector_readout_time', + u'nframes_sum', + u'frame_count_time', + u'frame_period', + #u'sub_image_count_time', + u'auto_summation', + u'summation_nimages', + u'bit_depth_readout', + u'efficiency_correction_applied', + u'flatfield_correction_applied', + u'number_of_excluded_pixels', + u'calibration_type', + u'countrate_correction_applied', + u'countrate_correction_bunch_mode', + u'pixel_mask_applied', + #u'pixel_mask', + u'virtual_pixel_correction_applied', + u'software_version', + u'sensor_material', + u'sensor_thickness', + u'x_pixels_in_detector', + u'y_pixels_in_detector', + u'x_pixel_size', + u'y_pixel_size', + u'wavelength', + u'detector_distance', + u'beam_center_x', + u'beam_center_y', + u'detector_translation', + u'detector_orientation'] +CHECK_DOWNLOAD="/tmp/check_download" + +# for filewriter config to have data bundles of ~ 1GB +# 16M = 20 (45MB x 20) +# 4M = 80 (12MB x 80) +# 1M = 320 ( ?MB x 320) +NIMAGES_PER_FILE=10000 + + +class EigerTest(DEigerClient): + def setEnergy(self, photon_energy, threshold_ratio=0.5): + self.setDetectorConfig("photon_energy", photon_energy) + self.setDetectorConfig("threshold_energy", photon_energy * threshold_ratio) + + def setElement(self, element='Cu'): + self.setDetectorConfig(u'element', element) + + def imageSeries(self, expp, nimages, auto_sum=False, ff_corr=True, + pixel_mask=True): + self.setDetectorConfig("auto_summation", auto_sum) + self.setDetectorConfig("frame_time", expp) + # to avoid warm pixels in center of module + if expp > 0.099: + readout_time = 5.0e-04 # no simultaneous read/write + else: + # simultaneous read/write will give high duty cycle but also warm pixels + readout_time = self.detectorConfig('detector_readout_time')['value'] + self.setDetectorConfig("count_time", expp - readout_time) + self.setDetectorConfig("nimages", nimages) + self.setDetectorConfig("flatfield_correction_applied", ff_corr) + self.setDetectorConfig("pixel_mask_applied", pixel_mask) + + def imageSeries2(self, expp, nimages, auto_sum=True, ff_corr=True, + pixel_mask=True): + self.setDetectorConfig("auto_summation", auto_sum) + self.setDetectorConfig("frame_time", expp) + # to avoid warm pixels in center of module + if expp > 0.099: + readout_time = 5.0e-04 # no simultaneous read/write + else: + # simultaneous read/write will give high duty cycle but also warm pixels + readout_time = self.detectorConfig('detector_readout_time')['value'] + self.setDetectorConfig("count_time", expp - readout_time) + self.setDetectorConfig("nimages", nimages) + self.setDetectorConfig("ntrigger", nimages) + self.setDetectorConfig("flatfield_correction_applied", ff_corr) + self.setDetectorConfig("pixel_mask_applied", pixel_mask) +# self.printConf('time|image') + + def printConf(self, regex='', full=0): + for param in LISTED_DETECTOR_PARAMS: + if full: + if re.search(regex, param): + try: + print str(param).ljust(35), ' = ', str(eiger.detectorConfig(param)['value']).ljust(35),' ', str(eiger.detectorConfig(param)['min']).ljust(35),' ', str(eiger.detectorConfig(param)['max']).ljust(35) + except: + print "" + pass + #print str(param).ljust(35), ' = ', str(eiger.detectorConfig(param)['value']).ljust(35) + else: + if eiger.search(regex, param): + print str(param).ljust(35), ' = ', eiger.detectorConfig(param)['value'] + + + + def setFileNameBase(self, fnBase): + self.setFileWriterConfig("name_pattern", fnBase) + + def setImagesPerFile(self, nimages=1000): + self.setFileWriterConfig("nimages_per_file", nimages) + + def pHello(self, z="today"): + print "Hello " + z + + def printFileWriterConfig(self): + for param in self.fileWriterConfig(): + try: + print param, ' = ', self.fileWriterConfig(param)['value'] + except RuntimeError as e: + print "RuntimeError accessing %s: %s" % (param, e) + + def printFileWriterStatus(self): + for param in self.fileWriterStatus(): + try: + print param, ' = ', self.fileWriterStatus(param)['value'] + except RuntimeError as e: + print "RuntimeError accessing %s: %s" % (param, e) + + def printTempHum(self, all_data=0): + for param in self.detectorStatus(): + if all_data: + if re.search("temp|humidity", param): + print (param).ljust(35), ' = ', self.detectorStatus(param)['value'] + else: + if re.search("th0", param): + print (param).ljust(35), ' = ', self.detectorStatus(param)['value'] + + def printFW(self): + for param in self.detectorStatus(): + if re.search("fw", param): + print (param).ljust(35), ' = ', self.detectorStatus(param)['value'] + + def printDetectorState(self): + print "State: %s" % self.detectorStatus('state')['state'] + print "Error: %s" % self.detectorStatus('error') + + def setDetConMultiple(self, **params): + """ + Convenience function to set a single or multiple detector + configuration parameters in the form (parameter=value[, ...]). + Multiple parameters are set in arbitrary order! + You have to check the print output of this function whether + you obtain the desired detector configuration + """ + for p, data in params.items(): + changeList = self.setDetectorConfig(param=p, value=data, dataType=None) + changes = '' + for changed_param in changeList: + changed_value = self.detectorConfig(changed_param)['value'] + changes += '%s = %s ; ' % (changed_param, str(changed_value)) + print "Setting: %s = %s" % (p, str(data)) + print "Changing: " + changes[:-2] + + def purgeFiles(self, force=False): + f_list = self.fileWriterFiles() + if not force: + print "Files on the detector control unit:" + #~ [print(f) for f in f_list] + for f in f_list: + print f + if force == True or raw_input('Do you really want to purge all ' + 'these files? \n' + 'Then enter y. ') == 'y': + [self.fileWriterFiles(f, 'DELETE') for f in f_list] + #~ for f in f_list: + #~ self.fileWriterFiles(f, 'DELETE') + else: + print "Aborting without deleting files." + + def startMonitor(self): + m = None + if not MONITOR_AVAILABLE: + print "Monitor nor available. Check dependencies." + print "Returning None." + else: + m = Monitor(self) + m.start() + print "Monitor started and monitor object returned." + self._monitor = m + return m + + def arm(self): + self.sendDetectorCommand(u'arm') + + def trigger(self): + self.sendDetectorCommand(u'trigger') + + def disarm(self): + self.sendDetectorCommand(u'disarm') + + def initialize(self, element=None, energy=None): + self.sendDetectorCommand(u'initialize') + if element is not None and energy is not None: + print "You cannot give element AND energy." + elif element is not None: + self.setElement(element) + elif energy is not None: + self.setEnergy(energy) + + def exposure(self, fnBase=None): + """ + tvx style exposure command + """ + if fnBase is not None: + self.setFileNameBase(fnBase=fnBase) + self.setDetectorConfig('data_collection_date', + self.fileWriterStatus('time')['value']) + print "Arm ..." + self.arm() + print "Trigger ..." + self.trigger() + print "Disarm ..." + time.sleep(1) + self.disarm() + print "DONE!" + + def download(self, downloadpath="/tmp"): + try: + matching = self.fileWriterFiles() + except: + print "could not get file list" + if len(matching): + try: + [self.fileWriterSave(i, downloadpath) for i in matching] + except: + print "error saveing - noting deleted" + else: + print "Downloaded ..." + for i in matching: + print i + " to " + str(downloadpath) + [self.fileWriterFiles(i, method = 'DELETE') for i in matching] + print "Deteted " + str(len(matching)) + " file(s)" + + def downloadD(self, downloadpath="/tmp"): + if not os.path.exists(downloadpath): + os.makedirs(downloadpath) + open(CHECK_DOWNLOAD, 'a').close() + while os.path.exists(CHECK_DOWNLOAD): + try: + matching = self.fileWriterFiles() + except: + print "could not get file list" + time.sleep(1) + if len(matching)>0: + try: + [self.fileWriterSave(i, downloadpath) for i in matching] + except: + print "error saveing - noting deleted" + else: + print "Downloaded ..." + for i in matching: + print i + [self.fileWriterFiles(i, method = 'DELETE') for i in matching] + print "Deteted " + str(len(matching)) + " file(s)" + + def stopDownloadD(self): + os.remove(CHECK_DOWNLOAD) + + + + def setup_bt_Nov_2016(self): + """ + setup the beamtime for operation + """ + self.setDetectorConfig("photon_energy", 15000) + print "Photon energy set to: " + str(self.detectorConfig("photon_energy")["value"]) + self.setDetectorConfig("threshold_energy", 10000) + print "Threshold energy set to: " + str(self.detectorConfig("threshold_energy")["value"]) + self.setDetectorConfig("ntrigger",1e6) + self.setDetectorConfig("nimages", 1) + self.setFileWriterConfig("compression_enabled",False) + print "Compression set to: " + str(self.fileWriterConfig("compression_enabled")['value']) + self.setFileWriterConfig("nimages_per_file",20) + + def config_bt_Nov_2016(self,file_name="series",count_time=1): + """ + configure one run - set name and count time (assume that you record 1e6 triggerd images) + """ + readout_time = self.detectorConfig('detector_readout_time')['value'] + self.setDetectorConfig("count_time", count_time) + self.setDetectorConfig("frame_time", count_time + readout_time) + self.setFileWriterConfig("name_pattern", file_name + "_$id") + print "Images with " + str(self.detectorConfig("count_time")["value"]) + " s" + print "Named to " + str(self.fileWriterConfig("name_pattern")["value"]) + + def setup_of(self): + """ + setup the beamtime for operation + """ + self.setDetectorConfig("photon_energy", 19000) + print "Photon energy set to: " + str(self.detectorConfig("photon_energy")["value"]) + self.setDetectorConfig("threshold_energy", 5000) + print "Threshold energy set to: " + str(self.detectorConfig("threshold_energy")["value"]) + self.setDetectorConfig("ntrigger",1e6) + self.setDetectorConfig("nimages", 1) + self.setDetectorConfig("trigger_mode", 'exts') + self.setFileWriterConfig("compression_enabled",False) + print "Compression set to: " + str(self.fileWriterConfig("compression_enabled")['value']) + self.setFileWriterConfig("nimages_per_file",20) + + def setup_of_exte(self): + """ + setup the beamtime for operation + """ + self.setDetectorConfig("photon_energy", 19000) + print "Photon energy set to: " + str(self.detectorConfig("photon_energy")["value"]) + self.setDetectorConfig("threshold_energy", 5000) + print "Threshold energy set to: " + str(self.detectorConfig("threshold_energy")["value"]) + self.setDetectorConfig("ntrigger",1e6) + self.setDetectorConfig("nimages", 1) + self.setDetectorConfig("trigger_mode", 'exte') + self.setFileWriterConfig("compression_enabled",False) + print "Compression set to: " + str(self.fileWriterConfig("compression_enabled")['value']) + self.setFileWriterConfig("nimages_per_file",20) + + def setup_sg(self): + """ + setup the beamtime for operation + """ + self.setDetectorConfig("photon_energy", 19000) + print "Photon energy set to: " + str(self.detectorConfig("photon_energy")["value"]) + self.setDetectorConfig("threshold_energy", 5000) + print "Threshold energy set to: " + str(self.detectorConfig("threshold_energy")["value"]) + self.setDetectorConfig("ntrigger",1e6) + self.setDetectorConfig("nimages", 1) + self.setDetectorConfig("trigger_mode", 'ints') + self.setFileWriterConfig("compression_enabled",False) + print "Compression set to: " + str(self.fileWriterConfig("compression_enabled")['value']) + self.setFileWriterConfig("nimages_per_file",20) + + def config_filename_countime(self,file_name="series",count_time=1): + """ + configure one run - set name and count time (assume that you record 1e6 triggerd images) + """ + readout_time = self.detectorConfig('detector_readout_time')['value'] + self.setDetectorConfig("count_time", count_time) + self.setDetectorConfig("frame_time", count_time + readout_time) + self.setFileWriterConfig("name_pattern", file_name + "_$id") + print "Images with " + str(self.detectorConfig("count_time")["value"]) + " s" + print "Named to " + str(self.fileWriterConfig("name_pattern")["value"]) + + + def exp(self,frame_time=1,nimages=1,ntrigger=1000): + """ + tvx style exposure command + """ + self.setDetectorConfig("frame_time", frame_time) + readout_time = self.detectorConfig('detector_readout_time')['value'] + self.setDetectorConfig("count_time", frame_time - readout_time) + self.setDetectorConfig("nimages", nimages) + self.setDetectorConfig("ntrigger",ntrigger) + if nimages < NIMAGES_PER_FILE: + nipf = nimages + else: + nipf = NIMAGES_PER_FILE + self.setFileWriterConfig("nimages_per_file",nipf+1) + + print "Arm ..." + self.arm() + print "Trigger ..." + print(datetime.datetime.now().strftime("%H:%M:%S.%f")) + self.trigger() + print(datetime.datetime.now().strftime("%H:%M:%S.%f")) + print "Disarm ..." + time.sleep(1) + self.disarm() + print "DONE!" + self.printConf('time|image') + + def hdf_file_check(self): + """ + tvx style exposure command + """ + self.setDetectorConfig("omega_range_average",0.1) + self.setDetectorConfig("frame_time", 1) + readout_time = self.detectorConfig('detector_readout_time')['value'] + self.setDetectorConfig("count_time", 1 - readout_time) + self.setDetectorConfig("nimages", 1) + self.setDetectorConfig("ntrigger",1) + + self.setFileWriterConfig("nimages_per_file",1+1) + + print "Arm ..." + self.arm() + print "Trigger ..." + self.trigger() + print "Disarm ..." + time.sleep(1) + self.disarm() + print "DONE!" + self.printConf('time|image') + + def testLoop(self, nloops, purge=True, **kwargs): + print "#" * 72 + "\nRunning test loop with %d series.\n" % nloops + self.imageSeries(**kwargs) + print "-" * 72 + for n in range(nloops): + print "Running series %d" % (n + 1) + self.exposure() + if purge: + print "Purging files." + time.sleep(1) + self.purgeFiles(force=True) + print "-" * 72 + print "Finished %d series." % nloops + print "#" * 72 + "\n" + + +if __name__ == '__main__': + print "EIGER test client - running at " + str(IP) + eiger = EigerTest(host=IP, port=PORT, verbose=False) + state_now = eiger.detectorStatus("state")["value"] + print "Detector: " + eiger.detectorStatus("state")["value"] + if state_now is "na": + print "!!! initalize by typing: eiger.initialize() !!!" + print "" + eiger.printTempHum() + + + + + #~ e.setDetectorConfig('auto_summation', False) + #~ e.setDetectorConfig('countrate_correction_applied', True) + #~ e.setDetectorConfig('element', 'Cu') + + #~ e.sendDetectorCommand(u'initialize') + #~ e.setEnergy(12400) + #~ e.imageSeries(expp=0.2, nimages=5) + #~ e.printTempHum() + # ~ e.setImagesPerFile(100) + #~ e.printDetectorConfig() + #~ e.printFileWriterConfig() + #~ print "Exposure ..." + #~ e.exposure(fnBase='test') + #~ print "... done" + #~ e.fileWriterSave(filename='test*', targetDir=os.path.curdir) + + diff --git a/script/Tasks/DetectorsCheck.py b/script/Tasks/DetectorsCheck.py new file mode 100644 index 0000000..fc34cfc --- /dev/null +++ b/script/Tasks/DetectorsCheck.py @@ -0,0 +1,16 @@ +#print "Detectors Check" + + +for name, info in DETECTORS.items(): + path = info["path"] + try: + #print path, + caget_str(path) + info["enabled"] = True + #print " ok" + except: + info["enabled"] = False + #print " error" + + + \ No newline at end of file diff --git a/script/201812041240_VERSI_pinholescan.py b/script/Users/201812041240_VERSI_pinholescan.py similarity index 100% rename from script/201812041240_VERSI_pinholescan.py rename to script/Users/201812041240_VERSI_pinholescan.py diff --git a/script/local.py b/script/local.py index 347d019..3e0e184 100644 --- a/script/local.py +++ b/script/local.py @@ -21,6 +21,12 @@ crlogic_config["class"] = "ch.psi.pshell.crlogic.CrlogicScan" run("CPython/wrapper") +DETECTORS={ \ + 'Eiger4m': {"path":"X05LA-ES1-EIGER1:cam1:FilePath", "enabled": False}, \ + 'XRayEye': {"path":"X05LA-ES2-GIGE01:TIFF1:FilePath", "enabled": False} \ + } + + ################################################################################################### # EPICS utilities ################################################################################################### @@ -45,3 +51,34 @@ def run_fda(file_name, arguments={}): Run FDA loop """ ProcessorFDA().execute(file_name,arguments) + +################################################################################################### +# System callbaks +################################################################################################### + + +def on_command_started(info): + pass + +def on_command_finished(info): + pass + +def on_change_data_path(path): + if path is not None: + print "Data path: " + str(path) + raw_data_folder = path + "/raw_data" + os.makedirs(raw_data_folder) + #with open(raw_data_folder + "/test.txt", "w") as f: + # f.write("Success") + for name, info in DETECTORS.items(): + log(name + " enabled = " + str(info["enabled"])) + if info["enabled"]: + channel_path = info["path"] + caput_str(channel_path, raw_data_folder + "/" + name) + + +def on_session_started(id): + pass + +def on_session_finished(id): + pass