diff --git a/script/anuschka/makeref.py b/script/anuschka/makeref.py new file mode 100644 index 0000000..3324384 --- /dev/null +++ b/script/anuschka/makeref.py @@ -0,0 +1,4 @@ +print caget("X06DA-OP-BPM1:SUM") + + +print mono_beam.read() 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..7eb0b5f --- /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/diode_scan.py b/script/diode_scan.py new file mode 100644 index 0000000..b1ae215 --- /dev/null +++ b/script/diode_scan.py @@ -0,0 +1,6 @@ +""" +Diode scan +""" + asd +#Execute the scan: 200 steps, a1 from 0 to 40 +a= lscan(ao1, (diode,current), 0, 40, 200, 0.01) diff --git a/script/fbm.py b/script/fbm.py new file mode 100644 index 0000000..ff62a39 --- /dev/null +++ b/script/fbm.py @@ -0,0 +1,77 @@ +################################################################################################### +# +################################################################################################### + + +#tc1 = caget('X06DA-OP-MO:TC1') # theta1 thermo couple 1 +energy = get_energy() # Mono energy +dtz = detector_z.read() + +if current.read() < 200: + raise Exception ('Ring current too low') + +if fe_absorber.read()!= 'OPEN': + raise Exception ('FrontEndAbsorber closed') # FrontEnd absorber shutter state + +if fe_shutter.read() != 'OPEN': + raise Exception ('FrontendShutter closed') + +if eh_shutter.read() != 'OPEN': # ExpHutch shutter state + raise Exception ('ExpHutchShutter closed ') + +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 = es_beam.read() +op1 = caget('X06DA-OP-XPM1:CHAN1', 'd') + +if op1 < 1.0: + 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 +dmx = 14.0 # 2 x distance mirror HR-XBPM +ymax = 2e-3 # endwhile criterion for vertical correction + + +if cur < tc: #check if beam is on CVD-XBPM + sete_failed = 1 + raise Exception ('evere problem - NO BEAM ON HR-DIFFRACTOMETER XBPM') + +# initial mirror TRY3 position +y3i = try3.read() +print "initial y3i: " + str(y3i) + +# how much beam is off? +by = es_beam_posv.read() +print "EBOX-POSV before rock: " + str(by) +# if beam is not off, do nothing +if abs(by) > ymax: + rock(th1) + +# result of ROCK +time.sleep(2.0) +by = es_beam_posv.read() +print "EBOX-POSV after rock: " + str(by) + +# feedback +while abs(by) >= ymax : + by = es_beam_posv.read() + print "current EBOX-POSV: " + str(by) + cur = es_beam.read() + if cur > tc: + if (eh_shutter.read() == 'OPEN') and (abs(by) > ymax): + if abs(by) > (50*ymax): + raise Exception ('TODO') + #limit mirror TRY3 movement + y3 = try3.read() + if abs(y3i - y3 - 1e-4 * round(by/1e-3)) > 0.008: + raise Exception ('Feedback trying to move mirror Y3 beyond safe limit') + try3.moveRel(-1e-4 * round(by/1e-3)) + print "current X06DA-OP-MI1:TRY3: ", y3 + time.sleep(0.25) + + +print "TRY3 net movement: " + str(y3i-try3.read()) #print how much TRY3 moved + diff --git a/script/fit.py b/script/fit.py new file mode 100644 index 0000000..8748bfa --- /dev/null +++ b/script/fit.py @@ -0,0 +1,55 @@ +from mathutils import estimate_peak_indexes, fit_gaussians, create_fit_point_list, Gaussian +import java.awt.Color as Color + +import mathutils +mathutils.MAX_ITERATIONS = 100000 + +def fit(ydata, xdata = None, draw_plot = True): + if xdata is None: + xdata = frange(0, len(ydata), 1) + max_y= max(ydata) + index_max = ydata.index(max_y) + max_x= xdata[index_max] + print "Max index:" + str(index_max), + print " x:" + str(max_x), + print " y:" + str(max_y) + + if draw_plot: + plots = plot([ydata],["data"],[xdata], title="Fit" ) + p = None if plots is None else plots[0] + + gaussians = fit_gaussians(ydata, xdata, [index_max,]) + if gaussians[0] is None: + if draw_plot and (p is not None): + p.addMarker(max_x, None, "Max="+str(round(max_x,4)), Color.GRAY) + print "Fitting error" + return (None, None, None) + + (norm, mean, sigma) = gaussians[0] + if draw_plot: + 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)) + #Server + if p is None: + plot([ydata,fit_y],["data","fit"],[xdata,fit_x], title="Fit") + draw_plot = False + else: + 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 draw_plot: + p.addMarker(mean, None, "Mean="+str(round(mean,4)), Color.MAGENTA.darker()) + print "Mean -> " + str(mean) + return (norm, mean, sigma) + else: + 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 9dc8b0d..cb4fff2 100644 --- a/script/local.py +++ b/script/local.py @@ -1,4 +1,184 @@ -################################################################################################### -# Deployment specific global definitions - executed after startup.py -################################################################################################### +################################################################################################### +# Deployment specific global definitions - executed after startup.py +################################################################################################### + 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 + d0=2 * 5.43102 * (1.0-lncorr) / math.sqrt(h**2+k**2+l**2) + tt= (t * dtor) if (deg or (t>1.0)) else t + return 12.39842 / (d0*math.sin(tt)) + +def angle(e,h=1.0,k=1.0,l=1.0, deg =True, ln = False,bent = False): + lncorr = 2.e-4 if ln else 0.0 + d0 =2 * 5.43102 * (1.0-lncorr) / math.sqrt(h**2+k**2+l**2) + a = math.asin(12.39842/d0/e) + if bent: + rho = 2*19.65*8.35/28*math.sin(a) + dt = 0.2e-3/rho*0.279 + d0 = 2*5.43102*(1+dt)/math.sqrt(h**2+k**2+l**2) + a = math.asin(12.39842/d0/e) + a = a/dtor if deg else a + return a + +def get_energy(debug_msg = True): + 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") +#run("seteq") + + + +def fbm(): + """ + """ + run("fbm") + +def rocknroll(): + """ + """ + run("rocknroll") + +def censlits(): + """ + """ + run("censlits") + +def flux_diode(): + """ + """ + run("flux_diode") + +def sete(e, all=True, wavelength=False): + run("sete", {"e":e, "all":all, "wavelength":wavelength}) + +def seteq(e): + run("seteq", {"e":e}) + + +def check_rock(): + run("check_rock") + + +import ch.psi.pshell.device.ReadonlyRegisterBase as ReadonlyRegisterBase +class EnergyReader(ReadonlyRegisterBase): + def doRead(self): + return get_energy(False) + +add_device(EnergyReader("energy",3), True) + +energy.polling = 1000 \ No newline at end of file diff --git a/script/rock.py b/script/rock.py new file mode 100644 index 0000000..59084a2 --- /dev/null +++ b/script/rock.py @@ -0,0 +1,47 @@ +################################################################################################### +# +################################################################################################### + +#from startup import * #Not needed: executed from local + +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: + mono_beam_ref.write(-1.0) + e = get_energy() + if dx is None: + dx = 7.5e-2/e + + # put 'Retry deadband' to 0.00004 and 'Retries Max' to 5 + time.sleep(0.2) + + caput(axis.channelName + '.RDBD',0.00004) + caput(axis.channelName + '.RTRY',5) + + print time.strftime('%X %x') + axis_pos = axis.read() + 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) + if seti0: + time.sleep(2) + run("setI0") + #add after_rock BPM1:SUM as reference for monitoring monochromator thermal drift + if (noref==False): + time.sleep(3) # wait a bit until mono theta finish moving + br = mono_beam.read() + mono_beam_ref.write(br) + print 'rock_success new mono beam at ' + str(br) + ' at ' + str(e) + ' keV' + return True + else: + max_x= xdata[ydata.index(max(ydata))] + print 'fit failed - centering on maximum: ' + str(max_x) + axis.move(max_x) + return False + \ No newline at end of file diff --git a/script/rocknroll.py b/script/rocknroll.py new file mode 100644 index 0000000..dc7a97e --- /dev/null +++ b/script/rocknroll.py @@ -0,0 +1,14 @@ +ei = get_energy() +if ei < 6.0: + print "No rocking optimization for lower energy for 3rd harmonics rejection' +rock(th1) + +#check beam position at EBOX and fbm if needed +time.sleep(2.0) + +by = es_beam_posv.read() +if (abs(by) > 0.005): + print by + print 'Beam is not aligned at E-BOX BPM: do fbm.' + run("fbm") + diff --git a/script/sete.py b/script/sete.py new file mode 100644 index 0000000..597b3ff --- /dev/null +++ b/script/sete.py @@ -0,0 +1,83 @@ +def error(msg): + caput(beam_err, (msg[:40]) if len(msg) > 40 else msg) + raise Exception (msg) + +#def sete(e, all=True, 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 +if e < 4.7 or e > 17.5: + error('ERROR:Energy out of range: 4.7 to 17.5 keV') + +print time.strftime('%X %x') +print '... Setting energy to '+ str(e) +' keV.' +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') + +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 + +# do a setenergy to move theta 1 and 2 to calculated position in case they are not synchronized. +theta1 = th1.read() #TODO: setpoint? +etheta1 = a2e(abs(theta1),1,1,1,deg=True,ln=True) +theta2 = th2.read() +etheta2 = a2e(abs(theta2),1,1,1,deg=True,ln=False) +if abs (etheta1-etheta2) > 0.01: + set_energy(e) + + +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 + set_energy(e) + e0 = get_energy(False) + + + +#----- correcting theta2 if intensity is low or if the encoder ----- +#----- differs by more than rocking curve width from theory -------- + + +# -------- for sete, /all, remove all filters +if all: + filter1.write("None") + filter2.write("None") + filter3.write("None") + filter4.write("None") + time.sleep(0.5) + +#-------- rock FIRST crystal until its peak is reached ------------- +while rock(th1)==False: #TODO: #ROCK,1,dt = (dE>1.)*4e-2/e,ffail=ff + pass + +# finer final rock +time.sleep(1.0) +print 'FINER FINAL ROCK' +rock() + + +e0 = get_energy() +print e0 +mono_energy.write(e0) +print mono_energy.read() + +caput(beam_err, 'Finito') +caput(beam_set, 'DONE') + +print 'sete_done' \ No newline at end of file diff --git a/script/seteq.py b/script/seteq.py new file mode 100644 index 0000000..44ed6c7 --- /dev/null +++ b/script/seteq.py @@ -0,0 +1,95 @@ +#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) +try: + 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)))): + t1v = th1.read() #TODO: setpoint? + t2v = th2.read() + t2s = angle(float(e),1,1,1, deg=True) + 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) + e0=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) + +finally: + 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 mono_energy.read() + + +# release the token! +#free_setetoken + +print 'seteq_done' diff --git a/script/seti0.py b/script/seti0.py new file mode 100644 index 0000000..5d8f72f --- /dev/null +++ b/script/seti0.py @@ -0,0 +1,19 @@ +s = [] +v = [] +t = [] +for i in range(10): + s.append(caget('X06SA-OP-BPM3:SUM')) + v.append(caget ('X06SA-OP-BPM3:POSV')) + t.append(caget('X06SA-OP-MO:TC3')) + time.sleep(0.09) + +""" +#TODO +!x06saopbpm3y = MEAN(v) +#dum = NEWCAPUT('X06SA-OP1-MI:BPM_IO',MEAN(S)) + +""" + +print 'Setting I0 to '+ str(mean(s))+' +/- '+str(stdev(s))+' nA' +print 'Setting BPM3_Y to'+ str(mean(v))+' +/- '+str(stdev(v))+' mm' +print 'Setting TC3 to '+ str(mean(t))+' +/- '+str(stdev(t))+' mm' \ No newline at end of file diff --git a/script/test/test.py b/script/test/test.py new file mode 100644 index 0000000..a70aa88 --- /dev/null +++ b/script/test/test.py @@ -0,0 +1,12 @@ + +show_message("My message", title = "Title", blocking = True) + +print get_option("Choose:" , type = "YesNoCancel") + +print get_string("Enter string:", default = "default") + +print get_string("Choose string:", default = "default", alternatives = ["default", "alt1", "alt2"]) + +print get_string("Enter password:", password = True) + + \ No newline at end of file