lots of (seemingly) unused files
This commit is contained in:
@@ -0,0 +1,96 @@
|
||||
import numpy as np
|
||||
import h5py
|
||||
from epics import PV
|
||||
import os
|
||||
import data_api as api
|
||||
import datetime
|
||||
from threading import Thread
|
||||
from time import sleep
|
||||
|
||||
from .utilities import Acquisition
|
||||
|
||||
class Ioxostools:
|
||||
def __init__(self,
|
||||
default_channel_list={'listname':[]},
|
||||
default_file_path='%s',
|
||||
elog=None,
|
||||
sleeptime=0.0305,
|
||||
channel_list = None):
|
||||
self.sleeptime = sleeptime
|
||||
self._default_file_path = default_file_path
|
||||
self._default_channel_list = default_channel_list
|
||||
self._elog = elog
|
||||
self.channels = []
|
||||
if not channel_list:
|
||||
print('No channels specified, using default list \'%s\' instead.'%list(self._default_channel_list.keys())[0])
|
||||
self.channel_list = self._default_channel_list[list(self._default_channel_list.keys())[0]]
|
||||
for channel in self.channel_list:
|
||||
self.channels.append(PV(channel))
|
||||
|
||||
def h5(self,fina=None,channel_list = None, N_pulses=None,default_path=True,queue_size=100):
|
||||
channel_list = self.channel_list
|
||||
if default_path:
|
||||
fina = self._default_file_path%fina
|
||||
|
||||
if os.path.isfile(fina):
|
||||
print('!!! File %s already exists, would you like to delete it?'%fina)
|
||||
if input('(y/n)')=='y':
|
||||
print('Deleting %s .'%fina)
|
||||
os.remove(fina)
|
||||
else:
|
||||
return
|
||||
|
||||
data = []
|
||||
counters = []
|
||||
channels = self.channels
|
||||
|
||||
for channel in channels:
|
||||
channelval = channel.value
|
||||
if type(channelval) == np.ndarray:
|
||||
shape = (N_pulses,)+channelval.shape
|
||||
dtype = channelval.dtype
|
||||
else:
|
||||
shape = (N_pulses,)
|
||||
dtype = type(channelval)
|
||||
data.append(np.ndarray(shape, dtype = dtype))
|
||||
counters.append(0)
|
||||
|
||||
def cb_getdata(ch=None, m=0,*args, **kwargs):
|
||||
sleep(0.001)
|
||||
data[m][counters[m]] = kwargs['value']
|
||||
counters[m] =counters[m] + 1
|
||||
if counters[m] == N_pulses:
|
||||
ch.clear_callbacks()
|
||||
|
||||
for (m, channel) in enumerate(channels):
|
||||
channel.add_callback(callback = cb_getdata, ch = channel, m=m)
|
||||
while True:
|
||||
sleep(0.01)
|
||||
if np.mean(counters) == N_pulses:
|
||||
break
|
||||
|
||||
|
||||
|
||||
#for n in range(N_pulses):
|
||||
# channelvals = []
|
||||
|
||||
|
||||
# sleep(self.sleeptime)
|
||||
|
||||
f = h5py.File(name = fina, mode = 'w')
|
||||
for (n, channel) in enumerate(channel_list):
|
||||
f.create_dataset(name = channel, data = data[n])
|
||||
return data
|
||||
|
||||
|
||||
def acquire(self,file_name=None,Npulses=100):
|
||||
file_name += '.h5'
|
||||
def acquire():
|
||||
self.h5(fina=file_name,N_pulses=Npulses)
|
||||
return Acquisition(acquire=acquire,acquisition_kwargs={'file_names':[file_name], 'Npulses':Npulses},hold=False)
|
||||
|
||||
def wait_done(self):
|
||||
self.check_running()
|
||||
self.check_still_running()
|
||||
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
from ..devices_general.smaract import SmarActRecord
|
||||
from epics import PV
|
||||
|
||||
class XTG:
|
||||
def __init__(self,Id,alias_namespace=None):
|
||||
self.Id = Id
|
||||
|
||||
|
||||
### sample smaract motors ###
|
||||
self.sx = SmarActRecord(Id+':TRX3')
|
||||
self.sy = SmarActRecord(Id+':TRY3')
|
||||
|
||||
|
||||
### grating 1 motors ###
|
||||
self.g1x = SmarActRecord(Id+':TRX1')
|
||||
self.g1y = SmarActRecord(Id+':TRY1')
|
||||
self.g1z = SmarActRecord(Id+':TRZ1')
|
||||
### grating 2 motors ###
|
||||
self.g2x = SmarActRecord(Id+':TRX2')
|
||||
self.g2y = SmarActRecord(Id+':TRY2')
|
||||
self.g2z = SmarActRecord(Id+':TRZ2')
|
||||
|
||||
def get_adjustable_positions_str(self):
|
||||
ostr = '*****SmarAct motor positions******\n'
|
||||
|
||||
for tkey,item in self.__dict__.items():
|
||||
if hasattr(item,'get_current_value'):
|
||||
pos = item.get_current_value()
|
||||
ostr += ' ' + tkey.ljust(10) + ' : % 14g\n'%pos
|
||||
return ostr
|
||||
|
||||
|
||||
def __repr__(self):
|
||||
return self.get_adjustable_positions_str()
|
||||
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
import sys
|
||||
sys.path.append("..")
|
||||
from ..devices_general.motors import MotorRecord
|
||||
from epics import PV
|
||||
|
||||
class EXP:
|
||||
def __init__(self,Id,alias_namespace=None):
|
||||
self.Id = Id
|
||||
|
||||
|
||||
### motors 1.5M JF Zaber ###
|
||||
#self.det_x = MotorRecord(Id+':MOT_TX')
|
||||
#self.det_y = MotorRecord(Id+':MOT_TY')
|
||||
self.zaber_x = MotorRecord(Id+':MOT_TZ')
|
||||
self.qioptiq_zoom = MotorRecord(Id+':MOT_QIOPT_Z')
|
||||
|
||||
### motors crystal ###
|
||||
#self.c_focus = MotorRecord(Id+':MOT_VT80')
|
||||
#self.c_rot = MotorRecord(Id+':MOT_ROT')
|
||||
|
||||
def __repr__(self):
|
||||
s = "**Detector and crystal positions**\n"
|
||||
motors = "zaber_x qioptiq_zoom".split()
|
||||
for motor in motors:
|
||||
s+= " - %s %.4f\n"%(motor,getattr(self,motor).wm())
|
||||
s+= "\n"
|
||||
|
||||
return s
|
||||
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
import sys
|
||||
sys.path.append("..")
|
||||
from ..devices_general.motors import MotorRecord
|
||||
from epics import PV
|
||||
|
||||
class GPS:
|
||||
def __init__(self,Id,alias_namespace=None):
|
||||
self.Id = Id
|
||||
|
||||
|
||||
### motors heavy load gps table ###
|
||||
self.xhl = MotorRecord(Id+':MOT_TBL_TX')
|
||||
self.zhl = MotorRecord(Id+':MOT_TBL_TZ')
|
||||
self.yhl = MotorRecord(Id+':MOT_TBL_TY')
|
||||
self.th = MotorRecord(Id+':MOT_MY_RYTH')
|
||||
try:
|
||||
self.rxhl = MotorRecord(Id+':MOT_TBL_RX')
|
||||
except:
|
||||
print ('GPS.pitch not found')
|
||||
pass
|
||||
try:
|
||||
self.ryhl = MotorRecord(Id+':MOT_TBL_RY')
|
||||
except:
|
||||
print ('GPS.roll not found')
|
||||
pass
|
||||
|
||||
### motors heavy load gonio base ###
|
||||
self.xmu = MotorRecord(Id+':MOT_HEX_TX')
|
||||
self.mu = MotorRecord(Id+':MOT_HEX_RX')
|
||||
self.tth = MotorRecord(Id+':MOT_NY_RY2TH')
|
||||
self.xbase = MotorRecord(Id+':MOT_TX')
|
||||
self.ybase = MotorRecord(Id+':MOT_TY')
|
||||
|
||||
self.hex_x = PV("SARES20-HEX_PI:POSI-X")
|
||||
self.hex_y = PV("SARES20-HEX_PI:POSI-Y")
|
||||
self.hex_z = PV("SARES20-HEX_PI:POSI-Z")
|
||||
self.hex_u = PV("SARES20-HEX_PI:POSI-U")
|
||||
self.hex_v = PV("SARES20-HEX_PI:POSI-V")
|
||||
self.hex_w = PV("SARES20-HEX_PI:POSI-W")
|
||||
|
||||
def __repr__(self):
|
||||
s = "**Heavy Load**\n"
|
||||
motors = "xmu mu tth xbase ybase".split()
|
||||
for motor in motors:
|
||||
s+= " - %s %.4f\n"%(motor,getattr(self,motor).wm())
|
||||
|
||||
s+= " - HLX %.4f\n"%(self.xhl.wm())
|
||||
s+= " - HLY %.4f\n"%(self.yhl.wm())
|
||||
s+= " - HLZ %.4f\n"%(self.zhl.wm())
|
||||
s+= " - HLTheta %.4f\n"%(self.th.wm())
|
||||
s+= "\n"
|
||||
|
||||
s+= "**Gonio**\n"
|
||||
motors = "xmu mu tth xbase ybase".split()
|
||||
for motor in motors:
|
||||
s+= " - %s %.4f\n"%(motor,getattr(self,motor).wm())
|
||||
s+= "\n"
|
||||
|
||||
s+= "**Hexapod**\n"
|
||||
motors = "x y z u v w".split()
|
||||
for motor in motors:
|
||||
s+= " - hex_%s %.4f\n"%(motor,getattr(self,"hex_"+motor).get())
|
||||
return s
|
||||
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
import sys
|
||||
sys.path.append("..")
|
||||
from ..devices_general.motors import MotorRecord
|
||||
from epics import PV
|
||||
|
||||
class XRD:
|
||||
def __init__(self,Id,alias_namespace=None):
|
||||
self.Id = Id
|
||||
|
||||
|
||||
### motors heavy load table ###
|
||||
self.xhl = MotorRecord(Id+':MOT_TBL_TX')
|
||||
self.zhl = MotorRecord(Id+':MOT_TBL_TZ')
|
||||
self.yhl = MotorRecord(Id+':MOT_TBL_TY')
|
||||
self.th = MotorRecord(Id+':MOT_MY_RYTH')
|
||||
self.zaber_x = MotorRecord('SARES20-EXP'+':MOT_TZ')
|
||||
try:
|
||||
self.rxhl = MotorRecord(Id+':MOT_TBL_RX')
|
||||
except:
|
||||
print ('GPS.pitch not found')
|
||||
pass
|
||||
try:
|
||||
self.ryhl = MotorRecord(Id+':MOT_TBL_RY')
|
||||
except:
|
||||
print ('GPS.roll not found')
|
||||
pass
|
||||
|
||||
### motors heavy load gonio base ###
|
||||
#self.xmu = MotorRecord(Id+':MOT_HEX_TX')
|
||||
#self.mu = MotorRecord(Id+':MOT_HEX_RX')
|
||||
self.gamma = MotorRecord(Id+':MOT_NY_RY2TH')
|
||||
self.xbase = MotorRecord(Id+':MOT_TX')
|
||||
self.ybase = MotorRecord(Id+':MOT_TY')
|
||||
|
||||
#self.hex_x = PV("SARES20-HEX_PI:POSI-X")
|
||||
#self.hex_y = PV("SARES20-HEX_PI:POSI-Y")
|
||||
#self.hex_z = PV("SARES20-HEX_PI:POSI-Z")
|
||||
#self.hex_u = PV("SARES20-HEX_PI:POSI-U")
|
||||
#self.hex_v = PV("SARES20-HEX_PI:POSI-V")
|
||||
#self.hex_w = PV("SARES20-HEX_PI:POSI-W")
|
||||
|
||||
|
||||
### motors XRD arm ###
|
||||
self.delta = MotorRecord(Id+':MOT_DT_RX2TH')
|
||||
self.det_z = MotorRecord(Id+':MOT_D_T')
|
||||
self.cam_z = MotorRecord(Id+':MOT_P_T')
|
||||
|
||||
|
||||
|
||||
|
||||
def __repr__(self):
|
||||
|
||||
s= "**Table**\n"
|
||||
motors = "xhl yhl zhl zaber_x th".split()
|
||||
for motor in motors:
|
||||
s+= " - %s %.4f\n"%(motor,getattr(self,motor).wm())
|
||||
s+= "\n"
|
||||
s+= "**Gonio**\n"
|
||||
motors = " xbase ybase gamma delta det_z cam_z".split()
|
||||
for motor in motors:
|
||||
s+= " - %s %.4f\n"%(motor,getattr(self,motor).wm())
|
||||
s+= "\n"
|
||||
|
||||
#s+= "**Hexapod**\n"
|
||||
#motors = "x y z u v w".split()
|
||||
#for motor in motors:
|
||||
# s+= " - hex_%s %.4f\n"%(motor,getattr(self,"hex_"+motor).get())
|
||||
return s
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
class Hexapod_PI:
|
||||
def __init__(self, Id):
|
||||
self.Id = Id
|
||||
self.x, self.y, self.z = [
|
||||
ValueRdback(self.id + f":SET-POSI-{i}", self.id + f":POSI-{i}")
|
||||
for i in "XYZ"
|
||||
]
|
||||
self.dx, self.dy, self.dz = [
|
||||
ValueRdback(self.id + f":SET-POSI-{i}", self.id + f":POSI-{i}")
|
||||
for i in "UVW"
|
||||
]
|
||||
self._piv_x, self._piv_y, self._piv_z = [
|
||||
ValueRdback(self.id + f":SET-PIVOT-{i}", self.id + f":PIVOT-R-{i}")
|
||||
for i in "RST"
|
||||
]
|
||||
@@ -0,0 +1,84 @@
|
||||
import sys
|
||||
|
||||
sys.path.append("..")
|
||||
from ..devices_general.motors import MotorRecord
|
||||
from epics import PV
|
||||
from ..aliases import Alias
|
||||
|
||||
|
||||
class XRD:
|
||||
def __init__(self, name=None, Id=None, configuration=[]):
|
||||
"""X-ray diffractometer platform in AiwssFEL Bernina.\
|
||||
<configuration> : list of elements mounted on
|
||||
the plaform, options are kappa, nutable, hlgonio, polana"""
|
||||
self.Id = Id
|
||||
self.name = name
|
||||
self.alias = Alias(name)
|
||||
|
||||
### motors base platform ###
|
||||
self.xbase = MotorRecord(Id + ":MOT_TX", name="xbase")
|
||||
self.ybase = MotorRecord(Id + ":MOT_TY", name="ybase")
|
||||
self.rxbase = MotorRecord(Id + ":MOT_RX", name="rxbase")
|
||||
self.omega = MotorRecord(Id + ":MOT_MY_RYTH", name="omega")
|
||||
|
||||
### motors XRD detector arm ###
|
||||
self.gamma = MotorRecord(Id + ":MOT_NY_RY2TH", name="gam")
|
||||
self.delta = MotorRecord(Id + ":MOT_DT_RX2TH", name="del")
|
||||
|
||||
### motors XRD area detector branch ###
|
||||
self.tdet = MotorRecord(Id + ":MOT_D_T", name="tdet")
|
||||
|
||||
### motors XRD polarisation analyzer branch ###
|
||||
self.tpol = MotorRecord(Id + ":MOT_P_T", name="tpol")
|
||||
# missing: slits of flight tube
|
||||
|
||||
### motors heavy load goniometer ###
|
||||
self.xhl = MotorRecord(Id + ":MOT_TBL_TX", name="xhl")
|
||||
self.zhl = MotorRecord(Id + ":MOT_TBL_TZ", name="zhl")
|
||||
self.yhl = MotorRecord(Id + ":MOT_TBL_TY", name="yhl")
|
||||
try:
|
||||
self.rxhl = MotorRecord(Id + ":MOT_TBL_RX", name="rxhl")
|
||||
except:
|
||||
print("GPS.pitch not found")
|
||||
pass
|
||||
try:
|
||||
self.ryhl = MotorRecord(Id + ":MOT_TBL_RY", name="rxhl")
|
||||
except:
|
||||
print("GPS.roll not found")
|
||||
pass
|
||||
|
||||
### motors nu table ###
|
||||
self.tnu = MotorRecord(Id + ":MOT_HEX_TX", name="tnu")
|
||||
self.nu = MotorRecord(Id + ":MOT_HEX_RX", name="nu")
|
||||
|
||||
### motors PI hexapod ###
|
||||
self.hex_x = PV("SARES20-HEX_PI:POSI-X")
|
||||
self.hex_y = PV("SARES20-HEX_PI:POSI-Y")
|
||||
self.hex_z = PV("SARES20-HEX_PI:POSI-Z")
|
||||
self.hex_u = PV("SARES20-HEX_PI:POSI-U")
|
||||
self.hex_v = PV("SARES20-HEX_PI:POSI-V")
|
||||
self.hex_w = PV("SARES20-HEX_PI:POSI-W")
|
||||
|
||||
def __repr__(self):
|
||||
s = "**Heavy Load**\n"
|
||||
motors = "xmu mu tth xbase ybase".split()
|
||||
for motor in motors:
|
||||
s += " - %s %.4f\n" % (motor, getattr(self, motor).wm())
|
||||
|
||||
s += " - xhl %.4f\n" % (self.xhl.wm())
|
||||
s += " - yhl %.4f\n" % (self.yhl.wm())
|
||||
s += " - zhl %.4f\n" % (self.zhl.wm())
|
||||
s += " - th %.4f\n" % (self.th.wm())
|
||||
s += "\n"
|
||||
|
||||
s += "**Gonio**\n"
|
||||
motors = "xmu mu tth delta det_z cam_z xbase ybase".split()
|
||||
for motor in motors:
|
||||
s += " - %s %.4f\n" % (motor, getattr(self, motor).wm())
|
||||
s += "\n"
|
||||
|
||||
s += "**Hexapod**\n"
|
||||
motors = "x y z u v w".split()
|
||||
for motor in motors:
|
||||
s += " - hex_%s %.4f\n" % (motor, getattr(self, "hex_" + motor).get())
|
||||
return s
|
||||
+387
@@ -0,0 +1,387 @@
|
||||
import numpy as np
|
||||
from epics import caget
|
||||
from epics import PV
|
||||
from ..eco_epics.utilities_epics import EnumWrapper
|
||||
|
||||
from cam_server import PipelineClient
|
||||
from cam_server.utils import get_host_port_from_stream_address
|
||||
from bsread import source, SUB
|
||||
import subprocess
|
||||
import h5py
|
||||
from time import sleep
|
||||
from threading import Thread
|
||||
from datetime import datetime
|
||||
|
||||
from ..acquisition.utilities import Acquisition
|
||||
|
||||
from bsread import Source
|
||||
from bsread.h5 import receive
|
||||
from bsread.avail import dispatcher
|
||||
import zmq
|
||||
import os
|
||||
import data_api as api
|
||||
#import datetime
|
||||
#from threading import Thread
|
||||
#import datetime
|
||||
#from .utilities import Acquisition
|
||||
|
||||
try:
|
||||
import sys, os
|
||||
tpath = os.path.dirname(__file__)
|
||||
sys.path.insert(0,os.path.join(tpath,'../../detector_integration_api'))
|
||||
#ask Leo(2018.03.14):
|
||||
#sys.path.insert(0,os.path.join(tpath,'../../jungfrau_utils'))
|
||||
from detector_integration_api import DetectorIntegrationClient
|
||||
except:
|
||||
print('NB: detector integration could not be imported!')
|
||||
|
||||
|
||||
_cameraArrayTypes = ['monochrome','rgb']
|
||||
|
||||
class CameraCA:
|
||||
def __init__(self, pvname, cameraArrayType='monochrome',elog=None):
|
||||
self.Id = pvname
|
||||
self.isBS = False
|
||||
self.px_height = None
|
||||
self.px_width = None
|
||||
self.elog = elog
|
||||
|
||||
def get_px_height(self):
|
||||
if not self.px_height:
|
||||
self.px_height = caget(self.Id + ':HEIGHT')
|
||||
return self.px_height
|
||||
|
||||
def get_px_width(self):
|
||||
if not self.px_width:
|
||||
self.px_width = caget(self.Id + ':WIDTH')
|
||||
return self.px_width
|
||||
|
||||
def get_data(self):
|
||||
w = self.get_px_width()
|
||||
h = self.get_px_height()
|
||||
numpix = int(caget(self.Id+':FPICTURE.NORD'))
|
||||
i = caget(self.Id+':FPICTURE', count=numpix)
|
||||
return i.reshape(h,w)
|
||||
|
||||
def record_images(self,fina,N_images,sleeptime=0.2):
|
||||
with h5py.File(fina,'w') as f:
|
||||
d = []
|
||||
for n in range(N_images):
|
||||
d.append(self.get_data())
|
||||
sleep(sleeptime)
|
||||
f['images'] = np.asarray(d)
|
||||
|
||||
def gui(self, guiType='xdm'):
|
||||
""" Adjustable convention"""
|
||||
cmd = ['caqtdm','-macro']
|
||||
|
||||
cmd.append('\"NAME=%s,CAMNAME=%s\"'%(self.Id, self.Id))
|
||||
cmd.append('/sf/controls/config/qt/Camera/CameraMiniView.ui')
|
||||
return subprocess.Popen(' '.join(cmd),shell=True)
|
||||
|
||||
#/sf/controls/config/qt/Camera/CameraMiniView.ui" with macro "NAME=SAROP21-PPRM138,CAMNAME=SAROP21-PPRM138
|
||||
|
||||
class CameraBS:
|
||||
def __init__(self,host=None,port=None,elog=None):
|
||||
self._stream_host = host
|
||||
self._stream_port = port
|
||||
|
||||
def checkServer(self):
|
||||
# Check if your instance is running on the server.
|
||||
if self._instance_id not in client.get_server_info()["active_instances"]:
|
||||
raise ValueError("Requested pipeline is not running.")
|
||||
|
||||
def get_images(self,N_images):
|
||||
data = []
|
||||
with source(host=self._stream_host, port=self._stream_port, mode=SUB) as input_stream:
|
||||
input_stream.connect()
|
||||
|
||||
for n in range(N_images):
|
||||
data.append(input_stream.receive().data.data['image'].value)
|
||||
return data
|
||||
|
||||
def record_images(self,fina,N_images,dsetname='images'):
|
||||
ds = None
|
||||
with h5py.File(fina,'w') as f:
|
||||
with source(host=self._stream_host, port=self._stream_port, mode=SUB) as input_stream:
|
||||
|
||||
input_stream.connect()
|
||||
|
||||
for n in range(N_images):
|
||||
image = input_stream.receive().data.data['image'].value
|
||||
if not ds:
|
||||
ds = f.create_dataset(dsetname,dtype=image.dtype, shape=(N_images,)+image.shape)
|
||||
ds[n,:,:] = image
|
||||
|
||||
class FeDigitizer:
|
||||
def __init__(self,Id,elog=None):
|
||||
self.Id = Id
|
||||
self.gain = EnumWrapper(Id+'-WD-gain')
|
||||
self._bias = PV(Id+'-HV_SET')
|
||||
self.channels = [
|
||||
Id+'-BG-DATA',
|
||||
Id+'-BG-DRS_TC',
|
||||
Id+'-BG-PULSEID-valid',
|
||||
Id+'-DATA',
|
||||
Id+'-DRS_TC',
|
||||
Id+'-PULSEID-valid']
|
||||
|
||||
def set_bias(self, value):
|
||||
self._bias.put(value)
|
||||
|
||||
def get_bias(self):
|
||||
return self._bias.value
|
||||
|
||||
class DiodeDigitizer:
|
||||
def __init__(self,Id,VME_crate=None,link=None,
|
||||
ch_0=7,ch_1=8, elog=None):
|
||||
self.Id = Id
|
||||
if VME_crate:
|
||||
self.diode_0 = FeDigitizer('%s:Lnk%dCh%d'%(VME_crate,link,ch_0))
|
||||
self.diode_1 = FeDigitizer('%s:Lnk%dCh%d'%(VME_crate,link,ch_1))
|
||||
|
||||
|
||||
|
||||
class DIAClient:
|
||||
def __init__(self, Id, instrument=None, api_address = None, jf_name=None):
|
||||
self.Id = Id
|
||||
self._api_address = api_address
|
||||
self.client = DetectorIntegrationClient(api_address)
|
||||
print("\nDetector Integration API on %s" % api_address)
|
||||
# No pgroup by default
|
||||
self.pgroup = 0
|
||||
self.n_frames = 100
|
||||
self.jf_name = jf_name
|
||||
self.pede_file = ""
|
||||
self.gain_file = ""
|
||||
self.instrument = instrument
|
||||
if instrument is None:
|
||||
print("ERROR: please configure the instrument parameter in DIAClient")
|
||||
self.gain_file = "/sf/%s/config/jungfrau/gainMaps" % self.instrument
|
||||
self.update_config()
|
||||
self.active_clients = list(self.get_active_clients()['clients_enabled'].keys())
|
||||
|
||||
def update_config(self, ):
|
||||
self.writer_config = {
|
||||
"output_file": "/sf/%s/data/p%d/raw/test_data.h5" % (self.instrument, self.pgroup),
|
||||
"user_id": self.pgroup,
|
||||
"n_frames": self.n_frames,
|
||||
"general/user": str(self.pgroup),
|
||||
"general/process": __name__,
|
||||
"general/created": str(datetime.now()),
|
||||
"general/instrument": self.instrument,
|
||||
# "general/correction": "test"
|
||||
}
|
||||
|
||||
self.is_HG0 = True
|
||||
|
||||
self.backend_config = {
|
||||
"n_frames": self.n_frames,
|
||||
"bit_depth": 16,
|
||||
"gain_corrections_filename": self.gain_file, # "/sf/alvra/config/jungfrau/jungfrau_4p5_gaincorrections_v0.h5",
|
||||
#"gain_corrections_dataset": "gains",
|
||||
#"pede_corrections_filename": "/sf/alvra/data/res/p%d/pedestal_20171210_1628_res.h5" % self.pgroup,
|
||||
#"pede_corrections_dataset": "gains",
|
||||
#"pede_mask_dataset": "pixel_mask",
|
||||
#"activate_corrections_preview": True,
|
||||
# FIXME: HARDCODED!!!
|
||||
"is_HG0": self.is_HG0
|
||||
}
|
||||
|
||||
if self.pede_file != "":
|
||||
self.backend_config["gain_corrections_filename"] = self.gain_file # "/sf/alvra/config/jungfrau/jungfrau_4p5_gaincorrections_v0.h5",
|
||||
self.backend_config["gain_corrections_dataset"] = "gains"
|
||||
self.backend_config["pede_corrections_filename"] = self.pede_file # "/sf/alvra/data/res/p%d/pedestal_20171210_1628_res.h5" % self.pgroup,
|
||||
self.backend_config["pede_corrections_dataset"] = "gains"
|
||||
self.backend_config["pede_mask_dataset"] = "pixel_mask"
|
||||
self.backend_config["activate_corrections_preview"] = True
|
||||
else:
|
||||
self.backend_config["pede_corrections_dataset"] = "gains"
|
||||
self.backend_config["pede_mask_dataset"] = "pixel_mask"
|
||||
self.backend_config["gain_corrections_filename"] = ""
|
||||
self.backend_config["pede_corrections_filename"] = ""
|
||||
self.backend_config["activate_corrections_preview"] = False
|
||||
|
||||
# remove below since it sets the JF to high-gain mode explicitly
|
||||
# if self.is_HG0:
|
||||
# print(self.client.set_detector_value("setbit", "0x5d 0"))
|
||||
# else:
|
||||
# print(self.client.set_detector_value("clearbit", "0x5d 0"))
|
||||
|
||||
|
||||
self.detector_config = {
|
||||
"timing": "trigger",
|
||||
|
||||
|
||||
# "setbit" = "0x5d 0"
|
||||
|
||||
# FIXME: HARDCODED
|
||||
"exptime": 0.000005,
|
||||
"cycles": self.n_frames,
|
||||
#"delay" : 0.001992,
|
||||
"frames" : 1,
|
||||
"dr": 16,
|
||||
}
|
||||
|
||||
# Not needed anymore?
|
||||
#default_channels_list = parseChannelListFile(
|
||||
# '/sf/alvra/config/com/channel_lists/default_channel_list')
|
||||
|
||||
self.bsread_config = {
|
||||
'output_file': '/sf/%s/data/p%d/raw/test_bsread.h5' % (self.instrument, self.pgroup),
|
||||
'user_id': self.pgroup,
|
||||
"general/user": str(self.pgroup),
|
||||
"general/process": __name__,
|
||||
"general/created": str(datetime.now()),
|
||||
"general/instrument": self.instrument,
|
||||
#'Npulses':100,
|
||||
#'channels': default_channels_list
|
||||
}
|
||||
# self.default_channels_list = jungfrau_utils.load_default_channel_list()
|
||||
|
||||
def reset(self):
|
||||
self.client.reset()
|
||||
#pass
|
||||
|
||||
def get_status(self):
|
||||
return self.client.get_status()
|
||||
|
||||
def get_config(self):
|
||||
config = self.client.get_config()
|
||||
return config
|
||||
|
||||
def get_active_clients(self):
|
||||
return self.client.get_clients_enabled()
|
||||
|
||||
def set_pgroup(self, pgroup):
|
||||
self.pgroup = pgroup
|
||||
self.update_config()
|
||||
|
||||
def set_bs_channels(self, ):
|
||||
print("Please update /sf/%s/config/com/channel_lists/default_channel_list and restart all services on the DAQ server" % self.instrument)
|
||||
|
||||
def set_config(self):
|
||||
self.reset()
|
||||
self.client.set_config({"writer": self.writer_config, "backend": self.backend_config, "detector": self.detector_config, "bsread": self.bsread_config})
|
||||
|
||||
def check_still_running(self, time_interval=1):
|
||||
cfg = self.get_config()
|
||||
running = True
|
||||
while running:
|
||||
if not self.get_status()['status'][-7:] == 'RUNNING':
|
||||
running = False
|
||||
break
|
||||
# elif not self.get_status()['status'][-20:]=='BSREAD_STILL_RUNNING':
|
||||
# running = False
|
||||
# break
|
||||
else:
|
||||
sleep(time_interval)
|
||||
|
||||
def take_pedestal(self, n_frames, analyze=True, n_bad_modules=0, update_config=True, period=0.04):
|
||||
from jungfrau_utils.scripts.jungfrau_run_pedestals import run as jungfrau_utils_run
|
||||
directory = '/sf/%s/data/p%d/raw/JF_pedestal/' % (self.instrument, self.pgroup)
|
||||
if not os.path.exists(directory):
|
||||
print("Directory %s not existing, creating it" % directory)
|
||||
os.makedirs(directory)
|
||||
|
||||
res_dir = directory.replace("/raw/", "/res/")
|
||||
if not os.path.exists(res_dir):
|
||||
print("Directory %s not existing, creating it" % res_dir)
|
||||
os.makedirs(res_dir)
|
||||
filename = "pedestal_%s.h5" % datetime.now().strftime("%Y%m%d_%H%M")
|
||||
# period = 0.02 # for 25 Hz this is 0.04, for 10 Hz this 0.1
|
||||
jungfrau_utils_run(self._api_address, filename, directory, self.pgroup, period, self.detector_config["exptime"],
|
||||
n_frames, 1, analyze, n_bad_modules, self.instrument, self.jf_name)
|
||||
|
||||
if update_config:
|
||||
self.pede_file = (directory + filename).replace("raw/", "res/").replace(".h5", "_res.h5")
|
||||
print("Pedestal file updated to %s" % self.pede_file)
|
||||
return self.pede_file
|
||||
|
||||
def start(self):
|
||||
self.client.start()
|
||||
print("start acquisition")
|
||||
pass
|
||||
|
||||
def stop(self):
|
||||
self.client.stop()
|
||||
print("stop acquisition")
|
||||
pass
|
||||
|
||||
def config_and_start_test(self):
|
||||
self.reset()
|
||||
self.set_config()
|
||||
self.start()
|
||||
pass
|
||||
|
||||
def wait_for_status(self,*args,**kwargs):
|
||||
return self.client.wait_for_status(*args,**kwargs)
|
||||
|
||||
def acquire(self, file_name=None, Npulses=100, JF_factor=1, bsread_padding=0, reset_before=False):
|
||||
"""
|
||||
JF_factor?
|
||||
bsread_padding?
|
||||
"""
|
||||
file_rootdir = '/sf/%s/data/p%d/raw/' % (self.instrument, self.pgroup)
|
||||
|
||||
if file_name is None:
|
||||
# FIXME /dev/null crashes the data taking (h5py can't close /dev/null and crashes)
|
||||
print("Not saving any data, as file_name is not set")
|
||||
file_name_JF = file_rootdir + "DelMe" + '_JF4p5M.h5'
|
||||
file_name_bsread = file_rootdir + "DelMe" + '.h5'
|
||||
else:
|
||||
# FIXME hardcoded
|
||||
file_name_JF = file_rootdir + file_name + '_JF4p5M.h5'
|
||||
file_name_bsread = file_rootdir + file_name + '.h5'
|
||||
|
||||
if self.pgroup == 0:
|
||||
raise ValueError("Please use set_pgroup() to set a pgroup value.")
|
||||
|
||||
def acquire():
|
||||
self.n_frames = Npulses * JF_factor
|
||||
self.update_config()
|
||||
#self.detector_config.update({
|
||||
# 'cycles': n_frames})
|
||||
self.writer_config.update({
|
||||
'output_file': file_name_JF,
|
||||
# 'n_messages': n_frames
|
||||
})
|
||||
#self.backend_config.update({
|
||||
# 'n_frames': n_frames})
|
||||
self.bsread_config.update({
|
||||
'output_file':file_name_bsread,
|
||||
# 'Npulses': Npulses + bsread_padding
|
||||
})
|
||||
|
||||
# self.reset()
|
||||
if reset_before:
|
||||
print('Starting reset in acquire')
|
||||
self.reset()
|
||||
print('Just resetted in acquire')
|
||||
self.set_config()
|
||||
#print(self.get_config())
|
||||
self.client.start()
|
||||
done = False
|
||||
|
||||
self.client.wait_for_status("IntegrationStatus.FINISHED")
|
||||
|
||||
while not done:
|
||||
stat = self.get_status()
|
||||
if stat['status'] =='IntegrationStatus.FINISHED':
|
||||
done = True
|
||||
if stat['status'] == 'IntegrationStatus.BSREAD_STILL_RUNNING':
|
||||
done = True
|
||||
if stat['status'] == 'IntegrationStatus.INITIALIZED':
|
||||
done = True
|
||||
if stat['status'] == 'IntegrationStatus.DETECTOR_STOPPED':
|
||||
done = True
|
||||
sleep(.1)
|
||||
outputfilenames = [f'{file_name_JF}.{tcli.upper()}.h5' for tcli in self.active_clients]
|
||||
|
||||
return Acquisition(acquire=acquire, acquisition_kwargs={'file_names': outputfilenames, 'Npulses': Npulses},hold=False)
|
||||
|
||||
# return Acquisition(acquire=acquire, acquisition_kwargs={'file_names': [file_name_bsread, file_name_JF], 'Npulses': Npulses},hold=False)
|
||||
|
||||
def wait_done(self):
|
||||
# self.check_running()
|
||||
self.check_still_running()
|
||||
@@ -0,0 +1,7 @@
|
||||
from data_api import get_data
|
||||
|
||||
class DataApi:
|
||||
def __init__(self):
|
||||
pass
|
||||
def get_data(self):
|
||||
pass
|
||||
@@ -0,0 +1,33 @@
|
||||
|
||||
from ..aliases import Alias,append_object_to_object
|
||||
from .adjustable import PvRecord,PvEnum
|
||||
|
||||
class CameraBasler:
|
||||
def __init__(self,pvname,name=None):
|
||||
self.pvname = pvname
|
||||
self.name = name
|
||||
self.alias = Alias(name)
|
||||
append_object_to_object(self,PvEnum,self.pvname+':INIT',name='initialize')
|
||||
append_object_to_object(self,PvEnum,self.pvname+':CAMERA',name='running')
|
||||
append_object_to_object(self,PvRecord,self.pvname+':BOARD',name='board_no')
|
||||
append_object_to_object(self,PvRecord,self.pvname+':SERIALNR',name='serial_no')
|
||||
append_object_to_object(self,PvRecord,self.pvname+':EXPOSURE',name='_exposure_time')
|
||||
append_object_to_object(self,PvEnum,self.pvname+':ACQMODE',name='_acq_mode')
|
||||
append_object_to_object(self,PvEnum,self.pvname+':RECMODE',name='_req_mode')
|
||||
append_object_to_object(self,PvEnum,self.pvname+':STOREMODE',name='_store_mode')
|
||||
append_object_to_object(self,PvRecord,self.pvname+':BINY',name='_binx')
|
||||
append_object_to_object(self,PvRecord,self.pvname+':BINY',name='_biny')
|
||||
append_object_to_object(self,PvRecord,self.pvname+':REGIONX_START',name='_roixmin')
|
||||
append_object_to_object(self,PvRecord,self.pvname+':REGIONX_END',name='_roixmax')
|
||||
append_object_to_object(self,PvRecord,self.pvname+':REGIONY_START',name='_roiymin')
|
||||
append_object_to_object(self,PvRecord,self.pvname+':REGIONY_END',name='_roiymax')
|
||||
append_object_to_object(self,PvEnum,self.pvname+':SET_PARAM',name='_set_parameters')
|
||||
append_object_to_object(self,PvEnum,self.pvname+':TRIGGER',name='trigger_on')
|
||||
append_object_to_object(self,PvEnum,self.pvname+':TRIGGERSOURCE',name='trigger_source')
|
||||
#append_object_to_object(self,PvEnum,self.pvname+':TRIGGEREDGE',name='trigger_edge')
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Executable
+83
@@ -0,0 +1,83 @@
|
||||
from ..devices_general.utilities import Changer
|
||||
from epics import PV
|
||||
|
||||
|
||||
_status_messages = {
|
||||
-13 : 'invalid value (cannot convert to float). Move not attempted.',
|
||||
-12 : 'target value outside soft limits. Move not attempted.',
|
||||
-11 : 'drive PV is not connected: Move not attempted.',
|
||||
-8 : 'move started, but timed-out.',
|
||||
-7 : 'move started, timed-out, but appears done.',
|
||||
-5 : 'move started, unexpected return value from PV.put()',
|
||||
-4 : 'move-with-wait finished, soft limit violation seen',
|
||||
-3 : 'move-with-wait finished, hard limit violation seen',
|
||||
0 : 'move-with-wait finish OK.',
|
||||
0 : 'move-without-wait executed, not comfirmed',
|
||||
1 : 'move-without-wait executed, move confirmed' ,
|
||||
3 : 'move-without-wait finished, hard limit violation seen',
|
||||
4 : 'move-without-wait finished, soft limit violation seen',
|
||||
}
|
||||
|
||||
|
||||
class DummyMot:
|
||||
def __init__(self):
|
||||
self._mot
|
||||
self.name = "Dummy Motor"
|
||||
self.Id = self.Id
|
||||
|
||||
def get_current_value(self):
|
||||
""" Adjustable convention"""
|
||||
motor_pos = self._stage.get_current_value()
|
||||
motor_pos -= self.delay_stage_offset
|
||||
delay = motor_pos*2.*3.33333333*1e-12
|
||||
return delay
|
||||
|
||||
def set_current_value(self, value):
|
||||
motor_pos = self.delay_to_motor(value) + self.delay_stage_offset
|
||||
self._stage.set_current_value(motor_pos)
|
||||
return (value, motor_pos)
|
||||
|
||||
def changeTo(self, value, hold=False, check=True):
|
||||
value = self.delay_to_motor(value) + self.delay_stage_offset
|
||||
delay = (value - self.delay_stage_offset)*2.*3.33333333*1e-12
|
||||
return self._stage.changeTo(value, hold, check)
|
||||
|
||||
|
||||
def gui(self, guiType='xdm'):
|
||||
return self._stage.gui()
|
||||
|
||||
|
||||
# spec-inspired convenience methods
|
||||
def mv(self,value):
|
||||
self._stage._currentChange = self.changeTo(value)
|
||||
|
||||
def wm(self,*args,**kwargs):
|
||||
return self.get_current_value(*args,**kwargs)
|
||||
|
||||
def mvr(self,value,*args,**kwargs):
|
||||
motor_pos = self.delay_to_motor(value)
|
||||
self._stage.mvr(motor_pos)
|
||||
|
||||
def wait(self):
|
||||
self._stage._currentChange.wait()
|
||||
|
||||
def stop(self):
|
||||
""" Adjustable convention"""
|
||||
try:
|
||||
self._stage._currentChange.stop()
|
||||
except:
|
||||
self._stage.stop()
|
||||
pass
|
||||
|
||||
|
||||
|
||||
# return string with motor value as variable representation
|
||||
def __str__(self):
|
||||
return "Motor is at %s"%self.wm()
|
||||
|
||||
def __repr__(self):
|
||||
return self.__str__()
|
||||
|
||||
def __call__(self,value):
|
||||
self._currentChange = self.changeTo(value)
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
from .devices_general.adjustable import PvEnum
|
||||
|
||||
|
||||
|
||||
class PowerSocket:
|
||||
def __init__(self, pvname, name=None):
|
||||
self.alias = Alias(name)
|
||||
self.name = name
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
from epics import PV
|
||||
import os
|
||||
import numpy as np
|
||||
import time
|
||||
from .utilities import Changer
|
||||
from ..aliases import Alias
|
||||
from time import sleep
|
||||
|
||||
|
||||
class PvRecord:
|
||||
def __init__(
|
||||
self,
|
||||
pvsetname,
|
||||
pvreadbackname=None,
|
||||
accuracy=None,
|
||||
sleeptime=0,
|
||||
name=None,
|
||||
elog=None,
|
||||
):
|
||||
|
||||
# alias_fields={"setpv": pvsetname, "readback": pvreadbackname},
|
||||
# ):
|
||||
self.Id = pvsetname
|
||||
self.name = name
|
||||
self.alias = Alias(name)
|
||||
self.sleeptime = sleeptime
|
||||
# for an, af in alias_fields.items():
|
||||
# self.alias.append(
|
||||
# Alias(an, channel=".".join([pvname, af]), channeltype="CA")
|
||||
# )
|
||||
|
||||
self._pv = PV(self.Id)
|
||||
self._currentChange = None
|
||||
self.accuracy = accuracy
|
||||
|
||||
if pvreadbackname is None:
|
||||
self._pvreadback = PV(self.Id)
|
||||
else:
|
||||
self._pvreadback = PV(pvreadbackname)
|
||||
|
||||
def get_current_value(self, readback=True):
|
||||
if readback:
|
||||
currval = self._pvreadback.get()
|
||||
if not readback:
|
||||
currval = self._pv.get()
|
||||
return currval
|
||||
|
||||
def get_moveDone(self):
|
||||
""" Adjustable convention"""
|
||||
""" 0: moving 1: move done"""
|
||||
movedone = 1
|
||||
if self.accuracy is not None:
|
||||
if (
|
||||
np.abs(
|
||||
self.get_current_value(readback=False)
|
||||
- self.get_current_value(readback=True)
|
||||
)
|
||||
> self.accuracy
|
||||
):
|
||||
movedone = 0
|
||||
else:
|
||||
sleep(self.sleeptime)
|
||||
return movedone
|
||||
|
||||
def move(self, value):
|
||||
self._pv.put(value)
|
||||
time.sleep(0.1)
|
||||
while self.get_moveDone() == 0:
|
||||
time.sleep(0.1)
|
||||
|
||||
def set_target_value(self, value, hold=False):
|
||||
""" Adjustable convention"""
|
||||
|
||||
changer = lambda value: self.move(value)
|
||||
return Changer(
|
||||
target=value, parent=self, changer=changer, hold=hold, stopper=None
|
||||
)
|
||||
|
||||
# spec-inspired convenience methods
|
||||
def mv(self, value):
|
||||
self._currentChange = self.set_target_value(value)
|
||||
|
||||
def wm(self, *args, **kwargs):
|
||||
return self.get_current_value(*args, **kwargs)
|
||||
|
||||
def mvr(self, value, *args, **kwargs):
|
||||
|
||||
if self.get_moveDone == 1:
|
||||
startvalue = self.get_current_value(readback=True, *args, **kwargs)
|
||||
else:
|
||||
startvalue = self.get_current_value(readback=False, *args, **kwargs)
|
||||
self._currentChange = self.set_target_value(value + startvalue, *args, **kwargs)
|
||||
|
||||
def wait(self):
|
||||
self._currentChange.wait()
|
||||
|
||||
def __repr__(self):
|
||||
return "%s is at: %s" % (self.Id, self.get_current_value())
|
||||
@@ -0,0 +1,318 @@
|
||||
import subprocess
|
||||
from threading import Thread
|
||||
from epics import PV, ca
|
||||
import time
|
||||
from ..eco_epics import device
|
||||
from ..eco_epics.device import Device
|
||||
|
||||
_guiTypes = ['xdm']
|
||||
|
||||
def _keywordChecker(kw_key_list_tups):
|
||||
for tkw,tkey,tlist in kw_key_list_tups:
|
||||
assert tkey in tlist, "Keyword %s should be one of %s"%(tkw,tlist)
|
||||
|
||||
class SmarActException(Exception):
|
||||
""" raised to indicate a problem with a smartact"""
|
||||
def __init__(self, msg, *args):
|
||||
Exception.__init__(self, *args)
|
||||
self.msg = msg
|
||||
def __str__(self):
|
||||
return str(self.msg)
|
||||
|
||||
class SmarAct(Device):
|
||||
_extras = {'disabled':'_able.VAL', }
|
||||
_init_list = ('VAL', 'DESC', 'RTYP')
|
||||
_nonpvs = ('_prefix', '_pvs', '_delim', '_init', '_init_list', '_alias', '_extras')
|
||||
def __init__(self, name=None, timeout=3.0, record=None):
|
||||
if name is None:
|
||||
raise SmarActException("must supply SmarAct name")
|
||||
|
||||
if name.endswith('.VAL'):
|
||||
name = name[:-4]
|
||||
if name.endswith('.'):
|
||||
name = name[:-1]
|
||||
|
||||
self._prefix = name
|
||||
self._record = record
|
||||
self._callbacks = {}
|
||||
|
||||
device.Device.__init__(self, name, delim='.',
|
||||
attrs=self._init_list,
|
||||
timeout=timeout)
|
||||
|
||||
|
||||
# for key, val in self._extras.items():
|
||||
# pvname = "%s%s" % (name, val)
|
||||
# self.add_pv(pvname, attr=key)
|
||||
|
||||
# self.put('disabled', 0)
|
||||
|
||||
class SmarActRecord:
|
||||
def __init__(self,Id, name=None, elog=None):
|
||||
self.Id = Id
|
||||
self._drive = SmarAct(Id+':DRIVE')
|
||||
self._rbv = SmarAct(Id+':MOTRBV')
|
||||
self._hlm = SmarAct(Id+':HLM')
|
||||
self._llm = SmarAct(Id+':LLM')
|
||||
self._status = SmarAct(Id+':STATUS')
|
||||
self._set_pos = SmarAct(Id+':SET_POS')
|
||||
self._stop = SmarAct(Id+':STOP')
|
||||
self._hold = SmarAct(Id+':HOLD')
|
||||
self._twv = SmarAct(Id+':TWV')
|
||||
self._elog = elog
|
||||
self.name = name
|
||||
self.units = self._drive.get('EGU')
|
||||
|
||||
# Conventional methods and properties for all Adjustable objects
|
||||
def changeTo(self, value, hold=False, check=True):
|
||||
""" Adjustable convention"""
|
||||
|
||||
mover = lambda value: self.move(\
|
||||
value, ignore_limits=(not check),
|
||||
wait=True)
|
||||
return Changer(
|
||||
target=value,
|
||||
parent=self,
|
||||
mover=mover,
|
||||
hold=hold,
|
||||
stopper=self._stop.put('PROC', 1))
|
||||
|
||||
def stop(self):
|
||||
""" Adjustable convention"""
|
||||
try:
|
||||
self._currentChange.stop()
|
||||
except:
|
||||
self._stop.put('VAL',1)
|
||||
pass
|
||||
|
||||
def within_limits(self, val):
|
||||
""" returns whether a value for a motor is within drive limits"""
|
||||
return (val <= self._hlm.get('VAL') and val >= self._llm.get('VAL'))
|
||||
|
||||
def move(self, val, relative=False, wait=False, timeout=300.0, ignore_limits=False, confirm_move=False):
|
||||
""" moves smaract drive to position
|
||||
|
||||
arguments:
|
||||
==========
|
||||
val value to move to (float) [Must be provided]
|
||||
relative move relative to current position (T/F) [F]
|
||||
wait whether to wait for move to complete (T/F) [F]
|
||||
ignore_limits try move without regard to limits (T/F) [F]
|
||||
confirm_move try to confirm that move has begun (T/F) [F]
|
||||
timeout max time for move to complete (in seconds) [300]
|
||||
|
||||
return values:
|
||||
-13 : invalid value (cannot convert to float). Move not attempted.
|
||||
-12 : target value outside soft limits. Move not attempted.
|
||||
-11 : drive PV is not connected: Move not attempted.
|
||||
-8 : move started, but timed-out.
|
||||
-7 : move started, timed-out, but appears done.
|
||||
-5 : move started, unexpected return value from PV.put()
|
||||
-4 : move-with-wait finished, soft limit violation seen
|
||||
-3 : move-with-wait finished, hard limit violation seen
|
||||
0 : move-with-wait finish OK.
|
||||
0 : move-without-wait executed, not cpmfirmed
|
||||
1 : move-without-wait executed, move confirmed
|
||||
3 : move-without-wait finished, hard limit violation seen
|
||||
4 : move-without-wait finished, soft limit violation seen
|
||||
|
||||
"""
|
||||
NONFLOAT, OUTSIDE_LIMITS, UNCONNECTED = -13, -12, -11
|
||||
TIMEOUT = -8
|
||||
UNKNOWN_ERROR = -5
|
||||
DONE_OK = 0
|
||||
MOVE_BEGUN, MOVE_BEGUN_CONFIRMED = 0, 1
|
||||
try:
|
||||
val = float(val)
|
||||
except TypeError:
|
||||
return NONFLOAT
|
||||
|
||||
if relative:
|
||||
val += self._drive.get('VAL')
|
||||
|
||||
# Check for limit violations
|
||||
if not ignore_limits:
|
||||
if not self.within_limits(val):
|
||||
return OUTSIDE_LIMITS
|
||||
|
||||
stat = self._drive.put('VAL', val, wait=wait, timeout=timeout)
|
||||
if stat is None:
|
||||
return UNCONNECTED
|
||||
|
||||
if wait and stat == -1:
|
||||
return TIMEOUT
|
||||
|
||||
if 1 == stat:
|
||||
s0 = self._status.get('VAL')
|
||||
s1 = s0
|
||||
t0 = time.time()
|
||||
t1 = t0 + min(10.0, timeout) # should be moving by now
|
||||
thold = self._hold.get('VAL') * 0.001 + t0
|
||||
tout = t0 + timeout
|
||||
if wait or confirm_move:
|
||||
while time.time() <= thold and s1 == 3:
|
||||
ca.poll(evt=1.e-2)
|
||||
s1 = self._status.get('VAL')
|
||||
while time.time() <= t1 and s1 == 0:
|
||||
ca.poll(evt=1.e-2)
|
||||
s1 = self._status.get('VAL')
|
||||
if s1 == 4:
|
||||
if wait:
|
||||
while time.time() <= tout and s1 == 4:
|
||||
ca.poll(evt=1.e-2)
|
||||
s1 = self._status.get('VAL')
|
||||
if s1 == 3 or s1 == 4:
|
||||
if time.time() > tout:
|
||||
return TIMEOUT
|
||||
else:
|
||||
twv = abs(self._twv.get('VAL'))
|
||||
while s1==3 and time.time()<=tout and abs(self._rbv.get('VAL')-val)>=twv:
|
||||
ca.poll(evt=1.e-2)
|
||||
return DONE_OK
|
||||
else:
|
||||
return MOVE_BEGUN_CONFIRMED
|
||||
elif time.time() > tout:
|
||||
return TIMEOUT
|
||||
else:
|
||||
return UNKNOWN_ERROR
|
||||
else:
|
||||
return MOVE_BEGUN
|
||||
return UNKNOWN_ERROR
|
||||
|
||||
def get_current_value(self,readback=True):
|
||||
if readback:
|
||||
return self._rbv.get('VAL')
|
||||
else :
|
||||
return self._drive.get('VAL')
|
||||
|
||||
def set_current_value(self,value):
|
||||
return self._set_pos.put('VAL',value)
|
||||
|
||||
def get_precision(self):
|
||||
""" Adjustable convention"""
|
||||
pass
|
||||
|
||||
def set_precision(self):
|
||||
""" Adjustable convention"""
|
||||
pass
|
||||
|
||||
precision = property(get_precision,set_precision)
|
||||
|
||||
def set_speed(self):
|
||||
""" Adjustable convention"""
|
||||
pass
|
||||
def get_speed(self):
|
||||
""" Adjustable convention"""
|
||||
pass
|
||||
def set_speedMax(self):
|
||||
""" Adjustable convention"""
|
||||
pass
|
||||
|
||||
def get_moveDone(self):
|
||||
pass
|
||||
|
||||
def set_limits(self, values, posType='user', relative_to_present=False):
|
||||
""" Adjustable convention"""
|
||||
if relative_to_present:
|
||||
v = self.get_current_value()
|
||||
values = [v-values[0],v-values[1]]
|
||||
self._llm.put('VAL',values[0])
|
||||
self._hlm.put('VAL',values[1])
|
||||
|
||||
def get_limits(self, posType='user'):
|
||||
""" Adjustable convention"""
|
||||
return self._llm.get('VAL'), self._hlm.get('VAL')
|
||||
|
||||
def gui(self, guiType='xdm'):
|
||||
""" Adjustable convention"""
|
||||
cmd = ['caqtdm','-macro']
|
||||
|
||||
for i in range(len(self.Id)-1):
|
||||
if self.Id[-i-1].isnumeric() is False:
|
||||
M = self.Id[-i:]
|
||||
P = self.Id[:-i]
|
||||
print(P, M)
|
||||
break
|
||||
|
||||
cmd.append('\"P=%s,M=%s\"'%(P, M))
|
||||
# #cmd.append('/sf/common/config/qt/motorx_more.ui')
|
||||
cmd.append('ESB_MX_SMARACT_mot_exp.ui')
|
||||
# #os.system(' '.join(cmd))
|
||||
return subprocess.Popen(' '.join(cmd),shell=True)
|
||||
|
||||
|
||||
|
||||
def mv(self,value):
|
||||
self._currentChange = self.changeTo(value)
|
||||
def wm(self,*args,**kwargs):
|
||||
return self.get_current_value(*args,**kwargs)
|
||||
def mvr(self,value,*args,**kwargs):
|
||||
startvalue = self.get_current_value(readback=True,*args,**kwargs)
|
||||
self._currentChange = self.changeTo(value+startvalue,*args,**kwargs)
|
||||
def wait(self):
|
||||
self._currentChange.wait()
|
||||
|
||||
|
||||
# return string with motor value as variable representation
|
||||
def __str__(self):
|
||||
return "SmarAct is at %s"%(self.wm())
|
||||
#return "SmarAct is at %s %s"%(self.wm(),self.units)
|
||||
|
||||
def __repr__(self):
|
||||
return self.__str__()
|
||||
|
||||
def __call__(self,value):
|
||||
self._currentChange = self.changeTo(value)
|
||||
|
||||
|
||||
class SmarActDevice(SmarActRecord):
|
||||
def __init__(self,Id,alias_namespace=None):
|
||||
SmarActRecord.__init__(self, Id)
|
||||
# self.Id = Id
|
||||
#
|
||||
# self.x = SmarActRecord(Id+':DRIVE')
|
||||
|
||||
class SmarActStage:
|
||||
def __init__(self, axes, name):
|
||||
self._keys = axes.keys()
|
||||
for axis in self._keys:
|
||||
self.__dict__[axis] = axes[axis]
|
||||
self.name = name
|
||||
|
||||
def __str__(self):
|
||||
return "SmarAct positions\n%s" % "\n".join(["%s: %s"%(key,self.__dict__[key].wm()) for key in self._keys])
|
||||
|
||||
def __repr__(self):
|
||||
return str({key:self.__dict__[key].wm() for key in self._keys})
|
||||
|
||||
class Changer:
|
||||
def __init__(self, target=None, parent=None, mover=None, hold=True, stopper=None):
|
||||
self.target = target
|
||||
self._mover = mover
|
||||
self._stopper = stopper
|
||||
self._thread = Thread(target=self._mover,args=(target,))
|
||||
if not hold:
|
||||
self._thread.start()
|
||||
|
||||
def wait(self):
|
||||
self._thread.join()
|
||||
|
||||
def start(self):
|
||||
self._thread.start()
|
||||
|
||||
def status(self):
|
||||
if self._thread.ident is None:
|
||||
return 'waiting'
|
||||
else:
|
||||
if self._isAlive:
|
||||
return 'changing'
|
||||
else:
|
||||
return 'done'
|
||||
def stop(self):
|
||||
self._stopper()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Executable
+85
@@ -0,0 +1,85 @@
|
||||
from ..devices_general.utilities import Changer
|
||||
from epics import PV
|
||||
|
||||
|
||||
_status_messages = {
|
||||
-13: "invalid value (cannot convert to float). Move not attempted.",
|
||||
-12: "target value outside soft limits. Move not attempted.",
|
||||
-11: "drive PV is not connected: Move not attempted.",
|
||||
-8: "move started, but timed-out.",
|
||||
-7: "move started, timed-out, but appears done.",
|
||||
-5: "move started, unexpected return value from PV.put()",
|
||||
-4: "move-with-wait finished, soft limit violation seen",
|
||||
-3: "move-with-wait finished, hard limit violation seen",
|
||||
0: "move-with-wait finish OK.",
|
||||
0: "move-without-wait executed, not comfirmed",
|
||||
1: "move-without-wait executed, move confirmed",
|
||||
3: "move-without-wait finished, hard limit violation seen",
|
||||
4: "move-without-wait finished, soft limit violation seen",
|
||||
}
|
||||
|
||||
|
||||
class User_to_motor:
|
||||
def __init__(self, stage, conversion_conv, offset):
|
||||
self.conv = conversion_conv
|
||||
self._stage = stage
|
||||
self.offset = offset
|
||||
self.name = self._stage.name
|
||||
self.Id = self._stage.Id
|
||||
self._elog = self._stage._elog
|
||||
|
||||
def user_to_motor(self, user):
|
||||
motor_pos = user / self.conv
|
||||
return motor_pos
|
||||
|
||||
def get_current_value(self):
|
||||
""" Adjustable convention"""
|
||||
motor_pos = self._stage.get_current_value()
|
||||
motor_pos -= self.offset
|
||||
user = motor_pos * self.conv
|
||||
return user
|
||||
|
||||
def set_current_value(self, value):
|
||||
motor_pos = self.user_to_motor(value) + self.offset
|
||||
self._stage.set_current_value(motor_pos)
|
||||
return (value, motor_pos)
|
||||
|
||||
def set_target_value(self, value, hold=False, check=True):
|
||||
value = self.user_to_motor(value) + self.offset
|
||||
user = (value - self.offset) * self.conv
|
||||
return self._stage.set_target_value(value, hold, check)
|
||||
|
||||
def gui(self, guiType="xdm"):
|
||||
return self._stage.gui()
|
||||
|
||||
# spec-inspired convenience methods
|
||||
def mv(self, value):
|
||||
self._stage._currentChange = self.set_target_value(value)
|
||||
|
||||
def wm(self, *args, **kwargs):
|
||||
return self.get_current_value(*args, **kwargs)
|
||||
|
||||
def mvr(self, value, *args, **kwargs):
|
||||
motor_pos = self.user_to_motor(value)
|
||||
self._stage.mvr(motor_pos)
|
||||
|
||||
def wait(self):
|
||||
self._stage._currentChange.wait()
|
||||
|
||||
def stop(self):
|
||||
""" Adjustable convention"""
|
||||
try:
|
||||
self._stage._currentChange.stop()
|
||||
except:
|
||||
self._stage.stop()
|
||||
pass
|
||||
|
||||
# return string with motor value as variable representation
|
||||
def __str__(self):
|
||||
return "Motor is at %s" % self.wm()
|
||||
|
||||
def __repr__(self):
|
||||
return self.__str__()
|
||||
|
||||
def __call__(self, value):
|
||||
self._currentChange = self.set_target_value(value)
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
from ..devices_general.smaract import SmarActRecord
|
||||
from epics import PV
|
||||
|
||||
class SmaractTower:
|
||||
def __init__(self,Id):
|
||||
self.Id = Id
|
||||
|
||||
### Mirrors used in the expeirment ###
|
||||
try:
|
||||
self.x = SmarActRecord(Id+'-ESB1')
|
||||
except:
|
||||
print('No Smaract x linear stage')
|
||||
pass
|
||||
|
||||
try:
|
||||
self.gonio = SmarActRecord(Id+'-ESB2')
|
||||
except:
|
||||
print('No Smaract Gonio')
|
||||
pass
|
||||
|
||||
|
||||
Executable
+19
@@ -0,0 +1,19 @@
|
||||
from ..devices_general.motors import MotorRecord
|
||||
from epics import PV
|
||||
|
||||
|
||||
class Laser_Exp:
|
||||
def __init__(self, Id):
|
||||
self.Id = Id
|
||||
|
||||
### Mirrors used in the expeirment ###
|
||||
try:
|
||||
self.phi = MotorRecord(Id + "-M517:MOT")
|
||||
except:
|
||||
print("No Standa steering phi mirror")
|
||||
pass
|
||||
try:
|
||||
self.th = MotorRecord(Id + "-M518:MOT")
|
||||
except:
|
||||
print("No Standa steering theta mirror")
|
||||
pass
|
||||
Executable
+24
@@ -0,0 +1,24 @@
|
||||
from ..devices_general.motors import MotorRecord
|
||||
from ..devices_general.smaract import SmarActRecord
|
||||
from epics import PV
|
||||
from ..devices_general.delay_stage import DelayStage
|
||||
|
||||
|
||||
class Palm:
|
||||
def __init__(self, Id):
|
||||
self.Id = Id
|
||||
|
||||
self._delayStg = MotorRecord(self.Id + "-M552:MOT")
|
||||
self.delay = DelayStage(self._delayStg)
|
||||
|
||||
def get_adjustable_positions_str(self):
|
||||
ostr = "*****Palm motor positions******\n"
|
||||
|
||||
for tkey, item in self.__dict__.items():
|
||||
if hasattr(item, "get_current_value"):
|
||||
pos = item.get_current_value()
|
||||
ostr += " " + tkey.ljust(10) + " : % 14g\n" % pos
|
||||
return ostr
|
||||
|
||||
def __repr__(self):
|
||||
return self.get_adjustable_positions_str()
|
||||
Executable
+24
@@ -0,0 +1,24 @@
|
||||
from ..devices_general.motors import MotorRecord
|
||||
from ..devices_general.smaract import SmarActRecord
|
||||
from epics import PV
|
||||
from ..devices_general.delay_stage import DelayStage
|
||||
|
||||
|
||||
class Psen:
|
||||
def __init__(self, Id):
|
||||
self.Id = Id
|
||||
|
||||
self._delayStg = MotorRecord(self.Id + "-M561:MOT")
|
||||
self.delay = DelayStage(self._delayStg)
|
||||
|
||||
def get_adjustable_positions_str(self):
|
||||
ostr = "*****PSEN motor positions******\n"
|
||||
|
||||
for tkey, item in self.__dict__.items():
|
||||
if hasattr(item, "get_current_value"):
|
||||
pos = item.get_current_value()
|
||||
ostr += " " + tkey.ljust(10) + " : % 14g\n" % pos
|
||||
return ostr
|
||||
|
||||
def __repr__(self):
|
||||
return self.get_adjustable_positions_str()
|
||||
@@ -0,0 +1,35 @@
|
||||
import numpy as np
|
||||
from matplotlib import pylab as plt
|
||||
|
||||
|
||||
def readTraceTextfile(fina, numbers=None):
|
||||
if not numbers is None:
|
||||
d = [readTraceTextfile(fina % number) for number in numbers]
|
||||
else:
|
||||
d = np.loadtxt(fina, skiprows=5, delimiter=",")
|
||||
return d
|
||||
|
||||
|
||||
def getRiseTime(t, s, lims=[0.1, 0.9]):
|
||||
lims = np.asarray(lims)
|
||||
t = np.asarray(t)
|
||||
s = np.asarray(s)
|
||||
sel = t > 0
|
||||
mxind = np.min((np.diff(s[sel]) < 0).nonzero()[0])
|
||||
mxind = sel.nonzero()[0][mxind]
|
||||
sel = t <= 0
|
||||
mnind = np.max((np.diff(s[sel]) < 0).nonzero()[0])
|
||||
mnind = sel.nonzero()[0][mnind] + 1
|
||||
crosspty = lims * (s[mxind] - s[mnind]) + s[mnind]
|
||||
crossptx = np.interp(crosspty, s[mnind : mxind + 1], t[mnind : mxind + 1])
|
||||
return float(np.round(np.diff(crossptx), decimals=13)), [crossptx, crosspty]
|
||||
|
||||
|
||||
def plotTrace(fina="./scope2_testdata_2017-02-21/C2Trace00003txt"):
|
||||
t, s = readTraceTextfile(fina).T
|
||||
rt, crossers = getRiseTime(t, s)
|
||||
ax = plt.gca()
|
||||
ax.plot(t, s, ".-", label="rise time = %3g (fwhm)" % rt)
|
||||
ax.plot(crossers[0], crossers[1], "xr")
|
||||
ax.set_xlabel("Time / s")
|
||||
ax.set_ylabel("Amplitude / V")
|
||||
@@ -0,0 +1,42 @@
|
||||
import time
|
||||
import os
|
||||
import signal
|
||||
from subprocess import Popen, PIPE, STDOUT
|
||||
|
||||
|
||||
class ScreenPanel:
|
||||
def __init__(self, name=None):
|
||||
self.name = name
|
||||
self._proc = None
|
||||
|
||||
@property
|
||||
def proc(self):
|
||||
if not self._proc:
|
||||
if (
|
||||
input(
|
||||
"No screenpanel running, would you like to start now? (y/n)\n"
|
||||
).strip()
|
||||
== "y"
|
||||
):
|
||||
self.start()
|
||||
return self._proc
|
||||
|
||||
def start(self):
|
||||
if self._proc:
|
||||
print(f"Sreenpanel {self.name} is already running")
|
||||
else:
|
||||
# self.proc = subprocess.Popen(["screen_panel","-console"],stdout=subprocess.PIPE)
|
||||
self._proc = Popen(
|
||||
["bash", "screen_panel", "-console", "-persist"],
|
||||
stdin=PIPE,
|
||||
stdout=PIPE,
|
||||
preexec_fn=os.setsid,
|
||||
)
|
||||
|
||||
def quit(self):
|
||||
os.killpg(self.proc.pid, signal.SIGTERM)
|
||||
self._proc = None
|
||||
|
||||
def set_camera(self, camera_name):
|
||||
self.proc.stdin.write(("cam " + camera_name + "\n").encode())
|
||||
self.proc.stdin.flush()
|
||||
Executable
+47
@@ -0,0 +1,47 @@
|
||||
from ..devices_general.motors import MotorRecord
|
||||
from ..devices_general.smaract import SmarActRecord
|
||||
from epics import PV
|
||||
from ..devices_general.delay_stage import DelayStage
|
||||
|
||||
|
||||
class palm:
|
||||
def __init__(self, Id):
|
||||
self.Id = Id
|
||||
|
||||
self.delay = MotorRecord(self.Id + "-M423:MOT")
|
||||
self.delayTime = DelayStage(self.delay)
|
||||
|
||||
# self.delay2 = MotorRecord(self.Id+'-M422:MOT')
|
||||
# self.delayTime2 = DelayStage(self.delay)
|
||||
|
||||
def get_adjustable_positions_str(self):
|
||||
ostr = "***** PALM motor positions ******\n"
|
||||
|
||||
for tkey, item in self.__dict__.items():
|
||||
if hasattr(item, "get_current_value"):
|
||||
pos = item.get_current_value()
|
||||
ostr += " " + tkey.ljust(10) + " : % 14g\n" % pos
|
||||
return ostr
|
||||
|
||||
def __repr__(self):
|
||||
return self.get_adjustable_positions_str()
|
||||
|
||||
|
||||
class eo:
|
||||
def __init__(self, Id):
|
||||
self.Id = Id
|
||||
|
||||
self.delay = MotorRecord(self.Id + "-M422:MOT")
|
||||
self.delayTime = DelayStage(self.delay)
|
||||
|
||||
def get_adjustable_positions_str(self):
|
||||
ostr = "***** PALM EO sampling motor positions ******\n"
|
||||
|
||||
for tkey, item in self.__dict__.items():
|
||||
if hasattr(item, "get_current_value"):
|
||||
pos = item.get_current_value()
|
||||
ostr += " " + tkey.ljust(10) + " : % 14g\n" % pos
|
||||
return ostr
|
||||
|
||||
def __repr__(self):
|
||||
return self.get_adjustable_positions_str()
|
||||
Executable
+26
@@ -0,0 +1,26 @@
|
||||
from ..devices_general.motors import MotorRecord
|
||||
from ..devices_general.smaract import SmarActRecord
|
||||
from epics import PV
|
||||
from ..devices_general.delay_stage import DelayStage
|
||||
|
||||
class psen:
|
||||
def __init__(self,Id):
|
||||
self.Id = Id
|
||||
|
||||
self.delay = MotorRecord(self.Id+'-M424:MOT')
|
||||
self.delayTime = DelayStage(self.delay)
|
||||
|
||||
|
||||
def get_adjustable_positions_str(self):
|
||||
ostr = '*****PSEN motor positions******\n'
|
||||
|
||||
for tkey,item in self.__dict__.items():
|
||||
if hasattr(item,'get_current_value'):
|
||||
pos = item.get_current_value()
|
||||
ostr += ' ' + tkey.ljust(10) + ' : % 14g\n'%pos
|
||||
return ostr
|
||||
|
||||
|
||||
def __repr__(self):
|
||||
return self.get_adjustable_positions_str()
|
||||
|
||||
Executable
+426
@@ -0,0 +1,426 @@
|
||||
from ..devices_general.motors import MotorRecord
|
||||
from epics import PV
|
||||
from ..eco_epics.utilities_epics import EnumWrapper
|
||||
from ..devices_general.utilities import Changer
|
||||
from time import sleep
|
||||
import numpy as np
|
||||
|
||||
|
||||
class Double_Crystal_Mono_AramisMacro:
|
||||
def __init__(self,Id,timeAdjustable=None,timeReferenceEnergy=None,timeReference=None):
|
||||
self.Id = Id
|
||||
self.theta = MotorRecord(Id+':RX12')
|
||||
self.x = MotorRecord(Id+':TX12')
|
||||
self.gap = MotorRecord(Id+':T2')
|
||||
self.roll1 = MotorRecord(Id+':RZ1')
|
||||
self.roll2 = MotorRecord(Id+':RZ2')
|
||||
self.pitch2 = MotorRecord(Id+':RX2')
|
||||
|
||||
self.energy_rbk = PV(Id+':ENERGY')
|
||||
self.energy_sp = PV(Id+':ENERGY_SP')
|
||||
self.moving = PV(Id+':MOVING')
|
||||
self._stop = PV(Id +':STOP.PROC')
|
||||
self.crystal_type = EnumWrapper(Id + ':CRYSTAL_SP')
|
||||
self.beam_offset = PV(Id + ':BEAM_OFFSET')
|
||||
self.timeAdjustable = timeAdjustable
|
||||
self.timeReferenceEnergy = timeReferenceEnergy
|
||||
self.timeReference = timeReference
|
||||
self.correctTime = False
|
||||
|
||||
def _calcOffsetDetour(self,E,crystal_type=None,beam_offset=None):
|
||||
if not crystal_type:
|
||||
crystal_type = self.crystal_type.get()
|
||||
if crystal_type is "Si-111":
|
||||
d = 3.1356124059796264
|
||||
else:
|
||||
raise NotImplementedError
|
||||
if not beam_offset:
|
||||
beam_offset = self.beam_offset.get()
|
||||
theta = np.arcsin(12398.419739640718/E/2/d)
|
||||
return np.tan(theta) * beam_offset
|
||||
|
||||
def setTimeReference(self,t=None,E=None):
|
||||
if not t:
|
||||
t = self.timeAdjustable.get_current_value()
|
||||
if not E:
|
||||
E = self.get_current_value()
|
||||
print(f"Setting mono time reference to {t} s and {E} eV.")
|
||||
self.timeReference = t
|
||||
self.timeReferenceEnergy = E
|
||||
|
||||
def move_and_wait(self,value,checktime=.01,precision=.5):
|
||||
if self.correctTime:
|
||||
p_ref = self._calcOffsetDetour(self.timeReferenceEnergy)
|
||||
p_target = self._calcOffsetDetour(value)
|
||||
t_delta = (p_target-p_ref)*1e-3/299792458.
|
||||
t_new = self.timeReference + t_delta
|
||||
print('correcting timing by Dt = {t_delta} s to {t_new} s')
|
||||
|
||||
|
||||
#self.energy_sp.put(value)
|
||||
#while abs(self.wait_for_valid_value()-value)>precision:
|
||||
# sleep(checktime)
|
||||
|
||||
def changeTo(self,value,hold=False):
|
||||
changer = lambda value: self.move_and_wait(value)
|
||||
return Changer(
|
||||
target=value,
|
||||
parent=self,
|
||||
changer=changer,
|
||||
hold=hold,
|
||||
stopper=self.stop)
|
||||
|
||||
def stop(self):
|
||||
self._stop.put(1)
|
||||
|
||||
def get_current_value(self):
|
||||
currentenergy = self.energy_rbk.get()
|
||||
return currentenergy
|
||||
|
||||
def wait_for_valid_value(self):
|
||||
tval = np.nan
|
||||
while not np.isfinite(tval):
|
||||
tval = self.energy_rbk.get()
|
||||
return(tval)
|
||||
|
||||
def set_current_value(self,value):
|
||||
self.energy_sp.put(value)
|
||||
|
||||
def get_moveDone(self):
|
||||
inmotion = int(self.moving.get())
|
||||
return inmotion
|
||||
|
||||
# spec-inspired convenience methods
|
||||
def mv(self,value):
|
||||
self._currentChange = self.changeTo(value)
|
||||
def wm(self,*args,**kwargs):
|
||||
return self.get_current_value(*args,**kwargs)
|
||||
def mvr(self,value,*args,**kwargs):
|
||||
|
||||
if(self.get_moveDone == 1):
|
||||
startvalue = self.get_current_value(*args,**kwargs)
|
||||
else:
|
||||
startvalue = self.get_current_value(*args,**kwargs)
|
||||
self._currentChange = self.changeTo(value+startvalue,*args,**kwargs)
|
||||
def wait(self):
|
||||
self._currentChange.wait()
|
||||
|
||||
def __str__(self):
|
||||
s = "**Double crystal monochromator**\n\n"
|
||||
motors = "theta gap x roll1 roll2 pitch2".split()
|
||||
for motor in motors:
|
||||
s+= " - %s = %.4f\n" %(motor, getattr(self,motor).wm())
|
||||
pvs = "energy_rbk".split()
|
||||
for pv in pvs:
|
||||
s+= " - %s = %.4f\n" %(pv, getattr(self,pv).value)
|
||||
return s
|
||||
|
||||
def __repr__(self):
|
||||
return self.__str__()
|
||||
|
||||
def __call__(self,value):
|
||||
self._currentChange = self.changeTo(value)
|
||||
|
||||
|
||||
class EcolEnergy:
|
||||
def __init__(self,Id, val='SARCL02-MBND100:P-SET',rb='SARCL02-MBND100:P-READ' ,dmov='SFB_BEAM_ENERGY_ECOL:SUM-ERROR-OK'):
|
||||
self.Id = Id
|
||||
self.setter = PV(val)
|
||||
self.readback = PV(rb)
|
||||
self.dmov = PV(dmov)
|
||||
self.done = False
|
||||
|
||||
def get_current_value(self):
|
||||
return self.readback.get()
|
||||
|
||||
def move_and_wait(self,value,checktime=.01,precision=2):
|
||||
curr = self.setter.get()
|
||||
while abs(curr-value)>0.1:
|
||||
curr = self.setter.get()
|
||||
self.setter.put(curr + np.sign(value-curr)*.1)
|
||||
sleep(0.3)
|
||||
|
||||
self.setter.put(value)
|
||||
while abs(self.get_current_value() - value)>precision:
|
||||
sleep(checktime)
|
||||
while not self.dmov.get():
|
||||
#print(self.dmov.get())
|
||||
sleep(checktime)
|
||||
|
||||
def changeTo(self,value,hold=False):
|
||||
changer = lambda value: self.move_and_wait(value)
|
||||
return Changer(
|
||||
target=value,
|
||||
parent=self,
|
||||
changer=changer,
|
||||
hold=hold,
|
||||
stopper=None)
|
||||
|
||||
class Double_Crystal_Mono:
|
||||
def __init__(self,Id,timeAdjustable=None,timeReferenceEnergy=None,timeReference=None):
|
||||
self.Id = Id
|
||||
self.theta = MotorRecord(Id+':RX12')
|
||||
self.x = MotorRecord(Id+':TX12')
|
||||
self.gap = MotorRecord(Id+':T2')
|
||||
self.roll1 = MotorRecord(Id+':RZ1')
|
||||
self.roll2 = MotorRecord(Id+':RZ2')
|
||||
self.pitch2 = MotorRecord(Id+':RX2')
|
||||
|
||||
self.energy_rbk = PV(Id+':ENERGY')
|
||||
self.energy_sp = PV(Id+':ENERGY_SP')
|
||||
self.moving = PV(Id+':MOVING')
|
||||
self._stop = PV(Id +':STOP.PROC')
|
||||
self.crystal_type = EnumWrapper(Id + ':CRYSTAL_SP')
|
||||
self.beam_offset = PV(Id + ':BEAM_OFFSET')
|
||||
self.timeAdjustable = timeAdjustable
|
||||
self.timeReferenceEnergy = timeReferenceEnergy
|
||||
self.timeReference = timeReference
|
||||
self.correctTime = False
|
||||
|
||||
def _calcOffsetDetour(self,E,crystal_type=None,beam_offset=None):
|
||||
if not crystal_type:
|
||||
crystal_type = str(self.crystal_type)
|
||||
if crystal_type=="Si-111":
|
||||
d = 3.1356124059796264
|
||||
else:
|
||||
raise NotImplementedError
|
||||
if not beam_offset:
|
||||
beam_offset = self.beam_offset.get()
|
||||
theta = np.arcsin(12398.419739640718/E/2/d)
|
||||
return np.tan(theta) * beam_offset
|
||||
|
||||
def setTimeReference(self,t=None,E=None):
|
||||
if not t:
|
||||
t = self.timeAdjustable.get_current_value()
|
||||
if not E:
|
||||
E = self.get_current_value()
|
||||
print(f"Setting mono time reference to {t} s and {E} eV.")
|
||||
self.timeReference = t
|
||||
self.timeReferenceEnergy = E
|
||||
|
||||
def move_and_wait(self,value,checktime=.01,precision=.5):
|
||||
if self.correctTime:
|
||||
p_ref = self._calcOffsetDetour(self.timeReferenceEnergy)
|
||||
p_target = self._calcOffsetDetour(value)
|
||||
t_delta = (p_target-p_ref)*1e-3/299792458.
|
||||
t_new = self.timeReference - t_delta
|
||||
print(f'correcting laser to xray timing delay by\nDt = {-t_delta} s to {t_new} s')
|
||||
time_mover = self.timeAdjustable.changeTo(t_new)
|
||||
self.energy_sp.put(value)
|
||||
while abs(self.wait_for_valid_value()-value)>precision:
|
||||
sleep(checktime)
|
||||
if self.correctTime:
|
||||
time_mover.wait()
|
||||
|
||||
def changeTo(self,value,hold=False):
|
||||
changer = lambda value: self.move_and_wait(value)
|
||||
return Changer(
|
||||
target=value,
|
||||
parent=self,
|
||||
changer=changer,
|
||||
hold=hold,
|
||||
stopper=self.stop)
|
||||
|
||||
def stop(self):
|
||||
self._stop.put(1)
|
||||
|
||||
def get_current_value(self):
|
||||
currentenergy = self.energy_rbk.get()
|
||||
return currentenergy
|
||||
|
||||
def wait_for_valid_value(self):
|
||||
tval = np.nan
|
||||
while not np.isfinite(tval):
|
||||
tval = self.energy_rbk.get()
|
||||
return(tval)
|
||||
|
||||
def set_current_value(self,value):
|
||||
self.energy_sp.put(value)
|
||||
|
||||
def get_moveDone(self):
|
||||
inmotion = int(self.moving.get())
|
||||
return inmotion
|
||||
|
||||
# spec-inspired convenience methods
|
||||
def mv(self,value):
|
||||
self._currentChange = self.changeTo(value)
|
||||
def wm(self,*args,**kwargs):
|
||||
return self.get_current_value(*args,**kwargs)
|
||||
def mvr(self,value,*args,**kwargs):
|
||||
|
||||
if(self.get_moveDone == 1):
|
||||
startvalue = self.get_current_value(*args,**kwargs)
|
||||
else:
|
||||
startvalue = self.get_current_value(*args,**kwargs)
|
||||
self._currentChange = self.changeTo(value+startvalue,*args,**kwargs)
|
||||
def wait(self):
|
||||
self._currentChange.wait()
|
||||
|
||||
def __str__(self):
|
||||
s = "**Double crystal monochromator**\n\n"
|
||||
motors = "theta gap x roll1 roll2 pitch2".split()
|
||||
for motor in motors:
|
||||
s+= " - %s = %.4f\n" %(motor, getattr(self,motor).wm())
|
||||
pvs = "energy_rbk".split()
|
||||
for pv in pvs:
|
||||
s+= " - %s = %.4f\n" %(pv, getattr(self,pv).value)
|
||||
return s
|
||||
|
||||
def __repr__(self):
|
||||
return self.__str__()
|
||||
|
||||
def __call__(self,value):
|
||||
self._currentChange = self.changeTo(value)
|
||||
|
||||
|
||||
class EcolEnergy:
|
||||
def __init__(self,Id, val='SARCL02-MBND100:P-SET',rb='SARCL02-MBND100:P-READ' ,dmov='SFB_BEAM_ENERGY_ECOL:SUM-ERROR-OK'):
|
||||
self.Id = Id
|
||||
self.setter = PV(val)
|
||||
self.readback = PV(rb)
|
||||
self.dmov = PV(dmov)
|
||||
self.done = False
|
||||
|
||||
def get_current_value(self):
|
||||
return self.readback.get()
|
||||
|
||||
def move_and_wait(self,value,checktime=.01,precision=2):
|
||||
curr = self.setter.get()
|
||||
while abs(curr-value)>0.1:
|
||||
curr = self.setter.get()
|
||||
self.setter.put(curr + np.sign(value-curr)*.1)
|
||||
sleep(0.3)
|
||||
|
||||
self.setter.put(value)
|
||||
while abs(self.get_current_value() - value)>precision:
|
||||
sleep(checktime)
|
||||
while not self.dmov.get():
|
||||
#print(self.dmov.get())
|
||||
sleep(checktime)
|
||||
|
||||
def changeTo(self,value,hold=False):
|
||||
changer = lambda value: self.move_and_wait(value)
|
||||
return Changer(
|
||||
target=value,
|
||||
parent=self,
|
||||
changer=changer,
|
||||
hold=hold,
|
||||
stopper=None)
|
||||
|
||||
|
||||
class MonoEcolEnergy:
|
||||
def __init__(self,Id):
|
||||
self.Id = Id
|
||||
self.name = 'energy_collimator'
|
||||
self.dcm = Double_Crystal_Mono(Id)
|
||||
self.ecol = EcolEnergy('ecol_dummy')
|
||||
self.offset = None
|
||||
self.MeVperEV = 0.78333
|
||||
|
||||
|
||||
def get_current_value(self):
|
||||
return self.dcm.get_current_value()
|
||||
|
||||
def move_and_wait(self,value):
|
||||
ch = [self.dcm.changeTo(value),
|
||||
self.ecol.changeTo(self.calcEcol(value))]
|
||||
for tc in ch:
|
||||
tc.wait()
|
||||
|
||||
def changeTo(self,value,hold=False):
|
||||
changer = lambda value: self.move_and_wait(value)
|
||||
return Changer(
|
||||
target=value,
|
||||
parent=self,
|
||||
changer=changer,
|
||||
hold=hold,
|
||||
stopper=self.dcm.stop)
|
||||
|
||||
def alignOffsets(self):
|
||||
mrb = self.dcm.get_current_value()
|
||||
erb = self.ecol.get_current_value()
|
||||
self.offset = {'dcm':mrb, 'ecol':erb}
|
||||
|
||||
def calcEcol(self,eV):
|
||||
return (eV-self.offset['dcm'])*self.MeVperEV + self.offset['ecol']
|
||||
|
||||
|
||||
class AlvraDCM_FEL:
|
||||
def __init__(self,Id):
|
||||
self.Id = Id
|
||||
self.name = 'Alvra DCM monochromator coupled to FEL beam'
|
||||
# self.IOCstatus = PV('ALVRA:running') # bool 0 running, 1 not running
|
||||
self._FELcoupling = PV('SGE-OP2E-ARAMIS:MODE_SP') # string "Off" or "e-beam"
|
||||
self._setEnergy = PV('SAROP11-ARAMIS:ENERGY_SP_USER') # float eV
|
||||
self._getEnergy = PV('SAROP11-ARAMIS:ENERGY') # float eV
|
||||
self.ebeamEnergy = PV('SARCL02-MBND100:P-READ') # float MeV/c
|
||||
# self.ebeamEnergySP = PV('ALVRA:Energy_SP') # float MeV
|
||||
self.dcmStop = PV('SAROP11-ODCM105:STOP.PROC') # stop the DCM motors
|
||||
self.dcmMoving = PV('SAROP11-ODCM105:MOVING') # DCM moving field
|
||||
self._energyChanging = PV('SGE-OP2E-ARAMIS:MOVING') # PV telling you something related to the energy is changing
|
||||
self._alvraMode = PV('SAROP11-ARAMIS:MODE') # string Aramis SAROP11 mode
|
||||
self.ebeamOK = PV('SFB_BEAM_ENERGY_ECOL:SUM-ERROR-OK') # is ebeam no longer changing
|
||||
self.photCalib1 = PV('SGE-OP2E-ARAMIS:PH2E_X1') # photon energy calibration low calibration point
|
||||
self.photCalib2 = PV('SGE-OP2E-ARAMIS:PH2E_X2') # photon energy calibration high calibration point
|
||||
self.ebeamCalib1 = PV('SGE-OP2E-ARAMIS:PH2E_Y1') # electron energy calibration low calibration point
|
||||
self.ebeamCalib2 = PV('SGE-OP2E-ARAMIS:PH2E_Y2') # electron energy calibration high calibration point
|
||||
|
||||
def __str__(self):
|
||||
# ioc = self.IOCstatus.get()
|
||||
# if ioc == 0:
|
||||
# iocStr = "Soft IOC running"
|
||||
# else:
|
||||
# iocStr = "Soft IOC not running"
|
||||
FELcouplingStr = self._FELcoupling.get(as_string=True)
|
||||
alvraModeStr = self._alvraMode.get(as_string=True)
|
||||
currEnergy = self._getEnergy.get()
|
||||
currebeamEnergy = self.ebeamEnergy.get()
|
||||
photCalib1Str = self.photCalib1.get()
|
||||
photCalib2Str = self.photCalib2.get()
|
||||
ebeamCalib1Str = self.ebeamCalib1.get()
|
||||
ebeamCalib2Str = self.ebeamCalib2.get()
|
||||
|
||||
s = '**Alvra DCM-FEL status**\n\n'
|
||||
# print('%s'%iocStr)
|
||||
# print('FEL coupling %s'%FELcouplingStr)
|
||||
# print('Alvra beamline mode %s'%alvraModeStr)
|
||||
# print('Photon energy (eV) %'%currEnergy)
|
||||
# s += '%s\n'%iocStr
|
||||
s += 'FEL coupling: %s\n'%FELcouplingStr
|
||||
s += 'Alvra beamline mode: %s\n'%alvraModeStr
|
||||
s += 'Photon energy: %.2f eV\n'%currEnergy
|
||||
s += 'Electron energy: %.2f MeV\n'%currebeamEnergy
|
||||
s += 'Calibration set points:\n'
|
||||
s += 'Low: Photon %.2f keV, Electron %.2f MeV\n'%(photCalib1Str, ebeamCalib1Str)
|
||||
s += 'High: Photon %.2f keV, Electron %.2f MeV\n'%(photCalib2Str, ebeamCalib2Str)
|
||||
return s
|
||||
|
||||
def get_current_value(self):
|
||||
return self._getEnergy.get()
|
||||
|
||||
def move_and_wait(self,value,checktime=.1,precision=0.5):
|
||||
self._FELcoupling.put(1) # ensure the FEL coupling is turned on
|
||||
self._setEnergy.put(value)
|
||||
# while self.ebeamOK.get()==0:
|
||||
# sleep(checktime)
|
||||
# while abs(self.ebeamEnergy.get()-self.ebeamEnergySP.get())>precision:
|
||||
# sleep(checktime)
|
||||
# while self.dcmMoving.get()==1:
|
||||
# sleep(checktime)
|
||||
while self._energyChanging == 1:
|
||||
sleep(checktime)
|
||||
|
||||
def changeTo(self,value,hold=False):
|
||||
changer = lambda value: self.move_and_wait(value)
|
||||
return Changer(
|
||||
target=value,
|
||||
parent=self,
|
||||
changer=changer,
|
||||
hold=hold,
|
||||
stopper=None)
|
||||
|
||||
def __repr__(self):
|
||||
return self.__str__()
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
from ..devices_general.motors import MotorRecord
|
||||
from epics import PV
|
||||
from ..aliases import Alias, append_object_to_object
|
||||
|
||||
|
||||
class RefLaser_Aramis:
|
||||
def __init__(self, Id, elog=None, name=None, inpos=-18.818, outpos=-5):
|
||||
self.Id = Id
|
||||
self.elog = elog
|
||||
self.name = name
|
||||
self.alias = Alias(name)
|
||||
# append_object_to_object(self,
|
||||
|
||||
self._inpos = inpos
|
||||
self._outpos = outpos
|
||||
self.mirrmotor = MotorRecord(self.Id + ":MOTOR_1")
|
||||
|
||||
def __call__(self, *args, **kwargs):
|
||||
self.set(*args, **kwargs)
|
||||
|
||||
def __str__(self):
|
||||
status = self.get_status()
|
||||
if status:
|
||||
return "Reflaser is In."
|
||||
elif status == False:
|
||||
return "Reflaser is Out."
|
||||
elif status == None:
|
||||
return "Reflaser status not defined."
|
||||
|
||||
def get_status(self):
|
||||
v = self.mirrmotor.get_current_value()
|
||||
if abs(v - self._inpos) < 0.2:
|
||||
isin = True
|
||||
elif abs(v - self._outpos) < 0.2:
|
||||
isin = False
|
||||
else:
|
||||
isin = None
|
||||
return isin
|
||||
|
||||
def set(self, value):
|
||||
if type(value) is str:
|
||||
if value.lower() == "in":
|
||||
value = True
|
||||
elif value.lower() == "out":
|
||||
value = False
|
||||
else:
|
||||
print("String %s not recognized!" % value)
|
||||
if value:
|
||||
self.mirrmotor.set_target_value(self._inpos)
|
||||
else:
|
||||
self.mirrmotor.set_target_value(self._outpos)
|
||||
|
||||
def __repr__(self):
|
||||
return self.__str__()
|
||||
@@ -0,0 +1,24 @@
|
||||
#!/opt/gfa/python-3.5/latest/bin/python
|
||||
from epics import PV
|
||||
import datetime
|
||||
import sys
|
||||
|
||||
|
||||
class stationMessage:
|
||||
def __init__(self, station):
|
||||
self._BL = station
|
||||
|
||||
def post(self, message):
|
||||
stationStr = self._BL
|
||||
msg = message
|
||||
date_formatted = datetime.datetime.strftime(
|
||||
datetime.datetime.now(), "%a %d-%b-%Y %H:%M:%S"
|
||||
)
|
||||
mscroll = PV("SF-OP:" + str(stationStr) + "-MSG:OP-MSCROLL.PROC")
|
||||
mscroll.value = 1
|
||||
msg1 = PV("SF-OP:" + str(stationStr) + "-MSG:OP-MSG1")
|
||||
msg1.value = msg.encode()
|
||||
date1 = PV("SF-OP:" + str(stationStr) + "-MSG:OP-DATE1")
|
||||
date1.value = date_formatted.encode()
|
||||
msg1.disconnect()
|
||||
date1.disconnect()
|
||||
@@ -0,0 +1,8 @@
|
||||
import matplotlib.pyplot as plt
|
||||
|
||||
|
||||
def identifyContrastplotData(x, y, i):
|
||||
assert i.ndim == 2, "Intensity data needs to be 2 dimensional!"
|
||||
assert (
|
||||
x.ndim == y.ndim
|
||||
), "please provide x and y plotting coordinate in same dimension"
|
||||
@@ -0,0 +1,24 @@
|
||||
from time import sleep
|
||||
|
||||
import sys, select
|
||||
|
||||
|
||||
|
||||
_wait_strs = '\|/-\|/-'
|
||||
|
||||
class WaitInput:
|
||||
def __init__(self,text,wait_time=5,update_interval=1):
|
||||
self.text = text
|
||||
self.wait_time=wait_time
|
||||
|
||||
|
||||
def start(self):
|
||||
resttime = self.wait_time
|
||||
while resttime>0:
|
||||
print(f"You have {resttime} seconds to answer!")
|
||||
i, o, e = select.select( [sys.stdin], [], [], 2 )
|
||||
|
||||
if (i):
|
||||
print("You said", sys.stdin.readline().strip())
|
||||
else:
|
||||
print("You said nothing!")
|
||||
@@ -0,0 +1,77 @@
|
||||
import traceback
|
||||
from colorama import Fore as _color
|
||||
from importlib import import_module
|
||||
import copy
|
||||
|
||||
try:
|
||||
from lazy_object_proxy import Proxy as LazyProxy
|
||||
except:
|
||||
print(
|
||||
"Could not find package lazy-object-proxy for lazy initialisation of devices!"
|
||||
)
|
||||
pass
|
||||
|
||||
|
||||
def init_device(devDict, devId, args, kwargs, verbose=True):
|
||||
imp_p = devDict["eco_type"].split(sep=".")
|
||||
dev_alias = devDict["alias"]
|
||||
dev_alias = dev_alias[0].lower() + dev_alias[1:]
|
||||
eco_type_name = imp_p[-1]
|
||||
istr = "from .." + ".".join(imp_p[:-1]) + " import "
|
||||
istr += "%s as _%s" % (eco_type_name, eco_type_name)
|
||||
# print(istr)
|
||||
if verbose:
|
||||
print(("Configuring %s " % (dev_alias)).ljust(25), end="")
|
||||
print(("(%s)" % (devId)).ljust(25), end="")
|
||||
error = None
|
||||
try:
|
||||
exec(istr)
|
||||
tdev = eval("_%s(Id='%s',*args,**kwargs)" % (eco_type_name, devId))
|
||||
tdev.name = dev_alias
|
||||
tdev._z_und = devDict["z_und"]
|
||||
if verbose:
|
||||
print((_color.GREEN + "OK" + _color.RESET).rjust(5))
|
||||
return tdev
|
||||
except Exception as expt:
|
||||
# tb = traceback.format_exc()
|
||||
if verbose:
|
||||
print((_color.RED + "FAILED" + _color.RESET).rjust(5))
|
||||
# print(sys.exc_info())
|
||||
raise expt
|
||||
|
||||
|
||||
def initDeviceAliasList(aliases, lazy=False, verbose=True):
|
||||
devices = {}
|
||||
problems = {}
|
||||
for device_Id in aliases.keys():
|
||||
alias = aliases[device_Id]["alias"]
|
||||
alias = alias[0].lower() + alias[1:]
|
||||
if "eco_type" in aliases[device_Id].keys() and aliases[device_Id]["eco_type"]:
|
||||
if "args" in aliases[device_Id].keys() and aliases[device_Id]["args"]:
|
||||
args = aliases[device_Id]["args"]
|
||||
else:
|
||||
args = tuple()
|
||||
|
||||
if "kwargs" in aliases[device_Id].keys() and aliases[device_Id]["kwargs"]:
|
||||
kwargs = aliases[device_Id]["kwargs"]
|
||||
else:
|
||||
kwargs = dict()
|
||||
try:
|
||||
devices[alias] = {}
|
||||
devices[alias]["device_Id"] = device_Id
|
||||
if lazy:
|
||||
devices[alias]["factory"] = lambda: init_device(
|
||||
aliases[device_Id], device_Id, args, kwargs, verbose=verbose
|
||||
)
|
||||
dev = LazyProxy(devices[alias]["factory"])
|
||||
else:
|
||||
dev = init_device(
|
||||
aliases[device_Id], device_Id, args, kwargs, verbose=verbose
|
||||
)
|
||||
devices[alias]["instance"] = dev
|
||||
except:
|
||||
device.pop(alias)
|
||||
problems[alias] = {}
|
||||
problems[alias]["device_Id"] = device_Id
|
||||
problems[alias]["trace"] = traceback.format_exc()
|
||||
return devices, problems
|
||||
@@ -0,0 +1 @@
|
||||
from . import materials
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,110 @@
|
||||
import xrayutilities as xu
|
||||
from . import consts as _consts
|
||||
from scipy.constants import torr, bar, k, N_A, R
|
||||
import numpy as np
|
||||
|
||||
# This module holds relevant materials of the
|
||||
# xrayutilities materials class,
|
||||
|
||||
|
||||
class MaterialCollection:
|
||||
""" Dummy class collections of materials (dict-like)."""
|
||||
|
||||
def __init__(self, **entries):
|
||||
self.__dict__.update(entries)
|
||||
|
||||
def __setitem__(self, key, value):
|
||||
self.__dict__.update({key: value})
|
||||
|
||||
|
||||
_amorphous = dict()
|
||||
_crystal = dict()
|
||||
_gas = dict()
|
||||
|
||||
amorphous = MaterialCollection()
|
||||
crystal = MaterialCollection()
|
||||
gas = MaterialCollection()
|
||||
|
||||
|
||||
def _get_transmission(self, d, E="config"):
|
||||
""" calculate the transmittion after thickness d (in m) of material at energy E (in eV)."""
|
||||
return np.exp(-d * 1e6 / self.absorption_length(E))
|
||||
|
||||
|
||||
xu.materials.Material.transmission = _get_transmission
|
||||
|
||||
|
||||
crystal["Si"] = xu.materials.Si
|
||||
crystal["Ge"] = xu.materials.Ge
|
||||
crystal["GaAs"] = xu.materials.GaAs
|
||||
crystal["Al"] = xu.materials.Al
|
||||
crystal["Diamond"] = xu.materials.C
|
||||
crystal["Be"] = xu.materials.material.Crystal(
|
||||
"Be",
|
||||
xu.materials.spacegrouplattice.SGLattice(
|
||||
194, 2.2858, 3.5843, atoms=[xu.materials.elements.Be], pos=["2c"]
|
||||
),
|
||||
)
|
||||
|
||||
amorphous["B4C"] = xu.materials.material.Amorphous("B4C", 2520, [("B", 4), ("C", 1)])
|
||||
amorphous["Mo"] = xu.materials.material.Amorphous("Mo", 10220, [("Mo", 1)])
|
||||
amorphous["polyimide"] = xu.materials.material.Amorphous(
|
||||
"polyimide", 1430, [("C", 22), ("H", 10), ("N", 2), ("O", 5)]
|
||||
)
|
||||
amorphous["mylar"] = xu.materials.material.Amorphous(
|
||||
"mylar", 1400, [("C", 10), ("H", 8), ("O", 4)]
|
||||
)
|
||||
amorphous["polycarbonate"] = xu.materials.material.Amorphous(
|
||||
"polycarbonate", 1200, [("C", 16), ("H", 14), ("O", 3)]
|
||||
)
|
||||
amorphous["Si3N4"] = xu.materials.material.Amorphous(
|
||||
"Silicon nitride", 3440, [("Si", 3), ("N", 4)]
|
||||
)
|
||||
amorphous["air"] = xu.materials.material.Amorphous(
|
||||
"air", 1000, [("N", 1.562), ("O", 0.42), ("C", 0.0003), ("Ar", 0.0094)]
|
||||
)
|
||||
|
||||
|
||||
# more useful values and constants
|
||||
# elementName = DummyClassDict(_consts.elementName)
|
||||
# meltPoint = DummyClassDict(_consts.meltPoint)
|
||||
# density = DummyClassDict(_consts.Density)
|
||||
|
||||
|
||||
class Gas(xu.materials.material.Amorphous):
|
||||
def __init__(
|
||||
self, name, pressure=bar, temperature=295, molecule_size=1, atoms=None, cij=None
|
||||
):
|
||||
"""pressure in Pascal, temperature in Kelvin"""
|
||||
self.pressure = pressure
|
||||
self.temperature = temperature
|
||||
self.molecule_size = molecule_size
|
||||
super(Gas, self).__init__(name, 0, atoms=atoms, cij=cij)
|
||||
|
||||
def _getdensity(self):
|
||||
"""
|
||||
calculates the mass density of an material from the atomic composition and the average molecule size (ideal gas).
|
||||
|
||||
Returns
|
||||
-------
|
||||
mass density in kg/m^3
|
||||
"""
|
||||
num_dens = self.pressure / k / self.temperature
|
||||
return self._get_composition_mass() * num_dens * self.molecule_size
|
||||
|
||||
density = property(_getdensity)
|
||||
|
||||
def _get_composition_mass(self):
|
||||
w = 0
|
||||
for atom, occ in self.base:
|
||||
w += atom.weight * occ
|
||||
return w
|
||||
|
||||
|
||||
gas["air"] = Gas(
|
||||
"air",
|
||||
molecule_size=1.9917,
|
||||
atoms=[("N", 1.562), ("O", 0.42), ("C", 0.0003), ("Ar", 0.0094)],
|
||||
)
|
||||
gas["He"] = Gas("He", molecule_size=1, atoms=[("He", 1)])
|
||||
gas["N"] = Gas("He", molecule_size=2, atoms=[("N", 1)])
|
||||
@@ -0,0 +1,44 @@
|
||||
import xrayutilities as xu
|
||||
import xraylib as xl
|
||||
import numpy as np
|
||||
from . import materials
|
||||
|
||||
|
||||
def getKBMirrorLayer():
|
||||
subst = xu.simpack.Layer(materials.crystal.Si, np.inf)
|
||||
highZ = xu.simpack.Layer(materials.amorphous.Mo, 200)
|
||||
lowZ = xu.simpack.Layer(materials.amorphous.B4C, 150)
|
||||
return subst + highZ + lowZ
|
||||
|
||||
|
||||
def calcReflectivity(
|
||||
mirror=getKBMirrorLayer(),
|
||||
energys=np.linspace(2000, 12000, 200),
|
||||
alphais=np.linspace(0, 3, 200),
|
||||
sample_width=500,
|
||||
**kwargs
|
||||
):
|
||||
Refl = []
|
||||
for E in energys:
|
||||
m = xu.simpack.SpecularReflectivityModel(mirror, energy=E, **kwargs)
|
||||
Refl.append(m.simulate(alphais))
|
||||
|
||||
return np.asarray(Refl), energys, alphais
|
||||
|
||||
|
||||
def absorptionEdge(element, edge=None):
|
||||
if type(element) is str:
|
||||
element = xl.SymbolToAtomicNumber(element)
|
||||
shells = ["K", "L1", "L2", "L3", "M1", "M2", "M3", "M4", "M5"]
|
||||
if edge is not None:
|
||||
shell_ind = shells.index(edge)
|
||||
return xl.EdgeEnergy(element, shell_ind)
|
||||
else:
|
||||
shell_inds = range(8)
|
||||
print("Absorption edges %s" % xl.AtomicNumberToSymbol(element))
|
||||
for shell_ind in shell_inds:
|
||||
print(
|
||||
" "
|
||||
+ shells[shell_ind].ljust(3)
|
||||
+ " = %7.1f eV" % (xl.EdgeEnergy(element, shell_ind) * 1000)
|
||||
)
|
||||
@@ -0,0 +1,82 @@
|
||||
import numpy as np
|
||||
from scipy import constants
|
||||
import xraylib as xl
|
||||
|
||||
|
||||
def cartesian(arrays, out=None):
|
||||
"""
|
||||
Generate a cartesian product of input arrays.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
arrays : list of array-like
|
||||
1-D arrays to form the cartesian product of.
|
||||
out : ndarray
|
||||
Array to place the cartesian product in.
|
||||
|
||||
Returns
|
||||
-------
|
||||
out : ndarray
|
||||
2-D array of shape (M, len(arrays)) containing cartesian products
|
||||
formed of input arrays.
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> cartesian(([1, 2, 3], [4, 5], [6, 7]))
|
||||
array([[1, 4, 6],
|
||||
[1, 4, 7],
|
||||
[1, 5, 6],
|
||||
[1, 5, 7],
|
||||
[2, 4, 6],
|
||||
[2, 4, 7],
|
||||
[2, 5, 6],
|
||||
[2, 5, 7],
|
||||
[3, 4, 6],
|
||||
[3, 4, 7],
|
||||
[3, 5, 6],
|
||||
[3, 5, 7]])
|
||||
|
||||
"""
|
||||
|
||||
arrays = [np.asarray(x) for x in arrays]
|
||||
dtype = arrays[0].dtype
|
||||
|
||||
n = np.prod([x.size for x in arrays])
|
||||
if out is None:
|
||||
out = np.zeros([n, len(arrays)], dtype=dtype)
|
||||
|
||||
m = n / arrays[0].size
|
||||
out[:, 0] = np.repeat(arrays[0], m)
|
||||
if arrays[1:]:
|
||||
cartesian(arrays[1:], out=out[0:m, 1:])
|
||||
for j in range(1, arrays[0].size):
|
||||
out[j * m : (j + 1) * m, 1:] = out[0:m, 1:]
|
||||
return out
|
||||
|
||||
|
||||
def E2lam(energy):
|
||||
"""energy in eV, lambda in Ångstrøm"""
|
||||
return constants.h * constants.c / constants.e / energy * 1e10
|
||||
|
||||
|
||||
def QE2theta(Q, energy):
|
||||
"""Q in Å**(-1), energy in eV, theta in radians"""
|
||||
return np.arcsin(E2lam(energy) / 4 / np.pi * Q)
|
||||
|
||||
|
||||
def absorptionEdge(element, edge=None):
|
||||
if type(element) is str:
|
||||
element = xl.SymbolToAtomicNumber(element)
|
||||
shells = ["K", "L1", "L2", "L3", "M1", "M2", "M3", "M4", "M5"]
|
||||
if edge is not None:
|
||||
shell_ind = shells.index(edge)
|
||||
return xl.EdgeEnergy(element, shell_ind)
|
||||
else:
|
||||
shell_inds = range(8)
|
||||
print("Absorption edges %s" % xl.AtomicNumberToSymbol(element))
|
||||
for shell_ind in shell_inds:
|
||||
print(
|
||||
" "
|
||||
+ shells[shell_ind].ljust(3)
|
||||
+ " = %7.1f eV" % (xl.EdgeEnergy(element, shell_ind) * 1000)
|
||||
)
|
||||
Reference in New Issue
Block a user