after p22760 before cleanup
This commit is contained in:
@@ -3,7 +3,8 @@ from loguru import logger
|
||||
from slic.devices.xoptics.aramis_attenuator import Attenuator
|
||||
from slic.devices.xoptics.pulsepicker import PulsePicker
|
||||
from slic.devices.xdiagnostics.intensitymonitor import IntensityMonitorPBPS
|
||||
from .Cristallina_mono import CristallinaMono
|
||||
#from .Cristallina_mono import CristallinaMono
|
||||
from .cristallina_mono import CristallinaMono
|
||||
from .alignment_laser import AlignmentLaser
|
||||
|
||||
from slic.devices.xoptics.kb import KBHor, KBVer
|
||||
|
||||
105
beamline/cristallina_mono.py
Executable file
105
beamline/cristallina_mono.py
Executable file
@@ -0,0 +1,105 @@
|
||||
from types import SimpleNamespace
|
||||
from time import sleep
|
||||
import numpy as np
|
||||
|
||||
from slic.core.adjustable import Adjustable, PVAdjustable, PVEnumAdjustable
|
||||
from slic.core.adjustable.pvchangemon import PVChangeMonitor
|
||||
from slic.core.device import Device
|
||||
from slic.utils.hastyepics import get_pv as PV
|
||||
from slic.devices.general.motor import Motor
|
||||
from slic.devices.cameras import CameraCA
|
||||
|
||||
class CristallinaMono(Device):
|
||||
"""Cristallina mono SAROP31-ODCC110"""
|
||||
def __init__(self, ID, name="Cristallina double-channel-cut monochromator", **kwargs):
|
||||
super().__init__(ID, name=name, **kwargs)
|
||||
|
||||
self.TX = Motor(ID + ":MOT_TX1")
|
||||
self.bragg1 = Motor(ID + ":MOT_RX1")
|
||||
self.bragg2 = Motor(ID + ":MOT_RX2")
|
||||
self.energy = Motor(ID + ":MOT_ENY")
|
||||
self.angle2_offset = Motor(ID + ":MOT_OFS")
|
||||
self.screen = CristallinaMonoScreen("SAROP31-PSCR110", name='SAROP31-PSCR110')
|
||||
|
||||
class CristallinaMonoScreen(Device):
|
||||
|
||||
def __init__(self, ID, name="Profile Monitor", **kwargs):
|
||||
super().__init__(ID, name=name, **kwargs)
|
||||
|
||||
self.cam = CameraCA(ID)
|
||||
|
||||
self.target = PVEnumAdjustable(ID + ":SCR_SP", name="target")
|
||||
self.target_pos = Motor(ID + ":MOT_TY1", name="target position")
|
||||
self.target_in_position = PVEnumAdjustable(ID + ":IN_POS",name="target in valid position")
|
||||
|
||||
def move_mono(self):
|
||||
return self.target.set_target_value(1)
|
||||
|
||||
def move_pink(self):
|
||||
return self.target.set_target_value(2)
|
||||
|
||||
def move_out(self):
|
||||
return self.target.set_target_value(0)
|
||||
|
||||
|
||||
|
||||
|
||||
# class DoubleCrystalMonoEnergy(Adjustable):
|
||||
|
||||
# def __init__(self, ID, name=None):
|
||||
# self.wait_time = 0.1
|
||||
|
||||
# pvname_setvalue = "SAROP21-ARAMIS:ENERGY_SP"
|
||||
# pvname_readback = "SAROP21-ARAMIS:ENERGY"
|
||||
# pvname_moving = "SAROP21-ODCM098:MOVING"
|
||||
# pvname_stop = "SAROP21-ODCM098:STOP.PROC"
|
||||
|
||||
# pv_setvalue = PV(pvname_setvalue)
|
||||
# pv_readback = PV(pvname_readback)
|
||||
# pv_moving = PV(pvname_moving)
|
||||
# pv_stop = PV(pvname_stop)
|
||||
|
||||
# units = pv_readback.units
|
||||
# super().__init__(ID, name=name, units=units)
|
||||
|
||||
# self.pvnames = SimpleNamespace(
|
||||
# setvalue = pvname_setvalue,
|
||||
# readback = pvname_readback,
|
||||
# moving = pvname_moving,
|
||||
# stop = pvname_stop
|
||||
# )
|
||||
|
||||
# self.pvs = SimpleNamespace(
|
||||
# setvalue = pv_setvalue,
|
||||
# readback = pv_readback,
|
||||
# moving = pv_moving,
|
||||
# stop = pv_stop
|
||||
# )
|
||||
|
||||
|
||||
# def get_current_value(self):
|
||||
# return self.pvs.readback.get()
|
||||
|
||||
# def set_current_value(self, value):
|
||||
# self.pvs.setvalue.put(value)
|
||||
# sleep(3)
|
||||
|
||||
# def set_target_value(self, value):
|
||||
# self.set_current_value(value)
|
||||
# # while abs(self.wait_for_valid_value() - value) > accuracy:
|
||||
# while self.is_moving():
|
||||
# sleep(self.wait_time)
|
||||
|
||||
|
||||
# def wait_for_valid_value(self):
|
||||
# val = np.nan
|
||||
# while not np.isfinite(val):
|
||||
# val = self.get_current_value()
|
||||
# return val
|
||||
|
||||
# def is_moving(self):
|
||||
# moving = self.pvs.moving.get()
|
||||
# return bool(moving)
|
||||
|
||||
# def stop(self):
|
||||
# self.pvs.stop.put(1)
|
||||
@@ -26,17 +26,16 @@ N_UNDS = list(range(3, 15 + 1))
|
||||
|
||||
### SETTINGS ####
|
||||
|
||||
PSSS_MOVE = True
|
||||
DCCM_MOVE = True
|
||||
PSSS_MOVE = False
|
||||
DCCM_MOVE = False
|
||||
TRAJECTORY_FEEDBACK_DISABLE_ENABLE = False
|
||||
POINTING_FEEDFORWARD = False
|
||||
|
||||
energy_offset_undulators = 52 # eV
|
||||
energy_offset_PSSS = 2 # eV
|
||||
energy_offset_undulators = 43 # eV
|
||||
energy_offset_PSSS = 0 # eV
|
||||
energy_offset_DCCM = 0 # eV
|
||||
|
||||
DCCM_RX2_energy_offset = 1.6 # eV
|
||||
# eV
|
||||
DCCM_RX2_angle_offset = 0.0617 # deg
|
||||
|
||||
################
|
||||
|
||||
@@ -49,8 +48,8 @@ def print_configuration():
|
||||
print(f"Undulator energy offset = {energy_offset_undulators}")
|
||||
print(f"PSSS energy offset = {energy_offset_PSSS}")
|
||||
print(f"DCCM energy offset = {energy_offset_DCCM}")
|
||||
print(f" DCCM RX2 energy offset = {DCCM_RX2_energy_offset}")
|
||||
|
||||
# print(f" DCCM RX2 energy offset = {DCCM_RX2_energy_offset}")
|
||||
print(f" DCCM RX2 angle offset = {DCCM_RX2_angle_offset}")
|
||||
|
||||
|
||||
def pointing_slope_X(energy):
|
||||
@@ -97,12 +96,19 @@ def set_DCCM_energy(energy: float):
|
||||
DCCM_energy_PV_name = "SAROP31-ODCC110:MOT_ENY"
|
||||
DCCM_energy_PV = PV(DCCM_energy_PV_name)
|
||||
|
||||
DCCM_energy_offset_PV_name = "SAROP31-ODCC110:MOT_OFS"
|
||||
DCCM_energy_offset_PV = PV(DCCM_energy_offset_PV_name)
|
||||
# DCCM_energy_offset_PV_name = "SAROP31-ODCC110:MOT_OFS"
|
||||
# DCCM_energy_offset_PV = PV(DCCM_energy_offset_PV_name)
|
||||
|
||||
DCCM_energy_offset_PV.put(DCCM_RX2_energy_offset, wait=True)
|
||||
# DCCM_energy_offset_PV.put(DCCM_RX2_energy_offset, wait=True)
|
||||
# DCCM_energy_PV.put(energy, wait=False)
|
||||
# DCCM_energy_offset_PV.put(DCCM_RX2_energy_offset, wait=False)#
|
||||
|
||||
DCCM_angle_offset_PV_name = "SAROP31-ODCC110:MOT_OFS"
|
||||
DCCM_angle_offset_PV = PV(DCCM_angle_offset_PV_name)
|
||||
|
||||
DCCM_angle_offset_PV.put(DCCM_RX2_angle_offset, wait=True)
|
||||
DCCM_energy_PV.put(energy, wait=False)
|
||||
DCCM_energy_offset_PV.put(DCCM_RX2_energy_offset, wait=False)
|
||||
DCCM_angle_offset_PV.put(DCCM_RX2_angle_offset, wait=False)
|
||||
|
||||
print(f"Finished adjusting DCCM.")
|
||||
|
||||
|
||||
@@ -6,13 +6,13 @@
|
||||
from slic.core.acquisition.detcfg import DetectorConfig
|
||||
|
||||
# TODO: JF settings regarding raw conversion, compression, etc.
|
||||
detectors = [
|
||||
"JF16T03V02", # 1.5M from 2025
|
||||
#detectors = [
|
||||
# "JF16T03V02", # 1.5M from 2025
|
||||
# "JF16T03V01", # 1.5M from 2022
|
||||
# "JF17T16V01", # 8M
|
||||
"JF20T01V01", # IO
|
||||
# "JF20T01V01", # IO
|
||||
# "JF05T01V01", # 0.5M stripsel borrowed from Bernina, now registered in esc network
|
||||
]
|
||||
#]
|
||||
|
||||
# ALLOWED_PARAMS = dict(
|
||||
# adc_to_energy = bool,
|
||||
@@ -28,7 +28,7 @@ detectors = [
|
||||
# save_dap_results = bool
|
||||
# )
|
||||
|
||||
detectors = DetectorConfig(detectors)
|
||||
detectors = DetectorConfig("JF16T03V02","JF20T01V01")
|
||||
# detectors_with_config["JF16T03V01"]['save_dap_results'] = True
|
||||
|
||||
# JF 1.5M default settings
|
||||
@@ -38,6 +38,7 @@ detectors["JF16T03V02"]['adc_to_energy'] = True
|
||||
detectors["JF16T03V02"]['compression'] = True
|
||||
detectors["JF16T03V02"]['save_dap_results'] = False
|
||||
detectors["JF16T03V02"]['geometry'] = True
|
||||
#detectors["JF16T03V02"]['disabled_modules'] = [0, 2] # bottom module:0, middle module:1, top module:2
|
||||
|
||||
# I0 JF default settings
|
||||
detectors["JF20T01V01"]['remove_raw_files'] = True
|
||||
@@ -47,6 +48,16 @@ detectors["JF20T01V01"]['compression'] = True
|
||||
detectors["JF20T01V01"]['save_dap_results'] = False
|
||||
detectors["JF20T01V01"]['geometry'] = False
|
||||
|
||||
# JF 8M default settings
|
||||
# detectors["JF17T16V01"]['remove_raw_files'] = True # We switched off quite a few modules, let's not keep all the raw data.
|
||||
# detectors["JF17T16V01"]['factor'] = 0.1 # Some useful compromise to save space.
|
||||
# detectors["JF17T16V01"]['adc_to_energy'] = True # We switched off quite a few modules, let's not keep all the raw data.
|
||||
# detectors["JF17T16V01"]['compression'] = True
|
||||
# detectors["JF17T16V01"]['save_dap_results'] = False
|
||||
# detectors["JF17T16V01"]['geometry'] = True
|
||||
#detectors["JF17T16V01"]['disabled_modules'] = [0, 1, 2, 3, 9, 10, 11, 12, 13, 14, 15]
|
||||
|
||||
|
||||
|
||||
detectors_I0_only = DetectorConfig(["JF20T01V01"])
|
||||
# I0 JF settings with finer resolution
|
||||
@@ -555,7 +566,7 @@ bs_channels = (
|
||||
+ channels_PSCD153
|
||||
+ channels_EVR
|
||||
+ channels_digitizer
|
||||
# + channels_Xeye
|
||||
#+ channels_Xeye
|
||||
+ diffractometer_1_bs
|
||||
+ diffractometer_2_bs
|
||||
# + camera_channels
|
||||
|
||||
@@ -300,7 +300,6 @@ pvs_OOMV092_bernina = [
|
||||
|
||||
pvs_PPRM094_bernina = [
|
||||
"SAROP21-PPRM113:MOTOR_PROBE",
|
||||
#"SAROP21-PPRM113:FPICTURE",
|
||||
]
|
||||
|
||||
|
||||
@@ -863,6 +862,7 @@ pvs_diffractometer_extras = [
|
||||
###############################
|
||||
# DilSc
|
||||
|
||||
# LakeShore
|
||||
ID_DilSc_LakeShore = "SARES31-DIL-LS1"
|
||||
pvs_DilSc_Lakeshore = [
|
||||
ID_DilSc_LakeShore + ":A_KELVIN",
|
||||
@@ -873,14 +873,33 @@ pvs_DilSc_Lakeshore = [
|
||||
ID_DilSc_LakeShore + ":7_RES",
|
||||
ID_DilSc_LakeShore + ":8_RES",
|
||||
|
||||
ID_DilSc_LakeShore + ":1_RES",
|
||||
ID_DilSc_LakeShore + ":2_RES",
|
||||
ID_DilSc_LakeShore + ":3_RES",
|
||||
|
||||
ID_DilSc_LakeShore + ":A_EX_STRING.SVAL",
|
||||
ID_DilSc_LakeShore + ":7_EX_STRING.SVAL",
|
||||
ID_DilSc_LakeShore + ":8_EX_STRING.SVAL",
|
||||
|
||||
ID_DilSc_LakeShore + ":1_EX_STRING.SVAL",
|
||||
ID_DilSc_LakeShore + ":2_EX_STRING.SVAL",
|
||||
ID_DilSc_LakeShore + ":3_EX_STRING.SVAL",
|
||||
|
||||
ID_DilSc_LakeShore + ":H0_SETP_GET",
|
||||
ID_DilSc_LakeShore + ":H0_PWR_GET",
|
||||
]
|
||||
|
||||
# Magnet Mercury iPS
|
||||
ID_DilSc_MagnetPSU = "SARES31-MAG-IPS1"
|
||||
|
||||
pvs_DilSc_MagnetPSU = []
|
||||
for axis in ['X','Y','Z']:
|
||||
ID_with_axis = f'{ID_DilSc_MagnetPSU}'+'-'+f'{axis}'
|
||||
pvs_DilSc_MagnetPSU.append( ID_with_axis + ':SIG_FLD' )
|
||||
pvs_DilSc_MagnetPSU.append( ID_with_axis + ':SIG_FSET' )
|
||||
pvs_DilSc_MagnetPSU.append( ID_with_axis + ':SIG_RFST' )
|
||||
pvs_DilSc_MagnetPSU.append( ID_with_axis + ':ACTN' )
|
||||
|
||||
###############################
|
||||
# PuMa Aerotech motor controller
|
||||
|
||||
@@ -970,11 +989,13 @@ pv_channels = (
|
||||
+ pvs_standa
|
||||
# + pvs_newport_300
|
||||
# + pvs_smaract_xyz
|
||||
# + pvs_diffractometer_1
|
||||
+ pvs_diffractometer_2
|
||||
+ pvs_diffractometer_extras
|
||||
# + pvs_DilSc_Lakeshore
|
||||
+ pvs_PuMa_Aerotech
|
||||
+ pvs_diffractometer_1
|
||||
# + pvs_diffractometer_2
|
||||
# these do not work properly at the moment:
|
||||
# + pvs_diffractometer_extras
|
||||
+ pvs_DilSc_Lakeshore
|
||||
+ pvs_DilSc_MagnetPSU
|
||||
# + pvs_PuMa_Aerotech
|
||||
+ pvs_huber_z
|
||||
+ pvs_JJ_slits
|
||||
# + pvs_attocube
|
||||
|
||||
@@ -38,7 +38,8 @@ def setup_general_logging():
|
||||
def setup_logging_pgroup(pgroup, level="INFO"):
|
||||
try:
|
||||
logger.add(
|
||||
f"/sf/cristallina/data/{pgroup}/scratch/slic.log",
|
||||
# f"/sf/cristallina/data/{pgroup}/scratch/slic.log",
|
||||
f"/sf/cristallina/data/{pgroup}/res/slic.log",
|
||||
format="{time:YYYY-MM-DD at HH:mm:ss} | {level} | {message}",
|
||||
level=level,
|
||||
rotation="1 week",
|
||||
@@ -135,11 +136,10 @@ from beamline import photon_energy
|
||||
cr_photon_energy = photon_energy.PhotonEnergy()
|
||||
|
||||
# added limit to photon energy setpoint
|
||||
cr_photon_energy.set_limits(5720-100, 5720+100)
|
||||
cr_photon_energy.set_limits(5000, 13000)
|
||||
|
||||
|
||||
logger.info(f"Photon energy offsets: PSSS {photon_energy.energy_offset_PSSS} eV , DCCM {photon_energy.energy_offset_DCCM} eV, undulator {photon_energy.energy_offset_undulators} eV.")
|
||||
|
||||
logger.info(f"Photon energy offsets: PSSS {photon_energy.energy_offset_PSSS} eV, DCCM {photon_energy.energy_offset_DCCM} eV, undulator {photon_energy.energy_offset_undulators} eV.")
|
||||
|
||||
|
||||
|
||||
@@ -167,19 +167,19 @@ dm1 = Diffractometer("SARES31-GPS")
|
||||
dm2 = Diffractometer("SARES32-GPS")
|
||||
|
||||
# Set according to which diffractometer is being used
|
||||
diffractometer = dm2
|
||||
diffractometer = dm1
|
||||
|
||||
# Dilution fridge
|
||||
#from crq_exp.dilsc import Dilution
|
||||
from crq_exp.dilsc import Dilution
|
||||
|
||||
try:
|
||||
dilution = Dilution()
|
||||
dilution = Dilution('SARES31-DIL-LS1','SARES31-MAG-IPS1')
|
||||
except Exception as e:
|
||||
logger.warning(f"Error: Could not connect to dilution fridge. {e}")
|
||||
dilution = None
|
||||
|
||||
|
||||
# MX adajustables
|
||||
# MX adjustables
|
||||
# import mx.mx_adjustables
|
||||
|
||||
# Temporary quick hack thermometer addition for stand
|
||||
@@ -196,8 +196,8 @@ downstream_transmission = PVAdjustable("SARFE10-OATT053:UsrRec.TC1")
|
||||
|
||||
|
||||
|
||||
from crq_exp.puma import Puma
|
||||
puma = Puma()
|
||||
# from crq_exp.puma import Puma
|
||||
# puma = Puma()
|
||||
|
||||
|
||||
################# Stand setup ##################
|
||||
@@ -225,25 +225,25 @@ adjs_for_spreadsheet = {
|
||||
"TRYBASE": diffractometer.try_base,
|
||||
"THETA": diffractometer.theta,
|
||||
"TWOTHETA": diffractometer.twotheta,
|
||||
"Sample_X": puma.sample_x,
|
||||
"Sample_Y": puma.sample_y,
|
||||
"Sample_Z": puma.sample_z,
|
||||
"Sample_R": puma.sample_r,
|
||||
"Magnet_X": puma.magnet_x,
|
||||
"Magnet_Y": puma.magnet_y,
|
||||
"Magnet_Z": puma.magnet_z,
|
||||
# PuMa positions if available:
|
||||
# "Sample_X": puma.sample_x,
|
||||
# "Sample_Y": puma.sample_y,
|
||||
# " Sample_Z": puma.sample_z,
|
||||
# "Sample_R": puma.sample_r,
|
||||
# "Magnet_X": puma.magnet_x,
|
||||
# "Magnet_Y": puma.magnet_y,
|
||||
# "Magnet_Z": puma.magnet_z,
|
||||
}
|
||||
|
||||
dilution = None
|
||||
|
||||
if dilution is not None:
|
||||
adjs_dilsc = {
|
||||
#"Magnet_X": dilution.x,
|
||||
#"Magnet_Y": dilution.y,
|
||||
#"Magnet_Z": dilution.z,
|
||||
"DilSc_T_chip": T_chip,
|
||||
"DilSc_T_plato": T_plato,
|
||||
#"DilSc_T_chip": dilution.T_chip,
|
||||
"DilSc_T_pucksensor": T_reg,
|
||||
"Magnet_X": dilution.x,
|
||||
"Magnet_Y": dilution.y,
|
||||
"Magnet_Z": dilution.z,
|
||||
"DilSc_T_reg": dilution.T_CHA,
|
||||
"DilSc_T_CH7": dilution.T_CH7,
|
||||
"DilSc_T_CH8": dilution.T_CH8,
|
||||
}
|
||||
adjs_for_spreadsheet.update(adjs_dilsc)
|
||||
|
||||
@@ -260,6 +260,7 @@ spreadsheet = Spreadsheet(
|
||||
port=9090,
|
||||
)
|
||||
|
||||
|
||||
try:
|
||||
from stand.client import Client
|
||||
stand_host = "saresc-vcons-02.psi.ch"
|
||||
@@ -332,7 +333,7 @@ DAQS = multiple_daqs.generate_DAQS(instrument, pgroup, bs_channels, pv_channels,
|
||||
# required fraction defines amount of data recorded to save the step and move on to the next one
|
||||
check_intensity_gas_monitor = PVCondition(
|
||||
"SARFE10-PBPG050:PHOTON-ENERGY-PER-PULSE-US",
|
||||
vmin=400,
|
||||
vmin=500,
|
||||
vmax=2000,
|
||||
wait_time=0.5,
|
||||
required_fraction=0.8,
|
||||
@@ -363,20 +364,21 @@ temperature_setpoint=PVAdjustable('SARES31-DIL-LS1:H0_SETP_SET')
|
||||
|
||||
# d fixed to 3.0 mm, x_0 = 4.574 mm and theta_0 = -67.853 deg
|
||||
import numpy as np
|
||||
d = 3
|
||||
theta_0 = -67.853
|
||||
x_0 = 4.574
|
||||
thetas = np.linspace(-2, 25)
|
||||
TRX = d * np.sin(np.deg2rad(thetas + theta_0)) + x_0
|
||||
linked_theta = LinkedInterpolated("ThetaLinked", diffractometer.theta, diffractometer.tr_x, thetas, TRX)
|
||||
|
||||
# d = 3
|
||||
# theta_0 = -67.853
|
||||
# x_0 = 4.574
|
||||
# thetas = np.linspace(-2, 25)
|
||||
# TRX = d * np.sin(np.deg2rad(thetas + theta_0)) + x_0
|
||||
# linked_theta = LinkedInterpolated("ThetaLinked", diffractometer.theta, diffractometer.tr_x, thetas, TRX)
|
||||
|
||||
# Sample 3
|
||||
d = 2.5000000
|
||||
x_0 = 4.04466204
|
||||
theta_0 = -64.1376413
|
||||
thetas = np.linspace(-10, 15)
|
||||
TRX = d * np.sin(np.deg2rad(thetas + theta_0)) + x_0
|
||||
linked_theta_s3 = LinkedInterpolated("ThetaLinked", diffractometer.theta, diffractometer.tr_x, thetas, TRX)
|
||||
# d = 2.5000000
|
||||
# x_0 = 4.04466204
|
||||
# theta_0 = -64.1376413
|
||||
# thetas = np.linspace(-10, 15)
|
||||
# TRX = d * np.sin(np.deg2rad(thetas + theta_0)) + x_0
|
||||
# linked_theta_s3 = LinkedInterpolated("ThetaLinked", diffractometer.theta, diffractometer.tr_x, thetas, TRX)
|
||||
|
||||
|
||||
# Beware: double_pixels_action interpolate does not seem to work, results in empty data
|
||||
@@ -415,7 +417,7 @@ daq_1p5M_I0 = SFAcquisition(
|
||||
spreadsheet=spreadsheet)
|
||||
|
||||
|
||||
from tqdm.notebook import tqdm
|
||||
|
||||
|
||||
def scan_with_sync(adjustable, start_pos, end_pos, step_size, n_pulses, filename, acquisitions = [daq], return_to_initial_values=False, condition=check_intensity_gas_monitor, spreadsheet=spreadsheet):
|
||||
"""
|
||||
|
||||
182
crq_exp/dilsc-frappy.py
Executable file
182
crq_exp/dilsc-frappy.py
Executable file
@@ -0,0 +1,182 @@
|
||||
""" DilSc prototype
|
||||
|
||||
"""
|
||||
|
||||
from slic.core.adjustable import Adjustable, PVAdjustable
|
||||
|
||||
from slic.core.device import Device, SimpleDevice
|
||||
|
||||
from frappy.client import SecopClient
|
||||
from frappy import states
|
||||
from frappy.datatypes import StatusType
|
||||
|
||||
|
||||
class Dilution(Device):
|
||||
def __init__(self, **kwargs):
|
||||
|
||||
self.name = 'DilSc'
|
||||
ID = self.name
|
||||
super().__init__(ID, **kwargs)
|
||||
|
||||
self.address = 'dilsc.psi.ch:5000'
|
||||
self.dilsc = SecopClient(self.address)
|
||||
self.dilsc.connect()
|
||||
|
||||
self.x = MagnetCoil("X", self.dilsc, 'x', limit_low=-0.6, limit_high=0.6)
|
||||
self.y = MagnetCoil("Y", self.dilsc, 'y', limit_low=-0.6, limit_high=0.6)
|
||||
self.z = MagnetCoil("Z", self.dilsc, 'z', limit_low=-5.2, limit_high=5.2)
|
||||
self.T_plato = Thermometer('T_plato', self.dilsc, limit_low=0, limit_high=300)
|
||||
self.T_chip = Thermometer('T_chip', self.dilsc, limit_low=0, limit_high=300)
|
||||
self.T_reg = Thermometer('T_reg', self.dilsc, limit_low=0, limit_high=300)
|
||||
|
||||
class Thermometer(Adjustable):
|
||||
|
||||
def __init__(self, name, dilsc_connection, limit_low=-0.0001, limit_high=0.0001):
|
||||
|
||||
super().__init__(name, limit_low=limit_low, limit_high=limit_high)
|
||||
self.dilsc = dilsc_connection
|
||||
|
||||
# Heater to regulate channel A on the Galgen LakeShore372. Give value in Ohm.
|
||||
self.heater_resistance = 82
|
||||
# Defines heater ranges and PID values for various control temperature regions.
|
||||
self.heater_settings = [
|
||||
{'range': 'off', 'pid': (800, 1, 0), 'temp_start': -1, 'temp_end': 0.00099},
|
||||
{'range': '300uA', 'pid': (800, 1, 0), 'temp_start': 0.001, 'temp_end': 0.037},
|
||||
{'range': '1mA', 'pid': (40, 14, 0), 'temp_start': 0.038, 'temp_end': 0.108},
|
||||
{'range': '3mA', 'pid': (4, 15, 0), 'temp_start': 0.110, 'temp_end': 0.350},
|
||||
{'range': '10mA', 'pid': (2, 12, 0), 'temp_start': 0.352, 'temp_end': 1.100},
|
||||
{'range': '30mA', 'pid': (2, 60, 0), 'temp_start': 1.100, 'temp_end': 2.300}
|
||||
]
|
||||
|
||||
def _check_connection(func):
|
||||
def checker(self, *args, **kwargs):
|
||||
if not self.dilsc.online:
|
||||
raise ConnectionError(f'No connection to dilsc at {self.address}')
|
||||
else:
|
||||
return func(self, *args, **kwargs)
|
||||
return checker
|
||||
|
||||
@_check_connection
|
||||
def set_heater_range(self, range_value):
|
||||
""" Sets the heater range for the control channel and sets the PID parameters for the associated control loop.
|
||||
TODO: Consider redoing so that it only works for the T_reg channel.
|
||||
TODO: the pid values are now sent with stringio and not saved as parameters in slic, this should be fixed.
|
||||
-
|
||||
"""
|
||||
heater_range_map = {
|
||||
'off': 0, '30uA': 1, '100uA': 2, '300uA': 3, '1mA': 4, '3mA': 5, '10mA': 6, '30mA': 7, '100mA': 8}
|
||||
if range_value not in heater_range_map:
|
||||
raise ValueError("Invalid range value. Allowed are: ['off','30uA','100uA','300uA','1mA','3mA','10mA','30mA','100mA']")
|
||||
enum_value = heater_range_map[range_value]
|
||||
self.dilsc.setParameter(self.name, 'htrrng', enum_value)
|
||||
|
||||
for setting in self.heater_settings:
|
||||
if setting['range'] == range_value:
|
||||
self.set_PID_parameters(*setting['pid'])
|
||||
break
|
||||
return
|
||||
|
||||
@_check_connection
|
||||
def get_current_value(self):
|
||||
cacheitem = self.dilsc.getParameter(f'{self.name}', 'value', trycache=False)
|
||||
return cacheitem.value
|
||||
|
||||
|
||||
@_check_connection
|
||||
def set_target_value(self, value, adjust_heater_range=True):
|
||||
if adjust_heater_range:
|
||||
range_to_set = None
|
||||
for setting in self.heater_settings:
|
||||
if setting['temp_start'] <= value and setting['temp_end'] >= value:
|
||||
range_to_set = setting['range']
|
||||
if range_to_set != None:
|
||||
self.set_heater_range(range_to_set)
|
||||
else:
|
||||
raise ValueError(f"Heater range for the target value {value} could not be set")
|
||||
self.dilsc.setParameter(f'{self.name}', 'target', value)
|
||||
|
||||
@_check_connection
|
||||
def get_target_value(self):
|
||||
cacheitem = self.dilsc.getParameter(f'{self.name}', 'target', trycache=False)
|
||||
return cacheitem.value
|
||||
|
||||
|
||||
@_check_connection
|
||||
def is_moving(self):
|
||||
response = self.dilsc.getParameter(f'{self.name}','status', trycache=False)
|
||||
return response[0][0] > StatusType.PREPARED
|
||||
|
||||
@_check_connection
|
||||
def get_PID_parameters(self):
|
||||
""" Returns the current PID parameters associated with the control loop for
|
||||
this thermometer.
|
||||
"""
|
||||
# response = self.dilsc.getParameter(f'{self.name}','ctrlpars', trycache=False)
|
||||
response = self.dilsc.execCommand('lscio', 'communicate', 'PID?')
|
||||
return response
|
||||
|
||||
@_check_connection
|
||||
def set_PID_parameters(self, p, i, d):
|
||||
""" Sets the PID parameters for the associated control loop.
|
||||
TODO:
|
||||
- This still returns a timeout error but sets the correct values.
|
||||
- The range is limited to less than the Lakeshore range allows, this needs
|
||||
to be fixed in frappy.
|
||||
"""
|
||||
# self.dilsc.setParameter(f'{self.name}', 'ctrlpars', {'p': p, 'i': i, 'd': d})
|
||||
command_string = f'PID {0},{p},{i},{d}; PID?'
|
||||
self.dilsc.execCommand('lscio', 'communicate', command_string)
|
||||
|
||||
|
||||
class MagnetCoil(Adjustable):
|
||||
|
||||
def __init__(self, name, dilsc_connection, direction, limit_low=-0.0001, limit_high=0.0001):
|
||||
|
||||
super().__init__(name, limit_low=-0.0001, limit_high=0.0001)
|
||||
|
||||
self.direction = direction.lower()
|
||||
|
||||
if self.direction not in ["x", "y", "z"]:
|
||||
raise ValueError("Direction must be either x, y or z.")
|
||||
|
||||
self.dilsc = dilsc_connection
|
||||
|
||||
|
||||
def _check_connection(func):
|
||||
def checker(self, *args, **kwargs):
|
||||
if not self.dilsc.online:
|
||||
raise ConnectionError(f'No connection to dilsc at {self.address}')
|
||||
else:
|
||||
return func(self, *args, **kwargs)
|
||||
return checker
|
||||
|
||||
@_check_connection
|
||||
def get_current_value(self):
|
||||
cacheitem = self.dilsc.getParameter(f'mf{self.direction}', 'value', trycache=False)
|
||||
return cacheitem.value
|
||||
|
||||
|
||||
@_check_connection
|
||||
def set_target_value(self, value):
|
||||
self.dilsc.setParameter(f'mf{self.direction}', 'target', value)
|
||||
|
||||
@_check_connection
|
||||
def is_moving(self):
|
||||
response = self.dilsc.getParameter(f'mf{self.direction}','status', trycache=False)
|
||||
return response[0][0] > StatusType.PREPARED
|
||||
|
||||
@_check_connection
|
||||
def set_ramp_speed(self, direction, value):
|
||||
""" Sets ramp speed for a given direction (x,y or z) and value in T/min.
|
||||
"""
|
||||
if value > 0.5:
|
||||
raise ValueError('Do not exceed 0.5 T/min unless you want a quench party')
|
||||
if value <= 0:
|
||||
raise ValueError('Only positive values are allowed')
|
||||
if self.direction not in ["x", "y", "z"]:
|
||||
raise ValueError("Direction must be either x, y or z.")
|
||||
else:
|
||||
self.dilsc.setParameter(direction, 'ramp', value)
|
||||
return
|
||||
|
||||
|
||||
213
crq_exp/dilsc.py
213
crq_exp/dilsc.py
@@ -1,182 +1,75 @@
|
||||
""" DilSc prototype
|
||||
|
||||
""" DilSc prototype with Edwin's EPICS panels
|
||||
"""
|
||||
|
||||
from slic.core.adjustable import Adjustable, PVAdjustable
|
||||
|
||||
from slic.core.adjustable import Adjustable, PVAdjustable, Collection
|
||||
from slic.core.device import Device, SimpleDevice
|
||||
|
||||
from frappy.client import SecopClient
|
||||
from frappy import states
|
||||
from frappy.datatypes import StatusType
|
||||
|
||||
import time
|
||||
import numpy as np
|
||||
|
||||
class Dilution(Device):
|
||||
def __init__(self, **kwargs):
|
||||
|
||||
def __init__(self, ID_DilSc_LakeShore, ID_DilSc_MagnetPSU, **kwargs):
|
||||
|
||||
super().__init__(ID_DilSc_LakeShore,ID_DilSc_MagnetPSU, **kwargs)
|
||||
|
||||
self.name = 'DilSc'
|
||||
ID = self.name
|
||||
super().__init__(ID, **kwargs)
|
||||
|
||||
self.address = 'dilsc.psi.ch:5000'
|
||||
self.dilsc = SecopClient(self.address)
|
||||
self.dilsc.connect()
|
||||
self.ID_DilSc_LakeShore = ID_DilSc_LakeShore
|
||||
|
||||
self.x = MagnetCoil("X", self.dilsc, 'x', limit_low=-0.6, limit_high=0.6)
|
||||
self.y = MagnetCoil("Y", self.dilsc, 'y', limit_low=-0.6, limit_high=0.6)
|
||||
self.z = MagnetCoil("Z", self.dilsc, 'z', limit_low=-5.2, limit_high=5.2)
|
||||
self.T_plato = Thermometer('T_plato', self.dilsc, limit_low=0, limit_high=300)
|
||||
self.T_chip = Thermometer('T_chip', self.dilsc, limit_low=0, limit_high=300)
|
||||
self.T_reg = Thermometer('T_reg', self.dilsc, limit_low=0, limit_high=300)
|
||||
|
||||
class Thermometer(Adjustable):
|
||||
|
||||
def __init__(self, name, dilsc_connection, limit_low=-0.0001, limit_high=0.0001):
|
||||
self.x = MagnetCoil(ID_DilSc_MagnetPSU, 'X', limit_low=-0.6, limit_high=0.6)
|
||||
self.y = MagnetCoil(ID_DilSc_MagnetPSU, 'Y', limit_low=-0.6, limit_high=0.6)
|
||||
self.z = MagnetCoil(ID_DilSc_MagnetPSU, 'Z', limit_low=-5.2, limit_high=5.2)
|
||||
|
||||
super().__init__(name, limit_low=limit_low, limit_high=limit_high)
|
||||
self.dilsc = dilsc_connection
|
||||
self.T_CHA = PVAdjustable(ID_DilSc_LakeShore + ":A_KELVIN")
|
||||
self.T_CH7 = PVAdjustable(ID_DilSc_LakeShore + ":7_KELVIN")
|
||||
self.T_CH8 = PVAdjustable(ID_DilSc_LakeShore + ":8_KELVIN")
|
||||
|
||||
# Heater to regulate channel A on the Galgen LakeShore372. Give value in Ohm.
|
||||
self.heater_resistance = 82
|
||||
# Defines heater ranges and PID values for various control temperature regions.
|
||||
self.heater_settings = [
|
||||
{'range': 'off', 'pid': (800, 1, 0), 'temp_start': -1, 'temp_end': 0.00099},
|
||||
{'range': '300uA', 'pid': (800, 1, 0), 'temp_start': 0.001, 'temp_end': 0.037},
|
||||
{'range': '1mA', 'pid': (40, 14, 0), 'temp_start': 0.038, 'temp_end': 0.108},
|
||||
{'range': '3mA', 'pid': (4, 15, 0), 'temp_start': 0.110, 'temp_end': 0.350},
|
||||
{'range': '10mA', 'pid': (2, 12, 0), 'temp_start': 0.352, 'temp_end': 1.100},
|
||||
{'range': '30mA', 'pid': (2, 60, 0), 'temp_start': 1.100, 'temp_end': 2.300}
|
||||
]
|
||||
|
||||
def _check_connection(func):
|
||||
def checker(self, *args, **kwargs):
|
||||
if not self.dilsc.online:
|
||||
raise ConnectionError(f'No connection to dilsc at {self.address}')
|
||||
else:
|
||||
return func(self, *args, **kwargs)
|
||||
return checker
|
||||
self.T_reg_setpoint = PVAdjustable(ID_DilSc_LakeShore + ':H0_SETP_SET')
|
||||
|
||||
@_check_connection
|
||||
def set_heater_range(self, range_value):
|
||||
""" Sets the heater range for the control channel and sets the PID parameters for the associated control loop.
|
||||
TODO: Consider redoing so that it only works for the T_reg channel.
|
||||
TODO: the pid values are now sent with stringio and not saved as parameters in slic, this should be fixed.
|
||||
-
|
||||
"""
|
||||
heater_range_map = {
|
||||
'off': 0, '30uA': 1, '100uA': 2, '300uA': 3, '1mA': 4, '3mA': 5, '10mA': 6, '30mA': 7, '100mA': 8}
|
||||
if range_value not in heater_range_map:
|
||||
raise ValueError("Invalid range value. Allowed are: ['off','30uA','100uA','300uA','1mA','3mA','10mA','30mA','100mA']")
|
||||
enum_value = heater_range_map[range_value]
|
||||
self.dilsc.setParameter(self.name, 'htrrng', enum_value)
|
||||
|
||||
for setting in self.heater_settings:
|
||||
if setting['range'] == range_value:
|
||||
self.set_PID_parameters(*setting['pid'])
|
||||
break
|
||||
return
|
||||
self.heater = SimpleDevice('DilSc sample heater', p = PVAdjustable(ID_DilSc_LakeShore + ':H0_PID_P'),
|
||||
i = PVAdjustable(ID_DilSc_LakeShore + ':H0_PID_I'),
|
||||
d = PVAdjustable(ID_DilSc_LakeShore + ':H0_PID_D'),
|
||||
)
|
||||
|
||||
@_check_connection
|
||||
def get_current_value(self):
|
||||
cacheitem = self.dilsc.getParameter(f'{self.name}', 'value', trycache=False)
|
||||
return cacheitem.value
|
||||
|
||||
|
||||
@_check_connection
|
||||
def set_target_value(self, value, adjust_heater_range=True):
|
||||
if adjust_heater_range:
|
||||
range_to_set = None
|
||||
for setting in self.heater_settings:
|
||||
if setting['temp_start'] <= value and setting['temp_end'] >= value:
|
||||
range_to_set = setting['range']
|
||||
if range_to_set != None:
|
||||
self.set_heater_range(range_to_set)
|
||||
else:
|
||||
raise ValueError(f"Heater range for the target value {value} could not be set")
|
||||
self.dilsc.setParameter(f'{self.name}', 'target', value)
|
||||
def set_pids(self,P,I,D):
|
||||
self.heater.p.set_target_value(P)
|
||||
self.heater.i.set_target_value(I)
|
||||
self.heater.d.set_target_value(D)
|
||||
|
||||
@_check_connection
|
||||
def get_target_value(self):
|
||||
cacheitem = self.dilsc.getParameter(f'{self.name}', 'target', trycache=False)
|
||||
return cacheitem.value
|
||||
PVAdjustable(self.ID_DilSc_LakeShore +':H0_01_SEND.PROC').set_target_value(1)
|
||||
|
||||
|
||||
@_check_connection
|
||||
def is_moving(self):
|
||||
response = self.dilsc.getParameter(f'{self.name}','status', trycache=False)
|
||||
return response[0][0] > StatusType.PREPARED
|
||||
|
||||
@_check_connection
|
||||
def get_PID_parameters(self):
|
||||
""" Returns the current PID parameters associated with the control loop for
|
||||
this thermometer.
|
||||
"""
|
||||
# response = self.dilsc.getParameter(f'{self.name}','ctrlpars', trycache=False)
|
||||
response = self.dilsc.execCommand('lscio', 'communicate', 'PID?')
|
||||
return response
|
||||
|
||||
@_check_connection
|
||||
def set_PID_parameters(self, p, i, d):
|
||||
""" Sets the PID parameters for the associated control loop.
|
||||
TODO:
|
||||
- This still returns a timeout error but sets the correct values.
|
||||
- The range is limited to less than the Lakeshore range allows, this needs
|
||||
to be fixed in frappy.
|
||||
"""
|
||||
# self.dilsc.setParameter(f'{self.name}', 'ctrlpars', {'p': p, 'i': i, 'd': d})
|
||||
command_string = f'PID {0},{p},{i},{d}; PID?'
|
||||
self.dilsc.execCommand('lscio', 'communicate', command_string)
|
||||
|
||||
|
||||
class MagnetCoil(Adjustable):
|
||||
def __init__(self, ID, direction, limit_low, limit_high):
|
||||
|
||||
super().__init__(ID, limit_low=limit_low, limit_high=limit_high)
|
||||
|
||||
self.direction = direction
|
||||
self.ID = self.name + '-' + self.direction
|
||||
|
||||
def __init__(self, name, dilsc_connection, direction, limit_low=-0.0001, limit_high=0.0001):
|
||||
if self.direction not in ["X", "Y", "Z"]:
|
||||
raise ValueError("Direction must be either X, Y or Z.")
|
||||
|
||||
super().__init__(name, limit_low=-0.0001, limit_high=0.0001)
|
||||
|
||||
self.direction = direction.lower()
|
||||
self.target = PVAdjustable(self.ID+':SET_FSET')
|
||||
self.target_readback = PVAdjustable(self.ID+':SIG_FSET')
|
||||
self.ramp_rate = PVAdjustable(self.ID+':SIG_RFST')
|
||||
self.done = PVAdjustable(self.ID+':FSET_FLAG')
|
||||
self.field_target_tolerance = 1e-3
|
||||
|
||||
if self.direction not in ["x", "y", "z"]:
|
||||
raise ValueError("Direction must be either x, y or z.")
|
||||
|
||||
self.dilsc = dilsc_connection
|
||||
|
||||
|
||||
def _check_connection(func):
|
||||
def checker(self, *args, **kwargs):
|
||||
if not self.dilsc.online:
|
||||
raise ConnectionError(f'No connection to dilsc at {self.address}')
|
||||
else:
|
||||
return func(self, *args, **kwargs)
|
||||
return checker
|
||||
|
||||
@_check_connection
|
||||
def get_current_value(self):
|
||||
cacheitem = self.dilsc.getParameter(f'mf{self.direction}', 'value', trycache=False)
|
||||
return cacheitem.value
|
||||
|
||||
|
||||
@_check_connection
|
||||
def set_target_value(self, value):
|
||||
self.dilsc.setParameter(f'mf{self.direction}', 'target', value)
|
||||
|
||||
@_check_connection
|
||||
def is_moving(self):
|
||||
response = self.dilsc.getParameter(f'mf{self.direction}','status', trycache=False)
|
||||
return response[0][0] > StatusType.PREPARED
|
||||
self.target.set_target_value(value)
|
||||
PVAdjustable(self.ID+':ACTN_RTOS.PROC').set_target_value(1)
|
||||
|
||||
def get_current_value(self):
|
||||
return PVAdjustable(self.ID+':SIG_FLD').get_current_value()
|
||||
|
||||
@_check_connection
|
||||
def set_ramp_speed(self, direction, value):
|
||||
""" Sets ramp speed for a given direction (x,y or z) and value in T/min.
|
||||
"""
|
||||
if value > 0.5:
|
||||
raise ValueError('Do not exceed 0.5 T/min unless you want a quench party')
|
||||
if value <= 0:
|
||||
raise ValueError('Only positive values are allowed')
|
||||
if self.direction not in ["x", "y", "z"]:
|
||||
raise ValueError("Direction must be either x, y or z.")
|
||||
else:
|
||||
self.dilsc.setParameter(direction, 'ramp', value)
|
||||
return
|
||||
def hold(self):
|
||||
return PVAdjustable(self.ID+':ACTN_HOLD.PROC').set_target_value(1)
|
||||
|
||||
def press_to_setpoint(self):
|
||||
return PVAdjustable(self.ID+':ACTN_RTOS.PROC').set_target_value(1)
|
||||
|
||||
#TODO: Bodge. There must be a better way..
|
||||
def is_moving(self):
|
||||
time.sleep(0.1)
|
||||
return abs( self.target.get_current_value() - self.get_current_value() ) > self.field_target_tolerance
|
||||
|
||||
|
||||
@@ -2,6 +2,13 @@ import requests
|
||||
import numpy as np
|
||||
|
||||
from loguru import logger
|
||||
from tqdm import tqdm
|
||||
|
||||
from slic.core.condition import ValueCondition
|
||||
from slic.utils.npy import nice_arange
|
||||
from slic.core.scanner.scaninfo import ScanInfo
|
||||
|
||||
|
||||
|
||||
|
||||
def start_sequence(n: int = 100, pulse_phase: float = np.pi/8):
|
||||
@@ -10,4 +17,89 @@ def start_sequence(n: int = 100, pulse_phase: float = np.pi/8):
|
||||
r = requests.get(url, params=parameters)
|
||||
|
||||
d = r.json()
|
||||
return d['pids']
|
||||
return d['pids']
|
||||
|
||||
|
||||
def happy_condition():
|
||||
""" Enjoy the bright side of life.
|
||||
"""
|
||||
|
||||
get_value = lambda: 1
|
||||
check_time = 0.1
|
||||
vmin = 0
|
||||
vmax = 2
|
||||
wait_time = 0.1
|
||||
required_fraction = 0
|
||||
condition = ValueCondition(get_value, check_time, vmin, vmax, wait_time, required_fraction)
|
||||
|
||||
return condition
|
||||
|
||||
|
||||
def scan_with_sync(adjustable, start_pos, end_pos, step_size, n_pulses, filename, acquisitions = [None], return_to_initial_values=False, condition=None, spreadsheet=None, stand_client=None):
|
||||
"""
|
||||
Convenience function to make scans when pulse tube synchronisation is used for a given
|
||||
start position, end position and step size.
|
||||
|
||||
"""
|
||||
positions = nice_arange(start_pos, end_pos, step_size)
|
||||
|
||||
scan_with_sync_seq(adjustable, positions, n_pulses, filename, acquisitions=acquisitions, return_to_initial_values=return_to_initial_values, condition=condition, spreadsheet=spreadsheet, stand_client=stand_client)
|
||||
|
||||
|
||||
def scan_with_sync_seq(adjustable, positions, n_pulses, filename, acquisitions = [None], return_to_initial_values=False, condition=None, spreadsheet=None, stand_client=None):
|
||||
"""
|
||||
Convenience function to make scans when pulse tube synchronisation is used for a given
|
||||
list of positions to drive to.
|
||||
"""
|
||||
|
||||
scaninfo = ScanInfo(filename, "scan_info", [adjustable], positions)
|
||||
assert len(acquisitions) == 1, f"Only one acquisition can be given for one run. Now {acquisitions} were given."
|
||||
|
||||
for i, position in enumerate(tqdm(positions)):
|
||||
# Go to the position and save readback
|
||||
adjustable.set_target_value(position).wait()
|
||||
readback = adjustable.get_current_value()
|
||||
scaninfo.append([position], [readback], None, None)
|
||||
|
||||
if condition is None:
|
||||
condition = happy_condition()
|
||||
|
||||
successful_acquisition = False
|
||||
|
||||
while not successful_acquisition:
|
||||
condition.clear_and_start_counting()
|
||||
|
||||
try:
|
||||
# Measure the step and save the pids
|
||||
# It's done with try because every now and then the pids are not retrieved and the step should be repeated.
|
||||
pids = start_sequence(n_pulses)
|
||||
scan_info_d = scaninfo.to_sfdaq_dict()
|
||||
successful_acquisition = condition.stop_counting_and_analyze()
|
||||
except KeyboardInterrupt:
|
||||
print('Aborting.')
|
||||
break
|
||||
except:
|
||||
successful_acquisition = False
|
||||
|
||||
# Retrieve data
|
||||
# First step needs to be made separately, because a run number can't be given to sfdaq until the folder is created.
|
||||
# TODO: is this still true?
|
||||
if i == 0:
|
||||
for acquisition in acquisitions:
|
||||
first_step = acquisition.retrieve(filename, pulseids=pids, scan_info=scan_info_d)
|
||||
run_number= first_step['run_number']
|
||||
else:
|
||||
for acquisition in acquisitions:
|
||||
acquisition.retrieve(filename, pulseids=pids, run_number=run_number, scan_info=scan_info_d)
|
||||
|
||||
if return_to_initial_values:
|
||||
adjustable.set_target_value(positions[0]).wait()
|
||||
|
||||
# Write to stand table
|
||||
if stand_client is not None:
|
||||
if spreadsheet is not None:
|
||||
stand_client.add_row(run=str(run_number), filename=filename, n_pulses=str(n_pulses), sync="True", **spreadsheet.get_adjs_values())
|
||||
else:
|
||||
stand_client.add_row(run=str(run_number), filename=filename, n_pulses=str(n_pulses), sync="True")
|
||||
|
||||
print(f"Scan {run_number} finished")
|
||||
187
devices/LakeShore372/curves/X165053.340
Normal file
187
devices/LakeShore372/curves/X165053.340
Normal file
@@ -0,0 +1,187 @@
|
||||
Sensor Model: CX-1030-CD-0.3L
|
||||
Serial Number: X165053
|
||||
Data Format: 4 (Log Ohms/Kelvin)
|
||||
SetPoint Limit: 325.0 (Kelvin)
|
||||
Temperature coefficient: 1 (Negative)
|
||||
Number of Breakpoints: 178
|
||||
|
||||
No. Units Temperature (K)
|
||||
|
||||
1 1.53734 330.052
|
||||
2 1.54198 325.000
|
||||
3 1.54763 319.000
|
||||
4 1.55292 313.500
|
||||
5 1.55832 308.000
|
||||
6 1.56384 302.500
|
||||
7 1.56948 297.000
|
||||
8 1.57524 291.500
|
||||
9 1.58112 286.000
|
||||
10 1.58714 280.500
|
||||
11 1.59329 275.000
|
||||
12 1.59958 269.500
|
||||
13 1.60602 264.000
|
||||
14 1.61260 258.500
|
||||
15 1.61934 253.000
|
||||
16 1.62623 247.500
|
||||
17 1.63329 242.000
|
||||
18 1.64052 236.500
|
||||
19 1.64724 231.500
|
||||
20 1.65411 226.500
|
||||
21 1.66114 221.500
|
||||
22 1.66833 216.500
|
||||
23 1.67568 211.500
|
||||
24 1.68321 206.500
|
||||
25 1.69091 201.500
|
||||
26 1.69879 196.500
|
||||
27 1.70687 191.500
|
||||
28 1.71515 186.500
|
||||
29 1.72363 181.500
|
||||
30 1.73233 176.500
|
||||
31 1.74125 171.500
|
||||
32 1.75041 166.500
|
||||
33 1.75886 162.000
|
||||
34 1.76752 157.500
|
||||
35 1.77640 153.000
|
||||
36 1.78550 148.500
|
||||
37 1.79485 144.000
|
||||
38 1.80444 139.500
|
||||
39 1.81429 135.000
|
||||
40 1.82443 130.500
|
||||
41 1.83485 126.000
|
||||
42 1.84439 122.000
|
||||
43 1.85418 118.000
|
||||
44 1.86425 114.000
|
||||
45 1.87462 110.000
|
||||
46 1.88530 106.000
|
||||
47 1.89631 102.000
|
||||
48 1.90483 99.000
|
||||
49 1.91207 96.500
|
||||
50 1.91947 94.000
|
||||
51 1.92704 91.500
|
||||
52 1.93478 89.000
|
||||
53 1.94271 86.500
|
||||
54 1.95083 84.000
|
||||
55 1.95915 81.500
|
||||
56 1.96770 79.000
|
||||
57 1.97647 76.500
|
||||
58 1.98549 74.000
|
||||
59 1.99477 71.500
|
||||
60 2.00241 69.500
|
||||
61 2.01023 67.500
|
||||
62 2.01825 65.500
|
||||
63 2.02648 63.500
|
||||
64 2.03493 61.500
|
||||
65 2.04406 59.400
|
||||
66 2.05302 57.400
|
||||
67 2.06225 55.400
|
||||
68 2.07177 53.400
|
||||
69 2.08160 51.400
|
||||
70 2.09073 49.600
|
||||
71 2.10015 47.800
|
||||
72 2.10987 46.000
|
||||
73 2.11991 44.200
|
||||
74 2.13031 42.400
|
||||
75 2.14109 40.600
|
||||
76 2.15164 38.900
|
||||
77 2.16193 37.300
|
||||
78 2.17259 35.700
|
||||
79 2.18366 34.100
|
||||
80 2.19516 32.500
|
||||
81 2.20638 31.000
|
||||
82 2.21806 29.500
|
||||
83 2.22941 28.100
|
||||
84 2.24124 26.700
|
||||
85 2.25360 25.300
|
||||
86 2.26561 24.000
|
||||
87 2.27721 22.800
|
||||
88 2.28934 21.600
|
||||
89 2.30210 20.400
|
||||
90 2.31162 19.550
|
||||
91 2.32031 18.800
|
||||
92 2.32871 18.100
|
||||
93 2.33679 17.450
|
||||
94 2.34517 16.800
|
||||
95 2.35388 16.150
|
||||
96 2.36224 15.550
|
||||
97 2.37092 14.950
|
||||
98 2.37997 14.350
|
||||
99 2.38863 13.800
|
||||
100 2.39765 13.250
|
||||
101 2.40709 12.700
|
||||
102 2.41606 12.200
|
||||
103 2.42545 11.700
|
||||
104 2.43529 11.200
|
||||
105 2.44564 10.700
|
||||
106 2.45546 10.250
|
||||
107 2.46577 9.800
|
||||
108 2.47666 9.350
|
||||
109 2.48819 8.900
|
||||
110 2.49907 8.500
|
||||
111 2.51056 8.100
|
||||
112 2.52278 7.700
|
||||
113 2.53582 7.300
|
||||
114 2.54801 6.950
|
||||
115 2.56097 6.600
|
||||
116 2.57485 6.250
|
||||
117 2.59065 5.880
|
||||
118 2.60540 5.560
|
||||
119 2.62128 5.240
|
||||
120 2.63739 4.940
|
||||
121 2.65480 4.640
|
||||
122 2.67249 4.360
|
||||
123 2.69172 4.080
|
||||
124 2.70745 3.870
|
||||
125 2.72182 3.690
|
||||
126 2.73720 3.510
|
||||
127 2.75279 3.340
|
||||
128 2.76853 3.180
|
||||
129 2.78651 3.010
|
||||
130 2.80468 2.850
|
||||
131 2.82307 2.700
|
||||
132 2.84302 2.550
|
||||
133 2.86320 2.410
|
||||
134 2.88511 2.270
|
||||
135 2.90906 2.130
|
||||
136 2.93348 2.000
|
||||
137 2.95817 1.880
|
||||
138 2.98524 1.760
|
||||
139 3.01521 1.640
|
||||
140 3.04574 1.530
|
||||
141 3.07965 1.420
|
||||
142 3.11779 1.310
|
||||
143 3.15700 1.210
|
||||
144 3.16370 1.195
|
||||
145 3.17876 1.160
|
||||
146 3.19702 1.120
|
||||
147 3.21628 1.080
|
||||
148 3.23668 1.040
|
||||
149 3.25832 1.000
|
||||
150 3.28136 0.960
|
||||
151 3.30594 0.920
|
||||
152 3.32890 0.885
|
||||
153 3.35329 0.850
|
||||
154 3.37933 0.815
|
||||
155 3.40721 0.780
|
||||
156 3.43716 0.745
|
||||
157 3.46945 0.710
|
||||
158 3.49934 0.680
|
||||
159 3.53133 0.650
|
||||
160 3.56588 0.620
|
||||
161 3.60325 0.590
|
||||
162 3.64391 0.560
|
||||
163 3.68840 0.530
|
||||
164 3.72895 0.505
|
||||
165 3.76208 0.486
|
||||
166 3.79551 0.468
|
||||
167 3.83118 0.450
|
||||
168 3.86939 0.432
|
||||
169 3.91040 0.414
|
||||
170 3.94954 0.398
|
||||
171 3.99133 0.382
|
||||
172 4.03619 0.366
|
||||
173 4.08440 0.350
|
||||
174 4.13658 0.334
|
||||
175 4.18610 0.320
|
||||
176 4.23214 0.308
|
||||
177 4.26529 0.300
|
||||
178 4.45964 0.260
|
||||
@@ -1,7 +1,7 @@
|
||||
# How to upload .340 curve to a LakeShore 372 in EPICS
|
||||
If something unclear, contact the creator Edwin
|
||||
|
||||
active the enviromnet with pyepics in it. Then in this folder run 'python UploadTempCurve.py _340-file_ _LakeShoreBaseName:CVCurveNumber_'
|
||||
active the enviromnet with pyepics in it (e.g. slic). Then in this folder run 'python UploadTempCurve.py _340-file_ _LakeShoreBaseName:CVCurveNumber_'
|
||||
e.g. python UploadTempCurve.py U08910.340 SARES31-DIL-LS1:CV1
|
||||
|
||||
the code gives an error, but works.
|
||||
|
||||
43
p22760.py
Normal file
43
p22760.py
Normal file
@@ -0,0 +1,43 @@
|
||||
"""Module for the p22760 beamtime experiment at Cristallina. For slic purposes only.
|
||||
"""
|
||||
|
||||
import scipy
|
||||
import numpy as np
|
||||
|
||||
|
||||
|
||||
def get_theta_prediction(B_field):
|
||||
"""Get predicted theta angle from B field using linear interpolation.
|
||||
|
||||
Args:
|
||||
B_field (float): Magnetic field value in Tesla.
|
||||
|
||||
Returns:
|
||||
tuple: Predicted theta angles (left, right) in degrees.
|
||||
"""
|
||||
|
||||
B = np.array([0. , 0. , 0.05 , 0.1 , 0.15 , 0.2 , 0.25 , 0.3 ,
|
||||
0.35 , 0.4 , 0.5 , 0.525 , 0.53 , 0.55 , 0.555 , 0.56 ,
|
||||
0.565 , 0.5675, 0.57 , 0.5725, 0.575 , 0.6 ])
|
||||
|
||||
left = np.array([-16.72402197, -16.72592595, -16.72266943, -16.71780642,
|
||||
-16.70710748, -16.68879129, -16.67129814, -16.64430405,
|
||||
-16.61258093, -16.57162955, -16.43958512, -16.36767873,
|
||||
-16.35235521, -16.20000072, -16.14585335, -16.14986136,
|
||||
-16.14953497, -16.15033841, -16.14907281, -16.14883662,
|
||||
-16.14936827, -16.14544489])
|
||||
|
||||
right = np.array([-15.82641889, -15.82810495, -15.82810142, -15.83362565,
|
||||
-15.84191596, -15.85030174, -15.86875095, -15.88716295,
|
||||
-15.91257856, -15.94358668, -16.0436225 , -16.07455302,
|
||||
-16.08374928, -16.13199655, -16.14585335, -16.14986136,
|
||||
-16.14953497, -16.15033841, -16.14907281, -16.14883662,
|
||||
-16.14936827, -16.14544489])
|
||||
|
||||
interpolation_right = scipy.interpolate.interp1d(B, right, kind='linear')
|
||||
interpolation_left = scipy.interpolate.interp1d(B, left, kind='linear')
|
||||
|
||||
theta_right = interpolation_right(B_field)
|
||||
theta_left = interpolation_left(B_field)
|
||||
|
||||
return theta_left, theta_right
|
||||
11
pgroups.py
11
pgroups.py
@@ -1,7 +1,8 @@
|
||||
|
||||
pgroup_scratch = "p19150" # Scratch
|
||||
|
||||
# pgroup = "p19150" # Scratch
|
||||
|
||||
pgroup = "p19150" # Scratch
|
||||
# pgroup = "p19152" # Scratch
|
||||
|
||||
# pgroup = "p19739" # commissioning March 2022 -- July 2022
|
||||
@@ -54,4 +55,10 @@ pgroup_scratch = "p19150" # Scratch
|
||||
|
||||
# pgroup = "p22581" # Cr-Q commissioning Puma June 2025
|
||||
|
||||
pgroup = "p22761" # Cr-Q commissioning Puma June 2025
|
||||
# pgroup = "p22761" # Cr-Q commissioning Puma Sep 2025
|
||||
|
||||
# pgroup = "p23016" # Cr-Q user experiment Vonka Nov 2025 on /sf/maloja/data
|
||||
|
||||
# pgroup = "p22760" # Cr-Q user experiment Vonka Nov 2025
|
||||
|
||||
# pgroup = "p22569" # Cr-Q user experiment Bianchi Dec 2025
|
||||
|
||||
@@ -5,7 +5,7 @@ class Time(Adjustable):
|
||||
""" Adjustable only for spreadsheet, no other functionality
|
||||
"""
|
||||
def __init__(self):
|
||||
super().__init__(self, "")
|
||||
super().__init__(self, "Time")
|
||||
|
||||
def get_current_value(self):
|
||||
return datetime.datetime.now().replace(microsecond=0).isoformat()
|
||||
|
||||
Reference in New Issue
Block a user