diff --git a/config/config.properties b/config/config.properties index 6246d8a..d7c3017 100644 --- a/config/config.properties +++ b/config/config.properties @@ -1,16 +1,17 @@ -#Wed Jan 20 15:37:49 CET 2016 +#Thu Mar 17 10:47:20 CET 2016 autoSaveScanData=true createSessionFiles=false +dataLayout=default dataPath={data}/{year}_{month}/{date}/{date}_{time}_{exec} dataProvider=default dataScanFlushRecords=true -dataScanStrategy=default devicePoolFile={config}/devices.properties deviceUpdateStrategyFile={config}/update.properties logDaysToLive=-1 logLevel=Info logLevelConsole=Off logPath={logs}/{date}_{time} +scanStreamingPort=-1 serverEnabled=true serverPort=8080 simulation=false @@ -21,5 +22,5 @@ userAuthenticator= userManagement=false versionTrackingEnabled=true versionTrackingLogin= -versionTrackingManual=false -versionTrackingRemote=git@git.psi.ch\:pshell_config/x06da.git +versionTrackingManual=true +versionTrackingRemote=https\://git.psi.ch/pshell_config/x06da.git diff --git a/config/devices.properties b/config/devices.properties index 3a79aef..59a36c8 100644 --- a/config/devices.properties +++ b/config/devices.properties @@ -1,4 +1,5 @@ -bpm1=ch.psi.pshell.epics.ChannelDouble|X06DA-ES-BPM1:POSV|Read||true +es_beam=ch.psi.pshell.epics.ChannelDouble|X06DA-ES-BPM1:SUM|Read||true +es_beam_posv=ch.psi.pshell.epics.ChannelDouble|X06DA-ES-BPM1:POSV|Read||true current=ch.psi.pshell.epics.ChannelDouble|ARIDI-PCT:CURRENT|Read||true i0=ch.psi.pshell.epics.ChannelDouble|X06DA-ES-I0:READOUT 6|Read||true diode=ch.psi.pshell.epics.ChannelDouble|X06DA-ES-DIODE:READOUT|Read||true @@ -9,6 +10,9 @@ beam_stop_pos=ch.psi.pshell.epics.BinaryPositioner|X06DA-ES-BS:SET-POS X06DA-ES- det_cover=ch.psi.pshell.epics.DiscretePositioner|X06DA-ES-PILCOV:SET|Read||true backlight_pos=ch.psi.pshell.epics.BinaryPositioner|X06DA-ES-BL:SET-POS X06DA-ES-BL:GET-POS|Read||true frontlight_enable=ch.psi.pshell.epics.BinaryPositioner|X06DA-ES-FL:ENABLE|Read||true +fe_absorber=ch.psi.pshell.epics.BinaryPositioner|X06DA-FE-AB1:OPEN_EPS||| +fe_shutter=ch.psi.pshell.epics.BinaryPositioner|X06DA-FE-PH1:OPEN_EPS||| +eh_shutter=ch.psi.pshell.epics.BinaryPositioner|X06DA-OP-ST1:OPEN_EPS||| filter1=ch.psi.pshell.epics.DiscretePositioner|X06DA-ES-FI1:SET X06DA-ES-FI1:GET|||true filter2=ch.psi.pshell.epics.DiscretePositioner|X06DA-ES-FI2:SET X06DA-ES-FI2:GET|||true filter3=ch.psi.pshell.epics.DiscretePositioner|X06DA-ES-FI3:SET X06DA-ES-FI3:GET|||true @@ -34,11 +38,29 @@ cryo_jet_tans=ch.psi.pshell.epics.Motor|X06DA-ES-CJ:TRX1|||true aperture_x=ch.psi.pshell.epics.Motor|X06DA-ES-KBOX:TRX1|||true collimator_x=ch.psi.pshell.epics.Motor|X06DA-ES-KBOX:TRX2|||true diode_z=ch.psi.pshell.epics.Motor|X06DA-ES-KBOX:TRZ3|||true +marcover=ch.psi.pshell.epics.ChannelDouble|X06DA-ES-KBOX:SIG-RAW|||true +fluo_monitor=ch.psi.pshell.epics.ChannelDouble|X06DA-ES-BM:I0|||true #beamstop=ch.psi.pshell.device.MotorGroupDiscretePositioner|beamstop_x beamstop_y beamstop_z||| mono_beam=ch.psi.pshell.epics.ChannelDouble|X06DA-OP-BPM1:SUM|Read||true +mono_beam_ref=ch.psi.pshell.epics.ChannelDouble|X06DA-OP-MO:MONOBEAM||| +mono_energy=ch.psi.pshell.epics.ChannelDouble|X06DA-OP-MO:E-GET|||true slithop=ch.psi.pshell.epics.Slit|X06DA-OP-SH1:TRX2 X06DA-OP-SH1:TRX1|||true +pvs=ch.psi.pshell.epics.ChannelDouble|X06DA-FE-SVsize|||false +pvc=ch.psi.pshell.epics.ChannelDouble|X06DA-FE-SVcenter|||false +phs=ch.psi.pshell.epics.ChannelDouble|X06DA-OP-SHsize||| +phc=ch.psi.pshell.epics.ChannelDouble|X06DA-OP-SHcenter||| +ths=ch.psi.pshell.epics.ChannelDouble|X06DA-ES-SH1:TRX1||| +thc=ch.psi.pshell.epics.ChannelDouble|X06DA-ES-SH1:TRX2||| +tvs=ch.psi.pshell.epics.ChannelDouble|X06DA-ES-SV1:TRY1||| +tvc=ch.psi.pshell.epics.ChannelDouble|X06DA-ES-SV1:TRY2||| +qhs=ch.psi.pshell.epics.ChannelDouble|X06DA-ES-SH2:TRX1||| +qhc=ch.psi.pshell.epics.ChannelDouble|X06DA-ES-SH2:TRX2||| +qvs=ch.psi.pshell.epics.ChannelDouble|X06DA-ES-SV2:TRY1||| +qvc=ch.psi.pshell.epics.ChannelDouble|X06DA-ES-SV2:TRY2||| th1=ch.psi.pshell.epics.Motor|X06DA-OP-MO1:ROX1|||true th2=ch.psi.pshell.epics.Motor|X06DA-OP-MO1:ROX2|||true +th1_encoder=ch.psi.pshell.epics.ChannelDouble|X06DA-OP-MO1:ECX1|Read||false +th2_encoder=ch.psi.pshell.epics.ChannelDouble|X06DA-OP-MO1:ECX2|Read||false try3=ch.psi.pshell.epics.Motor|X06DA-OP-MI1:TRY3|||true slit1h_size=ch.psi.pshell.epics.Motor|X06DA-ES-SH1:TRX1|||true slit1h_center=ch.psi.pshell.epics.Motor|X06DA-ES-SH1:TRX2|||true diff --git a/devices/bpm1v.properties b/devices/bpm1v.properties new file mode 100644 index 0000000..e98c266 --- /dev/null +++ b/devices/bpm1v.properties @@ -0,0 +1,14 @@ +#Fri Feb 19 14:38:26 CET 2016 +defaultSpeed=NaN +estbilizationDelay=0 +hasEnable=false +homingType=None +maxSpeed=NaN +maxValue=NaN +minSpeed=NaN +minValue=NaN +offset=0.0 +precision=-1 +resolution=NaN +scale=1.0 +unit=null diff --git a/devices/phc.properties b/devices/phc.properties new file mode 100644 index 0000000..0dc2807 --- /dev/null +++ b/devices/phc.properties @@ -0,0 +1,14 @@ +#Mon Feb 22 17:00:46 CET 2016 +defaultSpeed=NaN +estbilizationDelay=0 +hasEnable=false +homingType=None +maxSpeed=NaN +maxValue=NaN +minSpeed=NaN +minValue=NaN +offset=0.0 +precision=-1 +resolution=NaN +scale=1.0 +unit=null diff --git a/devices/phs.properties b/devices/phs.properties new file mode 100644 index 0000000..0dc2807 --- /dev/null +++ b/devices/phs.properties @@ -0,0 +1,14 @@ +#Mon Feb 22 17:00:46 CET 2016 +defaultSpeed=NaN +estbilizationDelay=0 +hasEnable=false +homingType=None +maxSpeed=NaN +maxValue=NaN +minSpeed=NaN +minValue=NaN +offset=0.0 +precision=-1 +resolution=NaN +scale=1.0 +unit=null diff --git a/devices/pvc.properties b/devices/pvc.properties new file mode 100644 index 0000000..acc0a37 --- /dev/null +++ b/devices/pvc.properties @@ -0,0 +1,14 @@ +#Mon Feb 22 17:07:43 CET 2016 +defaultSpeed=NaN +estbilizationDelay=0 +hasEnable=false +homingType=None +maxSpeed=NaN +maxValue=NaN +minSpeed=NaN +minValue=NaN +offset=0.0 +precision=-1 +resolution=NaN +scale=1.0 +unit=null diff --git a/devices/pvs.properties b/devices/pvs.properties new file mode 100644 index 0000000..acc0a37 --- /dev/null +++ b/devices/pvs.properties @@ -0,0 +1,14 @@ +#Mon Feb 22 17:07:43 CET 2016 +defaultSpeed=NaN +estbilizationDelay=0 +hasEnable=false +homingType=None +maxSpeed=NaN +maxValue=NaN +minSpeed=NaN +minValue=NaN +offset=0.0 +precision=-1 +resolution=NaN +scale=1.0 +unit=null diff --git a/script/censlits.py b/script/censlits.py new file mode 100644 index 0000000..9681850 --- /dev/null +++ b/script/censlits.py @@ -0,0 +1,79 @@ +slits = ['Primaries horizontal','Primaries Vertical', + 'ExpBox Tert. horizontal ','ExpBox Tert. vertical', + 'ExpBox Quart. horizontal','ExpBox Quart. vertical'] + +ev = get_string('Please select slits', None, slits) +if ev is None: + raise Exception("Aborted") + +elif ev == slits[0]: #Primaries-Horizontal after collimating mirror and before mono + mmot = phs # slit size + smot = phc # slit centre + r = 10.0 # scan half range + pclose = r/10. # slit size for scan + popen = 12.0 # slit size in open position + detector = mono_beam + #MESSAGE,'Not ready yet',/cont +elif ev == slits[0]: #Primaries-Vertical before collimating mirror + mmot = pvs + smot = pvc + r = 2.0 + pclose = r/10. + popen = 2.0 + detector = mono_beam + #MESSAGE,'Not ready yet',/cont +elif ev == slits[2]: #Exposure box Tertiary slits-Horizontal before IO + mmot = ths + smot = thc + r = 1.0 + pclose = r/10.0 + popen = 1.0 + detector = Channel('X06DA-ES-BM:I0', 'd') +elif ev == slits[0]: #Exposure box Tertiary slits-Vertical + mmot = tvs + smot = tvc + r = 0.4 + pclose = r/4. + popen = .4 + detector = Channel('X06DA-ES-BM:I0', 'd') +elif ev == slits[0]: #Exposure box Quartenary slits-Horizontal after I0 + mmot = qhs + smot = qhc + r = 0.4 + pclose = r/8. + popen = .40 + detector = marcover + #MESSAGE,'To make sure the diode is connected',/cont +elif ev == slits[5]: #Exposure box Quartenary slits-Vertical + mmot = qvs + smot = qvc + r = 0.3 + pclose = r/6. + popen = .20 + detector = mono_beam + #MESSAGE,'To make sure the diode is connected',/cont + +mmot.write(pclose) +result = lscan(smot, detector, -r,r, 20, latency = 0.5, relative = True) #SCAN,smot,-r,r,20,data=d,gfit=a,time=.5,detec=detector +(ydata, xdata) = (result.getReadable(0), result.getPositions(0)) + +ydata = [x*1e6 for x in ydata] +maxy = max(ydata) #MAX(y,im) +cen =sum([ydata[i] * xdata[i] for i in range(len(ydata))]) / sum(ydata) #TOTAL(x*y) / TOTAL(y) #TODO: is right? + + + +#OPLOT,x,GAUSSFIT(x,y,a,ESTIMATES = [maxy,cen,pclose,0,0,0],nterms=6)*1e-6, color=240,psym=6 +(n, m, s) = fit(ydata, xdata) + +#help,mmot +mmot.write(popen) + +if abs(m) < 1 and abs(m-cen) < 0.5: #TODO: is a(1) the mean? + print 'moving centre of slits to: ', m + smot.mov(m) +else: + #PLOTS,cen,[0,maxy]*1e6,color=240,linestyle=1 : #TODO ? + msg='fit failed - do you want to drive to centre of mass position: '+ cen +' ?' + if get_option(msg, 'YesNo') == 'Yes': + smot.mov(cen) diff --git a/script/check_rock.py b/script/check_rock.py new file mode 100644 index 0000000..cd45756 --- /dev/null +++ b/script/check_rock.py @@ -0,0 +1,90 @@ +# check_rock.com: a shell script to call idl routine to rock first or second crystal at X06DA +# when the flux is low +# purpose: to prevent crystal falls off the rocking curve when the temp of first crystal change. +# 20080506 meitian +# 20100621 mt & vo -> new CVD BPM in mono. check flux and ROCK, and then check vertical beam position and FBM + +print "======" +print "check&rock" +print "======" +# get energy first with simple calculation (i.e. not very accurate) +THETA1 = th1.read() +THETA2 = th2.read() +ENERGY = get_energy() +if int(ENERGY) < 6: + raise Exception("No rocking optimization for lower energy for 3rd harmonics rejection") + +# if theta1 and theta2 differ too much (>0.01deg), rock won't work well, sete should be used in this case +# 20130614, change threshold from 0.015 to 0.02 +if abs(THETA1 - THETA2) > 0.02: + raise Exception("Two mono crystals are not synchronized, please use 'sete()'") +# +# check the flux +print "check and rock" +BPM1C1 = caget("X06DA-OP-BPM1:CHAN1", 'd') +BPM1C2 = caget("X06DA-OP-BPM1:CHAN2", 'd') +BPM1C3 = caget("X06DA-OP-BPM1:CHAN3", 'd') +BPM1C4 = caget("X06DA-OP-BPM1:CHAN4", 'd') +BPM1 = (BPM1C1 + BPM1C2 + BPM1C3 + BPM1C4) / 4 +print "OP-BPM1 average = ", BPM1 +# if the BPM1 reading is too low, means no beam, do not rock, and quit +# without beam, BPM1 and 2 readings are about 1.2-1.2 nA +if BPM1 <= 2: + raise Exception("Flux is too low, either no beam or FE shutter is not open.") + +print "Current energy is ", ENERGY, ", mono theta2 is ", THETA2, "." +# 20080507 number for BPM1 +# keV 7 8 9 10 11 12 13 14 15 16 17 +# BPM1 with room light: 150 140 120 110 100 90 80 80 70 50 40 +# BPM1 w/o room light: 134 123 111 95 81 70 61 54 47 40 20 +# new CVD BPM 20100621 +# 6 7 8 9 10 11 12.4 13 14 15 16 17 +# 51 65 63 57 53 48 40 37 33 27 18 6 + +# get correct threshold for different energy +BPM1_limit = ["41", "52", "50", "44," "42", "39", "32", "30", "26", "21", "14", "4"] +i = 0 +for i in range(12): + n = i + 6 + if n == int(ENERGY): + print int(ENERGY), n, i, BPM1_limit[i] #TODO: There was bug indexing here? + BPM1_lowLimit = BPM1_limit[i] + + +# if flux is low, rock +if BPM1 <= BPM1_lowLimit: + print "BPM1 reading is lower than ", BPM1_lowLimit + print "lets rock." + rock() + time.sleep(2) +else : + print "BPM1 reading is higher than ", BPM1_lowLimit + print "nothing to do, quit." + print " " + #TODO: Should abort? + + +#========================================================== +print "======" +print "check and fbm" +# check the X06DA-ES-BPM1:POSV + +if ( eh_shutter.read() == "NOT_OPEN" ): + raise Exception("ExpHutchShutter closed - program will exit") + +BPM1POSV = es_beam_posv.read() +print "Vertical beam postion at ES-BPM1: ", BPM1POSV +# to get an integer (microns), 0.005 * 1000 / 1 with bc will do it. +POSV = int(BPM1POSV * 1000) +# if the POSV reading is not within +/- 8 microns means beam position is drifted, do FBM + +# if flux is low, rock +if POSV <= -6 or POSV >= 6 : + print "Beam is not aligned at E-BOX BPM1" + print "lets fix it." + fbm() + time.sleep(2) +else : + print "Beam is aligned at E-BOX BPM1," + print "nothing to do, quit." + print " " \ No newline at end of file diff --git a/script/fbm.py b/script/fbm.py index 938d957..ff62a39 100644 --- a/script/fbm.py +++ b/script/fbm.py @@ -3,31 +3,31 @@ ################################################################################################### -tc1 = caget('X06DA-OP-MO:TC1') # theta1 thermo couple 1 +#tc1 = caget('X06DA-OP-MO:TC1') # theta1 thermo couple 1 energy = get_energy() # Mono energy -dtz = caget('X06DA-ES-DET:TRZ1') # detector Z- position +dtz = detector_z.read() if current.read() < 200: raise Exception ('Ring current too low') -if caget('X06DA-FE-AB1:OPEN_EPS','i') == 0: +if fe_absorber.read()!= 'OPEN': raise Exception ('FrontEndAbsorber closed') # FrontEnd absorber shutter state -if caget('X06DA-FE-PH1:OPEN_EPS','i') == 0: # FrontEnd shutter state - raise Exception ('FrontEndShutter closed') +if fe_shutter.read() != 'OPEN': + raise Exception ('FrontendShutter closed') -if caget('X06DA-OP-ST1:OPEN_EPS','i') == 0: # ExpHutch shutter state +if eh_shutter.read() != 'OPEN': # ExpHutch shutter state raise Exception ('ExpHutchShutter closed ') -if caget(('X06DA-OP-MO:E-GET'),'d') > 17.5: #Mono energy - raise Exception ('Sorry, no feedback above 17.5 keV for now') +if mono_energy.read()> 17.5: #Mono energy + raise Exception ('Sorry, no feedback above 17.5 keV for now') tc = 40 # 2015.09.20 quick fix by MT JW -cur = caget('X06DA-ES-BPM1:SUM','d') +cur = es_beam.read() op1 = caget('X06DA-OP-XPM1:CHAN1', 'd') if op1 < 1.0: - sete_failed = 1 + sete_failed = 1 raise Exception ('X06DA-OP-XPM1:CHAN1 < 10 - please check monochromator, frontend, primary slits, ring current and undulator - program exits') # define max deviations @@ -36,15 +36,15 @@ ymax = 2e-3 # endwhile criterion for vertical correction if cur < tc: #check if beam is on CVD-XBPM - sete_failed = 1 + sete_failed = 1 raise Exception ('evere problem - NO BEAM ON HR-DIFFRACTOMETER XBPM') - + # initial mirror TRY3 position -y3i = try3.read() +y3i = try3.read() print "initial y3i: " + str(y3i) # how much beam is off? -by = bpm1.read() +by = es_beam_posv.read() print "EBOX-POSV before rock: " + str(by) # if beam is not off, do nothing if abs(by) > ymax: @@ -52,17 +52,16 @@ if abs(by) > ymax: # result of ROCK time.sleep(2.0) -by = bpm1.read() +by = es_beam_posv.read() print "EBOX-POSV after rock: " + str(by) # feedback while abs(by) >= ymax : - by = bpm1.read() + by = es_beam_posv.read() print "current EBOX-POSV: " + str(by) - cur = caget('X06DA-ES-BPM1:SUM','d') + cur = es_beam.read() if cur > tc: - ehs = caget('X06DA-OP-ST1:OPEN_EPS','i') # make sure that shutter is open - if (ehs > 0) and (abs(by) > ymax): + if (eh_shutter.read() == 'OPEN') and (abs(by) > ymax): if abs(by) > (50*ymax): raise Exception ('TODO') #limit mirror TRY3 movement diff --git a/script/fit.py b/script/fit.py index 017879f..e71c000 100644 --- a/script/fit.py +++ b/script/fit.py @@ -1,7 +1,7 @@ from mathutils import estimate_peak_indexes, fit_gaussians, create_fit_point_list, Gaussian import java.awt.Color as Color -def fit(ydata, xdata = None): +def fit(ydata, xdata = None, draw_plot = True): if xdata is None: xdata = frange(0, len(ydata), 1) max_y= max(ydata) @@ -13,24 +13,26 @@ def fit(ydata, xdata = None): gaussians = fit_gaussians(ydata, xdata, [index_max,]) (norm, mean, sigma) = gaussians[0] + if draw_plot: + p = plot([ydata],["data"],[xdata], title="Fit" )[0] + fitted_gaussian_function = Gaussian(norm, mean, sigma) + scale_x = [float(min(xdata)), float(max(xdata)) ] + points = max((len(xdata)+1), 100) + resolution = (scale_x[1]-scale_x[0]) / points + fit_y = [] + fit_x = frange(scale_x[0],scale_x[1],resolution, True) + for x in fit_x: + fit_y.append(fitted_gaussian_function.value(x)) + p.addSeries(LinePlotSeries("fit")) + p.getSeries(1).setData(fit_x, fit_y) - p = plot([ydata],["data"],[xdata], context="Fit" )[0] - fitted_gaussian_function = Gaussian(norm, mean, sigma) - scale_x = [float(min(xdata)), float(max(xdata)) ] - points = max((len(xdata)+1), 100) - resolution = (scale_x[1]-scale_x[0]) / points - fit_y = [] - fit_x = frange(scale_x[0],scale_x[1],resolution, True) - for x in fit_x: - fit_y.append(fitted_gaussian_function.value(x)) - p.addSeries(LinePlotSeries("fit")) - p.getSeries(1).setData(fit_x, fit_y) - - if abs(mean - xdata[index_max]) < abs((scale_x[0] + scale_x[1])/2): + if abs(mean - xdata[index_max]) < abs((scale_x[0] + scale_x[1])/2): + if draw_plot: + p.addMarker(mean, None, "Mean="+str(round(mean,4)), Color.MAGENTA.darker()) print "Mean -> " + str(mean) - p.addMarker(mean, None, "Mean="+str(round(mean,4)), Color.MAGENTA.darker()) return (norm, mean, sigma) else: - p.addMarker(max_x, None, "Max="+str(round(max_x,4)), Color.GRAY) + if draw_plot: + p.addMarker(max_x, None, "Max="+str(round(max_x,4)), Color.GRAY) print "Invalid gaussian fit: " + str(mean) return (None, None, None) diff --git a/script/flux_diode.py b/script/flux_diode.py new file mode 100644 index 0000000..a6d3e05 --- /dev/null +++ b/script/flux_diode.py @@ -0,0 +1,86 @@ +# from Clemens' flux calc & Robin's paper [Owen et al, JSR 16, 2009, Silicon PIN diodes] +#--------- formula -------------------------------------------- +# flux = I_ph * eps_Si /e/E/( 1-exp(A_Si*rsi*t_Si ) ) +# with Al and air atten: +# flux= flux * exp(A_Al*ral*t_Al) * exp(A_air*rair*t_air) +# +# with A_ being the photoelectric cross sections of the materials + +#--------- parameters ----------------------------------------- +# density of Si +rsi = 2.33 # g/cm^3 +# density of Al +ral = 2.699 # g/cm^3 +# density of air +rair = 1.205e-3 # g/cm^3 + +eps_si = 3.62 # eV energy req. for charge separation in Si (generation of el/hole pairs) +e = 1.602e-19 # As , elementary charge + +t_si = 0.0012 # thickness of diode in cm (== 12 micron) ; [* 10000] +t_al = 0.002 # thickness of diode in cm ; (== 20 micron) + +#--------- input--------------------------------------------------- + +cur = float(get_string('Please enter the measured diode current [in mA]', 0.1)) +ep = float(get_string('Please enter the photon energy [in keV]', 12.4 )) +t_si= float(get_string('Please enter the thickness of the Si layer [in micron]', t_si)) +t_si = t_si/10000. # --> cm +t_al = float(get_string('Please enter the thickness of the Al layer [in micron, 0 if not available]', t_al)) +t_al = t_al/10000 +t_air = float(get_string('Please enter the pathway in air [in mm]', 165.+100.)) + + +#--------- calc---------------------------------------------------- +# energy deposit in Silicon + +polys=[4.158,- 2.238, - 0.477, 0.0789] + +hlp_si= poly(math.log10(ep), polys) +A_Si= 10.0 ** hlp_si +efact=math.exp(-A_Si*rsi*t_si) + +sifact=1.0-efact + +#help, cur, eps_si, ep + +fl0=cur* eps_si/1.602/ep/sifact *1.e13 + + +# Aluminium attenuation + +# ratio of photoelectric cross section to density for Aluminium +polyal= [4.106, - 2.349, - 0.413, 0.0638 ] +hlp_al= poly(math.log10(ep), polyal) +A_Al= 10.0 ** hlp_al + +# attenuation due to aluminium +alfact=math.exp(-A_Al*ral*t_al) + +# Air attenuation + +# ratio of photoelectric cross section to density for air +polyair= [3.153, - 1.026, - 2.348, 0.928] +hlp_air= poly(math.log10(ep), polyair) +A_air= 10.0 ** hlp_air + +# attenuation due to air +airfact=math.exp(-A_air*rair*t_air/10.) + +# total flux from photocurrent + +fl=fl0/alfact/airfact + +f = fl + +msg = ' Energy: ' + '%7.4f' % e + ' keV\n' +msg = msg+ ' Diodecurrent: ' + str(cur).strip() +' mA\n' +msg = msg+ '\n' +msg = msg+ ' Thickness of active Si layer: ' + str(t_si*10000.).strip() + ' micron\n' +msg = msg+ ' Thickness of Al layer in front of diode: ' + str(t_al*10000.).strip() + ' micron\n' +msg = msg+ ' Length of path in air in front of diode: ' + str(t_air).strip() + ' mm\n' +msg = msg+ '\n' +msg = msg+ ' ===> flux: %8.2E photons / s' % f + +print msg +show_message(msg, "flux_diode", False) diff --git a/script/local.py b/script/local.py index 924d426..7c8127e 100644 --- a/script/local.py +++ b/script/local.py @@ -4,6 +4,10 @@ BEAMLINE_XNAME = "X06DA" dtor = math.pi /180.0 + +for d in [pvs, pvc, phs, phc, ths, thc, tvs, tvc, qhs, qhc, qvs, qvc]: + d.setBlockingWrite(True) + def a2e(t,h=1.0,k=1.0,l=1.0, deg =True, ln = False): lncorr= 2.e-4 if ln else 0.0 @@ -24,12 +28,114 @@ def angle(e,h=1.0,k=1.0,l=1.0, deg =True, ln = False,bent = False): return a def get_energy(debug_msg = True): - t2 = caget("X06DA-OP-MO1:ROX2.RBV",'d') + t2 = th2.position e = a2e(abs(t2)) if debug_msg: print 'Energy [keV]:'+ str(e) + ' Wavelength [A]:' + str(12.39842/e) return e - + +def set_energy(e, debug_msg = True): + e = float(e) + if e< 4.7 or e > 18.0: + raise Exception ("please select an energy between 4.7 an 18 keV") + t1e = th1_encoder.read() + t2e = th2_encoder.read() + t1v = th1.read() + t2v = th2.read() + t1s = angle(e,1,1,1,ln=True) + t2s = angle(e,1,1,1) + + # calculate the corrections later, after + # calibration of encoders + dt1 = 0. + dt2 = 0. + + # it is better to move both crystals by the same amount. however, + # if one motor got stuck and the other did not, we should not move + # them by the same amount but each according to its calculated deltha theta + t1p = -t1s + t2p = t2s + + if debug_msg: + print 'set angles th1=' + str(t1p) + " th2=" + str(t2p) + th1.move(t1p) #TODO: simultaneous move? + th2.move(t2p) + th1.waitReady(-1) + th2.waitReady(-1) + if debug_msg: + print 'done set energy' + + +def shopen(): + exp_shutter.write("OPEN") + +def shclose(): + exp_shutter.write("CLOSED") + +def vfoc (dx=0.1): + #scan,'dfy',0,2*dx,25,/fit,det='des',dat=d + motor = cy #TODO: Is right? original was not relative; motor channel was X06DA-ES-DF1:TRY-VAL + sensor = mono_beam #TODO: sensor is not clear since set det to des(X06DA-ES-KBOX:SIG-RAW) but parameter is called 'detector' in scan: is default mono_beam used? + + result = lscan(motor, sensor, -dx, dx, 25, latency = 0.3, relative = True) #TODO: range is 0, 2*dx? + (ydata, xdata) = (result.getReadable(0), result.getPositions(0)) + + from mathutils import deriv, fit_gaussians, Gaussian, get_values + d = [x*1e6 for x in deriv(ydata, xdata)] + gaussians = fit_gaussians(d, xdata , [d.index(max(d)) ,]) + (n, m, s) = gaussians[0] + fitted_gaussian_function = Gaussian(n, m, s) + g = get_values(fitted_gaussian_function,xdata) + plot((ydata, d, g), ("Sensor", "Deriv", "Gauss Fit"), (xdata,xdata,xdata)) + #PLOT,d(0,*),deriv(reform(d(1,*))*1e6) + #oplot,d(0,*),gaussfit(reform(d(0,*)),deriv(reform(d(1,*))*1e6),a,nterm=5),ps=-6 + print 'CENTRE ',m + print 'FWHM microns',s*2354. + motor.move(m) #?motor.move(-dx+a(1)) + #WM,'mb1' #WHAT for? + #WM,'mb2' + return (n, m, s) + +def knife(): + pvc0 = pvc.read() + pvs0 = pvs.read() + try: + step = 0.175 + pvc.write(pvc0 - 3.*step) + pvs.write(0.1) + c = [] + for i in range(5): + pvc.write(pvc0 + step * i) + a = vfoc() + c.apppend(a[1]) + print 'mean',mean(c) + print 'stdev',stdev(c) + finally: + pvc.write(pvc0) + pvs.write(pvs0) + +def knifescan(motor, ll, hl, n=25): + try: + shopen() + time.sleep(1.0) + result = lscan(motor, marcover, ll, hl, n, latency = 0.3, relative = True) + #scan, motor, ll, hl, n,det='marcover',dat=d + (ydata, xdata) = (result.getReadable(0), result.getPositions(0)) + d = deriv(ydata, xdata) + #inversed #IF MOTOR EQ 'dfx' THEN sign = -1. ELSE sign = 1 #TODO + if motor in []: + d = [x*-1.0 for x in d] + gaussians = fit_gaussians(d, xdata , [d.index(max(d)) ,]) + (n, m, s) = gaussians[0] + + #PLOT,D(0,*), SIGN*DERIV(d(1,*)), THICK=2 + #OPLOT, d(0,*), GAUSSFIT(d(0,*),SIGN*DERIV(d(1,*)),a),col=150 + plot((ydata, d, g), ("Sensor", "Deriv", "Gauss Fit"), (xdata,xdata,xdata)) + print 'Centre [scanunits]',m + print 'FWHM [scanunits]',s*2.3542 #sigma to FWHM factor is 2.3542 + finally: + shclose() + run("fit") run("rock") #run("sete") @@ -47,6 +153,21 @@ def rocknroll(): """ run("rocknroll") +def censlits(): + """ + """ + run("censlits") + +def flux_diode(): + """ + """ + run("flux_diode") + +def sete(e, all=True, wavelengt=False): + run("sete", {"e":e, "all":all, "wavelengt":wavelengt}) + +def seteq(e): + runq("seteq", {"e":e}) import ch.psi.pshell.device.ReadonlyRegisterBase as ReadonlyRegisterBase class EnergyReader(ReadonlyRegisterBase): diff --git a/script/rock.py b/script/rock.py index 3ad1bf6..0e2f080 100644 --- a/script/rock.py +++ b/script/rock.py @@ -4,14 +4,14 @@ #from startup import * #Not needed: executed from local -def rock(axis = th1, ffail = False, tt = 0.2, seti0 = False, dx = None, noref = False): +def rock(axis = th1, tt = 0.2, seti0 = False, dx = None, noref = False): """ """ #inject() #Not needed: executed from local if axis is None: axis = th1 if noref == False: - caput('X06DA-OP-MO:MONOBEAM', -1 ) + mono_beam_ref.write(-1.0) e = get_energy() if dx is None: dx = 7.5e-2/e @@ -24,17 +24,11 @@ def rock(axis = th1, ffail = False, tt = 0.2, seti0 = False, dx = None, noref = print time.strftime('%X %x') axis_pos = axis.read() - result = lscan(axis, mono_beam, -dx, dx, 20, latency = 0.3, relative = True, context = None, before_read = None, after_read = None) + result = lscan(axis, mono_beam, -dx, dx, 20, latency = 0.3, relative = True) (ydata, xdata) = (result.getReadable(0), result.getPositions(0)) (norm, mean, sigma) = fit(ydata, xdata) if (mean is not None) and (mean <= (axis_pos + dx)) and (mean >= (axis_pos - dx)): axis.move(mean) - else: - print 'fit failed - centering on maximum' - max_x= xdata[ydata.index(max(ydata))] - axis.move(max_x) - - if not ffail: if seti0: time.sleep(2) run("setI0") @@ -42,7 +36,12 @@ def rock(axis = th1, ffail = False, tt = 0.2, seti0 = False, dx = None, noref = if (noref==False): time.sleep(3) # wait a bit until mono theta finish moving br = mono_beam.read() - caput('X06DA-OP-MO:MONOBEAM', br) + mono_beam_ref.write(br) print 'rock_success new mono beam at ' + str(br) + ' at' + str(e) + ' keV' - + return true + else: + print 'fit failed - centering on maximum' + max_x= xdata[ydata.index(max(ydata))] + axis.move(max_x) + return false \ No newline at end of file diff --git a/script/rocknroll.py b/script/rocknroll.py index 905a11a..dc7a97e 100644 --- a/script/rocknroll.py +++ b/script/rocknroll.py @@ -6,7 +6,7 @@ rock(th1) #check beam position at EBOX and fbm if needed time.sleep(2.0) -by = bpm1.read() +by = es_beam_posv.read() if (abs(by) > 0.005): print by print 'Beam is not aligned at E-BOX BPM: do fbm.' diff --git a/script/sete.py b/script/sete.py index 7f6fd5f..12f8445 100644 --- a/script/sete.py +++ b/script/sete.py @@ -3,16 +3,14 @@ def error(msg): raise Exception (msg) #def sete(e, all=True, wavelengt=False): -e = 0 -all = False -wavelengt = False + beam_err = BEAMLINE_XNAME + '-ES-DAQ:BEAM-ERROR' beam_set = BEAMLINE_XNAME + '-ES-DAQ:BEAM-SET' ring_current_cutoff = 300.0 if wavelength: - e = 12.39842/e + e = 12.39842/e if e < 4.7 or e > 17.5: error('ERROR:Energy out of range: 4.7 to 17.5 keV') @@ -22,34 +20,33 @@ msg = 'Working... (aiming @ '+ str(e) +' keV)' caput(beam_err, (msg[:40]) if len(msg) > 40 else msg) if caget('ALIRF-GUN:CUR-LOWLIM', 'd') < ring_current_cutoff: - error('ERROR:Current is too low: < ' + str(ring_current_cutoff) + 'mA') + error('ERROR:Current is too low: < ' + str(ring_current_cutoff) + 'mA') -if caget('X06DA-FE-AB1:CLOSE_EPS') == 'CLOSE': - error('ERROR:ABSORBER closed; aborting...') - -if caget('X06DA-FE-PH1:OPEN_EPS') != "OPEN": - error('ERROR:FE Shutter closed; aborting...') +if fe_absorber.read()!= 'OPEN': + raise Exception ('FrontEndAbsorber closed') # FrontEnd absorber shutter state +if fe_shutter.read() != "OPEN": + raise Exception ('FrontendShutter closed') e0 = get_energy(False); dE = abs(e-e0) print '... started to move monochromator motors' print '... alignment will take some minutes ' -act = 0 +act = 0 # do a setenergy to move theta 1 and 2 to calculated position in case they are not synchronized. -theta1 = caget('X06DA-OP-MO1:ROX1.RBV', 'd') +theta1 = th1.read() #TODO: setpoint? etheta1 = a2e(abs(theta1),1,1,1,True) -theta2 = caget('X06DA-OP-MO1:ROX2.RBV', 'd') +theta2 = th2.read() etheta2 = a2e(ABS(theta2),1,1,1,True) if abs (etheta1-etheta2) > 0.01: set_energy(e) -while abs(e-e0) > 3e-5/tan(angle(e)): - set_energy(e) - e0 = get_energy(False) +while abs(e-e0) > 3e-5/tan(angle(e, deg=False)): #TODO: deg==false? WHILE ABS(e-e0) GT 3e-5/TAN(ANGLE(e)) DO BEGIN + set_energy(e) + e0 = get_energy(False) @@ -59,16 +56,15 @@ while abs(e-e0) > 3e-5/tan(angle(e)): # -------- for sete, /all, remove all filters if all: - caput('X06DA-ES-FI1:SET',0) - caput('X06DA-ES-FI2:SET',0) - caput('X06DA-ES-FI3:SET',0) - caput('X06DA-ES-FI4:SET',0) + filter1.write("None") + filter2.write("None") + filter3.write("None") + filter4.write("None") time.sleep(0.5) #-------- rock FIRST crystal until its peak is reached ------------- -ff = 1 -while ff: - rock() #TODO: #ROCK,1,dt = (dE>1.)*4e-2/e,ffail=ff +while rock(th1)==False: #TODO: #ROCK,1,dt = (dE>1.)*4e-2/e,ffail=ff + pass # finer final rock time.sleep(1.0) @@ -77,10 +73,9 @@ rock() e0 = get_energy() -caput('X06DA-OP-MO:E-GET',e0) print e0 -print '' -print caget('X06DA-OP-MO:E-GET') +mono_energy.write(e0) +print caget(mono_energy.read()) caput(beam_err, 'Finito') caput(beam_set, 'DONE') diff --git a/script/seteq.py b/script/seteq.py index f908e07..bac7b41 100644 --- a/script/seteq.py +++ b/script/seteq.py @@ -1,2 +1,94 @@ -def seteq(e): - pass \ No newline at end of file +#def seteq(e): + +# this is sete not so quick version. +# mono two rotation stages are not as recise as needed. +# for quick energy change (needed for energy scan), move two thetas with same amount sometime go off the rocking curve. +# possible solutions: +# 1) check flux, if low , rock --> slow +# 2) maxth1 to adjust theta1 +# 3) reduce 'Retry deadband' to 0.0001 (from 0.00004) and 'Retries Max' to 1 (from 5) --> use encoder too much will make things worse. +# what's the flux at beginning +Istart = mono_beam.read() + +if e < 4.6 or e > 17.5: + raise Exception('ERROR:Energy out of range: 4.6 to 17.5 keV') + +if fe_absorber.read()!= 'OPEN': + raise Exception ('FrontEndAbsorber closed') # FrontEnd absorber shutter state + +if fe_shutter.read() != "OPEN": + raise Exception ('FrontendShutter closed') + +if exp_shutter.read() == 'CLOSED': + raise Exception('Experiments hutch shutter closed - program needs beam for alignment') + +e0 = get_energy(False) + + +#X06DA-ES-BPM1:POSV before energy change +eboxbpm0 = es_beam_posv.read() +print 'X06DA-ES-BPM1 vertial feedback to max flux' +print "X06DA-ES-BPM1:POSV BEFORE" + str(eboxbpm0) + +#--------------- setting theta 1, 2 -------------------- + +# adjust 'Retry deadband' to 0.0001 (from 0.00004) and 'Retries Max' to 1 (from 5) +caput(th1.channelName +'.RDBD',0.00001) +caput(th2.channelName +'.RDBD',0.00001) +caput(th1.channelName +'.RTRY',1) +caput(th2.channelName +'.RTRY',1) + +#in order to do a small energy change without rock, +# 1) move theta2 to calculated angle +# 2) move theta1 to exact amount as theta2 moved +# +while abs(e-e0) > (3e-5 / math.tan(angle(e, deg=False)))): #TODO: deg==false? WHILE ABS(e-e0) GT 3e-5/TAN(ANGLE(e)) DO BEGIN + t1v = th1.read() #TODO: setpoint? + t2v = th2.read() + t2s = angle(float(e),1,1,1) + dt2 = t2s-t2v + dt1 = -dt2 + t1p = t1v+dt1 + t2p = t2s # which is t2v+dt2 + print 'set angles th1, th2, relative move dt1, dt2 ', t1p, t2p, dt1, dt2 + th1.move(t1p) + th2.move(t2p) + eo=get_energy(False) + time.sleep(2.0) + Inow = mono_beam.read() + print e, Istart, Inow + + +# feedback at BPM5 +eboxbpm = es_beam_posv.read() +while abs(eboxbpm-eboxbpm0) > 0.002: + if (eboxbpm-eboxbpm0) >0: + th1.moveRel(-0.00004) + else: + th1.moveRel(0.00004) + +time.sleep(1.0) +eboxbpm = es_beam_posv.read() +# if BPM1:POSV is too off, stop it +if eboxbpm > 0.050: + raise Exception("BPM1:POSV is too off") + + +# put 'Retry deadband' to 0.00004 and 'Retries Max' to 5 +# wait a bit until motor movement finished (of course, this won't work if move across large energy range. but who use seteq to do that.) +time.sleep(0.2) +caput(th1.channelName +'.RDBD',0.00004) +caput(th2.channelName +'.RDBD',0.00004) +caput(th1.channelName +'.RTRY',5) +caput(th2.channelName +'.RTRY',5) + +e0 = get_energy() +print e0 +mono_energy.write(e0) +print caget(mono_energy.read()) + + +# release the token! +#free_setetoken + +print 'seteq_done' diff --git a/script/seti0.py b/script/seti0.py index 613cc96..5d8f72f 100644 --- a/script/seti0.py +++ b/script/seti0.py @@ -9,8 +9,9 @@ for i in range(10): """ #TODO -!x06saopbpm3y = MEAN(v) +!x06saopbpm3y = MEAN(v) #dum = NEWCAPUT('X06SA-OP1-MI:BPM_IO',MEAN(S)) + """ print 'Setting I0 to '+ str(mean(s))+' +/- '+str(stdev(s))+' nA' diff --git a/script/test.py b/script/test.py index e1d9e7d..a70aa88 100644 --- a/script/test.py +++ b/script/test.py @@ -1,7 +1,7 @@ show_message("My message", title = "Title", blocking = True) -print get_option("Choose:" , option_type = SwingUtils.OptionType.YesNoCancel) +print get_option("Choose:" , type = "YesNoCancel") print get_string("Enter string:", default = "default")