Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

4 generate lookup tables #14

Draft
wants to merge 26 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .env
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
CLUSTER=k8s-i18
NAMESPACE=i18-beamline
23 changes: 19 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,25 @@ Plans and devices for the DLS beamline i18
This is where you should write a short paragraph that describes what your module does,
how it does it, and why people should use it.

Source | <https://github.com/DiamondLightSource/i18-bluesky>
:---: | :---:
PyPI | `pip install i18-bluesky`
Releases | <https://github.com/DiamondLightSource/i18-bluesky/releases>
table again, t1 theta and d7bdiode
MO table is ok

16 channels Xspress3 detector
-EA-XPS-02:CAM:MaxSizeX_RBV
also ArraySize
also :CONNECTED

pinhole PVs? -AL-APTR-01:TEMP1

diode reading and also DRAIN
diode is ok, there are A and B variants
motors A and B
camera not used

| Source | <https://github.com/DiamondLightSource/i18-bluesky> |
| :------: | :----------------------------------------------------------: |
| PyPI | `pip install i18-bluesky` |
| Releases | <https://github.com/DiamondLightSource/i18-bluesky/releases> |

This is where you should put some images or code snippets that illustrate
some relevant examples. If it is a library then you might put some
Expand Down
54 changes: 54 additions & 0 deletions docs/alignment/idgap.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# idgap alignment

## prerequistes

- must be ran with beam

## explanations

harmonics are an emergent property of the optics physics, found out empirically
harmonics rise monotonically with Z atomic number. Still
`/dls/science/groups/i18/lookuptable/Fe_Co_Ni_Aug24.txt` - so three elements next to one another, all 3 under the same harmonic

XFAS community uses eV for initial energy and inverse angsotmr sfor final energy

energies for each element are stable for 200 years and often scanned with a 10% margin of errror to read more

Mo hightest energy so at the highest harmonic - 19

<https://docs.scipy.org/doc/scipy/reference/constants.html>

usually 1 element has one edge

## physical description

idgap(undulator)- beam -> Monochromator (Bragg angle) - beam -> diode d7 (readout)

## steps

### preparation step

- set diode to `in line diode` mode
- filter A must be adjusted so that the current is below 20 (magic number found decades ago)
- the diode must be configured so that it's giving maximum intensity variance without being oversaturated
- that is done through adjusting the discrete size of a gap between the diode and the beam

### Scannign step

1. scan goes to the first angle/energy - using the previous lookup table
2. mm on x and readig is in microAmps
3. peak fitting, resulting in a 2d relationship of x,y maxxing the z value

### Cleanup stage

- move d7 filter a back into 'gap' mode
- move d7 filter b back into 'gap' mode

## Common issues

sources of issues when running manually:

- saturation
- if the original idgap is so far out of the scan

usually takes 10 minutes, so for 19 harmonics 3 hours?
107 changes: 107 additions & 0 deletions docs/alignment/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
# alignment plan overview

sample stages T1X
T1Y

(for tomography also T1Theta)

two ion chambers

kb motors, two mirrors vertical and horizontal
ecah has 2 motors, bend1, bend2
usually moved simultaneously, but for fine focus separately

get the gaussian shape IT transmission detector we get the shape

first, we lookup table - calibrate the DCM
- measure foil, etc Fe, Mg, then absorption spectrum
then the xanes absorption - then derivative, argmax of the first derivative
https://www.geeksforgeeks.org/python-sympy-derivative-method/
then Bragg offset is adjusted to match the calibrated value

second the idgap lookup tables
- for 10-15 points inside the energy range for this element
we scan the gap fo the insertion devise, looking for the maximum
then quadratic interpolation, written into the file,
then GDA probably some interpolation
TFG calculates frequency from current via voltage
so we need to load the panda configuration

align the pinhole to reduce the scatter -
400 micron or 200 micron, then centralize it
usuallly not seen immediately
FocusingMirror misses curvature
preparation for the wire stage - check if we have any
gold wires on the sample stage - scanned in one direction
first horizonal, vertical
then record with IT the absorption profile, derviative and fitting
then changing the bend
could be 10 iterations, in either direction
to minimuze the beam size until it changes
to see the beam shape and the size
takes usually 30 minutes to go through focusing manually, 2-3 hours

visual comparison fo the drviative -
best if without the tails, could be parametrized
or 50 micron beam - and then defocus to get to that

golden plate with wires is moved by some other location

## Alignment types

There are three major types of alignment:

- idgap
- pinhole
- wire scan

Other alignment (non exhaustive):

- KB mirror optimization (?)

Only the idgap one caches the results in a lookup table.

### IDGAP alignment details

moving the monochromator to a given Bragg angle, keeping it fixed and then scanning the undulator gap across a small range.

On the d7 diode the Bragg with a peak is that gap

2d scan of Bragg angle vs undulator gap, and peak compared to d7

### pinhole

## from the files

first, we lookup table - calibratre the DCM -
measure foil, etc Fe, Mg, then absorption spectrum
then the xanes absorption - then derivative, argmax of the first derivative
https://www.geeksforgeeks.org/python-sympy-derivative-method/
then Bragg offset is adjusted to match the calibrated value

second the idgap lookup tables -
for 10-15 points inside the energy range for this element
we scan the gap fo the insertion devise, looking for the maximum
then quadratic interpolation
written into the file, then GDA probably some interpolation
TFG calculates frequency from current via voltage
so we need to load the panda configuration

align the pinhole to reduce the scatter

- 400 micron or 200 micron, then centralize it
usuallly not seen immediately
FocusingMirror misses curvature
preparation for the wire stage - check if we have any
gold wires on the sample stage - scanned in one direction
first horizonal, vertical
then record with IT the absorption profile, derviative and fitting
then changing the bend
could be 10 iterations, in either direction
to minimuze the beam size until it changes
to see the beam shape and the size
takes usually 30 minutes to go through focusing manually, 2-3 hours

visual comparison fo the derivative- best if without the tails,
could be parametrized
or 50 micron beam - and then defocus to get to that
11 changes: 11 additions & 0 deletions helm/charts/redis-service.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
apiVersion: v1
kind: Service
metadata:
name: redis-service
spec:
selector:
app: redis
ports:
- protocol: TCP
port: 6379
targetPort: 6379
164 changes: 164 additions & 0 deletions old_scripts/Create_deg_Lookuptabledcm.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
from gda.analysis.numerical.optimization.objectivefunction import AbstractObjectiveFunction
from gda.analysis.numerical.linefunction import AbstractCompositeFunction
from gda.analysis.numerical.linefunction import CompositeFunction
from gda.analysis.numerical.linefunction import Gaussian1D
from gda.analysis.numerical.linefunction import BGAsymmetricGaussian1D
from gda.analysis.numerical.linefunction import BGGaussian1D
from gda.analysis.numerical.linefunction import AsymmetricGaussian1D
from gda.analysis.numerical.linefunction import Polynomial
from gda.analysis.numerical.linefunction import Parameter
from gda.analysis.numerical.differentiation import Differentiate
from gda.analysis.numerical.optimization.objectivefunction import chisquared
from gda.analysis.numerical.optimization.optimizers.leastsquares import minpackOptimizer
from gda.analysis.numerical.optimization.optimizers.simplex import NelderMeadOptimizer
from gda.analysis.datastructure import DataVector
from time import sleep
#
# A simple method for performing the gap scan
#
def scangap(start_gap,stop_gap,step_gap):
npoints=int((stop_gap-start_gap)/step_gap)
currentgap=start_gap
xdata = DataVector([npoints])
ydata = DataVector([npoints])
for i in range(npoints):
pos sc_idgap currentgap
xdata[i] = currentgap
ydata[i] = d7bdiode.getPosition()
#ydata[i] = multict.getPosition()[0]
print 'i gap',i,('%.3f' %xdata[i]),('%.5f' %ydata[i])
#print 'i gap',i,('%.3f' %currentgap),('%.3f' %multict.getPosition()[0])
currentgap=currentgap+step_gap
return xdata, ydata

#
#
# Fit the data from the gap scan with a gaussian and return
# the peak position
#
#
def fitdata(xdata,ydata):
# Find the min and max of the data set
maxcount=0
mincount=0
maxval=ydata[0]
minval= 10000000000000.0
ysize=len(ydata)
for i in range(ysize):
if(ydata[i]>maxval):
maxval=ydata[i]
maxcount=i
if(ydata[i]<minval):
minval=ydata[i]
mincount=i
for i in range(ysize):
ydata[i]=ydata[i]-minval
for i in range(ysize):
ydata[i]=ydata[i]/maxval

gauss = BGGaussian1D([ydata[maxcount]/100.0,xdata[maxcount],0.005,minval])
#gauss=BGAsymmetricGaussian1D([ydata[maxcount]/100.0,xdata[maxcount],0.005,0.005,minval])
gauss.getParameter("area").setLowerLimit(1.0E-5)
gauss.getParameter("area").setUpperLimit(0.1)
gauss.getParameter("position").setLowerLimit(xdata[0])
gauss.getParameter("position").setUpperLimit(xdata[ysize-1])
gauss.getParameter("sigma").setLowerLimit(0.0005)
gauss.getParameter("sigma").setUpperLimit(0.05)

#gauss.getParameter("sigma1").setLowerLimit(0.0005)
#gauss.getParameter("sigma1").setUpperLimit(0.05)
#gauss.getParameter("sigma2").setLowerLimit(0.0005)
#gauss.getParameter("sigma2").setUpperLimit(0.05)
gauss.getParameter("background").setLowerLimit(1.0E-12)
gauss.getParameter("background").setUpperLimit(0.1)
myfunction = CompositeFunction()
myfunction.addFunction("Gaussian", gauss)
chifunc = chisquared(myfunction,[xdata,ydata])
minpack = minpackOptimizer(chifunc)
minpack.setMaxNoOfEvaluations(150000)
minpack.reset()
minpack.optimize()
bestValues=minpack.getBest()
print 'maxcount',xdata[maxcount]
print 'best values',bestValues,minpack.getMinimum()
return bestValues,xdata[maxcount]

#
# Script to regenerate a lookup table for a given harmonic
#
#angleStart=10439
#angleStart=55400
angleStart=70400
angleStop=54000
angleStep=-1000
gaprange=0.030
gapstep=0.003
offset=0.0



#
# The code uses comboDCM, i.e. the current lookup table to get a starting point for the scans
#
converter = finder.find("auto_mDeg_idGap_mm_converter_Si111")

converter.enableAutoConversion()

pos sc_comboDCM_d_Si111 angleStart/1000.0
#pos comboDCM_eV 7200

#converter = finder.find("auto_mDeg_idGap_mm_converter")

converter.disableAutoConversion()

lookup = finder.find("lookup_name_provider_Si111")
print 'Harmonic set to ',lookup.getConverterName()

#
# Selection mode
# 0 fit the curve with a gaussian and pick the centre
# 1 use the peak position
selectionMode=1

new_harmonic_file='/dls/science/groups/i18/lookuptables/P_Jul24.txt'
#new_harmonic_file='/dls/science/groups/i18/lookuptables/S_K_May24.txt'
#new_harmonic_file='/dls/science/groups/i18/lookuptables/Ni_K_May24.txt'
#new_harmonic_file='/dls/science/groups/i18/lookuptables/Ir_L3_Jan24.txt'


fod=open(new_harmonic_file,"w")
print >>fod,"Bragg\tGap"
#
# Will update
#
#pos comboDCM angleStart
#current_gap=idgap.getPosition()
for j in range(angleStart,angleStop,angleStep):
#convert to degrees
i = j / 1000.0

# Move to position
pos sc_comboDCM_d_Si111 i
sleep(2)
current_gap=sc_idgap.getPosition()+offset
# Scan gap
myxdata,myydata=scangap(current_gap-gaprange,current_gap+gaprange,gapstep)
result,bestx=fitdata(myxdata,myydata)
# Write to new file
if(selectionMode==0):
myline="%.3f\t%.5f" %(i,result[1])
else:
myline="%.3f\t%.5f" %(i,bestx)
print >>fod,myline
#print >>fod,i,"\t",result[1]
fod.close()

converter.enableAutoConversion()
print 'Done'







Loading
Loading