This commit is contained in:
@@ -55,8 +55,8 @@ aerotech:
|
||||
deviceConfig:
|
||||
prefix: http://mx-x10sa-queue-01:5234
|
||||
deviceTags:
|
||||
- aerotech
|
||||
- motors
|
||||
- aerotech
|
||||
enabled: true
|
||||
onFailure: buffer
|
||||
readoutPriority: baseline
|
||||
@@ -64,14 +64,13 @@ aerotech:
|
||||
u:
|
||||
mount: 0
|
||||
work: 0
|
||||
work: null
|
||||
x:
|
||||
in: 0
|
||||
out: -10
|
||||
safe: -50
|
||||
y:
|
||||
mount: -0.0
|
||||
work: -0.16
|
||||
work: -0.0
|
||||
z:
|
||||
mount: 0
|
||||
work: 0
|
||||
@@ -292,7 +291,7 @@ bs_x:
|
||||
onFailure: buffer
|
||||
readoutPriority: baseline
|
||||
userParameter:
|
||||
in: 1.9
|
||||
in: 0.2
|
||||
bs_y:
|
||||
description: Beamstop Y
|
||||
deviceClass: ophyd_devices.EpicsMotor
|
||||
@@ -304,7 +303,7 @@ bs_y:
|
||||
onFailure: buffer
|
||||
readoutPriority: baseline
|
||||
userParameter:
|
||||
in: -0.6
|
||||
in: -3.154
|
||||
bs_z:
|
||||
description: Beamstop Z
|
||||
deviceClass: ophyd_devices.EpicsMotor
|
||||
@@ -320,7 +319,7 @@ bs_z:
|
||||
max_blout: 70
|
||||
min: 13
|
||||
safe: 45.1
|
||||
samp: 15.3
|
||||
samp: 16.408
|
||||
type: continuous
|
||||
work_min: 20
|
||||
bsf_f1_y:
|
||||
@@ -433,6 +432,8 @@ coll_x:
|
||||
enabled: true
|
||||
onFailure: buffer
|
||||
readoutPriority: baseline
|
||||
userParameter:
|
||||
in: -3.080
|
||||
coll_y:
|
||||
description: Collimator Y
|
||||
deviceClass: ophyd_devices.EpicsMotor
|
||||
@@ -444,7 +445,7 @@ coll_y:
|
||||
onFailure: buffer
|
||||
readoutPriority: baseline
|
||||
userParameter:
|
||||
in: 39.393
|
||||
in: 39.16
|
||||
intermediate: 32
|
||||
out: 20.002
|
||||
park: 1
|
||||
@@ -602,6 +603,9 @@ det_y:
|
||||
enabled: true
|
||||
onFailure: buffer
|
||||
readoutPriority: baseline
|
||||
userParameter:
|
||||
work: 70
|
||||
xi: 214
|
||||
det_z:
|
||||
description: Detector Z
|
||||
deviceClass: ophyd_devices.EpicsMotor
|
||||
@@ -614,7 +618,7 @@ det_z:
|
||||
readoutPriority: baseline
|
||||
userParameter:
|
||||
mse: 800
|
||||
vis: 1198
|
||||
vis: 800
|
||||
diag_y:
|
||||
description: Scintillator/diode Y
|
||||
deviceClass: ophyd_devices.EpicsMotor
|
||||
@@ -1206,6 +1210,26 @@ mag_ref:
|
||||
onFailure: buffer
|
||||
readOnly: true
|
||||
readoutPriority: baseline
|
||||
microscope_stats:
|
||||
description: Stats Signal of MS camera
|
||||
deviceClass: pxii_bec.devices.stats_signal.StatsSignal
|
||||
deviceConfig:
|
||||
prefix: 'X10SA-ES-MS:'
|
||||
enabled: true
|
||||
readoutPriority: async
|
||||
softwareTrigger: true
|
||||
samcam_ecc:
|
||||
description: Sample Camera Eccentricity
|
||||
deviceClass: ophyd.EpicsSignalRO
|
||||
deviceConfig:
|
||||
auto_monitor: true
|
||||
read_pv: X10SA-ES-MS:Stats5:Eccentricity_RBV
|
||||
deviceTags:
|
||||
- scam
|
||||
enabled: true
|
||||
onFailure: buffer
|
||||
readOnly: true
|
||||
readoutPriority: monitored
|
||||
samcam_exp:
|
||||
description: Sample Camera Exposure
|
||||
deviceClass: ophyd.EpicsSignal
|
||||
@@ -1240,6 +1264,30 @@ samcam_max:
|
||||
onFailure: buffer
|
||||
readOnly: true
|
||||
readoutPriority: monitored
|
||||
samcam_mean:
|
||||
description: Sample Camera Mean
|
||||
deviceClass: ophyd.EpicsSignalRO
|
||||
deviceConfig:
|
||||
auto_monitor: true
|
||||
read_pv: X10SA-ES-MS:Stats1:MeanValue_RBV
|
||||
deviceTags:
|
||||
- scam
|
||||
enabled: true
|
||||
onFailure: buffer
|
||||
readOnly: true
|
||||
readoutPriority: monitored
|
||||
samcam_sigma:
|
||||
description: Sample Camera Sigma
|
||||
deviceClass: ophyd.EpicsSignalRO
|
||||
deviceConfig:
|
||||
auto_monitor: true
|
||||
read_pv: X10SA-ES-MS:Stats1:Sigma_RBV
|
||||
deviceTags:
|
||||
- scam
|
||||
enabled: true
|
||||
onFailure: buffer
|
||||
readOnly: true
|
||||
readoutPriority: monitored
|
||||
samcam_x:
|
||||
description: Sample Camera X
|
||||
deviceClass: ophyd.EpicsSignalRO
|
||||
@@ -1288,18 +1336,6 @@ samcam_ysig:
|
||||
onFailure: buffer
|
||||
readOnly: true
|
||||
readoutPriority: monitored
|
||||
samcam_ecc:
|
||||
description: Sample Camera Eccentricity
|
||||
deviceClass: ophyd.EpicsSignalRO
|
||||
deviceConfig:
|
||||
auto_monitor: true
|
||||
read_pv: X10SA-ES-MS:Stats5:Eccentricity_RBV
|
||||
deviceTags:
|
||||
- scam
|
||||
enabled: true
|
||||
onFailure: buffer
|
||||
readOnly: true
|
||||
readoutPriority: monitored
|
||||
scam_zoom:
|
||||
description: Sample Camera Zoom
|
||||
deviceClass: ophyd_devices.EpicsMotor
|
||||
@@ -1328,8 +1364,8 @@ smargon:
|
||||
deviceConfig:
|
||||
prefix: http://x10sa-smargopolo.psi.ch:3000
|
||||
deviceTags:
|
||||
- smargon
|
||||
- motors
|
||||
- smargon
|
||||
enabled: true
|
||||
onFailure: buffer
|
||||
readoutPriority: baseline
|
||||
@@ -1424,6 +1460,18 @@ ss_bpmsum:
|
||||
onFailure: buffer
|
||||
readOnly: true
|
||||
readoutPriority: monitored
|
||||
transm:
|
||||
description: Beam Transmission
|
||||
deviceClass: ophyd_devices.EpicsSignal
|
||||
deviceConfig:
|
||||
read_pv: 'X10SA-ES-SSFI:TRANSM-SET'
|
||||
write_pv: 'X10SA-ES-SSFI:TRANSM-SET'
|
||||
deviceTags:
|
||||
- transm
|
||||
enabled: true
|
||||
onFailure: retry
|
||||
readOnly: false
|
||||
readoutPriority: baseline
|
||||
ss_f1_x:
|
||||
description: SS Filter 1 X
|
||||
deviceClass: ophyd_devices.EpicsMotor
|
||||
|
||||
@@ -1,5 +1,17 @@
|
||||
base_config:
|
||||
- !include ./pxii-devices.yaml
|
||||
|
||||
microscope_stats:
|
||||
readoutPriority: async
|
||||
description: Stats Signal of MS camera
|
||||
deviceClass: pxii_bec.devices.stats_signal.StatsSignal
|
||||
deviceConfig:
|
||||
prefix: 'X10SA-ES-MS:'
|
||||
onFailure: retry
|
||||
enabled: true
|
||||
readOnly: false
|
||||
softwareTrigger: true
|
||||
|
||||
# sample_env:
|
||||
# - !include ./pxii-state-devices.yaml
|
||||
# id_gap:
|
||||
|
||||
@@ -1,14 +1,18 @@
|
||||
from ophyd_devices import AsyncMultiSignal
|
||||
|
||||
from ophyd_devices.interfaces.base_classes.psi_device_base import PSIDeviceBase
|
||||
from ophyd import Component as Cpt
|
||||
from ophyd import EpicsSignalRO, Kind
|
||||
import time
|
||||
from collections import defaultdict
|
||||
from threading import RLock
|
||||
import time
|
||||
|
||||
import numpy as np
|
||||
from bec_lib.logger import bec_logger
|
||||
from ophyd import Component as Cpt
|
||||
from ophyd import EpicsSignalRO, Kind, Signal
|
||||
from ophyd_devices import AsyncMultiSignal, StatusBase, TransitionStatus
|
||||
from ophyd_devices.interfaces.base_classes.psi_device_base import PSIDeviceBase
|
||||
|
||||
logger = bec_logger.logger
|
||||
|
||||
|
||||
class StatsSignal(PSIDeviceBase, AsyncMultiSignal):
|
||||
class StatsSignal(PSIDeviceBase):
|
||||
|
||||
data = Cpt(
|
||||
AsyncMultiSignal,
|
||||
@@ -27,7 +31,7 @@ class StatsSignal(PSIDeviceBase, AsyncMultiSignal):
|
||||
|
||||
def on_init(self):
|
||||
self._rlock = RLock()
|
||||
self._cached_average_data = defaultdict(float)
|
||||
self._cached_average_data = defaultdict(list)
|
||||
|
||||
def on_connected(self):
|
||||
self._cached_average_data.clear()
|
||||
@@ -37,26 +41,44 @@ class StatsSignal(PSIDeviceBase, AsyncMultiSignal):
|
||||
def _update_average_data(self, value, obj, **kwargs):
|
||||
if value is None:
|
||||
return
|
||||
if self.scan_info.msg is None:
|
||||
return
|
||||
if self.scan_info.msg.status != "open":
|
||||
return
|
||||
|
||||
sig_name = obj.name
|
||||
logger.info(f"Received update from signal {sig_name} with value{ value}")
|
||||
|
||||
with self._rlock:
|
||||
self._cached_average_data[sig_name] += value
|
||||
self._cached_average_data[sig_name].append(value)
|
||||
|
||||
def on_trigger(self):
|
||||
with self._rlock:
|
||||
self._cached_average_data.clear()
|
||||
time.sleep(
|
||||
self.scan_info.msg.scan_parameters.get("exp_time")
|
||||
) # Wait for the exposure time to finish
|
||||
status = StatusBase(obj=self) # TransitionStatus(self.acquiring, transitions=[1, 0])
|
||||
status.add_callback(self._publish_data)
|
||||
time.sleep(self.scan_info.msg.scan_parameters.get("exp_time", 0))
|
||||
status.set_finished()
|
||||
return status
|
||||
|
||||
with self._rlock:
|
||||
sigma_x = self._cached_average_data.get("sigma_x_raw", 0.0)
|
||||
sigma_y = self._cached_average_data.get("sigma_y_raw", 0.0)
|
||||
eccentricity = self._cached_average_data.get("eccentricity_raw", 0.0)
|
||||
def _publish_data(self, status, **kwargs):
|
||||
if status.done:
|
||||
with self._rlock:
|
||||
|
||||
ret = {
|
||||
"sigma_x": {"value": sigma_x},
|
||||
"sigma_y": {"value": sigma_y},
|
||||
"eccentricity": {"value": eccentricity},
|
||||
}
|
||||
self.data.put(ret)
|
||||
sigma_x = float(
|
||||
np.average(self._cached_average_data.get(self.sigma_x_raw.name, [0]))
|
||||
)
|
||||
sigma_y = float(
|
||||
np.average(self._cached_average_data.get(self.sigma_y_raw.name, [0]))
|
||||
)
|
||||
eccentricity = float(
|
||||
np.average(self._cached_average_data.get(self.eccentricity_raw.name, [0]))
|
||||
)
|
||||
|
||||
ret = {
|
||||
"sigma_x": {"value": sigma_x},
|
||||
"sigma_y": {"value": sigma_y},
|
||||
"eccentricity": {"value": eccentricity},
|
||||
}
|
||||
logger.info(f"Setting data for {self.name} data signal to {ret}.")
|
||||
self.data.put(ret)
|
||||
|
||||
@@ -313,9 +313,10 @@ def justfit(data_x, data_y, model="gauss", ibg=0):
|
||||
# diagnostics
|
||||
# print(f'Gfit: {g.params}')
|
||||
|
||||
print(f'Center of {model} fit: {g.pars["center"].value:.5f}')
|
||||
print(f'Sigma: {g.pars["sigma"].value:.5f}')
|
||||
print(f'FWHM: {g.pars["fwhm"].value:.5f}')
|
||||
#print(f'Center of {model} fit: {g.pars["center"].value:.5f}')
|
||||
#print(f'Sigma: {g.pars["sigma"].value:.5f}')
|
||||
#print(f'FWHM: {g.pars["fwhm"].value:.5f}')
|
||||
print(g.fit_report())
|
||||
print(f"Position of maximum: {xm}")
|
||||
|
||||
return g, xm
|
||||
@@ -338,13 +339,21 @@ def fit_plothist(hindex: int, signal_name: str, model="gauss", ibg=0):
|
||||
from lmfit.models import LinearModel, GaussianModel, VoigtModel, QuadraticModel, LorentzianModel
|
||||
import matplotlib.pyplot as plt
|
||||
|
||||
h = bec.history[hindex]
|
||||
if hindex < 0:
|
||||
h = bec.history[hindex]
|
||||
print('by scan number')
|
||||
else:
|
||||
h = bec.history.get_by_scan_number(hindex)
|
||||
print('by scan number')
|
||||
md = h.metadata["bec"]
|
||||
scanvar = list(md["args"].keys())[0] # string, returns the variable of the last performed scan
|
||||
# data = h.devices[device_name][signal].read()["value"]
|
||||
# data_x = h.devices.dcm_pitch.dcm_pitch.read()["value"]
|
||||
# data_y = h.devices.lu_bpmsum.lu_bpmsum.read()["value"]
|
||||
# data_x = h.devices[device_name][device_name].read()["value"]
|
||||
|
||||
## that should work in any case:
|
||||
device_name = scanvar
|
||||
#data_x = h.devices[device_name][device_name].read()["value"]
|
||||
|
||||
data_xd = md["positions"] # last scan knows which device ... however, double array
|
||||
data_x = data_xd.flatten()
|
||||
@@ -352,6 +361,10 @@ def fit_plothist(hindex: int, signal_name: str, model="gauss", ibg=0):
|
||||
data_y = h.devices[signal_name][signal_name].read()["value"]
|
||||
print("dy = ", data_y)
|
||||
|
||||
prefix='v_'
|
||||
if model == 'gauss':
|
||||
prefix='g_'
|
||||
|
||||
g, xm = justfit(data_x, data_y, model=model, ibg=ibg)
|
||||
|
||||
plt.ion()
|
||||
@@ -362,7 +375,9 @@ def fit_plothist(hindex: int, signal_name: str, model="gauss", ibg=0):
|
||||
plt.ylabel(signal_name)
|
||||
plt.show()
|
||||
|
||||
gcen = g.pars["center"].value
|
||||
# g.params
|
||||
returncenvar = prefix+"center"
|
||||
gcen = g.params[returncenvar].value
|
||||
|
||||
return gcen, xm, data_x, data_y
|
||||
|
||||
@@ -499,7 +514,7 @@ def fit_plot(data_x, data_y, model="gauss", ibg=1, fitrange=0, fitclick=0):
|
||||
|
||||
fit_id = pre+'_center'
|
||||
|
||||
center = g.pars[fit_id].value
|
||||
center = g.params[fit_id].value
|
||||
return center, xm
|
||||
|
||||
|
||||
@@ -550,7 +565,7 @@ def save_data(hindex: int, device_name: str, signal_name: str, isave = 1):
|
||||
#########################################
|
||||
### just retrieve the saved data from csv
|
||||
########################################
|
||||
def read_data(filename: str):
|
||||
def read_data_csv(filename: str):
|
||||
"""
|
||||
Get data stored in a CSV file
|
||||
|
||||
@@ -872,7 +887,7 @@ def colliscan(direction: str, range=0.3, nsteps=30, stime=0.5, centre=1):
|
||||
settling time: default = 0.5
|
||||
move to centre or not [0/1]
|
||||
|
||||
Example: colliscan("h", centre=1)
|
||||
Example: colliscan("h", range=0.2, nsteps=30, stime=0.5,centre=1)
|
||||
|
||||
"""
|
||||
import sys
|
||||
@@ -972,13 +987,14 @@ def slitscan(device_location: str, direction: str, range: 1, nsteps=50, centre=0
|
||||
default_v = 1.0 ## 1.2
|
||||
det = dev.lu_bpmsum
|
||||
if direction in ["x","h"]:
|
||||
mot = dev.fe_sxcen
|
||||
size = dev.fe_sxsize
|
||||
mot = dev.fe_sl_xcen
|
||||
size = dev.fe_sl_xsize
|
||||
s_closed = 0.1
|
||||
s_open = default_h
|
||||
else:
|
||||
mot = dev.fe_sycen
|
||||
size = dev.fe_sysize
|
||||
mot = dev.fe_sl_ycen
|
||||
size = dev.fe_sl_ysize
|
||||
|
||||
s_closed = 0.1
|
||||
s_open = default_v
|
||||
|
||||
@@ -1072,9 +1088,9 @@ def slitscan(device_location: str, direction: str, range: 1, nsteps=50, centre=0
|
||||
# FE slits ================================
|
||||
data_y = s.scan.live_data.lu_bpmsum.lu_bpmsum.val
|
||||
|
||||
if mot.name == "fe_sxcen":
|
||||
if mot.name == "fe_sl_xcen":
|
||||
data_x = s.scan.live_data.fe_sxcen.fe_sxcen.val
|
||||
if mot.name == "fe_sycen":
|
||||
if mot.name == "fe_sl_ycen":
|
||||
data_x = s.scan.live_data.fe_sycen.fe_sycen.val
|
||||
# BSF slits ================================
|
||||
if mot.name == "bsf_sl_xcen":
|
||||
@@ -1486,7 +1502,7 @@ def scan_eg(erange, nsteps=50, fit=True):
|
||||
data_e = energy_data
|
||||
data_y = bpm_data
|
||||
|
||||
dirname = "/home/gac-x10sa/Data/"
|
||||
dirname = "/sls/x10sa/config/commissioning/Data"
|
||||
# writing output to simple data file for later analysis:
|
||||
combined = np.column_stack((data_x, data_e, data_y))
|
||||
tname = f"Scan_{timestamp}.txt"
|
||||
@@ -1533,3 +1549,33 @@ def scan_window(wname="Scan", fit=True):
|
||||
|
||||
### if done, remove
|
||||
#w2.remove()
|
||||
################################################
|
||||
### beam centre on detector with distance
|
||||
################################################
|
||||
|
||||
#/sls/x10sa/config/commissioning/Data
|
||||
|
||||
def readdist(filename):
|
||||
with open(filename, "r") as f:
|
||||
combined_data = np.loadtxt(f, delimiter=",")
|
||||
|
||||
ind1 = 0
|
||||
ind2 = 1
|
||||
ind3 = 2
|
||||
detdist = combined_data[:, ind1]
|
||||
bposx = combined_data[:, ind2]
|
||||
bposy = combined_data[:, ind3]
|
||||
|
||||
plt.ion()
|
||||
plt.figure(1)
|
||||
plt.plot(detdist,bposx, ".")
|
||||
plt.title("Bpos X vs Detectordist")
|
||||
plt.xlabel("dist / mm")
|
||||
plt.ylabel("bpos X in det pix ")
|
||||
|
||||
plt.figure(2)
|
||||
plt.plot(detdist,bposy, ".")
|
||||
plt.title("Bpos Y vs Detectordist")
|
||||
plt.xlabel("dist / mm")
|
||||
plt.ylabel("bpos Y in det pix ")
|
||||
plt.show()
|
||||
|
||||
@@ -13,10 +13,10 @@ class KBMirror:
|
||||
self.P2 = 0.583490
|
||||
self.P3 = -0.372950
|
||||
self.L1 = -0.955798
|
||||
self.curv_approx_fact = 1.0121
|
||||
self.s1 = 24.15 #24.35
|
||||
self.curv_approx_fact = 0.9550 # 0.9550 # origin: 1.0121
|
||||
self.s1 = 24.15
|
||||
self.s2 = 1.45
|
||||
self.asym0 = 0.08
|
||||
self.asym0 = 0.114 ## origin: 0.0.08 + 0.034 # user asymm, eg 0.4750, will be added ( - sign)
|
||||
|
||||
elif self.mirror_type == "PXII_HFM":
|
||||
self.C0 = 0.060453
|
||||
@@ -24,10 +24,10 @@ class KBMirror:
|
||||
self.P2 = 0.586057
|
||||
self.P3 = -0.088093
|
||||
self.L1 = -0.999445
|
||||
self.curv_approx_fact = 0.995
|
||||
self.s1 = 24.90 #25.10
|
||||
self.curv_approx_fact = 0.8810 # origin: # 0.995
|
||||
self.s1 = 24.90
|
||||
self.s2 = 0.7
|
||||
self.asym0 = -0.0107
|
||||
self.asym0 = 0.06455 ## origin: -0.0107 + 0.07525 # added user asymm 2.75 (-sign)
|
||||
|
||||
else:
|
||||
raise ValueError(f"Unknown mirror type: {self.mirror_type}")
|
||||
|
||||
@@ -17,6 +17,10 @@ class Constants:
|
||||
# d-spacings
|
||||
d_spacing = {120: 3.13481, 298: 3.13562}
|
||||
|
||||
# offset
|
||||
# bragg_offset = -0.1457
|
||||
bragg_offset = 0
|
||||
|
||||
|
||||
def speed_of_light_ang():
|
||||
"""
|
||||
@@ -116,7 +120,9 @@ def calculate_wavelength_from_angle(bragg_angle_mrad: float, temp=120) -> float:
|
||||
The calculated wavelength as a float value.
|
||||
"""
|
||||
d = Constants.d_spacing[temp]
|
||||
return 2 * d * np.sin(bragg_angle_mrad / 1000)
|
||||
fudge = bragg_angle_mrad + Constants.bragg_offset
|
||||
# return 2 * d * np.sin((bragg_angle_mrad / 1000)
|
||||
return 2 * d * np.sin(fudge / 1000)
|
||||
|
||||
|
||||
def calculate_energy_from_wavelength(wavelength: float) -> float:
|
||||
|
||||
@@ -0,0 +1,484 @@
|
||||
"""
|
||||
BPM calibration using inverse PCHIP spline.
|
||||
|
||||
Calibration concept:
|
||||
BPM signal -> beam position relative to BPM
|
||||
|
||||
Final beam position:
|
||||
beam_absolute = bpm_motor_position + local_beam_position
|
||||
beam_relative_to_camera_crosshair = beam_absolute - camera_crosshair_position
|
||||
"""
|
||||
|
||||
import time
|
||||
import os
|
||||
from datetime import datetime, timedelta
|
||||
import numpy as np
|
||||
import matplotlib.pyplot as plt
|
||||
from pyparsing import results
|
||||
from scipy.optimize import curve_fit
|
||||
import scipy.special as special
|
||||
from scipy.interpolate import PchipInterpolator
|
||||
|
||||
|
||||
def read_currents():
|
||||
"""Read the individual bpm channels"""
|
||||
vals_bpm1 = []
|
||||
vals_bpm2 = []
|
||||
vals_bpm3 = []
|
||||
vals_bpm4 = []
|
||||
|
||||
for _ in range(5):
|
||||
vals_bpm1.append(dev.bcu_bpm1.read()["bcu_bpm1"]["value"])
|
||||
time.sleep(0.1)
|
||||
for _ in range(5):
|
||||
vals_bpm2.append(dev.bcu_bpm2.read()["bcu_bpm2"]["value"])
|
||||
time.sleep(0.1)
|
||||
for _ in range(5):
|
||||
vals_bpm3.append(dev.bcu_bpm3.read()["bcu_bpm3"]["value"])
|
||||
time.sleep(0.1)
|
||||
for _ in range(5):
|
||||
vals_bpm4.append(dev.bcu_bpm4.read()["bcu_bpm4"]["value"])
|
||||
time.sleep(0.1)
|
||||
bpm1 = np.mean(vals_bpm1)
|
||||
bpm2 = np.mean(vals_bpm2)
|
||||
bpm3 = np.mean(vals_bpm3)
|
||||
bpm4 = np.mean(vals_bpm4)
|
||||
|
||||
# bpm1 = dev.bcu_bpm1.read()["bcu_bpm1"]["value"]
|
||||
# bpm2 = dev.bcu_bpm2.read()["bcu_bpm2"]["value"]
|
||||
# bpm3 = dev.bcu_bpm3.read()["bcu_bpm3"]["value"]
|
||||
# bpm4 = dev.bcu_bpm4.read()["bcu_bpm4"]["value"]
|
||||
# print(f"bpm1 = {bpm1:.3f}, bpm2 = {bpm2:.3f}, bpm3 = {bpm3:.3f}, bpm4 = {bpm4:.3f}")
|
||||
return {"bpm1": bpm1, "bpm2": bpm2, "bpm3": bpm3, "bpm4": bpm4}
|
||||
|
||||
|
||||
def compute_norm():
|
||||
"""Compute normalised x and y positions"""
|
||||
readings = read_currents()
|
||||
total = readings["bpm1"] + readings["bpm2"] + readings["bpm3"] + readings["bpm4"]
|
||||
# print(f"Sum is {total:.2f}")
|
||||
xn = (
|
||||
(readings["bpm1"] + readings["bpm2"]) - (readings["bpm3"] + readings["bpm4"])
|
||||
) / total
|
||||
yn = (
|
||||
(readings["bpm1"] + readings["bpm3"]) - (readings["bpm2"] + readings["bpm4"])
|
||||
) / total
|
||||
# return xn, yn, readings["bpm1"], readings["bpm2"], readings["bpm3"], readings["bpm4"]
|
||||
return xn, yn
|
||||
|
||||
|
||||
# def compute_pos():
|
||||
# """Compute the beam x and y positions"""
|
||||
# cal = {
|
||||
# "bcu_bpm": {
|
||||
# "x_slope": 7.778,
|
||||
# "x_off": -1.019,
|
||||
# "y_slope": -8.625,
|
||||
# "y_off": -1.935,
|
||||
# }
|
||||
# }
|
||||
# xn, yn, bpm1, bpm2, bpm3, bpm4 = compute_norm()
|
||||
# # print(f"Normalised positions are {xn}, {yn}")
|
||||
# x_pos = (xn - cal["bcu_bpm"]["x_off"]) / cal["bcu_bpm"]["x_slope"]
|
||||
# y_pos = (yn - cal["bcu_bpm"]["y_off"]) / cal["bcu_bpm"]["y_slope"]
|
||||
# return x_pos, y_pos
|
||||
|
||||
|
||||
def run_calibration():
|
||||
"""Scan bpm in x and y and record normalised x and y positions"""
|
||||
# centred_x = 0.749
|
||||
# centred_y = -0.660
|
||||
now = datetime.now()
|
||||
fnow = now.strftime("%d%m%H%M")
|
||||
centred_x = 0.46
|
||||
centred_y = -1.51
|
||||
print(f"moving bpm to {centred_x}, {centred_y}")
|
||||
umv(dev.bcu_bpm_y, centred_y)
|
||||
umv(dev.bcu_bpm_x, centred_x)
|
||||
|
||||
# # Calibrate in X
|
||||
umv(dev.ss_sl_xsize,0.02)
|
||||
umv(dev.ss_sl_xsize, 3.0)
|
||||
filename = f"luts/bpm_calib/{fnow}_bcu_bpm_x.csv"
|
||||
xn_data = []
|
||||
x_positions = np.linspace(centred_x - 0.6, centred_x + 0.6, 101)
|
||||
with open(filename, "w", encoding="utf-8") as f:
|
||||
f.write(f"Xpos,Xnorm,BPM1,BPM2,BPM3,BPM4\n")
|
||||
for x in x_positions:
|
||||
umv(dev.bcu_bpm_x, x)
|
||||
print(f"Moving BPM to {x} mm")
|
||||
time.sleep(0.2)
|
||||
xn, yn, bpm1, bpm2, bpm3, bpm4 = compute_norm()
|
||||
xn_data.append(xn)
|
||||
with open(filename, "a", encoding="utf-8") as f:
|
||||
f.write(f"{x},{xn},{bpm1},{bpm2},{bpm3},{bpm4}\n")
|
||||
|
||||
# Calibrate in Y
|
||||
umv(dev.bcu_bpm_x, centred_x)
|
||||
umv(dev.ss_sl_xsize, 3.0)
|
||||
umv(dev.ss_sl_ysize, 0.03)
|
||||
filename = f"luts/bpm_calib/{fnow}_bcu_bpm_y.csv"
|
||||
y_positions = np.linspace(centred_y - 0.1, centred_y + 0.1, 251)
|
||||
yn_data = []
|
||||
with open(filename, "w", encoding="utf-8") as f:
|
||||
f.write(f"Ypos,Ynorm,BPM1,BPM2,BPM3,BPM4\n")
|
||||
for y in y_positions:
|
||||
umv(dev.bcu_bpm_y, y)
|
||||
print(f"Moving BPM to {y} mm")
|
||||
time.sleep(0.2)
|
||||
xn, yn, bpm1, bpm2, bpm3, bpm4 = compute_norm()
|
||||
yn_data.append(yn)
|
||||
with open(filename, "a", encoding="utf-8") as f:
|
||||
f.write(f"{y},{yn},{bpm1},{bpm2},{bpm3},{bpm4}\n")
|
||||
|
||||
umv(dev.bcu_bpm_x, centred_x)
|
||||
umv(dev.bcu_bpm_y, centred_y)
|
||||
umv(dev.ss_sl_ysize, 3.0)
|
||||
|
||||
|
||||
# Read data from BPM calibration files
|
||||
# def fit_bpm_data(x_y):
|
||||
# """
|
||||
# Read data from bpm calibration files.
|
||||
# """
|
||||
# filedir = "luts/bpm_calib/"
|
||||
# rundate= "02072130_"
|
||||
# name = f"bcu_bpm_{x_y}.csv"
|
||||
# filename = filedir + rundate + name
|
||||
# data = np.loadtxt(filename, delimiter=",", skiprows=1)
|
||||
# xdata = data[:, 0]
|
||||
# ydata = data[:, 1]
|
||||
# return xdata, ydata
|
||||
|
||||
|
||||
|
||||
def fit_bpm_data(x_y, rundate="02072130_", bpm_name="bcu_bpm"):
|
||||
CALIB_DIR = "luts/bpm_calib/"
|
||||
filename = os.path.join(CALIB_DIR, f"{rundate}{bpm_name}_{x_y}.csv")
|
||||
data = np.loadtxt(filename, delimiter=",", skiprows=1)
|
||||
|
||||
xdata = data[:, 0] # scan / motor position
|
||||
ydata = data[:, 1] # normalised BPM signal
|
||||
|
||||
return xdata, ydata
|
||||
|
||||
def linear_calibration(
|
||||
x_y,
|
||||
bpm_motor_position,
|
||||
crosshair_bpm_signal,
|
||||
rundate = "05071923_",
|
||||
bpm_name = "bcu_bpm",
|
||||
sanity_limit = 0.2,
|
||||
plot = True
|
||||
):
|
||||
calib_dir = "luts/bpm_calib"
|
||||
xdata, ydata = fit_bpm_data(x_y, rundate = rundate, bpm_name = bpm_name)
|
||||
# Remove non-linear region
|
||||
if x_y == 'x':
|
||||
mask_limit = 0.65
|
||||
else:
|
||||
mask_limit = 0.9
|
||||
mask = np.abs(ydata) < mask_limit
|
||||
xdata = xdata[mask]
|
||||
ydata = ydata[mask]
|
||||
|
||||
m, c = np.polyfit(xdata, ydata, 1)
|
||||
|
||||
# --- Plot ---
|
||||
plt.figure(figsize=(7, 5))
|
||||
plt.scatter(xdata, ydata, color="red", label=f"BPM {x_y} data")
|
||||
|
||||
x_fit = np.linspace(min(xdata), max(xdata), 100)
|
||||
plt.plot(x_fit, m * x_fit + c, "r--", label=f"Fit: Linear")
|
||||
|
||||
plt.xlabel("HFM Lat Position")
|
||||
plt.ylabel("SamCam X")
|
||||
plt.title("Zoom Calibration")
|
||||
plt.legend()
|
||||
plt.grid(True)
|
||||
plt.tight_layout()
|
||||
plt.show()
|
||||
|
||||
def make_inverse_spline_calibration(
|
||||
x_y,
|
||||
bpm_motor_position,
|
||||
crosshair_bpm_signal,
|
||||
rundate="05071923_",
|
||||
bpm_name="bcu_bpm",
|
||||
sanity_limit=0.2,
|
||||
plot=True,
|
||||
):
|
||||
"""
|
||||
Create and save inverse BPM calibration.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
x_y : str
|
||||
"x" or "y"
|
||||
bpm_motor_position : float
|
||||
Current physical BPM motor position during calibration.
|
||||
crosshair_bpm_signal : float
|
||||
Normalised BPM reading when the beam is on the sample-camera crosshair.
|
||||
mask_limit : float
|
||||
Ignore saturated BPM readings outside +/- mask_limit.
|
||||
sanity_limit : float
|
||||
Warn later if BPM motor has moved by more than this.
|
||||
"""
|
||||
CALIB_DIR = "luts/bpm_calib/"
|
||||
xdata, ydata = fit_bpm_data(x_y, rundate=rundate, bpm_name=bpm_name)
|
||||
|
||||
# Remove saturated BPM response
|
||||
if x_y == 'x':
|
||||
mask_limit = 0.98
|
||||
else:
|
||||
mask_limit = 0.91
|
||||
mask = np.abs(ydata) < mask_limit
|
||||
xdata = xdata[mask]
|
||||
ydata = ydata[mask]
|
||||
|
||||
# For inverse calibration: BPM signal -> beam position
|
||||
order = np.argsort(ydata)
|
||||
bpm_signal = ydata[order]
|
||||
local_position = xdata[order]
|
||||
|
||||
# Remove duplicate BPM signal values
|
||||
bpm_signal, unique_idx = np.unique(bpm_signal, return_index=True)
|
||||
local_position = local_position[unique_idx]
|
||||
|
||||
spline = PchipInterpolator(bpm_signal, local_position)
|
||||
|
||||
# Local beam position when beam is visually on camera crosshair
|
||||
crosshair_local_position = float(spline(crosshair_bpm_signal))
|
||||
|
||||
# Absolute beamline coordinate of camera crosshair
|
||||
crosshair_absolute_position = bpm_motor_position + crosshair_local_position
|
||||
|
||||
save_file = os.path.join(CALIB_DIR, f"{bpm_name}_{x_y}_inverse_spline.npz")
|
||||
|
||||
np.savez(
|
||||
save_file,
|
||||
bpm_signal=bpm_signal,
|
||||
local_position=local_position,
|
||||
bpm_motor_position=bpm_motor_position,
|
||||
crosshair_bpm_signal=crosshair_bpm_signal,
|
||||
crosshair_local_position=crosshair_local_position,
|
||||
crosshair_absolute_position=crosshair_absolute_position,
|
||||
mask_limit=mask_limit,
|
||||
sanity_limit=sanity_limit,
|
||||
)
|
||||
|
||||
print(f"Saved {x_y} BPM calibration to:")
|
||||
print(save_file)
|
||||
print()
|
||||
print(f"Calibration BPM motor position: {bpm_motor_position:.6f}")
|
||||
print(f"Crosshair BPM signal: {crosshair_bpm_signal:.6f}")
|
||||
print(f"Crosshair local position: {crosshair_local_position:.6f}")
|
||||
print(f"Crosshair absolute position: {crosshair_absolute_position:.6f}")
|
||||
|
||||
if plot:
|
||||
signal_fit = np.linspace(np.min(bpm_signal), np.max(bpm_signal), 1000)
|
||||
pos_fit = spline(signal_fit)
|
||||
|
||||
plt.figure()
|
||||
plt.scatter(ydata, xdata, label="calibration data")
|
||||
plt.plot(signal_fit, pos_fit, label="inverse PCHIP spline", color='red')
|
||||
plt.axvline(crosshair_bpm_signal, linestyle="--", label="camera crosshair")
|
||||
plt.xlabel(f"{bpm_name}_{x_y} normalised signal")
|
||||
plt.ylabel(f"{x_y} local beam position")
|
||||
plt.title(f"{bpm_name}_{x_y} inverse calibration")
|
||||
plt.grid(True)
|
||||
plt.legend()
|
||||
plt.show()
|
||||
|
||||
return save_file
|
||||
|
||||
class BPMCalibration:
|
||||
def __init__(self, filename):
|
||||
data = np.load(filename)
|
||||
|
||||
self.bpm_signal = data["bpm_signal"]
|
||||
self.local_position = data["local_position"]
|
||||
|
||||
self.bpm_motor_position_calib = float(data["bpm_motor_position"])
|
||||
self.crosshair_absolute_position = float(data["crosshair_absolute_position"])
|
||||
self.sanity_limit = float(data["sanity_limit"])
|
||||
|
||||
self.spline = PchipInterpolator(
|
||||
self.bpm_signal,
|
||||
self.local_position,
|
||||
)
|
||||
|
||||
def beam_position(self, bpm_signal, bpm_motor_position, warn=True):
|
||||
"""
|
||||
Return beam position relative to the sample-camera crosshair.
|
||||
"""
|
||||
|
||||
motor_shift = bpm_motor_position - self.bpm_motor_position_calib
|
||||
|
||||
if warn and abs(motor_shift) > self.sanity_limit:
|
||||
print(
|
||||
"Warning: BPM motor has moved since calibration: "
|
||||
f"delta = {motor_shift:.3f} mm"
|
||||
)
|
||||
|
||||
local_beam_position = float(self.spline(bpm_signal))
|
||||
absolute_beam_position = bpm_motor_position + local_beam_position
|
||||
|
||||
relative_to_crosshair = (
|
||||
absolute_beam_position - self.crosshair_absolute_position
|
||||
)
|
||||
|
||||
return relative_to_crosshair
|
||||
|
||||
def get_beampos():
|
||||
x_cal = BPMCalibration("luts/bpm_calib/bcu_bpm_x_inverse_spline.npz")
|
||||
y_cal = BPMCalibration("luts/bpm_calib/bcu_bpm_y_inverse_spline.npz")
|
||||
|
||||
bpm_x_signal, bpm_y_signal = compute_norm()
|
||||
|
||||
beam_x = x_cal.beam_position(
|
||||
bpm_signal=bpm_x_signal,
|
||||
bpm_motor_position=dev.bcu_bpm_x.position,
|
||||
)
|
||||
|
||||
beam_y = y_cal.beam_position(
|
||||
bpm_signal=bpm_y_signal,
|
||||
bpm_motor_position=dev.bcu_bpm_y.position,
|
||||
)
|
||||
|
||||
beam_x_mic = 1000 * beam_x
|
||||
beam_y_mic = 1000 * beam_y
|
||||
|
||||
print(f"Beam relative to camera crosshair:")
|
||||
print(f"X = {beam_x_mic:.4f} um")
|
||||
print(f"Y = {beam_y_mic:.4f} um")
|
||||
|
||||
return beam_x_mic, beam_y_mic
|
||||
|
||||
#!/usr/bin/env python
|
||||
"""Calculate photon flux from a Si diode current."""
|
||||
|
||||
import math
|
||||
from dataclasses import dataclass
|
||||
|
||||
import numpy as np
|
||||
|
||||
|
||||
@dataclass
|
||||
class PXIIDiodeConfig:
|
||||
"""Diode/beamline-specific constants."""
|
||||
|
||||
si_thickness_um: float = 12.0
|
||||
al_thickness_um: float = 20.0
|
||||
diode_offset_mm: float = 15.0
|
||||
|
||||
si_density: float = 2.33 # g/cm^3
|
||||
al_density: float = 2.699 # g/cm^3
|
||||
air_density: float = 1.205e-3 # g/cm^3
|
||||
|
||||
eps_si: float = 3.62 # eV per electron-hole pair
|
||||
|
||||
|
||||
def flux(
|
||||
current_a: float,
|
||||
energy_kev: float | None = None,
|
||||
det_z: float | None = None,
|
||||
config = PXIIDiodeConfig,
|
||||
) -> float:
|
||||
"""
|
||||
Calculate photon flux from Si diode current.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
current_a:
|
||||
Diode current in A.
|
||||
energy_kev:
|
||||
Beam energy in keV. Will use the current energy if
|
||||
not specified.
|
||||
det_z:
|
||||
Detector distance (dev.det_z) (mm). Will use the current
|
||||
detector distance if not specified.
|
||||
config:
|
||||
DiodeConfig containing Si/Al thicknesses and material constants.
|
||||
|
||||
Returns
|
||||
-------
|
||||
float
|
||||
Flux in photons/s.
|
||||
"""
|
||||
if energy_kev is None:
|
||||
energy_kev = get_current_energy() / 1000
|
||||
|
||||
if det_z is None:
|
||||
det_z = dev.det_z.position
|
||||
|
||||
air_path_mm = det_z + config.diode_offset_mm
|
||||
|
||||
si_thickness_cm = config.si_thickness_um / 10_000.0
|
||||
al_thickness_cm = config.al_thickness_um / 10_000.0
|
||||
|
||||
log_energy = math.log10(energy_kev)
|
||||
|
||||
# Photoelectric mass attenuation coefficient fits
|
||||
si_poly = np.poly1d([0.0789, -0.477, -2.238, 4.158])
|
||||
al_poly = np.poly1d([0.0638, -0.413, -2.349, 4.106])
|
||||
air_poly = np.poly1d([0.928, -2.348, -1.026, 3.153])
|
||||
|
||||
a_si = 10 ** si_poly(log_energy)
|
||||
a_al = 10 ** al_poly(log_energy)
|
||||
a_air = 10 ** air_poly(log_energy)
|
||||
|
||||
# Fraction of beam absorbed in active Si layer
|
||||
si_absorbed_fraction = -np.expm1(
|
||||
-a_si * config.si_density * si_thickness_cm
|
||||
)
|
||||
|
||||
if si_absorbed_fraction <= 0:
|
||||
raise ValueError("Calculated Si absorption fraction is zero or negative.")
|
||||
|
||||
# Flux before Al/air correction
|
||||
flux = (
|
||||
1000.0
|
||||
* current_a
|
||||
* config.eps_si
|
||||
/ 1.602
|
||||
/ energy_kev
|
||||
/ si_absorbed_fraction
|
||||
* 1.0e13
|
||||
)
|
||||
|
||||
# Transmission through Al and air
|
||||
al_transmission = np.exp(
|
||||
-a_al * config.al_density * al_thickness_cm
|
||||
)
|
||||
|
||||
air_transmission = np.exp(
|
||||
-a_air * config.air_density * air_path_mm / 10.0
|
||||
)
|
||||
|
||||
flux /= al_transmission
|
||||
flux /= air_transmission
|
||||
|
||||
print(f"The flux is {flux: .3g} ph/s")
|
||||
|
||||
return float(flux)
|
||||
|
||||
def calibrate_bpm_flux():
|
||||
# d['det_z'].move('mse')
|
||||
# d['det_y'].move('xi')
|
||||
# d['det_z'].move(200)
|
||||
|
||||
flux = flux(dev.xidiode.read()['xidiode']['value'])
|
||||
|
||||
|
||||
def zero_xidiode():
|
||||
vals = []
|
||||
for i in range(1,101):
|
||||
reading = dev.xidiode.read()['xidiode']['value']
|
||||
vals.append(reading)
|
||||
|
||||
zero = np.mean(vals)
|
||||
print(zero)
|
||||
|
||||
|
||||
|
||||
+38
-69
@@ -2,60 +2,9 @@ import numpy as np
|
||||
import math, time
|
||||
import matplotlib.pyplot as plt
|
||||
import scipy
|
||||
#########################################
|
||||
### just retrieve the saved data from csv
|
||||
########################################
|
||||
def read_data(filename: str):
|
||||
"""
|
||||
Get data stored in a CSV file
|
||||
|
||||
Args:
|
||||
filename (str): the csv file, eg, of a Scan
|
||||
e.g., dat = read_data("/home/e18747/SLS2/Data/gaps/gaps10.txt")
|
||||
"""
|
||||
|
||||
# dirname = '/home/gac-x10sa/Data/'
|
||||
# read output to simple data file for later analysis:
|
||||
|
||||
with open(filename, "r") as f:
|
||||
combined_data = np.loadtxt(f, delimiter=",") # no header and fmt for load
|
||||
|
||||
rows, cols = combined_data.shape
|
||||
|
||||
print("No of Rows =", rows)
|
||||
print("No of Colums =", cols)
|
||||
ind1 = 0
|
||||
ind2 = 1
|
||||
if cols > 2:
|
||||
print(
|
||||
"only first 2 colums (data[:, 0] and data[:, 1]) are plotted, please consider the other columns as well!"
|
||||
)
|
||||
index1 = 0
|
||||
index2 = 1
|
||||
index1, index2 = input(
|
||||
"please enter the columns to be plotted vs first one [eg: 1,2] : "
|
||||
).split(",")
|
||||
ind1 = int(index1)
|
||||
ind2 = int(index2)
|
||||
|
||||
if ind2 > cols - 1:
|
||||
print(" no valid index")
|
||||
|
||||
data_x = combined_data[:, ind1]
|
||||
data_y = combined_data[:, ind2]
|
||||
|
||||
plt.ion()
|
||||
plt.figure()
|
||||
plt.plot(data_x, data_y, ".")
|
||||
|
||||
plt.title(f"Scan from {filename}")
|
||||
plt.xlabel(f"data column {ind1}")
|
||||
plt.ylabel(f"data column {ind2}")
|
||||
|
||||
plt.show()
|
||||
|
||||
return combined_data
|
||||
|
||||
########################################################
|
||||
### scan FE slits and check BPMs before and after mirror
|
||||
########################################################
|
||||
|
||||
def gaussfit(x,y,p):
|
||||
# define a gaussian fitting function where
|
||||
@@ -95,22 +44,42 @@ def gaussfit(x,y,p):
|
||||
|
||||
return bestfit, p1
|
||||
|
||||
def scan_fe_sl():
|
||||
fe_v_size0 = dev.fe_sl_ysize.user_readback.get()
|
||||
umv(dev.fe_sl_xsize, 0.1)
|
||||
s = scans.line_scan(dev.fe_sl_ycen,-1,1, exp_time=02., steps=21, relative=True)
|
||||
time.sleep(0.1)
|
||||
umv(dev.fe_sl_xsize, fe_v_size0)
|
||||
def scan_fe_sl(dir = "y"):
|
||||
if dir in ["y","v"]:
|
||||
sdir ="vertical"
|
||||
fe_size0 = dev.fe_sl_ysize.user_readback.get()
|
||||
print('Closing vertical FE slits to 0.1')
|
||||
umv(dev.fe_sl_ysize, 0.1)
|
||||
s = scans.line_scan(dev.fe_sl_ycen,-1,1, exp_time=02., steps=21, relative=True)
|
||||
time.sleep(0.1)
|
||||
umv(dev.fe_sl_ysize, fe_size0)
|
||||
print(f'Opening {sdir} FE slits to {fe_size0}')
|
||||
if dir in ["x","h"]:
|
||||
sdir ="horizontal"
|
||||
fe_size0 = dev.fe_sl_xsize.user_readback.get()
|
||||
print('Closing horizontal FE slits to 0.1')
|
||||
umv(dev.fe_sl_xsize, 0.1)
|
||||
s = scans.line_scan(dev.fe_sl_xcen,-1,1, exp_time=02., steps=21, relative=True)
|
||||
time.sleep(0.1)
|
||||
umv(dev.fe_sl_xsize, fe_size0)
|
||||
print(f'Opening {sdir} FE slits to {fe_size0}')
|
||||
else:
|
||||
print('no valid direction, doing nothing')
|
||||
|
||||
def mirrh():
|
||||
def mirrh(dir='y'):
|
||||
|
||||
#dat_ss = read_data("/home/anuschka/SS_pitch2p94.csv")
|
||||
#dat_bcu = read_data("/home/anuschka/BCU_pitch2p94.csv")
|
||||
#dat_ss = read_data_csv("/home/anuschka/SS_pitch2p94.csv")
|
||||
#dat_bcu = read_data_csv("/home/anuschka/BCU_pitch2p94.csv")
|
||||
|
||||
scan_fe_sl()
|
||||
scan_fe_sl(dir=dir)
|
||||
ind = -1
|
||||
dat_ss = save_data(ind, 'fe_sl_ycen', 'ss_bpmsum', isave = 0)
|
||||
dat_bcu = save_data(ind, 'fe_sl_ycen', 'bcu_bpmsum', isave = 0)
|
||||
if dir in ["x","h"]:
|
||||
slitmot = 'fe_sl_xcen'
|
||||
if dir in ["y","v"]:
|
||||
slitmot = 'fe_sl_ycen'
|
||||
|
||||
dat_ss = save_data(ind, slitmot, 'ss_bpmsum', isave = 0)
|
||||
dat_bcu = save_data(ind, slitmot, 'bcu_bpmsum', isave = 0)
|
||||
|
||||
|
||||
data_xs = dat_ss[0] # csv would be: dat_ss[:, 0]
|
||||
@@ -124,7 +93,7 @@ def mirrh():
|
||||
#plt.plot(data_xs, data_ys, "*")
|
||||
#plt.plot(data_xb, data_yb, "+")
|
||||
|
||||
data_ys_norm = data_ys/max(data_ys)
|
||||
data_ys_norm = data_ys/max(data_ys) # looks better than data_ys/sum(data_ys)
|
||||
data_yb_norm = data_yb/max(data_yb)
|
||||
|
||||
plt.figure()
|
||||
@@ -138,7 +107,7 @@ def mirrh():
|
||||
xmi = data_xs[xm]
|
||||
#print('xm, xmi', xm, xmi)
|
||||
|
||||
pf1 = [1, xmi , np.std(data_ys_norm),0]
|
||||
pf1 = [1, xmi , np.std(data_ys_norm), np.mean(y[0:5])] # bg = 0
|
||||
fit_s, ps = gaussfit(data_xs,data_ys_norm, pf1)
|
||||
|
||||
y= data_yb_norm
|
||||
@@ -146,7 +115,7 @@ def mirrh():
|
||||
xmi = data_xb[xm]
|
||||
#print('xm, xmi', xm, xmi)
|
||||
|
||||
pf2 = [1, xmi, np.std(data_yb_norm),-11]
|
||||
pf2 = [1, xmi, np.std(data_yb_norm), np.mean(y[0:5])] # bg = -11
|
||||
fit_b, pb = gaussfit(data_xb,data_yb_norm, pf2)
|
||||
|
||||
|
||||
|
||||
@@ -1,142 +0,0 @@
|
||||
import numpy as np
|
||||
import math
|
||||
import matplotlib.pyplot as plt
|
||||
import scipy
|
||||
#########################################
|
||||
### just retrieve the saved data from csv
|
||||
########################################
|
||||
def read_data(filename: str):
|
||||
"""
|
||||
Get data stored in a CSV file
|
||||
|
||||
Args:
|
||||
filename (str): the csv file, eg, of a Scan
|
||||
e.g., dat = read_data("/home/e18747/SLS2/Data/gaps/gaps10.txt")
|
||||
"""
|
||||
|
||||
# dirname = '/home/gac-x10sa/Data/'
|
||||
# read output to simple data file for later analysis:
|
||||
|
||||
with open(filename, "r") as f:
|
||||
combined_data = np.loadtxt(f, delimiter=",") # no header and fmt for load
|
||||
|
||||
rows, cols = combined_data.shape
|
||||
|
||||
print("No of Rows =", rows)
|
||||
print("No of Colums =", cols)
|
||||
ind1 = 0
|
||||
ind2 = 1
|
||||
if cols > 2:
|
||||
print(
|
||||
"only first 2 colums (data[:, 0] and data[:, 1]) are plotted, please consider the other columns as well!"
|
||||
)
|
||||
index1 = 0
|
||||
index2 = 1
|
||||
index1, index2 = input(
|
||||
"please enter the columns to be plotted vs first one [eg: 1,2] : "
|
||||
).split(",")
|
||||
ind1 = int(index1)
|
||||
ind2 = int(index2)
|
||||
|
||||
if ind2 > cols - 1:
|
||||
print(" no valid index")
|
||||
|
||||
data_x = combined_data[:, ind1]
|
||||
data_y = combined_data[:, ind2]
|
||||
|
||||
plt.ion()
|
||||
plt.figure()
|
||||
plt.plot(data_x, data_y, ".")
|
||||
|
||||
plt.title(f"Scan from {filename}")
|
||||
plt.xlabel(f"data column {ind1}")
|
||||
plt.ylabel(f"data column {ind2}")
|
||||
|
||||
plt.show()
|
||||
|
||||
return combined_data
|
||||
|
||||
|
||||
def gaussfit(x,y,p):
|
||||
# define a gaussian fitting function where
|
||||
# p[0] = amplitude
|
||||
# p[1] = mean
|
||||
# p[2] = sigma
|
||||
# p[3] = const offset
|
||||
|
||||
fitfct = lambda p, x0: p[0]*np.exp(-(x0-p[1])**2/(2.0*p[2]**2))+p[3]
|
||||
#fitfct = lambda p, x0: p[0]*np.exp(-(x0-p[1])**2/(2.0*p[2]**2))
|
||||
errfct = lambda p, x0,y0: fitfct(p,x0)-y0
|
||||
|
||||
# guess fit parameters
|
||||
ind0 = np.where(y==max(y))[0]
|
||||
p0=scipy.c_[max(y), x[ind0], np.std(y), np.mean(y[0:5])]
|
||||
#p0=scipy.c_[max(y), np.where(y==max(y))[0], np.std(y)]
|
||||
# array generation [[]], and taking only one dimens
|
||||
# fit a gaussian to the correlation function
|
||||
|
||||
print('p0 = ' , p0)
|
||||
p1, success = scipy.optimize.leastsq(errfct, p0.copy()[0],
|
||||
args=(x,y))
|
||||
|
||||
plt.figure()
|
||||
bestfit=fitfct(p1,x)
|
||||
#print('************************', x,y)
|
||||
plt.plot(x,y,'r*')
|
||||
plt.plot(x,bestfit,'r-')
|
||||
|
||||
# different fit fct
|
||||
#popt, pcov = curve_fit(fitfct, x, y)
|
||||
#newfit=fitfct(popt,x)
|
||||
#plt.plot(x,newfit,'g+')
|
||||
|
||||
|
||||
plt.show()
|
||||
#time.sleep(1)
|
||||
#plt.close()
|
||||
return bestfit, p1
|
||||
|
||||
def mirh():
|
||||
|
||||
dat_ss = read_data("/home/anuschka/SS_pitch2p94.csv")
|
||||
dat_bcu = read_data("/home/anuschka/BCU_pitch2p94.csv")
|
||||
|
||||
data_xs = dat_ss[:, 0]
|
||||
data_ys = dat_ss[:, 1]
|
||||
|
||||
data_xb = dat_bcu[:, 0]
|
||||
data_yb = dat_bcu[:, 1]
|
||||
|
||||
plt.figure()
|
||||
|
||||
plt.plot(data_xs, data_ys, "*")
|
||||
plt.plot(data_xb, data_yb, "+")
|
||||
|
||||
data_ys_norm = data_ys/max(data_ys)
|
||||
data_yb_norm = data_yb/max(data_yb)
|
||||
|
||||
plt.figure()
|
||||
|
||||
plt.plot(data_xs, data_ys_norm, "*")
|
||||
plt.plot(data_xb, data_yb_norm, "+")
|
||||
|
||||
|
||||
pf1 = [1, 0.8 , np.std(data_ys_norm),0]
|
||||
|
||||
y= data_ys_norm
|
||||
xm = np.where(y==max(y))[0]
|
||||
xmi = data_xs[xm]
|
||||
print('xm, xmi', xm, xmi)
|
||||
|
||||
fit_s, ps = gaussfit(data_xs,data_ys_norm, pf1)
|
||||
|
||||
pf2 = [1, 0.8, np.std(data_yb_norm),-11]
|
||||
fit_b, pb = gaussfit(data_xb,data_yb_norm, pf2)
|
||||
|
||||
|
||||
plt.figure()
|
||||
|
||||
plt.plot(data_xs, fit_s-ps[3], "*")
|
||||
plt.plot(data_xb, fit_b-pb[3], "+")
|
||||
|
||||
|
||||
+408
-356
@@ -1,7 +1,7 @@
|
||||
"""Some simple scripts for commissioning"""
|
||||
|
||||
import time, os
|
||||
from datetime import datetime
|
||||
from datetime import datetime, timedelta
|
||||
from dataclasses import dataclass
|
||||
import numpy as np
|
||||
import matplotlib.pyplot as plt
|
||||
@@ -10,15 +10,6 @@ import pandas as pd
|
||||
from scipy.optimize import linear_sum_assignment
|
||||
|
||||
|
||||
def goto1a():
|
||||
"""Set beamline to 1A position"""
|
||||
bragg_angle = 160.117
|
||||
perp_dist = 0.0389
|
||||
gap = 5.319
|
||||
umv(dev.dcm_bragg, bragg_angle)
|
||||
umv(dev.dcm_perp, perp_dist)
|
||||
umv(dev.id_gap, gap)
|
||||
|
||||
|
||||
def bragg_scan():
|
||||
"""Energy scans from 6 to 18 keV at various gap positions"""
|
||||
@@ -59,26 +50,10 @@ def energy_checks(start_energy=8000, end_energy=20000):
|
||||
"""Check gap, pitch and intensities at different energies"""
|
||||
f = open("luts/test.csv", "a", encoding="utf-8")
|
||||
|
||||
gaps = {
|
||||
8000: 8.04,
|
||||
9000: 9.55,
|
||||
10000: 7.45,
|
||||
11000: 8.46,
|
||||
12000: 7.09,
|
||||
13000: 7.77,
|
||||
14000: 8.61,
|
||||
15000: 9.57,
|
||||
16000: 8.09,
|
||||
17000: 7.18,
|
||||
18000: 7.67,
|
||||
19000: 8.24,
|
||||
20000: 7.52,
|
||||
}
|
||||
for energy in range(start_energy, end_energy, 1000):
|
||||
f = open("luts/test.csv", "a", encoding="utf-8")
|
||||
print(f"Moving to {energy} eV")
|
||||
umv(dev.id_gap, gaps[energy])
|
||||
move_and_set_dcm(energy)
|
||||
bl_energy
|
||||
if energy < 16000:
|
||||
close_fe_slits(True)
|
||||
go_to_peak(
|
||||
@@ -277,86 +252,75 @@ def write_beamsize():
|
||||
f.write(f"{lens_config},{sx:.4g},{sy:.4g},{i1_reading:.4g}\n")
|
||||
|
||||
|
||||
def beamsize(size):
|
||||
"""WIP to dial up different beam sizes"""
|
||||
# Set mirror trans and pitch to default settings for 12.4 keV
|
||||
# vlaues from a 2025
|
||||
# umv(dev.vfm_vert,2.136)
|
||||
# umv(dev.vfm_pitch, 2.695)
|
||||
# umv(dev.hfm_lat, 1.64)
|
||||
# umv(dev.hfm_pitch, 2.9844)
|
||||
umv(dev.vfm_vert, 2.5301)
|
||||
umv(dev.vfm_pitch, 2.60)
|
||||
umv(dev.hfm_lat, 1.6586)
|
||||
umv(dev.hfm_pitch, 2.9964)
|
||||
print(f"changing beam size to {size}")
|
||||
|
||||
# values = {"xs": {"vbu": -0.9095, "vbd": -1.246, "hbu": -2.9375, "hbd": -5.698},
|
||||
# "s": {"vbu": -0.8365, "vbd": -1.22, "hbu": -2.804, "hbd": -5.473},
|
||||
# "m": {"vbu": -0.7865, "vbd": -1.17, "hbu": -2.604, "hbd": -5.273},
|
||||
# "l": {"vbu": -0.7459, "vbd": -1.13, "hbu": -2.504, "hbd": -5.173}}
|
||||
# values = {"xs": {"vbu": -0.9095, "vbd": -1.246, "hbu": -2.8075, "hbd": -5.668},
|
||||
# "s": {"vbu": -0.8606, "vbd": -1.195, "hbu": -2.6975, "hbd": -5.5585},
|
||||
# "m": {"vbu": -0.8410, "vbd": -1.465, "hbu": -2.5575, "hbd": -5.418},
|
||||
# "l": {"vbu": -0.762, "vbd": -1.094, "hbu": -2.4582, "hbd": -5.3187}}
|
||||
values = {
|
||||
"xs": {"vbu": -0.741, "vbd": -1.206, "hbu": -2.869, "hbd": -5.819},
|
||||
"s": {"vbu": -0.7101, "vbd": -1.176, "hbu": -2.7133, "hbd": -5.5535},
|
||||
"m": {"vbu": -0.6601, "vbd": -1.126, "hbu": -2.5133, "hbd": -5.3535},
|
||||
"l": {"vbu": -0.6196, "vbd": -1.086, "hbu": -2.4133, "hbd": -5.2535},
|
||||
}
|
||||
umv(
|
||||
dev.vfm_bu,
|
||||
values[size]["vbu"],
|
||||
dev.vfm_bd,
|
||||
values[size]["vbd"],
|
||||
dev.hfm_bu,
|
||||
values[size]["hbu"],
|
||||
dev.hfm_bd,
|
||||
values[size]["hbd"],
|
||||
)
|
||||
print("Setting camera exposure time")
|
||||
auto_exposure()
|
||||
xsig = dev.samcam_xsig.read()["samcam_xsig"]["value"]
|
||||
ysig = dev.samcam_ysig.read()["samcam_ysig"]["value"]
|
||||
print(f"Beam has Xsigma = {xsig:.3g}, Ysigma = {ysig:.3g}")
|
||||
|
||||
# if size == 'm':
|
||||
# move_to_x()
|
||||
# print(f"Beam has Xsigma = {xsig:.3g}, Ysigma = {ysig:.3g}")
|
||||
# return
|
||||
# if size == 'l':
|
||||
# move_to_x()
|
||||
# move_to_y()
|
||||
# umv(dev.hfm_pitch, 2.9684)
|
||||
# print(f"Beam has Xsigma = {xsig:.3g}, Ysigma = {ysig:.3g}")
|
||||
# return
|
||||
# else:
|
||||
# move_to_x()
|
||||
# move_to_y()
|
||||
# print(f"Beam has Xsigma = {xsig:.3g}, Ysigma = {ysig:.3g}")
|
||||
|
||||
|
||||
def scan_Ge():
|
||||
scanbefore = 30 # eV
|
||||
scanafter = 30 # eV
|
||||
stepsize = 0.5 # eV
|
||||
edge_Ge = 11103.1 # eV
|
||||
|
||||
scanstart = edge_Ge + scanafter
|
||||
scanend = edge_Ge - scanbefore
|
||||
bragg_start = convert_from_energy(scanstart)["bragg_angle_mrad"]
|
||||
bragg_end = convert_from_energy(scanend)["bragg_angle_mrad"]
|
||||
stepnumber = abs(int((scanend - scanstart) / stepsize))
|
||||
|
||||
print(f"Changing energy to {scanstart}")
|
||||
stepsize = 0.2 # eV
|
||||
# Edge sgould be at 11103.1
|
||||
actual_edge_Ge = 11103.1 # eV
|
||||
actual_bragg = convert_from_energy(actual_edge_Ge)["bragg_angle_mrad"]
|
||||
current_edge = 11095
|
||||
current_bragg = convert_from_energy(current_edge)["bragg_angle_mrad"]
|
||||
print(f"Ge edge should be at a bragg angle of {actual_bragg:.5g} mrad\n")
|
||||
print(f"Current estimate of edge is {current_bragg:.5g} mrad\n")
|
||||
xdata = []
|
||||
ydata = []
|
||||
filedir, fname = fnow()
|
||||
filename = f"{filedir}{fname}_ge_edge.csv"
|
||||
print(filename)
|
||||
with open(filename, 'w') as f:
|
||||
f.write(f"Energy,Bragg,bcu_bpmsum\n")
|
||||
|
||||
# scanstart = edge_Ge + scanafter
|
||||
# scanend = edge_Ge - scanbefore
|
||||
# bragg_start = convert_from_energy(scanstart)["bragg_angle_mrad"]
|
||||
# bragg_end = convert_from_energy(scanend)["bragg_angle_mrad"]
|
||||
# stepnumber = abs(int((scanend - scanstart) / stepsize))
|
||||
# print(f"Changing energy to {scanstart}")
|
||||
# bl_energy(scanstart)
|
||||
# scan_gap()
|
||||
umv(dev.bsc_f4_x, 6) # Put Ge filter in place
|
||||
print(f"scanning from {bragg_start} to {bragg_end} with {stepnumber} steps")
|
||||
s = scans.line_scan(dev.dcm_bragg, bragg_start, bragg_end, steps=stepnumber, relative=False)
|
||||
print(s)
|
||||
umv(dev.bsc_f4_x, 2)
|
||||
# # scan_gap()
|
||||
# umv(dev.ss_f4_x, 6) # Put Ge filter in place
|
||||
# print(f"scanning from {bragg_start} to {bragg_end} with {stepnumber} steps")
|
||||
# s = scans.line_scan(dev.dcm_bragg, bragg_start, bragg_end, steps=stepnumber, relative=False)
|
||||
# print(s)
|
||||
# umv(dev.ss_f4_x, 2)
|
||||
|
||||
plot_live_data_bec(dev.dcm_bragg,dev.bcu_bpmsum)
|
||||
scanpoints = np.linspace(current_bragg - 0.5, current_bragg + 0.5, 300)
|
||||
start_energy = convert_from_bragg(current_bragg+0.5)["energy_ev"]
|
||||
bl_energy(start_energy)
|
||||
umv(dev.ss_f4_x, 6) # Put Ge filter in place
|
||||
|
||||
for bragg in scanpoints:
|
||||
scans.umv(dev.dcm_bragg, bragg, relative=False)
|
||||
energy = convert_from_bragg(bragg)["energy_ev"]
|
||||
inten = average_inten()
|
||||
xdata.append(energy)
|
||||
ydata.append(inten)
|
||||
with open(filename, 'a') as f:
|
||||
f.write(f"{energy:.2f},{bragg:.2f},{inten:.2f}\n")
|
||||
data = {
|
||||
"x_data": np.array(xdata),
|
||||
"y_data": np.array(ydata),
|
||||
"motor_name": "dcm_bragg",
|
||||
"signal_name": "bcu_bpmsum",
|
||||
"motor_device": dev.dcm_bragg,
|
||||
"scan_number": "Current",
|
||||
}
|
||||
|
||||
# Define and fit model to scan data
|
||||
fit_params = create_fit_parameters(deriv = True,
|
||||
negative = False,
|
||||
model = FitDefaults.MODEL,
|
||||
baseline = FitDefaults.BASELINE)
|
||||
fit_result = fit(data, fit_params)
|
||||
|
||||
# Plot the fitted data if plot = True
|
||||
|
||||
plot_fitted_data_bec(data, fit_result)
|
||||
|
||||
|
||||
|
||||
|
||||
def cal_samcam_fixed_x():
|
||||
@@ -434,79 +398,79 @@ def cal_samcam_fixed_x():
|
||||
plt.show()
|
||||
|
||||
|
||||
def cal_samcam_fixed_y():
|
||||
vert = dev.vfm_vert.read()["vfm_vert"]["value"]
|
||||
pitch = dev.vfm_pitch.read()["vfm_pitch"]["value"]
|
||||
scanpoints = np.linspace(vert - 0.1, vert + 0.1, 7)
|
||||
zoom_high = 800
|
||||
zoom_low = 200
|
||||
highs, lows = [], []
|
||||
high_vert, low_vert = [], []
|
||||
# def cal_samcam_fixed_y():
|
||||
# vert = dev.vfm_vert.read()["vfm_vert"]["value"]
|
||||
# pitch = dev.vfm_pitch.read()["vfm_pitch"]["value"]
|
||||
# scanpoints = np.linspace(vert - 0.1, vert + 0.1, 7)
|
||||
# zoom_high = 800
|
||||
# zoom_low = 200
|
||||
# highs, lows = [], []
|
||||
# high_vert, low_vert = [], []
|
||||
|
||||
# high zoom
|
||||
umv(dev.scam_zoom, zoom_high)
|
||||
auto_exposure("samcam")
|
||||
for i in scanpoints:
|
||||
umv(dev.vfm_vert, i)
|
||||
umv(dev.vfm_pitch, pitch)
|
||||
time.sleep(0.2)
|
||||
high_y = dev.samcam_y.read()["samcam_y"]["value"]
|
||||
high_x = dev.vfm_vert.read()["vfm_vert"]["value"]
|
||||
print(f"Ypos at zoom {zoom_high} is {high_y}")
|
||||
highs.append(high_y)
|
||||
high_vert.append(high_x)
|
||||
# # high zoom
|
||||
# umv(dev.scam_zoom, zoom_high)
|
||||
# auto_exposure("samcam")
|
||||
# for i in scanpoints:
|
||||
# umv(dev.vfm_vert, i)
|
||||
# umv(dev.vfm_pitch, pitch)
|
||||
# time.sleep(0.2)
|
||||
# high_y = dev.samcam_y.read()["samcam_y"]["value"]
|
||||
# high_x = dev.vfm_vert.read()["vfm_vert"]["value"]
|
||||
# print(f"Ypos at zoom {zoom_high} is {high_y}")
|
||||
# highs.append(high_y)
|
||||
# high_vert.append(high_x)
|
||||
|
||||
umv(dev.scam_zoom, zoom_low)
|
||||
auto_exposure("samcam")
|
||||
for i in scanpoints:
|
||||
umv(dev.vfm_vert, i)
|
||||
umv(dev.vfm_pitch, pitch)
|
||||
time.sleep(0.2)
|
||||
low_y = dev.samcam_y.read()["samcam_y"]["value"]
|
||||
low_x = dev.vfm_vert.read()["vfm_vert"]["value"]
|
||||
print(f"Ypos at zoom {zoom_low} is {low_y}")
|
||||
lows.append(low_y)
|
||||
low_vert.append(low_x)
|
||||
# umv(dev.scam_zoom, zoom_low)
|
||||
# auto_exposure("samcam")
|
||||
# for i in scanpoints:
|
||||
# umv(dev.vfm_vert, i)
|
||||
# umv(dev.vfm_pitch, pitch)
|
||||
# time.sleep(0.2)
|
||||
# low_y = dev.samcam_y.read()["samcam_y"]["value"]
|
||||
# low_x = dev.vfm_vert.read()["vfm_vert"]["value"]
|
||||
# print(f"Ypos at zoom {zoom_low} is {low_y}")
|
||||
# lows.append(low_y)
|
||||
# low_vert.append(low_x)
|
||||
|
||||
umv(dev.vfm_vert, vert)
|
||||
umv(dev.vfm_pitch, pitch)
|
||||
# umv(dev.vfm_vert, vert)
|
||||
# umv(dev.vfm_pitch, pitch)
|
||||
|
||||
# Convert to numpy arrays
|
||||
x_high = np.array(high_vert)
|
||||
x_low = np.array(low_vert)
|
||||
y_high = np.array(highs)
|
||||
y_low = np.array(lows)
|
||||
# # Convert to numpy arrays
|
||||
# x_high = np.array(high_vert)
|
||||
# x_low = np.array(low_vert)
|
||||
# y_high = np.array(highs)
|
||||
# y_low = np.array(lows)
|
||||
|
||||
# Fit linear models: y = m*x + b
|
||||
m_high, b_high = np.polyfit(x_high, y_high, 1)
|
||||
m_low, b_low = np.polyfit(x_low, y_low, 1)
|
||||
# # Fit linear models: y = m*x + b
|
||||
# m_high, b_high = np.polyfit(x_high, y_high, 1)
|
||||
# m_low, b_low = np.polyfit(x_low, y_low, 1)
|
||||
|
||||
# Intersection point
|
||||
x_intersect = (b_low - b_high) / (m_high - m_low)
|
||||
y_intersect = m_high * x_intersect + b_high
|
||||
# # Intersection point
|
||||
# x_intersect = (b_low - b_high) / (m_high - m_low)
|
||||
# y_intersect = m_high * x_intersect + b_high
|
||||
|
||||
print(f"\nIntersection at:")
|
||||
print(f" VFM_vert = {x_intersect:.5f}")
|
||||
print(f" SamCam_y = {y_intersect:.2f}")
|
||||
# print(f"\nIntersection at:")
|
||||
# print(f" VFM_vert = {x_intersect:.5f}")
|
||||
# print(f" SamCam_y = {y_intersect:.2f}")
|
||||
|
||||
# --- Plot ---
|
||||
plt.figure(figsize=(7, 5))
|
||||
plt.scatter(x_high, y_high, color="red", label=f"Zoom = {zoom_high} data")
|
||||
plt.scatter(x_low, y_low, color="blue", label=f"Zoom = {zoom_low} data")
|
||||
# # --- Plot ---
|
||||
# plt.figure(figsize=(7, 5))
|
||||
# plt.scatter(x_high, y_high, color="red", label=f"Zoom = {zoom_high} data")
|
||||
# plt.scatter(x_low, y_low, color="blue", label=f"Zoom = {zoom_low} data")
|
||||
|
||||
x_fit = np.linspace(min(x_high), max(x_high), 100)
|
||||
plt.plot(x_fit, m_high * x_fit + b_high, "r--", label=f"Fit: Zoom {zoom_high}")
|
||||
plt.plot(x_fit, m_low * x_fit + b_low, "b--", label=f"Fit: Zoom {zoom_low}")
|
||||
# x_fit = np.linspace(min(x_high), max(x_high), 100)
|
||||
# plt.plot(x_fit, m_high * x_fit + b_high, "r--", label=f"Fit: Zoom {zoom_high}")
|
||||
# plt.plot(x_fit, m_low * x_fit + b_low, "b--", label=f"Fit: Zoom {zoom_low}")
|
||||
|
||||
plt.scatter(x_intersect, y_intersect, color="green", s=80, zorder=5, label="Intersection")
|
||||
# plt.scatter(x_intersect, y_intersect, color="green", s=80, zorder=5, label="Intersection")
|
||||
|
||||
plt.xlabel("VFM Vert Position")
|
||||
plt.ylabel("SamCam Y")
|
||||
plt.title("Zoom Calibration")
|
||||
plt.legend()
|
||||
plt.grid(True)
|
||||
plt.tight_layout()
|
||||
plt.show()
|
||||
# plt.xlabel("VFM Vert Position")
|
||||
# plt.ylabel("SamCam Y")
|
||||
# plt.title("Zoom Calibration")
|
||||
# plt.legend()
|
||||
# plt.grid(True)
|
||||
# plt.tight_layout()
|
||||
# plt.show()
|
||||
|
||||
|
||||
def correlate_froll():
|
||||
@@ -620,37 +584,37 @@ def correlate_hfm_lat():
|
||||
plt.show()
|
||||
|
||||
|
||||
def correlate_vfm_vert():
|
||||
y_correlation = []
|
||||
vert = dev.vfm_vert.read()["vfm_vert"]["value"]
|
||||
scanpoints = np.linspace(vert - 0.06, vert + 0.06, 10)
|
||||
for pos in scanpoints:
|
||||
umv(dev.vfm_vert, pos)
|
||||
xpos, ypos = compute_pos()
|
||||
y_correlation.append(ypos)
|
||||
umv(dev.vfm_vert, vert)
|
||||
# def correlate_vfm_vert():
|
||||
# y_correlation = []
|
||||
# vert = dev.vfm_vert.read()["vfm_vert"]["value"]
|
||||
# scanpoints = np.linspace(vert - 0.06, vert + 0.06, 10)
|
||||
# for pos in scanpoints:
|
||||
# umv(dev.vfm_vert, pos)
|
||||
# xpos, ypos = compute_pos()
|
||||
# y_correlation.append(ypos)
|
||||
# umv(dev.vfm_vert, vert)
|
||||
|
||||
x = np.array(scanpoints)
|
||||
y1 = np.array(y_correlation)
|
||||
# x = np.array(scanpoints)
|
||||
# y1 = np.array(y_correlation)
|
||||
|
||||
yslope, yint = np.polyfit(x, y1, 1)
|
||||
# yslope, yint = np.polyfit(x, y1, 1)
|
||||
|
||||
print(f"Fit for xpos is: y = {yslope}.x + {yint}")
|
||||
plt.figure(figsize=(7, 5))
|
||||
# plt.scatter(x, y1, label='xpos')
|
||||
plt.scatter(x, y1, label="beam y position", color="rebeccapurple")
|
||||
# print(f"Fit for xpos is: y = {yslope}.x + {yint}")
|
||||
# plt.figure(figsize=(7, 5))
|
||||
# # plt.scatter(x, y1, label='xpos')
|
||||
# plt.scatter(x, y1, label="beam y position", color="rebeccapurple")
|
||||
|
||||
x_fit = np.linspace(min(x), max(x), 100)
|
||||
# plt.plot(x_fit, xslope*x_fit + xint, 'r--', label=f'y = {xslope}*x + {xint}')
|
||||
plt.plot(
|
||||
x_fit, yslope * x_fit + yint, label=f"y = {yslope:.5g}*x + ({yint:.5g})", color="lightcoral"
|
||||
)
|
||||
plt.xlabel("VFM vertical (mm)")
|
||||
plt.ylabel("beam Y(from BCU BPM)")
|
||||
plt.legend()
|
||||
plt.grid(True)
|
||||
plt.tight_layout()
|
||||
plt.show()
|
||||
# x_fit = np.linspace(min(x), max(x), 100)
|
||||
# # plt.plot(x_fit, xslope*x_fit + xint, 'r--', label=f'y = {xslope}*x + {xint}')
|
||||
# plt.plot(
|
||||
# x_fit, yslope * x_fit + yint, label=f"y = {yslope:.5g}*x + ({yint:.5g})", color="lightcoral"
|
||||
# )
|
||||
# plt.xlabel("VFM vertical (mm)")
|
||||
# plt.ylabel("beam Y(from BCU BPM)")
|
||||
# plt.legend()
|
||||
# plt.grid(True)
|
||||
# plt.tight_layout()
|
||||
# plt.show()
|
||||
|
||||
|
||||
def correlate_hfm_pitch():
|
||||
@@ -703,21 +667,21 @@ def move_to_x(targetx=0.13):
|
||||
umv(dev.hfm_lat, mot_new)
|
||||
|
||||
|
||||
def move_to_y(targety=-0.033):
|
||||
# Calibration and drift compensation
|
||||
# target from previous run = -0.283
|
||||
slope = -1.2779
|
||||
intercept = 2.4374
|
||||
# def move_to_y(targety=-0.033):
|
||||
# # Calibration and drift compensation
|
||||
# # target from previous run = -0.283
|
||||
# slope = -1.2779
|
||||
# intercept = 2.4374
|
||||
|
||||
xpos, ypos = compute_pos()
|
||||
# xpos, ypos = compute_pos()
|
||||
|
||||
beam_drift = ypos - targety # beam moved +0.1 mm (100 µm)
|
||||
mot_current = dev.vfm_vert.read()["vfm_vert"]["value"] # current motor position (example)
|
||||
# beam_drift = ypos - targety # beam moved +0.1 mm (100 µm)
|
||||
# mot_current = dev.vfm_vert.read()["vfm_vert"]["value"] # current motor position (example)
|
||||
|
||||
# Compute correction
|
||||
delta = -beam_drift / slope
|
||||
mot_new = mot_current + delta
|
||||
umv(dev.vfm_vert, mot_new)
|
||||
# # Compute correction
|
||||
# delta = -beam_drift / slope
|
||||
# mot_new = mot_current + delta
|
||||
# umv(dev.vfm_vert, mot_new)
|
||||
|
||||
|
||||
from epics import caget, caput
|
||||
@@ -792,34 +756,34 @@ def auto_exposure(
|
||||
return exposure
|
||||
|
||||
|
||||
def get_new_beamsizes(mirror):
|
||||
filename = f"luts/{mirror}_size.csv"
|
||||
if mirror == "hfm":
|
||||
bu = dev.hfm_bu
|
||||
bd = dev.hfm_bd
|
||||
step = 0.2
|
||||
else:
|
||||
bu = dev.vfm_bu
|
||||
bd = dev.vfm_bd
|
||||
step = 0.05
|
||||
beamsize("xs")
|
||||
move_targetx_with_hfm_lat()
|
||||
move_targety_with_vfm_vert()
|
||||
with open(filename, "w") as f:
|
||||
for _ in range(4):
|
||||
curr_bu = bu.user_readback.get()
|
||||
curr_bd = bd.user_readback.get()
|
||||
auto_exposure()
|
||||
umv(bu, curr_bu + step)
|
||||
umv(bd, curr_bd + step)
|
||||
move_targetx_with_hfm_lat()
|
||||
move_targety_with_vfm_vert()
|
||||
xpos = dev.samcam_x.read()["samcam_x"]["value"]
|
||||
ypos = dev.samcam_y.read()["samcam_y"]["value"]
|
||||
xsig = dev.samcam_xsig.read()["samcam_xsig"]["value"]
|
||||
ysig = dev.samcam_ysig.read()["samcam_ysig"]["value"]
|
||||
f.write(f"{curr_bu}, {curr_bd}, {xpos}, {ypos}, {xsig}, {ysig}\n")
|
||||
print(f"{curr_bu}, {curr_bd}, {xpos}, {ypos}, {xsig}, {ysig}")
|
||||
# def get_new_beamsizes(mirror):
|
||||
# filename = f"luts/{mirror}_size.csv"
|
||||
# if mirror == "hfm":
|
||||
# bu = dev.hfm_bu
|
||||
# bd = dev.hfm_bd
|
||||
# step = 0.2
|
||||
# else:
|
||||
# bu = dev.vfm_bu
|
||||
# bd = dev.vfm_bd
|
||||
# step = 0.05
|
||||
# beamsize("xs")
|
||||
# move_targetx_with_hfm_lat()
|
||||
# move_targety_with_vfm_vert()
|
||||
# with open(filename, "w") as f:
|
||||
# for _ in range(4):
|
||||
# curr_bu = bu.user_readback.get()
|
||||
# curr_bd = bd.user_readback.get()
|
||||
# auto_exposure()
|
||||
# umv(bu, curr_bu + step)
|
||||
# umv(bd, curr_bd + step)
|
||||
# move_targetx_with_hfm_lat()
|
||||
# move_targety_with_vfm_vert()
|
||||
# xpos = dev.samcam_x.read()["samcam_x"]["value"]
|
||||
# ypos = dev.samcam_y.read()["samcam_y"]["value"]
|
||||
# xsig = dev.samcam_xsig.read()["samcam_xsig"]["value"]
|
||||
# ysig = dev.samcam_ysig.read()["samcam_ysig"]["value"]
|
||||
# f.write(f"{curr_bu}, {curr_bd}, {xpos}, {ypos}, {xsig}, {ysig}\n")
|
||||
# print(f"{curr_bu}, {curr_bd}, {xpos}, {ypos}, {xsig}, {ysig}")
|
||||
|
||||
|
||||
def filters(pos="out"):
|
||||
@@ -832,6 +796,11 @@ def filters(pos="out"):
|
||||
if SE.scin.checkpos():
|
||||
auto_exposure(cam="samcam", max_iter=20)
|
||||
|
||||
def fnow():
|
||||
now = datetime.now()
|
||||
fnow = now.strftime("%Y%m%d-%H%M")
|
||||
filedir = "luts/"
|
||||
return filedir, fnow
|
||||
|
||||
def energy_vs_height(start_energy=11000, end_energy=25000, step=1000):
|
||||
"""Correlate beam height with energy from start_energy to end_energy in steps of step"""
|
||||
@@ -867,111 +836,6 @@ def energy_vs_height(start_energy=11000, end_energy=25000, step=1000):
|
||||
# umv(dev.id_gap, 20.0)
|
||||
|
||||
|
||||
@dataclass
|
||||
class SlitParameters:
|
||||
small: float
|
||||
large: float
|
||||
scanwidth: float
|
||||
steps: any
|
||||
x_size: any
|
||||
x_cen: any
|
||||
y_size: any
|
||||
y_cen: any
|
||||
mon: any
|
||||
|
||||
|
||||
# Generic scan function
|
||||
def scan_slits(name="s1", x=True, y=True):
|
||||
# Define parameters for all slits
|
||||
s1_params = SlitParameters(
|
||||
small=0.075,
|
||||
large=2.5,
|
||||
scanwidth=2.5,
|
||||
steps=40,
|
||||
x_size=dev.s1_xsize,
|
||||
y_size=dev.s1_ysize,
|
||||
x_cen=dev.s1_xcen,
|
||||
y_cen=dev.s1_ycen,
|
||||
mon=dev.lu_bpmsum,
|
||||
)
|
||||
s2_params = SlitParameters(
|
||||
small=0.075,
|
||||
large=3.0,
|
||||
scanwidth=2.5,
|
||||
steps=50,
|
||||
x_size=dev.s2_xsize,
|
||||
y_size=dev.s2_ysize,
|
||||
x_cen=dev.s2_xcen,
|
||||
y_cen=dev.s2_ycen,
|
||||
mon=dev.bcu_bpmsum,
|
||||
)
|
||||
s3_params = SlitParameters(
|
||||
small=0.05,
|
||||
large=0.5,
|
||||
scanwidth=0.7,
|
||||
steps=50,
|
||||
x_size=dev.s3_xsize,
|
||||
y_size=dev.s3_ysize,
|
||||
x_cen=dev.s3_xcen,
|
||||
y_cen=dev.s3_ycen,
|
||||
mon=dev.i1,
|
||||
)
|
||||
|
||||
# Map slit names to their parameters
|
||||
slit_parameters = {"s1": s1_params, "s2": s2_params, "s3": s3_params}
|
||||
|
||||
if name not in slit_parameters:
|
||||
raise ValueError(f"Unknown slit name: {name}")
|
||||
|
||||
params = slit_parameters[name]
|
||||
print("Moving filters out")
|
||||
filters("out")
|
||||
|
||||
print("Moving i1 diode into position")
|
||||
SE.i1.mvin()
|
||||
|
||||
if x and y:
|
||||
scan_in_x(
|
||||
xsize=params.x_size,
|
||||
xcen=params.x_cen,
|
||||
mon=params.mon,
|
||||
small=params.small,
|
||||
large=params.large,
|
||||
width=params.scanwidth,
|
||||
steps=params.steps,
|
||||
)
|
||||
scan_in_y(
|
||||
ysize=params.y_size,
|
||||
ycen=params.y_cen,
|
||||
mon=params.mon,
|
||||
small=params.small,
|
||||
large=params.large,
|
||||
width=params.scanwidth,
|
||||
steps=params.steps,
|
||||
)
|
||||
if x and not y:
|
||||
scan_in_x(
|
||||
xsize=params.x_size,
|
||||
xcen=params.x_cen,
|
||||
mon=params.mon,
|
||||
small=params.small,
|
||||
large=params.large,
|
||||
width=params.scanwidth,
|
||||
steps=params.steps,
|
||||
)
|
||||
else:
|
||||
scan_in_y(
|
||||
ysize=params.y_size,
|
||||
ycen=params.y_cen,
|
||||
mon=params.mon,
|
||||
small=params.small,
|
||||
large=params.large,
|
||||
width=params.scanwidth,
|
||||
steps=params.steps,
|
||||
)
|
||||
|
||||
filters("in")
|
||||
|
||||
|
||||
def scan_in_x(xsize, xcen, mon, small, large, width, steps):
|
||||
umv(xsize, small)
|
||||
@@ -1015,35 +879,43 @@ def calc_from_centre(cam="samcam"):
|
||||
return read, diff_px
|
||||
|
||||
|
||||
def get_cam():
|
||||
umv(dev.scam_zoom, 100)
|
||||
def get_cam(low_zoom, high_zoom):
|
||||
umv(dev.scam_zoom, low_zoom)
|
||||
x = dev.samcam_x.read()["samcam_x"]["value"]
|
||||
y = dev.samcam_y.read()["samcam_y"]["value"]
|
||||
print(f"Low zoom: x = {x}, y = {y}")
|
||||
umv(dev.scam_zoom, 500)
|
||||
umv(dev.scam_zoom, high_zoom)
|
||||
x = dev.samcam_x.read()["samcam_x"]["value"]
|
||||
y = dev.samcam_y.read()["samcam_y"]["value"]
|
||||
print(f"High zoom: x = {x}, y = {y}")
|
||||
|
||||
|
||||
def read_currents():
|
||||
"""Read the individual bpm channels"""
|
||||
bpm1 = dev.bcu_bpm1.read()["bcu_bpm1"]["value"]
|
||||
bpm2 = dev.bcu_bpm2.read()["bcu_bpm2"]["value"]
|
||||
bpm3 = dev.bcu_bpm3.read()["bcu_bpm3"]["value"]
|
||||
bpm4 = dev.bcu_bpm4.read()["bcu_bpm4"]["value"]
|
||||
# print(f"bpm1 = {bpm1:.3f}, bpm2 = {bpm2:.3f}, bpm3 = {bpm3:.3f}, bpm4 = {bpm4:.3f}")
|
||||
return {"bpm1": bpm1, "bpm2": bpm2, "bpm3": bpm3, "bpm4": bpm4}
|
||||
# def read_currents():
|
||||
# """Read the individual bpm channels"""
|
||||
# bpm1 = dev.bcu_bpm1.read()["bcu_bpm1"]["value"]
|
||||
# bpm2 = dev.bcu_bpm2.read()["bcu_bpm2"]["value"]
|
||||
# bpm3 = dev.bcu_bpm3.read()["bcu_bpm3"]["value"]
|
||||
# bpm4 = dev.bcu_bpm4.read()["bcu_bpm4"]["value"]
|
||||
# # print(f"bpm1 = {bpm1:.3f}, bpm2 = {bpm2:.3f}, bpm3 = {bpm3:.3f}, bpm4 = {bpm4:.3f}")
|
||||
# return {"bpm1": bpm1, "bpm2": bpm2, "bpm3": bpm3, "bpm4": bpm4}
|
||||
|
||||
|
||||
def compute_norm():
|
||||
"""Compute normalised x and y positions"""
|
||||
readings = read_currents()
|
||||
total = readings["bpm1"] + readings["bpm2"] + readings["bpm3"] + readings["bpm4"]
|
||||
# print(f"Sum is {total:.2f}")
|
||||
xn = ((readings["bpm1"] + readings["bpm2"]) - (readings["bpm3"] + readings["bpm4"])) / total
|
||||
yn = ((readings["bpm1"] + readings["bpm3"]) - (readings["bpm2"] + readings["bpm4"])) / total
|
||||
return xn, yn
|
||||
# def compute_norm():
|
||||
# """Compute normalised x and y positions"""
|
||||
# readings = read_currents()
|
||||
# total = readings["bpm1"] + readings["bpm2"] + readings["bpm3"] + readings["bpm4"]
|
||||
# # print(f"Sum is {total:.2f}")
|
||||
# xn = ((readings["bpm1"] + readings["bpm2"]) - (readings["bpm3"] + readings["bpm4"])) / total
|
||||
# yn = ((readings["bpm1"] + readings["bpm3"]) - (readings["bpm2"] + readings["bpm4"])) / total
|
||||
# return xn, yn
|
||||
|
||||
def average_inten():
|
||||
vals_inten = []
|
||||
for _ in range(5):
|
||||
vals_inten.append(dev.bcu_bpmsum.read()['bcu_bpmsum']['value'])
|
||||
time.sleep(0.1)
|
||||
inten = np.mean(vals_inten)
|
||||
return inten
|
||||
|
||||
def mirror_pitch(mirror = 'vfm'):
|
||||
|
||||
@@ -1471,4 +1343,184 @@ def get_mirror_data(history_index: int):
|
||||
# "y_data": y_data,
|
||||
# "motor_name": motor_name,
|
||||
# "scan_number": scan_number,
|
||||
# }
|
||||
# }
|
||||
|
||||
|
||||
def record_beampos_until(stop_time_str, interval_minutes=10):
|
||||
"""
|
||||
Runs `record_beam()` every `interval_minutes` minutes
|
||||
until the next occurrence of the given stop time (HH:MM).
|
||||
"""
|
||||
|
||||
# Prepare the file
|
||||
now = datetime.now()
|
||||
fnow = now.strftime("%d%m%H%M")
|
||||
filename = f"luts/beampos/beam_pos_record_{fnow}.csv"
|
||||
scam_zoom = dev.scam_zoom.read()['scam_zoom']['value']
|
||||
umv(dev.scam_zoom, 1000)
|
||||
beam_size = "25 x 25"
|
||||
|
||||
energy = get_current_energy()
|
||||
|
||||
|
||||
# Write the header to the file
|
||||
with open(filename, "w", encoding="utf-8") as f:
|
||||
f.write(f"Beam size: {beam_size}, Energy: {energy:.0f} eV, Zoom: {scam_zoom}\n")
|
||||
# f.write("Time,BPM_x,BPM_y,Scin_x,Scin_y,BPM_x,BPM_y\n")
|
||||
f.write("Time,Scin_x,Scin_y,BPM_x,BPM_y\n")
|
||||
|
||||
|
||||
# Parse the stop time (HH:MM)
|
||||
stop_hour, stop_minute = map(int, stop_time_str.split(":"))
|
||||
end_time = now.replace(hour=stop_hour, minute=stop_minute, second=0, microsecond=0)
|
||||
|
||||
# If that time already passed today, set it for tomorrow
|
||||
if end_time <= now:
|
||||
end_time += timedelta(days=1)
|
||||
|
||||
print(f"Starting now ({now:%Y-%m-%d %H:%M}), running until {end_time:%Y-%m-%d %H:%M}")
|
||||
print(f"Interval: {interval_minutes} minutes\n")
|
||||
|
||||
while datetime.now() < end_time:
|
||||
record_beam(filename)
|
||||
next_run = datetime.now() + timedelta(minutes=interval_minutes)
|
||||
if next_run > end_time:
|
||||
break
|
||||
print(f"Next run at {next_run:%H:%M:%S}")
|
||||
time.sleep(interval_minutes * 60)
|
||||
|
||||
print(f"Finished — reached {end_time:%H:%M}.")
|
||||
|
||||
|
||||
|
||||
def record_beam(filename):
|
||||
"""
|
||||
Record the beam position to file.
|
||||
"""
|
||||
|
||||
# Perform the usual recording steps
|
||||
umv(dev.ss_f4_x, 10)
|
||||
auto_exposure(cam="samcam")
|
||||
time.sleep(2)
|
||||
now = datetime.now()
|
||||
|
||||
# Append data to the file
|
||||
with open(filename, "a", encoding="utf-8") as f:
|
||||
fnow = now.strftime("%H:%M:%S")
|
||||
xpos_cam = dev.samcam_x.read()["samcam_x"]["value"]
|
||||
ypos_cam = dev.samcam_y.read()["samcam_y"]["value"]
|
||||
x_bpm, y_bpm = get_beampos()
|
||||
print(f"Time is {fnow}, X position is {xpos_cam:.5g}, Y position is {ypos_cam:.5g}")
|
||||
# xpos, ypos = compute_pos()
|
||||
f.write(
|
||||
# f"{fnow}, {xpos: .5g}, {ypos: .4g}, {xpos_cam: .5g}, {ypos_cam: .4g}\n"
|
||||
f"{fnow},{xpos_cam: .5g},{ypos_cam: .4g},{x_bpm: .5g},{y_bpm: .5g}\n"
|
||||
)
|
||||
|
||||
umv(dev.ss_f4_x, 16)
|
||||
|
||||
|
||||
def analyse_beampos(file):
|
||||
"""Plot the recorded beam position data"""
|
||||
# Load the CSV file into a Pandas DataFrame
|
||||
filedir = "luts/beampos/"
|
||||
filename = filedir + file
|
||||
data = pd.read_csv(filename, skiprows=1)
|
||||
print(data.head())
|
||||
|
||||
# ref_bpmx = 0.110
|
||||
# ref_bmpy = -0.175
|
||||
ref_scinx = 1024
|
||||
ref_sciny = 980
|
||||
scam_zoom = 116
|
||||
|
||||
# Extract the first column (time) as the x-axis
|
||||
meas_time = data["Time"]
|
||||
|
||||
# subtract the reference positions from the measures position
|
||||
# data["bpm_x"] = data["bpm_x"] - ref_bpmx
|
||||
# data["bpm_y"] = data["bpm_y"] - ref_bmpy
|
||||
data["Scin_x"] = (data["Scin_x"] - ref_scinx) * calc_scam_microns(1)
|
||||
data["Scin_y"] = (data["Scin_y"] - ref_sciny) * calc_scam_microns(1)
|
||||
|
||||
|
||||
# Extract Y-position columns (all columns except the first column)
|
||||
y_positions = data.iloc[:, 1:] # Exclude the first column
|
||||
|
||||
fig, axs = plt.subplots(
|
||||
2, 2, figsize=(12, 8), layout="constrained"
|
||||
) # Create a 2x2 grid for subplots
|
||||
# Flatten axs for easy iteration (if axs is a 2D array of axes)
|
||||
axs = axs.flatten()
|
||||
# Specify which columns to color differently
|
||||
red_columns = ["bpm_x", "scin_x"]
|
||||
|
||||
for idx, column in enumerate(y_positions.columns):
|
||||
ax = axs[idx] # Select the current subplot
|
||||
|
||||
# Determine the color based on the column name
|
||||
color = "red" if column in red_columns else "blue"
|
||||
|
||||
# Plot the line and scatter with the chosen color
|
||||
ax.plot(meas_time, y_positions[column], color=color, linewidth=0.5) # Line plot
|
||||
ax.scatter(
|
||||
meas_time, y_positions[column], color=color, label=column
|
||||
) # Scatter plot
|
||||
|
||||
# Set x-axis tick positions and labels
|
||||
tick_positions = range(0, len(meas_time), 7) # Adjust the step size as needed
|
||||
ax.set_xticks(tick_positions)
|
||||
ax.set_xticklabels([meas_time[i] for i in tick_positions], rotation=45)
|
||||
|
||||
# Add labels, title, legend, and grid to each subplot
|
||||
ax.set_xlabel("Time")
|
||||
ax.set_ylabel("beam displacement (microns)")
|
||||
ax.set_title(f"Beam position at {column}")
|
||||
ax.legend()
|
||||
ax.grid(True)
|
||||
|
||||
# Show the resulting figure
|
||||
plt.show()
|
||||
|
||||
import time
|
||||
import numpy as np
|
||||
import matplotlib.pyplot as plt
|
||||
from epics import caget
|
||||
|
||||
|
||||
def scan_scin_focus():
|
||||
z0 = dev.diag_z.position
|
||||
|
||||
z_positions = np.linspace(-4,4,30)
|
||||
contrasts = []
|
||||
|
||||
|
||||
|
||||
for z in z_positions:
|
||||
umv(dev.diag_z, z)
|
||||
time.sleep(0.1)
|
||||
|
||||
sigma = dev.samcam_sigma.read()['samcam_sigma']['value']
|
||||
mean = dev.samcam_mean.read()['samcam_mean']['value']
|
||||
|
||||
contrast = sigma / mean if mean > 0 else 0
|
||||
contrasts.append(contrast)
|
||||
|
||||
print(f"z = {z:.4f}, sigma = {sigma:.3f}, mean = {mean:.3f}, contrast = {contrast:.5f}")
|
||||
|
||||
contrasts = np.asarray(contrasts)
|
||||
|
||||
best_idx = np.argmax(contrasts)
|
||||
best_z = z_positions[best_idx]
|
||||
|
||||
print(f"\nBest scintillator focus z = {best_z:.4f}")
|
||||
|
||||
umv(dev.diag_z,best_z)
|
||||
|
||||
plt.plot(z_positions, contrasts, "o-")
|
||||
plt.axvline(best_z, linestyle="--")
|
||||
plt.xlabel("Scintillator z")
|
||||
plt.ylabel("Sigma / Mean")
|
||||
plt.show()
|
||||
|
||||
return best_z, z_positions, contrasts
|
||||
@@ -105,6 +105,7 @@ def go_to_peak(
|
||||
settle: float = FitDefaults.SETTLE_TIME,
|
||||
confirm: bool = True,
|
||||
gomax: bool = False,
|
||||
negative: bool = False
|
||||
):
|
||||
"""
|
||||
Go to the peak of a signal by scanning a motor within a specified range and
|
||||
@@ -177,7 +178,10 @@ def go_to_peak(
|
||||
}
|
||||
|
||||
# Define and fit model to scan data
|
||||
fit_params = create_fit_parameters(False, FitDefaults.MODEL, FitDefaults.BASELINE)
|
||||
fit_params = create_fit_parameters(deriv = False,
|
||||
negative = False,
|
||||
model = FitDefaults.MODEL,
|
||||
baseline = FitDefaults.BASELINE)
|
||||
fit_result = fit(data, fit_params)
|
||||
|
||||
# Plot the fitted data if plot = True
|
||||
@@ -199,6 +203,7 @@ def fit_history(
|
||||
signal_name: str,
|
||||
deriv: bool = False,
|
||||
negative: bool = False,
|
||||
smoothing: bool = False,
|
||||
model: str = FitDefaults.MODEL,
|
||||
move_to_peak: bool = False,
|
||||
):
|
||||
|
||||
Reference in New Issue
Block a user