Merge branch 'master' into slab
Merge master into SLAB to add new functionalities
This commit is contained in:
Vendored
+5
-1
@@ -1,5 +1,9 @@
|
||||
{
|
||||
"python.linting.pylintEnabled": true,
|
||||
"python.linting.enabled": true,
|
||||
"python.pythonPath": "/sf/bernina/anaconda/bernina_envs/bernina37/bin/python"
|
||||
"python.pythonPath": "/sf/bernina/applications/bm/envs/bernina38/bin/python",
|
||||
"[python]": {
|
||||
"editor.defaultFormatter": "ms-python.black-formatter"
|
||||
},
|
||||
"python.formatting.provider": "none"
|
||||
}
|
||||
@@ -4,3 +4,5 @@ except:
|
||||
print("cannot import Prototypic protocol classes")
|
||||
|
||||
from eco.elements.assembly import Assembly
|
||||
|
||||
ELOG = None
|
||||
|
||||
@@ -3,11 +3,13 @@ import numpy as np
|
||||
from ..elements.adjustable import AdjustableFS
|
||||
from ..epics.adjustable import AdjustablePv
|
||||
from ..epics.detector import DetectorPvDataStream
|
||||
from ..detector.detectors_psi import DetectorBsStream
|
||||
|
||||
from ..elements.assembly import Assembly
|
||||
|
||||
|
||||
class CheckerCA(Assembly):
|
||||
def __init__(self, pvname, thresholds, required_fraction, name=None):
|
||||
def __init__(self, pvname=None, thresholds=None, required_fraction=None, name=None):
|
||||
super().__init__(name=name)
|
||||
self._append(DetectorPvDataStream, pvname, name="monitor")
|
||||
self._append(
|
||||
@@ -51,6 +53,51 @@ class CheckerCA(Assembly):
|
||||
print(f" given limit was {self.required_fraction()*100}%.")
|
||||
return fraction >= self.required_fraction()
|
||||
|
||||
class CheckerBS(Assembly):
|
||||
def __init__(self, bs_channel=None, thresholds=None, required_fraction=None, name=None):
|
||||
super().__init__(name=name)
|
||||
self._append(DetectorBsStream, bs_channel, name="monitor")
|
||||
self._append(
|
||||
AdjustableFS,
|
||||
"/photonics/home/gac-bernina/eco/configuration/checker_thresholds",
|
||||
default_value=sorted(thresholds),
|
||||
name="thresholds",
|
||||
)
|
||||
self._append(
|
||||
AdjustableFS,
|
||||
"/photonics/home/gac-bernina/eco/configuration/checker_required_fraction",
|
||||
default_value=required_fraction,
|
||||
name="required_fraction",
|
||||
)
|
||||
|
||||
def check_now(self):
|
||||
cv = self.monitor.get_current_value()
|
||||
thresholds = self.thresholds()
|
||||
if cv > thresholds[0] and cv < thresholds[1]:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
# def append_to_data(self, **kwargs):
|
||||
# self.data.append(kwargs["value"])
|
||||
|
||||
def clear_and_start_counting(self):
|
||||
self.monitor.accumulate_start()
|
||||
|
||||
# def stopcounting(self):
|
||||
# self.PV.clear_callbacks()
|
||||
|
||||
def stop_and_analyze(self):
|
||||
data = np.asarray(self.monitor.accumulate_stop())
|
||||
thresholds = self.thresholds()
|
||||
good = np.logical_and(data > thresholds[0], data < thresholds[1])
|
||||
fraction = good.sum() / len(good)
|
||||
isgood = fraction >= self.required_fraction()
|
||||
if not isgood:
|
||||
print(f"Checker: {fraction*100}% inside limits {self.thresholds()},")
|
||||
print(f" given limit was {self.required_fraction()*100}%.")
|
||||
return fraction >= self.required_fraction()
|
||||
|
||||
|
||||
# checker_obj = Checker_obj(checkerPV)
|
||||
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
import requests
|
||||
from pathlib import Path
|
||||
from time import sleep
|
||||
|
||||
from eco.elements.protocols import Adjustable
|
||||
from ..epics.detector import DetectorPvDataStream
|
||||
from epics import PV
|
||||
from ..acquisition.utilities import Acquisition
|
||||
from ..elements.assembly import Assembly
|
||||
from ..utilities.path_alias import PathAlias
|
||||
@@ -23,6 +26,7 @@ class Daq(Assembly):
|
||||
channels_BSCAM=None,
|
||||
channels_CA=None,
|
||||
config_JFs=None,
|
||||
rate_multiplicator=None,
|
||||
name=None,
|
||||
):
|
||||
super().__init__(name=name)
|
||||
@@ -43,9 +47,14 @@ class Daq(Assembly):
|
||||
self.broker_address = broker_address
|
||||
self.broker_address_aux = broker_address_aux
|
||||
self.timeout = timeout
|
||||
self.pgroup = pgroup
|
||||
self._pgroup = pgroup
|
||||
if type(pulse_id_adj) is str:
|
||||
self.pulse_id = DetectorPvDataStream(pulse_id_adj, name="pulse_id")
|
||||
self._pid_wo_automonitor = PV(
|
||||
"SGE-CPCW-85-EVR0:RX-PULSEID",
|
||||
connection_timeout=0.05,
|
||||
auto_monitor=False,
|
||||
)
|
||||
else:
|
||||
self.pulse_id = pulse_id_adj
|
||||
self.running = []
|
||||
@@ -54,7 +63,24 @@ class Daq(Assembly):
|
||||
self.name = name
|
||||
self._default_file_path = None
|
||||
|
||||
self.rate_multiplicator = rate_multiplicator
|
||||
|
||||
@property
|
||||
def pgroup(self):
|
||||
if isinstance(self._pgroup, Adjustable):
|
||||
return self._pgroup.get_current_value()
|
||||
else:
|
||||
return self._pgroup
|
||||
|
||||
@pgroup.setter
|
||||
def pgroup(self, value):
|
||||
if isinstance(self._pgroup, Adjustable):
|
||||
self._pgroup.set_target_value(value).wait()
|
||||
else:
|
||||
self._pgroup = value
|
||||
|
||||
def acquire(self, file_name=None, Npulses=100, acq_pars={}):
|
||||
print(acq_pars)
|
||||
print(file_name, Npulses)
|
||||
acquisition = Acquisition(
|
||||
acquire=None,
|
||||
@@ -164,6 +190,7 @@ class Daq(Assembly):
|
||||
parameters["directory_name"] = directory_relative.as_posix()
|
||||
|
||||
parameters["pgroup"] = pgroup
|
||||
parameters["rate_multiplicator"] = self.rate_multiplicator
|
||||
# print("----- debug info ----->\n", parameters, "\n<----- debug info -----")
|
||||
response = validate_response(
|
||||
requests.post(
|
||||
@@ -172,10 +199,10 @@ class Daq(Assembly):
|
||||
timeout=self.timeout,
|
||||
).json()
|
||||
)
|
||||
|
||||
runno = response['run_number']
|
||||
|
||||
filenames = response['files']
|
||||
runno = response["run_number"]
|
||||
|
||||
filenames = response["files"]
|
||||
|
||||
# filenames = [
|
||||
# (directory_base / Path(filename_format.format(runno)))
|
||||
@@ -186,27 +213,27 @@ class Daq(Assembly):
|
||||
|
||||
return runno, filenames
|
||||
|
||||
def get_next_run_number(self,pgroup=None):
|
||||
def get_next_run_number(self, pgroup=None):
|
||||
if pgroup is None:
|
||||
pgroup = self.pgroup
|
||||
res = requests.get(
|
||||
f"{self.broker_address}/get_next_run_number",
|
||||
json={'pgroup':pgroup},
|
||||
json={"pgroup": pgroup},
|
||||
timeout=self.timeout,
|
||||
)
|
||||
assert res.ok, f'Getting last run number failed {res.raise_for_status()}'
|
||||
return int(res.json()['message'])
|
||||
)
|
||||
assert res.ok, f"Getting last run number failed {res.raise_for_status()}"
|
||||
return int(res.json()["message"])
|
||||
|
||||
def get_last_run_number(self,pgroup=None):
|
||||
def get_last_run_number(self, pgroup=None):
|
||||
if pgroup is None:
|
||||
pgroup = self.pgroup
|
||||
res = requests.get(
|
||||
f"{self.broker_address}/get_last_run_number",
|
||||
json={'pgroup':pgroup},
|
||||
json={"pgroup": pgroup},
|
||||
timeout=self.timeout,
|
||||
)
|
||||
assert res.ok, f'Getting last run number failed {res.raise_for_status()}'
|
||||
return int(res.json()['message'])
|
||||
)
|
||||
assert res.ok, f"Getting last run number failed {res.raise_for_status()}"
|
||||
return int(res.json()["message"])
|
||||
|
||||
def get_detector_frequency(self):
|
||||
return self._event_master.event_codes[
|
||||
@@ -243,16 +270,17 @@ class Daq(Assembly):
|
||||
f"{self.broker_address}/take_pedestal", json=parameters
|
||||
).json()
|
||||
|
||||
def append_aux(self,*file_names,run_number=None,pgroup=None):
|
||||
def append_aux(self, *file_names, run_number=None, pgroup=None):
|
||||
if pgroup is None:
|
||||
pgroup = self.pgroup
|
||||
if run_number is None:
|
||||
run_number = self.get_last_run_number()
|
||||
|
||||
return requests.post(
|
||||
self.broker_address_aux+'/copy_user_files',
|
||||
json={'pgroup': pgroup, 'run_number': run_number, 'files': file_names}
|
||||
)
|
||||
self.broker_address_aux + "/copy_user_files",
|
||||
json={"pgroup": pgroup, "run_number": run_number, "files": file_names},
|
||||
)
|
||||
|
||||
|
||||
def validate_response(resp):
|
||||
if resp.get("status") == "ok":
|
||||
|
||||
+79
-10
@@ -1,3 +1,4 @@
|
||||
from numbers import Number
|
||||
import os
|
||||
import json
|
||||
import numpy as np
|
||||
@@ -51,34 +52,50 @@ class Scan:
|
||||
Npulses=100,
|
||||
basepath="",
|
||||
scan_info_dir="",
|
||||
settling_time=0,
|
||||
checker=None,
|
||||
scan_directories=False,
|
||||
callbackStartStep=None,
|
||||
callbacks_start_scan=[],
|
||||
callbacks_start_step=[],
|
||||
callbacks_end_step=[],
|
||||
callbacks_end_scan=[],
|
||||
checker_sleep_time=2,
|
||||
return_at_end="question",
|
||||
run_table=None,
|
||||
run_number=None,
|
||||
elog=None,
|
||||
**kwargs_callbacks,
|
||||
):
|
||||
if np.any([char in fina for char in inval_chars]):
|
||||
raise ScanNameError
|
||||
self.Nsteps = len(values)
|
||||
self._run_table = run_table
|
||||
self.pulses_per_step = Npulses
|
||||
if not isinstance(Npulses, Number):
|
||||
if not len(Npulses) == len(values):
|
||||
raise ValueError("steps for Number of pulses and values must match!")
|
||||
self.pulses_per_step = Npulses
|
||||
else:
|
||||
self.pulses_per_step = [Npulses] * len(values)
|
||||
self.adjustables = adjustables
|
||||
self.values_todo = values
|
||||
self.values_done = []
|
||||
self.pulses_done = []
|
||||
self.readbacks = []
|
||||
self.counterCallers = counterCallers
|
||||
self.settling_time = settling_time
|
||||
self.fina = fina
|
||||
self.nextStep = 0
|
||||
self.basepath = basepath
|
||||
self.scan_info_dir = scan_info_dir
|
||||
|
||||
anames = []
|
||||
for ta in adjustables:
|
||||
try:
|
||||
anames.append(ta.alias.get_full_name())
|
||||
except:
|
||||
anames.append(ta.name)
|
||||
|
||||
self.scan_info = {
|
||||
"scan_parameters": {
|
||||
"name": [ta.name for ta in adjustables],
|
||||
"name": anames,
|
||||
"Id": [ta.Id if hasattr(ta, "Id") else "noId" for ta in adjustables],
|
||||
},
|
||||
"scan_values_all": values,
|
||||
@@ -95,7 +112,11 @@ class Scan:
|
||||
self._checker_sleep_time = checker_sleep_time
|
||||
self._elog = elog
|
||||
self.run_number = run_number
|
||||
self.remaining_tasks = []
|
||||
self.callbacks_start_step = callbacks_start_step
|
||||
self.callbacks_end_step = callbacks_end_step
|
||||
self.callbacks_end_scan = callbacks_end_scan
|
||||
self.callbacks_kwargs = kwargs_callbacks
|
||||
print(f"Scan info in file {self.scan_info_filename}.")
|
||||
for adj in self.adjustables:
|
||||
tv = adj.get_current_value()
|
||||
@@ -104,7 +125,7 @@ class Scan:
|
||||
|
||||
if callbacks_start_scan:
|
||||
for caller in callbacks_start_scan:
|
||||
caller(self)
|
||||
caller(self, **self.callbacks_kwargs)
|
||||
|
||||
def get_filename(self, stepNo, Ndigits=4):
|
||||
fina = os.path.join(self.basepath, Path(self.fina).stem)
|
||||
@@ -136,6 +157,10 @@ class Scan:
|
||||
)
|
||||
self.checker.clear_and_start_counting()
|
||||
|
||||
if self.callbacks_start_step:
|
||||
for caller in self.callbacks_start_step:
|
||||
caller(self, **self.callbacks_kwargs)
|
||||
|
||||
if not len(self.values_todo) > 0:
|
||||
return False
|
||||
values_step = self.values_todo[0]
|
||||
@@ -150,6 +175,10 @@ class Scan:
|
||||
ms.append(adj.set_target_value(tv))
|
||||
for tm in ms:
|
||||
tm.wait()
|
||||
|
||||
# settling
|
||||
sleep(self.settling_time)
|
||||
|
||||
readbacks_step = []
|
||||
adjs_name = []
|
||||
adjs_offset = []
|
||||
@@ -185,12 +214,12 @@ class Scan:
|
||||
"user_tag": self.fina,
|
||||
}
|
||||
acq = ctr.acquire(
|
||||
file_name=fina, Npulses=self.pulses_per_step, acq_pars=acq_pars
|
||||
file_name=fina, Npulses=self.pulses_per_step[0], acq_pars=acq_pars
|
||||
)
|
||||
elif isinstance(ctr, Slab_Ioxos_Daq):
|
||||
acq = ctr.acquire(file_name=fina, N_pulses=self.pulses_per_step, adjs_rb=readbacks_step, adjs_name=[adj.name for adj in self.adjustables])
|
||||
else:
|
||||
acq = ctr.acquire(file_name=fina, Npulses=self.pulses_per_step)
|
||||
acq = ctr.acquire(file_name=fina, Npulses=self.pulses_per_step[0])
|
||||
acs.append(acq)
|
||||
filenames = []
|
||||
for ta in acs:
|
||||
@@ -207,12 +236,17 @@ class Scan:
|
||||
else:
|
||||
tstepinfo = step_info
|
||||
self.values_done.append(self.values_todo.pop(0))
|
||||
self.pulses_done.append(self.pulses_per_step.pop(0))
|
||||
self.readbacks.append(readbacks_step)
|
||||
self.appendScanInfo(
|
||||
values_step, readbacks_step, step_files=filenames, step_info=tstepinfo
|
||||
)
|
||||
self.writeScanInfo()
|
||||
if self.callbacks_end_step:
|
||||
for caller in self.callbacks_end_step:
|
||||
caller(self, **self.callbacks_kwargs)
|
||||
self.nextStep += 1
|
||||
|
||||
return True
|
||||
|
||||
def appendScanInfo(
|
||||
@@ -254,7 +288,7 @@ class Scan:
|
||||
|
||||
if self.callbacks_end_scan:
|
||||
for caller in self.callbacks_end_scan:
|
||||
caller(self)
|
||||
caller(self, **self.callbacks_kwargs)
|
||||
if self.return_at_end == "question":
|
||||
if input("Change back to initial values? (y/n)")[0] == "y":
|
||||
chs = self.changeToInitialValues()
|
||||
@@ -285,12 +319,16 @@ class Scans:
|
||||
checker=None,
|
||||
scan_directories=False,
|
||||
callbacks_start_scan=[],
|
||||
callbacks_start_step=[],
|
||||
callbacks_end_step=[],
|
||||
callbacks_end_scan=[],
|
||||
run_table=None,
|
||||
elog=None,
|
||||
):
|
||||
self._run_table = run_table
|
||||
self.callbacks_start_scan = callbacks_start_scan
|
||||
self.callbacks_start_step = callbacks_start_step
|
||||
self.callbacks_end_step = callbacks_end_step
|
||||
self.callbacks_end_scan = callbacks_end_scan
|
||||
self.data_base_dir = data_base_dir
|
||||
scan_info_dir = Path(scan_info_dir)
|
||||
@@ -337,6 +375,7 @@ class Scans:
|
||||
start_immediately=True,
|
||||
step_info=None,
|
||||
return_at_end="question",
|
||||
**kwargs_callbacks,
|
||||
):
|
||||
positions0 = np.linspace(start0_pos, end0_pos, N_intervals + 1)
|
||||
positions1 = np.linspace(start1_pos, end1_pos, N_intervals + 1)
|
||||
@@ -354,10 +393,13 @@ class Scans:
|
||||
checker=self.checker,
|
||||
scan_directories=self._scan_directories,
|
||||
callbacks_start_scan=self.callbacks_start_scan,
|
||||
callbacks_start_step=self.callbacks_start_step,
|
||||
callbacks_end_step=self.callbacks_end_step,
|
||||
callbacks_end_scan=self.callbacks_end_scan,
|
||||
run_table=self._run_table,
|
||||
elog=self._elog,
|
||||
return_at_end=return_at_end,
|
||||
**kwargs_callbacks,
|
||||
)
|
||||
if start_immediately:
|
||||
s.scanAll(step_info=step_info)
|
||||
@@ -370,10 +412,11 @@ class Scans:
|
||||
file_name="",
|
||||
counters=[],
|
||||
start_immediately=True,
|
||||
settling_time=0,
|
||||
step_info=None,
|
||||
return_at_end=True,
|
||||
**kwargs_callbacks,
|
||||
):
|
||||
|
||||
adjustable = DummyAdjustable()
|
||||
|
||||
positions = list(range(N_repetitions))
|
||||
@@ -390,14 +433,18 @@ class Scans:
|
||||
Npulses=N_pulses,
|
||||
basepath=self.data_base_dir,
|
||||
scan_info_dir=self.scan_info_dir,
|
||||
settling_time=settling_time,
|
||||
checker=self.checker,
|
||||
scan_directories=self._scan_directories,
|
||||
callbacks_start_scan=self.callbacks_start_scan,
|
||||
callbacks_start_step=self.callbacks_start_step,
|
||||
callbacks_end_step=self.callbacks_end_step,
|
||||
callbacks_end_scan=self.callbacks_end_scan,
|
||||
run_table=self._run_table,
|
||||
elog=self._elog,
|
||||
run_number=run_number,
|
||||
return_at_end=return_at_end,
|
||||
**kwargs_callbacks,
|
||||
)
|
||||
if start_immediately:
|
||||
s.scanAll(step_info=step_info)
|
||||
@@ -415,6 +462,8 @@ class Scans:
|
||||
start_immediately=True,
|
||||
step_info=None,
|
||||
return_at_end="question",
|
||||
settling_time=0,
|
||||
**kwargs_callbacks,
|
||||
):
|
||||
positions = np.linspace(start_pos, end_pos, N_intervals + 1)
|
||||
values = [[tp] for tp in positions]
|
||||
@@ -431,13 +480,17 @@ class Scans:
|
||||
basepath=self.data_base_dir,
|
||||
scan_info_dir=self.scan_info_dir,
|
||||
checker=self.checker,
|
||||
settling_time=settling_time,
|
||||
scan_directories=self._scan_directories,
|
||||
return_at_end=return_at_end,
|
||||
callbacks_start_scan=self.callbacks_start_scan,
|
||||
callbacks_start_step=self.callbacks_start_step,
|
||||
callbacks_end_step=self.callbacks_end_step,
|
||||
callbacks_end_scan=self.callbacks_end_scan,
|
||||
run_table=self._run_table,
|
||||
elog=self._elog,
|
||||
run_number=run_number,
|
||||
**kwargs_callbacks,
|
||||
)
|
||||
if start_immediately:
|
||||
s.scanAll(step_info=step_info)
|
||||
@@ -453,8 +506,10 @@ class Scans:
|
||||
file_name="",
|
||||
counters=[],
|
||||
start_immediately=True,
|
||||
settling_time=0,
|
||||
step_info=None,
|
||||
return_at_end="question",
|
||||
**kwargs_callbacks,
|
||||
):
|
||||
positions = np.linspace(start_pos, end_pos, N_intervals + 1)
|
||||
current = adjustable.get_current_value()
|
||||
@@ -474,11 +529,15 @@ class Scans:
|
||||
checker=self.checker,
|
||||
scan_directories=self._scan_directories,
|
||||
return_at_end=return_at_end,
|
||||
settling_time=settling_time,
|
||||
callbacks_start_scan=self.callbacks_start_scan,
|
||||
callbacks_start_step=self.callbacks_start_step,
|
||||
callbacks_end_step=self.callbacks_end_step,
|
||||
callbacks_end_scan=self.callbacks_end_scan,
|
||||
run_table=self._run_table,
|
||||
elog=self._elog,
|
||||
run_number=run_number,
|
||||
**kwargs_callbacks,
|
||||
)
|
||||
if start_immediately:
|
||||
s.scanAll(step_info=step_info)
|
||||
@@ -498,8 +557,10 @@ class Scans:
|
||||
file_name=None,
|
||||
counters=[],
|
||||
start_immediately=True,
|
||||
settling_time=0,
|
||||
step_info=None,
|
||||
return_at_end="question",
|
||||
**kwargs_callbacks,
|
||||
):
|
||||
positions = posList
|
||||
values = [[tp] for tp in positions]
|
||||
@@ -517,12 +578,16 @@ class Scans:
|
||||
scan_info_dir=self.scan_info_dir,
|
||||
checker=self.checker,
|
||||
scan_directories=self._scan_directories,
|
||||
settling_time=settling_time,
|
||||
return_at_end=return_at_end,
|
||||
callbacks_start_scan=self.callbacks_start_scan,
|
||||
callbacks_start_step=self.callbacks_start_step,
|
||||
callbacks_end_step=self.callbacks_end_step,
|
||||
callbacks_end_scan=self.callbacks_end_scan,
|
||||
run_table=self._run_table,
|
||||
elog=self._elog,
|
||||
run_number=run_number,
|
||||
**kwargs_callbacks,
|
||||
)
|
||||
if start_immediately:
|
||||
s.scanAll(step_info=step_info)
|
||||
@@ -543,6 +608,7 @@ class Scans:
|
||||
start_immediately=True,
|
||||
step_info=None,
|
||||
return_at_end="question",
|
||||
**kwargs_callbacks,
|
||||
):
|
||||
positions0 = np.linspace(start0_pos, end0_pos, N_intervals + 1)
|
||||
positions1 = np.linspace(start1_pos, end1_pos, N_intervals + 1)
|
||||
@@ -566,9 +632,12 @@ class Scans:
|
||||
scan_directories=self._scan_directories,
|
||||
return_at_end=return_at_end,
|
||||
callbacks_start_scan=self.callbacks_start_scan,
|
||||
callbacks_start_step=self.callbacks_start_step,
|
||||
callbacks_end_step=self.callbacks_end_step,
|
||||
callbacks_end_scan=self.callbacks_end_scan,
|
||||
run_table=self._run_table,
|
||||
elog=self._elog,
|
||||
**kwargs_callbacks,
|
||||
)
|
||||
if start_immediately:
|
||||
s.scanAll(step_info=step_info)
|
||||
|
||||
+12
-10
@@ -30,10 +30,10 @@ class Alias:
|
||||
|
||||
def pop_object(self, obj):
|
||||
i = self.children.index(obj)
|
||||
o = self.children[i]
|
||||
o = self.children.pop(i)
|
||||
o.parent = None
|
||||
|
||||
def get_all(self, joiner="."):
|
||||
def get_all(self, joiner=".", channeltypes=None):
|
||||
aa = []
|
||||
if self.channel:
|
||||
ta = {}
|
||||
@@ -41,18 +41,20 @@ class Alias:
|
||||
ta["channel"] = self.channel
|
||||
if self.channeltype:
|
||||
ta["channeltype"] = self.channeltype
|
||||
aa.append(ta)
|
||||
if (not channeltypes) or (ta["channeltype"] in channeltypes):
|
||||
aa.append(ta)
|
||||
if self.children:
|
||||
for tc in self.children:
|
||||
taa = tc.get_all()
|
||||
for ta in taa:
|
||||
aa.append(
|
||||
{
|
||||
"alias": joiner.join([self.alias, ta["alias"]]),
|
||||
"channel": ta["channel"],
|
||||
"channeltype": ta["channeltype"],
|
||||
}
|
||||
)
|
||||
if (not channeltypes) or (ta["channeltype"] in channeltypes):
|
||||
aa.append(
|
||||
{
|
||||
"alias": joiner.join([self.alias, ta["alias"]]),
|
||||
"channel": ta["channel"],
|
||||
"channeltype": ta["channeltype"],
|
||||
}
|
||||
)
|
||||
return aa
|
||||
|
||||
def get_full_name(self, base=None, joiner="."):
|
||||
|
||||
+1820
-199
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,87 @@
|
||||
|
||||
# new beamline startup
|
||||
|
||||
from eco import Assembly
|
||||
from eco.xoptics.attenuator_aramis import AttenuatorAramis
|
||||
|
||||
|
||||
namespace.append_obj(
|
||||
"Att_usd",
|
||||
name="att_usd",
|
||||
module_name="eco.xoptics.att_usd",
|
||||
xp=xp,
|
||||
lazy=True,
|
||||
)
|
||||
|
||||
namespace.append_obj(
|
||||
"SlitPosWidth",
|
||||
"SAROP21-OAPU138",
|
||||
name="slit_att",
|
||||
lazy=True,
|
||||
module_name="eco.xoptics.slits",
|
||||
),
|
||||
|
||||
namespace.append_obj(
|
||||
"JJSlitUnd",
|
||||
name="slit_und",
|
||||
module_name="eco.xoptics.slits",
|
||||
lazy=True,
|
||||
)
|
||||
namespace.append_obj(
|
||||
"SlitBlades",
|
||||
"SAROP21-OAPU092",
|
||||
name="slit_switch",
|
||||
module_name="eco.xoptics.slits",
|
||||
lazy=True,
|
||||
)
|
||||
namespace.append_obj(
|
||||
"SlitBlades",
|
||||
"SAROP21-OAPU102",
|
||||
name="slit_mono",
|
||||
module_name="eco.xoptics.slits",
|
||||
lazy=True,
|
||||
)
|
||||
|
||||
|
||||
{
|
||||
"name": "pshut_und",
|
||||
"type": "eco.xoptics.shutters:PhotonShutter",
|
||||
"args": ["SARFE10-OPSH044:REQUEST"],
|
||||
"kwargs": {},
|
||||
"z_und": 44,
|
||||
"desc": "First shutter after Undulators",
|
||||
},
|
||||
|
||||
{
|
||||
"name": "xp",
|
||||
"args": [],
|
||||
"kwargs": {
|
||||
"Id": "SAROP21-OPPI113",
|
||||
"evronoff": "SGE-CPCW-72-EVR0:FrontUnivOut15-Ena-SP",
|
||||
"evrsrc": "SGE-CPCW-72-EVR0:FrontUnivOut15-Src-SP",
|
||||
},
|
||||
"z_und": 103,
|
||||
"desc": "X-ray pulse picker",
|
||||
"type": "eco.xoptics.pp:Pulsepick",
|
||||
},
|
||||
|
||||
|
||||
{
|
||||
"name": "att_fe",
|
||||
"type": "eco.xoptics.attenuator_aramis:AttenuatorAramis",
|
||||
"args": ["SARFE10-OATT053"],
|
||||
"kwargs": {"shutter": Component("pshut_und")},
|
||||
"z_und": 53,
|
||||
"desc": "Attenuator in Front End",
|
||||
},
|
||||
|
||||
|
||||
class AttenuationFELBernina(Assembly):
|
||||
def __init__(self, name=None):
|
||||
super().__init__(name=name)
|
||||
self._append(
|
||||
AttenuatorAramis, "SAROP21-OATT135", set_limits=[], name="opt", shutter=None
|
||||
)
|
||||
self._append(
|
||||
AttenuatorAramis, "SARFE10-OATT053", set_limits=[], name="fe", shutter=None
|
||||
)
|
||||
+103
-225
@@ -32,27 +32,27 @@ components = [
|
||||
"kwargs": {},
|
||||
"lazy": True,
|
||||
},
|
||||
{
|
||||
"name": "elog",
|
||||
"type": "eco.utilities.elog:Elog",
|
||||
"args": ["https://elog-gfa.psi.ch/Bernina"],
|
||||
"kwargs": {
|
||||
"screenshot_directory": "/tmp",
|
||||
},
|
||||
},
|
||||
{
|
||||
"name": "screenshot",
|
||||
"type": "eco.utilities.elog:Screenshot",
|
||||
"args": [],
|
||||
"kwargs": {"screenshot_directory": "/sf/bernina/config/screenshots"},
|
||||
},
|
||||
{
|
||||
"name": "fel",
|
||||
"type": "eco.fel.swissfel:SwissFel",
|
||||
"args": [],
|
||||
"kwargs": {},
|
||||
"desc": "Fel related control and feedback",
|
||||
},
|
||||
# {
|
||||
# "name": "screenshot",
|
||||
# "type": "eco.utilities.elog:Screenshot",
|
||||
# "args": [],
|
||||
# "kwargs": {"screenshot_directory": "/sf/bernina/config/screenshots"},
|
||||
# },
|
||||
# {
|
||||
# "name": "fel",
|
||||
# "type": "eco.fel.swissfel:SwissFel",
|
||||
# "args": [],
|
||||
# "kwargs": {},
|
||||
# "desc": "Fel related control and feedback",
|
||||
# },
|
||||
# {
|
||||
# "name": "mono",
|
||||
# "args": ["SAROP21-ODCM098"],
|
||||
# "kwargs": {},
|
||||
# "z_und": 98,
|
||||
# "desc": "DCM Monochromator",
|
||||
# "type": "eco.xoptics.dcm_new:DoubleCrystalMono",
|
||||
# },
|
||||
# {
|
||||
# "name": "slit_und",
|
||||
# "type": "eco.xoptics.slits:SlitFourBlades_old",
|
||||
@@ -75,28 +75,28 @@ components = [
|
||||
# "type": "eco.xdiagnostics.intensity_monitors:SolidTargetDetectorPBPS",
|
||||
# "kwargs": {"VME_crate": "SAROP21-CVME-PBPS2", "link": 9},
|
||||
# },
|
||||
{
|
||||
"name": "mon_und",
|
||||
"z_und": 53,
|
||||
"desc": "Intensity/position monitor after Undulator",
|
||||
"type": "eco.xdiagnostics.intensity_monitors:SolidTargetDetectorPBPS_new",
|
||||
"args": ["SARFE10-PBPS053"],
|
||||
"kwargs": {
|
||||
"VME_crate": "SAROP21-CVME-PBPS1",
|
||||
"link": 9,
|
||||
"channels": {
|
||||
"up": "SLAAR21-LSCP1-FNS:CH6:VAL_GET",
|
||||
"down": "SLAAR21-LSCP1-FNS:CH7:VAL_GET",
|
||||
"left": "SLAAR21-LSCP1-FNS:CH4:VAL_GET",
|
||||
"right": "SLAAR21-LSCP1-FNS:CH5:VAL_GET",
|
||||
},
|
||||
"calc": {
|
||||
"itot": "SLAAR21-LTIM01-EVR0:CALCI",
|
||||
"xpos": "SLAAR21-LTIM01-EVR0:CALCX",
|
||||
"ypos": "SLAAR21-LTIM01-EVR0:CALCY",
|
||||
},
|
||||
},
|
||||
},
|
||||
# {
|
||||
# "name": "mon_und",
|
||||
# "z_und": 53,
|
||||
# "desc": "Intensity/position monitor after Undulator",
|
||||
# "type": "eco.xdiagnostics.intensity_monitors:SolidTargetDetectorPBPS_new",
|
||||
# "args": ["SARFE10-PBPS053"],
|
||||
# "kwargs": {
|
||||
# "VME_crate": "SAROP21-CVME-PBPS1",
|
||||
# "link": 9,
|
||||
# "channels": {
|
||||
# "up": "SLAAR21-LSCP1-FNS:CH6:VAL_GET",
|
||||
# "down": "SLAAR21-LSCP1-FNS:CH7:VAL_GET",
|
||||
# "left": "SLAAR21-LSCP1-FNS:CH4:VAL_GET",
|
||||
# "right": "SLAAR21-LSCP1-FNS:CH5:VAL_GET",
|
||||
# },
|
||||
# "calc": {
|
||||
# "itot": "SLAAR21-LTIM01-EVR0:CALCI",
|
||||
# "xpos": "SLAAR21-LTIM01-EVR0:CALCX",
|
||||
# "ypos": "SLAAR21-LTIM01-EVR0:CALCY",
|
||||
# },
|
||||
# },
|
||||
# },
|
||||
{
|
||||
"name": "pshut_und",
|
||||
"type": "eco.xoptics.shutters:PhotonShutter",
|
||||
@@ -145,14 +145,14 @@ components = [
|
||||
# "args": ["SARFE10-PBPS053"],
|
||||
# "kwargs": {},
|
||||
# },
|
||||
{
|
||||
"name": "xspect",
|
||||
"z_und": 53,
|
||||
"desc": "X-ray single shot spectrometer",
|
||||
"type": "eco.xdiagnostics.xspect:Xspect",
|
||||
"args": [],
|
||||
"kwargs": {},
|
||||
},
|
||||
# {
|
||||
# "name": "xspect",
|
||||
# "z_und": 53,
|
||||
# "desc": "X-ray single shot spectrometer",
|
||||
# "type": "eco.xdiagnostics.xspect:Xspect",
|
||||
# "args": [],
|
||||
# "kwargs": {},
|
||||
# },
|
||||
{
|
||||
"name": "prof_fe",
|
||||
"args": ["SARFE10-PPRM064"] * 2,
|
||||
@@ -186,25 +186,17 @@ components = [
|
||||
"type": "eco.xoptics.offsetMirrors_new:OffsetMirrorsBernina",
|
||||
"kwargs": {},
|
||||
},
|
||||
{
|
||||
"name": "mono",
|
||||
"args": ["SAROP21-ODCM098"],
|
||||
"kwargs": {},
|
||||
"z_und": 98,
|
||||
"desc": "DCM Monochromator",
|
||||
"type": "eco.xoptics.dcm_new:DoubleCrystalMono",
|
||||
},
|
||||
{
|
||||
"name": "mono_old",
|
||||
"args": ["SAROP21-ODCM098"],
|
||||
"kwargs": {
|
||||
"energy_sp": "SAROP21-ARAMIS:ENERGY_SP",
|
||||
"energy_rb": "SAROP21-ARAMIS:ENERGY",
|
||||
},
|
||||
"z_und": 98,
|
||||
"desc": "DCM Monochromator",
|
||||
"type": "eco.xoptics.dcm:Double_Crystal_Mono",
|
||||
},
|
||||
# {
|
||||
# "name": "mono_old",
|
||||
# "args": ["SAROP21-ODCM098"],
|
||||
# "kwargs": {
|
||||
# "energy_sp": "SAROP21-ARAMIS:ENERGY_SP",
|
||||
# "energy_rb": "SAROP21-ARAMIS:ENERGY",
|
||||
# },
|
||||
# "z_und": 98,
|
||||
# "desc": "DCM Monochromator",
|
||||
# "type": "eco.xoptics.dcm:Double_Crystal_Mono",
|
||||
# },
|
||||
{
|
||||
"name": "prof_mono",
|
||||
"args": ["SAROP21-PPRM113"] * 2,
|
||||
@@ -233,28 +225,6 @@ components = [
|
||||
# "args": ["SAROP21-PBPS133"],
|
||||
# "kwargs": {"VME_crate": "SAROP21-CVME-PBPS1", "link": 9},
|
||||
# },
|
||||
{
|
||||
"name": "mon_opt",
|
||||
"z_und": 133,
|
||||
"desc": "Intensity/position monitor after Optics hutch",
|
||||
"type": "eco.xdiagnostics.intensity_monitors:SolidTargetDetectorPBPS_new",
|
||||
"args": ["SAROP21-PBPS133"],
|
||||
"kwargs": {
|
||||
"VME_crate": "SAROP21-CVME-PBPS1",
|
||||
"link": 9,
|
||||
"channels": {
|
||||
"up": "SLAAR21-LSCP1-FNS:CH6:VAL_GET",
|
||||
"down": "SLAAR21-LSCP1-FNS:CH7:VAL_GET",
|
||||
"left": "SLAAR21-LSCP1-FNS:CH4:VAL_GET",
|
||||
"right": "SLAAR21-LSCP1-FNS:CH5:VAL_GET",
|
||||
},
|
||||
"calc": {
|
||||
"itot": "SLAAR21-LTIM01-EVR0:CALCI",
|
||||
"xpos": "SLAAR21-LTIM01-EVR0:CALCX",
|
||||
"ypos": "SLAAR21-LTIM01-EVR0:CALCY",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"name": "prof_opt",
|
||||
"args": ["SAROP21-PPRM133"] * 2,
|
||||
@@ -279,22 +249,22 @@ components = [
|
||||
"desc": "Attenuator Bernina",
|
||||
"type": "eco.xoptics.attenuator_aramis:AttenuatorAramis",
|
||||
},
|
||||
{
|
||||
"name": "slit_att",
|
||||
"args": ["SAROP21-OAPU136"],
|
||||
"kwargs": {},
|
||||
"z_und": 136,
|
||||
"desc": "Slits behind attenuator",
|
||||
"type": "eco.xoptics.slits:SlitPosWidth",
|
||||
},
|
||||
{
|
||||
"name": "det_dio",
|
||||
"args": ["SAROP21-PDIO138"],
|
||||
"z_und": 138,
|
||||
"desc": "Diode digitizer for exp data",
|
||||
"type": "eco.devices_general.detectors:DiodeDigitizer",
|
||||
"kwargs": {"VME_crate": "SAROP21-CVME-PBPS2", "link": 9},
|
||||
},
|
||||
# {
|
||||
# "name": "slit_att",
|
||||
# "args": ["SAROP21-OAPU136"],
|
||||
# "kwargs": {},
|
||||
# "z_und": 136,
|
||||
# "desc": "Slits behind attenuator",
|
||||
# "type": "eco.xoptics.slits:SlitPosWidth",
|
||||
# },
|
||||
# {
|
||||
# "name": "det_dio",
|
||||
# "args": ["SAROP21-PDIO138"],
|
||||
# "z_und": 138,
|
||||
# "desc": "Diode digitizer for exp data",
|
||||
# "type": "eco.devices_general.detectors:DiodeDigitizer",
|
||||
# "kwargs": {"VME_crate": "SAROP21-CVME-PBPS2", "link": 9},
|
||||
# },
|
||||
{
|
||||
"name": "prof_att",
|
||||
"args": ["SAROP21-PPRM138"] * 2,
|
||||
@@ -354,17 +324,6 @@ components = [
|
||||
# "diff_detector": {"jf_id": "JF01T03V01"},
|
||||
# },
|
||||
# },
|
||||
{
|
||||
"args": [],
|
||||
"name": "vonHamos",
|
||||
"z_und": 142,
|
||||
"desc": "Kern experiment, von Hamos vertical and horizontal stages ",
|
||||
"type": "eco.devices_general.micos_stage:stage",
|
||||
"kwargs": {
|
||||
"vonHamos_horiz_pv": config["Kern"]["vonHamos_horiz"],
|
||||
"vonHamos_vert_pv": config["Kern"]["vonHamos_vert"],
|
||||
},
|
||||
},
|
||||
# {
|
||||
# "args": [],
|
||||
# "name": "gasjet",
|
||||
@@ -386,22 +345,6 @@ components = [
|
||||
"bsport": 11151,
|
||||
},
|
||||
},
|
||||
{
|
||||
"args": ["SARES20-CAMS142-M1"],
|
||||
"name": "cam_sample_sideview",
|
||||
"z_und": 142,
|
||||
"desc": "",
|
||||
"type": "eco.devices_general.cameras_swissfel:CameraBasler",
|
||||
"kwargs": {},
|
||||
},
|
||||
{
|
||||
"args": ["SARES20-CAMS142-M3"],
|
||||
"name": "cam_sample_inline",
|
||||
"z_und": 142,
|
||||
"desc": "",
|
||||
"type": "eco.devices_general.cameras_swissfel:CameraBasler",
|
||||
"kwargs": {},
|
||||
},
|
||||
# {
|
||||
# "args": ["SARES20-CAMS142-C3"],
|
||||
# "name": "cam_sample_xrd",
|
||||
@@ -423,18 +366,6 @@ components = [
|
||||
# "camera_pv": config["cams_qioptiq"]["camera_pv"],
|
||||
# },
|
||||
# },
|
||||
{
|
||||
"args": [],
|
||||
"name": "cams_sigma",
|
||||
"z_und": 142,
|
||||
"desc": "Sigma objective",
|
||||
"type": "eco.endstations.bernina_cameras:Sigma",
|
||||
"kwargs": {
|
||||
"bshost": "sf-daqsync-01.psi.ch",
|
||||
"bsport": 11149,
|
||||
"camera_pv": config["cams_sigma"]["camera_pv"],
|
||||
},
|
||||
},
|
||||
# {
|
||||
# "args": ["SLAAR02-TSPL-EPL"],
|
||||
# "name": "phase_shifter",
|
||||
@@ -451,28 +382,6 @@ components = [
|
||||
"type": "eco.loptics.laser_shutter:laser_shutter",
|
||||
"kwargs": {},
|
||||
},
|
||||
{
|
||||
"args": [],
|
||||
"name": "epics_channel_list",
|
||||
"desc": "epics channel list",
|
||||
"type": "eco.utilities.config:ChannelList",
|
||||
"kwargs": {
|
||||
"file_name": "/sf/bernina/config/channel_lists/default_channel_list_epics"
|
||||
},
|
||||
"lazy": True,
|
||||
},
|
||||
{
|
||||
"args": [],
|
||||
"name": "epics_daq",
|
||||
"z_und": 142,
|
||||
"desc": "epics data acquisition",
|
||||
"type": "eco.acquisition.epics_data:Epicstools",
|
||||
"kwargs": {
|
||||
"channel_list": Component("epics_channel_list"),
|
||||
"default_file_path": f"/sf/bernina/data/{config['pgroup']}/res/epics_daq/",
|
||||
},
|
||||
"lazy": True,
|
||||
},
|
||||
# {
|
||||
# "args": [],
|
||||
# "name": "daq_dia_old",
|
||||
@@ -489,17 +398,17 @@ components = [
|
||||
# "default_file_path": None,
|
||||
# },
|
||||
# },
|
||||
{
|
||||
"args": [
|
||||
config["checker_PV"],
|
||||
config["checker_thresholds"],
|
||||
config["checker_fractionInThreshold"],
|
||||
], #'SARFE10-PBPG050:HAMP-INTENSITY-CAL',[60,700],.7],
|
||||
"name": "checker",
|
||||
"desc": "checker functions for data acquisition",
|
||||
"type": "eco.acquisition.checkers:CheckerCA",
|
||||
"kwargs": {},
|
||||
},
|
||||
# {
|
||||
# "args": [
|
||||
# config["checker_PV"],
|
||||
# config["checker_thresholds"],
|
||||
# config["checker_fractionInThreshold"],
|
||||
# ], #'SARFE10-PBPG050:HAMP-INTENSITY-CAL',[60,700],.7],
|
||||
# "name": "checker",
|
||||
# "desc": "checker functions for data acquisition",
|
||||
# "type": "eco.acquisition.checkers:CheckerCA",
|
||||
# "kwargs": {},
|
||||
# },
|
||||
# {
|
||||
# "args": [
|
||||
# "SARES20-LSCP9-FNS:CH1:VAL_GET",
|
||||
@@ -513,21 +422,6 @@ components = [
|
||||
# },
|
||||
# {
|
||||
# "args": [],
|
||||
# "name": "scans_epics",
|
||||
# "desc": "epics non beam synchronous based acquisition",
|
||||
# "type": "eco.acquisition.scan:Scans",
|
||||
# "kwargs": {
|
||||
# "data_base_dir": "scan_data",
|
||||
# "scan_info_dir": f"/sf/bernina/data/{config['pgroup']}/res/scan_info",
|
||||
# "default_counters": [Component("epics_daq")],
|
||||
# "checker": Component("checker_epics"),
|
||||
# "scan_directories": True,
|
||||
# "run_table": Component("run_table"),
|
||||
# },
|
||||
# "lazy": True,
|
||||
# },
|
||||
# {
|
||||
# "args": [],
|
||||
# "name": "lxt",
|
||||
# "desc": "laser timing with pockels cells and phase shifter",
|
||||
# "type": "eco.timing.lasertiming:Lxt",
|
||||
@@ -579,14 +473,6 @@ components = [
|
||||
"default_file_path": f"/sf/bernina/data/{config['pgroup']}/res/%s",
|
||||
},
|
||||
},
|
||||
{
|
||||
"args": [],
|
||||
"name": "usd_table",
|
||||
"z_und": 141,
|
||||
"desc": "Upstream diagnostics table",
|
||||
"type": "eco.endstations.hexapod:HexapodSymmetrie",
|
||||
"kwargs": {"offset": [0.0, 0.0, 0.0, 0.0, 0.0, 0.0]},
|
||||
},
|
||||
# {
|
||||
# "args": ["SARES23-"],
|
||||
# "name": "slit_kb",
|
||||
@@ -603,20 +489,20 @@ components = [
|
||||
# "type": "eco.xoptics.slit_USD:Upstream_diagnostic_slits",
|
||||
# "kwargs": {"right": "LIC7", "left": "LIC8", "up": "LIC8", "down": "LIC5"},
|
||||
# },
|
||||
{
|
||||
"args": [
|
||||
[
|
||||
Component("slit_und"),
|
||||
Component("slit_switch"),
|
||||
Component("slit_att"),
|
||||
Component("slit_kb"),
|
||||
]
|
||||
],
|
||||
"name": "slits",
|
||||
"desc": "collection of all slits",
|
||||
"type": "eco.utilities.beamline:Slits",
|
||||
"kwargs": {},
|
||||
},
|
||||
# {
|
||||
# "args": [
|
||||
# [
|
||||
# Component("slit_und"),
|
||||
# Component("slit_switch"),
|
||||
# Component("slit_att"),
|
||||
# Component("slit_kb"),
|
||||
# ]
|
||||
# ],
|
||||
# "name": "slits",
|
||||
# "desc": "collection of all slits",
|
||||
# "type": "eco.utilities.beamline:Slits",
|
||||
# "kwargs": {},
|
||||
# },
|
||||
# {
|
||||
# "args": [
|
||||
# [Component("slit_switch"), Component("slit_att"), Component("slit_kb"),]
|
||||
@@ -659,14 +545,6 @@ components = [
|
||||
# },
|
||||
# },
|
||||
# },
|
||||
{
|
||||
"args": [],
|
||||
"name": "dsd",
|
||||
"z_und": 146,
|
||||
"desc": "downstream diagnostics",
|
||||
"type": "eco.xdiagnostics.dsd:DownstreamDiagnostic",
|
||||
"kwargs": {},
|
||||
},
|
||||
]
|
||||
|
||||
try:
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
import subprocess, os
|
||||
|
||||
|
||||
def get_strip_chart_function():
|
||||
return strip_chart
|
||||
|
||||
|
||||
def strip_chart(*args, **kwargs):
|
||||
"""Usage: Arguments represent channels in the strip_chart config command line argument.
|
||||
Alternatively arguments can be detectors or adjustables, from which _all_ channels are determined
|
||||
"""
|
||||
channels = list(args)
|
||||
cmd = ["strip_chart"]
|
||||
cmd += ['-config="' + str(channels) + '"']
|
||||
cmd += ["-start"]
|
||||
line = " ".join(cmd)
|
||||
print(f"Starting following commandline silently:\n" + line)
|
||||
with open(os.devnull, "w") as FNULL:
|
||||
subprocess.Popen(line, shell=True, stdout=FNULL, stderr=subprocess.STDOUT)
|
||||
@@ -5,6 +5,9 @@ from epics.pv import PV
|
||||
from bsread.bsavail import pollStream
|
||||
from bsread import dispatcher, source
|
||||
from ..epics import get_from_archive
|
||||
from escape import stream
|
||||
from time import time, sleep
|
||||
from eco.acquisition.utilities import Acquisition
|
||||
|
||||
|
||||
@get_from_archive
|
||||
@@ -20,8 +23,18 @@ class DetectorBsStream:
|
||||
self._pv = PV(self.pvname)
|
||||
self.alias = Alias(name, channel=bs_channel, channeltype="BS")
|
||||
|
||||
self.stream = stream.EscData(source=stream.EventSource(self.bs_channel, None))
|
||||
|
||||
def bs_avail(self):
|
||||
return self.bs_channel in [
|
||||
tmp["name"] for tmp in dispatcher.get_current_channels()
|
||||
]
|
||||
|
||||
def get_current_value(self, force_bsstream=False):
|
||||
|
||||
if not force_bsstream:
|
||||
if not hasattr(self, "_pv"):
|
||||
return None
|
||||
return self._pv.get()
|
||||
else:
|
||||
raise NotImplementedError(
|
||||
@@ -37,6 +50,109 @@ class DetectorBsStream:
|
||||
while not done:
|
||||
done = foo(s.receive())
|
||||
|
||||
def collect(self, seconds=None, samples=None):
|
||||
if (not seconds) and (not samples):
|
||||
raise Exception(
|
||||
"Either a time interval or number of samples need to be defined."
|
||||
)
|
||||
try:
|
||||
self._pv.callbacks.pop(self._collection["ix_cb"])
|
||||
except:
|
||||
pass
|
||||
self._collection = {"done": False}
|
||||
self.data_collected = []
|
||||
if seconds:
|
||||
self._collection["start_time"] = time()
|
||||
self._collection["seconds"] = seconds
|
||||
stopcond = (
|
||||
lambda: (time() - self._collection["start_time"])
|
||||
> self._collection["seconds"]
|
||||
)
|
||||
|
||||
def addData(**kw):
|
||||
if not stopcond():
|
||||
self.data_collected.append(kw["value"])
|
||||
else:
|
||||
self._pv.callbacks.pop(self._collection["ix_cb"])
|
||||
self._collection["done"] = True
|
||||
|
||||
elif samples:
|
||||
self._collection["samples"] = samples
|
||||
stopcond = lambda: len(self.data_collected) >= self._collection["samples"]
|
||||
|
||||
def addData(**kw):
|
||||
self.data_collected.append(kw["value"])
|
||||
if stopcond():
|
||||
self._pv.callbacks.pop(self._collection["ix_cb"])
|
||||
self._collection["done"] = True
|
||||
|
||||
self._collection["ix_cb"] = self._pv.add_callback(addData)
|
||||
time_wait_start = time()
|
||||
while not self._collection["done"]:
|
||||
sleep(0.005)
|
||||
if seconds:
|
||||
if (time() - time_wait_start) > seconds:
|
||||
if len(self.data_collected) == 0:
|
||||
print(
|
||||
f"No {self.name}({self.Id}) data update in time interval, reporting last value"
|
||||
)
|
||||
self._pv.callbacks.pop(self._collection["ix_cb"])
|
||||
self.data_collected.append(self.get_current_value())
|
||||
break
|
||||
|
||||
return self.data_collected
|
||||
|
||||
def acquire(self, hold=False, seconds=None, samples=None, **kwargs):
|
||||
return Acquisition(
|
||||
acquire=lambda: self.collect(seconds=seconds, samples=samples, **kwargs),
|
||||
hold=hold,
|
||||
stopper=None,
|
||||
get_result=lambda: self.data_collected,
|
||||
)
|
||||
|
||||
def accumulate_ring_buffer(self, n_buffer):
|
||||
if not hasattr(self, "_accumulate"):
|
||||
self._accumulate = {"n_buffer": n_buffer, "ix": 0, "n_cb": -1}
|
||||
else:
|
||||
self._accumulate["n_buffer"] = n_buffer
|
||||
self._accumulate["ix"] = 0
|
||||
self._pv.callbacks.pop(self._accumulate["n_cb"], None)
|
||||
self._data = np.squeeze(np.zeros([n_buffer * 2, self._pv.count])) * np.nan
|
||||
|
||||
def addData(**kw):
|
||||
self._accumulate["ix"] = (self._accumulate["ix"] + 1) % self._accumulate[
|
||||
"n_buffer"
|
||||
]
|
||||
self._data[self._accumulate["ix"] :: self._accumulate["n_buffer"]] = kw[
|
||||
"value"
|
||||
]
|
||||
|
||||
self._accumulate["n_cb"] = self._pv.add_callback(addData)
|
||||
|
||||
def accumulate_start(self):
|
||||
if not hasattr(self, "_accumulate_inf"):
|
||||
self._accumulate_inf = {"n_cb": -1}
|
||||
self._pv.callbacks.pop(self._accumulate_inf["n_cb"], None)
|
||||
self._data_inf = []
|
||||
|
||||
def addData(**kw):
|
||||
self._data_inf.append(kw["value"])
|
||||
|
||||
self._accumulate_inf["n_cb"] = self._pv.add_callback(addData)
|
||||
|
||||
def accumulate_stop(self):
|
||||
self._pv.callbacks.pop(self._accumulate_inf["n_cb"], None)
|
||||
return self._data_inf
|
||||
|
||||
@property
|
||||
def data(self):
|
||||
return self._data[
|
||||
self._accumulate["ix"]
|
||||
+ 1 : self._accumulate["ix"]
|
||||
+ 1
|
||||
+ self._accumulate["n_buffer"]
|
||||
]
|
||||
|
||||
|
||||
@get_from_archive
|
||||
class DetectorBsCam:
|
||||
|
||||
+336
-5
@@ -1,11 +1,15 @@
|
||||
import shutil
|
||||
from tkinter import W
|
||||
from ..elements.adjustable import AdjustableVirtual, AdjustableGetSet
|
||||
|
||||
from eco.base.adjustable import Adjustable
|
||||
from ..elements.adjustable import AdjustableFS, AdjustableVirtual, AdjustableGetSet
|
||||
from ..epics.adjustable import AdjustablePv
|
||||
from ..elements.assembly import Assembly
|
||||
from ..aliases import Alias
|
||||
from pathlib import Path
|
||||
from ..elements import memory
|
||||
from datetime import datetime
|
||||
import requests
|
||||
|
||||
|
||||
class Jungfrau(Assembly):
|
||||
@@ -15,12 +19,16 @@ class Jungfrau(Assembly):
|
||||
pv_trigger="SAR-CVME-TIFALL5-EVG0:SoftEvt-EvtCode-SP",
|
||||
trigger_on=254,
|
||||
trigger_off=255,
|
||||
broker_address="http://sf-daq:10002",
|
||||
pgroup_adj=None,
|
||||
config_adj=None,
|
||||
name=None,
|
||||
):
|
||||
super().__init__(name=name)
|
||||
self.alias = Alias(name, channel=jf_id, channeltype="JF")
|
||||
|
||||
self.pgroup = pgroup_adj
|
||||
self.jf_id = jf_id
|
||||
self.broker_address = broker_address
|
||||
self._append(
|
||||
AdjustablePv,
|
||||
pv_trigger,
|
||||
@@ -57,6 +65,34 @@ class Jungfrau(Assembly):
|
||||
name="gain_file",
|
||||
is_display=True,
|
||||
)
|
||||
self._append(
|
||||
AdjustableGetSet,
|
||||
self.get_present_pedestal_filename_in_run,
|
||||
lambda value: NotImplementedError(
|
||||
"Can not set the pedestal file manually yet."
|
||||
),
|
||||
name="pedestal_file_in_run",
|
||||
is_display=True,
|
||||
)
|
||||
self._append(
|
||||
AdjustableGetSet,
|
||||
self.get_present_gain_filename_in_run,
|
||||
lambda value: NotImplementedError(
|
||||
"Can not set the pedestal file manually yet."
|
||||
),
|
||||
name="gain_file_in_run",
|
||||
is_display=True,
|
||||
)
|
||||
if config_adj:
|
||||
self._append(
|
||||
JungfrauDaqConfig,
|
||||
jf_id,
|
||||
config_adj,
|
||||
name="config_daq",
|
||||
is_setting=True,
|
||||
is_status=True,
|
||||
is_display="recursive",
|
||||
)
|
||||
|
||||
def _set_trigger_enable(self, value):
|
||||
if value:
|
||||
@@ -68,12 +104,307 @@ class Jungfrau(Assembly):
|
||||
filepath = Path(f"/sf/jungfrau/config/gainMaps/{self.jf_id}/gains.h5")
|
||||
|
||||
if filepath.exists():
|
||||
return filepath.resolve().as_posix()
|
||||
return filepath.as_posix()
|
||||
else:
|
||||
raise Exception(f"File {filepath.resolve().as_posix()} seems not to exist!")
|
||||
raise Exception(f"File {filepath.as_posix()} seems not to exist!")
|
||||
|
||||
def get_present_gain_filename_in_run(self, intempdir=False):
|
||||
f = Path(self.get_present_gain_filename())
|
||||
dest = Path(
|
||||
f"/sf/bernina/data/{self.pgroup()}/res/tmp/gainmaps_{self.jf_id}.h5"
|
||||
)
|
||||
if not dest.exists():
|
||||
shutil.copyfile(f, dest)
|
||||
if intempdir:
|
||||
return dest.as_posix()
|
||||
else:
|
||||
return f"aux/{dest.name}"
|
||||
|
||||
def get_present_pedestal_filename(self):
|
||||
searchpath = Path(f"/sf/jungfrau/data/pedestal/{self.jf_id}")
|
||||
filelist = list(searchpath.glob("*.h5"))
|
||||
times = [datetime.strptime(f.stem, "%Y%m%d_%H%M%S") for f in filelist]
|
||||
return filelist[times.index(max(times))].resolve().as_posix()
|
||||
return filelist[times.index(max(times))].as_posix()
|
||||
|
||||
def get_present_pedestal_filename_in_run(self, intempdir=False):
|
||||
f = Path(self.get_present_pedestal_filename())
|
||||
dest = Path(
|
||||
f"/sf/bernina/data/{self.pgroup()}/res/tmp/pedestal_{self.jf_id}_{f.stem}.h5"
|
||||
)
|
||||
if not dest.exists():
|
||||
shutil.copyfile(f, dest)
|
||||
|
||||
if intempdir:
|
||||
return dest.as_posix()
|
||||
else:
|
||||
return f"aux/{dest.name}"
|
||||
|
||||
def get_detector_frequency(self):
|
||||
return self._event_master.event_codes[
|
||||
self._detectors_event_code
|
||||
].frequency.get_current_value()
|
||||
|
||||
def get_availability(self):
|
||||
is_available = (
|
||||
self.jf_id
|
||||
in requests.get(f"{self.broker_address}/get_allowed_detectors_list").json()[
|
||||
"detectors"
|
||||
]
|
||||
)
|
||||
return is_available
|
||||
|
||||
def get_vis_url(self):
|
||||
tmp = requests.get(f"{self.broker_address}/get_allowed_detectors_list").json()
|
||||
ix = tmp["detectors"].index(self.jf_id)
|
||||
return tmp["visualisation_address"][ix]
|
||||
|
||||
def get_isrunning(self):
|
||||
is_running = (
|
||||
self.jf_id
|
||||
in requests.get(f"{self.broker_address}/get_running_detectors_list").json()[
|
||||
"detectors"
|
||||
]
|
||||
)
|
||||
return is_running
|
||||
|
||||
def power_on(self):
|
||||
JF_channel = self.jf_id
|
||||
par = {"detector_name": JF_channel}
|
||||
return requests.post(
|
||||
f"{self.broker_address}/power_on_detector", json=par
|
||||
).json()
|
||||
|
||||
# def take_pedestal(self, JF_list=None, pgroup=None):
|
||||
# if pgroup is None:
|
||||
# pgroup = self.pgroup
|
||||
# if not JF_list:
|
||||
# JF_list = self.get_JFs_running()
|
||||
# parameters = {
|
||||
# "pgroup": pgroup,
|
||||
# "rate_multiplicator": 1,
|
||||
# "detectors": {tJF: {} for tJF in JF_list},
|
||||
# }
|
||||
# return requests.post(
|
||||
# f"{self.broker_address}/take_pedestal", json=parameters
|
||||
# ).json()
|
||||
|
||||
|
||||
class JungfrauDaqConfig(Assembly):
|
||||
def __init__(self, jf_id, jf_daq_cfg: Adjustable, name=None):
|
||||
super().__init__(name=name)
|
||||
self._jf_id = jf_id
|
||||
self._jf_daq_cfg = jf_daq_cfg
|
||||
cfg = self._jf_daq_cfg.get_current_value()
|
||||
if self._jf_id not in cfg.keys():
|
||||
cfg[self._jf_id] = {}
|
||||
self._jf_daq_cfg.set_target_value(cfg).wait()
|
||||
|
||||
self._append(
|
||||
AdjustableGetSet,
|
||||
self._get_adc_to_energy,
|
||||
self._set_adc_to_energy,
|
||||
name="convert_adc_to_energy",
|
||||
is_display=True,
|
||||
is_setting=True,
|
||||
)
|
||||
self._append(
|
||||
AdjustableGetSet,
|
||||
self._get_geometry_corr,
|
||||
self._set_geometry_corr,
|
||||
name="apply_tile_geometry",
|
||||
is_display=True,
|
||||
is_setting=True,
|
||||
)
|
||||
|
||||
self._append(
|
||||
AdjustableGetSet,
|
||||
self._get_compressed_bitshuffle,
|
||||
self._set_compressed_bitshuffle,
|
||||
name="compress_bitshuffle",
|
||||
is_display=True,
|
||||
is_setting=True,
|
||||
)
|
||||
self._append(
|
||||
AdjustableGetSet,
|
||||
self._get_keep_raw_data,
|
||||
self._set_keep_raw_data,
|
||||
name="keep_raw_data",
|
||||
is_display=True,
|
||||
is_setting=True,
|
||||
)
|
||||
self._append(
|
||||
AdjustableGetSet,
|
||||
self._get_large_pixel_processing,
|
||||
self._set_large_pixel_processing,
|
||||
name="large_pixel_processing",
|
||||
is_display=True,
|
||||
is_setting=True,
|
||||
)
|
||||
self._append(
|
||||
AdjustableGetSet,
|
||||
self._get_rounding_factor,
|
||||
self._set_rounding_factor,
|
||||
name="rounding_factor_keV",
|
||||
is_display=True,
|
||||
is_setting=True,
|
||||
)
|
||||
self._append(
|
||||
AdjustableGetSet,
|
||||
self._get_disabled_modules,
|
||||
self._set_disabled_modules,
|
||||
name="disabled_tiles",
|
||||
is_display=True,
|
||||
is_setting=True,
|
||||
)
|
||||
|
||||
def _get_adc_to_energy(self, *args):
|
||||
try:
|
||||
return self._jf_daq_cfg.get_current_value()[self._jf_id]["adc_to_energy"]
|
||||
except KeyError:
|
||||
return False
|
||||
|
||||
def _set_adc_to_energy(self, value):
|
||||
if value:
|
||||
cfg = self._jf_daq_cfg.get_current_value()
|
||||
cfg[self._jf_id]["adc_to_energy"] = True
|
||||
self._jf_daq_cfg.set_target_value(cfg).wait()
|
||||
else:
|
||||
cfg = self._jf_daq_cfg.get_current_value()
|
||||
cfg[self._jf_id]["adc_to_energy"] = False
|
||||
self._jf_daq_cfg.set_target_value(cfg).wait()
|
||||
|
||||
def _get_geometry_corr(self, *args):
|
||||
try:
|
||||
return self._jf_daq_cfg.get_current_value()[self._jf_id]["geometry"]
|
||||
except KeyError:
|
||||
return "not sure what happens"
|
||||
|
||||
def _set_geometry_corr(self, value):
|
||||
if value:
|
||||
cfg = self._jf_daq_cfg.get_current_value()
|
||||
cfg[self._jf_id]["geometry"] = True
|
||||
self._jf_daq_cfg.set_target_value(cfg).wait()
|
||||
else:
|
||||
cfg = self._jf_daq_cfg.get_current_value()
|
||||
cfg[self._jf_id]["adc_to_energy"] = False
|
||||
self._jf_daq_cfg.set_target_value(cfg).wait()
|
||||
|
||||
def _get_compressed_bitshuffle(self, *args):
|
||||
try:
|
||||
return self._jf_daq_cfg.get_current_value()[self._jf_id]["compression"]
|
||||
except KeyError:
|
||||
return False
|
||||
|
||||
def _set_compressed_bitshuffle(self, value):
|
||||
if value:
|
||||
cfg = self._jf_daq_cfg.get_current_value()
|
||||
cfg[self._jf_id]["compression"] = True
|
||||
self._jf_daq_cfg.set_target_value(cfg).wait()
|
||||
else:
|
||||
cfg = self._jf_daq_cfg.get_current_value()
|
||||
cfg[self._jf_id]["compression"] = False
|
||||
self._jf_daq_cfg.set_target_value(cfg).wait()
|
||||
|
||||
def _get_keep_raw_data(self, *args):
|
||||
try:
|
||||
return not self._jf_daq_cfg.get_current_value()[self._jf_id][
|
||||
"remove_raw_files"
|
||||
]
|
||||
except KeyError:
|
||||
# raise Exception("unclear what the default for keeping raw files is!")
|
||||
return None
|
||||
|
||||
def _set_keep_raw_data(self, value):
|
||||
if value:
|
||||
cfg = self._jf_daq_cfg.get_current_value()
|
||||
cfg[self._jf_id]["remove_raw_files"] = False
|
||||
self._jf_daq_cfg.set_target_value(cfg).wait()
|
||||
else:
|
||||
cfg = self._jf_daq_cfg.get_current_value()
|
||||
cfg[self._jf_id]["remove_raw_files"] = True
|
||||
self._jf_daq_cfg.set_target_value(cfg).wait()
|
||||
|
||||
def _get_large_pixel_processing(self, *args):
|
||||
try:
|
||||
return self._jf_daq_cfg.get_current_value()[self._jf_id][
|
||||
"double_pixels_action"
|
||||
]
|
||||
except KeyError:
|
||||
# raise Exception("unclear what the default for double pixels is!")
|
||||
return None
|
||||
|
||||
def _set_large_pixel_processing(self, value):
|
||||
cfg = self._jf_daq_cfg.get_current_value()
|
||||
cfg[self._jf_id]["double_pixels_action"] = value
|
||||
self._jf_daq_cfg.set_target_value(cfg).wait()
|
||||
|
||||
def _get_rounding_factor(self, *args):
|
||||
try:
|
||||
return self._jf_daq_cfg.get_current_value()[self._jf_id]["factor"]
|
||||
except KeyError:
|
||||
# raise Exception("unclear what the default for double pixels is!")
|
||||
return None
|
||||
|
||||
def _set_rounding_factor(self, value):
|
||||
cfg = self._jf_daq_cfg.get_current_value()
|
||||
cfg[self._jf_id]["factor"] = value
|
||||
self._jf_daq_cfg.set_target_value(cfg).wait()
|
||||
|
||||
def _get_disabled_modules(self, *args):
|
||||
try:
|
||||
return self._jf_daq_cfg.get_current_value()[self._jf_id]["disabled_modules"]
|
||||
except KeyError:
|
||||
return []
|
||||
|
||||
def _set_disabled_modules(self, value):
|
||||
cfg = self._jf_daq_cfg.get_current_value()
|
||||
if value == []:
|
||||
cfg[self._jf_id].pop("disabled_modules")
|
||||
else:
|
||||
cfg[self._jf_id]["disabled_modules"] = value
|
||||
self._jf_daq_cfg.set_target_value(cfg).wait()
|
||||
|
||||
def _get_binning(self, *args):
|
||||
try:
|
||||
return self._jf_daq_cfg.get_current_value()[self._jf_id]["downsample"]
|
||||
except KeyError:
|
||||
return [1, 1]
|
||||
|
||||
def _set_binning(self, value):
|
||||
cfg = self._jf_daq_cfg.get_current_value()
|
||||
if value == [1, 1]:
|
||||
cfg[self._jf_id].pop("downsample")
|
||||
else:
|
||||
cfg[self._jf_id]["downsample"] = value
|
||||
self._jf_daq_cfg.set_target_value(cfg).wait()
|
||||
|
||||
def _get_keepraw(self, *args):
|
||||
try:
|
||||
remove_raw = self._jf_daq_cfg.get_current_value()[self._jf_id][
|
||||
"remove_raw_files"
|
||||
]
|
||||
# if type(remove_raw) is bool:
|
||||
return remove_raw
|
||||
|
||||
except KeyError:
|
||||
return "not sure what happens"
|
||||
|
||||
def _set_keepraw(self, value):
|
||||
cfg = self._jf_daq_cfg.get_current_value()
|
||||
cfg[self._jf_id]["remove_raw_files"] = value
|
||||
self._jf_daq_cfg.set_target_value(cfg).wait()
|
||||
|
||||
|
||||
# {
|
||||
# "adc_to_energy": true,
|
||||
# "compression": true,
|
||||
# "double_pixels_actions": "interpolate",
|
||||
# "downsample": [
|
||||
# 1,
|
||||
# 1
|
||||
# ],
|
||||
# "factor": 0.25,x
|
||||
# "geometry": true,
|
||||
# "remove_raw_files": false
|
||||
# "disabled_modules": [],
|
||||
# },
|
||||
|
||||
@@ -1,14 +1,18 @@
|
||||
from cam_server import CamClient, PipelineClient
|
||||
|
||||
from matplotlib.backend_bases import MouseButton
|
||||
from eco.devices_general.utilities import Changer
|
||||
from ..aliases import Alias, append_object_to_object
|
||||
from ..elements.adjustable import AdjustableVirtual, AdjustableGetSet, value_property
|
||||
from eco.elements.detector import DetectorGet
|
||||
from ..epics.adjustable import AdjustablePv, AdjustablePvEnum
|
||||
from eco.elements.adj_obj import AdjustableObject, DetectorObject
|
||||
from .pipelines_swissfel import Pipeline
|
||||
from ..elements.assembly import Assembly
|
||||
from .motors import MotorRecord
|
||||
import sys
|
||||
from pathlib import Path
|
||||
import time
|
||||
import matplotlib.pyplot as plt
|
||||
|
||||
sys.path.append("/sf/bernina/config/src/python/sf_databuffer/")
|
||||
import bufferutils
|
||||
@@ -30,6 +34,120 @@ def get_pipelineclient():
|
||||
PIPELINE_CLIENT = PipelineClient()
|
||||
return PIPELINE_CLIENT
|
||||
|
||||
@value_property
|
||||
class CamserverConfig2(Assembly):
|
||||
def __init__(self, cam_id, camserver_alias=None, name=None, camserver_group=None):
|
||||
super().__init__(name=name)
|
||||
self.cam_id = cam_id
|
||||
self.camserver_alias = camserver_alias
|
||||
self.camserver_group = camserver_group
|
||||
self._cross = None
|
||||
self._append(AdjustableGetSet,
|
||||
self._get_config,
|
||||
self._set_config,
|
||||
cache_get_seconds =.05,
|
||||
precision=0,
|
||||
check_interval=None,
|
||||
name='_config',
|
||||
is_setting=False,
|
||||
is_display=False)
|
||||
|
||||
self._append(AdjustableObject, self._config, name='config',is_setting=True, is_display='recursive')
|
||||
self._append(DetectorGet, self._get_info, cache_get_seconds =.05, name='_info', is_setting=False, is_display=False)
|
||||
self._append(DetectorObject, self._info, name='info', is_display='recursive', is_setting=False)
|
||||
|
||||
@property
|
||||
def pc(self):
|
||||
return get_pipelineclient()
|
||||
|
||||
@property
|
||||
def cc(self):
|
||||
return get_camclient()
|
||||
|
||||
def _get_config(self):
|
||||
return self.cc.get_camera_config(self.cam_id)
|
||||
|
||||
def _set_config(self, value, hold=False):
|
||||
return Changer(
|
||||
target=value,
|
||||
changer=lambda v: self.cc.set_camera_config(self.cam_id, v),
|
||||
hold=hold,
|
||||
)
|
||||
|
||||
def _get_info(self):
|
||||
fields = {
|
||||
"camera_geometry": self.cc.get_camera_geometry(self.cam_id),
|
||||
"pipelines": self._get_pipelines(),
|
||||
}
|
||||
return fields
|
||||
|
||||
### convenience functions ###
|
||||
def get_camera_image(self):
|
||||
im = self.cc.get_camera_array(self.cam_id)
|
||||
return im
|
||||
|
||||
def set_alias(self, alias=None):
|
||||
"""creates an alias in the camera config on the server. If no alias is provided, it defaults to the camera name"""
|
||||
if not alias:
|
||||
alias = self.camserver_alias
|
||||
self.set_config_fields({"alias": [alias.upper()]})
|
||||
|
||||
def set_group(self, group=None):
|
||||
"""adds the camera to the given group"""
|
||||
if not group:
|
||||
group = self.camserver_group
|
||||
self.config.group(group)
|
||||
|
||||
def _get_pipelines(self):
|
||||
return [p for p in self.pc.get_pipelines() if self.cam_id in p]
|
||||
|
||||
def set_config_fields(self, fields):
|
||||
"""fields is a dictionary containing the keys and values that should be updated, e.g. fields={'group': ['Laser', 'Bernina']}"""
|
||||
config = self.cc.get_camera_config(self.cam_id)
|
||||
config.update(fields)
|
||||
self.cc.set_camera_config(self.cam_id, config)
|
||||
|
||||
def set_config_fields_multiple_cams(self, conditions, fields):
|
||||
"""
|
||||
conditions is a dictionary holding the conditions to select a subset of cameras, e.g. {"group": Bernina}
|
||||
fields is a dictionary containing the keys and values that should be updated, e.g. fields={'alias': ['huhu', 'duda']}
|
||||
"""
|
||||
cams = {
|
||||
cam: self.cc.get_camera_config(cam)
|
||||
for cam in self.cc.get_cameras()
|
||||
if not "jungfrau" in cam
|
||||
}
|
||||
cams_selected = {}
|
||||
for cam, cfg in cams.items():
|
||||
try:
|
||||
if all([value in cfg[key] for key, value in conditions.items()]):
|
||||
cfg.update(fields)
|
||||
self.cc.set_camera_config(cam, cfg)
|
||||
cams_selected[cam] = cfg
|
||||
except Exception as e:
|
||||
print(f"{type(e)} {e} in cam {cam}")
|
||||
return cams_selected
|
||||
|
||||
def clear_all_bernina_aliases(self, verbose=True):
|
||||
cams_selected = self.set_config_fields_multiple_cams(
|
||||
conditions={"group": "Bernina"}, fields={"alias": []}
|
||||
)
|
||||
if verbose:
|
||||
print(f"Reset alias of {len(cams_selected)} cameras")
|
||||
print(cams_selected.keys())
|
||||
|
||||
def _run_cmd(self, line, silent=True):
|
||||
if silent:
|
||||
print(f"Starting following commandline silently:\n" + line)
|
||||
with open(os.devnull, "w") as FNULL:
|
||||
subprocess.Popen(
|
||||
line, shell=True, stdout=FNULL, stderr=subprocess.STDOUT
|
||||
)
|
||||
else:
|
||||
subprocess.Popen(line, shell=True)
|
||||
|
||||
def gui(self):
|
||||
self._run_cmd(f'csm')
|
||||
|
||||
@value_property
|
||||
class CamserverConfig(Assembly):
|
||||
@@ -50,7 +168,7 @@ class CamserverConfig(Assembly):
|
||||
def get_current_value(self):
|
||||
return self.cc.get_camera_config(self.cam_id)
|
||||
|
||||
def set_target_calue(self, value, hold=False):
|
||||
def set_target_value(self, value, hold=False):
|
||||
return Changer(
|
||||
target=value,
|
||||
changer=lambda v: self.cc.set_camera_config(self.cam_id, v),
|
||||
@@ -165,13 +283,14 @@ class CameraBasler(Assembly):
|
||||
if not camserver_alias:
|
||||
camserver_alias = self.alias.get_full_name() + f" ({pvname})"
|
||||
self._append(
|
||||
CamserverConfig,
|
||||
CamserverConfig2,
|
||||
self.pvname,
|
||||
camserver_alias=camserver_alias,
|
||||
camserver_group=camserver_group,
|
||||
name="config_cs",
|
||||
is_display=False,
|
||||
)
|
||||
|
||||
self.config_cs.set_alias()
|
||||
if camserver_group is not None:
|
||||
self.config_cs.set_group()
|
||||
@@ -233,7 +352,7 @@ class CameraBasler(Assembly):
|
||||
)
|
||||
self._append(
|
||||
AdjustablePv,
|
||||
self.pvname + ":BINY",
|
||||
self.pvname + ":BINX",
|
||||
name="_binx",
|
||||
is_setting=True,
|
||||
is_display=False,
|
||||
@@ -338,11 +457,71 @@ class CameraBasler(Assembly):
|
||||
)
|
||||
|
||||
def _set_params(self, *args):
|
||||
self.running(0)
|
||||
self.running(1)
|
||||
for ob, val in args:
|
||||
ob(val)
|
||||
self._set_parameters(1)
|
||||
self.running(1)
|
||||
self.running(2)
|
||||
|
||||
def set_cross(self, x=None, y=None, x_um_per_px=None, y_um_per_px=None):
|
||||
"""set x and y position of the refetence marker on a camera px/um calibration is conserved if no new value is given"""
|
||||
def prompt(x,y,x_um_per_px,y_um_per_px):
|
||||
x=int(x)
|
||||
y=int(y)
|
||||
answer = input(f"Set the new cross position [{x}, {y}] with calibration [{x_um_per_px:.3}, {y_um_per_px:.3}] ([y]/n)?") or "y"
|
||||
if answer == "y":
|
||||
calib.reference_marker([x - 1, y - 1, x + 1, y + 1])
|
||||
calib.reference_marker_width(2 * x_um_per_px)
|
||||
calib.reference_marker_height(2 * y_um_per_px)
|
||||
print("\nNew calibration:")
|
||||
print(calib)
|
||||
else:
|
||||
print("aborted")
|
||||
|
||||
calib = self.config_cs.config.camera_calibration
|
||||
print("Current calibration:")
|
||||
print(calib)
|
||||
try:
|
||||
w = calib.reference_marker_width()
|
||||
h = calib.reference_marker_height()
|
||||
rm = calib.reference_marker()
|
||||
if not x_um_per_px:
|
||||
x_um_per_px = w / abs(rm[2] - rm[0])
|
||||
if not y_um_per_px:
|
||||
y_um_per_px = h / abs(rm[3] - rm[1])
|
||||
except:
|
||||
rm=[0,0,0,0]
|
||||
x_um_per_px = 1
|
||||
y_um_per_px = 1
|
||||
if x is None or y is None:
|
||||
x = (rm[2] + rm[0])/2
|
||||
y = (rm[3] + rm[1])/2
|
||||
img = self.config_cs.get_camera_image()
|
||||
|
||||
run = True
|
||||
def on_click(event):
|
||||
if event.button is MouseButton.LEFT:
|
||||
x = event.xdata
|
||||
y = event.ydata
|
||||
cross_plot.set_data(x,y)
|
||||
plt.draw()
|
||||
print(f'cross at x: {x:.4} and y: {y:.4}')
|
||||
self.config_cs._cross = [x,y]
|
||||
else:
|
||||
plt.disconnect(bid)
|
||||
plt.close(self.config_cs.cam_id)
|
||||
|
||||
fig = plt.figure(num=self.config_cs.cam_id)
|
||||
plt.title(f"Set cross: left mouse click, Finish: right click")
|
||||
plt.imshow(img)
|
||||
cross_plot = plt.plot(x,y, '+r', markersize=10)[0]
|
||||
bid = fig.canvas.mpl_connect('button_press_event', on_click)
|
||||
plt.show(block=True)
|
||||
x, y = self.config_cs._cross
|
||||
print(x,y)
|
||||
prompt(x,y,x_um_per_px,y_um_per_px)
|
||||
|
||||
|
||||
|
||||
def gui(self):
|
||||
self._run_cmd(
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
from eco import Assembly
|
||||
from eco.epics.adjustable import AdjustablePv, AdjustablePvEnum, AdjustablePvString
|
||||
from eco.epics.detector import DetectorPvData, DetectorPvEnum
|
||||
from epics import PV
|
||||
|
||||
|
||||
|
||||
|
||||
class I2cChannel(Assembly):
|
||||
def __init__(self, pvbase, channelnumber, name=None):
|
||||
super().__init__(name=name)
|
||||
self.pvbase = pvbase
|
||||
self.channel_number = channelnumber
|
||||
self._append(
|
||||
AdjustablePvString,
|
||||
f'{self.pvbase}_CH{self.channel_number}:PROCESS.DESC',
|
||||
name="description",
|
||||
is_setting=True,
|
||||
)
|
||||
self._append(DetectorPvData,f'{self.pvbase}_CH{self.channel_number}:TEMP', has_unit=True, name='temp')
|
||||
self._append(DetectorPvData,f'{self.pvbase}_CH{self.channel_number}:HUMIREL', has_unit=True, name = 'humi')
|
||||
self._append(DetectorPvData,f'{self.pvbase}_CH{self.channel_number}:PRES', has_unit=True, name='pres')
|
||||
self._append(AdjustablePv,f'{self.pvbase}_CH{self.channel_number}:ONOFF', name='enabled', is_setting=True)
|
||||
self._append(AdjustablePvEnum,f'{self.pvbase}_CH{self.channel_number}:SENSOR_TYPE', name='sensor_type', is_setting=True)
|
||||
self._pv_init = PV(self.pvbase+':INIT.PROC')
|
||||
|
||||
def get_current_value(self,*args,**kwargs):
|
||||
return f'{self.temp.get_current_value(*args,**kwargs):.2f}°C , {self.humi.get_current_value(*args,**kwargs):.2f}%relHum, {self.pres.get_current_value(*args,**kwargs):.2f} mB'
|
||||
|
||||
# def set_target_value(self,*args,**kwargs):
|
||||
# return self.enabled.set_target_value(*args,**kwargs)
|
||||
|
||||
def initialize(self):
|
||||
self._pv_init.put(1)
|
||||
|
||||
|
||||
|
||||
|
||||
class I2cModule(Assembly):
|
||||
def __init__(self,pvbase='SARES20-CI2C',N_channels=8, name=None):
|
||||
super().__init__(name=name)
|
||||
for n in range(1,N_channels+1):
|
||||
self._append(I2cChannel,pvbase,channelnumber=n,name=f'ch{n}')
|
||||
|
||||
|
||||
class BerninaEnvironment(Assembly):
|
||||
def __init__(self,pvbases=['SLAAR21-LI2C01', 'SARES20-CI2C'],channels=[[1,2,3,4,5,6,7,8],[4,5,6,7,8]], channelnames = [['las_tab1_in', 'las_tab1_cen', 'las_tab1_out', 'las_tab2_in', 'las_tab2_cen', 'las_tab2_out', 'las_tab2_below', 'tt_spec'], ['tt_opt', 'tt_kb', 'exp1', 'exp2', 'exp3']], name=None):
|
||||
super().__init__(name=name)
|
||||
for pvbase,channelnumbers,tnames in zip(pvbases,channels,channelnames):
|
||||
for n,tname in zip(channelnumbers,tnames):
|
||||
self._append(I2cChannel,pvbase,channelnumber=n,name=tname)
|
||||
|
||||
|
||||
class WagoSensor(Assembly):
|
||||
def __init__(self,pvbase='SARES20-CWAG-GPS01:TEMP-T9', name=None):
|
||||
super().__init__(name=name)
|
||||
self.pvbase = pvbase
|
||||
self._append(DetectorPvData,f'{self.pvbase}', unit='°C', name='temperature')
|
||||
self._append(DetectorPvEnum,f'{self.pvbase}-SS', name='status')
|
||||
self._append(AdjustablePv,f'{self.pvbase}-WLEN', name='cable_length', unit='m', is_setting=True)
|
||||
self.unit = self.temperature.unit
|
||||
|
||||
def get_current_value(self):
|
||||
return self.temperature.get_current_value()
|
||||
|
||||
|
||||
|
||||
+545
-42
@@ -13,6 +13,7 @@ from ..elements.adjustable import (
|
||||
update_changes,
|
||||
value_property,
|
||||
)
|
||||
from ..devices_general.pv_adjustable import PvRecord
|
||||
from ..elements.detector import DetectorGet
|
||||
from ..epics import get_from_archive
|
||||
from ..utilities.keypress import KeyPress
|
||||
@@ -26,6 +27,7 @@ import numpy as np
|
||||
from .motor_controller import MforceChannel
|
||||
from .detectors import DetectorVirtual
|
||||
from ..epics.detector import DetectorPvData
|
||||
import json
|
||||
|
||||
if hasattr(global_config, "elog"):
|
||||
elog = global_config.elog
|
||||
@@ -433,8 +435,10 @@ class MotorRecord(Assembly):
|
||||
# alias_fields={"readback": "RBV"},
|
||||
alias_fields={},
|
||||
backlash_definition=False,
|
||||
is_psi_mforce=False,
|
||||
schneider_config=None,
|
||||
expect_bad_limits=True,
|
||||
has_park_pv=False,
|
||||
):
|
||||
super().__init__(name=name)
|
||||
# self.settings.append(self)
|
||||
@@ -520,6 +524,14 @@ class MotorRecord(Assembly):
|
||||
name="description",
|
||||
is_setting=True,
|
||||
)
|
||||
|
||||
if has_park_pv:
|
||||
self._append(
|
||||
AdjustablePv,
|
||||
self.pvname + "_KILL",
|
||||
name="parked",
|
||||
is_setting=True,
|
||||
)
|
||||
if backlash_definition:
|
||||
self._append(
|
||||
AdjustablePv,
|
||||
@@ -546,8 +558,38 @@ class MotorRecord(Assembly):
|
||||
is_setting=True,
|
||||
)
|
||||
|
||||
if expect_bad_limits:
|
||||
self.check_bad_limits()
|
||||
if is_psi_mforce:
|
||||
controller_base, tmp = self.pvname.split(":")
|
||||
channel = int(tmp.split("_")[1])
|
||||
mforce_base = controller_base + ":" + str(channel)
|
||||
|
||||
self._append(
|
||||
AdjustablePv,
|
||||
mforce_base + "_RC",
|
||||
name="run_current",
|
||||
is_setting=True,
|
||||
)
|
||||
self._append(
|
||||
AdjustablePv,
|
||||
mforce_base + "_HC",
|
||||
name="hold_current",
|
||||
is_setting=True,
|
||||
)
|
||||
self._append(
|
||||
AdjustablePv,
|
||||
mforce_base + "_set",
|
||||
name="m_code_set",
|
||||
is_setting=False,
|
||||
is_display=False,
|
||||
)
|
||||
self._append(
|
||||
AdjustablePv,
|
||||
mforce_base + "_get",
|
||||
name="m_code_get",
|
||||
is_setting=False,
|
||||
is_display=False,
|
||||
)
|
||||
|
||||
if schneider_config:
|
||||
pv_base, port = schneider_config
|
||||
self._append(
|
||||
@@ -558,6 +600,8 @@ class MotorRecord(Assembly):
|
||||
is_setting=True,
|
||||
is_display=False,
|
||||
)
|
||||
if expect_bad_limits:
|
||||
self.check_bad_limits()
|
||||
|
||||
def check_bad_limits(self, abs_set_value=2**53):
|
||||
ll, hl = self.get_limits()
|
||||
@@ -568,8 +612,19 @@ class MotorRecord(Assembly):
|
||||
"""Adjustable convention"""
|
||||
|
||||
def changer(value):
|
||||
statflag_start = self.status_flag.get_current_value()
|
||||
if not statflag_start.value == 0:
|
||||
raise AdjustableError(
|
||||
f"Motor {self.alias.get_full_name()}({self.pvname}) cannot start moving with status flag {statflag_start.name} ."
|
||||
)
|
||||
self._status = self._motor.move(value, ignore_limits=(not check), wait=True)
|
||||
self._status_message = _status_messages[self._status]
|
||||
statflag_end = self.status_flag.get_current_value()
|
||||
if not statflag_end.value == 0:
|
||||
raise AdjustableError(
|
||||
f"Motor {self.alias.get_full_name()}({self.pvname}) cannot finish move with status flag {statflag_end.name} ."
|
||||
)
|
||||
|
||||
if self._status < 0:
|
||||
raise AdjustableError(self._status_message)
|
||||
elif self._status > 0:
|
||||
@@ -856,6 +911,85 @@ class MForceSettings(Assembly):
|
||||
self.set_controller_command(f"IS=1,{switch1},{polarity}")
|
||||
self.set_controller_command(f"IS=2,{switch2},{polarity}")
|
||||
|
||||
class SmaractSettings(Assembly):
|
||||
def __init__(self,
|
||||
pvname,
|
||||
name=None,
|
||||
):
|
||||
super().__init__(name=name)
|
||||
self.pvname = pvname
|
||||
|
||||
self._append(
|
||||
PvRecord,
|
||||
pvsetname = self.pvname + "_PTYP",
|
||||
pvreadbackname=self.pvname + "_PTYP_RB",
|
||||
name="sensor_type_num",
|
||||
is_setting=True,
|
||||
)
|
||||
self._append(
|
||||
AdjustablePv,
|
||||
self.pvname + "_AUTOZERO",
|
||||
name="autozero_on_homing",
|
||||
is_setting=True,
|
||||
)
|
||||
self._append(
|
||||
AdjustablePv,
|
||||
self.pvname + "_MCLF",
|
||||
name="max_frequency",
|
||||
is_setting=True,
|
||||
)
|
||||
|
||||
self._append(
|
||||
AdjustableFS,
|
||||
file_path="/photonics/home/gac-bernina/eco/configuration/smaract/setting_table",
|
||||
name="_setting_table",
|
||||
is_setting=False,
|
||||
is_display=False,
|
||||
)
|
||||
|
||||
def recall(self, stage_alias_or_model=None):
|
||||
setting_table = self._setting_table()
|
||||
stages = np.array([(alias, settings["models"]) for alias, settings in setting_table.items()], dtype=object)
|
||||
if stage_alias_or_model is not None:
|
||||
if stage_alias_or_model in stages.T[0]:
|
||||
alias = stage_alias_or_model
|
||||
else:
|
||||
idx = [stage_alias_or_model in a for a in stages.T[1]]
|
||||
if np.sum(idx) == 1:
|
||||
alias = stages.T[0][idx][0]
|
||||
if np.sum(idx) > 1:
|
||||
print("Multiple entries found for model {stage_alias_or_model}. Please check _settings_table")
|
||||
return
|
||||
if np.sum(idx ==0 ):
|
||||
print("No entries found for model {stage_alias_or_model}. Please check _settings_table or model number / alias.")
|
||||
return
|
||||
else:
|
||||
stages = [(alias, settings["models"]) for alias, settings in setting_table.items()]
|
||||
input_message = "\nSelect the stage to load setting:\n q) quit\n"
|
||||
input_message += f'{"Idx":>3} {"Alias":<30} {"Models"}\n'
|
||||
for index, (alias, model) in enumerate(stages):
|
||||
input_message += f'{index:>3}) {alias:<30} {model}\n'
|
||||
input_message += 'Input: '
|
||||
idx = ''
|
||||
while idx not in range(len(stages)):
|
||||
idx = input(input_message)
|
||||
if idx == 'q':
|
||||
return
|
||||
else:
|
||||
try:
|
||||
idx = int(idx)
|
||||
except:
|
||||
continue
|
||||
print(f'Selected stage: {stages[idx]}')
|
||||
alias = stages[idx][0]
|
||||
stage_settings = setting_table[alias]
|
||||
if np.any([mcs in self.pvname for mcs in ["SARES23-USR", "SARES23-LIC"]]):
|
||||
mcs_code = stage_settings["MCS"]
|
||||
else:
|
||||
mcs_code = stage_settings["MCS2"]
|
||||
stage_settings["settings"]["sensor_type_num"] = mcs_code
|
||||
self.memory.recall(input_obj=stage_settings)
|
||||
|
||||
|
||||
@spec_convenience
|
||||
@update_changes
|
||||
@@ -870,6 +1004,7 @@ class SmaractRecord(Assembly):
|
||||
# alias_fields={"readback": "RBV"},
|
||||
alias_fields={},
|
||||
backlash_definition=False,
|
||||
expect_bad_limits=True,
|
||||
):
|
||||
super().__init__(name=name)
|
||||
# self.settings.append(self)
|
||||
@@ -883,6 +1018,16 @@ class SmaractRecord(Assembly):
|
||||
Alias(an, channel=".".join([pvname, af]), channeltype="CA")
|
||||
)
|
||||
self._currentChange = None
|
||||
|
||||
self._append(
|
||||
SmaractSettings, self.pvname, name="motor_parameters", is_setting=False
|
||||
)
|
||||
self._append(
|
||||
AdjustablePv, self.pvname + ".LLM", name="limit_low", is_setting=True
|
||||
)
|
||||
self._append(
|
||||
AdjustablePv, self.pvname + ".HLM", name="limit_high", is_setting=True
|
||||
)
|
||||
self._append(
|
||||
AdjustablePvEnum,
|
||||
self.pvname + ".STAT",
|
||||
@@ -890,6 +1035,12 @@ class SmaractRecord(Assembly):
|
||||
is_setting=False,
|
||||
is_display=True,
|
||||
)
|
||||
self._append(
|
||||
AdjustablePv,
|
||||
self.pvname + ".ACCL",
|
||||
name="acceleration_time",
|
||||
is_setting=True,
|
||||
)
|
||||
self._append(
|
||||
AdjustablePvEnum, self.pvname + ".DIR", name="direction", is_setting=True
|
||||
)
|
||||
@@ -897,17 +1048,13 @@ class SmaractRecord(Assembly):
|
||||
self._append(
|
||||
AdjustablePv, self.pvname + ".FOFF", name="force_offset", is_setting=True
|
||||
)
|
||||
self._append(
|
||||
AdjustablePv,
|
||||
self.pvname + "_AUTO_SET_EGU",
|
||||
name="autoset_unit",
|
||||
is_setting=True,
|
||||
)
|
||||
self._append(AdjustablePv, self.pvname + ".VELO", name="speed", is_setting=True)
|
||||
|
||||
self._append(
|
||||
AdjustablePv,
|
||||
self.pvname + ".HOMR",
|
||||
name="home_forward",
|
||||
is_setting=True,
|
||||
is_setting=False,
|
||||
is_status=False,
|
||||
is_display=False,
|
||||
)
|
||||
@@ -915,7 +1062,7 @@ class SmaractRecord(Assembly):
|
||||
AdjustablePv,
|
||||
self.pvname + ".HOMR",
|
||||
name="home_reverse",
|
||||
is_setting=True,
|
||||
is_setting=False,
|
||||
is_status=False,
|
||||
is_display=False,
|
||||
)
|
||||
@@ -927,21 +1074,7 @@ class SmaractRecord(Assembly):
|
||||
is_setting=False,
|
||||
is_display=True,
|
||||
)
|
||||
self._append(
|
||||
AdjustablePv, self.pvname + ".VELO", name="speed", is_setting=False
|
||||
)
|
||||
self._append(
|
||||
AdjustablePv,
|
||||
self.pvname + ".ACCL",
|
||||
name="acceleration_time",
|
||||
is_setting=False,
|
||||
)
|
||||
self._append(
|
||||
AdjustablePv, self.pvname + ".LLM", name="limit_low", is_setting=False
|
||||
)
|
||||
self._append(
|
||||
AdjustablePv, self.pvname + ".HLM", name="limit_high", is_setting=False
|
||||
)
|
||||
|
||||
self._append(
|
||||
AdjustablePvEnum, self.pvname + ".SPMG", name="mode", is_setting=False
|
||||
)
|
||||
@@ -956,36 +1089,24 @@ class SmaractRecord(Assembly):
|
||||
is_display="recursive",
|
||||
is_status=True,
|
||||
)
|
||||
# self._append(
|
||||
# AdjustablePvEnum,
|
||||
# self.pvname + ".SPMG",
|
||||
# name="motor_state",
|
||||
# is_setting=False,
|
||||
# )
|
||||
|
||||
self._append(
|
||||
AdjustablePvString, self.pvname + ".EGU", name="unit", is_setting=False
|
||||
AdjustablePvString, self.pvname + ".EGU", name="unit", is_setting=True
|
||||
)
|
||||
self._append(
|
||||
AdjustablePvString,
|
||||
self.pvname + ".DESC",
|
||||
name="description",
|
||||
is_setting=False,
|
||||
is_setting=True,
|
||||
)
|
||||
self._append(
|
||||
AdjustablePv,
|
||||
self.pvname + "_CAL_CMD",
|
||||
self.pvname + "_CAL",
|
||||
name="_calibrate_sensor",
|
||||
is_setting=False,
|
||||
is_setting=True,
|
||||
is_status=False,
|
||||
is_display=False,
|
||||
)
|
||||
self._append(
|
||||
AdjustablePvEnum,
|
||||
self.pvname + "_POS_TYPE_RB",
|
||||
pvname_set=self.pvname + "_POS_TYPE_SP",
|
||||
name="sensor_type",
|
||||
is_setting=True,
|
||||
)
|
||||
if backlash_definition:
|
||||
self._append(
|
||||
AdjustablePv,
|
||||
@@ -1011,6 +1132,388 @@ class SmaractRecord(Assembly):
|
||||
name="backlash_fraction",
|
||||
is_setting=True,
|
||||
)
|
||||
if expect_bad_limits:
|
||||
self.check_bad_limits()
|
||||
|
||||
def check_bad_limits(self, abs_set_value=2**53):
|
||||
ll, hl = self.get_limits()
|
||||
if ll == 0 and hl == 0:
|
||||
self.set_limits(-abs_set_value, abs_set_value)
|
||||
|
||||
def home(self):
|
||||
self.home_forward(1)
|
||||
time.sleep(0.1)
|
||||
while not self.flags.is_homed.get_current_value():
|
||||
time.sleep(0.1)
|
||||
|
||||
def calibrate_sensor(self):
|
||||
self._calibrate_sensor(1)
|
||||
time.sleep(0.1)
|
||||
while not self.flags.motion_complete.get_current_value():
|
||||
time.sleep(0.1)
|
||||
|
||||
def set_target_value(self, value, hold=False, check=True):
|
||||
"""Adjustable convention"""
|
||||
|
||||
def changer(value):
|
||||
self._status = self._motor.move(value, ignore_limits=(not check), wait=True)
|
||||
self._status_message = _status_messages[self._status]
|
||||
if self._status < 0:
|
||||
raise AdjustableError(self._status_message)
|
||||
elif self._status > 0:
|
||||
print("\n")
|
||||
print(self._status_message)
|
||||
|
||||
# changer = lambda value: self._motor.move(\
|
||||
# value, ignore_limits=(not check),
|
||||
# wait=True)
|
||||
return Changer(
|
||||
target=value,
|
||||
parent=self,
|
||||
changer=changer,
|
||||
hold=hold,
|
||||
stopper=self._motor.stop,
|
||||
)
|
||||
|
||||
def stop(self):
|
||||
"""Adjustable convention"""
|
||||
try:
|
||||
self._currentChange.stop()
|
||||
except:
|
||||
self.mode.set_target_value(0)
|
||||
pass
|
||||
|
||||
def get_current_value(self, posType="user", readback=True):
|
||||
"""Adjustable convention"""
|
||||
_keywordChecker([("posType", posType, _posTypes)])
|
||||
if posType == "user":
|
||||
return self._motor.get_position(readback=readback)
|
||||
if posType == "dial":
|
||||
return self._motor.get_position(readback=readback, dial=True)
|
||||
if posType == "raw":
|
||||
return self._motor.get_position(readback=readback, raw=True)
|
||||
|
||||
def reset_current_value_to(self, value, posType="user"):
|
||||
"""Adjustable convention"""
|
||||
_keywordChecker([("posType", posType, _posTypes)])
|
||||
if posType == "user":
|
||||
return self._motor.set_position(value)
|
||||
if posType == "dial":
|
||||
return self._motor.set_position(value, dial=True)
|
||||
if posType == "raw":
|
||||
return self._motor.set_position(value, raw=True)
|
||||
|
||||
def get_moveDone(self):
|
||||
"""Adjustable convention"""
|
||||
""" 0: moving 1: move done"""
|
||||
return PV(str(self.Id + ".DMOV")).value
|
||||
|
||||
def set_limits(
|
||||
self, low_limit, high_limit, posType="user", relative_to_present=False
|
||||
):
|
||||
"""
|
||||
set limits. usage: set_limits(low_limit, high_limit)
|
||||
|
||||
"""
|
||||
_keywordChecker([("posType", posType, _posTypes)])
|
||||
ll_name, hl_name = "LLM", "HLM"
|
||||
if posType == "dial":
|
||||
ll_name, hl_name = "DLLM", "DHLM"
|
||||
if relative_to_present:
|
||||
v = self.get_current_value(posType=posType)
|
||||
low_limit = v + low_limit
|
||||
high_limit = v + high_limit
|
||||
self._motor.put(ll_name, low_limit)
|
||||
self._motor.put(hl_name, high_limit)
|
||||
|
||||
def add_value_callback(self, callback, index=None):
|
||||
return self._motor.get_pv("RBV").add_callback(callback=callback, index=index)
|
||||
|
||||
def clear_value_callback(self, index=None):
|
||||
if index:
|
||||
self._motor.get_pv("RBV").remove_callback(index)
|
||||
else:
|
||||
self._motor.get_pv("RBV").clear_callbacks()
|
||||
|
||||
def get_limits(self, posType="user"):
|
||||
"""Adjustable convention"""
|
||||
_keywordChecker([("posType", posType, _posTypes)])
|
||||
ll_name, hl_name = "LLM", "HLM"
|
||||
if posType == "dial":
|
||||
ll_name, hl_name = "DLLM", "DHLM"
|
||||
return self._motor.get(ll_name), self._motor.get(hl_name)
|
||||
|
||||
def gui(self):
|
||||
pv, m = tuple(self.pvname.split(":"))
|
||||
self._run_cmd(f'caqtdm -macro "P={pv},M=:{m}, T=MCS" /sf/controls/config/qt/motorx_all.ui')
|
||||
|
||||
def gui_extra(self):
|
||||
pv, m = tuple(self.pvname.split(":"))
|
||||
self._run_cmd(f'caqtdm -macro "P={pv},M={m}" /ioc/modules/qt/MCS_extra.ui')
|
||||
|
||||
# return string with motor value as variable representation
|
||||
def __str__(self):
|
||||
# """ return short info for the current motor"""
|
||||
s = f"{self.name}"
|
||||
s += f"\t@ {colorama.Style.BRIGHT}{self.get_current_value():1.6g}{colorama.Style.RESET_ALL} (dial @ {self.get_current_value(posType='dial'):1.6g}; stat: {self.status_flag().name})"
|
||||
# # s += "\tuser limits (low,high) : {:1.6g},{:1.6g}\n".format(*self.get_limits())
|
||||
s += f"\n{colorama.Style.DIM}low limit {colorama.Style.RESET_ALL}"
|
||||
s += ValueInRange(*self.get_limits()).get_str(self.get_current_value())
|
||||
s += f" {colorama.Style.DIM}high limit{colorama.Style.RESET_ALL}"
|
||||
# # s += "\tuser limits (low,high) : {:1.6g},{1.6g}".format(self.get_limits())
|
||||
return s
|
||||
|
||||
def __repr__(self):
|
||||
print(str(self))
|
||||
return object.__repr__(self)
|
||||
|
||||
def __call__(self, value):
|
||||
self._currentChange = self.set_target_value(value)
|
||||
|
||||
def _tweak_ioc(self, step_value=None):
|
||||
pv = self._motor.get_pv("TWV")
|
||||
pvf = self._motor.get_pv("TWF")
|
||||
pvr = self._motor.get_pv("TWR")
|
||||
if not step_value:
|
||||
step_value = pv.get()
|
||||
print(f"Tweaking {self.name} at step size {step_value}", end="\r")
|
||||
|
||||
help = "q = exit; up = step*2; down = step/2, left = neg dir, right = pos dir\n"
|
||||
help = help + "g = go abs, s = set"
|
||||
print(f"tweaking {self.name}")
|
||||
print(help)
|
||||
print(f"Starting at {self.get_current_value()}")
|
||||
step_value = float(step_value)
|
||||
oldstep = 0
|
||||
k = KeyPress()
|
||||
cll = colorama.ansi.clear_line()
|
||||
|
||||
class Printer:
|
||||
def print(self, **kwargs):
|
||||
print(
|
||||
cll + f"stepsize: {self.stepsize}; current: {kwargs['value']}",
|
||||
end="\r",
|
||||
)
|
||||
|
||||
p = Printer()
|
||||
print(" ")
|
||||
p.stepsize = step_value
|
||||
p.print(value=self.get_current_value())
|
||||
ind_callback = self.add_value_callback(p.print)
|
||||
pv.put(step_value)
|
||||
while k.isq() is False:
|
||||
if oldstep != step_value:
|
||||
p.stepsize = step_value
|
||||
p.print(value=self.get_current_value())
|
||||
oldstep = step_value
|
||||
k.waitkey()
|
||||
if k.isu():
|
||||
step_value = step_value * 2.0
|
||||
pv.put(step_value)
|
||||
elif k.isd():
|
||||
step_value = step_value / 2.0
|
||||
pv.put(step_value)
|
||||
elif k.isr():
|
||||
pvf.put(1)
|
||||
elif k.isl():
|
||||
pvr.put(1)
|
||||
elif k.iskey("g"):
|
||||
print("enter absolute position (char to abort go to)")
|
||||
sys.stdout.flush()
|
||||
v = sys.stdin.readline()
|
||||
try:
|
||||
v = float(v.strip())
|
||||
self.set_target_value(v)
|
||||
except:
|
||||
print("value cannot be converted to float, exit go to mode ...")
|
||||
sys.stdout.flush()
|
||||
elif k.iskey("s"):
|
||||
print("enter new set value (char to abort setting)")
|
||||
sys.stdout.flush()
|
||||
v = sys.stdin.readline()
|
||||
try:
|
||||
v = float(v[0:-1])
|
||||
self.reset_current_value_to(v)
|
||||
except:
|
||||
print("value cannot be converted to float, exit go to mode ...")
|
||||
sys.stdout.flush()
|
||||
elif k.isq():
|
||||
break
|
||||
else:
|
||||
print(help)
|
||||
self.clear_value_callback(index=ind_callback)
|
||||
print(f"final position: {self.get_current_value()}")
|
||||
print(f"final tweak step: {pv.get()}")
|
||||
|
||||
def tweak(self, *args, **kwargs):
|
||||
return self._tweak_ioc(*args, **kwargs)
|
||||
|
||||
|
||||
@spec_convenience
|
||||
@update_changes
|
||||
@get_from_archive
|
||||
@value_property
|
||||
class SmaractRecord_old(Assembly):
|
||||
#Note: this is the one that works with the old SmarAct IOCs before Thierry made changes in 09/2023
|
||||
def __init__(
|
||||
self,
|
||||
pvname,
|
||||
name=None,
|
||||
elog=None,
|
||||
# alias_fields={"readback": "RBV"},
|
||||
alias_fields={},
|
||||
backlash_definition=False,
|
||||
expect_bad_limits=True,
|
||||
):
|
||||
super().__init__(name=name)
|
||||
# self.settings.append(self)
|
||||
self.settings_collection.append(self, force=True)
|
||||
|
||||
self.pvname = pvname
|
||||
self._motor = _Motor(pvname)
|
||||
self._elog = elog
|
||||
for an, af in alias_fields.items():
|
||||
self.alias.append(
|
||||
Alias(an, channel=".".join([pvname, af]), channeltype="CA")
|
||||
)
|
||||
self._currentChange = None
|
||||
|
||||
self._append(
|
||||
AdjustablePvEnum,
|
||||
self.pvname + "_POS_TYPE_RB",
|
||||
pvname_set=self.pvname + "_POS_TYPE_SP",
|
||||
name="sensor_type",
|
||||
is_setting=True,
|
||||
)
|
||||
self._append(
|
||||
AdjustablePv,
|
||||
self.pvname + "_MAX_FREQ",
|
||||
name="max_frequency",
|
||||
is_setting=True,
|
||||
)
|
||||
self._append(AdjustablePv, self.pvname + ".VELO", name="speed", is_setting=True)
|
||||
self._append(
|
||||
AdjustablePv,
|
||||
self.pvname + ".ACCL",
|
||||
name="acceleration_time",
|
||||
is_setting=True,
|
||||
)
|
||||
self._append(
|
||||
AdjustablePv, self.pvname + ".LLM", name="limit_low", is_setting=True
|
||||
)
|
||||
self._append(
|
||||
AdjustablePv, self.pvname + ".HLM", name="limit_high", is_setting=True
|
||||
)
|
||||
self._append(
|
||||
AdjustablePvEnum,
|
||||
self.pvname + ".STAT",
|
||||
name="status_flag",
|
||||
is_setting=False,
|
||||
is_display=True,
|
||||
)
|
||||
self._append(
|
||||
AdjustablePvEnum, self.pvname + ".DIR", name="direction", is_setting=True
|
||||
)
|
||||
self._append(AdjustablePv, self.pvname + ".OFF", name="offset", is_setting=True)
|
||||
self._append(
|
||||
AdjustablePv, self.pvname + ".FOFF", name="force_offset", is_setting=True
|
||||
)
|
||||
self._append(
|
||||
AdjustablePv,
|
||||
self.pvname + "_AUTO_SET_EGU",
|
||||
name="autoset_unit",
|
||||
is_setting=True,
|
||||
)
|
||||
|
||||
self._append(
|
||||
AdjustablePv,
|
||||
self.pvname + ".HOMR",
|
||||
name="home_forward",
|
||||
is_setting=False,
|
||||
is_status=False,
|
||||
is_display=False,
|
||||
)
|
||||
self._append(
|
||||
AdjustablePv,
|
||||
self.pvname + ".HOMR",
|
||||
name="home_reverse",
|
||||
is_setting=False,
|
||||
is_status=False,
|
||||
is_display=False,
|
||||
)
|
||||
|
||||
self._append(
|
||||
DetectorPvData,
|
||||
self.pvname + ".RBV",
|
||||
name="readback",
|
||||
is_setting=False,
|
||||
is_display=True,
|
||||
)
|
||||
|
||||
self._append(
|
||||
AdjustablePvEnum, self.pvname + ".SPMG", name="mode", is_setting=False
|
||||
)
|
||||
self._append(
|
||||
DetectorPvData, self.pvname + ".MSTA", name="_flags", is_setting=False
|
||||
)
|
||||
self._append(
|
||||
SmaractRecordFlags,
|
||||
self.pvname,
|
||||
self._flags,
|
||||
name="flags",
|
||||
is_display="recursive",
|
||||
is_status=True,
|
||||
)
|
||||
|
||||
self._append(
|
||||
AdjustablePvString, self.pvname + ".EGU", name="unit", is_setting=True
|
||||
)
|
||||
self._append(
|
||||
AdjustablePvString,
|
||||
self.pvname + ".DESC",
|
||||
name="description",
|
||||
is_setting=True,
|
||||
)
|
||||
self._append(
|
||||
AdjustablePv,
|
||||
self.pvname + "_CAL_CMD",
|
||||
name="_calibrate_sensor",
|
||||
is_setting=True,
|
||||
is_status=False,
|
||||
is_display=False,
|
||||
)
|
||||
if backlash_definition:
|
||||
self._append(
|
||||
AdjustablePv,
|
||||
self.pvname + ".BVEL",
|
||||
name="backlash_velocity",
|
||||
is_setting=True,
|
||||
)
|
||||
self._append(
|
||||
AdjustablePv,
|
||||
self.pvname + ".BACC",
|
||||
name="backlash_acceleration",
|
||||
is_setting=True,
|
||||
)
|
||||
self._append(
|
||||
AdjustablePv,
|
||||
self.pvname + ".BDST",
|
||||
name="backlash_distance",
|
||||
is_setting=True,
|
||||
)
|
||||
self._append(
|
||||
AdjustablePv,
|
||||
self.pvname + ".FRAC",
|
||||
name="backlash_fraction",
|
||||
is_setting=True,
|
||||
)
|
||||
if expect_bad_limits:
|
||||
self.check_bad_limits()
|
||||
|
||||
def check_bad_limits(self, abs_set_value=2**53):
|
||||
ll, hl = self.get_limits()
|
||||
if ll == 0 and hl == 0:
|
||||
self.set_limits(-abs_set_value, abs_set_value)
|
||||
|
||||
def home(self):
|
||||
self.home_forward(1)
|
||||
|
||||
@@ -0,0 +1,179 @@
|
||||
from cam_server import CamClient, PipelineClient
|
||||
|
||||
from eco.devices_general.utilities import Changer
|
||||
from eco.elements.adj_obj import AdjustableObject, DetectorObject
|
||||
from eco.elements.detector import DetectorGet
|
||||
from ..aliases import Alias, append_object_to_object
|
||||
from ..elements.adjustable import AdjustableVirtual, AdjustableGetSet, value_property
|
||||
from ..epics.adjustable import AdjustablePv, AdjustablePvEnum
|
||||
from ..elements.assembly import Assembly
|
||||
from .motors import MotorRecord
|
||||
import sys
|
||||
from pathlib import Path
|
||||
import time
|
||||
|
||||
sys.path.append("/sf/bernina/config/src/python/sf_databuffer/")
|
||||
import bufferutils
|
||||
|
||||
CAM_CLIENT = None
|
||||
PIPELINE_CLIENT = None
|
||||
|
||||
|
||||
def get_camclient():
|
||||
global CAM_CLIENT
|
||||
if not CAM_CLIENT:
|
||||
CAM_CLIENT = CamClient()
|
||||
return CAM_CLIENT
|
||||
|
||||
|
||||
def get_pipelineclient():
|
||||
global PIPELINE_CLIENT
|
||||
if not PIPELINE_CLIENT:
|
||||
PIPELINE_CLIENT = PipelineClient()
|
||||
return PIPELINE_CLIENT
|
||||
|
||||
|
||||
@value_property
|
||||
class Pipeline(Assembly):
|
||||
def __init__(self, pipeline_name, name=None, camserver_group=None):
|
||||
super().__init__(name=name)
|
||||
self.pipeline_name = pipeline_name
|
||||
self.camserver_group = camserver_group
|
||||
self._append(AdjustableGetSet,
|
||||
self._get_config,
|
||||
self._set_config,
|
||||
cache_get_seconds =.05,
|
||||
precision=0,
|
||||
check_interval=None,
|
||||
name='_config',
|
||||
is_setting=False,
|
||||
is_display=False)
|
||||
|
||||
self._append(AdjustableObject, self._config, name='config',is_setting=True, is_display='recursive')
|
||||
self._append(DetectorGet, self._get_info, cache_get_seconds =.05, name='_info', is_setting=False, is_display=False)
|
||||
self._append(DetectorObject, self._info, name='info', is_display='recursive', is_setting=False)
|
||||
|
||||
|
||||
# @property
|
||||
# def cc(self):
|
||||
# return get_camclient()
|
||||
|
||||
@property
|
||||
def pc(self):
|
||||
return get_pipelineclient()
|
||||
|
||||
def _get_config(self):
|
||||
return self.pc.get_pipeline_config(self.pipeline_name)
|
||||
|
||||
def _set_config(self, value, hold=False):
|
||||
return Changer(
|
||||
target=value,
|
||||
changer=lambda v: self.pc.set_pipeline_config(self.pipeline_name, v),
|
||||
hold=hold,
|
||||
)
|
||||
|
||||
def _get_info(self, reject_kws = ['config']):
|
||||
info = self.pc.get_instance_info(self.pipeline_name)
|
||||
for rkw in reject_kws:
|
||||
info.pop(rkw)
|
||||
return info
|
||||
|
||||
def _get_stream(self):
|
||||
return self.pc.get_instance_stream(self.pipeline_name)
|
||||
|
||||
|
||||
|
||||
# ### convenience functions ###
|
||||
# def set_alias(self, alias=None):
|
||||
# """creates an alias in the camera config on the server. If no alias is provided, it defaults to the camera name"""
|
||||
# if not alias:
|
||||
# alias = self.camserver_alias
|
||||
# self.set_config_fields({"alias": [alias.upper()]})
|
||||
|
||||
# def set_group(self, group=None):
|
||||
# """creates an alias in the camera config on the server. If no alias is provided, it defaults to the camera name"""
|
||||
# if not group:
|
||||
# group = self.camserver_group
|
||||
# self.set_config_fields({"group": group})
|
||||
|
||||
def restart_pipeline(self):
|
||||
base_directory = "/sf/bernina/config/src/python/sf_databuffer/"
|
||||
label = self.pipeline_name
|
||||
|
||||
policies = bufferutils.read_files(base_directory / Path("policies"), "policies")
|
||||
sources = bufferutils.read_files(base_directory / Path("sources"), "sources")
|
||||
sources_new = sources.copy()
|
||||
|
||||
# Only for debugging purposes
|
||||
labeled_sources = bufferutils.get_labeled_sources(sources_new, label)
|
||||
for s in labeled_sources:
|
||||
bufferutils.logging.info(f"Restarting {s['stream']}")
|
||||
|
||||
sources_new = bufferutils.remove_labeled_source(sources_new, label)
|
||||
|
||||
# Stopping the removed source(s)
|
||||
bufferutils.update_sources_and_policies(sources_new, policies)
|
||||
|
||||
# Starting the source(s) again
|
||||
bufferutils.update_sources_and_policies(sources, policies)
|
||||
|
||||
def stop(self):
|
||||
self.pc.stop_instance(self.pipeline_name)
|
||||
|
||||
# def set_cross(self, x, y, x_um_per_px=None, y_um_per_px=None):
|
||||
# """set x and y position of the refetence marker on a camera px/um calibration is conserved if no new value is given"""
|
||||
# calib = self.get_current_value()["camera_calibration"]
|
||||
# if calib:
|
||||
# if not x_um_per_px:
|
||||
# x_um_per_px = calib["reference_marker_width"] / abs(
|
||||
# calib["reference_marker"][2] - calib["reference_marker"][0]
|
||||
# )
|
||||
# if not y_um_per_px:
|
||||
# y_um_per_px = calib["reference_marker_height"] / abs(
|
||||
# calib["reference_marker"][3] - calib["reference_marker"][1]
|
||||
# )
|
||||
# else:
|
||||
# calib = {}
|
||||
# x_um_per_px = 1
|
||||
# y_um_per_px = 1
|
||||
|
||||
# calib["reference_marker"] = [x - 1, y - 1, x + 1, y + 1]
|
||||
# calib["reference_marker_width"] = 2 * x_um_per_px
|
||||
# calib["reference_marker_height"] = 2 * y_um_per_px
|
||||
# self.set_config_fields(fields={"camera_calibration": calib})
|
||||
|
||||
# def set_config_fields_multiple_cams(self, conditions, fields):
|
||||
# """
|
||||
# conditions is a dictionary holding the conditions to select a subset of cameras, e.g. {"group": Bernina}
|
||||
# fields is a dictionary containing the keys and values that should be updated, e.g. fields={'alias': ['huhu', 'duda']}
|
||||
# """
|
||||
# cams = {
|
||||
# cam: self.cc.get_camera_config(cam)
|
||||
# for cam in self.cc.get_cameras()
|
||||
# if not "jungfrau" in cam
|
||||
# }
|
||||
# cams_selected = {}
|
||||
# for cam, cfg in cams.items():
|
||||
# try:
|
||||
# if all([value in cfg[key] for key, value in conditions.items()]):
|
||||
# cfg.update(fields)
|
||||
# self.cc.set_camera_config(cam, cfg)
|
||||
# cams_selected[cam] = cfg
|
||||
# except Exception as e:
|
||||
# print(f"{type(e)} {e} in cam {cam}")
|
||||
# return cams_selected
|
||||
|
||||
# def clear_all_bernina_aliases(self, verbose=True):
|
||||
# cams_selected = self.set_config_fields_multiple_cams(
|
||||
# conditions={"group": "Bernina"}, fields={"alias": []}
|
||||
# )
|
||||
# if verbose:
|
||||
# print(f"Reset alias of {len(cams_selected)} cameras")
|
||||
# print(cams_selected.keys())
|
||||
|
||||
# def __repr__(self):
|
||||
# s = f"**Camera Server Config {self.pipeline_name} with Alias {self.name}**\n"
|
||||
# for key, item in self.get_current_value().items():
|
||||
# s += f"{key:20} : {item}\n"
|
||||
# return s
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
from ..epics.adjustable import AdjustablePvEnum, AdjustablePvString
|
||||
from ..epics.adjustable import AdjustablePvEnum, AdjustablePvString, AdjustablePv
|
||||
from ..elements.assembly import Assembly
|
||||
from ..epics.detector import DetectorPvEnum, DetectorPvData
|
||||
from eco.elements.adjustable import spec_convenience
|
||||
|
||||
|
||||
class PowerSocket(Assembly):
|
||||
@@ -65,3 +66,69 @@ class GudeStrip(Assembly):
|
||||
self._append(
|
||||
DetectorPvData, pvbase + ":VOLTAGE", is_display=True, name="voltage"
|
||||
)
|
||||
|
||||
|
||||
|
||||
class MpodStatus(Assembly):
|
||||
def __init__(self,pvbase,channel_number, module_string='LV_OMPV_1', name=None):
|
||||
super().__init__(name=name)
|
||||
self.pvbase = pvbase
|
||||
self._module_string = module_string
|
||||
self.channel_number = channel_number
|
||||
self._append(DetectorPvEnum,self.pvbase + f':{self._module_string}_CH{self.channel_number}_ON',name='is_on')
|
||||
self._append(DetectorPvEnum,self.pvbase + f':{self._module_string}_CH{self.channel_number}_INHIBIT',name='inhibited')
|
||||
self._append(DetectorPvEnum,self.pvbase + f':{self._module_string}_CH{self.channel_number}_FAILURE_MIN_SENS_VOLTAGE',name='voltage_readback_low')
|
||||
self._append(DetectorPvEnum,self.pvbase + f':{self._module_string}_CH{self.channel_number}_FAILURE_MAX_SENS_VOLTAGE',name='voltage_readback_high')
|
||||
self._append(DetectorPvEnum,self.pvbase + f':{self._module_string}_CH{self.channel_number}_FAILURE_MAX_TERM_VOLTAGE',name='terminal_voltage_readback_high')
|
||||
self._append(DetectorPvEnum,self.pvbase + f':{self._module_string}_CH{self.channel_number}_FAILURE_MAX_CURRENT',name='current_too_high')
|
||||
self._append(DetectorPvEnum,self.pvbase + f':{self._module_string}_CH{self.channel_number}_FAILURE_MAX_TEMP',name='temperature_high')
|
||||
self._append(DetectorPvEnum,self.pvbase + f':{self._module_string}_CH{self.channel_number}_FAILURE_MAX_POWER',name='output_power_high')
|
||||
self._append(DetectorPvEnum,self.pvbase + f':{self._module_string}_CH{self.channel_number}_TIMEOUT',name='communication_timeout')
|
||||
self._append(DetectorPvEnum,self.pvbase + f':{self._module_string}_CH{self.channel_number}_CURR_CTRL',name='constant_current_mode')
|
||||
self._append(DetectorPvEnum,self.pvbase + f':{self._module_string}_CH{self.channel_number}_RMP_UP',name='ramping_up')
|
||||
self._append(DetectorPvEnum,self.pvbase + f':{self._module_string}_CH{self.channel_number}_RMP_DOWN',name='ramping_down')
|
||||
self._append(DetectorPvEnum,self.pvbase + f':{self._module_string}_CH{self.channel_number}_KILL',name='kill_enabled')
|
||||
self._append(DetectorPvEnum,self.pvbase + f':{self._module_string}_CH{self.channel_number}_EMERGENCY_OFF',name='emergency_off')
|
||||
self._append(DetectorPvEnum,self.pvbase + f':{self._module_string}_CH{self.channel_number}_FINE_ADJUST',name='fine_adjustment')
|
||||
self._append(DetectorPvEnum,self.pvbase + f':{self._module_string}_CH{self.channel_number}_VOLTAGE_CTRL',name='constant_voltage_mode')
|
||||
self._append(DetectorPvEnum,self.pvbase + f':{self._module_string}_CH{self.channel_number}_LOW_CURR_MEAS',name='current_readback_range_low')
|
||||
self._append(DetectorPvEnum,self.pvbase + f':{self._module_string}_CH{self.channel_number}_OUT_CURR_OOB',name='current_readback_range_high')
|
||||
self._append(DetectorPvEnum,self.pvbase + f':{self._module_string}_CH{self.channel_number}_OVERCURRENT',name='overcurrent')
|
||||
|
||||
@spec_convenience
|
||||
class MpodChannel(Assembly):
|
||||
def __init__(self,pvbase,channel_number, module_string='LV_OMPV_1', name=None):
|
||||
super().__init__(name=name)
|
||||
self.pvbase = pvbase
|
||||
self._module_string = module_string
|
||||
self.channel_number = channel_number
|
||||
self._append(AdjustablePvEnum,self.pvbase+f':{self._module_string}_CH{self.channel_number}_SWITCH_SP', name='on', is_setting=True)
|
||||
self._append(AdjustablePv,
|
||||
self.pvbase+f':{self._module_string}_CH{self.channel_number}_OUTPUT_V_SP',
|
||||
pvreadbackname = self.pvbase+f':{self._module_string}_CH{self.channel_number}_MEAS_SENS_V',
|
||||
pvlowlimname = self.pvbase+f':{self._module_string}_CH{self.channel_number}_OUTPUT_V_SP.LOPR',
|
||||
pvhighlimname = self.pvbase+f':{self._module_string}_CH{self.channel_number}_OUTPUT_V_SP.HOPR',
|
||||
name='voltage', is_setting=True)
|
||||
self._append(AdjustablePv,
|
||||
self.pvbase+f':{self._module_string}_CH{self.channel_number}_RMP_UP_RATE_SP',
|
||||
pvlowlimname = self.pvbase+f':{self._module_string}_CH{self.channel_number}_RMP_UP_RATE_SP.LOPR',
|
||||
pvhighlimname = self.pvbase+f':{self._module_string}_CH{self.channel_number}_RMP_UP_RATE_SP.HOPR',
|
||||
name='ramp_up', is_setting=True)
|
||||
self._append(AdjustablePv,
|
||||
self.pvbase+f':{self._module_string}_CH{self.channel_number}_RMP_DOWN_RATE_SP',
|
||||
pvlowlimname = self.pvbase+f':{self._module_string}_CH{self.channel_number}_RMP_DOWN_RATE_SP.LOPR',
|
||||
pvhighlimname = self.pvbase+f':{self._module_string}_CH{self.channel_number}_RMP_DOWN_RATE_SP.HOPR',
|
||||
name='ramp_down', is_setting=True)
|
||||
self._append(MpodStatus,self.pvbase, self.channel_number, self._module_string, name='flags')
|
||||
|
||||
def get_current_value(self,*args,**kwargs):
|
||||
return self.on.get_current_value(*args,**kwargs)
|
||||
|
||||
def set_target_value(self,*args,**kwargs):
|
||||
return self.on.set_target_value(*args,**kwargs)
|
||||
|
||||
class MpodModule(Assembly):
|
||||
def __init__(self,pvbase,channelnumbers, channelnames, module_string='LV_OMPV_1', name=None):
|
||||
super().__init__(name=name)
|
||||
for channelnumber,channelname in zip(channelnumbers,channelnames):
|
||||
self._append(MpodChannel,pvbase,channel_number=channelnumber, module_string=module_string,name=channelname)
|
||||
|
||||
+126
-3
@@ -1,10 +1,18 @@
|
||||
from eco.elements.assembly import Assembly
|
||||
from eco.epics.detector import DetectorPvData
|
||||
from eco.epics.adjustable import AdjustablePvString, AdjustablePv
|
||||
from eco.epics.adjustable import (
|
||||
AdjustablePvString,
|
||||
AdjustablePv,
|
||||
spec_convenience,
|
||||
tweak_option,
|
||||
)
|
||||
|
||||
|
||||
class AnalogInput(Assembly):
|
||||
def __init__(self, pvname, name=None):
|
||||
"""Analog input, which is defined by a PV name. There are linear calibration
|
||||
options (hidden adjustment and visible linear_calibration values):
|
||||
value = raw*linear_calibration_slope + linear_calibration_offset"""
|
||||
super().__init__(name=name)
|
||||
self.pvname = pvname
|
||||
self._append(
|
||||
@@ -17,6 +25,106 @@ class AnalogInput(Assembly):
|
||||
is_setting=True,
|
||||
is_display=True,
|
||||
)
|
||||
self._append(
|
||||
AdjustablePvString,
|
||||
self.pvname + ".EGU",
|
||||
name="unit",
|
||||
is_setting=False,
|
||||
is_display=True,
|
||||
)
|
||||
self.value.unit = self.unit
|
||||
self._append(
|
||||
DetectorPvData,
|
||||
self.pvname + ".RVAL",
|
||||
name="raw",
|
||||
is_setting=False,
|
||||
is_display=False,
|
||||
)
|
||||
self._append(
|
||||
AdjustablePv,
|
||||
self.pvname + ".AOFF",
|
||||
name="_adj_offset",
|
||||
is_setting=True,
|
||||
is_display=False,
|
||||
)
|
||||
self._append(
|
||||
AdjustablePv,
|
||||
self.pvname + ".ASLO",
|
||||
name="_adj_slope",
|
||||
is_setting=True,
|
||||
is_display=False,
|
||||
)
|
||||
self._append(
|
||||
AdjustablePv,
|
||||
self.pvname + ".EOFF",
|
||||
name="linear_calibration_offset",
|
||||
is_setting=True,
|
||||
is_display=True,
|
||||
)
|
||||
self._append(
|
||||
AdjustablePv,
|
||||
self.pvname + ".ESLO",
|
||||
name="linear_calibration_slope",
|
||||
is_setting=True,
|
||||
is_display=True,
|
||||
)
|
||||
|
||||
def get_current_value(self):
|
||||
return self.value.get_current_value()
|
||||
|
||||
def reset_offset_current_value_to(self,value=0):
|
||||
self.linear_calibration_offset.set_target_value(
|
||||
(-1)
|
||||
* self.raw.get_current_value()
|
||||
* self.linear_calibration_slope.get_current_value()
|
||||
* self._adj_slope.get_current_value()
|
||||
+ value
|
||||
).wait()
|
||||
|
||||
def reset_slope_current_value_to(self,value=1):
|
||||
oslo = self.linear_calibration_slope.get_current_value()
|
||||
ooff = self.linear_calibration_offset.get_current_value()
|
||||
ooff_raw = ooff / oslo / self._adj_slope.get_current_value()
|
||||
# print(ooff_raw)
|
||||
|
||||
|
||||
nslo = value / (self.raw.get_current_value()+ooff_raw)
|
||||
self.linear_calibration_slope.set_target_value(nslo).wait()
|
||||
self.linear_calibration_offset.set_target_value(
|
||||
ooff_raw
|
||||
* nslo
|
||||
* self._adj_slope.get_current_value()
|
||||
).wait()
|
||||
|
||||
|
||||
class WagoAnalogInputs(Assembly):
|
||||
def __init__(self, pvbase, name=None):
|
||||
super().__init__(name=name)
|
||||
self.pvbase = pvbase
|
||||
for n in range(1, 9):
|
||||
self._append(AnalogInput, pvbase + f":ADC{n:02d}", name=f"ch{n:d}")
|
||||
|
||||
|
||||
@spec_convenience
|
||||
@tweak_option
|
||||
class AnalogOutput(Assembly):
|
||||
def __init__(self, pvname, name=None):
|
||||
super().__init__(name=name)
|
||||
self.pvname = pvname
|
||||
self._append(
|
||||
AdjustablePv,
|
||||
self.pvname,
|
||||
name="value",
|
||||
is_setting=True,
|
||||
is_display=True,
|
||||
)
|
||||
self._append(
|
||||
AdjustablePvString,
|
||||
self.pvname + ".DESC",
|
||||
name="description",
|
||||
is_setting=True,
|
||||
is_display=True,
|
||||
)
|
||||
self._append(
|
||||
AdjustablePvString,
|
||||
self.pvname + ".EGU",
|
||||
@@ -35,10 +143,25 @@ class AnalogInput(Assembly):
|
||||
def get_current_value(self):
|
||||
return self.value.get_current_value()
|
||||
|
||||
def set_target_value(self, *args, **kwargs):
|
||||
return self.value.set_target_value(*args, **kwargs)
|
||||
|
||||
class WagoAnalogInputs(Assembly):
|
||||
def __call__(self, *args):
|
||||
if args:
|
||||
self.value.set_target_Value(*args).wait()
|
||||
else:
|
||||
return self.value.get_current_value()
|
||||
|
||||
|
||||
class WagoAnalogOutputs(Assembly):
|
||||
def __init__(self, pvbase, name=None):
|
||||
super().__init__(name=name)
|
||||
self.pvbase = pvbase
|
||||
for n in range(1, 9):
|
||||
self._append(AnalogInput, pvbase + f":ADC{n:02d}", name=f"ch{n:d}")
|
||||
self._append(
|
||||
AnalogOutput,
|
||||
pvbase + f":DAC{n:02d}",
|
||||
name=f"ch{n:d}",
|
||||
is_setting=True,
|
||||
is_display=True,
|
||||
)
|
||||
|
||||
@@ -1,82 +0,0 @@
|
||||
from .dummy import *
|
||||
|
||||
# from ..utilities.config import initFromConfigList
|
||||
# from epics import PV
|
||||
# from .. import ecocnf
|
||||
# from ..aliases import NamespaceCollection
|
||||
# import logging
|
||||
|
||||
# from .config import components, config
|
||||
# import sys
|
||||
|
||||
|
||||
# _namespace = globals()
|
||||
|
||||
# _mod = sys.modules[__name__]
|
||||
|
||||
# _scope_name = "bernina"
|
||||
|
||||
# alias_namespaces = NamespaceCollection()
|
||||
|
||||
|
||||
# # from ..utilities.runtable import Run_Table
|
||||
# # def init(pgroup, alias_namespaces, instances):
|
||||
# # run_table = Run_Table(pgroup, alias_namespaces.bernina, instances)
|
||||
# # return run_table
|
||||
# def init(*args, lazy=None):
|
||||
# if args:
|
||||
# allnames = [tc["name"] for tc in components]
|
||||
# comp_toinit = []
|
||||
# for arg in args:
|
||||
# if not arg in allnames:
|
||||
# raise Exception(f"The component {arg} has no configuration defined!")
|
||||
# else:
|
||||
# comp_toinit.append(components[allnames.index(arg)])
|
||||
# else:
|
||||
# comp_toinit = components
|
||||
|
||||
# if lazy is None:
|
||||
# lazy = ecocnf.startup_lazy
|
||||
|
||||
# op = {}
|
||||
# for key, value in initFromConfigList(comp_toinit, components, lazy=lazy).items():
|
||||
# # _namespace[key] = value
|
||||
# _mod.__dict__[key] = value
|
||||
# op[key] = value
|
||||
# if not lazy:
|
||||
# print("made here")
|
||||
# if hasattr(value, "alias"):
|
||||
# for ta in value.alias.get_all():
|
||||
# try:
|
||||
# alias_namespaces.bernina.update(
|
||||
# ta["alias"], ta["channel"], ta["channeltype"]
|
||||
# )
|
||||
# except:
|
||||
# print(f'could not init alias {ta["alias"]}')
|
||||
# else:
|
||||
# print(f"object {key} has no alias!")
|
||||
# alias_namespaces.bernina.store()
|
||||
# # try:
|
||||
# # run_table = bernina.init(config['pgroup'], alias_namespaces,_mod)
|
||||
# # _mod.__dict__['rt'] = run_table
|
||||
# # op['rt'] = run_table
|
||||
# # except:
|
||||
# # print('Initializing of run_table failed')
|
||||
# return op
|
||||
|
||||
|
||||
# def parse_for_aliases():
|
||||
# names = [tc["name"] for tc in components]
|
||||
# for name in names:
|
||||
# to = _mod.__dict__[name]
|
||||
# if hasattr(to, "alias"):
|
||||
# for ta in to.alias.get_all():
|
||||
# try:
|
||||
# globals()["alias_namespaces"].bernina.update(
|
||||
# ta["alias"], ta["channel"], ta["channeltype"]
|
||||
# )
|
||||
# except:
|
||||
# print(f'could not init alias {ta["alias"]}')
|
||||
# else:
|
||||
# print(f"object {name} has no alias!")
|
||||
# globals()["alias_namespaces"].bernina.store()
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,676 +0,0 @@
|
||||
# # New configuration of components:
|
||||
# components is an ordered list of
|
||||
# - name in parent package
|
||||
# - type, describing the python Class or factory function.
|
||||
# - arguments of that type args
|
||||
# - kwargs of that type
|
||||
|
||||
# # Conventions for the type
|
||||
# the call of type will try to pass a kwarg 'name' with the
|
||||
# name of the component, before only calling args and kwargs.
|
||||
# if arg or kwarg is of type eco.utilities.Component (dummy class)
|
||||
# this indicates that an earlier initialized object is used
|
||||
# (e.g. from same configuration).
|
||||
from ..utilities.config import (
|
||||
Component,
|
||||
init_device,
|
||||
initFromConfigList,
|
||||
Configuration,
|
||||
)
|
||||
|
||||
_eco_lazy_init = False
|
||||
|
||||
config = Configuration(
|
||||
"/sf/bernina/config/eco/bernina_config_eco.json", name="bernina_config"
|
||||
)
|
||||
|
||||
components = [
|
||||
{
|
||||
"type": "eco.utilities.config:append_to_path",
|
||||
"args": config["path_exp"],
|
||||
"name": "path_exp",
|
||||
"kwargs": {},
|
||||
"lazy": True,
|
||||
},
|
||||
{
|
||||
"name": "elog",
|
||||
"type": "eco.utilities.elog:Elog",
|
||||
"args": ["https://elog-gfa.psi.ch/Bernina"],
|
||||
"kwargs": {
|
||||
"screenshot_directory": "/tmp",
|
||||
},
|
||||
},
|
||||
{
|
||||
"name": "screenshot",
|
||||
"type": "eco.utilities.elog:Screenshot",
|
||||
"args": [],
|
||||
"kwargs": {"screenshot_directory": "/sf/bernina/config/screenshots"},
|
||||
},
|
||||
{
|
||||
"name": "fel",
|
||||
"type": "eco.fel.swissfel:SwissFel",
|
||||
"args": [],
|
||||
"kwargs": {},
|
||||
"desc": "Fel related control and feedback",
|
||||
},
|
||||
# {
|
||||
# "name": "slit_und",
|
||||
# "type": "eco.xoptics.slits:SlitFourBlades_old",
|
||||
# "args": ["SARFE10-OAPU044"],
|
||||
# "kwargs": {},
|
||||
# "desc": "Slit after Undulator",
|
||||
# },
|
||||
# {
|
||||
# "name": "slit_und_epics",
|
||||
# "type": "eco.xoptics.slits:SlitFourBlades_old",
|
||||
# "args": ["SARFE10-OAPU044"],
|
||||
# "kwargs": {},
|
||||
# "desc": "Slit after Undulator",
|
||||
# },
|
||||
# {
|
||||
# "name": "mon_und",
|
||||
# "args": ["SARFE10-PBPS053"],
|
||||
# "z_und": 53,
|
||||
# "desc": "Intensity/Position monitor after Undolator",
|
||||
# "type": "eco.xdiagnostics.intensity_monitors:SolidTargetDetectorPBPS",
|
||||
# "kwargs": {"VME_crate": "SAROP21-CVME-PBPS2", "link": 9},
|
||||
# },
|
||||
{
|
||||
"name": "mon_und",
|
||||
"z_und": 53,
|
||||
"desc": "Intensity/position monitor after Undulator",
|
||||
"type": "eco.xdiagnostics.intensity_monitors:SolidTargetDetectorPBPS_new",
|
||||
"args": ["SARFE10-PBPS053"],
|
||||
"kwargs": {
|
||||
"VME_crate": "SAROP21-CVME-PBPS1",
|
||||
"link": 9,
|
||||
"channels": {
|
||||
"up": "SLAAR21-LSCP1-FNS:CH6:VAL_GET",
|
||||
"down": "SLAAR21-LSCP1-FNS:CH7:VAL_GET",
|
||||
"left": "SLAAR21-LSCP1-FNS:CH4:VAL_GET",
|
||||
"right": "SLAAR21-LSCP1-FNS:CH5:VAL_GET",
|
||||
},
|
||||
"calc": {
|
||||
"itot": "SLAAR21-LTIM01-EVR0:CALCI",
|
||||
"xpos": "SLAAR21-LTIM01-EVR0:CALCX",
|
||||
"ypos": "SLAAR21-LTIM01-EVR0:CALCY",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"name": "pshut_und",
|
||||
"type": "eco.xoptics.shutters:PhotonShutter",
|
||||
"args": ["SARFE10-OPSH044:REQUEST"],
|
||||
"kwargs": {},
|
||||
"z_und": 44,
|
||||
"desc": "First shutter after Undulators",
|
||||
},
|
||||
{
|
||||
"name": "pshut_fe",
|
||||
"type": "eco.xoptics.shutters:PhotonShutter",
|
||||
"args": ["SARFE10-OPSH059:REQUEST"],
|
||||
"kwargs": {},
|
||||
"z_und": 59,
|
||||
"desc": "Photon shutter end of front end",
|
||||
},
|
||||
{
|
||||
"name": "sshut_opt",
|
||||
"type": "eco.xoptics.shutters:SafetyShutter",
|
||||
"args": ["SGE01-EPKT822:BST1_oeffnen"],
|
||||
"kwargs": {},
|
||||
"z_und": 115,
|
||||
"desc": "Bernina safety shutter",
|
||||
},
|
||||
{
|
||||
"name": "sshut_fe",
|
||||
"type": "eco.xoptics.shutters:SafetyShutter",
|
||||
"args": ["SGE01-EPKT820:BST1_oeffnen"],
|
||||
"kwargs": {},
|
||||
"z_und": 115,
|
||||
"desc": "Bernina safety shutter",
|
||||
},
|
||||
{
|
||||
"name": "att_fe",
|
||||
"type": "eco.xoptics.attenuator_aramis:AttenuatorAramis",
|
||||
"args": ["SARFE10-OATT053"],
|
||||
"kwargs": {"shutter": Component("pshut_und")},
|
||||
"z_und": 53,
|
||||
"desc": "Attenuator in Front End",
|
||||
},
|
||||
# {
|
||||
# "name": "mon_und",
|
||||
# "z_und": 53,
|
||||
# "desc": "Intensity/position monitor after Optics hutch",
|
||||
# "type": "eco.xdiagnostics.intensity_monitors:SolidTargetDetectorPBPS",
|
||||
# "args": ["SARFE10-PBPS053"],
|
||||
# "kwargs": {},
|
||||
# },
|
||||
{
|
||||
"name": "xspect",
|
||||
"z_und": 53,
|
||||
"desc": "X-ray single shot spectrometer",
|
||||
"type": "eco.xdiagnostics.xspect:Xspect",
|
||||
"args": [],
|
||||
"kwargs": {},
|
||||
},
|
||||
{
|
||||
"name": "prof_fe",
|
||||
"args": ["SARFE10-PPRM064"] * 2,
|
||||
"kwargs": {},
|
||||
"z_und": 64,
|
||||
"desc": "Profile monitor after Front End",
|
||||
"type": "eco.xdiagnostics.profile_monitors:Pprm",
|
||||
},
|
||||
{
|
||||
"name": "prof_mirr_alv1",
|
||||
"args": ["SAROP11-PPRM066"] * 2,
|
||||
"kwargs": {},
|
||||
"z_und": 66,
|
||||
"desc": "Profile monitor after Alvra Mirror 1",
|
||||
"type": "eco.xdiagnostics.profile_monitors:Pprm",
|
||||
},
|
||||
{
|
||||
"name": "prof_mirr1",
|
||||
"args": ["SAROP21-PPRM094"] * 2,
|
||||
"kwargs": {},
|
||||
"z_und": 94,
|
||||
"desc": "Profile monitor after Mirror 1",
|
||||
"type": "eco.xdiagnostics.profile_monitors:Pprm",
|
||||
},
|
||||
{
|
||||
"name": "offset",
|
||||
"args": [],
|
||||
"kwargs": {},
|
||||
"z_und": 96,
|
||||
"desc": "offset mirrors in pink mode",
|
||||
"type": "eco.xoptics.offsetMirrors_new:OffsetMirrorsBernina",
|
||||
"kwargs": {},
|
||||
},
|
||||
{
|
||||
"name": "mono",
|
||||
"args": ["SAROP21-ODCM098"],
|
||||
"kwargs": {},
|
||||
"z_und": 98,
|
||||
"desc": "DCM Monochromator",
|
||||
"type": "eco.xoptics.dcm_new:DoubleCrystalMono",
|
||||
},
|
||||
{
|
||||
"name": "mono_old",
|
||||
"args": ["SAROP21-ODCM098"],
|
||||
"kwargs": {
|
||||
"energy_sp": "SAROP21-ARAMIS:ENERGY_SP",
|
||||
"energy_rb": "SAROP21-ARAMIS:ENERGY",
|
||||
},
|
||||
"z_und": 98,
|
||||
"desc": "DCM Monochromator",
|
||||
"type": "eco.xoptics.dcm:Double_Crystal_Mono",
|
||||
},
|
||||
{
|
||||
"name": "prof_mono",
|
||||
"args": ["SAROP21-PPRM113"] * 2,
|
||||
"kwargs": {},
|
||||
"z_und": 102,
|
||||
"desc": "Profile monitor after Monochromator",
|
||||
"type": "eco.xdiagnostics.profile_monitors:Pprm",
|
||||
},
|
||||
{
|
||||
"name": "xp",
|
||||
"args": [],
|
||||
"kwargs": {
|
||||
"Id": "SAROP21-OPPI113",
|
||||
"evronoff": "SGE-CPCW-72-EVR0:FrontUnivOut15-Ena-SP",
|
||||
"evrsrc": "SGE-CPCW-72-EVR0:FrontUnivOut15-Src-SP",
|
||||
},
|
||||
"z_und": 103,
|
||||
"desc": "X-ray pulse picker",
|
||||
"type": "eco.xoptics.pp:Pulsepick",
|
||||
},
|
||||
# {
|
||||
# "name": "mon_opt_old",
|
||||
# "z_und": 133,
|
||||
# "desc": "Intensity/position monitor after Optics hutch",
|
||||
# "type": "eco.xdiagnostics.intensity_monitors:SolidTargetDetectorPBPS",
|
||||
# "args": ["SAROP21-PBPS133"],
|
||||
# "kwargs": {"VME_crate": "SAROP21-CVME-PBPS1", "link": 9},
|
||||
# },
|
||||
{
|
||||
"name": "mon_opt",
|
||||
"z_und": 133,
|
||||
"desc": "Intensity/position monitor after Optics hutch",
|
||||
"type": "eco.xdiagnostics.intensity_monitors:SolidTargetDetectorPBPS_new",
|
||||
"args": ["SAROP21-PBPS133"],
|
||||
"kwargs": {
|
||||
"VME_crate": "SAROP21-CVME-PBPS1",
|
||||
"link": 9,
|
||||
"channels": {
|
||||
"up": "SLAAR21-LSCP1-FNS:CH6:VAL_GET",
|
||||
"down": "SLAAR21-LSCP1-FNS:CH7:VAL_GET",
|
||||
"left": "SLAAR21-LSCP1-FNS:CH4:VAL_GET",
|
||||
"right": "SLAAR21-LSCP1-FNS:CH5:VAL_GET",
|
||||
},
|
||||
"calc": {
|
||||
"itot": "SLAAR21-LTIM01-EVR0:CALCI",
|
||||
"xpos": "SLAAR21-LTIM01-EVR0:CALCX",
|
||||
"ypos": "SLAAR21-LTIM01-EVR0:CALCY",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"name": "prof_opt",
|
||||
"args": ["SAROP21-PPRM133"] * 2,
|
||||
"kwargs": {},
|
||||
"z_und": 133,
|
||||
"desc": "Profile monitor after Optics hutch",
|
||||
"type": "eco.xdiagnostics.profile_monitors:Pprm",
|
||||
},
|
||||
{
|
||||
"name": "spect_tt",
|
||||
"args": ["SAROP21-PSEN135"],
|
||||
"kwargs": {"reduction_client_address": "http://sf-daqsync-01:8889/"},
|
||||
"z_und": 135,
|
||||
"desc": "Spectral encoding timing diagnostics before Attenuator.",
|
||||
"type": "eco.xdiagnostics.timetools:SpectralEncoder",
|
||||
},
|
||||
{
|
||||
"name": "att",
|
||||
"args": ["SAROP21-OATT135"],
|
||||
"kwargs": {"shutter": Component("xp"), "set_limits": []},
|
||||
"z_und": 135,
|
||||
"desc": "Attenuator Bernina",
|
||||
"type": "eco.xoptics.attenuator_aramis:AttenuatorAramis",
|
||||
},
|
||||
{
|
||||
"name": "slit_att",
|
||||
"args": ["SAROP21-OAPU136"],
|
||||
"kwargs": {},
|
||||
"z_und": 136,
|
||||
"desc": "Slits behind attenuator",
|
||||
"type": "eco.xoptics.slits:SlitPosWidth",
|
||||
},
|
||||
{
|
||||
"name": "det_dio",
|
||||
"args": ["SAROP21-PDIO138"],
|
||||
"z_und": 138,
|
||||
"desc": "Diode digitizer for exp data",
|
||||
"type": "eco.devices_general.detectors:DiodeDigitizer",
|
||||
"kwargs": {"VME_crate": "SAROP21-CVME-PBPS2", "link": 9},
|
||||
},
|
||||
{
|
||||
"name": "prof_att",
|
||||
"args": ["SAROP21-PPRM138"] * 2,
|
||||
"kwargs": {},
|
||||
"z_und": 138,
|
||||
"desc": "Profile monitor after Attenuator",
|
||||
"type": "eco.xdiagnostics.profile_monitors:Pprm",
|
||||
},
|
||||
# {
|
||||
# "name": "spatial_tt",
|
||||
# "args": [],
|
||||
# "kwargs": {"reduction_client_address": "http://sf-daqsync-02:12003/"},
|
||||
# "z_und": 141,
|
||||
# "desc": "spatial encoding timing diagnostics before sample.",
|
||||
# "type": "eco.xdiagnostics.timetools:SpatialEncoder",
|
||||
# "lazy": True,
|
||||
# },
|
||||
# {
|
||||
# "name": "slit_kb",
|
||||
# "args": [],
|
||||
# "kwargs": {"pvname": "SARES20-MF1"},
|
||||
# "z_und": 141,
|
||||
# "desc": "Slits behind Kb",
|
||||
# "type": "eco.xoptics.slits:SlitBlades_JJ",
|
||||
# # "type": "eco.xoptics.slits:SlitBladesJJ_old",
|
||||
# },
|
||||
# {
|
||||
# "args": [],
|
||||
# "name": "gps_old",
|
||||
# "z_und": 142,
|
||||
# "desc": "General purpose station",
|
||||
# "type": "eco.endstations.bernina_diffractometers:GPS_old",
|
||||
# "kwargs": {
|
||||
# "Id": "SARES22-GPS",
|
||||
# "configuration": config["gps_config"],
|
||||
# "fina_hex_angle_offset": "/sf/bernina/config/eco/reference_values/hex_pi_angle_offset.json",
|
||||
# },
|
||||
# "lazy": True,
|
||||
# },
|
||||
# {
|
||||
# "args": [],
|
||||
# "name": "xrd_old",
|
||||
# "z_und": 142,
|
||||
# "desc": "Xray diffractometer",
|
||||
# "type": "eco.endstations.bernina_diffractometers:XRD_old",
|
||||
# "kwargs": {"Id": "SARES21-XRD", "configuration": config["xrd_config"]},
|
||||
# },
|
||||
# {
|
||||
# "args": [],
|
||||
# "name": "xrd",
|
||||
# "z_und": 142,
|
||||
# "desc": "Xray diffractometer",
|
||||
# "type": "eco.endstations.bernina_diffractometers:XRD",
|
||||
# "kwargs": {
|
||||
# "Id": "SARES21-XRD",
|
||||
# "configuration": config["xrd_config"],
|
||||
# "diff_detector": {"jf_id": "JF01T03V01"},
|
||||
# },
|
||||
# },
|
||||
{
|
||||
"args": [],
|
||||
"name": "vonHamos",
|
||||
"z_und": 142,
|
||||
"desc": "Kern experiment, von Hamos vertical and horizontal stages ",
|
||||
"type": "eco.devices_general.micos_stage:stage",
|
||||
"kwargs": {
|
||||
"vonHamos_horiz_pv": config["Kern"]["vonHamos_horiz"],
|
||||
"vonHamos_vert_pv": config["Kern"]["vonHamos_vert"],
|
||||
},
|
||||
},
|
||||
# {
|
||||
# "args": [],
|
||||
# "name": "gasjet",
|
||||
# "z_und": 142,
|
||||
# "desc": "ToF comm. gasjet",
|
||||
# "type": "tof:jet",
|
||||
# "kwargs": {},
|
||||
# },
|
||||
{
|
||||
"args": [],
|
||||
"name": "xeye",
|
||||
"z_und": 142,
|
||||
"desc": "Mobile X-ray eye in Bernina hutch",
|
||||
"type": "eco.xdiagnostics.profile_monitors:Bernina_XEYE",
|
||||
"kwargs": {
|
||||
"zoomstage_pv": config["xeye"]["zoomstage_pv"],
|
||||
"camera_pv": config["xeye"]["camera_pv"],
|
||||
"bshost": "sf-daqsync-01.psi.ch",
|
||||
"bsport": 11151,
|
||||
},
|
||||
},
|
||||
{
|
||||
"args": ["SARES20-CAMS142-M1"],
|
||||
"name": "cam_sample_sideview",
|
||||
"z_und": 142,
|
||||
"desc": "",
|
||||
"type": "eco.devices_general.cameras_swissfel:CameraBasler",
|
||||
"kwargs": {},
|
||||
},
|
||||
{
|
||||
"args": ["SARES20-CAMS142-M3"],
|
||||
"name": "cam_sample_inline",
|
||||
"z_und": 142,
|
||||
"desc": "",
|
||||
"type": "eco.devices_general.cameras_swissfel:CameraBasler",
|
||||
"kwargs": {},
|
||||
},
|
||||
# {
|
||||
# "args": ["SARES20-CAMS142-C3"],
|
||||
# "name": "cam_sample_xrd",
|
||||
# "z_und": 142,
|
||||
# "desc": "",
|
||||
# "type": "eco.devices_general.cameras_swissfel:CameraBasler",
|
||||
# "kwargs": {},
|
||||
# },
|
||||
# {
|
||||
# "args": [],
|
||||
# "name": "cams_qioptiq",
|
||||
# "z_und": 142,
|
||||
# "desc": "Qioptic sample viewer in Bernina hutch",
|
||||
# "type": "eco.endstations.bernina_cameras:Qioptiq",
|
||||
# "kwargs": {
|
||||
# "bshost": "sf-daqsync-01.psi.ch",
|
||||
# "bsport": 11149,
|
||||
# "zoomstage_pv": config["cams_qioptiq"]["zoomstage_pv"],
|
||||
# "camera_pv": config["cams_qioptiq"]["camera_pv"],
|
||||
# },
|
||||
# },
|
||||
{
|
||||
"args": [],
|
||||
"name": "cams_sigma",
|
||||
"z_und": 142,
|
||||
"desc": "Sigma objective",
|
||||
"type": "eco.endstations.bernina_cameras:Sigma",
|
||||
"kwargs": {
|
||||
"bshost": "sf-daqsync-01.psi.ch",
|
||||
"bsport": 11149,
|
||||
"camera_pv": config["cams_sigma"]["camera_pv"],
|
||||
},
|
||||
},
|
||||
# {
|
||||
# "args": ["SLAAR02-TSPL-EPL"],
|
||||
# "name": "phase_shifter",
|
||||
# "z_und": 142,
|
||||
# "desc": "Experiment laser phase shifter",
|
||||
# "type": "eco.devices_general.timing:PhaseShifterAramis",
|
||||
# "kwargs": {},
|
||||
# },
|
||||
{
|
||||
"args": ["SLAAR21-LTIM01-EVR0"],
|
||||
"name": "laser_shutter",
|
||||
"z_und": 142,
|
||||
"desc": "Laser Shutter",
|
||||
"type": "eco.loptics.laser_shutter:laser_shutter",
|
||||
"kwargs": {},
|
||||
},
|
||||
{
|
||||
"args": [],
|
||||
"name": "epics_channel_list",
|
||||
"desc": "epics channel list",
|
||||
"type": "eco.utilities.config:ChannelList",
|
||||
"kwargs": {
|
||||
"file_name": "/sf/bernina/config/channel_lists/default_channel_list_epics"
|
||||
},
|
||||
"lazy": True,
|
||||
},
|
||||
{
|
||||
"args": [],
|
||||
"name": "epics_daq",
|
||||
"z_und": 142,
|
||||
"desc": "epics data acquisition",
|
||||
"type": "eco.acquisition.epics_data:Epicstools",
|
||||
"kwargs": {
|
||||
"channel_list": Component("epics_channel_list"),
|
||||
"default_file_path": f"/sf/bernina/data/{config['pgroup']}/res/epics_daq/",
|
||||
},
|
||||
"lazy": True,
|
||||
},
|
||||
# {
|
||||
# "args": [],
|
||||
# "name": "daq_dia_old",
|
||||
# "desc": "server based acquisition",
|
||||
# "type": "eco.acquisition.dia:DIAClient",
|
||||
# "kwargs": {
|
||||
# "instrument": "bernina",
|
||||
# "api_address": config["daq_address"],
|
||||
# "pgroup": config["pgroup"],
|
||||
# "pedestal_directory": config["jf_pedestal_directory"],
|
||||
# "gain_path": config["jf_gain_path"],
|
||||
# "config_default": config["daq_dia_config"],
|
||||
# "jf_channels": config["jf_channels"],
|
||||
# "default_file_path": None,
|
||||
# },
|
||||
# },
|
||||
{
|
||||
"args": [
|
||||
config["checker_PV"],
|
||||
config["checker_thresholds"],
|
||||
config["checker_fractionInThreshold"],
|
||||
], #'SARFE10-PBPG050:HAMP-INTENSITY-CAL',[60,700],.7],
|
||||
"name": "checker",
|
||||
"desc": "checker functions for data acquisition",
|
||||
"type": "eco.acquisition.checkers:CheckerCA",
|
||||
"kwargs": {},
|
||||
},
|
||||
# {
|
||||
# "args": [
|
||||
# "SARES20-LSCP9-FNS:CH1:VAL_GET",
|
||||
# [-100000, 100000],
|
||||
# config["checker_fractionInThreshold"],
|
||||
# ], #'SARFE10-PBPG050:HAMP-INTENSITY-CAL',[60,700],.7],
|
||||
# "name": "checker_epics",
|
||||
# "desc": "checker functions for data acquisition",
|
||||
# "type": "eco.acquisition.checkers:CheckerCA",
|
||||
# "kwargs": {},
|
||||
# },
|
||||
# {
|
||||
# "args": [],
|
||||
# "name": "scans_epics",
|
||||
# "desc": "epics non beam synchronous based acquisition",
|
||||
# "type": "eco.acquisition.scan:Scans",
|
||||
# "kwargs": {
|
||||
# "data_base_dir": "scan_data",
|
||||
# "scan_info_dir": f"/sf/bernina/data/{config['pgroup']}/res/scan_info",
|
||||
# "default_counters": [Component("epics_daq")],
|
||||
# "checker": Component("checker_epics"),
|
||||
# "scan_directories": True,
|
||||
# "run_table": Component("run_table"),
|
||||
# },
|
||||
# "lazy": True,
|
||||
# },
|
||||
# {
|
||||
# "args": [],
|
||||
# "name": "lxt",
|
||||
# "desc": "laser timing with pockels cells and phase shifter",
|
||||
# "type": "eco.timing.lasertiming:Lxt",
|
||||
# "kwargs": {},
|
||||
# },
|
||||
# {
|
||||
# "args": ["SARES20-CVME-01-EVR0"],
|
||||
# "name": "evr_bernina",
|
||||
# "desc": "Bernina event receiver",
|
||||
# "type": "eco.timing.event_timing:EventReceiver",
|
||||
# "kwargs": {},
|
||||
# },
|
||||
{
|
||||
"args": [],
|
||||
"name": "default_channel_list",
|
||||
"desc": "Bernina default channels, used in daq",
|
||||
"type": "eco.utilities.config:ChannelList",
|
||||
"kwargs": {
|
||||
"file_name": "/sf/bernina/config/channel_lists/default_channel_list"
|
||||
},
|
||||
},
|
||||
{
|
||||
"args": [],
|
||||
"name": "default_channel_list_bs",
|
||||
"desc": "Bernina default bs channels, used by bs_daq",
|
||||
"type": "eco.utilities.config:ChannelList",
|
||||
"kwargs": {
|
||||
"file_name": "/sf/bernina/config/channel_lists/default_channel_list_bs"
|
||||
},
|
||||
},
|
||||
{
|
||||
"args": [],
|
||||
"name": "channels_spectrometer_projection",
|
||||
"desc": "",
|
||||
"type": "eco.utilities.config:ChannelList",
|
||||
"kwargs": {
|
||||
"file_name": "/sf/bernina/config/channel_lists/channel_list_PSSS_projection"
|
||||
},
|
||||
},
|
||||
{
|
||||
"args": [],
|
||||
"name": "bs_daq",
|
||||
"desc": "bs daq writer (locally!)",
|
||||
"type": "eco.acquisition.bs_data:BStools",
|
||||
"kwargs": {
|
||||
"default_channel_list": {
|
||||
"bernina_default_channels_bs": Component("default_channel_list_bs")
|
||||
},
|
||||
"default_file_path": f"/sf/bernina/data/{config['pgroup']}/res/%s",
|
||||
},
|
||||
},
|
||||
{
|
||||
"args": [],
|
||||
"name": "usd_table",
|
||||
"z_und": 141,
|
||||
"desc": "Upstream diagnostics table",
|
||||
"type": "eco.endstations.hexapod:HexapodSymmetrie",
|
||||
"kwargs": {"offset": [0.0, 0.0, 0.0, 0.0, 0.0, 0.0]},
|
||||
},
|
||||
# {
|
||||
# "args": ["SARES23-"],
|
||||
# "name": "slit_kb",
|
||||
# "z_und": 141,
|
||||
# "desc": "Upstream diagnostics slits",
|
||||
# "type": "eco.xoptics.slit_USD:Upstream_diagnostic_slits",
|
||||
# "kwargs": {"right": "LIC4", "left": "LIC3", "up": "LIC2", "down": "LIC1"},
|
||||
# },
|
||||
# {
|
||||
# "args": ["SARES23-"],
|
||||
# "name": "slit_cleanup",
|
||||
# "z_und": 141,
|
||||
# "desc": "Upstream diagnostics slits",
|
||||
# "type": "eco.xoptics.slit_USD:Upstream_diagnostic_slits",
|
||||
# "kwargs": {"right": "LIC7", "left": "LIC8", "up": "LIC8", "down": "LIC5"},
|
||||
# },
|
||||
{
|
||||
"args": [
|
||||
[
|
||||
Component("slit_und"),
|
||||
Component("slit_switch"),
|
||||
Component("slit_att"),
|
||||
Component("slit_kb"),
|
||||
]
|
||||
],
|
||||
"name": "slits",
|
||||
"desc": "collection of all slits",
|
||||
"type": "eco.utilities.beamline:Slits",
|
||||
"kwargs": {},
|
||||
},
|
||||
# {
|
||||
# "args": [
|
||||
# [Component("slit_switch"), Component("slit_att"), Component("slit_kb"),]
|
||||
# ],
|
||||
# "name": "slits",
|
||||
# "desc": "collection of all slits",
|
||||
# "type": "eco.utilities.beamline:Slits",
|
||||
# "kwargs": {},
|
||||
# "lazy": False,
|
||||
# },
|
||||
# {
|
||||
# "args": [],
|
||||
# "name": "thc",
|
||||
# "z_und": 142,
|
||||
# "desc": "High field THz Chamber",
|
||||
# "type": "eco.endstations.bernina_sample_environments:High_field_thz_chamber",
|
||||
# "kwargs": {"Id": "SARES23", "configuration": ["ottifant"]},
|
||||
# },
|
||||
# {
|
||||
# "args": [],
|
||||
# "name": "ocb",
|
||||
# "z_und": 142,
|
||||
# "desc": "Organic Crystal Breadboard",
|
||||
# "type": "eco.endstations.bernina_sample_environments:Organic_crystal_breadboard",
|
||||
# "kwargs": {"Id": "SARES23"},
|
||||
# },
|
||||
# {
|
||||
# "args": [],
|
||||
# "name": "eos",
|
||||
# "z_und": 142,
|
||||
# "desc": "electro optic sampling stages",
|
||||
# "type": "eco.endstations.bernina_sample_environments:Electro_optic_sampling",
|
||||
# "kwargs": {
|
||||
# "Id": "SARES23",
|
||||
# "pgroup": config["pgroup"],
|
||||
# "diode_channels": {
|
||||
# "d1": "SARES20-LSCP9-FNS:CH1:VAL_GET",
|
||||
# "d2": "SARES20-LSCP9-FNS:CH2:VAL_GET",
|
||||
# "diff": "SARES20-LSCP9-FNS:CH3:VAL_GET",
|
||||
# },
|
||||
# },
|
||||
# },
|
||||
{
|
||||
"args": [],
|
||||
"name": "dsd",
|
||||
"z_und": 146,
|
||||
"desc": "downstream diagnostics",
|
||||
"type": "eco.xdiagnostics.dsd:DownstreamDiagnostic",
|
||||
"kwargs": {},
|
||||
},
|
||||
]
|
||||
|
||||
try:
|
||||
components.extend(config["components"])
|
||||
print("Did append additional components!")
|
||||
except:
|
||||
print("Could not append components from config.")
|
||||
@@ -1,32 +0,0 @@
|
||||
from eco.elements.adjustable import AdjustableFS
|
||||
from eco.motion.smaract import SmaractController
|
||||
|
||||
# from .config import components
|
||||
# from .config import config as config_berninamesp
|
||||
from ..utilities.config import Namespace
|
||||
|
||||
# from ..aliases import NamespaceCollection
|
||||
import pyttsx3
|
||||
|
||||
from ..utilities.path_alias import PathAlias
|
||||
import sys, os
|
||||
from IPython import get_ipython
|
||||
|
||||
|
||||
# path_aliases = PathAlias()
|
||||
# sys.path.append("/sf/bernina/config/src/python/bernina_analysis")
|
||||
|
||||
# namespace = Namespace(
|
||||
# name="bernina", root_module=__name__, alias_namespace=NamespaceCollection().bernina
|
||||
# )
|
||||
# namespace.alias_namespace.data = []
|
||||
|
||||
# # Adding stuff that might be relevant for stuff configured below (e.g. config)
|
||||
|
||||
# _config_bernina_dict = AdjustableFS(
|
||||
# "/sf/bernina/config/eco/configuration/bernina_config.json",
|
||||
# name="_config_bernina_dict",
|
||||
# )
|
||||
# from eco.elements.adj_obj import AdjustableObject
|
||||
|
||||
# namespace.append_obj(AdjustableObject, _config_bernina_dict, name="config_bernina")
|
||||
+51
-4
@@ -1,3 +1,4 @@
|
||||
from eco.elements.detector import DetectorGet
|
||||
from .assembly import Assembly
|
||||
|
||||
from .adjustable import AdjustableGetSet
|
||||
@@ -5,10 +6,10 @@ from functools import partial
|
||||
|
||||
|
||||
class AdjustableObject(Assembly):
|
||||
def __init__(self, adjustable_dict, name=None):
|
||||
def __init__(self, adjustable_dict, is_setting_children = True, name=None):
|
||||
super().__init__(name=name)
|
||||
self._base_dict = adjustable_dict
|
||||
self.init_object()
|
||||
self.init_object(is_setting_children=is_setting_children)
|
||||
|
||||
def set_field(self, fieldname, value):
|
||||
d = self._base_dict.get_current_value()
|
||||
@@ -23,7 +24,13 @@ class AdjustableObject(Assembly):
|
||||
raise Exception(f"{fieldname} is not in dictionary")
|
||||
return d[fieldname]
|
||||
|
||||
def init_object(self):
|
||||
def update_base_dict(self, updatedict):
|
||||
tmp = self._base_dict.get_current_value()
|
||||
tmp.update(updatedict)
|
||||
self._base_dict.set_target_value(tmp)
|
||||
self.__init__(self._base_dict, name=self.name)
|
||||
|
||||
def init_object(self, is_setting_children=True):
|
||||
# super().__init__(name=self.name)
|
||||
for k, v in self._base_dict.get_current_value().items():
|
||||
tadj = AdjustableGetSet(
|
||||
@@ -38,11 +45,51 @@ class AdjustableObject(Assembly):
|
||||
self._append(
|
||||
AdjustableObject(tadj, name=k),
|
||||
call_obj=False,
|
||||
is_setting=is_setting_children,
|
||||
name=ln,
|
||||
is_display="recursive",
|
||||
)
|
||||
else:
|
||||
self._append(
|
||||
tadj, call_obj=False, is_setting=is_setting_children, is_display=True, name=ln
|
||||
)
|
||||
|
||||
class DetectorObject(Assembly):
|
||||
def __init__(self, detector_dict, name=None):
|
||||
super().__init__(name=name)
|
||||
self._base_dict = detector_dict
|
||||
self.init_object()
|
||||
|
||||
|
||||
def get_field(self, fieldname):
|
||||
d = self._base_dict.get_current_value()
|
||||
if fieldname not in d.keys():
|
||||
raise Exception(f"{fieldname} is not in dictionary")
|
||||
return d[fieldname]
|
||||
|
||||
|
||||
def init_object(self):
|
||||
# super().__init__(name=self.name)
|
||||
for k, v in self._base_dict.get_current_value().items():
|
||||
tdet = DetectorGet(
|
||||
partial(self.get_field, k), name=k
|
||||
)
|
||||
if k in self.__dict__.keys():
|
||||
ln = f"{k}_"
|
||||
else:
|
||||
ln = f"{k}"
|
||||
if type(v) is dict:
|
||||
|
||||
self._append(
|
||||
DetectorObject(tdet, name=k),
|
||||
call_obj=False,
|
||||
is_setting=False,
|
||||
name=ln,
|
||||
is_display="recursive",
|
||||
)
|
||||
else:
|
||||
self._append(
|
||||
tadj, call_obj=False, is_setting=False, is_display=True, name=ln
|
||||
tdet, call_obj=False, is_setting=False, is_display=True, name=ln
|
||||
)
|
||||
|
||||
|
||||
|
||||
+172
-28
@@ -4,9 +4,11 @@ import time
|
||||
from json import load, dump
|
||||
from pathlib import Path
|
||||
from threading import Thread
|
||||
|
||||
import itertools
|
||||
import colorama
|
||||
import numpy as np
|
||||
|
||||
import eco
|
||||
from eco.aliases import Alias
|
||||
from eco.devices_general.utilities import Changer
|
||||
|
||||
@@ -104,6 +106,60 @@ def spec_convenience(Adj):
|
||||
Adj.mv = mv
|
||||
Adj.mvr = mvr
|
||||
|
||||
def wm_elog(self, premessage=None, tags=[]):
|
||||
elog = self._get_elog()
|
||||
tname = self.alias.get_full_name()
|
||||
value = self.get_current_value()
|
||||
|
||||
if premessage:
|
||||
messages = [
|
||||
premessage,
|
||||
f"{tname} is at {value}.",
|
||||
]
|
||||
else:
|
||||
messages = [f"{tname} is at {value}."]
|
||||
self.mvr(value)
|
||||
elog.post(*messages, tags=tags)
|
||||
|
||||
def mv_elog(self, value, premessage=None, tags=[]):
|
||||
elog = self._get_elog()
|
||||
tname = self.alias.get_full_name()
|
||||
start = self.get_current_value()
|
||||
end = value
|
||||
rel_change = end - start
|
||||
if premessage:
|
||||
messages = [
|
||||
premessage,
|
||||
f"Changing {tname} from {start} by {rel_change} to {end}.",
|
||||
]
|
||||
else:
|
||||
messages = [f"Changing {tname} from {start} by {rel_change} to {end}."]
|
||||
self.mv(value)
|
||||
elog.post(*messages, tags=tags)
|
||||
|
||||
def mvr_elog(self, value, premessage=None, tags=[]):
|
||||
elog = self._get_elog()
|
||||
tname = self.alias.get_full_name()
|
||||
start = self.get_current_value()
|
||||
end = start + value
|
||||
rel_change = value
|
||||
if premessage:
|
||||
messages = [
|
||||
premessage,
|
||||
f"Changing {tname} from {start} by {rel_change} to {end}.",
|
||||
]
|
||||
else:
|
||||
messages = [f"Changing {tname} from {start} by {rel_change} to {end}."]
|
||||
self.mvr(value)
|
||||
elog.post(*messages, tags=tags)
|
||||
|
||||
if hasattr(Adj, "wm"):
|
||||
Adj.wm_elog = wm_elog
|
||||
if hasattr(Adj, "mv"):
|
||||
Adj.mv_elog = mv_elog
|
||||
if hasattr(Adj, "mvr"):
|
||||
Adj.mvr_elog = mvr_elog
|
||||
|
||||
def call(self, value=None):
|
||||
if not value is None:
|
||||
return self.mv(value)
|
||||
@@ -112,6 +168,18 @@ def spec_convenience(Adj):
|
||||
|
||||
Adj.__call__ = call
|
||||
|
||||
def _get_elog(self):
|
||||
if hasattr(self, "_elog") and self._elog:
|
||||
return self._elog
|
||||
elif hasattr(self, "__elog") and self.__elog:
|
||||
return self.__elog
|
||||
elif eco.ELOG:
|
||||
return eco.ELOG
|
||||
else:
|
||||
return None
|
||||
|
||||
Adj._get_elog = _get_elog
|
||||
|
||||
return Adj
|
||||
|
||||
|
||||
@@ -167,18 +235,31 @@ class ValueInRange:
|
||||
|
||||
def update_changes(Adj):
|
||||
def get_position_str(start, end, value):
|
||||
start = float(start)
|
||||
value = float(value)
|
||||
end = float(end)
|
||||
s = ValueInRange(start, end, bar_width=30, unit="", fmt="1.5g").get_str(value)
|
||||
return (
|
||||
colorama.Style.BRIGHT
|
||||
+ f"{value:1.5}".rjust(10)
|
||||
+ colorama.Style.RESET_ALL
|
||||
+ " "
|
||||
+ s
|
||||
+ 2 * "\t"
|
||||
)
|
||||
vals = [v if hasattr(v, "__iter__") else [v] for v in [start, end, value]]
|
||||
# bars = []
|
||||
bars = ""
|
||||
for s, v, e in zip(*vals):
|
||||
s = float(s)
|
||||
v = float(v)
|
||||
e = float(e)
|
||||
s = ValueInRange(s, e, bar_width=30, unit="", fmt="1.5g").get_str(v)
|
||||
bars = bars + (
|
||||
colorama.Style.BRIGHT
|
||||
+ f"{v:1.5}".rjust(10)
|
||||
+ colorama.Style.RESET_ALL
|
||||
+ " "
|
||||
+ s
|
||||
+ 2 * "\t"
|
||||
)
|
||||
# bars.append((
|
||||
# colorama.Style.BRIGHT
|
||||
# + f"{v:1.5}".rjust(10)
|
||||
# + colorama.Style.RESET_ALL
|
||||
# + " "
|
||||
# + s
|
||||
# + 2 * "\t"
|
||||
# ))
|
||||
return bars
|
||||
|
||||
def update_change(self, value, elog=None):
|
||||
start = self.get_current_value()
|
||||
@@ -188,14 +269,16 @@ def update_changes(Adj):
|
||||
)
|
||||
except TypeError:
|
||||
print(f"Changing {self.name} from {start} to {value}")
|
||||
|
||||
# for pos in get_position_str(start, value, start):
|
||||
# print(pos, end="\r")
|
||||
print(get_position_str(start, value, start), end="\r")
|
||||
try:
|
||||
if hasattr(self, "add_value_callback"):
|
||||
|
||||
def cbfoo(**kwargs):
|
||||
present_value = self.get_current_value()
|
||||
# print(get_position_str(start, value, kwargs["value"]), end="\r")
|
||||
# for pos in get_position_str(start, value, present_value):
|
||||
# print(pos, end="\r")
|
||||
print(get_position_str(start, value, present_value), end="\r")
|
||||
|
||||
cb_id = self.add_value_callback(cbfoo)
|
||||
@@ -246,19 +329,37 @@ def update_changes(Adj):
|
||||
def value_property(Adj, wait_for_change=True, value_name="_value"):
|
||||
if wait_for_change:
|
||||
|
||||
def tmp(Adj, value):
|
||||
Adj.set_target_value(value, hold=False).wait()
|
||||
def set_target_value_wait(self, value):
|
||||
try:
|
||||
self.set_target_value(value, hold=False).wait()
|
||||
except:
|
||||
self.set_target_value(value).wait()
|
||||
|
||||
def get_current_value(self):
|
||||
o = self.get_current_value()
|
||||
if hasattr(o, "__setitem__"):
|
||||
# print("overwriting output class")
|
||||
|
||||
class TempObj(o.__class__):
|
||||
def __setitem__(oself, *args):
|
||||
o.__class__.__setitem__(oself, *args)
|
||||
self._set_target_value_wait(oself)
|
||||
|
||||
return TempObj(o)
|
||||
else:
|
||||
return o
|
||||
|
||||
Adj._set_target_value_wait = set_target_value_wait
|
||||
Adj._get_current_value = get_current_value
|
||||
|
||||
setattr(
|
||||
Adj,
|
||||
value_name,
|
||||
property(
|
||||
Adj.get_current_value,
|
||||
tmp,
|
||||
Adj._get_current_value,
|
||||
Adj._set_target_value_wait,
|
||||
),
|
||||
)
|
||||
|
||||
Adj.value = property(lambda self: self._value)
|
||||
return Adj
|
||||
|
||||
|
||||
@@ -270,11 +371,12 @@ def value_property(Adj, wait_for_change=True, value_name="_value"):
|
||||
@tweak_option
|
||||
@value_property
|
||||
class DummyAdjustable:
|
||||
def __init__(self, name="no_adjustable"):
|
||||
def __init__(self, name="no_adjustable", limits=[-100, 100]):
|
||||
self.name = name
|
||||
self.alias = Alias(name)
|
||||
|
||||
self.current_value = 0
|
||||
self.limits = tuple(limits)
|
||||
|
||||
def get_current_value(self):
|
||||
return self.current_value
|
||||
@@ -287,6 +389,12 @@ class DummyAdjustable:
|
||||
target=value, parent=self, changer=changer, hold=hold, stopper=None
|
||||
)
|
||||
|
||||
def get_limits(self):
|
||||
return self.limits
|
||||
|
||||
def set_limits(self, lowlim, highlim):
|
||||
self.limits = (lowlim, highlim)
|
||||
|
||||
def __repr__(self):
|
||||
name = self.name
|
||||
cv = self.get_current_value()
|
||||
@@ -429,6 +537,7 @@ class AdjustableVirtual:
|
||||
append_aliases=False,
|
||||
name=None,
|
||||
unit=None,
|
||||
check_limits=False,
|
||||
):
|
||||
self.name = name
|
||||
self.alias = Alias(name)
|
||||
@@ -444,6 +553,7 @@ class AdjustableVirtual:
|
||||
self._foo_get_current_value = foo_get_current_value
|
||||
self._reset_current_value_to = reset_current_value_to
|
||||
self._change_simultaneously = change_simultaneously
|
||||
self._check_limits = check_limits
|
||||
if reset_current_value_to:
|
||||
for adj in self._adjustables:
|
||||
if not hasattr(adj, "reset_current_value_to"):
|
||||
@@ -457,18 +567,25 @@ class AdjustableVirtual:
|
||||
vals = (vals,)
|
||||
|
||||
def changer(value):
|
||||
if self._check_limits:
|
||||
if not self.check_target_value_within_limits(value):
|
||||
raise Exception(
|
||||
f"Target value of virtual adjustable {self.name} is higher than limit values of {[adj.name for adj in self._adjustables]}!"
|
||||
)
|
||||
|
||||
if self._change_simultaneously:
|
||||
self._active_changers = [
|
||||
adj.set_target_value(val, hold=False)
|
||||
for val, adj in zip(vals, self._adjustables)
|
||||
if val is not None
|
||||
]
|
||||
for tc in self._active_changers:
|
||||
tc.wait()
|
||||
else:
|
||||
|
||||
for val, adj in zip(vals, self._adjustables):
|
||||
self._active_changers = [adj.set_target_value(val, hold=False)]
|
||||
self._active_changers[0].wait()
|
||||
if val is not None:
|
||||
self._active_changers = [adj.set_target_value(val, hold=False)]
|
||||
self._active_changers[0].wait()
|
||||
|
||||
def stopper():
|
||||
for tc in self._active_changers:
|
||||
@@ -484,6 +601,14 @@ class AdjustableVirtual:
|
||||
*[adj.get_current_value() for adj in self._adjustables]
|
||||
)
|
||||
|
||||
def check_target_value_within_limits(self, value):
|
||||
in_lims = []
|
||||
values = self._foo_set_target_value_current_value(value)
|
||||
for val, adj in zip(values, self._adjustables):
|
||||
lim_low, lim_high = adj.get_limits()
|
||||
in_lims.append((lim_low < val) and (val < lim_high))
|
||||
return all(in_lims)
|
||||
|
||||
def reset_current_value_to(self, value):
|
||||
if not self._reset_current_value_to:
|
||||
raise NotImplementedError(
|
||||
@@ -500,7 +625,15 @@ class AdjustableVirtual:
|
||||
@tweak_option
|
||||
@value_property
|
||||
class AdjustableGetSet:
|
||||
def __init__(self, foo_get, foo_set, precision=0, check_interval=None, name=None):
|
||||
def __init__(
|
||||
self,
|
||||
foo_get,
|
||||
foo_set,
|
||||
precision=0,
|
||||
check_interval=None,
|
||||
cache_get_seconds=None,
|
||||
name=None,
|
||||
):
|
||||
"""assumes a waiting setterin function, in case no check_interval parameter is supplied"""
|
||||
self.alias = Alias(name)
|
||||
self.name = name
|
||||
@@ -508,6 +641,7 @@ class AdjustableGetSet:
|
||||
self._get = foo_get
|
||||
self._check_interval = check_interval
|
||||
self.precision = precision
|
||||
self._cache_get_seconds = cache_get_seconds
|
||||
|
||||
def set_and_wait(self, value):
|
||||
if self._check_interval:
|
||||
@@ -517,7 +651,7 @@ class AdjustableGetSet:
|
||||
else:
|
||||
self._set(value)
|
||||
|
||||
def set_target_value(self, value):
|
||||
def set_target_value(self, value, hold=False):
|
||||
return Changer(
|
||||
target=value,
|
||||
parent=self,
|
||||
@@ -527,7 +661,17 @@ class AdjustableGetSet:
|
||||
)
|
||||
|
||||
def get_current_value(self):
|
||||
return self._get()
|
||||
ts = time.time()
|
||||
if self._cache_get_seconds and hasattr(self, "_get_cache"):
|
||||
if ts - self._get_cache[0] < self._cache_get_seconds:
|
||||
value = self._get_cache[1]
|
||||
else:
|
||||
value = self._get()
|
||||
else:
|
||||
value = self._get()
|
||||
if self._cache_get_seconds:
|
||||
self._get_cache = (ts, value)
|
||||
return value
|
||||
|
||||
|
||||
@spec_convenience
|
||||
|
||||
+253
-20
@@ -1,8 +1,15 @@
|
||||
from datetime import datetime
|
||||
from inspect import isclass
|
||||
import json
|
||||
from pathlib import Path
|
||||
from tkinter import W
|
||||
from markdown import markdown
|
||||
|
||||
from numpy import isin
|
||||
|
||||
from eco.elements.protocols import Detector
|
||||
# from eco.acquisition.scan import NumpyEncoder
|
||||
|
||||
from eco.elements.protocols import Detector, InitialisationWaitable
|
||||
from ..aliases import Alias
|
||||
from tabulate import tabulate
|
||||
import colorama
|
||||
@@ -13,6 +20,11 @@ import subprocess
|
||||
from rich.progress import track
|
||||
from eco import Adjustable, Detector
|
||||
|
||||
import eco
|
||||
|
||||
|
||||
_initializing_assemblies = []
|
||||
|
||||
|
||||
class Collection:
|
||||
def __init__(self, name=None):
|
||||
@@ -60,7 +72,7 @@ class Collection:
|
||||
|
||||
|
||||
class Assembly:
|
||||
def __init__(self, name=None, parent=None, is_alias=True):
|
||||
def __init__(self, name=None, parent=None, is_alias=True, elog=None):
|
||||
self.name = name
|
||||
self.alias = Alias(name, parent=parent)
|
||||
# self.settings = []
|
||||
@@ -71,6 +83,10 @@ class Assembly:
|
||||
self.view_toplevel_only = []
|
||||
if memory.global_memory_dir:
|
||||
self.memory = memory.Memory(self)
|
||||
if elog:
|
||||
self.__elog = elog
|
||||
else:
|
||||
self.__class__.__elog = property(lambda dum: ELOG)
|
||||
|
||||
def _append(
|
||||
self,
|
||||
@@ -83,9 +99,16 @@ class Assembly:
|
||||
is_alias=True,
|
||||
view_toplevel_only=True,
|
||||
call_obj=True,
|
||||
append_property_with_name=False,
|
||||
**kwargs,
|
||||
):
|
||||
if call_obj and callable(foo_obj_init):
|
||||
if isinstance(foo_obj_init, Adjustable) and not isclass(foo_obj_init):
|
||||
self.__dict__[name] = foo_obj_init
|
||||
elif isinstance(foo_obj_init, Detector) and not isclass(foo_obj_init):
|
||||
self.__dict__[name] = foo_obj_init
|
||||
elif isinstance(foo_obj_init, Assembly) and not isclass(foo_obj_init):
|
||||
self.__dict__[name] = foo_obj_init
|
||||
elif call_obj and callable(foo_obj_init):
|
||||
self.__dict__[name] = foo_obj_init(*args, **kwargs, name=name)
|
||||
else:
|
||||
self.__dict__[name] = foo_obj_init
|
||||
@@ -93,6 +116,17 @@ class Assembly:
|
||||
# except:
|
||||
# print(f'object {name} / {foo_obj_init} not initialized with name/parent')
|
||||
# self.__dict__[name] = foo_obj_init(*args, **kwargs)
|
||||
if append_property_with_name:
|
||||
if isinstance(self.__dict__[name], Adjustable):
|
||||
self.__class__.__dict__[append_property_with_name] = property(
|
||||
self.__dict__[name].get_current_value,
|
||||
lambda val: self.__dict__[name].set_target_value(val).wait(),
|
||||
)
|
||||
elif isinstance(self.__dict__[name], Detector):
|
||||
self.__class__.__dict__[append_property_with_name] = property(
|
||||
self.__dict__[name].get_current_value,
|
||||
)
|
||||
|
||||
if is_setting == "auto":
|
||||
is_setting = isinstance(self.__dict__[name], Adjustable)
|
||||
if is_setting:
|
||||
@@ -110,11 +144,13 @@ class Assembly:
|
||||
if view_toplevel_only:
|
||||
self.view_toplevel_only.append(self.__dict__[name])
|
||||
|
||||
def get_status(self, base="self", verbose=True):
|
||||
def get_status(self, base="self", verbose=True, channeltypes=None):
|
||||
if base == "self":
|
||||
base = self
|
||||
settings = {}
|
||||
settings_channels = {}
|
||||
status = {}
|
||||
status_channels = {}
|
||||
nodet = []
|
||||
geterror = []
|
||||
for ts in track(
|
||||
@@ -129,11 +165,71 @@ class Assembly:
|
||||
# else:
|
||||
if hasattr(ts, "get_current_value"):
|
||||
try:
|
||||
settings[ts.alias.get_full_name(base=base)] = ts.get_current_value()
|
||||
if (not channeltypes) or (ts.alias.channeltype in channeltypes):
|
||||
settings[
|
||||
ts.alias.get_full_name(base=base)
|
||||
] = ts.get_current_value()
|
||||
try:
|
||||
settings_channels[
|
||||
ts.alias.get_full_name(base=base)
|
||||
] = ts.alias.channel
|
||||
except:
|
||||
pass
|
||||
except:
|
||||
geterror.append(ts.alias.get_full_name(base=base))
|
||||
else:
|
||||
nodet.append(ts.alias.get_full_name(base=base))
|
||||
|
||||
# with ThreadPoolExecutor(max_workers=max_workers) as exc:
|
||||
# list(
|
||||
# progress.track(
|
||||
# exc.map(
|
||||
# lambda name: self.init_name(
|
||||
# name, verbose=verbose, raise_errors=raise_errors
|
||||
# ),
|
||||
# self.all_names
|
||||
# - self.initialized_names
|
||||
# - set(exclude_names),
|
||||
# ),
|
||||
# description="Initializing ...",
|
||||
# total=len(
|
||||
# self.all_names - self.initialized_names - set(exclude_names)
|
||||
# ),
|
||||
# transient=True,
|
||||
# )
|
||||
# )
|
||||
|
||||
def get_stat_one_assembly(ts):
|
||||
if hasattr(ts, "get_current_value"):
|
||||
try:
|
||||
if (not channeltypes) or (ts.alias.channeltype in channeltypes):
|
||||
status[
|
||||
ts.alias.get_full_name(base=base)
|
||||
] = ts.get_current_value()
|
||||
try:
|
||||
status_channels[
|
||||
ts.alias.get_full_name(base=base)
|
||||
] = ts.alias.channel
|
||||
except:
|
||||
pass
|
||||
except:
|
||||
geterror.append(ts.alias.get_full_name(base=base))
|
||||
else:
|
||||
nodet.append(ts.alias.get_full_name(base=base))
|
||||
|
||||
# with ThreadPoolExecutor(max_workers=max_workers) as exc:
|
||||
# list(
|
||||
# progress.track(
|
||||
# exc.map(
|
||||
# get_stat_one_assembly,
|
||||
# self.status_collection.get_list(),
|
||||
# ),
|
||||
# description="Getting status...",
|
||||
# total=len(self.status_collection.get_list()),
|
||||
# transient=True,
|
||||
# )
|
||||
# )
|
||||
|
||||
for ts in track(
|
||||
self.status_collection.get_list(),
|
||||
transient=True,
|
||||
@@ -146,7 +242,16 @@ class Assembly:
|
||||
# else:
|
||||
if hasattr(ts, "get_current_value"):
|
||||
try:
|
||||
status[ts.alias.get_full_name(base=base)] = ts.get_current_value()
|
||||
if (not channeltypes) or (ts.alias.channeltype in channeltypes):
|
||||
status[
|
||||
ts.alias.get_full_name(base=base)
|
||||
] = ts.get_current_value()
|
||||
try:
|
||||
status_channels[
|
||||
ts.alias.get_full_name(base=base)
|
||||
] = ts.alias.channel
|
||||
except:
|
||||
pass
|
||||
except:
|
||||
geterror.append(ts.alias.get_full_name(base=base))
|
||||
else:
|
||||
@@ -159,7 +264,12 @@ class Assembly:
|
||||
"Retrieved error while running get_current_value from: "
|
||||
+ ", ".join(geterror)
|
||||
)
|
||||
return {"settings": settings, "status": status}
|
||||
return {
|
||||
"settings": settings,
|
||||
"status": status,
|
||||
"settings_channels": settings_channels,
|
||||
"status_channels": status_channels,
|
||||
}
|
||||
|
||||
def status(self, get_string=False):
|
||||
stat = self.get_status()
|
||||
@@ -194,38 +304,161 @@ class Assembly:
|
||||
s = tabulate([[name, value] for name, value in stat_filt[stat_field].items()])
|
||||
return s
|
||||
|
||||
def get_display_str(self):
|
||||
def get_display_str(self, tablefmt="simple"):
|
||||
main_name = self.name
|
||||
stats = self.display_collection()
|
||||
# stats_dict = {}
|
||||
tab = []
|
||||
for to in stats:
|
||||
name = to.alias.get_full_name(base=self)
|
||||
value = to.get_current_value()
|
||||
|
||||
is_adjustable = isinstance(to, Adjustable)
|
||||
if is_adjustable:
|
||||
typechar = "✏️"
|
||||
else:
|
||||
typechar = "👁️"
|
||||
is_detector = isinstance(to, Detector)
|
||||
typechar = ""
|
||||
if is_adjustable:
|
||||
typechar += "✏️"
|
||||
elif is_detector:
|
||||
typechar += "👁️"
|
||||
if hasattr(to, "settings_collection"):
|
||||
typechar += " ↳"
|
||||
|
||||
try:
|
||||
value = to.get_current_value()
|
||||
except AttributeError:
|
||||
if hasattr(to, "settings_collection"):
|
||||
value = "\x1b[3mhas lower level items\x1b[0m"
|
||||
|
||||
if isinstance(value, Enum):
|
||||
value = f"{value.value} ({value.name})"
|
||||
try:
|
||||
unit = to.unit()
|
||||
unit = to.unit.get_current_value()
|
||||
except:
|
||||
unit = None
|
||||
tab.append([".".join([main_name, name]), value, unit, typechar])
|
||||
s = tabulate(tab)
|
||||
try:
|
||||
description = to.description.get_current_value()
|
||||
except:
|
||||
description = None
|
||||
tab.append(
|
||||
[".".join([main_name, name]), value, unit, typechar, description]
|
||||
)
|
||||
s = tabulate(tab, tablefmt=tablefmt)
|
||||
return s
|
||||
|
||||
def status_to_elog(
|
||||
self,
|
||||
text="",
|
||||
text_encoding="markdown",
|
||||
auto_title=True,
|
||||
attach_display=True,
|
||||
attach_status_file=True,
|
||||
):
|
||||
elog = self._get_elog()
|
||||
message = ""
|
||||
files = []
|
||||
if auto_title:
|
||||
message += markdown(f"#### Status {self.alias.get_full_name()}")
|
||||
|
||||
if text:
|
||||
if text_encoding == "markdown":
|
||||
message += markdown(text)
|
||||
if attach_display:
|
||||
message += self.get_display_str(tablefmt="html")
|
||||
|
||||
if attach_status_file:
|
||||
stat = self.get_status()
|
||||
tmppath = Path("/tmp")
|
||||
filepath = tmppath / Path(
|
||||
f"status_{self.alias.get_full_name}_{datetime.now().isoformat()}.json"
|
||||
)
|
||||
with open(filepath, "w") as f:
|
||||
# json.dump(stat, f, cls=NumpyEncoder, indent=4)
|
||||
json.dump(stat, f, indent=4)
|
||||
files.append(filepath)
|
||||
|
||||
elog.post(
|
||||
message,
|
||||
*files,
|
||||
text_encoding="html",
|
||||
)
|
||||
# tags=[],
|
||||
|
||||
def __repr__(self):
|
||||
label = self.alias.get_full_name() + " status\n"
|
||||
return label + self.get_display_str()
|
||||
|
||||
def _run_cmd(self, line):
|
||||
print(f"Starting following commandline silently:\n" + line)
|
||||
with open(os.devnull, "w") as FNULL:
|
||||
subprocess.Popen(line, shell=True, stdout=FNULL, stderr=subprocess.STDOUT)
|
||||
# def _wait_for_initialisation(self, timeout=2):
|
||||
# for ton, to in self.__dict__.items():
|
||||
# try:
|
||||
# iswaitable = isinstance(to, InitialisationWaitable)
|
||||
# if iswaitable:
|
||||
# to._wait_for_initialisation()
|
||||
# except:
|
||||
# pass
|
||||
|
||||
def _wait_for_initialisation(self):
|
||||
for item in self.status_collection.get_list():
|
||||
if isinstance(item, Assembly) and (item in _initializing_assemblies):
|
||||
continue
|
||||
if isinstance(item, InitialisationWaitable):
|
||||
if isinstance(item, Assembly):
|
||||
_initializing_assemblies.append(item)
|
||||
item._wait_for_initialisation()
|
||||
|
||||
def _run_cmd(self, line, silent=True):
|
||||
if silent:
|
||||
print(f"Starting following commandline silently:\n" + line)
|
||||
with open(os.devnull, "w") as FNULL:
|
||||
subprocess.Popen(
|
||||
line, shell=True, stdout=FNULL, stderr=subprocess.STDOUT
|
||||
)
|
||||
else:
|
||||
subprocess.Popen(line, shell=True)
|
||||
|
||||
def _get_elog(self):
|
||||
if hasattr(self, "_elog") and self._elog:
|
||||
return self._elog
|
||||
elif hasattr(self, "__elog") and self.__elog:
|
||||
return self.__elog
|
||||
elif eco.ELOG:
|
||||
return eco.ELOG
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
import epics.pv
|
||||
import time
|
||||
|
||||
|
||||
class Monitor:
|
||||
def __init__(self, assembly):
|
||||
self.assembly = assembly
|
||||
self.data = {}
|
||||
self.callbacks = {}
|
||||
self.pvs = {}
|
||||
|
||||
def start_monitoring(self):
|
||||
o = self.assembly.get_status(channeltypes=["CA"])
|
||||
# self.data = {k: [v] for k, v in o["status"].items()}
|
||||
self.channelkeys = {v: k for k, v in o["status_channels"].items()}
|
||||
self.pvs = {k: epics.pv.PV(v) for k, v in o["status_channels"].items()}
|
||||
# for cik, civ in epics.pv._PVcache_.items():
|
||||
# if cik[0] in o["status_channels"].keys():
|
||||
# tname = self.channelkeys[cik[0]]
|
||||
# tpv = civ
|
||||
for tname, tpv in self.pvs.items():
|
||||
self.callbacks[tname] = tpv.add_callback(self.append)
|
||||
|
||||
def stop_monitoring(self):
|
||||
for tname in self.pvs:
|
||||
self.pvs[tname].remove_callback(index=self.callbacks[tname])
|
||||
|
||||
def append(self, pvname=None, value=None, timestamp=None, **kwargs):
|
||||
if not (self.channelkeys[pvname] in self.data):
|
||||
self.data[self.channelkeys[pvname]] = []
|
||||
ts_local = time.time()
|
||||
self.data[self.channelkeys[pvname]].append(
|
||||
{"value": value, "timestamp": timestamp, "timestamp_local": ts_local}
|
||||
)
|
||||
|
||||
|
||||
class Assembly_old:
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
from eco.elements.adjustable import AdjustableMemory
|
||||
from eco.elements.assembly import Assembly
|
||||
from eco.aliases import Alias
|
||||
import time
|
||||
|
||||
|
||||
def value_property(Det, value_name="_value"):
|
||||
@@ -65,11 +67,23 @@ class DetectorVirtual(Assembly):
|
||||
@call_convenience
|
||||
@value_property
|
||||
class DetectorGet:
|
||||
def __init__(self, foo_get, name=None):
|
||||
def __init__(self, foo_get, cache_get_seconds=None, name=None):
|
||||
""" """
|
||||
self.alias = Alias(name)
|
||||
self.name = name
|
||||
self._get = foo_get
|
||||
self._cache_get_seconds = cache_get_seconds
|
||||
|
||||
|
||||
def get_current_value(self):
|
||||
return self._get()
|
||||
ts = time.time()
|
||||
if self._cache_get_seconds and hasattr(self,'_get_cache'):
|
||||
if ts - self._get_cache[0] < self._cache_get_seconds:
|
||||
value = self._get_cache[1]
|
||||
else:
|
||||
value = self._get()
|
||||
else:
|
||||
value = self._get()
|
||||
if self._cache_get_seconds:
|
||||
self._get_cache= (ts,value)
|
||||
return value
|
||||
|
||||
+84
-16
@@ -5,6 +5,10 @@ from ..utilities.keypress import KeyPress
|
||||
from tabulate import tabulate
|
||||
import sys, colorama
|
||||
from inspect import getargspec
|
||||
import eco
|
||||
from ansi2html import Ansi2HTMLConverter
|
||||
|
||||
conv = Ansi2HTMLConverter()
|
||||
|
||||
global_memory_dir = None
|
||||
|
||||
@@ -60,8 +64,23 @@ class Memory:
|
||||
# print(self.get_memory_difference_str(index))
|
||||
self.recall(memory_index=index)
|
||||
|
||||
def _get_elog(self):
|
||||
if hasattr(self, "_elog") and self._elog:
|
||||
return self._elog
|
||||
elif hasattr(self, "__elog") and self.__elog:
|
||||
return self.__elog
|
||||
elif eco.ELOG:
|
||||
return eco.ELOG
|
||||
else:
|
||||
return None
|
||||
|
||||
def memorize(
|
||||
self, message=None, attributes={}, force_message=True, preset_varname=None
|
||||
self,
|
||||
message=None,
|
||||
attributes={},
|
||||
force_message=True,
|
||||
preset_varname=None,
|
||||
to_elog=True,
|
||||
):
|
||||
self.setup_path()
|
||||
stat_now = self.obj_parent.get_status(base=self.obj_parent)
|
||||
@@ -84,6 +103,15 @@ class Memory:
|
||||
tmp = AdjustableFS(self.dir / Path(key + ".json"))
|
||||
tmp(stat_now)
|
||||
self._memories(mem)
|
||||
print(f"Saved memory for {self.obj_parent.alias.get_full_name()}: {message}")
|
||||
print(f"memory file: {tmp.file_path.as_posix()}")
|
||||
if to_elog:
|
||||
elog = self._get_elog()
|
||||
elog.post(
|
||||
f"Saved memory for {self.obj_parent.alias.get_full_name()}: {message}",
|
||||
tmp.file_path,
|
||||
text_encoding="markdown",
|
||||
)
|
||||
|
||||
def get_memory(self, input_obj=None, index=None, key=None, filter_existing=True):
|
||||
if not input_obj is None:
|
||||
@@ -116,6 +144,15 @@ class Memory:
|
||||
else:
|
||||
return mem_full
|
||||
|
||||
def clear_memory(self, index=None, key=None):
|
||||
if not (index is None):
|
||||
key = list(self._memories().keys())[index]
|
||||
if key is None:
|
||||
raise Exception("memory key or index to be deleted needs to be specified!")
|
||||
mem = self._memories.get_current_value()
|
||||
mem.pop(key)
|
||||
self._memories.set_target_value(mem).wait()
|
||||
|
||||
def recall(
|
||||
self,
|
||||
memory_index=None,
|
||||
@@ -125,8 +162,26 @@ class Memory:
|
||||
show_changes_only=True,
|
||||
set_changes_only=True,
|
||||
check_limits=True,
|
||||
change_serially=False,
|
||||
force=False,
|
||||
):
|
||||
"""Recall a memory_index, from an index in the default meory list, from a
|
||||
dictionary containing the memory information, or from a path to a file containing the memory.
|
||||
|
||||
Args:
|
||||
memory_index (integer, optional): index in memory list. Defaults to None.
|
||||
input_obj (dictionary or string, optional): direct passing memory as dict or s filepath (string) to the memory file. Defaults to None.
|
||||
key (string, optional): key of memory in memory list (if not defined by the index). Defaults to None.
|
||||
wait (bool, optional): Wait for the memory recall changes to complete. Defaults to True.
|
||||
show_changes_only (bool, optional): in rpreview show only changes that are different to present setting. Defaults to True.
|
||||
set_changes_only (bool, optional): setting only the changes that changed. Defaults to True.
|
||||
check_limits (bool, optional): check limits before changing. Defaults to True.
|
||||
change_serially (bool, optional): change and wait each change after each other, not simultaneously. Defaults to False.
|
||||
force (bool, optional): force the change without previous preview. Defaults to False.
|
||||
|
||||
Returns:
|
||||
_type_: _description_
|
||||
"""
|
||||
# if input_obj:
|
||||
mem = self.get_memory(
|
||||
index=memory_index,
|
||||
@@ -160,6 +215,8 @@ class Memory:
|
||||
changes.append(to.set_target_value(val, check=check_limits))
|
||||
else:
|
||||
changes.append(to.set_target_value(val))
|
||||
if change_serially:
|
||||
changes[-1].wait()
|
||||
if wait:
|
||||
for change in changes:
|
||||
change.wait()
|
||||
@@ -171,7 +228,12 @@ class Memory:
|
||||
...
|
||||
|
||||
def get_memory_difference_str(
|
||||
self, memory, select=None, ask_select=True, show_changes_only=False
|
||||
self,
|
||||
memory,
|
||||
select=None,
|
||||
ask_select=True,
|
||||
show_changes_only=False,
|
||||
tablefmt="plain",
|
||||
):
|
||||
# mem = self.get_memory(index=memory_index)
|
||||
mem = memory
|
||||
@@ -187,12 +249,15 @@ class Memory:
|
||||
tselstr = " "
|
||||
if present_value == recall_value:
|
||||
changed = False
|
||||
comp_indicator = (
|
||||
colorama.Fore.GREEN
|
||||
+ colorama.Style.BRIGHT
|
||||
+ "=="
|
||||
+ colorama.Style.RESET_ALL
|
||||
)
|
||||
if tablefmt == "html":
|
||||
comp_indicator = "=="
|
||||
else:
|
||||
comp_indicator = (
|
||||
colorama.Fore.GREEN
|
||||
+ colorama.Style.BRIGHT
|
||||
+ "=="
|
||||
+ colorama.Style.RESET_ALL
|
||||
)
|
||||
else:
|
||||
changed = True
|
||||
if not tsel:
|
||||
@@ -202,14 +267,18 @@ class Memory:
|
||||
tdiff = f"{recall_value - present_value:+g}"
|
||||
except TypeError:
|
||||
tdiff = "special"
|
||||
comp_indicator = (
|
||||
colorama.Fore.RED
|
||||
+ colorama.Style.BRIGHT
|
||||
+ f"{tdiff:s}"
|
||||
+ colorama.Style.RESET_ALL
|
||||
)
|
||||
if tablefmt == "html":
|
||||
comp_indicator = f"{tdiff:s}"
|
||||
else:
|
||||
comp_indicator = (
|
||||
colorama.Fore.RED
|
||||
+ colorama.Style.BRIGHT
|
||||
+ f"{tdiff:s}"
|
||||
+ colorama.Style.RESET_ALL
|
||||
)
|
||||
if show_changes_only and (not changed):
|
||||
continue
|
||||
|
||||
table.append([n, tselstr, key, present_value, comp_indicator, recall_value])
|
||||
|
||||
if len(table) == 0:
|
||||
@@ -225,12 +294,12 @@ class Memory:
|
||||
"memory",
|
||||
],
|
||||
colalign=("decimal", "center", "left", "decimal", "center", "decimal"),
|
||||
tablefmt=tablefmt,
|
||||
)
|
||||
|
||||
def select_from_memory(
|
||||
self, input_obj=None, key=None, memory_index=None, show_changes_only=True
|
||||
):
|
||||
|
||||
mem = self.get_memory(input_obj=input_obj, key=key, index=memory_index)
|
||||
rec = mem["settings"]
|
||||
k = KeyPress()
|
||||
@@ -385,7 +454,6 @@ class Preset:
|
||||
return s
|
||||
|
||||
def __repr__(self):
|
||||
|
||||
return self.__str__()
|
||||
|
||||
|
||||
|
||||
@@ -16,3 +16,15 @@ class Adjustable(Protocol):
|
||||
class Detector(Protocol):
|
||||
def get_current_value(self):
|
||||
...
|
||||
|
||||
|
||||
@runtime_checkable
|
||||
class ValueUpdateMonitorable(Protocol):
|
||||
def get_current_value_callback(self):
|
||||
...
|
||||
|
||||
|
||||
@runtime_checkable
|
||||
class InitialisationWaitable(Protocol):
|
||||
def _wait_for_initialisation(self):
|
||||
...
|
||||
|
||||
@@ -14,6 +14,7 @@ from ..elements.assembly import Assembly
|
||||
from ..detector.jungfrau import Jungfrau
|
||||
from .kappa_conversion import kappa2you, you2kappa
|
||||
import numpy as np
|
||||
from ..utilities.recspace import Crystals, DiffGeometryYou
|
||||
|
||||
|
||||
def addMotorRecordToSelf(self, name=None, Id=None):
|
||||
@@ -32,6 +33,7 @@ class GPS(Assembly):
|
||||
configuration=["base"],
|
||||
alias_namespace=None,
|
||||
fina_hex_angle_offset=None,
|
||||
diffcalc=False,
|
||||
):
|
||||
super().__init__(name=name)
|
||||
self.pvname = pvname
|
||||
@@ -136,7 +138,6 @@ class GPS(Assembly):
|
||||
)
|
||||
|
||||
if "phi_hex" in self.configuration:
|
||||
|
||||
### motors PI hexapod ###
|
||||
if fina_hex_angle_offset:
|
||||
fina_hex_angle_offset = Path(fina_hex_angle_offset).expanduser()
|
||||
@@ -274,6 +275,15 @@ class GPS(Assembly):
|
||||
unit="deg",
|
||||
)
|
||||
|
||||
if diffcalc:
|
||||
self._append(
|
||||
Crystals,
|
||||
diffractometer_you=self,
|
||||
name="diffcalc",
|
||||
is_setting=False,
|
||||
is_display=False,
|
||||
)
|
||||
|
||||
def gui(self, guiType="xdm"):
|
||||
"""Adjustable convention"""
|
||||
cmd = ["caqtdm", "-macro"]
|
||||
@@ -400,8 +410,12 @@ class XRDYou(Assembly):
|
||||
name=None,
|
||||
Id=None,
|
||||
configuration=["base"],
|
||||
diff_detector=None,
|
||||
detectors=None,
|
||||
invert_kappa_ellbow=True,
|
||||
pgroup_adj=None,
|
||||
configsjf_adj=None,
|
||||
fina_hex_angle_offset=None,
|
||||
diffcalc=True,
|
||||
):
|
||||
"""X-ray diffractometer platform in AiwssFEL Bernina.\
|
||||
<configuration> : list of elements mounted on
|
||||
@@ -566,7 +580,7 @@ class XRDYou(Assembly):
|
||||
try:
|
||||
self._append(
|
||||
MotorRecord_new,
|
||||
Id + ":MOT_TBL_RY",
|
||||
Id + ":MOT_TBL_RZ",
|
||||
name="rzhl",
|
||||
is_setting=True,
|
||||
is_display=True,
|
||||
@@ -580,62 +594,75 @@ class XRDYou(Assembly):
|
||||
self._append(
|
||||
MotorRecord_new,
|
||||
Id + ":MOT_HEX_TX",
|
||||
name="tphi",
|
||||
name="transl_eta",
|
||||
is_setting=True,
|
||||
is_display=True,
|
||||
)
|
||||
self._append(
|
||||
MotorRecord_new,
|
||||
Id + ":MOT_HEX_RX",
|
||||
name="phi",
|
||||
name="eta",
|
||||
is_setting=True,
|
||||
is_display=True,
|
||||
)
|
||||
|
||||
if "phi_hex" in self.configuration:
|
||||
### motors PI hexapod ###
|
||||
append_object_to_object(
|
||||
self,
|
||||
AdjustablePv,
|
||||
"SARES20-HEX_PI:SET-POSI-X",
|
||||
pvreadbackname="SARES20-HEX_PI:POSI-X",
|
||||
name="xhex",
|
||||
)
|
||||
append_object_to_object(
|
||||
self,
|
||||
AdjustablePv,
|
||||
"SARES20-HEX_PI:SET-POSI-Y",
|
||||
pvreadbackname="SARES20-HEX_PI:POSI-Y",
|
||||
name="yhex",
|
||||
)
|
||||
append_object_to_object(
|
||||
self,
|
||||
AdjustablePv,
|
||||
"SARES20-HEX_PI:SET-POSI-Z",
|
||||
pvreadbackname="SARES20-HEX_PI:POSI-Z",
|
||||
name="zhex",
|
||||
)
|
||||
append_object_to_object(
|
||||
self,
|
||||
AdjustablePv,
|
||||
"SARES20-HEX_PI:SET-POSI-U",
|
||||
pvreadbackname="SARES20-HEX_PI:POSI-U",
|
||||
name="uhex",
|
||||
)
|
||||
append_object_to_object(
|
||||
self,
|
||||
AdjustablePv,
|
||||
"SARES20-HEX_PI:SET-POSI-V",
|
||||
pvreadbackname="SARES20-HEX_PI:POSI-V",
|
||||
name="vhex",
|
||||
)
|
||||
append_object_to_object(
|
||||
self,
|
||||
AdjustablePv,
|
||||
"SARES20-HEX_PI:SET-POSI-W",
|
||||
pvreadbackname="SARES20-HEX_PI:POSI-W",
|
||||
name="whex",
|
||||
if fina_hex_angle_offset:
|
||||
fina_hex_angle_offset = Path(fina_hex_angle_offset).expanduser()
|
||||
|
||||
self._append(
|
||||
HexapodPI,
|
||||
"SARES20-HEX_PI",
|
||||
name="hex",
|
||||
fina_angle_offset=fina_hex_angle_offset,
|
||||
is_setting=True,
|
||||
is_display="recursive",
|
||||
)
|
||||
# if "phi_hex" in self.configuration:
|
||||
# ### motors PI hexapod ###
|
||||
# append_object_to_object(
|
||||
# self,
|
||||
# AdjustablePv,
|
||||
# "SARES20-HEX_PI:SET-POSI-X",
|
||||
# pvreadbackname="SARES20-HEX_PI:POSI-X",
|
||||
# name="xhex",
|
||||
# )
|
||||
# append_object_to_object(
|
||||
# self,
|
||||
# AdjustablePv,
|
||||
# "SARES20-HEX_PI:SET-POSI-Y",
|
||||
# pvreadbackname="SARES20-HEX_PI:POSI-Y",
|
||||
# name="yhex",
|
||||
# )
|
||||
# append_object_to_object(
|
||||
# self,
|
||||
# AdjustablePv,
|
||||
# "SARES20-HEX_PI:SET-POSI-Z",
|
||||
# pvreadbackname="SARES20-HEX_PI:POSI-Z",
|
||||
# name="zhex",
|
||||
# )
|
||||
# append_object_to_object(
|
||||
# self,
|
||||
# AdjustablePv,
|
||||
# "SARES20-HEX_PI:SET-POSI-U",
|
||||
# pvreadbackname="SARES20-HEX_PI:POSI-U",
|
||||
# name="uhex",
|
||||
# )
|
||||
# append_object_to_object(
|
||||
# self,
|
||||
# AdjustablePv,
|
||||
# "SARES20-HEX_PI:SET-POSI-V",
|
||||
# pvreadbackname="SARES20-HEX_PI:POSI-V",
|
||||
# name="vhex",
|
||||
# )
|
||||
# append_object_to_object(
|
||||
# self,
|
||||
# AdjustablePv,
|
||||
# "SARES20-HEX_PI:SET-POSI-W",
|
||||
# pvreadbackname="SARES20-HEX_PI:POSI-W",
|
||||
# name="whex",
|
||||
# )
|
||||
|
||||
if "kappa" in self.configuration:
|
||||
self._append(
|
||||
@@ -757,14 +784,28 @@ class XRDYou(Assembly):
|
||||
unit="deg",
|
||||
)
|
||||
|
||||
if diff_detector:
|
||||
if detectors:
|
||||
for tdet in detectors:
|
||||
tname = tdet["name"]
|
||||
tid = tdet["jf_id"]
|
||||
self._append(
|
||||
Jungfrau,
|
||||
tid,
|
||||
name=tname,
|
||||
is_setting=False,
|
||||
is_display=False,
|
||||
pgroup_adj=pgroup_adj,
|
||||
config_adj=configsjf_adj,
|
||||
view_toplevel_only=True,
|
||||
)
|
||||
|
||||
if diffcalc:
|
||||
self._append(
|
||||
Jungfrau,
|
||||
diff_detector["jf_id"],
|
||||
name="det_diff",
|
||||
Crystals,
|
||||
diffractometer_you=self,
|
||||
name="diffcalc",
|
||||
is_setting=False,
|
||||
is_display=False,
|
||||
view_toplevel_only=True,
|
||||
)
|
||||
|
||||
def get_adjustable_positions_str(self):
|
||||
@@ -804,10 +845,12 @@ class XRDYou(Assembly):
|
||||
kappa_angle=60,
|
||||
degrees=True,
|
||||
bernina_kappa=True,
|
||||
invert_elbow=False,
|
||||
invert_elbow=None,
|
||||
):
|
||||
"""tool to convert from you definition angles to kappa angles, in
|
||||
particular the bernina kappa where the"""
|
||||
if invert_elbow is None:
|
||||
invert_elbow = self.invert_kappa_ellbow
|
||||
if bernina_kappa:
|
||||
eta = -eta
|
||||
phi = -phi
|
||||
@@ -828,16 +871,16 @@ class XRDYou(Assembly):
|
||||
if bernina_kappa:
|
||||
eta_k = eta_k - np.pi / 2
|
||||
kappa = -kappa
|
||||
if False:
|
||||
if True:
|
||||
|
||||
def flip_ang(ang):
|
||||
if 1 < abs(ang // np.pi):
|
||||
if 2 <= abs(ang // np.pi):
|
||||
return ang - np.sign(ang) * np.pi * 2
|
||||
else:
|
||||
return ang
|
||||
|
||||
# phi_k = flip_ang(phi_k)
|
||||
phi_k = phi_k + np.pi * 2
|
||||
phi_k = flip_ang(phi_k)
|
||||
# phi_k = phi_k + np.pi * 2
|
||||
eta_k = flip_ang(eta_k)
|
||||
kappa = flip_ang(kappa)
|
||||
if degrees:
|
||||
@@ -852,8 +895,10 @@ class XRDYou(Assembly):
|
||||
kappa_angle=60,
|
||||
degrees=True,
|
||||
bernina_kappa=True,
|
||||
invert_elbow=False,
|
||||
invert_elbow=None,
|
||||
):
|
||||
if invert_elbow is None:
|
||||
invert_elbow = self.invert_kappa_ellbow
|
||||
if degrees:
|
||||
eta_k, kappa, phi_k, kappa_angle = np.deg2rad(
|
||||
[eta_k, kappa, phi_k, kappa_angle]
|
||||
@@ -927,7 +972,14 @@ class XRDYou(Assembly):
|
||||
|
||||
|
||||
class XRD(Assembly):
|
||||
def __init__(self, name=None, Id=None, configuration=["base"], diff_detector=None):
|
||||
def __init__(
|
||||
self,
|
||||
name=None,
|
||||
Id=None,
|
||||
configuration=["base"],
|
||||
diff_detector=None,
|
||||
pgroup_adj=None,
|
||||
):
|
||||
"""X-ray diffractometer platform in AiwssFEL Bernina.\
|
||||
<configuration> : list of elements mounted on
|
||||
the plaform, options are kappa, nutable, hlgonio, polana"""
|
||||
@@ -1152,6 +1204,7 @@ class XRD(Assembly):
|
||||
name="det_diff",
|
||||
is_setting=False,
|
||||
is_display=True,
|
||||
pgroup_adj=pgroup_adj,
|
||||
view_toplevel_only=True,
|
||||
)
|
||||
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
from eco import Assembly
|
||||
from eco.detector.jungfrau import Jungfrau
|
||||
|
||||
|
||||
class DetectorRobot(Assembly):
|
||||
def __init__(
|
||||
self,
|
||||
JF_detector_id=None,
|
||||
JF_detector_name="det_diff",
|
||||
name="robot",
|
||||
pgroup_adj=None,
|
||||
config_adj=None,
|
||||
):
|
||||
super().__init__(name=name)
|
||||
self._append(
|
||||
Jungfrau,
|
||||
JF_detector_id,
|
||||
pgroup_adj=pgroup_adj,
|
||||
config_adj=config_adj,
|
||||
name=JF_detector_name,
|
||||
)
|
||||
@@ -1,15 +1,14 @@
|
||||
from eco.devices_general.powersockets import MpodChannel
|
||||
import sys
|
||||
|
||||
sys.path.append("..")
|
||||
from ..devices_general.motors import MotorRecord, SmaractStreamdevice
|
||||
from ..devices_general.smaract import SmarActRecord
|
||||
from ..devices_general.motors import MotorRecord, SmaractRecord
|
||||
from ..epics.adjustable import AdjustablePv
|
||||
import numpy as np
|
||||
from epics import PV
|
||||
from ..aliases import Alias, append_object_to_object
|
||||
from time import sleep
|
||||
import escape.parse.swissfel as sf
|
||||
from ..bernina import config
|
||||
import pylab as plt
|
||||
import escape
|
||||
from pathlib import Path
|
||||
@@ -33,20 +32,19 @@ def addMotorRecordToSelf(self, name=None, Id=None):
|
||||
|
||||
|
||||
def addSmarActRecordToSelf(self, Id=None, name=None, **kwargs):
|
||||
self.__dict__[name] = SmaractStreamdevice(Id, name=name, **kwargs)
|
||||
self.__dict__[name] = SmaractRecord(Id, name=name, **kwargs)
|
||||
self.alias.append(self.__dict__[name].alias)
|
||||
|
||||
|
||||
class High_field_thz_chamber(Assembly):
|
||||
def __init__(self, name=None, Id=None, alias_namespace=None, configuration=[]):
|
||||
def __init__(self, name=None, alias_namespace=None, configuration=[], illumination_mpod = None, helium_control_valve=None):
|
||||
super().__init__(name=name)
|
||||
self.Id = Id
|
||||
self.name = name
|
||||
self.alias = Alias(name)
|
||||
self.par_out_pos = [35, -9.5]
|
||||
self.motor_configuration = {
|
||||
"rx": {
|
||||
"id": "-ESB13",
|
||||
# "id": "SARES23-USR:MOT_13",
|
||||
"id": "SARES23-USR:MOT_6",
|
||||
"pv_descr": "Motor7:1 THz Chamber Rx",
|
||||
"type": 2,
|
||||
"sensor": 1,
|
||||
@@ -55,7 +53,8 @@ class High_field_thz_chamber(Assembly):
|
||||
"kwargs": {"accuracy": 0.01},
|
||||
},
|
||||
"x": {
|
||||
"id": "-ESB14",
|
||||
# "id": "SARES23-USR:MOT_14",
|
||||
"id": "SARES23-USR:MOT_15",
|
||||
"pv_descr": "Motor7:2 THz Chamber x ",
|
||||
"type": 1,
|
||||
"sensor": 0,
|
||||
@@ -63,7 +62,8 @@ class High_field_thz_chamber(Assembly):
|
||||
"home_direction": "back",
|
||||
},
|
||||
"z": {
|
||||
"id": "-ESB10",
|
||||
# "id": "SARES23-USR:MOT_10",
|
||||
"id": "SARES23-LIC:MOT_16",
|
||||
"pv_descr": "Motor6:1 THz Chamber z ",
|
||||
"type": 1,
|
||||
"sensor": 0,
|
||||
@@ -71,7 +71,8 @@ class High_field_thz_chamber(Assembly):
|
||||
"home_direction": "back",
|
||||
},
|
||||
"ry": {
|
||||
"id": "-ESB11",
|
||||
# "id": "SARES23-USR:MOT_11",
|
||||
"id": "SARES23-LIC:MOT_15",
|
||||
"pv_descr": "Motor6:2 THz Chamber Ry",
|
||||
"type": 2,
|
||||
"sensor": 1,
|
||||
@@ -79,7 +80,8 @@ class High_field_thz_chamber(Assembly):
|
||||
"home_direction": "back",
|
||||
},
|
||||
"rz": {
|
||||
"id": "-ESB12",
|
||||
# "id": "SARES23-USR:MOT_12",
|
||||
"id": "SARES23-USR:MOT_4",
|
||||
"pv_descr": "Motor6:3 THz Chamber Rz",
|
||||
"type": 2,
|
||||
"sensor": 1,
|
||||
@@ -91,33 +93,41 @@ class High_field_thz_chamber(Assembly):
|
||||
### lakeshore temperatures ####
|
||||
self._append(
|
||||
AdjustablePv,
|
||||
pvsetname="SARES20-CRYO:TEMP.VAL",
|
||||
pvreadbackname="SARES20-CRYO:TEMP_RBV",
|
||||
pvsetname="SARES20-LS336:LOOP1_SP",
|
||||
pvreadbackname="SARES20-LS336:A_RBV",
|
||||
accuracy=0.1,
|
||||
name="temp_sample",
|
||||
is_setting=False,
|
||||
)
|
||||
self._append(
|
||||
AdjustablePv,
|
||||
pvsetname="SARES20-CRYO:TEMP-B",
|
||||
pvreadbackname="SARES20-CRYO:TEMP-B_RBV",
|
||||
pvsetname="SARES20-LS336:LOOP2_SP",
|
||||
pvreadbackname="SARES20-LS336:B_RBV",
|
||||
accuracy=0.1,
|
||||
name="temp_coldfinger",
|
||||
is_setting=False,
|
||||
)
|
||||
|
||||
### in vacuum smaract motors ###
|
||||
#for name, config in self.motor_configuration.items():
|
||||
# if "kwargs" in config.keys():
|
||||
# tmp_kwargs = config["kwargs"]
|
||||
# else:
|
||||
# tmp_kwargs = {}
|
||||
# self._append(
|
||||
# SmaractStreamdevice,
|
||||
# pvname=Id + config["id"],
|
||||
# name=name,
|
||||
# is_setting=True,
|
||||
# **tmp_kwargs,
|
||||
# )
|
||||
### in vacuum smaract motors ###
|
||||
for name, config in self.motor_configuration.items():
|
||||
if "kwargs" in config.keys():
|
||||
tmp_kwargs = config["kwargs"]
|
||||
else:
|
||||
tmp_kwargs = {}
|
||||
self._append(
|
||||
SmaractStreamdevice,
|
||||
pvname=Id + config["id"],
|
||||
SmaractRecord,
|
||||
pvname=config["id"],
|
||||
name=name,
|
||||
is_setting=True,
|
||||
**tmp_kwargs,
|
||||
)
|
||||
self._append(
|
||||
AdjustableFS,
|
||||
@@ -160,6 +170,29 @@ class High_field_thz_chamber(Assembly):
|
||||
is_display=True,
|
||||
is_setting=True,
|
||||
)
|
||||
if illumination_mpod:
|
||||
for illu in illumination_mpod:
|
||||
self._append(MpodChannel,illu['pvbase'], illu['channel_number'], module_string=illu['module_string'], name=illu['name'])
|
||||
if helium_control_valve:
|
||||
self._append(MpodChannel,helium_control_valve['pvbase'], helium_control_valve['channel_number'], module_string=helium_control_valve['module_string'], name="_helium_valve_mpod_ch", is_display=True, is_setting=True)
|
||||
|
||||
def get_valve(voltage):
|
||||
if voltage < 2.9:
|
||||
val=0
|
||||
elif voltage > 5.5:
|
||||
val=100
|
||||
else:
|
||||
val = (voltage-2.9)/(5.5-2.9)*100
|
||||
return val
|
||||
|
||||
def set_valve(val):
|
||||
if val <1:
|
||||
voltage = .5
|
||||
else:
|
||||
voltage = val*(5.5-2.9)/100+2.9
|
||||
return voltage
|
||||
|
||||
self._append(AdjustableVirtual, [self._helium_valve_mpod_ch.voltage], get_valve, set_valve, name=helium_control_valve["name"], is_display=True, is_setting=False)
|
||||
|
||||
def moveout(self):
|
||||
change_in_pos = str(
|
||||
@@ -187,12 +220,12 @@ class High_field_thz_chamber(Assembly):
|
||||
def set_stage_config(self):
|
||||
for name, config in self.motor_configuration.items():
|
||||
mot = self.__dict__[name]
|
||||
mot.caqtdm_name(config["pv_descr"])
|
||||
mot.stage_type(config["type"])
|
||||
mot.description(config["pv_descr"])
|
||||
#mot.stage_type(config["type"])
|
||||
mot.sensor_type(config["sensor"])
|
||||
mot.speed(config["speed"])
|
||||
mot.max_frequency(config["speed"])
|
||||
sleep(0.5)
|
||||
mot.calibrate_sensor(1)
|
||||
mot.calibrate_sensor()
|
||||
|
||||
def home_smaract_stages(self, stages=None):
|
||||
if stages == None:
|
||||
@@ -209,25 +242,27 @@ class High_field_thz_chamber(Assembly):
|
||||
)
|
||||
sleep(1)
|
||||
if config["home_direction"] == "back":
|
||||
mot.home_backward(1)
|
||||
while mot.status_channel().value == 7:
|
||||
mot.home_reverse(1)
|
||||
sleep(.5)
|
||||
while not mot.flags.motion_complete():
|
||||
sleep(1)
|
||||
if mot.is_homed() == 0:
|
||||
if not mot.flags.is_homed():
|
||||
print(
|
||||
"Homing failed, try homing {} in forward direction".format(name)
|
||||
)
|
||||
mot.home_forward(1)
|
||||
elif config["home_direction"] == "forward":
|
||||
mot.home_forward(1)
|
||||
while mot.status_channel().value == 7:
|
||||
sleep(.5)
|
||||
while not mot.flags.motion_complete():
|
||||
sleep(1)
|
||||
if mot.is_homed() == 0:
|
||||
if not mot.flags.is_homed():
|
||||
print(
|
||||
"Homing failed, try homing {} in backward direction".format(
|
||||
name
|
||||
)
|
||||
)
|
||||
mot.home_backward(1)
|
||||
mot.home_reverse(1)
|
||||
|
||||
def calc_otti(
|
||||
self, otti_nu=None, otti_del=None, otti_det=None, plotit=True, **kwargs
|
||||
@@ -255,40 +290,45 @@ class Organic_crystal_breadboard(Assembly):
|
||||
self.alias = Alias(name)
|
||||
|
||||
self.motor_configuration = {
|
||||
"mirr2_x": {
|
||||
"id": "-LIC17",
|
||||
"mir_x": {
|
||||
# "id": "-LIC17",
|
||||
"id": "-USR:MOT_8",
|
||||
"pv_descr": "Motor8:2 THz mirror x ",
|
||||
"type": 1,
|
||||
"sensor": 13,
|
||||
"speed": 250,
|
||||
"home_direction": "back",
|
||||
},
|
||||
"mirr2_rz": {
|
||||
"id": "-LIC18",
|
||||
"mir_rz": {
|
||||
# "id": "-LIC18",
|
||||
"id": "-USR:MOT_9",
|
||||
"pv_descr": "Motor8:3 THz mirror rz ",
|
||||
"type": 1,
|
||||
"sensor": 13,
|
||||
"speed": 250,
|
||||
"home_direction": "back",
|
||||
},
|
||||
"mirr2_ry": {
|
||||
"id": "-ESB1",
|
||||
"mir_ry": {
|
||||
# "id": "-ESB1",
|
||||
"id": "-LIC:MOT_18",
|
||||
"pv_descr": "Motor3:1 THz mirror ry ",
|
||||
"type": 2,
|
||||
"sensor": 1,
|
||||
"speed": 250,
|
||||
"home_direction": "forward",
|
||||
},
|
||||
"mirr2_z": {
|
||||
"id": "-LIC16",
|
||||
"mir_z": {
|
||||
# "id": "-LIC16",
|
||||
"id": "-USR:MOT_7",
|
||||
"pv_descr": "Motor8:1 THz mirror z",
|
||||
"type": 1,
|
||||
"sensor": 13,
|
||||
"speed": 250,
|
||||
"home_direction": "back",
|
||||
},
|
||||
"par2_x": {
|
||||
"id": "-ESB3",
|
||||
"par_x": {
|
||||
# "id": "-ESB3",
|
||||
"id": "-LIC:MOT_17",
|
||||
"pv_descr": "Motor3:3 THz parabola2 x",
|
||||
"type": 1,
|
||||
"sensor": 0,
|
||||
@@ -296,39 +336,43 @@ class Organic_crystal_breadboard(Assembly):
|
||||
"home_direction": "back",
|
||||
},
|
||||
"delaystage_thz": {
|
||||
"id": "-ESB18",
|
||||
# "id": "-ESB18",
|
||||
"id": "-USR:MOT_1",
|
||||
"pv_descr": "Motor8:3 NIR delay stage",
|
||||
"type": 1,
|
||||
"sensor": 0,
|
||||
"speed": 100,
|
||||
"home_direction": "back",
|
||||
},
|
||||
"nir_mirr1_ry": {
|
||||
"id": "-ESB17",
|
||||
"nir_m1_ry": {
|
||||
# "id": "-ESB17",
|
||||
"id": "-USR:MOT_3",
|
||||
"pv_descr": "Motor8:2 near IR mirror 1 ry",
|
||||
"type": 2,
|
||||
"sensor": 1,
|
||||
"speed": 250,
|
||||
"home_direction": "back",
|
||||
},
|
||||
"nir_mirr1_rx": {
|
||||
"id": "-ESB16",
|
||||
"nir_m1_rx": {
|
||||
"id": "-USR:MOT_16",
|
||||
"pv_descr": "Motor8:1 near IR mirror 1 rx",
|
||||
"type": 2,
|
||||
"sensor": 1,
|
||||
"speed": 250,
|
||||
"home_direction": "back",
|
||||
},
|
||||
"nir_mirr2_ry": {
|
||||
"id": "-ESB9",
|
||||
"nir_m2_ry": {
|
||||
# "id": "-ESB9",
|
||||
"id": "-USR:MOT_14",
|
||||
"pv_descr": "Motor5:3 near IR mirror 2 ry",
|
||||
"type": 2,
|
||||
"sensor": 1,
|
||||
"speed": 250,
|
||||
"home_direction": "back",
|
||||
},
|
||||
"nir_mirr2_rx": {
|
||||
"id": "-ESB4",
|
||||
"nir_m2_rx": {
|
||||
# "id": "-USR:MOT_4",
|
||||
"id": "-USR:MOT_12",
|
||||
"pv_descr": "Motor4:1 near IR mirror 2 rx",
|
||||
"type": 1,
|
||||
"sensor": 13,
|
||||
@@ -336,7 +380,7 @@ class Organic_crystal_breadboard(Assembly):
|
||||
"home_direction": "back",
|
||||
},
|
||||
"crystal": {
|
||||
"id": "-ESB2",
|
||||
"id": "-USR:MOT_2",
|
||||
"pv_descr": "Motor3:2 crystal rotation",
|
||||
"type": 2,
|
||||
"sensor": 1,
|
||||
@@ -344,7 +388,7 @@ class Organic_crystal_breadboard(Assembly):
|
||||
"home_direction": "back",
|
||||
},
|
||||
"wp": {
|
||||
"id": "-ESB7",
|
||||
"id": "-USR:MOT_7",
|
||||
"pv_descr": "Motor5:1 waveplate rotation",
|
||||
"type": 2,
|
||||
"sensor": 1,
|
||||
@@ -359,7 +403,7 @@ class Organic_crystal_breadboard(Assembly):
|
||||
### smaract motors ###
|
||||
for name, config in self.motor_configuration.items():
|
||||
self._append(
|
||||
SmaractStreamdevice,
|
||||
SmaractRecord,
|
||||
pvname=Id + config["id"],
|
||||
name=name,
|
||||
is_setting=True,
|
||||
|
||||
+67
-11
@@ -1,6 +1,8 @@
|
||||
import time
|
||||
from epics import PV
|
||||
from ..elements.adjustable import AdjustableFS, AdjustableVirtual
|
||||
from ..epics.adjustable import AdjustablePv, AdjustablePvEnum
|
||||
from ..epics.detector import DetectorPvData
|
||||
from time import sleep
|
||||
from ..aliases import append_object_to_object, Alias
|
||||
from scipy.spatial.transform import Rotation
|
||||
@@ -24,80 +26,119 @@ class Hexapod_PI:
|
||||
for i in "RST"
|
||||
]
|
||||
|
||||
class AdjustablePiHex(AdjustablePv):
|
||||
def __init__(self, pvname=None, pvreadbackname=None, accuracy=None, unit=None, name=None):
|
||||
super().__init__(pvname, pvreadbackname=pvreadbackname, accuracy=accuracy, unit=unit, name=name)
|
||||
self.limit_high = AdjustableFS(f'/sf/bernina/config/eco/reference_values/hex_pi_{name}_limit_high.json', default_value=0)
|
||||
self.limit_low = AdjustableFS(f'/sf/bernina/config/eco/reference_values/hex_pi_{name}_limit_low.json', default_value=0)
|
||||
|
||||
|
||||
def change(self, value):
|
||||
if self.limit_low:
|
||||
if value < self.limit_low():
|
||||
raise Exception(
|
||||
f"Target value of {self.name} is smaller than limit value!"
|
||||
)
|
||||
if self.limit_high:
|
||||
if self.limit_high() < value:
|
||||
raise Exception(
|
||||
f"Target value of {self.name} is higher than limit value!"
|
||||
)
|
||||
self._pv.put(value)
|
||||
time.sleep(0.1)
|
||||
while self.get_change_done() == 0:
|
||||
time.sleep(0.1)
|
||||
|
||||
def get_limits(self):
|
||||
return (self.limit_low(), self.limit_high())
|
||||
|
||||
def set_limits(self, limit_low, limit_high):
|
||||
self.limit_low(limit_low)
|
||||
self.limit_high(limit_high)
|
||||
|
||||
|
||||
class HexapodPI(Assembly):
|
||||
def __init__(self, pvname, name=None, fina_angle_offset=None):
|
||||
super().__init__(name=name)
|
||||
self.pvname = pvname
|
||||
self._append(
|
||||
AdjustablePv,
|
||||
AdjustablePiHex,
|
||||
self.pvname + ":SET-POSI-X",
|
||||
pvreadbackname=self.pvname + ":POSI-X",
|
||||
accuracy=0.001,
|
||||
unit="mm",
|
||||
name="x_raw",
|
||||
is_setting=True,
|
||||
)
|
||||
self._append(
|
||||
AdjustablePv,
|
||||
AdjustablePiHex,
|
||||
self.pvname + ":SET-POSI-Y",
|
||||
pvreadbackname=self.pvname + ":POSI-Y",
|
||||
accuracy=0.001,
|
||||
unit="mm",
|
||||
name="y_raw",
|
||||
is_setting=True,
|
||||
)
|
||||
self._append(
|
||||
AdjustablePv,
|
||||
AdjustablePiHex,
|
||||
self.pvname + ":SET-POSI-Z",
|
||||
pvreadbackname=self.pvname + ":POSI-Z",
|
||||
accuracy=0.001,
|
||||
unit="mm",
|
||||
name="z_raw",
|
||||
is_setting=True,
|
||||
)
|
||||
self._append(
|
||||
AdjustablePv,
|
||||
AdjustablePiHex,
|
||||
self.pvname + ":SET-POSI-U",
|
||||
pvreadbackname=self.pvname + ":POSI-U",
|
||||
accuracy=0.001,
|
||||
unit="deg",
|
||||
name="rx_raw",
|
||||
is_setting=True,
|
||||
)
|
||||
self._append(
|
||||
AdjustablePv,
|
||||
AdjustablePiHex,
|
||||
self.pvname + ":SET-POSI-V",
|
||||
pvreadbackname=self.pvname + ":POSI-V",
|
||||
accuracy=0.001,
|
||||
unit="deg",
|
||||
name="ry_raw",
|
||||
is_setting=True,
|
||||
)
|
||||
self._append(
|
||||
AdjustablePv,
|
||||
AdjustablePiHex,
|
||||
self.pvname + ":SET-POSI-W",
|
||||
pvreadbackname=self.pvname + ":POSI-W",
|
||||
accuracy=0.001,
|
||||
unit="deg",
|
||||
name="rz_raw",
|
||||
is_setting=True,
|
||||
)
|
||||
self._append(
|
||||
AdjustablePv,
|
||||
AdjustablePiHex,
|
||||
self.pvname + ":SET-PIVOT-R",
|
||||
pvreadbackname=self.pvname + ":PIVOT-R",
|
||||
accuracy=0.001,
|
||||
unit="mm",
|
||||
name="pivot_x",
|
||||
is_setting=True,
|
||||
)
|
||||
self._append(
|
||||
AdjustablePv,
|
||||
AdjustablePiHex,
|
||||
self.pvname + ":SET-PIVOT-S",
|
||||
pvreadbackname=self.pvname + ":PIVOT-S",
|
||||
accuracy=0.001,
|
||||
unit="mm",
|
||||
name="pivot_y",
|
||||
is_setting=True,
|
||||
)
|
||||
self._append(
|
||||
AdjustablePv,
|
||||
AdjustablePiHex,
|
||||
self.pvname + ":SET-PIVOT-T",
|
||||
pvreadbackname=self.pvname + ":PIVOT-T",
|
||||
accuracy=0.001,
|
||||
unit="mm",
|
||||
name="pivot_z",
|
||||
is_setting=True,
|
||||
)
|
||||
@@ -115,6 +156,8 @@ class HexapodPI(Assembly):
|
||||
reset_current_value_to=False,
|
||||
append_aliases=False,
|
||||
change_simultaneously=False,
|
||||
check_limits=True,
|
||||
unit="mm",
|
||||
name="x",
|
||||
is_setting=False,
|
||||
)
|
||||
@@ -127,7 +170,9 @@ class HexapodPI(Assembly):
|
||||
),
|
||||
reset_current_value_to=False,
|
||||
change_simultaneously=False,
|
||||
check_limits=True,
|
||||
append_aliases=False,
|
||||
unit="mm",
|
||||
name="y",
|
||||
is_setting=False,
|
||||
)
|
||||
@@ -141,6 +186,8 @@ class HexapodPI(Assembly):
|
||||
reset_current_value_to=False,
|
||||
append_aliases=False,
|
||||
change_simultaneously=False,
|
||||
check_limits=True,
|
||||
unit="mm",
|
||||
name="z",
|
||||
is_setting=False,
|
||||
)
|
||||
@@ -364,16 +411,17 @@ class HexapodPI_old:
|
||||
return self.__str__()
|
||||
|
||||
|
||||
class HexapodSymmetrie:
|
||||
class HexapodSymmetrie(Assembly):
|
||||
def __init__(
|
||||
self, pv_master="SARES20-HEXSYM", name="hex_usd", offset=[0, 0, 0, 0, 0, 0]
|
||||
):
|
||||
self.name = name
|
||||
super().__init__(name=name)
|
||||
self.offset = offset
|
||||
self.pvname = pv_master
|
||||
self.coordinate_switch = AdjustablePvEnum(
|
||||
f"{self.pvname}:MOVE#PARAM:CM", name="hex_usd_coordinate_switch"
|
||||
)
|
||||
|
||||
self.pvs_setpos = {
|
||||
"x": PV(f"{self.pvname}:MOVE#PARAM:X.VAL"),
|
||||
"y": PV(f"{self.pvname}:MOVE#PARAM:Y.VAL"),
|
||||
@@ -390,6 +438,14 @@ class HexapodSymmetrie:
|
||||
"ry": PV(f"{self.pvname}:POSMACH:RY"),
|
||||
"rz": PV(f"{self.pvname}:POSMACH:RZ"),
|
||||
}
|
||||
|
||||
self._append(DetectorPvData, f"{self.pvname}:POSMACH:X", name="x")
|
||||
self._append(DetectorPvData, f"{self.pvname}:POSMACH:Y", name="y")
|
||||
self._append(DetectorPvData, f"{self.pvname}:POSMACH:Z", name="z")
|
||||
self._append(DetectorPvData, f"{self.pvname}:POSMACH:RX", name="rx")
|
||||
self._append(DetectorPvData, f"{self.pvname}:POSMACH:RY", name="ry")
|
||||
self._append(DetectorPvData, f"{self.pvname}:POSMACH:RZ", name="rz")
|
||||
|
||||
self._ctrl_pv = PV(f"{self.pvname}:STATE#PANEL:SET.VAL")
|
||||
|
||||
def set_coordinates(self, x, y, z, rx, ry, rz, relative_to_eco_offset=True):
|
||||
|
||||
+167
-15
@@ -5,51 +5,74 @@ import numpy as np
|
||||
from epics import PV
|
||||
|
||||
from eco.aliases import Alias
|
||||
from eco.elements.adjustable import tweak_option, spec_convenience, value_property
|
||||
from eco.elements.adjustable import (
|
||||
AdjustableMemory,
|
||||
tweak_option,
|
||||
spec_convenience,
|
||||
value_property,
|
||||
)
|
||||
from . import get_from_archive
|
||||
from eco.devices_general.utilities import Changer
|
||||
from ..elements.assembly import Assembly
|
||||
|
||||
|
||||
|
||||
# Work in progress! TODO
|
||||
@spec_convenience
|
||||
@get_from_archive
|
||||
@tweak_option
|
||||
@value_property
|
||||
class AdjustablePv:
|
||||
class AdjustableAtomicPv:
|
||||
def __init__(
|
||||
self,
|
||||
pvsetname,
|
||||
pvreadbackname=None,
|
||||
accuracy=None,
|
||||
name=None,
|
||||
elog=None,
|
||||
element_count=None,
|
||||
):
|
||||
|
||||
# alias_fields={"setpv": pvsetname, "readback": pvreadbackname},
|
||||
# ):
|
||||
self.Id = pvsetname
|
||||
self.pvname = pvsetname
|
||||
self.name = name
|
||||
# for an, af in alias_fields.items():
|
||||
# self.alias.append(
|
||||
# Alias(an, channel=".".join([pvname, af]), channeltype="CA")
|
||||
# )
|
||||
|
||||
self._pv = PV(self.Id, connection_timeout=0.05, count=element_count)
|
||||
self._pv = PV(self.pvname, connection_timeout=0.05, count=element_count)
|
||||
self._currentChange = None
|
||||
self.accuracy = accuracy
|
||||
|
||||
if pvreadbackname is None:
|
||||
self._pvreadback = PV(self.Id, count=element_count, connection_timeout=0.05)
|
||||
pvreadbackname = self.Id
|
||||
self.pvname = self.Id
|
||||
self._pvreadback = PV(self.pvname, count=element_count, connection_timeout=0.05)
|
||||
pvreadbackname = self.pvname
|
||||
self.pvname = self.pvname
|
||||
else:
|
||||
self._pvreadback = PV(
|
||||
pvreadbackname, count=element_count, connection_timeout=0.05
|
||||
)
|
||||
self.pvname = pvreadbackname
|
||||
|
||||
if pvlowlimname:
|
||||
self._pvlowlim = PV(
|
||||
pvlowlimname, count=element_count, connection_timeout=0.05
|
||||
)
|
||||
else:
|
||||
self._pvlowlim = None
|
||||
if pvhighlimname:
|
||||
self._pvhighlim = PV(
|
||||
pvhighlimname, count=element_count, connection_timeout=0.05
|
||||
)
|
||||
else:
|
||||
self._pvhighlim = None
|
||||
self.alias = Alias(name, channel=pvreadbackname, channeltype="CA")
|
||||
|
||||
def _wait_for_initialisation(self):
|
||||
self._pv.wait_for_connection()
|
||||
if hasattr(self, "_pv_readback") and self._pv_readback:
|
||||
self._pv_readback.wait_for_connection()
|
||||
if hasattr(self, "_pv_lowliself.accuracy = accuracym") and self._pv_lowlim:
|
||||
self._pv_lowlim.wait_for_connection()
|
||||
if hasattr(self, "_pv_highlim") and self._pv_highlim:
|
||||
self._pv_highlim.wait_for_connection()
|
||||
|
||||
def get_current_value(self, readback=True):
|
||||
if readback:
|
||||
currval = self._pvreadback.get()
|
||||
@@ -73,6 +96,130 @@ class AdjustablePv:
|
||||
return change_done
|
||||
|
||||
def change(self, value):
|
||||
if self._pvlowlim:
|
||||
if value < self._pvlowlim.get():
|
||||
raise Exception(
|
||||
f"Target value of {self.name} is smaller than limit value!"
|
||||
)
|
||||
if self._pvhighlim:
|
||||
if self._pvhighlim.get() < value:
|
||||
raise Exception(
|
||||
f"Target value of {self.name} is higher than limit value!"
|
||||
)
|
||||
|
||||
self._pv.put(value)
|
||||
time.sleep(0.1)
|
||||
while self.get_change_done() == 0:
|
||||
time.sleep(0.1)
|
||||
|
||||
def set_target_value(self, value, hold=False):
|
||||
"""Adjustable convention"""
|
||||
|
||||
changer = lambda value: self.change(value)
|
||||
return Changer(
|
||||
target=value, parent=self, changer=changer, hold=hold, stopper=None
|
||||
)
|
||||
|
||||
|
||||
@spec_convenience
|
||||
@get_from_archive
|
||||
@tweak_option
|
||||
@value_property
|
||||
class AdjustablePv:
|
||||
def __init__(
|
||||
self,
|
||||
pvsetname,
|
||||
pvreadbackname=None,
|
||||
pvlowlimname=None,
|
||||
pvhighlimname=None,
|
||||
accuracy=None,
|
||||
name=None,
|
||||
elog=None,
|
||||
element_count=None,
|
||||
unit=None,
|
||||
):
|
||||
# alias_fields={"setpv": pvsetname, "readback": pvreadbackname},
|
||||
# ):
|
||||
self.Id = pvsetname
|
||||
self.name = name
|
||||
# for an, af in alias_fields.items():
|
||||
# self.alias.append(
|
||||
# Alias(an, channel=".".join([pvname, af]), channeltype="CA")
|
||||
# )
|
||||
|
||||
self._pv = PV(self.Id, connection_timeout=0.05, count=element_count)
|
||||
self._currentChange = None
|
||||
self.accuracy = accuracy
|
||||
if unit:
|
||||
self.unit = AdjustableMemory(unit, name="unit")
|
||||
|
||||
if pvreadbackname is None:
|
||||
self._pvreadback = PV(self.Id, count=element_count, connection_timeout=0.05)
|
||||
pvreadbackname = self.Id
|
||||
self.pvname = self.Id
|
||||
else:
|
||||
self._pvreadback = PV(
|
||||
pvreadbackname, count=element_count, connection_timeout=0.05
|
||||
)
|
||||
self.pvname = pvreadbackname
|
||||
|
||||
if pvlowlimname:
|
||||
self._pvlowlim = PV(
|
||||
pvlowlimname, count=element_count, connection_timeout=0.05
|
||||
)
|
||||
else:
|
||||
self._pvlowlim = None
|
||||
if pvhighlimname:
|
||||
self._pvhighlim = PV(
|
||||
pvhighlimname, count=element_count, connection_timeout=0.05
|
||||
)
|
||||
else:
|
||||
self._pvhighlim = None
|
||||
self.alias = Alias(name, channel=pvreadbackname, channeltype="CA")
|
||||
|
||||
def _wait_for_initialisation(self):
|
||||
self._pv.wait_for_connection()
|
||||
if hasattr(self, "_pv_readback") and self._pv_readback:
|
||||
self._pv_readback.wait_for_connection()
|
||||
if hasattr(self, "_pv_lowlim") and self._pv_lowlim:
|
||||
self._pv_lowlim.wait_for_connection()
|
||||
if hasattr(self, "_pv_highlim") and self._pv_highlim:
|
||||
self._pv_highlim.wait_for_connection()
|
||||
|
||||
def get_current_value(self, readback=True):
|
||||
if readback:
|
||||
currval = self._pvreadback.get()
|
||||
if not readback:
|
||||
currval = self._pv.get()
|
||||
return currval
|
||||
|
||||
def get_change_done(self):
|
||||
"""Adjustable convention"""
|
||||
""" 0: moving 1: move done"""
|
||||
change_done = 1
|
||||
if self.accuracy is not None:
|
||||
if (
|
||||
np.abs(
|
||||
self.get_current_value(readback=False)
|
||||
- self.get_current_value(readback=True)
|
||||
)
|
||||
> self.accuracy
|
||||
):
|
||||
change_done = 0
|
||||
return change_done
|
||||
|
||||
def change(self, value):
|
||||
if self._pvlowlim:
|
||||
if value < self._pvlowlim.get():
|
||||
raise Exception(
|
||||
f"Target value of {self.name} is smaller than limit value!"
|
||||
)
|
||||
if self._pvhighlim:
|
||||
if self._pvhighlim.get() < value:
|
||||
raise Exception(
|
||||
f"Target value of {self.name} is higher than limit value!"
|
||||
)
|
||||
|
||||
self._pv.put(value)
|
||||
time.sleep(0.1)
|
||||
while self.get_change_done() == 0:
|
||||
@@ -122,8 +269,8 @@ class AdjustablePvEnum:
|
||||
if pvname_set:
|
||||
self._pv_set = PV(pvname_set, connection_timeout=0.05)
|
||||
tstrs = self._pv_set.enum_strs
|
||||
if not (tstrs == self.enum_strs):
|
||||
raise Exception("pv enum setter strings do not match the values!")
|
||||
if not all([tstr in self.enum_strs for tstr in tstrs]):
|
||||
raise Exception("pv enum setter strings are not all a readback option!")
|
||||
|
||||
else:
|
||||
self._pv_set = None
|
||||
@@ -137,6 +284,11 @@ class AdjustablePvEnum:
|
||||
)
|
||||
self.alias = Alias(name, channel=self.Id, channeltype="CA")
|
||||
|
||||
def _wait_for_initialisation(self):
|
||||
self._pv.wait_for_connection()
|
||||
if hasattr(self, "_pv_set") and self._pv_set:
|
||||
self._pv_set.wait_for_connection()
|
||||
|
||||
def validate(self, value):
|
||||
if type(value) is str:
|
||||
return self.PvEnum.__members__[value]
|
||||
|
||||
+23
-14
@@ -6,6 +6,7 @@ from ..epics.detector import DetectorPvData, DetectorPvEnum
|
||||
from ..aliases import Alias
|
||||
from datetime import datetime
|
||||
from time import sleep
|
||||
import numpy as np
|
||||
from ..detector.detectors_psi import DetectorBsStream
|
||||
|
||||
|
||||
@@ -67,7 +68,8 @@ class SwissFel(Assembly):
|
||||
# SAR-EVPO-010:DEACTIVATE "FALSE"
|
||||
self._append(
|
||||
AdjustablePvEnum,
|
||||
"SAROP-ARAMIS:BEAMLINE_SP",
|
||||
"SAROP-ARAMIS:BEAMLINE",
|
||||
pvname_set = "SAROP-ARAMIS:BEAMLINE_SP",
|
||||
name="aramis_beamline_switch",
|
||||
is_display=True,
|
||||
is_setting=True,
|
||||
@@ -248,6 +250,7 @@ class MessageBoard(Assembly):
|
||||
self._append(Message, "SF-OP:ESF-MSG", name="furka_message", is_setting=True)
|
||||
|
||||
|
||||
@spec_convenience
|
||||
class Message:
|
||||
def __init__(self, pvstem, name=None):
|
||||
self.pvname = pvstem
|
||||
@@ -258,36 +261,39 @@ class Message:
|
||||
AdjustablePvString(self.pvname + f":OP-DATE{n + 1}") for n in range(5)
|
||||
]
|
||||
self.alias = Alias(name, channel=self.pvname + ":OP-MSG1", channeltype="CA")
|
||||
self.pv_tmp = AdjustablePvString(self.pvname + ":OP-MSG-tmp")
|
||||
|
||||
def set_new_message(self, message):
|
||||
for i in range(3, -1, -1):
|
||||
self.pvs_msg[i + 1].set_target_value(
|
||||
self.pvs_msg[i].get_current_value()
|
||||
).wait()
|
||||
self.pvs_date[i + 1].set_target_value(
|
||||
self.pvs_date[i].get_current_value()
|
||||
).wait()
|
||||
timestr = datetime.now().strftime("%a %d-%b-%Y %H:%M:%S")
|
||||
self.pvs_msg[0].set_target_value(message).wait()
|
||||
self.pvs_date[0].set_target_value(timestr).wait()
|
||||
# for i in range(3, -1, -1):
|
||||
# self.pvs_msg[i + 1].set_target_value(
|
||||
# self.pvs_msg[i].get_current_value()
|
||||
# ).wait()
|
||||
# self.pvs_date[i + 1].set_target_value(
|
||||
# self.pvs_date[i].get_current_value()
|
||||
# ).wait()
|
||||
self.pv_tmp.set_target_value(message).wait()
|
||||
# timestr = datetime.now().strftime("%a %d-%b-%Y %H:%M:%S")
|
||||
# self.pvs_msg[0].set_target_value(message).wait()
|
||||
# self.pvs_date[0].set_target_value(timestr).wait()
|
||||
|
||||
def get_current_value(self):
|
||||
return self.pvs_msg[0].get_current_value()
|
||||
|
||||
def set_target_value(self, value):
|
||||
def set_target_value(self, value, hold=False):
|
||||
return Changer(
|
||||
target=value,
|
||||
parent=self,
|
||||
changer=self.set_new_message,
|
||||
hold=True,
|
||||
hold=hold,
|
||||
stopper=None,
|
||||
)
|
||||
|
||||
|
||||
@spec_convenience
|
||||
class UndulatorK(Assembly):
|
||||
def __init__(self, name=None):
|
||||
def __init__(self, maximum_energy_change_keV=1.0, name=None):
|
||||
super().__init__(name=name)
|
||||
self.maximum_energy_change_keV = maximum_energy_change_keV
|
||||
self._append(
|
||||
DetectorPvData,
|
||||
"SARUN:FELPHOTENE",
|
||||
@@ -332,6 +338,9 @@ class UndulatorK(Assembly):
|
||||
return self.aramis_undulator_photon_energy.get_current_value()
|
||||
|
||||
def change_energy(self, energy):
|
||||
if np.abs(energy - self.get_current_value()) > self.maximum_energy_change_keV:
|
||||
raise Exception("Likely too large undulator energy change requested!!!")
|
||||
|
||||
vals = self.calc_new_Ksets(energy)
|
||||
for kset, val in zip(self.ksets, vals):
|
||||
kset.set_target_value(val)
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
from eco.elements.assembly import Assembly
|
||||
from eco.loptics.position_monitors import CameraPositionMonitor
|
||||
from ..aliases import Alias
|
||||
from ..devices_general.motors import MotorRecord, SmaractStreamdevice
|
||||
from ..devices_general.smaract import SmarActRecord
|
||||
@@ -364,3 +366,5 @@ class Laser_Exp:
|
||||
|
||||
def __repr__(self):
|
||||
return self.get_adjustable_positions_str()
|
||||
|
||||
|
||||
|
||||
+354
-20
@@ -1,11 +1,17 @@
|
||||
from eco.loptics.position_monitors import CameraPositionMonitor
|
||||
from ..elements.assembly import Assembly
|
||||
from ..devices_general.motors import SmaractStreamdevice, MotorRecord
|
||||
from functools import partial
|
||||
from ..devices_general.motors import SmaractStreamdevice, MotorRecord, SmaractRecord
|
||||
from ..elements.adjustable import AdjustableMemory, AdjustableVirtual, AdjustableFS
|
||||
from ..timing.lasertiming_edwin import XltEpics
|
||||
from ..epics.adjustable import AdjustablePv, AdjustablePvEnum
|
||||
from ..epics.detector import DetectorPvData
|
||||
from ..devices_general.detectors import DetectorVirtual
|
||||
from ..timing.lasertiming_edwin import XltEpics, LaserRateControl
|
||||
import colorama
|
||||
import datetime
|
||||
from pint import UnitRegistry
|
||||
import numpy as np
|
||||
import time
|
||||
|
||||
# from time import sleep
|
||||
|
||||
@@ -15,12 +21,263 @@ ureg = UnitRegistry()
|
||||
class IncouplingCleanBernina(Assembly):
|
||||
def __init__(self, name=None):
|
||||
super().__init__(name=name)
|
||||
self._append(SmaractStreamdevice, "SARES23-ESB13", name="tilt")
|
||||
self._append(SmaractStreamdevice, "SARES23-ESB14", name="rotation")
|
||||
self._append(SmaractStreamdevice, "SARES23-LIC15", name="transl_vertical")
|
||||
self._append(SmaractRecord, "SARES23-LIC:MOT_17", name="tilt")
|
||||
self._append(SmaractRecord, "SARES23-LIC:MOT_18", name="rotation")
|
||||
self._append(SmaractRecord, "SARES23-LIC:MOT_16", name="transl_vertical")
|
||||
self._append(MotorRecord, "SARES20-MF2:MOT_5", name="transl_horizontal")
|
||||
|
||||
|
||||
class Spectrometer(Assembly):
|
||||
def __init__(self, pvname, name=None):
|
||||
super().__init__(name=name)
|
||||
self.pvname = pvname
|
||||
self._append(
|
||||
AdjustablePvEnum,
|
||||
pvname + ":TRIGGER",
|
||||
name="trigger_mode",
|
||||
is_setting=True,
|
||||
)
|
||||
self._append(AdjustablePvEnum, pvname + ":INIT", name="state", is_setting=True)
|
||||
self._append(
|
||||
AdjustablePv,
|
||||
pvname + ":EXPOSURE",
|
||||
name="exposure_time",
|
||||
is_setting=True,
|
||||
)
|
||||
self._append(DetectorPvData, pvname + ":CENTRE", name="center")
|
||||
self._append(DetectorPvData, pvname + ":FWHM", name="fwhm")
|
||||
self._append(DetectorPvData, pvname + ":AMPLITUDE", name="amplitude")
|
||||
self._append(DetectorPvData, pvname + ":INTEGRAL", name="integral")
|
||||
self._append(DetectorPvData, pvname + ":BASER_HEIGHT", name="base_value")
|
||||
self._append(
|
||||
AdjustablePv, pvname + ":XVAL1", name="spectrum_min", is_setting=True
|
||||
)
|
||||
self._append(
|
||||
AdjustablePv, pvname + ":XVAL2", name="spectrum_max", is_setting=True
|
||||
)
|
||||
# SLAAR02-LSPC-OSC:SERIALNR
|
||||
|
||||
|
||||
flag_names_filter_wheel = [
|
||||
"error",
|
||||
"proc_tongle",
|
||||
"connected",
|
||||
"moving",
|
||||
"homed",
|
||||
"remote_operation",
|
||||
]
|
||||
|
||||
|
||||
class FilterWheelFlags(Assembly):
|
||||
def __init__(self, flags, name="flags"):
|
||||
super().__init__(name=name)
|
||||
self._flags = flags
|
||||
for flag_name in flag_names_filter_wheel:
|
||||
self._append(
|
||||
DetectorVirtual,
|
||||
[self._flags],
|
||||
partial(self._get_flag_name_value, flag_name=flag_name),
|
||||
name=flag_name,
|
||||
is_status=True,
|
||||
is_display=True,
|
||||
)
|
||||
|
||||
def _get_flag_name_value(self, value, flag_name=None):
|
||||
index = flag_names_filter_wheel.index(flag_name)
|
||||
return int("{0:015b}".format(int(value))[-1 * (index + 1)]) == 1
|
||||
|
||||
|
||||
class FilterWheel(Assembly):
|
||||
def __init__(self, pvname, name=None):
|
||||
super().__init__(name=name)
|
||||
self.pvname = pvname
|
||||
self._append(AdjustablePvEnum, f"{pvname}.VAL", name="_val", is_setting=True)
|
||||
self._append(AdjustablePvEnum, f"{pvname}.RBV", name="_rb", is_setting=True)
|
||||
self._append(AdjustablePv, f"{pvname}.CMD", name="_cmd", is_setting=False)
|
||||
self.set_remote_operation()
|
||||
self._append(
|
||||
DetectorPvData,
|
||||
self.pvname + ".STA",
|
||||
name="_flags",
|
||||
is_setting=False,
|
||||
is_display=False,
|
||||
)
|
||||
self._append(
|
||||
FilterWheelFlags,
|
||||
self._flags,
|
||||
name="flags",
|
||||
is_display="recursive",
|
||||
is_setting=False,
|
||||
is_status=True,
|
||||
)
|
||||
|
||||
def set_remote_operation(self):
|
||||
self._val(7)
|
||||
|
||||
def set_manual_operation(self):
|
||||
self._val(8)
|
||||
|
||||
def home(self):
|
||||
self.set_remote_operation()
|
||||
self._val(6)
|
||||
|
||||
def is_moving(self):
|
||||
pass
|
||||
|
||||
|
||||
class FilterWheelAttenuator(Assembly):
|
||||
def __init__(self, pvname, name=None):
|
||||
super().__init__(name=name)
|
||||
self._append(FilterWheel, pvname=pvname + "IFW_A", name="wheel_1")
|
||||
self._append(FilterWheel, pvname=pvname + "IFW_B", name="wheel_2")
|
||||
|
||||
self.targets_1 = {
|
||||
"t": 10 ** -np.array([0.2, 0.3, 0.5, 0.6, 1.0]),
|
||||
"pos": np.array([1, 2, 3, 4, 5]),
|
||||
}
|
||||
self.targets_2 = {
|
||||
"t": 10 ** -np.array([0.2, 0.3, 0.4, 0.5, 0.6]),
|
||||
"pos": np.array([1, 2, 3, 4, 5]),
|
||||
}
|
||||
|
||||
self._calc_transmission()
|
||||
|
||||
def _calc_transmission(self):
|
||||
t1 = self.targets_1["t"]
|
||||
t2 = self.targets_2["t"]
|
||||
t_comb = (
|
||||
(np.expand_dims(t1, axis=0)).T * (np.expand_dims(t2, axis=0))
|
||||
).flatten()
|
||||
pos_comb = np.array(
|
||||
[[p1, p2] for p1 in self.targets_1["pos"] for p2 in self.targets_2["pos"]]
|
||||
)
|
||||
self.transmissions = {"t": t_comb, "pos": pos_comb}
|
||||
|
||||
def home(self):
|
||||
self.wheel_1.home()
|
||||
self.wheel_2.home()
|
||||
|
||||
|
||||
class StageLxtDelay(Assembly):
|
||||
def __init__(self, fine_delay_adj, coarse_delay_adj, direction=1, name=None):
|
||||
super().__init__(name=name)
|
||||
self._append(fine_delay_adj, name="_fine_delay_adj", is_setting=True)
|
||||
self._append(coarse_delay_adj, name="_coarse_delay_adj", is_setting=True)
|
||||
self._append(AdjustableMemory, direction, name="_direction", is_setting=True)
|
||||
self._append(
|
||||
AdjustableFS,
|
||||
f"/photonics/home/gac-bernina/eco/configuration/{name}_combined_delay_phase_shifter_threshold",
|
||||
name="switch_threshold",
|
||||
default_value=50e-12,
|
||||
is_setting=True,
|
||||
)
|
||||
self._append(
|
||||
AdjustableFS,
|
||||
f"/photonics/home/gac-bernina/eco/configuration/{name}_conbined_fine_adj_offset",
|
||||
name="offset_fine_adj",
|
||||
default_value=0.0,
|
||||
is_setting=True,
|
||||
)
|
||||
self._append(
|
||||
AdjustableFS,
|
||||
f"/photonics/home/gac-bernina/eco/configuration/{name}_combined_coarse_adj_offset",
|
||||
name="offset_coarse_adj",
|
||||
default_value=0.0,
|
||||
is_setting=True,
|
||||
)
|
||||
|
||||
self._append(
|
||||
AdjustableVirtual,
|
||||
[self._fine_delay_adj, self._coarse_delay_adj],
|
||||
self._get_comb_delay,
|
||||
self._set_comb_delay,
|
||||
name="delay",
|
||||
unit="s",
|
||||
)
|
||||
|
||||
def _get_comb_delay(self, pd, ps):
|
||||
ps_rel = ps - self.offset_coarse_adj()
|
||||
pd_rel = pd - self.offset_fine_adj()
|
||||
return (ps_rel + pd_rel) * self._direction.get_current_value()
|
||||
|
||||
def _set_comb_delay(self, delay):
|
||||
if delay < abs(self.switch_threshold.get_current_value()):
|
||||
### check to prevent slow phaseshifter corrections <50fs
|
||||
if (
|
||||
np.abs(
|
||||
self._coarse_delay_adj.get_current_value()
|
||||
- self.offset_coarse_adj.get_current_value()
|
||||
)
|
||||
> 50e-15
|
||||
):
|
||||
ps_pos = self.offset_coarse_adj.get_current_value()
|
||||
else:
|
||||
ps_pos = None
|
||||
pd_pos = self.offset_fine_adj.get_current_value() + delay
|
||||
else:
|
||||
ps_pos = self.offset_coarse_adj.get_current_value() + delay
|
||||
pd_pos = self.offset_fine_adj.get_current_value()
|
||||
|
||||
if pd_pos is None:
|
||||
outfine = None
|
||||
else:
|
||||
outfine = self._direction.get_current_value() * pd_pos,
|
||||
if ps_pos is None:
|
||||
outcoarse = None
|
||||
else:
|
||||
outcoarse = self._direction.get_current_value() * ps_pos,
|
||||
return (outfine,outcoarse)
|
||||
|
||||
|
||||
class Stage_LXT_Delay(AdjustableVirtual):
|
||||
def __init__(self, fine_delay_adj, coarse_delay_adj, direction=1, name=None):
|
||||
self._fine_delay_adj = fine_delay_adj
|
||||
self._coarse_delay_adj = coarse_delay_adj
|
||||
self._direction = direction
|
||||
self.switch_threshold = AdjustableFS(
|
||||
f"/photonics/home/gac-bernina/eco/configuration/{name}_combined_delay_phase_shifter_threshold",
|
||||
name="switch_threshold",
|
||||
default_value=50e-12,
|
||||
)
|
||||
self.offset_fine_adj = AdjustableFS(
|
||||
f"/photonics/home/gac-bernina/eco/configuration/{name}_conbined_fine_adj_offset",
|
||||
name="offset_fine_adj",
|
||||
default_value=0.0,
|
||||
)
|
||||
self.offset_coarse_adj = AdjustableFS(
|
||||
f"/photonics/home/gac-bernina/eco/configuration/{name}_combined_coarse_adj_offset",
|
||||
name="offset_coarse_adj",
|
||||
default_value=0.0,
|
||||
)
|
||||
|
||||
AdjustableVirtual.__init__(
|
||||
self,
|
||||
[self._fine_delay_adj, self._coarse_delay_adj],
|
||||
self._get_comb_delay,
|
||||
self._set_comb_delay,
|
||||
name=name,
|
||||
unit="s",
|
||||
)
|
||||
|
||||
def _get_comb_delay(self, pd, ps):
|
||||
ps_rel = ps - self.offset_coarse_adj()
|
||||
pd_rel = pd - self.offset_fine_adj()
|
||||
return (ps_rel + pd_rel) * self._direction
|
||||
|
||||
def _set_comb_delay(self, delay):
|
||||
if delay < abs(self.switch_threshold()):
|
||||
### check to prevent slow phaseshifter corrections <50fs
|
||||
if np.abs(self._coarse_delay_adj() - self.offset_coarse_adj()) > 50e-15:
|
||||
ps_pos = self.offset_coarse_adj()
|
||||
else:
|
||||
ps_pos = None
|
||||
pd_pos = self.offset_fine_adj() + delay
|
||||
else:
|
||||
ps_pos = self.offset_coarse_adj() + delay
|
||||
pd_pos = self.offset_fine_adj()
|
||||
return self._direction * pd_pos, self._direction * ps_pos
|
||||
|
||||
|
||||
class LaserBernina(Assembly):
|
||||
def __init__(self, pvname, name=None):
|
||||
super().__init__(name=name)
|
||||
@@ -44,15 +301,31 @@ class LaserBernina(Assembly):
|
||||
self._append(
|
||||
MotorRecord, self.pvname + "-M533:MOT", name="wp_pol", is_setting=True
|
||||
)
|
||||
|
||||
self._append(
|
||||
MotorRecord, self.pvname + "-M534:MOT", name="wp_att", is_setting=True
|
||||
)
|
||||
|
||||
self._append(
|
||||
AdjustableFS,
|
||||
"/photonics/home/gac-bernina/eco/configuration/wp_att_calibration",
|
||||
name="wp_att_calibration",
|
||||
is_display=False,
|
||||
)
|
||||
tmptime = time.time()
|
||||
while (time.time() - tmptime) < 10:
|
||||
try:
|
||||
self._append(
|
||||
Spectrometer,
|
||||
"SLAAR02-LSPC-OSC",
|
||||
name="oscillator_spectrum",
|
||||
is_setting=False,
|
||||
is_display=True,
|
||||
)
|
||||
print("SUCCESS: oscillator spectrometer configured!")
|
||||
break
|
||||
except:
|
||||
pass
|
||||
|
||||
def uJ2wp(uJ):
|
||||
direction = 1
|
||||
@@ -63,36 +336,55 @@ class LaserBernina(Assembly):
|
||||
)
|
||||
|
||||
def wp2uJ(wp):
|
||||
return np.interp(wp, *np.asarray(self.wp_att_calibration()).T)
|
||||
try:
|
||||
return np.interp(wp, *np.asarray(self.wp_att_calibration()).T)
|
||||
except:
|
||||
return np.nan
|
||||
|
||||
self._append(
|
||||
AdjustableVirtual, [self.wp_att], wp2uJ, uJ2wp, name="pulse_energy_pump"
|
||||
)
|
||||
|
||||
# self._append(
|
||||
# MotorRecord,
|
||||
# self.pvname + "-M522:MOTOR_1",
|
||||
# name="delaystage_pump",
|
||||
# is_setting=True,
|
||||
# )wp_att
|
||||
# self._append(
|
||||
# DelayTime, self.delaystage_pump, name="delay_pump", is_setting=True
|
||||
# )
|
||||
self._append(
|
||||
LaserRateControl, name="rate", is_setting=True, is_display="recursive"
|
||||
)
|
||||
self._append(XltEpics, name="xlt", is_setting=True, is_display="recursive")
|
||||
# Upstairs, Laser 1 LAM
|
||||
# self._append(
|
||||
# MotorRecord,
|
||||
# "SLAAR21-LMOT-M521:MOTOR_1",
|
||||
# name="delaystage_pump",
|
||||
# is_setting=True,
|
||||
# )
|
||||
self._append(
|
||||
MotorRecord,
|
||||
self.pvname + "-M522:MOTOR_1",
|
||||
"SLAAR21-LMOT-M521:MOTOR_1",
|
||||
name="delaystage_pump",
|
||||
is_setting=True,
|
||||
)
|
||||
self._append(
|
||||
DelayTime, self.delaystage_pump, name="delay_pump", is_setting=True
|
||||
)
|
||||
self._append(XltEpics, name="xlt", is_setting=True, is_display="recursive")
|
||||
# Upstairs, Laser 1 LAM
|
||||
self._append(
|
||||
MotorRecord,
|
||||
"SLAAR21-LMOT-M521:MOTOR_1",
|
||||
name="delaystage_eos",
|
||||
is_setting=True,
|
||||
)
|
||||
self._append(
|
||||
DelayTime,
|
||||
self.delaystage_eos,
|
||||
name="delay_eos",
|
||||
self.delaystage_pump,
|
||||
name="delay_pump",
|
||||
is_setting=True,
|
||||
)
|
||||
# self._append(
|
||||
# Stage_LXT_Delay,
|
||||
# self.delay_glob,
|
||||
# self.xlt,
|
||||
# direction=1,
|
||||
# name="delay",
|
||||
# )
|
||||
# self._append(
|
||||
# SmaractStreamdevice,
|
||||
# pvname="SARES23-ESB18",
|
||||
# name="delaystage_thz",
|
||||
@@ -181,3 +473,45 @@ class DelayCompensation(AdjustableVirtual):
|
||||
s += f"{(self.get_current_value()*ureg.second).to_compact():P~6.3f}"
|
||||
s += f"{colorama.Style.RESET_ALL}"
|
||||
return s
|
||||
|
||||
|
||||
class PositionMonitors(Assembly):
|
||||
def __init__(self, name=None):
|
||||
super().__init__(name=name)
|
||||
self._append(
|
||||
CameraPositionMonitor,
|
||||
"SLAAR21-LCAM-CS844",
|
||||
name="table1_angle",
|
||||
is_display="recursive",
|
||||
is_status=True,
|
||||
)
|
||||
self._append(
|
||||
CameraPositionMonitor,
|
||||
"SLAAR21-LCAM-CS843",
|
||||
name="table1_position",
|
||||
is_display="recursive",
|
||||
is_status=True,
|
||||
)
|
||||
self._append(
|
||||
CameraPositionMonitor,
|
||||
"SLAAR21-LCAM-CS842",
|
||||
name="table2_angle",
|
||||
is_display="recursive",
|
||||
is_status=True,
|
||||
)
|
||||
self._append(
|
||||
CameraPositionMonitor,
|
||||
"SLAAR21-LCAM-CS841",
|
||||
name="table2_position",
|
||||
is_display="recursive",
|
||||
is_status=True,
|
||||
)
|
||||
# self._append(
|
||||
# CameraPositionMonitor,
|
||||
# "SLAAR21-LCAM-C511",
|
||||
# name="opaout_focus",
|
||||
# is_display="recursive",
|
||||
# is_status=True,
|
||||
# )
|
||||
# self._append(CameraPositionMonitor, 'SLAAR21-LCAM-C541', name='cam541')
|
||||
# self._append(CameraPositionMonitor, 'SLAAR21-LCAM-C542', name='cam542')
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
from eco import Assembly
|
||||
from eco.epics.adjustable import AdjustablePv, AdjustablePvEnum
|
||||
from eco.epics.detector import DetectorPvData, DetectorPvDataStream
|
||||
|
||||
|
||||
class LabMaxEnergyMonitor(Assembly):
|
||||
def __init__(self,pvname, name=None):
|
||||
super().__init__(name=name)
|
||||
self.pvname = pvname
|
||||
self._append(DetectorPvDataStream, pvname+':READ_SC',name='pulse_energy')
|
||||
self._append(DetectorPvDataStream, pvname+':ENERGY_AVE100',name='pulse_energy_avg100')
|
||||
self._append(AdjustablePvEnum, pvname+':READ.SCAN',name='read_mode')
|
||||
self._append(AdjustablePv, pvname+':SET_FSD',name='output_signal_voltage', is_setting=True)
|
||||
self._append(AdjustablePvEnum, pvname+':WL_CORR_MODE',name='correct_wavelenght', is_setting=True)
|
||||
self._append(AdjustablePvEnum, pvname+':TRIG_SOURCE',name='trigger_source', is_setting=True)
|
||||
self._append(AdjustablePv, pvname+':SET_TRIG_LEVEL',name='output_signal_voltage', is_setting=True)
|
||||
self._append(DetectorPvData, pvname+':GET_RANGE_SC',name='range', is_setting=True)
|
||||
self._append(AdjustablePv, pvname+':SELECT_RANGE',name='set_range', is_setting=True)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
from eco.epics.detector import DetectorPvDataStream
|
||||
from eco.epics.adjustable import AdjustablePv
|
||||
from eco import Assembly
|
||||
|
||||
class CameraPositionMonitor(Assembly):
|
||||
def __init__(self,pvname,name=None):
|
||||
super().__init__(name=name)
|
||||
self.pvname = pvname
|
||||
self._append(DetectorPvDataStream,pvname+':FIT-XPOS',name='xpos_raw')
|
||||
self._append(DetectorPvDataStream,pvname+':FIT-YPOS',name='ypos_raw')
|
||||
self._append(DetectorPvDataStream,pvname+':FIT-XWID',name='xwidth_raw')
|
||||
self._append(DetectorPvDataStream,pvname+':FIT-YWID',name='ywidth_raw')
|
||||
self._append(DetectorPvDataStream,pvname+':FIT-XCOM',name='xcom_raw')
|
||||
self._append(DetectorPvDataStream,pvname+':FIT-YCOM',name='ycom_raw')
|
||||
self._append(DetectorPvDataStream,pvname+':FIT-XPOS_EGU',name='xpos')
|
||||
self._append(DetectorPvDataStream,pvname+':FIT-YPOS_EGU',name='ypos')
|
||||
self._append(DetectorPvDataStream,pvname+':FIT-XWID_EGU',name='xwidth')
|
||||
self._append(DetectorPvDataStream,pvname+':FIT-YWID_EGU',name='ywidth')
|
||||
self._append(AdjustablePv,pvname+':XCALIB',name='xcalib_gradient', is_setting=True)
|
||||
self._append(AdjustablePv,pvname+':YCALIB',name='ycalib_gradient', is_setting=True)
|
||||
self._append(AdjustablePv,pvname+':XCALIB-OFFS',name='xcalib_offset', is_setting=True)
|
||||
self._append(AdjustablePv,pvname+':YCALIB-OFFS',name='ycalib_offset', is_setting=True)
|
||||
|
||||
|
||||
|
||||
@@ -11,8 +11,6 @@ class MicroscopeMotorRecord(Assembly):
|
||||
def __init__(
|
||||
self,
|
||||
pvname_camera=None,
|
||||
camserver_alias=None,
|
||||
# camserver_alias=None,
|
||||
pvname_zoom=None,
|
||||
pvname_focus=None,
|
||||
name=None,
|
||||
@@ -22,7 +20,7 @@ class MicroscopeMotorRecord(Assembly):
|
||||
self._append(
|
||||
CameraBasler,
|
||||
pvname_camera,
|
||||
camserver_alias=camserver_alias,
|
||||
camserver_alias=name,
|
||||
name="camera",
|
||||
is_setting=True,
|
||||
is_display="recursive",
|
||||
@@ -110,3 +108,40 @@ class OptoSigmaZoom(Assembly):
|
||||
|
||||
def set_target_value(self, value, **kwargs):
|
||||
return self.zoom.set_target_value(value, **kwargs)
|
||||
|
||||
|
||||
@spec_convenience
|
||||
class FeturaPlusZoom(Assembly):
|
||||
def __init__(
|
||||
self,
|
||||
pv_get_position="SARES20-FETURA:POS_RB",
|
||||
pv_set_position="SARES20-FETURA:POS_SP",
|
||||
|
||||
name=None,
|
||||
):
|
||||
super().__init__(name=name)
|
||||
self.settings_collection.append(self)
|
||||
self._append(
|
||||
AdjustablePv,
|
||||
pv_set_position,
|
||||
pv_get_position,
|
||||
accuracy=1,
|
||||
name="zoom_raw",
|
||||
is_setting=False,
|
||||
)
|
||||
|
||||
self._append(
|
||||
AdjustableVirtual,
|
||||
[self.zoom_raw],
|
||||
lambda x: abs(round(x / 1000 * 100) - 100),
|
||||
lambda x: round(abs(x - 100) / 100 * 1000),
|
||||
name="zoom",
|
||||
is_setting=False,
|
||||
)
|
||||
|
||||
def get_current_value(self):
|
||||
return self.zoom.get_current_value()
|
||||
|
||||
def set_target_value(self, value, **kwargs):
|
||||
return self.zoom.set_target_value(value, **kwargs)
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ from epics import caget_many
|
||||
from ..elements.adjustable import AdjustableMemory, AdjustableVirtual
|
||||
from ..epics.adjustable import AdjustablePv, AdjustablePvEnum, AdjustablePvString
|
||||
from ..epics.detector import DetectorPvData, DetectorPvDataStream
|
||||
from ..detector.detectors_psi import DetectorBsStream
|
||||
from eco.epics.utilities_epics import EpicsString
|
||||
import logging
|
||||
from ..elements.assembly import Assembly
|
||||
@@ -13,12 +14,17 @@ logging.getLogger("cta_lib").setLevel(logging.WARNING)
|
||||
class TimingSystem(Assembly):
|
||||
"""This is a wrapper object for the global timing system at SwissFEL"""
|
||||
|
||||
def __init__(self, pv_master=None, pv_pulse_id=None, name=None):
|
||||
def __init__(self, pv_master=None, pv_pulse_id=None, pv_eventset=None, name=None):
|
||||
super().__init__(name=name)
|
||||
self._append(MasterEventSystem, pv_master, name="event_master", is_display=True)
|
||||
# self._append(DetectorPvDataStream, pv_pulse_id, name="pulse_id")
|
||||
self._append(
|
||||
MasterEventSystem, pv_master, name="event_master", is_display="recursive"
|
||||
DetectorBsStream, "pulse_id", cachannel=pv_pulse_id, name="pulse_id"
|
||||
)
|
||||
self._append(DetectorPvDataStream, pv_pulse_id, name="pulse_id")
|
||||
self._append(DetectorBsStream, "lab_time", cachannel=None, name="lab_time")
|
||||
|
||||
if pv_eventset:
|
||||
self._append(DetectorBsStream, pv_eventset, cachannel=None, name="eventset")
|
||||
|
||||
|
||||
# EVR output mapping
|
||||
@@ -212,7 +218,7 @@ class MasterEventSystem(Assembly):
|
||||
for s, c in zip(slots, codes):
|
||||
if not c == None:
|
||||
if c in codes_out:
|
||||
print(f"Code {c} exists multiple times!")
|
||||
# print(f"Code {c} exists multiple times!")
|
||||
continue
|
||||
slots_out.append(s)
|
||||
codes_out.append(c)
|
||||
@@ -295,31 +301,36 @@ class EvrPulser(Assembly):
|
||||
is_setting=True,
|
||||
)
|
||||
self.description = EpicsString(pv_base + "-Name-I")
|
||||
self._append(
|
||||
AdjustableVirtual,
|
||||
[self._eventcode.frequency],
|
||||
lambda x: x,
|
||||
lambda x: x,
|
||||
name="frequency",
|
||||
)
|
||||
self._append(
|
||||
AdjustableVirtual,
|
||||
[self._eventcode.delay],
|
||||
lambda x: x,
|
||||
lambda x: x,
|
||||
name="delay_eventcode",
|
||||
)
|
||||
self._append(
|
||||
AdjustableVirtual,
|
||||
[self.delay_pulser],
|
||||
lambda tp: self.delay_eventcode.get_current_value() + tp,
|
||||
lambda x: x - self.delay_eventcode.get_current_value(),
|
||||
name="delay",
|
||||
)
|
||||
|
||||
if True: #self._eventcode is not None:
|
||||
self._append(
|
||||
AdjustableVirtual,
|
||||
[self._eventcode.frequency],
|
||||
lambda x: x,
|
||||
lambda x: x,
|
||||
name="frequency",
|
||||
)
|
||||
self._append(
|
||||
AdjustableVirtual,
|
||||
[self._eventcode.delay],
|
||||
lambda x: x,
|
||||
lambda x: x,
|
||||
name="delay_eventcode",
|
||||
)
|
||||
self._append(
|
||||
AdjustableVirtual,
|
||||
[self.delay_pulser],
|
||||
lambda tp: self.delay_eventcode.get_current_value() + tp,
|
||||
lambda x: x - self.delay_eventcode.get_current_value(),
|
||||
name="delay",
|
||||
)
|
||||
|
||||
@property
|
||||
def _eventcode(self):
|
||||
return self._event_master.event_codes[self.eventcode.get_current_value()]
|
||||
try:
|
||||
return self._event_master.event_codes[self.eventcode.get_current_value()]
|
||||
except KeyError:
|
||||
return None
|
||||
|
||||
|
||||
class DummyPulser(Assembly):
|
||||
@@ -491,14 +502,14 @@ class EvrOutput(Assembly):
|
||||
def pulserA(self):
|
||||
try:
|
||||
return self._pulsers[self.pulserA_number.get_current_value()]
|
||||
except IndexError:
|
||||
except (IndexError, TypeError):
|
||||
return DummyPulser()
|
||||
|
||||
@property
|
||||
def pulserB(self):
|
||||
try:
|
||||
return self._pulsers[self.pulserA_number.get_current_value()]
|
||||
except IndexError:
|
||||
except (IndexError, TypeError):
|
||||
return DummyPulser()
|
||||
|
||||
|
||||
@@ -551,6 +562,17 @@ class EventReceiver(Assembly):
|
||||
# to._pulsers = self.pulsers
|
||||
self.outputs = outputs
|
||||
|
||||
self._append(
|
||||
AdjustablePv,
|
||||
self.pvname + ":SYSRESET",
|
||||
is_status=False,
|
||||
is_setting=False,
|
||||
name="restart_ioc_pv",
|
||||
)
|
||||
|
||||
def restart_ioc(self):
|
||||
self.restart_ioc_pv.set_target_value(1)
|
||||
|
||||
def gui(self):
|
||||
dev = self.pvname.split("-")[-1]
|
||||
sys = self.pvname[: -(len(dev) + 1)]
|
||||
|
||||
+312
-98
@@ -2,60 +2,281 @@ from epics import PV
|
||||
import os
|
||||
import numpy as np
|
||||
import time
|
||||
|
||||
from eco.elements.detector import DetectorVirtual
|
||||
from ..devices_general.utilities import Changer
|
||||
from ..elements.adjustable import (
|
||||
spec_convenience,
|
||||
AdjustableFS,
|
||||
AdjustableVirtual,
|
||||
tweak_option,
|
||||
value_property,
|
||||
)
|
||||
from ..epics.adjustable import AdjustablePv, AdjustablePvEnum
|
||||
from ..epics.detector import DetectorPvData
|
||||
from ..aliases import append_object_to_object, Alias
|
||||
from ..elements.assembly import Assembly
|
||||
|
||||
|
||||
# @spec_convenience
|
||||
# class XltEpics:
|
||||
# def __init__(self, pvname="SLAAR02-LTIM-PDLY", name="lxt_epics"):
|
||||
# self.pvname = pvname
|
||||
# self.alias = Alias(name)
|
||||
# append_object_to_object(
|
||||
# self,
|
||||
# AdjustablePvEnum,
|
||||
# self.pvname + ":SHOTDELAY",
|
||||
# name="oscialltor_pulse_offset",
|
||||
# )
|
||||
# append_object_to_object(
|
||||
# self,
|
||||
# AdjustablePvEnum,
|
||||
# self.pvname + ":SHOTMOFFS_ENA",
|
||||
# name="modulo_offset_mode",@spec_convenience
|
||||
# class XltEpics:
|
||||
# def __init__(self, pvname="SLAAR02-LTIM-PDLY", name="lxt_epics"):
|
||||
# self.pvname = pvname
|
||||
# self.alias = Alias(name)
|
||||
# append_object_to_object(
|
||||
# self,
|
||||
# AdjustablePvEnum,
|
||||
# self.pvname + ":SHOTDELAY",
|
||||
# name="oscialltor_pulse_offset",
|
||||
# )
|
||||
# append_object_to_object(
|
||||
# self,
|
||||
# AdjustablePvEnum,
|
||||
# self.pvname + ":SHOTMOFFS_ENA",
|
||||
# name="modulo_offset_mode",
|
||||
# )
|
||||
# append_object_to_object(
|
||||
# self, AdjustablePv, self.pvname + ":DELAY_Z_OFFS", name="_offset"
|
||||
# )
|
||||
# self.offset = AdjustableVirtual(
|
||||
# [self._offset],
|
||||
# lambda offset: offset * 1e-12,
|
||||
# lambda offset: offset / 1e-12,
|
||||
# name="offset",
|
||||
# )
|
||||
# append_object_to_object(
|
||||
# self, AdjustablePv, self.pvname + ":DELAY", name="_set_user_delay_value"
|
||||
# )
|
||||
# self._delay_dial_rb = PV("SLAAR-LGEN:DLY_OFFS2")
|
||||
# self.alias.append(
|
||||
# Alias("delay_dial_rb", "SLAAR-LGEN:DLY_OFFS2", channeltype="CA")
|
||||
# )
|
||||
# self.waiting_for_change = PV(self.pvname + ":WAITING")
|
||||
|
||||
# def get_current_dial_value(self):
|
||||
# return self._delay_dial_rb.get() * 1e-6
|
||||
|
||||
# def get_current_value(self):
|
||||
# return self.get_current_dial_value() - self.offset.get_current_value()
|
||||
|
||||
# def change_user_and_wait(self, value, check_interval=0.03):
|
||||
# if np.abs(value) > 0.1:
|
||||
# raise Exception("Very large value! This value is counted in seconds!")
|
||||
# if not self.waiting_for_change.get():
|
||||
# raise Exception("lxt is still moving!")
|
||||
# self.is_moving = False
|
||||
# self.is_stopped = False
|
||||
|
||||
# def set_is_stopped(**kwargs):
|
||||
# old_status = self.is_moving
|
||||
# new_status = not bool(kwargs["value"])
|
||||
# if (not new_status) and old_status:
|
||||
# self.is_stopped = True
|
||||
# self.is_moving = new_status
|
||||
|
||||
# self.waiting_for_change.add_callback(callback=set_is_stopped)
|
||||
# self._set_user_delay_value.set_target_value(value / 1e-12)
|
||||
|
||||
# while not self.is_stopped:
|
||||
# time.sleep(check_interval)
|
||||
# self.waiting_for_change.clear_callbacks()
|
||||
|
||||
# def set_target_value(self, value, hold=False):
|
||||
# return Changer(
|
||||
# target=value,
|
||||
# parent=self,
|
||||
# changer=self.change_user_and_wait,
|
||||
# hold=hold,
|
||||
# stopper=None,
|
||||
# )
|
||||
|
||||
# def reset_current_value_to(self, value):
|
||||
# self.offset.set_target_value((self.get_current_dial_value() - value)).wait()
|
||||
# )
|
||||
# append_object_to_object(
|
||||
# self, AdjustablePv, self.pvname + ":DELAY_Z_OFFS", name="_offset"
|
||||
# )
|
||||
# self.offset = AdjustableVirtual(
|
||||
# [self._offset],
|
||||
# lambda offset: offset * 1e-12,
|
||||
# lambda offset: offset / 1e-12,
|
||||
# name="offset",
|
||||
# )
|
||||
# append_object_to_object(
|
||||
# self, AdjustablePv, self.pvname + ":DELAY", name="_set_user_delay_value"
|
||||
# )
|
||||
# self._delay_dial_rb = PV("SLAAR-LGEN:DLY_OFFS2")
|
||||
# self.alias.append(
|
||||
# Alias("delay_dial_rb", "SLAAR-LGEN:DLY_OFFS2", channeltype="CA")
|
||||
# )
|
||||
# self.waiting_for_change = PV(self.pvname + ":WAITING")
|
||||
|
||||
# def get_current_dial_value(self):
|
||||
# return self._delay_dial_rb.get() * 1e-6
|
||||
|
||||
# def get_current_value(self):
|
||||
# return self.get_current_dial_value() - self.offset.get_current_value()
|
||||
|
||||
# def change_user_and_wait(self, value, check_interval=0.03):
|
||||
# if np.abs(value) > 0.1:
|
||||
# raise Exception("Very large value! This value is counted in seconds!")
|
||||
# if not self.waiting_for_change.get():
|
||||
# raise Exception("lxt is still moving!")
|
||||
# self.is_moving = False
|
||||
# self.is_stopped = False
|
||||
|
||||
# def set_is_stopped(**kwargs):
|
||||
# old_status = self.is_moving
|
||||
# new_status = not bool(kwargs["value"])
|
||||
# if (not new_status) and old_status:
|
||||
# self.is_stopped = True
|
||||
# self.is_moving = new_status
|
||||
|
||||
# self.waiting_for_change.add_callback(callback=set_is_stopped)
|
||||
# self._set_user_delay_value.set_target_value(value / 1e-12)
|
||||
|
||||
# while not self.is_stopped:
|
||||
# time.sleep(check_interval)
|
||||
# self.waiting_for_change.clear_callbacks()
|
||||
|
||||
# def set_target_value(self, value, hold=False):
|
||||
# return Changer(
|
||||
# target=value,
|
||||
# parent=self,
|
||||
# changer=self.change_user_and_wait,
|
||||
# hold=hold,
|
||||
# stopper=None,
|
||||
# )
|
||||
|
||||
# def reset_current_value_to(self, value):
|
||||
# self.offset.set_target_value((self.get_current_dial_value() - value)).wait()
|
||||
|
||||
|
||||
@spec_convenience
|
||||
class XltEpics:
|
||||
@tweak_option
|
||||
@value_property
|
||||
class XltEpics(Assembly):
|
||||
def __init__(self, pvname="SLAAR02-LTIM-PDLY", name="lxt_epics"):
|
||||
super().__init__(name=name)
|
||||
self.settings_collection.append(self, force=True)
|
||||
self.pvname = pvname
|
||||
self.alias = Alias(name)
|
||||
append_object_to_object(
|
||||
self,
|
||||
AdjustablePvEnum,
|
||||
self.pvname + ":SHOTDELAY",
|
||||
name="oscialltor_pulse_offset",
|
||||
# self.settings_collection.append(self, force=True)
|
||||
# self.status_collection.append(self, force=True)
|
||||
# self.display_collection.append(self, force=True)
|
||||
self._append(
|
||||
AdjustablePv,
|
||||
self.pvname + ":DELAY_Z_OFFS",
|
||||
name="_offset",
|
||||
is_setting=True,
|
||||
is_display=False,
|
||||
) # in picoseconds
|
||||
self._append(
|
||||
DetectorPvData,
|
||||
"SLAAR-LGEN:DLY_OFFS2",
|
||||
unit="ps",
|
||||
name="delay_dial_rb",
|
||||
is_setting=False,
|
||||
is_display=False,
|
||||
)
|
||||
append_object_to_object(
|
||||
self,
|
||||
AdjustablePvEnum,
|
||||
self.pvname + ":SHOTMOFFS_ENA",
|
||||
name="modulo_offset_mode",
|
||||
)
|
||||
append_object_to_object(
|
||||
self, AdjustablePv, self.pvname + ":DELAY_Z_OFFS", name="_offset"
|
||||
)
|
||||
self.offset = AdjustableVirtual(
|
||||
# SLAAR-LGEN:DLY_OFFS2
|
||||
self._append(
|
||||
AdjustableVirtual,
|
||||
[self._offset],
|
||||
lambda offset: offset * 1e-12,
|
||||
lambda offset: offset / 1e-12,
|
||||
name="offset",
|
||||
unit="s",
|
||||
is_setting=False,
|
||||
is_display=False,
|
||||
)
|
||||
append_object_to_object(
|
||||
self, AdjustablePv, self.pvname + ":DELAY", name="_set_user_delay_value"
|
||||
self._append(
|
||||
DetectorVirtual,
|
||||
[self.delay_dial_rb, self.offset],
|
||||
lambda dialrb,offset: dialrb * 1e-6 - offset,
|
||||
unit="s",
|
||||
name="readback",
|
||||
)
|
||||
self._delay_dial_rb = PV("SLAAR-LGEN:DLY_OFFS2")
|
||||
self.alias.append(
|
||||
Alias("delay_dial_rb", "SLAAR-LGEN:DLY_OFFS2", channeltype="CA")
|
||||
self._append(
|
||||
AdjustablePv,
|
||||
self.pvname + ":WINDOW_REQ",
|
||||
name="phase_shifter_window_start",
|
||||
is_setting=True,
|
||||
is_display=True,
|
||||
unit="ps",
|
||||
)
|
||||
self._append(
|
||||
AdjustablePv,
|
||||
self.pvname + ":LONG_DELAY_THRESH",
|
||||
name="_long_delay_threshold",
|
||||
is_setting=True,
|
||||
is_display=False,
|
||||
unit="ps",
|
||||
)
|
||||
self._append(
|
||||
AdjustableVirtual,
|
||||
[self._long_delay_threshold],
|
||||
lambda offset: offset * 1e-12,
|
||||
lambda offset: offset / 1e-12,
|
||||
name="long_delay_threshold",
|
||||
unit="s",
|
||||
is_setting=True,
|
||||
is_display=True,
|
||||
)
|
||||
self._append(
|
||||
AdjustablePv,
|
||||
self.pvname + ":DELAY",
|
||||
name="_set_user_delay_value",
|
||||
is_setting=False,
|
||||
is_display=False,
|
||||
)
|
||||
|
||||
|
||||
|
||||
# self._append(
|
||||
# DetectorPvData,
|
||||
# "SLAAR-LGEN:DLY_OFFS2",
|
||||
# name="delay_dial",
|
||||
# is_setting=False,
|
||||
# is_display=True,
|
||||
# )
|
||||
|
||||
# self._delay_dial_rb = PV("SLAAR-LGEN:DLY_OFFS2")
|
||||
# self.alias.append(
|
||||
# Alias("delay_dial_rb", "SLAAR-LGEN:DLY_OFFS2", channeltype="CA")
|
||||
# )
|
||||
self.waiting_for_change = PV(self.pvname + ":WAITING")
|
||||
|
||||
def get_current_dial_value(self):
|
||||
return self._delay_dial_rb.get() * 1e-6
|
||||
# def get_current_dial_value(self):
|
||||
# return self.delay_dial_rb.get_current_value() * 1e-6
|
||||
|
||||
def get_current_value(self):
|
||||
return self.get_current_dial_value() - self.offset.get_current_value()
|
||||
return self.readback.get_current_value()
|
||||
|
||||
def change_user_and_wait(self, value, check_interval=0.03):
|
||||
# def get_current_dial_value(self):
|
||||
# return self.delay_dial_rb.get_current_value() * 1e-6
|
||||
|
||||
# def get_current_user_value(self):
|
||||
# return (
|
||||
# self.delay_dial_rb.get_current_value() * 1e-6
|
||||
# - self.offset.get_current_value()
|
||||
# )
|
||||
|
||||
def change_user_and_wait(self, value, check_interval=0.03, evr_wait_time=0.01):
|
||||
if np.abs(value) > 0.1:
|
||||
raise Exception("Very large value! This value is counted in seconds!")
|
||||
if not self.waiting_for_change.get():
|
||||
@@ -70,8 +291,18 @@ class XltEpics:
|
||||
self.is_stopped = True
|
||||
self.is_moving = new_status
|
||||
|
||||
self.waiting_for_change.add_callback(callback=set_is_stopped)
|
||||
self._set_user_delay_value.set_target_value(value / 1e-12)
|
||||
is_phasshift = not (
|
||||
self.long_delay_threshold.get_current_value() < np.abs(value)
|
||||
)
|
||||
if is_phasshift:
|
||||
self.waiting_for_change.add_callback(callback=set_is_stopped)
|
||||
|
||||
self._set_user_delay_value.set_target_value(
|
||||
(value) / 1e-12
|
||||
)
|
||||
if not is_phasshift:
|
||||
time.sleep(evr_wait_time)
|
||||
self.is_stopped = True
|
||||
|
||||
while not self.is_stopped:
|
||||
time.sleep(check_interval)
|
||||
@@ -87,17 +318,41 @@ class XltEpics:
|
||||
)
|
||||
|
||||
def reset_current_value_to(self, value):
|
||||
self.offset.set_target_value((self.get_current_dial_value() - value)).wait()
|
||||
self.offset.set_target_value(self.offset.get_current_value() + self.get_current_value() - value).wait()
|
||||
|
||||
# caqtdm -noMsg -macro S=SLAAR02-LTIM-PDLY /sf/laser/config/qt/SLAAR02-L-SET_DELAY.ui
|
||||
|
||||
def gui(self):
|
||||
self._run_cmd(
|
||||
f"caqtdm -noMsg -macro S=SLAAR02-LTIM-PDLY /sf/laser/config/qt/SLAAR02-L-SET_DELAY.ui"
|
||||
)
|
||||
|
||||
@spec_convenience
|
||||
@tweak_option
|
||||
class XltEpics(Assembly):
|
||||
def __init__(self, pvname="SLAAR02-LTIM-PDLY", name="lxt_epics"):
|
||||
@value_property
|
||||
class LaserRateControl(Assembly):
|
||||
def __init__(self, pvname="SLAAR02-LTIM-PDLY", name=None):
|
||||
super().__init__(name=name)
|
||||
self.pvname = pvname
|
||||
self.settings_collection.append(self, force=True)
|
||||
self.status_collection.append(self, force=True)
|
||||
self.pvname = pvname
|
||||
# self.settings_collection.append(self, force=True)
|
||||
# self.status_collection.append(self, force=True)
|
||||
# self.display_collection.append(self, force=True)
|
||||
self._append(
|
||||
AdjustablePvEnum,
|
||||
self.pvname + ":ONEINN_MODE",
|
||||
name="reference_mode",
|
||||
is_setting=True,
|
||||
is_display=True,
|
||||
)
|
||||
self._append(
|
||||
AdjustablePv,
|
||||
"SIN-TIMAST-TMA:Evt-22-Freq-SP",
|
||||
name="laser_frequency",
|
||||
unit="Hz",
|
||||
is_setting=True,
|
||||
is_display=True,
|
||||
)
|
||||
self._append(
|
||||
AdjustablePvEnum,
|
||||
self.pvname + ":SHOTDELAY",
|
||||
@@ -113,84 +368,43 @@ class XltEpics(Assembly):
|
||||
is_display=True,
|
||||
)
|
||||
self._append(
|
||||
AdjustablePv,
|
||||
self.pvname + ":DELAY_Z_OFFS",
|
||||
name="_offset",
|
||||
AdjustablePvEnum,
|
||||
self.pvname + ":USE_EXT_EVT",
|
||||
name="use_ext_reference_event",
|
||||
is_setting=True,
|
||||
is_display=False,
|
||||
)
|
||||
self._append(
|
||||
AdjustableVirtual,
|
||||
[self._offset],
|
||||
lambda offset: offset * 1e-12,
|
||||
lambda offset: offset / 1e-12,
|
||||
name="offset",
|
||||
is_setting=False,
|
||||
is_display=True,
|
||||
)
|
||||
self._append(
|
||||
AdjustablePv,
|
||||
self.pvname + ":DELAY",
|
||||
name="_set_user_delay_value",
|
||||
is_setting=False,
|
||||
is_display=False,
|
||||
self.pvname + ":ALT_EXT_EVT",
|
||||
name="ext_reference_event",
|
||||
is_setting=True,
|
||||
is_display=True,
|
||||
)
|
||||
self._append(
|
||||
AdjustablePv,
|
||||
self.pvname + ":P_RATIO",
|
||||
name="rep_len",
|
||||
name="ref_pattern_len",
|
||||
is_setting=True,
|
||||
is_display=True,
|
||||
)
|
||||
self._append(
|
||||
AdjustablePv,
|
||||
"SIN-TIMAST-TMA:Evt-22-Freq-SP",
|
||||
name="laser_frequency",
|
||||
is_setting=True,
|
||||
is_display=True,
|
||||
)
|
||||
self._delay_dial_rb = PV("SLAAR-LGEN:DLY_OFFS2")
|
||||
self.alias.append(
|
||||
Alias("delay_dial_rb", "SLAAR-LGEN:DLY_OFFS2", channeltype="CA")
|
||||
)
|
||||
self.waiting_for_change = PV(self.pvname + ":WAITING")
|
||||
|
||||
def get_current_dial_value(self):
|
||||
return self._delay_dial_rb.get() * 1e-6
|
||||
|
||||
def get_current_value(self):
|
||||
return self.get_current_dial_value() - self.offset.get_current_value()
|
||||
# self._append(
|
||||
# DetectorPvData,
|
||||
# "SLAAR-LGEN:DLY_OFFS2",
|
||||
# name="delay_dial",
|
||||
# is_setting=False,
|
||||
# is_display=True,
|
||||
# )
|
||||
|
||||
def change_user_and_wait(self, value, check_interval=0.03):
|
||||
if np.abs(value) > 0.1:
|
||||
raise Exception("Very large value! This value is counted in seconds!")
|
||||
if not self.waiting_for_change.get():
|
||||
raise Exception("lxt is still moving!")
|
||||
self.is_moving = False
|
||||
self.is_stopped = False
|
||||
# self._delay_dial_rb = PV("SLAAR-LGEN:DLY_OFFS2")
|
||||
# self.alias.append(
|
||||
# Alias("delay_dial_rb", "SLAAR-LGEN:DLY_OFFS2", channeltype="CA")
|
||||
# )
|
||||
|
||||
|
||||
def set_is_stopped(**kwargs):
|
||||
old_status = self.is_moving
|
||||
new_status = not bool(kwargs["value"])
|
||||
if (not new_status) and old_status:
|
||||
self.is_stopped = True
|
||||
self.is_moving = new_status
|
||||
|
||||
self.waiting_for_change.add_callback(callback=set_is_stopped)
|
||||
self._set_user_delay_value.set_target_value(value / 1e-12)
|
||||
|
||||
while not self.is_stopped:
|
||||
time.sleep(check_interval)
|
||||
self.waiting_for_change.clear_callbacks()
|
||||
|
||||
def set_target_value(self, value, hold=False):
|
||||
return Changer(
|
||||
target=value,
|
||||
parent=self,
|
||||
changer=self.change_user_and_wait,
|
||||
hold=hold,
|
||||
stopper=None,
|
||||
)
|
||||
|
||||
def reset_current_value_to(self, value):
|
||||
self.offset.set_target_value((self.get_current_dial_value() - value)).wait()
|
||||
def gui(self):
|
||||
self._run_cmd(
|
||||
f"caqtdm -noMsg -macro S=SLAAR02-LTIM-PDLY /sf/laser/config/qt/SLAAR02-L-SET_DELAY.ui"
|
||||
)
|
||||
@@ -1,24 +0,0 @@
|
||||
from ..devices_general.motors import MotorRecord
|
||||
from ..devices_general.smaract import SmarActRecord
|
||||
from epics import PV
|
||||
from ..devices_general.delay_stage import DelayStage
|
||||
|
||||
|
||||
class Palm:
|
||||
def __init__(self, Id):
|
||||
self.Id = Id
|
||||
|
||||
self._delayStg = MotorRecord(self.Id + "-M552:MOT")
|
||||
self.delay = DelayStage(self._delayStg)
|
||||
|
||||
def get_adjustable_positions_str(self):
|
||||
ostr = "*****Palm motor positions******\n"
|
||||
|
||||
for tkey, item in self.__dict__.items():
|
||||
if hasattr(item, "get_current_value"):
|
||||
pos = item.get_current_value()
|
||||
ostr += " " + tkey.ljust(10) + " : % 14g\n" % pos
|
||||
return ostr
|
||||
|
||||
def __repr__(self):
|
||||
return self.get_adjustable_positions_str()
|
||||
@@ -1,24 +0,0 @@
|
||||
from ..devices_general.motors import MotorRecord
|
||||
from ..devices_general.smaract import SmarActRecord
|
||||
from epics import PV
|
||||
from ..devices_general.delay_stage import DelayStage
|
||||
|
||||
|
||||
class Psen:
|
||||
def __init__(self, Id):
|
||||
self.Id = Id
|
||||
|
||||
self._delayStg = MotorRecord(self.Id + "-M561:MOT")
|
||||
self.delay = DelayStage(self._delayStg)
|
||||
|
||||
def get_adjustable_positions_str(self):
|
||||
ostr = "*****PSEN motor positions******\n"
|
||||
|
||||
for tkey, item in self.__dict__.items():
|
||||
if hasattr(item, "get_current_value"):
|
||||
pos = item.get_current_value()
|
||||
ostr += " " + tkey.ljust(10) + " : % 14g\n" % pos
|
||||
return ostr
|
||||
|
||||
def __repr__(self):
|
||||
return self.get_adjustable_positions_str()
|
||||
+23
-5
@@ -97,29 +97,47 @@ class CtaSequencer(Assembly):
|
||||
|
||||
return arrays
|
||||
|
||||
def append_sequence_step(self, code, step_delay):
|
||||
def append_sequence_step(self, code, step_delay, send_immediately=True):
|
||||
if code not in self.event_code_sequences.keys():
|
||||
raise Exception(
|
||||
f"Eventcode {code} is not within the allowed or configured eventcodes for the sequencer"
|
||||
)
|
||||
oldlength = self.length.get_current_value()
|
||||
newlength = oldlength + step_delay
|
||||
changes = []
|
||||
|
||||
self.new_sequences = {}
|
||||
for i, ec in self.event_code_sequences.items():
|
||||
if oldlength == 0:
|
||||
o = []
|
||||
else:
|
||||
o = list(ec.get_current_value())
|
||||
if i == code:
|
||||
n = o + [0] * (newlength - oldlength - 1) + [1]
|
||||
ind = newlength - oldlength - 1
|
||||
if ind < 0:
|
||||
o[newlength - 1] = 1
|
||||
n = o
|
||||
else:
|
||||
n = o + [0] * (newlength - oldlength - 1) + [1]
|
||||
else:
|
||||
n = o + [0] * (newlength - oldlength)
|
||||
self.new_sequences[i] = n
|
||||
# print(o, n)
|
||||
changes.append(ec.set_target_value(n))
|
||||
|
||||
if send_immediately:
|
||||
self.send_new_sequences()
|
||||
|
||||
def send_new_sequences(self):
|
||||
for i, n in self.new_sequences.items():
|
||||
|
||||
changes = []
|
||||
changes.append(self.event_code_sequences[i].set_target_value(n))
|
||||
for change in changes:
|
||||
change.wait()
|
||||
|
||||
# self.event_code_sequences[code]._value[newlength - 1] = 1
|
||||
lengths = [len(n) for i, n in self.new_sequences.items()]
|
||||
newlength = lengths[0]
|
||||
print(f"newlength is {newlength}, lengths are {lengths}")
|
||||
|
||||
self.length.set_target_value(newlength).wait()
|
||||
|
||||
@@ -142,7 +160,7 @@ class CtaSequencer(Assembly):
|
||||
tsteps = is_present_array.nonzero()[0]
|
||||
for step in tsteps:
|
||||
if not step in seq_red.keys():
|
||||
seq_red[step] = []
|
||||
seq_red[int(step)] = []
|
||||
seq_red[step].append(code)
|
||||
|
||||
return seq_red
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
from eco.detector.detectors_psi import DetectorBsStream
|
||||
from eco.devices_general.pipelines_swissfel import Pipeline
|
||||
from ..elements.assembly import Assembly
|
||||
from ..devices_general.motors import SmaractStreamdevice, MotorRecord, SmaractRecord
|
||||
from ..elements.adjustable import AdjustableMemory, AdjustableVirtual
|
||||
@@ -22,12 +24,13 @@ class TimetoolBerninaUSD(Assembly):
|
||||
self,
|
||||
name=None,
|
||||
processing_pipeline="SARES20-CAMS142-M5_psen_db",
|
||||
processing_instance="SARES20-CAMS142-M5_psen_db1",
|
||||
edge_finding_pipeline="SAROP21-ATT01_proc",
|
||||
processing_instance="SARES20-CAMS142-M5_psen_db",
|
||||
spectrometer_camera_channel="SARES20-CAMS142-M5:FPICTURE",
|
||||
spectrometer_pvname="SARES20-CAMS142-M5",
|
||||
microscope_pvname="SARES20-PROF141-M1",
|
||||
delaystage_PV="SLAAR21-LMOT-M524:MOTOR_1",
|
||||
pvname_mirror="SARES23:LIC9",
|
||||
pvname_mirror="SARES23-LIC:MOT_9",
|
||||
pvname_zoom="SARES20-MF1:MOT_8",
|
||||
mirror_in=15,
|
||||
mirror_out=-5,
|
||||
@@ -43,7 +46,10 @@ class TimetoolBerninaUSD(Assembly):
|
||||
|
||||
self.proc_client = PipelineClient()
|
||||
self.proc_pipeline = processing_pipeline
|
||||
self._append(Pipeline,self.proc_pipeline, name='pipeline_projection', is_setting=True)
|
||||
self.proc_instance = processing_instance
|
||||
self.proc_pipeline_edge = edge_finding_pipeline
|
||||
self._append(Pipeline,self.proc_pipeline_edge, name='pipeline_edgefinding', is_setting=True)
|
||||
self.spectrometer_camera_channel = spectrometer_camera_channel
|
||||
self._append(
|
||||
Target_xyz,
|
||||
@@ -80,7 +86,7 @@ class TimetoolBerninaUSD(Assembly):
|
||||
CameraBasler,
|
||||
pvname=microscope_pvname,
|
||||
name="camera_microscope",
|
||||
camserver_alias=f"{name} ({microscope_pvname})",
|
||||
camserver_alias="PROF_KB (SARES20-PROF141-M1)",
|
||||
is_setting=True,
|
||||
is_display=False,
|
||||
)
|
||||
@@ -128,6 +134,45 @@ class TimetoolBerninaUSD(Assembly):
|
||||
is_setting=True,
|
||||
)
|
||||
|
||||
# SARES20-CAMS142-M5.bsen_signal_x_profile
|
||||
# SARES20-CAMS142-M5.processing_parameters
|
||||
# SARES20-CAMS142-M5.psen_signal_x_profile
|
||||
#
|
||||
#
|
||||
|
||||
self._append(
|
||||
DetectorBsStream,
|
||||
"SARES20-CAMS142-M5.roi_signal_x_profile",
|
||||
cachannel=None,
|
||||
name="spectrum_signal",
|
||||
is_setting=False,
|
||||
is_display=True,
|
||||
)
|
||||
self._append(
|
||||
DetectorBsStream,
|
||||
"SARES20-CAMS142-M5.roi_background_x_prof",
|
||||
cachannel=None,
|
||||
name="spectrum_background",
|
||||
is_setting=False,
|
||||
is_display=True,
|
||||
)
|
||||
self._append(
|
||||
DetectorBsStream,
|
||||
"SARES20-CAMS142-M5.bsen_signal_x_profilef",
|
||||
cachannel=None,
|
||||
name="spectrum_bsen",
|
||||
is_setting=False,
|
||||
is_display=True,
|
||||
)
|
||||
self._append(
|
||||
DetectorBsStream,
|
||||
"SAROP21-ATT01:arrival_time",
|
||||
cachannel=None,
|
||||
name="edge_position",
|
||||
is_setting=False,
|
||||
is_display=True,
|
||||
)
|
||||
|
||||
def get_online_data(self):
|
||||
self.online_monitor = TtProcessor()
|
||||
|
||||
|
||||
+86
-16
@@ -1,7 +1,9 @@
|
||||
import json
|
||||
import importlib
|
||||
from pathlib import Path
|
||||
from eco.elements.protocols import InitialisationWaitable
|
||||
import sys
|
||||
from time import time
|
||||
from colorama import Fore as _color
|
||||
from functools import partial
|
||||
|
||||
@@ -265,10 +267,16 @@ class Namespace(Assembly):
|
||||
# self.name = name
|
||||
self.lazy_items = {}
|
||||
self.initialized_items = {}
|
||||
self.failed_items = {}
|
||||
self.initialisation_times = {}
|
||||
self.names_without_alias = []
|
||||
self.root_module = root_module
|
||||
self.alias_namespace = alias_namespace
|
||||
|
||||
@property
|
||||
def initialisation_times_sorted(self):
|
||||
return dict(sorted(self.initialisation_times.items(), key=lambda w: w[1]))
|
||||
|
||||
@property
|
||||
def initialized_names(self):
|
||||
return set(self.initialized_items.keys())
|
||||
@@ -277,9 +285,13 @@ class Namespace(Assembly):
|
||||
def lazy_names(self):
|
||||
return set(self.lazy_items.keys())
|
||||
|
||||
@property
|
||||
def failed_names(self):
|
||||
return set(self.failed_items.keys())
|
||||
|
||||
@property
|
||||
def all_names(self):
|
||||
return self.initialized_names | self.lazy_names
|
||||
return self.initialized_names | self.lazy_names | self.failed_names
|
||||
|
||||
def init_name(self, name, verbose=True, raise_errors=False):
|
||||
# for name in self.all_names:
|
||||
@@ -289,17 +301,28 @@ class Namespace(Assembly):
|
||||
# if verbose:
|
||||
# print(("(%s)" % (name)).ljust(25), end="")
|
||||
# sys.stdout.flush()
|
||||
starttime = time()
|
||||
try:
|
||||
dir(self.get_obj(name))
|
||||
titem = self.get_obj(name)
|
||||
if isinstance(titem, InitialisationWaitable):
|
||||
titem._wait_for_initialisation()
|
||||
else:
|
||||
dir(titem)
|
||||
|
||||
if verbose:
|
||||
print((_color.GREEN + "OK" + _color.RESET).rjust(5))
|
||||
print(
|
||||
f"{time()-starttime} s "
|
||||
+ (_color.GREEN + "OK" + _color.RESET).rjust(5)
|
||||
)
|
||||
sys.stdout.flush()
|
||||
|
||||
except Exception as expt:
|
||||
# tb = traceback.format_exc()
|
||||
if verbose:
|
||||
print((_color.RED + "FAILED" + _color.RESET).rjust(5))
|
||||
print(
|
||||
f"{time()-starttime} s "
|
||||
+ (_color.RED + "FAILED" + _color.RESET).rjust(5)
|
||||
)
|
||||
# print(sys.exc_info())
|
||||
if raise_errors:
|
||||
raise expt
|
||||
@@ -312,11 +335,19 @@ class Namespace(Assembly):
|
||||
max_workers=5,
|
||||
N_cycles=4,
|
||||
silent=True,
|
||||
giveup_failed=True,
|
||||
exclude_names=[],
|
||||
):
|
||||
starttime = time()
|
||||
|
||||
if self.failed_names:
|
||||
print(
|
||||
f"WARNING - previously hard failed items are NOT initialized:\n{self.failed_names} "
|
||||
)
|
||||
if silent:
|
||||
self.silently_initializing = True
|
||||
print(
|
||||
f"Initializeing all items in namespace {self.name} silently in background.\n Be aware of unrelated output!"
|
||||
f"Initializing all items in namespace {self.name} silently in background.\n Be aware of unrelated output!"
|
||||
)
|
||||
|
||||
def init():
|
||||
@@ -325,7 +356,7 @@ class Namespace(Assembly):
|
||||
self.exc_init.submit(
|
||||
self.init_name, name, verbose=verbose, raise_errors=raise_errors
|
||||
)
|
||||
for name in self.all_names
|
||||
for name in (self.all_names - set(exclude_names))
|
||||
]
|
||||
self.exc_init.shutdown(wait=True)
|
||||
self.exc_init = ThreadPoolExecutor(max_workers=1)
|
||||
@@ -333,15 +364,25 @@ class Namespace(Assembly):
|
||||
self.exc_init.submit(
|
||||
self.init_name, name, verbose=verbose, raise_errors=raise_errors
|
||||
)
|
||||
for name in (self.all_names - self.initialized_names)
|
||||
for name in (
|
||||
self.all_names - self.initialized_names - set(exclude_names)
|
||||
)
|
||||
]
|
||||
self.exc_init.shutdown(wait=True)
|
||||
self.silently_initializing = False
|
||||
if giveup_failed:
|
||||
failed_names = self.lazy_names
|
||||
for k in failed_names:
|
||||
self.failed_items[k] = self.lazy_items.pop(k)
|
||||
if print_summary:
|
||||
print(
|
||||
f"Initialized {len(self.initialized_names)} of {len(self.all_names)}."
|
||||
)
|
||||
print("Failed objects: " + ", ".join(self.lazy_names))
|
||||
print(
|
||||
"Failed objects: "
|
||||
+ ", ".join(self.lazy_names.union(self.failed_names))
|
||||
)
|
||||
print(f"Initialisation took {time()-starttime} seconds")
|
||||
|
||||
Thread(target=init).start()
|
||||
else:
|
||||
@@ -354,10 +395,14 @@ class Namespace(Assembly):
|
||||
lambda name: self.init_name(
|
||||
name, verbose=verbose, raise_errors=raise_errors
|
||||
),
|
||||
self.all_names,
|
||||
self.all_names
|
||||
- self.initialized_names
|
||||
- set(exclude_names),
|
||||
),
|
||||
description="Initializing ...",
|
||||
total=len(self.all_names),
|
||||
total=len(
|
||||
self.all_names - self.initialized_names - set(exclude_names)
|
||||
),
|
||||
transient=True,
|
||||
)
|
||||
)
|
||||
@@ -369,21 +414,32 @@ class Namespace(Assembly):
|
||||
lambda name: self.init_name(
|
||||
name, verbose=verbose, raise_errors=raise_errors
|
||||
),
|
||||
self.all_names,
|
||||
self.all_names
|
||||
- self.initialized_names
|
||||
- set(exclude_names),
|
||||
),
|
||||
description="Initializing ...",
|
||||
total=len(self.all_names),
|
||||
total=len(
|
||||
self.all_names - self.initialized_names - set(exclude_names)
|
||||
),
|
||||
transient=True,
|
||||
)
|
||||
)
|
||||
# )
|
||||
# # )
|
||||
|
||||
if giveup_failed:
|
||||
failed_names = self.lazy_names
|
||||
for k in failed_names:
|
||||
self.failed_items[k] = self.lazy_items.pop(k)
|
||||
if print_summary:
|
||||
print(
|
||||
f"Initialized {len(self.initialized_names)} of {len(self.all_names)}."
|
||||
)
|
||||
print("Failed objects: " + ", ".join(self.lazy_names))
|
||||
print(
|
||||
"Failed objects: "
|
||||
+ ", ".join(self.lazy_names.union(self.failed_names))
|
||||
)
|
||||
print(f"Initialisation took {time()-starttime} seconds")
|
||||
|
||||
# if verbose:
|
||||
# print(("Configuring %s " % (name)).ljust(25), end="")
|
||||
@@ -406,7 +462,7 @@ class Namespace(Assembly):
|
||||
# if raise_errors:
|
||||
# raise expt
|
||||
|
||||
def get_initialized_aliases(self):
|
||||
def get_initialized_aliases(self, channeltypes=[]):
|
||||
aliases = []
|
||||
has_no_aliases = []
|
||||
for tn, tv in self.initialized_items.items():
|
||||
@@ -414,6 +470,13 @@ class Namespace(Assembly):
|
||||
aliases += tv.alias.get_all()
|
||||
except:
|
||||
has_no_aliases.append(tn)
|
||||
aliases_out = []
|
||||
for channeltype in channeltypes:
|
||||
for alias in aliases:
|
||||
if alias["channeltype"] == channeltype:
|
||||
aliases_out.append(alias)
|
||||
if not channeltypes:
|
||||
aliases_out = aliases
|
||||
return aliases, has_no_aliases
|
||||
|
||||
def append_obj(
|
||||
@@ -422,6 +485,7 @@ class Namespace(Assembly):
|
||||
if lazy:
|
||||
|
||||
def init_local():
|
||||
starttime = time()
|
||||
if module_name:
|
||||
obj_maker = getattr(import_module(module_name), obj_factory)
|
||||
else:
|
||||
@@ -432,7 +496,11 @@ class Namespace(Assembly):
|
||||
else:
|
||||
obj_initialized = obj_maker(*args, **kwargs)
|
||||
|
||||
self.initialized_items[name] = self.lazy_items.pop(name)
|
||||
try:
|
||||
self.initialized_items[name] = self.lazy_items.pop(name)
|
||||
except KeyError:
|
||||
self.initialized_items[name] = self.failed_items.pop(name)
|
||||
self.initialisation_times[name] = time() - starttime
|
||||
if hasattr(obj_initialized, "alias"):
|
||||
self._append(
|
||||
obj_initialized,
|
||||
@@ -462,6 +530,7 @@ class Namespace(Assembly):
|
||||
return obj_lazy
|
||||
|
||||
else:
|
||||
starttime = time()
|
||||
if module_name:
|
||||
obj_maker = getattr(import_module(module_name), obj_factory)
|
||||
else:
|
||||
@@ -471,6 +540,7 @@ class Namespace(Assembly):
|
||||
except TypeError:
|
||||
obj = obj_maker(*args, **kwargs)
|
||||
self.initialized_items[name] = obj
|
||||
self.initialisation_times[name] = time() - starttime
|
||||
if self.root_module:
|
||||
sys.modules[self.root_module].__dict__[name] = obj
|
||||
if hasattr(obj, "alias"):
|
||||
|
||||
+83
-7
@@ -1,7 +1,27 @@
|
||||
from pathlib import Path
|
||||
import elog as _elog_ha
|
||||
from getpass import getuser as _getuser
|
||||
from getpass import getpass as _getpass
|
||||
import os, datetime, subprocess
|
||||
from markdown import markdown
|
||||
import urllib3
|
||||
|
||||
urllib3.disable_warnings()
|
||||
|
||||
|
||||
######################
|
||||
class ElogsMultiplexer:
|
||||
def __init__(self, *args):
|
||||
self.elogs = args
|
||||
|
||||
def post(self, *args, **kwargs):
|
||||
mids = []
|
||||
for elog in self.elogs:
|
||||
mids.append(elog.post(*args, **kwargs))
|
||||
return mids
|
||||
|
||||
|
||||
##########################
|
||||
|
||||
|
||||
def getDefaultElogInstance(url, **kwargs):
|
||||
@@ -29,17 +49,74 @@ class Elog:
|
||||
self._screenshot = Screenshot(screenshot_directory)
|
||||
self.read = self._log.read
|
||||
|
||||
def post(self, *args, Title=None, Author=None, Encoding="html", **kwargs):
|
||||
def post(
|
||||
self,
|
||||
*args,
|
||||
text_encoding="markdown",
|
||||
markdown_extensions=["fenced_code"],
|
||||
tags=[],
|
||||
Title=None,
|
||||
Author=None,
|
||||
**kwargs,
|
||||
):
|
||||
""" """
|
||||
if Encoding == "html":
|
||||
args = list(args)
|
||||
args[0] = args[0].replace("\n", "<br />\n")
|
||||
|
||||
message = ""
|
||||
file_paths = []
|
||||
|
||||
for targ in args:
|
||||
if not (isinstance(targ, str) or isinstance(targ, Path)):
|
||||
raise Exception(
|
||||
"Log messages should be of type string or pathlib.Path!"
|
||||
)
|
||||
|
||||
if isinstance(targ, Path):
|
||||
if Path(targ).expanduser().exists():
|
||||
print("file exists")
|
||||
file_paths.append(targ.as_posix())
|
||||
if targ.suffix[1:] in ["jpg", "png"]:
|
||||
if text_encoding in ["markdown", "html"]:
|
||||
message += f'<p><img alt="" src="temporarypath-attachment_{len(file_paths)-1}" /></p>'
|
||||
else:
|
||||
targ = str(targ)
|
||||
if text_encoding == "markdown":
|
||||
message += markdown(targ, extensions=markdown_extensions)
|
||||
Encoding = "html"
|
||||
elif text_encoding == "html":
|
||||
Encoding = "html"
|
||||
else:
|
||||
message += targ + "\n"
|
||||
Encoding = "plain"
|
||||
|
||||
if not Author:
|
||||
Author = self.user
|
||||
return self._log.post(
|
||||
*args, Title=Title, Author=Author, Encoding=Encoding, **kwargs
|
||||
|
||||
if file_paths:
|
||||
attachments = file_paths
|
||||
else:
|
||||
attachments = None
|
||||
mid = self._log.post(
|
||||
message,
|
||||
attachments=attachments,
|
||||
Title=Title,
|
||||
Author=Author,
|
||||
Encoding=Encoding,
|
||||
**kwargs,
|
||||
)
|
||||
|
||||
if file_paths:
|
||||
pm, patt, pa = self._log.read(mid)
|
||||
for ntpa, tpa in enumerate(pa):
|
||||
filename = "".join(Path(tpa).parts[-1].split("_")[2:])
|
||||
print(filename)
|
||||
Nocc = pm.count(f"temporarypath-attachment_{ntpa}")
|
||||
print(Nocc)
|
||||
if Nocc:
|
||||
pm = pm.replace(f"temporarypath-attachment_{ntpa}", tpa)
|
||||
self._log.post(pm, msg_id=mid)
|
||||
|
||||
return mid
|
||||
|
||||
def screenshot(self, message="", window=False, desktop=False, delay=3, **kwargs):
|
||||
filepath = self._screenshot.shoot()[0]
|
||||
kwargs.update({"attachments": [filepath]})
|
||||
@@ -55,7 +132,6 @@ class Screenshot:
|
||||
self.user = kwargs["user"]
|
||||
|
||||
def show_directory(self):
|
||||
|
||||
p = subprocess.Popen(
|
||||
["nautilus", self._screenshot_directory],
|
||||
stdout=subprocess.PIPE,
|
||||
|
||||
Executable
+144
@@ -0,0 +1,144 @@
|
||||
from functools import lru_cache
|
||||
from markdown import markdown
|
||||
from scilog import SciLog, LogbookMessage
|
||||
from getpass import getuser as _getuser
|
||||
from getpass import getpass as _getpass
|
||||
import os, datetime, subprocess
|
||||
import urllib3
|
||||
from pathlib import Path
|
||||
|
||||
from eco.elements.assembly import Assembly
|
||||
|
||||
urllib3.disable_warnings()
|
||||
|
||||
|
||||
def getDefaultElogInstance(
|
||||
url="https://scilog.psi.ch/api/v1",
|
||||
user="swissfelaramis-bernina@psi.ch",
|
||||
pgroup=None,
|
||||
**kwargs,
|
||||
):
|
||||
home = str(Path.home())
|
||||
if not user:
|
||||
user = _getuser()
|
||||
|
||||
if not ("password" in kwargs.keys()):
|
||||
try:
|
||||
with open(os.path.join(home, ".scilog_psi"), "r") as f:
|
||||
_pw = f.read().strip()
|
||||
except:
|
||||
print(f"Enter scilog password for user: {user}")
|
||||
_pw = _getpass()
|
||||
kwargs.update(dict(password=_pw))
|
||||
log = SciLog(url, options := {"username": user, "password": kwargs["password"]})
|
||||
if pgroup:
|
||||
lbs = log.get_logbooks(ownerGroup=pgroup)
|
||||
if len(lbs) > 1:
|
||||
raise Exception(f"Found more than one elog for user group {pgroup}")
|
||||
log.select_logbook(lbs[0])
|
||||
return log, user
|
||||
|
||||
|
||||
class Elog(Assembly):
|
||||
def __init__(
|
||||
self,
|
||||
url="https://scilog.psi.ch/api/v1",
|
||||
pgroup_adj=None,
|
||||
screenshot_directory="",
|
||||
name="scilog",
|
||||
**kwargs,
|
||||
):
|
||||
super().__init__(name=name)
|
||||
self.scilog_url = url
|
||||
self._append(pgroup_adj, name="pgroup")
|
||||
dummy, self.user = getDefaultElogInstance(
|
||||
url, pgroup=pgroup_adj.get_current_value(), **kwargs
|
||||
)
|
||||
self.__class__._log = property(
|
||||
lambda dum: self._get_scilog_dynamically(
|
||||
self.scilog_url, self.pgroup.get_current_value()
|
||||
)
|
||||
)
|
||||
self._screenshot = Screenshot(screenshot_directory)
|
||||
# self.read = self._log.read
|
||||
|
||||
@lru_cache
|
||||
def _get_scilog_dynamically(self, url, pgroup):
|
||||
log, user = getDefaultElogInstance(url, pgroup=pgroup)
|
||||
self.user = user
|
||||
return log
|
||||
|
||||
def post(
|
||||
self,
|
||||
*args,
|
||||
tags=[],
|
||||
text_encoding="markdown",
|
||||
markdown_extensions=["fenced_code"],
|
||||
**kwargs,
|
||||
):
|
||||
"""args can be text or pathlibPath instances (for files to be uploaded)"""
|
||||
msg = LogbookMessage()
|
||||
for targ in args:
|
||||
if not (isinstance(targ, str) or isinstance(targ, Path)):
|
||||
raise Exception("Log messages should be of type string!")
|
||||
|
||||
if isinstance(targ, Path):
|
||||
if Path(targ).expanduser().exists():
|
||||
print("file exists")
|
||||
msg.add_file(targ.as_posix())
|
||||
else:
|
||||
targ = str(targ)
|
||||
if text_encoding == "markdown":
|
||||
msg.add_text(markdown(targ, extensions=markdown_extensions))
|
||||
elif text_encoding == "html":
|
||||
msg.add_text(targ)
|
||||
else:
|
||||
msg.add_text(targ)
|
||||
|
||||
for tag in tags:
|
||||
msg.add_tag(tag)
|
||||
|
||||
return self._log.send_logbook_message(msg)
|
||||
|
||||
def screenshot(self, message="", window=False, desktop=False, delay=3, **kwargs):
|
||||
filepath = self._screenshot.shoot()[0]
|
||||
kwargs.update({"attachments": [filepath]})
|
||||
self.post(message, **kwargs)
|
||||
|
||||
|
||||
class Screenshot:
|
||||
def __init__(self, screenshot_directory="", **kwargs):
|
||||
self._screenshot_directory = screenshot_directory
|
||||
if not ("user" in kwargs.keys()):
|
||||
self.user = _getuser()
|
||||
else:
|
||||
self.user = kwargs["user"]
|
||||
|
||||
def show_directory(self):
|
||||
p = subprocess.Popen(
|
||||
["nautilus", self._screenshot_directory],
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
)
|
||||
|
||||
def shoot(self, message="", window=False, desktop=False, delay=3, **kwargs):
|
||||
cmd = ["gnome-screenshot"]
|
||||
if window:
|
||||
cmd.append("-w")
|
||||
cmd.append("--delay=%d" % delay)
|
||||
elif desktop:
|
||||
cmd.append("--delay=%d" % delay)
|
||||
else:
|
||||
cmd.append("-a")
|
||||
tim = datetime.datetime.now()
|
||||
fina = "%s-%s-%s_%s-%s-%s" % tim.timetuple()[:6]
|
||||
if "Author" in kwargs.keys():
|
||||
fina += "_%s" % user
|
||||
else:
|
||||
fina += "_%s" % self.user
|
||||
fina += ".png"
|
||||
filepath = os.path.join(self._screenshot_directory, fina)
|
||||
cmd.append("--file")
|
||||
cmd.append(filepath)
|
||||
p = subprocess.call(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
return filepath, p
|
||||
@@ -0,0 +1,49 @@
|
||||
from simple_pid import PID
|
||||
from ..epics.detector import DetectorPvDataStream
|
||||
from ..elements.assembly import Assembly
|
||||
from threading import Thread
|
||||
from time import sleep
|
||||
from ..elements.adjustable import AdjustableFS
|
||||
|
||||
class Feedback_Timetool(Assembly):
|
||||
def __init__(self, name=None, pvname=None, control_adj = None, pid=[1, 0.01, 0], output_limits=(-100,100), setpoint=1060, calib_s_per_px=3e-15):
|
||||
super().__init__(name=name)
|
||||
self._append(DetectorPvDataStream, pvname, name="monitor")
|
||||
self.pid = PID(
|
||||
*pid,
|
||||
setpoint=0,
|
||||
output_limits=(output_limits[0]*abs(calib_s_per_px), output_limits[1]*abs(calib_s_per_px)),
|
||||
sample_time=10,
|
||||
)
|
||||
self.control_adj = control_adj
|
||||
self._append(
|
||||
AdjustableFS,
|
||||
"/photonics/home/gac-bernina/eco/configuration/tt_feedback_setpoint",
|
||||
default_value=setpoint,
|
||||
name="setpoint",
|
||||
)
|
||||
self._append(
|
||||
AdjustableFS,
|
||||
"/photonics/home/gac-bernina/eco/configuration/tt_feedback_calib_s_per_px",
|
||||
default_value=calib_s_per_px,
|
||||
name="calib_s_per_px",
|
||||
)
|
||||
self._running=False
|
||||
def stop(self):
|
||||
self._running = False
|
||||
def run_continuously(self):
|
||||
while(self._running):
|
||||
rb_val = self.monitor.get_current_value()
|
||||
set_val = self.pid(rb_val-self.setpoint())*self.calib_s_per_px()
|
||||
print(f"moving phase control adjustable by {set_val}")
|
||||
self.control_adj.mvr(set_val)
|
||||
sleep(60)
|
||||
|
||||
|
||||
def start_feedback(self):
|
||||
self._running=True
|
||||
self.feedback = Thread(target = self.run_continuously)
|
||||
|
||||
|
||||
|
||||
|
||||
+676
-26
@@ -2,12 +2,28 @@ from diffcalc.hkl.calc import HklCalculation
|
||||
from diffcalc.hkl.constraints import Constraints
|
||||
from diffcalc.hkl.geometry import Position
|
||||
from diffcalc.ub import calc as dccalc
|
||||
import pandas as pd
|
||||
import numpy as np
|
||||
from datetime import datetime
|
||||
import os
|
||||
from PIL import Image
|
||||
|
||||
# from diffcalc.ub import calc calc import UBCalculation, Crystal
|
||||
from eco.elements.assembly import Assembly
|
||||
from eco.elements.adjustable import AdjustableMemory
|
||||
from eco.elements.adjustable import AdjustableMemory, AdjustableFS, AdjustableVirtual, DummyAdjustable
|
||||
from typing import Tuple, Optional
|
||||
from eco.elements.adj_obj import AdjustableObject
|
||||
from epics import PV
|
||||
|
||||
class Diffractometer_Dummy(Assembly):
|
||||
def __init__(self, *args, name=None, **kwargs):
|
||||
Assembly.__init__(self, name=name)
|
||||
self.configuration = ["base", "arm"]
|
||||
adjs = ["nu", "mu", "delta", "eta", "chi", "phi"]
|
||||
for adj in adjs:
|
||||
self._append(DummyAdjustable, name=adj, is_setting=True, is_display=True, limits=[-180,180])
|
||||
|
||||
diffractometer_dummy = Diffractometer_Dummy(name = "dummy")
|
||||
|
||||
class CrystalNew(Assembly):
|
||||
def __init__(self, *args, name=None, **kwargs):
|
||||
@@ -32,26 +48,374 @@ class CrystalNew(Assembly):
|
||||
)
|
||||
|
||||
|
||||
class Crystals(Assembly):
|
||||
def __init__(self, diffractometer_you=diffractometer_dummy, name=None):
|
||||
super().__init__(name=name)
|
||||
self.diffractometer = diffractometer_you
|
||||
self._append(
|
||||
AdjustableFS,
|
||||
f"/photonics/home/gac-bernina/eco/configuration/crystals/{name}_list",
|
||||
name="crystal_list",
|
||||
default_value={},
|
||||
is_setting=True,
|
||||
)
|
||||
for key, meta in self.crystal_list().items():
|
||||
if self.diffractometer.name in meta:
|
||||
self._append(
|
||||
DiffGeometryYou, diffractometer_you=self.diffractometer, name=key
|
||||
)
|
||||
|
||||
def create_crystal(self, name=None):
|
||||
if name == None:
|
||||
name = input(
|
||||
"Please choose a name for your crystal (no spaces or other special characters):"
|
||||
)
|
||||
specials = np.array([".", " ", "/", "(", ")", "[", "]"]+list(self.crystal_list().keys()))
|
||||
in_name = np.array([s in name for s in specials])
|
||||
if np.any(in_name):
|
||||
raise Exception(
|
||||
f"Special character(s) {specials[in_name]} in name not allowed or name already exists"
|
||||
)
|
||||
self._append(
|
||||
DiffGeometryYou,
|
||||
diffractometer_you=self.diffractometer,
|
||||
name=name,
|
||||
is_setting=True,
|
||||
is_display=False,
|
||||
)
|
||||
crystals = self.crystal_list()
|
||||
crystals[name] = [str(datetime.now()), self.diffractometer.name]
|
||||
self.crystal_list.mv(crystals)
|
||||
self.__dict__[name].new_ub()
|
||||
|
||||
def delete_crystal(self, name=None):
|
||||
"""
|
||||
Delete crystal with a given name, deletes also the files.
|
||||
"""
|
||||
if name==None:
|
||||
crystal_names = list(self.crystal_list().keys())
|
||||
input_message = "Select the crystal to delete:\nq) quit\n"
|
||||
for index, crystal in enumerate(crystal_names):
|
||||
input_message += f'{index:2}) {crystal:15}\n'
|
||||
input_message += 'Your choice: '
|
||||
idx = ''
|
||||
while idx not in range(len(crystal_names)):
|
||||
if idx == 'q':
|
||||
break
|
||||
idx = int(input(input_message))
|
||||
print(f'Selected crystal: {crystal_names[idx]}')
|
||||
name = crystal_names[idx]
|
||||
sure = "n"
|
||||
sure = input(
|
||||
f"are you sure you want to permanently remove the crystal {name} and its UB matrix and memories (y/n)? "
|
||||
)
|
||||
if sure == "y":
|
||||
crystals = self.crystal_list()
|
||||
meta = crystals[name]
|
||||
if self.diffractometer.name in meta:
|
||||
self.deactivate_crystal(name=name)
|
||||
removed = crystals.pop(name)
|
||||
del removed
|
||||
self.crystal_list.mv(crystals)
|
||||
attrs = [
|
||||
"unit_cell",
|
||||
"u_matrix",
|
||||
"ub_matrix",
|
||||
"orientations",
|
||||
"reflections",
|
||||
"constraints",
|
||||
]
|
||||
for a in attrs:
|
||||
if os.path.exists(
|
||||
f"/photonics/home/gac-bernina/eco/configuration/crystals/{name}_{a}"
|
||||
):
|
||||
os.remove(
|
||||
f"/photonics/home/gac-bernina/eco/configuration/crystals/{name}_{a}"
|
||||
)
|
||||
|
||||
def activate_crystal(self, name=None):
|
||||
crystals = self.crystal_list()
|
||||
if name==None:
|
||||
inactive_crystals = [k for k in crystals.keys() if not self.diffractometer.name in crystals[k]]
|
||||
idx = ''
|
||||
input_message = "Select the crystal to activate:\nq) quit\n"
|
||||
for index, crystal in enumerate(inactive_crystals):
|
||||
input_message += f'{index:2}) {crystal:15}\n'
|
||||
input_message += 'Your choice: '
|
||||
while idx not in range(len(inactive_crystals)):
|
||||
if idx == 'q':
|
||||
break
|
||||
idx = int(input(input_message))
|
||||
print(f'Activated crystal: {inactive_crystals[idx]}')
|
||||
name = inactive_crystals[idx]
|
||||
self._append(
|
||||
DiffGeometryYou,
|
||||
diffractometer_you=self.diffractometer,
|
||||
name=name,
|
||||
is_setting=True,
|
||||
is_display=False,
|
||||
)
|
||||
meta = crystals[name]
|
||||
if not self.diffractometer.name in meta:
|
||||
meta = meta + [self.diffractometer.name]
|
||||
crystals[name] = meta
|
||||
self.crystal_list.mv(crystals)
|
||||
|
||||
def deactivate_crystal(self, name=None):
|
||||
crystals = self.crystal_list()
|
||||
if name==None:
|
||||
active_crystals = [k for k in crystals.keys() if self.diffractometer.name in crystals[k]]
|
||||
idx = ''
|
||||
input_message = "Select the crystal to activate:\nq) quit\n"
|
||||
for index, crystal in enumerate(active_crystals):
|
||||
input_message += f'{index:2}) {crystal:15}\n'
|
||||
input_message += 'Your choice: '
|
||||
while idx not in range(len(active_crystals)):
|
||||
if idx == "q":
|
||||
break
|
||||
idx = int(input(input_message))
|
||||
print(f'Selected crystal: {active_crystals[idx]}')
|
||||
name = active_crystals[idx]
|
||||
meta = crystals[name]
|
||||
if self.diffractometer.name in meta:
|
||||
i = meta.index(self.diffractometer.name)
|
||||
meta.pop(i)
|
||||
crystals[name] = meta
|
||||
self.crystal_list.mv(crystals)
|
||||
removed = self.__dict__.pop(name)
|
||||
self.alias.pop_object(removed.alias)
|
||||
del removed
|
||||
|
||||
class DiffGeometryYou(Assembly):
|
||||
def __init__(self, diffractometer_you=None, name=None):
|
||||
super().__init__(name=name)
|
||||
# self._append(diffractometer_you,call_obj=False, name='diffractometer')
|
||||
self._append(AdjustableMemory, {}, name="contraints")
|
||||
self._append(AdjustableMemory, {}, name="unit_cell")
|
||||
self._append(AdjustableMemory, {}, name="U_matrix")
|
||||
self._append(AdjustableMemory, {}, name="UB_matrix")
|
||||
self._append(AdjustableMemory, [], name="orientations")
|
||||
self._append(
|
||||
AdjustableFS,
|
||||
f"/photonics/home/gac-bernina/eco/configuration/crystals/{name}_unit_cell",
|
||||
name="unit_cell",
|
||||
default_value={
|
||||
"name": "",
|
||||
"a": 1,
|
||||
"b": 1,
|
||||
"c": 1,
|
||||
"alpha": 90,
|
||||
"beta": 90,
|
||||
"gamma": 90,
|
||||
},
|
||||
is_setting=True,
|
||||
)
|
||||
self._append(
|
||||
AdjustableFS,
|
||||
f"/photonics/home/gac-bernina/eco/configuration/crystals/{name}_u_matrix",
|
||||
name="u_matrix",
|
||||
default_value=[],
|
||||
is_setting=True,
|
||||
is_display=False,
|
||||
)
|
||||
self._append(
|
||||
AdjustableFS,
|
||||
f"/photonics/home/gac-bernina/eco/configuration/crystals/{name}_ub_matrix",
|
||||
name="ub_matrix",
|
||||
default_value=[],
|
||||
is_setting=True,
|
||||
is_display=False,
|
||||
)
|
||||
self._append(
|
||||
AdjustableFS,
|
||||
f"/photonics/home/gac-bernina/eco/configuration/crystals/{name}_orientations",
|
||||
name="orientations",
|
||||
default_value=[],
|
||||
is_setting=True,
|
||||
)
|
||||
self._append(
|
||||
AdjustableFS,
|
||||
f"/photonics/home/gac-bernina/eco/configuration/crystals/{name}_reflections",
|
||||
name="reflections",
|
||||
default_value=[],
|
||||
is_setting=True,
|
||||
)
|
||||
self.diffractometer = diffractometer_you
|
||||
cons = {
|
||||
"mu": None,
|
||||
"eta": None,
|
||||
"chi": None,
|
||||
"phi": None,
|
||||
"delta": None,
|
||||
"nu": None,
|
||||
"a_eq_b": None,
|
||||
"bin_eq_bout": None,
|
||||
"betain": None,
|
||||
"betaout": None,
|
||||
"qaz": None,
|
||||
"naz": None,
|
||||
"alpha": None,
|
||||
"beta": None,
|
||||
"bisect": None,
|
||||
"psi": None,
|
||||
"omega": None,
|
||||
}
|
||||
self._append(
|
||||
AdjustableFS,
|
||||
f"/photonics/home/gac-bernina/eco/configuration/crystals/{name}_constraints",
|
||||
name="_constraints",
|
||||
default_value=cons,
|
||||
is_setting=True,
|
||||
is_display=False,
|
||||
)
|
||||
self._append(
|
||||
AdjustableObject,
|
||||
self._constraints,
|
||||
name="constraints",
|
||||
is_setting=False,
|
||||
is_display="recursive",
|
||||
)
|
||||
|
||||
def get_position_angles(self):
|
||||
nu = self.diffractometer.nu.get_current_value()
|
||||
mu = self.diffractometer.mu.get_current_value()
|
||||
delta = self.diffractometer.delta.get_current_value()
|
||||
eta = self.diffractometer.eta.get_current_value()
|
||||
chi = self.diffractometer.chi.get_current_value()
|
||||
phi = self.diffractometer.phi.get_current_value()
|
||||
|
||||
adjs = ["nu", "mu", "delta", "eta", "chi", "phi"]
|
||||
cfg = []
|
||||
if hasattr(self.diffractometer, "configuration"):
|
||||
cfg = self.diffractometer.configuration
|
||||
if "kappa" in cfg:
|
||||
adjs = ["nu", "mu", "delta", "eta_kap", "kappa", "phi_kap"]
|
||||
self._diff_adjs = {
|
||||
adj: self.diffractometer.__dict__[adj] if adj in self.diffractometer.__dict__.keys() else DummyAdjustable(name = adj+"dummy")
|
||||
for adj in adjs
|
||||
}
|
||||
|
||||
def get_h(*args, **kwargs):
|
||||
return self.calc_hkl()[0]
|
||||
|
||||
def set_h(val):
|
||||
return self._calc_angles_unique_diffractometer([val, None, None])
|
||||
|
||||
def get_k(*args, **kwargs):
|
||||
return self.calc_hkl()[1]
|
||||
|
||||
def set_k(val):
|
||||
return self._calc_angles_unique_diffractometer([None, val, None])
|
||||
|
||||
def get_l(*args, **kwargs):
|
||||
return self.calc_hkl()[2]
|
||||
|
||||
def set_l(val):
|
||||
return self._calc_angles_unique_diffractometer([None, None, val])
|
||||
|
||||
def get_hkl(*args, **kwargs):
|
||||
return self.calc_hkl()
|
||||
|
||||
def set_hkl(val):
|
||||
return self._calc_angles_unique_diffractometer(val)
|
||||
|
||||
self._append(
|
||||
AdjustableVirtual, list(self._diff_adjs.values()), get_h, set_h, name="h"
|
||||
)
|
||||
self._append(
|
||||
AdjustableVirtual, list(self._diff_adjs.values()), get_k, set_k, name="k"
|
||||
)
|
||||
self._append(
|
||||
AdjustableVirtual, list(self._diff_adjs.values()), get_l, set_l, name="l"
|
||||
)
|
||||
self._append(
|
||||
AdjustableVirtual,
|
||||
list(self._diff_adjs.values()),
|
||||
get_hkl,
|
||||
self._calc_angles_unique_diffractometer,
|
||||
name="hkl",
|
||||
)
|
||||
self.recalculate()
|
||||
|
||||
def convert_from_you(self, **kwargs):
|
||||
cfg = self.diffractometer.configuration
|
||||
if "kappa" in cfg:
|
||||
eta_kap, kappa, phi_kap = self.diffractometer.calc_you2kappa(
|
||||
kwargs["eta"], kwargs["chi"], kwargs["phi"]
|
||||
)
|
||||
kwargs.update({"eta_kap": eta_kap, "kappa": kappa, "phi_kap": phi_kap})
|
||||
return {key:kwargs[key] for key in self._diff_adjs.keys()}
|
||||
|
||||
def convert_to_you(
|
||||
self,
|
||||
nu=None,
|
||||
mu=None,
|
||||
delta=None,
|
||||
eta=None,
|
||||
chi=None,
|
||||
phi=None,
|
||||
eta_kap=None,
|
||||
kappa=None,
|
||||
phi_kap=None,
|
||||
):
|
||||
cfg = self.diffractometer.configuration
|
||||
if "kappa" in cfg:
|
||||
eta, chi, phi = self.diffractometer.calc_kappa2you(eta_kap, kappa, phi_kap)
|
||||
return nu, mu, delta, eta, chi, phi
|
||||
|
||||
def get_diffractometer_angles(self):
|
||||
### assume that all angles exist in diffractometer at least as manual adjustable ###
|
||||
nu, mu, delta, eta, chi, phi = self.convert_to_you(
|
||||
**{key: adj() for key, adj in self._diff_adjs.items()}
|
||||
)
|
||||
return mu, delta, nu, eta, chi, phi
|
||||
|
||||
def _calc_angles_unique_diffractometer(self, hkl):
|
||||
angles = self.calc_angles_unique(*hkl)
|
||||
angles_diff_dict = self.convert_from_you(**angles)
|
||||
return [angles_diff_dict[tk] for tk in self._diff_adjs.keys()]
|
||||
|
||||
def check_target_value_within_limits(self, **kwargs):
|
||||
### virtual adjustables got a new function check_target_value_within_limits(values)
|
||||
in_lims = []
|
||||
target_dict = self.convert_from_you(**kwargs)
|
||||
for axname, target_value in target_dict.items():
|
||||
adj = self._diff_adjs[axname]
|
||||
|
||||
# for val, adj in zip(target_dict, self._diff_adjs.values()):
|
||||
if hasattr(adj, "get_limits"):
|
||||
lim_low, lim_high = adj.get_limits()
|
||||
in_lims.append((lim_low < target_value) and (target_value < lim_high))
|
||||
# print(axname,lim_low,target_value,lim_high)
|
||||
else:
|
||||
raise Exception(f"Failed to get limits of adjustable {adj.name}")
|
||||
return all(in_lims)
|
||||
|
||||
def new_ub(self):
|
||||
### missing: clear ub ###
|
||||
### missing: check ub ###
|
||||
crystal_name = input(f"Name of the crystal: ({self.name})" or str(self.name))
|
||||
a = float(input(f"Lattice constant a (1): ") or 1)
|
||||
b = float(input(f"Lattice constant b ({a}): ") or a)
|
||||
c = float(input(f"Lattice constant c ({a}): ") or a)
|
||||
alpha = float(input("Angle alpha (90): ") or 90)
|
||||
beta = float(input(f"Angle beta ({alpha}): ") or alpha)
|
||||
gamma = float(input(f"Angle gamma ({alpha}): ") or alpha)
|
||||
im = Image.open(
|
||||
"/photonics/home/gac-bernina/eco/configuration/crystals/you_diffractometer.png"
|
||||
)
|
||||
normal = [
|
||||
float(val)
|
||||
for val in input(
|
||||
"(h,k,l) surface normal (along YOU z-axis), e.g. 0,0,1: "
|
||||
).split(",")
|
||||
or [0, 0, 1]
|
||||
]
|
||||
inplane = [
|
||||
float(val)
|
||||
for val in input(
|
||||
"(h,k,l) in-plane orientation along beam (YOU y-axis), e.g. 1,0,0: "
|
||||
).split(",")
|
||||
or [1, 0, 0]
|
||||
]
|
||||
self.set_unit_cell(crystal_name, a, b, c, alpha, beta, gamma)
|
||||
self.add_orientation(normal, (0, 0, 1), tag="surface normal")
|
||||
self.add_orientation(
|
||||
inplane, (0, 1, 0), tag="in-plane along x-ray beam direction"
|
||||
)
|
||||
self.calc_ub()
|
||||
print(
|
||||
"UB was calculated - next please set the constraints (.constraints) and the limits of the diffractometer motors"
|
||||
)
|
||||
|
||||
def set_unit_cell(
|
||||
self, name_crystal, a=None, b=None, c=None, alpha=None, beta=None, gamma=None
|
||||
):
|
||||
@@ -70,16 +434,28 @@ class DiffGeometryYou(Assembly):
|
||||
|
||||
def recalculate(self):
|
||||
self.ubcalc = dccalc.UBCalculation("you")
|
||||
# self.ubcalc.n_phi = [0,0,1]
|
||||
uc = self.unit_cell()
|
||||
self.ubcalc.set_lattice(uc.pop("name"), **uc)
|
||||
for ori in self.orientations():
|
||||
self.ubcalc.add_orientation(ori.pop("hkl"), ori.pop("xyz"), **ori)
|
||||
for refl in self.reflections():
|
||||
position = Position(*refl.pop("position"))
|
||||
self.ubcalc.add_reflection(
|
||||
refl.pop("hkl"), position, refl.pop("energy") * 1e-3, **refl
|
||||
)
|
||||
self._u_ub_to_dc()
|
||||
|
||||
def add_reflection(
|
||||
self,
|
||||
hkl,
|
||||
position,
|
||||
energy,
|
||||
mu=None,
|
||||
delta=None,
|
||||
nu=None,
|
||||
eta=None,
|
||||
chi=None,
|
||||
phi=None,
|
||||
energy=None,
|
||||
tag=None,
|
||||
):
|
||||
"""Add a reference reflection.
|
||||
@@ -91,20 +467,43 @@ class DiffGeometryYou(Assembly):
|
||||
----------
|
||||
hkl : Tuple[float, float, float]
|
||||
hkl index of the reflection
|
||||
position: Position
|
||||
list of diffractometer angles in internal representation in degrees
|
||||
mu, delta, nu, eta, chi, phi: float
|
||||
diffractometer angles in degrees, if not given, the current diffractometer angles are used
|
||||
energy : float
|
||||
energy of the x-ray beam
|
||||
energy of the x-ray beam, if not given, the mono or machine energy are used depending on the beamline mode
|
||||
tag : Optional[str], default = None
|
||||
identifying tag for the reflection
|
||||
"""
|
||||
|
||||
setvals = [mu, delta, nu, eta, chi, phi]
|
||||
curvals = self.get_diffractometer_angles()
|
||||
angs = [
|
||||
curval if setval == None else setval
|
||||
for setval, curval in zip(setvals, curvals)
|
||||
]
|
||||
if energy is None:
|
||||
energy = self.get_energy()
|
||||
position = Position(*angs)
|
||||
self.ubcalc.add_reflection(hkl, position, energy, tag=tag)
|
||||
self.reflections.set_target_value(
|
||||
self.reflections()
|
||||
+ [{"hkl": hkl, "position": position, "energy": energy, "tag": tag}]
|
||||
+ [{"hkl": hkl, "position": angs, "energy": energy, "tag": tag}]
|
||||
)
|
||||
|
||||
def del_reflection(self, idx):
|
||||
"""Delete a reference reflection.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
idx : int
|
||||
index of the deleted reflection
|
||||
"""
|
||||
self.ubcalc.del_reflection(idx)
|
||||
refls = self.reflections()
|
||||
removed = refls.pop(idx)
|
||||
self.reflections.set_target_value(refls)
|
||||
print(f"Removed reflection {removed}")
|
||||
self.recalculate()
|
||||
|
||||
def add_orientation(self, hkl, xyz, position=None, tag=None):
|
||||
"""Add a reference orientation.
|
||||
|
||||
@@ -122,19 +521,270 @@ class DiffGeometryYou(Assembly):
|
||||
tag : str
|
||||
identifying tag for the reflection
|
||||
"""
|
||||
self.recalculate()
|
||||
self.ubcalc.add_orientation(hkl, xyz, position=None, tag=None)
|
||||
self.orientations.set_target_value(
|
||||
self.orientations()
|
||||
+ [{"hkl": hkl, "xyz": xyz, "position": position, "tag": tag}]
|
||||
)
|
||||
self.recalculate()
|
||||
|
||||
def calc_ub(self, *args, **kwargs):
|
||||
self.ubcalc.calc_ub(*args, **kwargs)
|
||||
def del_orientation(self, idx):
|
||||
"""Delete a reference reflection.
|
||||
|
||||
def fit_ub(self, *args, **kwargs):
|
||||
self.ubcalc.fit_ub(*args, **kwargs)
|
||||
Parameters
|
||||
----------
|
||||
idx : int
|
||||
index of the deleted reflection
|
||||
"""
|
||||
refls = self.orientations()
|
||||
removed = refls.pop(idx)
|
||||
self.orientations.set_target_value(refls)
|
||||
print(f"Removed reflection {removed}")
|
||||
self.recalculate()
|
||||
|
||||
def calc_ub(self, idx1=0, idx2=1):
|
||||
"""Calculate UB matrix.
|
||||
|
||||
Calculate UB matrix using two reference reflections and/or
|
||||
reference orientations.
|
||||
|
||||
By default use the first two reference reflections when provided.
|
||||
If one or both reflections are not available use one or two reference
|
||||
orientations to complement mission reflection data.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
idx1: int or str, optional
|
||||
The index or the tag of the first reflection or orientation.
|
||||
idx2: int or str, optional
|
||||
The index or the tag of the second reflection or orientation.
|
||||
"""
|
||||
self.recalculate()
|
||||
self.ubcalc.calc_ub(idx1, idx2)
|
||||
self._u_ub_from_dc()
|
||||
|
||||
def show_you_geometry(self):
|
||||
im = Image.open(
|
||||
"/photonics/home/gac-bernina/eco/configuration/crystals/you_diffractometer.png"
|
||||
)
|
||||
im.show()
|
||||
|
||||
def refine_ub(
|
||||
self,
|
||||
hkl,
|
||||
mu=None,
|
||||
delta=None,
|
||||
nu=None,
|
||||
eta=None,
|
||||
chi=None,
|
||||
phi=None,
|
||||
energy=None,
|
||||
refine_lattice=False,
|
||||
refine_umatrix=False,
|
||||
):
|
||||
"""
|
||||
Refine UB matrix to using single reflection.
|
||||
|
||||
Refine UB matrix to match diffractometer position for the specified
|
||||
reflection. Refined U matrix will be accurate up to an azimuthal rotation
|
||||
around the specified scattering vector.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
hkl: Tuple[float, float, float] Miller indices of the reflection.
|
||||
pos: Position Diffractometer position object.
|
||||
wavelength: float Radiation wavelength.
|
||||
refine_lattice: Optional[bool], default = False
|
||||
|
||||
Apply refined lattice parameters to the current UB calculation object.
|
||||
refine_umatrix: Optional[bool], default = False
|
||||
Apply refined U matrix to the current UB calculation object.
|
||||
|
||||
Returns
|
||||
-------
|
||||
Tuple[np.ndarray, Tuple[str, float, float, float, float, float, float]]
|
||||
Refined U matrix as NumPy array and refined crystal lattice parameters.
|
||||
|
||||
"""
|
||||
if refine_lattice:
|
||||
print("fitting the lattice is not yet implemented")
|
||||
return
|
||||
setvals = [mu, delta, nu, eta, chi, phi]
|
||||
curvals = self.get_diffractometer_angles()
|
||||
angs = [
|
||||
curval if setval == None else setval
|
||||
for setval, curval in zip(setvals, curvals)
|
||||
]
|
||||
if energy is None:
|
||||
energy = self.get_energy()
|
||||
wl = self.en2lam(energy)
|
||||
position = Position(*angs)
|
||||
self.recalculate()
|
||||
self.ubcalc.refine_ub(
|
||||
hkl,
|
||||
position=position,
|
||||
wavelength=wl,
|
||||
refine_lattice=refine_lattice,
|
||||
refine_umatrix=refine_umatrix,
|
||||
)
|
||||
self._u_ub_from_dc()
|
||||
|
||||
def fit_ub(self, indices=None, refine_lattice=False, refine_umatrix=True):
|
||||
"""Refine UB matrix using reference reflections.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
indices: Sequence[Union[str, int]]
|
||||
List of reference reflection indices or tags.
|
||||
refine_lattice: Optional[bool], default = False
|
||||
Apply refined lattice parameters to the current UB calculation object.
|
||||
refine_umatrix: Optional[bool], default = False
|
||||
Apply refined U matrix to the current UB calculation object.
|
||||
|
||||
Returns
|
||||
-------
|
||||
Tuple[np.ndarray, Tuple[str, float, float, float, float, float, float]]
|
||||
Refined U matrix as NumPy array and refined crystal lattice parameters.
|
||||
"""
|
||||
self.recalculate()
|
||||
if indices is None:
|
||||
indices = list(range(len(self.reflections())))
|
||||
ub, lat = self.ubcalc.fit_ub(
|
||||
indices, refine_lattice=refine_lattice, refine_umatrix=refine_umatrix
|
||||
)
|
||||
if refine_umatrix:
|
||||
print("\nFitted UB matrix applied")
|
||||
else:
|
||||
print(
|
||||
"\nFitted UB matrix not applied. To apply it, set refine_umatrix=True"
|
||||
)
|
||||
print(ub)
|
||||
if refine_lattice:
|
||||
print("\nFitted lattice applied")
|
||||
else:
|
||||
print("\nFitted lattice not applied. To apply it, set refine_lattice=True")
|
||||
for k, val in {
|
||||
"name": lat[0],
|
||||
"a": lat[1],
|
||||
"b": lat[2],
|
||||
"c": lat[3],
|
||||
"alpha": lat[4],
|
||||
"beta": lat[5],
|
||||
"gamma": lat[6],
|
||||
}.items():
|
||||
print(f"{k:8}: {val}")
|
||||
self._u_ub_from_dc()
|
||||
if refine_lattice:
|
||||
self._lat_from_dc()
|
||||
|
||||
def calc_angles(self, h=None, k=None, l=None, energy=None):
|
||||
"""calculate diffractometer angles for a given h,k,l and energy in eV.
|
||||
If any of the h, k, l are not given, their current value is used instead.
|
||||
energy: float energy of the x-ray beam, if not given, the mono or machine energy are used depending on the beamline mode
|
||||
Shows all solutions neglecting diffractometer limits"""
|
||||
setvals = [h, k, l]
|
||||
curvals = [self.h, self.k, self.l]
|
||||
h, k, l = [
|
||||
curval() if setval == None else setval
|
||||
for setval, curval in zip(setvals, curvals)
|
||||
]
|
||||
self.recalculate()
|
||||
cons = Constraints(self._constraints())
|
||||
hklcalc = HklCalculation(self.ubcalc, cons)
|
||||
if energy is None:
|
||||
energy = self.get_energy()
|
||||
lam = self.en2lam(energy)
|
||||
result = hklcalc.get_position(h, k, l, lam)
|
||||
result = pd.concat(
|
||||
[
|
||||
pd.DataFrame.from_dict(
|
||||
{**tres[0].asdict, **tres[1]}, orient="index", columns=[f"sol. {n}"]
|
||||
)
|
||||
for n, tres in enumerate(result)
|
||||
],
|
||||
axis=1,
|
||||
)
|
||||
return result.T
|
||||
|
||||
def calc_angles_unique(self, h=None, k=None, l=None, energy=None):
|
||||
"""calculate unique solution of diffractometer angles for a given h,k,l and energy in eV.
|
||||
If any of the h, k, l are not given, their current value is used instead.
|
||||
If the energy is not given, the monochromator energy is used."""
|
||||
df = self.calc_angles(h, k, l, energy)
|
||||
in_lims = np.array(
|
||||
[
|
||||
self.check_target_value_within_limits(**df.loc[idx].to_dict())
|
||||
for idx in df.index
|
||||
]
|
||||
)
|
||||
idx_in = df.index[in_lims]
|
||||
idx_out = df.index[~in_lims]
|
||||
|
||||
if len(idx_in) > 1:
|
||||
print(
|
||||
f"There is not a unique angular configuration to reach ({h},{k},{l}), please change the diffractometer motor soft limits to allow only one of the solutions shown below:"
|
||||
)
|
||||
print(df.loc[idx_in])
|
||||
raise Exception("No unique solution")
|
||||
elif len(idx_in) == 0:
|
||||
print(
|
||||
"There is no angular configuration, which is allowed for the current diffractometer motor soft limits. please check the diffractometer limits."
|
||||
)
|
||||
print("Solutions")
|
||||
print(df)
|
||||
raise Exception("No unique solution")
|
||||
solution_unique = df.loc[idx_in[0]]
|
||||
|
||||
return solution_unique.to_dict()
|
||||
|
||||
def calc_hkl(
|
||||
self, mu=None, delta=None, nu=None, eta=None, chi=None, phi=None, energy=None
|
||||
):
|
||||
"""calculate (h,k,l) for given diffractometer angles and energy in eV.
|
||||
If any of the diffractometer angles are not given, their current value is used instead.
|
||||
If the energy is not given, the monochromator energy is used"""
|
||||
setvals = [mu, delta, nu, eta, chi, phi]
|
||||
curvals = self.get_diffractometer_angles()
|
||||
angs = [
|
||||
curval if setval == None else setval
|
||||
for setval, curval in zip(setvals, curvals)
|
||||
]
|
||||
pos = Position(*angs)
|
||||
self.recalculate()
|
||||
if energy is None:
|
||||
energy = self.get_energy()
|
||||
lam = self.en2lam(energy)
|
||||
cons = Constraints(self._constraints())
|
||||
hklcalc = HklCalculation(self.ubcalc, cons)
|
||||
try:
|
||||
hkl = hklcalc.get_hkl(pos=pos, wavelength=lam)
|
||||
except Exception as e:
|
||||
print(str(e))
|
||||
return
|
||||
return hkl
|
||||
|
||||
def get_energy(self):
|
||||
energy = PV("SAROP21-ARAMIS:ENERGY").value
|
||||
return energy
|
||||
|
||||
def _u_ub_from_dc(self):
|
||||
self.ub_matrix(self.ubcalc.UB.tolist())
|
||||
self.u_matrix(self.ubcalc.U.tolist())
|
||||
|
||||
def _u_ub_to_dc(self):
|
||||
if len(self.ub_matrix()) > 0:
|
||||
self.ubcalc.set_ub(self.ub_matrix())
|
||||
self.ubcalc.set_u(self.u_matrix())
|
||||
|
||||
def _lat_from_dc(self):
|
||||
self.set_unit_cell(*self.ubcalc.crystal.get_lattice())
|
||||
|
||||
def en2lam(self, en):
|
||||
"""input: energy in eV, returns wavelength in A"""
|
||||
return 12398.419843320025 / en
|
||||
|
||||
def lam2en(self, lam):
|
||||
"""input: wavelength in A, returns energy in eV"""
|
||||
return 12398.419843320025 / lam
|
||||
|
||||
pass
|
||||
# def __init__(sel):
|
||||
|
||||
+112
-694
@@ -8,7 +8,7 @@ from subprocess import call
|
||||
|
||||
warnings.simplefilter(action="ignore", category=pd.errors.PerformanceWarning)
|
||||
warnings.simplefilter(action="ignore", category=UserWarning)
|
||||
|
||||
import timeit
|
||||
import os
|
||||
from pathlib import Path
|
||||
from epics import PV
|
||||
@@ -32,675 +32,6 @@ pd.options.display.width = None
|
||||
pd.set_option("display.float_format", lambda x: "%.5g" % x)
|
||||
|
||||
|
||||
class Run_Table:
|
||||
def __init__(
|
||||
self,
|
||||
pgroup=None,
|
||||
devices=None,
|
||||
channels_ca={"pulse_id": "SLAAR11-LTIM01-EVR0:RX-PULSEID"},
|
||||
name=None,
|
||||
):
|
||||
|
||||
### Load device and alias_namespace after init of other devices ###
|
||||
devices = eco.__dict__[devices]
|
||||
self.devices = devices
|
||||
self.name = name
|
||||
self.adj_df = DataFrame()
|
||||
self.unit_df = DataFrame()
|
||||
self.gspread_key_df = None
|
||||
self.gspread_key_file_name = (
|
||||
f"/sf/bernina/config/src/python/gspread/gspread_keys"
|
||||
)
|
||||
|
||||
self._channels_ca = channels_ca
|
||||
|
||||
### credentials and settings for uploading to gspread ###
|
||||
self._scope = [
|
||||
"https://spreadsheets.google.com/feeds",
|
||||
"https://www.googleapis.com/auth/drive",
|
||||
]
|
||||
self._credentials = ServiceAccountCredentials.from_json_keyfile_name(
|
||||
"/sf/bernina/config/src/python/gspread/pandas_push", self._scope
|
||||
)
|
||||
self.gc = gspread.authorize(self._credentials)
|
||||
self.keys = "metadata midir xrd energy transmission delay lxt pulse_id att_self att_fe_self"
|
||||
self.key_order = "metadata xrd midir env_thc temperature1_rbk temperature2_rbk time name gps gps_hex thc ocb eos las lxt phase_shifter mono att att_fe slit_und slit_switch slit_att slit_kb slit_cleanup pulse_id mono_energy_rbk att_transmission att_fe_transmission"
|
||||
spreadsheet_key = (None,)
|
||||
self.init_runtable(pgroup)
|
||||
|
||||
### dicts holding adjustables and bad (not connected) adjustables ###
|
||||
self.adjustables = {}
|
||||
self.bad_adjustables = {}
|
||||
self.units = {}
|
||||
|
||||
###parsing options
|
||||
self._parse_exclude_keys = "status_indicators settings_collection status_indicators_collection presets memory _elog _currentChange _flags __ alias namespace daq scan evr _motor Alias".split(
|
||||
" "
|
||||
)
|
||||
self._parse_exclude_class_types = (
|
||||
"__ alias namespace daq scan evr _motor Alias AdjustablePv AxisPTZ".split(
|
||||
" "
|
||||
)
|
||||
)
|
||||
self._adj_exclude_class_types = (
|
||||
"__ alias namespace daq scan evr _motor Alias".split(" ")
|
||||
)
|
||||
|
||||
pd.options.display.max_rows = 100
|
||||
pd.options.display.max_columns = 50
|
||||
pd.set_option("display.float_format", lambda x: "%.5g" % x)
|
||||
|
||||
def create_rt_spreadsheet(self, pgroup):
|
||||
self.gc = gspread.authorize(self._credentials)
|
||||
spreadsheet = self.gc.create(
|
||||
title=f"run_table_{pgroup}", folder_id="1F7DgF0HW1O71nETpfrTvQ35lRZCs5GvH"
|
||||
)
|
||||
spreadsheet.add_worksheet("runtable", 10, 10)
|
||||
spreadsheet.add_worksheet("positions", 10, 10)
|
||||
ws = spreadsheet.get_worksheet(0)
|
||||
spreadsheet.del_worksheet(ws)
|
||||
return spreadsheet
|
||||
|
||||
def _append_to_gspread_key_df(self, gspread_key_df):
|
||||
if os.path.exists(self.gspread_key_file_name + ".pkl"):
|
||||
self.gspread_key_df = pd.read_pickle(self.gspread_key_file_name + ".pkl")
|
||||
self.gspread_key_df = self.gspread_key_df.append(gspread_key_df)
|
||||
self.gspread_key_df.to_pickle(self.gspread_key_file_name + ".pkl")
|
||||
else:
|
||||
self.gspread_key_df.to_pickle(self.gspread_key_file_name + ".pkl")
|
||||
|
||||
def init_runtable(self, pgroup):
|
||||
if os.path.exists(self.gspread_key_file_name + ".pkl"):
|
||||
self.gspread_key_df = pd.read_pickle(self.gspread_key_file_name + ".pkl")
|
||||
if self.gspread_key_df is not None and str(pgroup) in self.gspread_key_df.index:
|
||||
spreadsheet_key = self.gspread_key_df["keys"][f"{pgroup}"]
|
||||
else:
|
||||
f_create = str(
|
||||
input(
|
||||
f"No google spreadsheet id found for pgroup {pgroup}. Create new run_table spreadsheet? (y/n) "
|
||||
)
|
||||
)
|
||||
if f_create == "y":
|
||||
print("creating")
|
||||
spreadsheet = self.create_rt_spreadsheet(pgroup=pgroup)
|
||||
print("created")
|
||||
gspread_key_df = DataFrame(
|
||||
{"keys": [spreadsheet.id]}, index=[f"{pgroup}"]
|
||||
)
|
||||
spreadsheet_key = spreadsheet.id
|
||||
else:
|
||||
f_entermanually = input(
|
||||
f"Do you want to enter a spreadsheet key for the pgroup {pgroup}? (y/n)"
|
||||
)
|
||||
if f_entermanually != "y":
|
||||
print("Runtable not initialized")
|
||||
return
|
||||
spreadsheet_key = str(
|
||||
input(
|
||||
f"Please enter the google spreadsheet key, e.g. 1gK--KePLpYCs7U3QfNSPo69XipndbINe1Iz8to9bY1U: "
|
||||
)
|
||||
)
|
||||
gspread_key_df = DataFrame(
|
||||
{"keys": [spreadsheet_key]}, index=[f"{pgroup}"]
|
||||
)
|
||||
self._append_to_gspread_key_df(gspread_key_df)
|
||||
self._spreadsheet_key = spreadsheet_key
|
||||
# self.alias_file_name = (
|
||||
# f"/sf/bernina/data/{pgroup}/res/runtables/{pgroup}_alias_runtable"
|
||||
# )
|
||||
self.adj_file_name = (
|
||||
f"/sf/bernina/data/{pgroup}/res/runtables/{pgroup}_adjustable_runtable"
|
||||
)
|
||||
self.unit_file_name = (
|
||||
f"/sf/bernina/data/{pgroup}/res/runtables/{pgroup}_unit_runtable"
|
||||
)
|
||||
self.load()
|
||||
return
|
||||
|
||||
def _query_by_keys(self, keys="", df=None):
|
||||
if df is None:
|
||||
df = self.adj_df
|
||||
keys = keys.split(" ")
|
||||
if len(df.columns[0]) > 1:
|
||||
query_df = df[
|
||||
df.columns[
|
||||
np.array(
|
||||
[
|
||||
np.any([np.any([x in i for x in keys]) for i in col])
|
||||
for col in df.columns
|
||||
]
|
||||
)
|
||||
]
|
||||
]
|
||||
else:
|
||||
query_df = df[
|
||||
df.columns[
|
||||
np.array([np.any([x in col for x in keys]) for col in df.columns])
|
||||
]
|
||||
]
|
||||
return query_df
|
||||
|
||||
def query(self, keys="", index=None, values=None, df=None):
|
||||
"""
|
||||
function to show saved data. keys is a string with keys separated by a space.
|
||||
All columns, which contain any of these strings are returned. self.prefix
|
||||
+ f"{runno:{self.Ndigits}0d}"
|
||||
+ self.separator
|
||||
+ "*."
|
||||
+ self.suffix
|
||||
Index can be a list od indices.
|
||||
|
||||
example: query(keys='xrd delay name', index = [0,5])
|
||||
will return all columns containing either xrd or delay and show the data for runs 0 and 5
|
||||
|
||||
example 2: query(keys = 'xrd delay name', index = ['p1', 'p2'])
|
||||
will return the same columns for the saved positions 1 and 2
|
||||
"""
|
||||
self.load()
|
||||
# if len(keys) > 0:
|
||||
# keys += " name"
|
||||
query_df = self._query_by_keys(keys, df)
|
||||
if not values is None:
|
||||
query_df = query_df.query(values)
|
||||
query_df = query_df.T
|
||||
if not index is None:
|
||||
query_df = query_df[index]
|
||||
return query_df
|
||||
|
||||
def _get_values(self):
|
||||
is_connected = np.array([pv.connected for pv in self._pvs.values()])
|
||||
filtered_dict = {key: pv.value for key, pv in self._pvs.items() if pv.connected}
|
||||
return filtered_dict
|
||||
|
||||
def _remove_duplicates(self):
|
||||
self.adj_df = self.adj_df[~self.adj_df.index.duplicated(keep="last")]
|
||||
# self.alias_df = self.alias_df[~self.alias_df.index.duplicated(keep="last")]
|
||||
self.unit_df = self.unit_df[~self.unit_df.index.duplicated(keep="last")]
|
||||
|
||||
def save(self):
|
||||
data_dir = Path(os.path.dirname(self.adj_file_name + ".pkl"))
|
||||
if not data_dir.exists():
|
||||
print(
|
||||
f"Path {data_dir.absolute().as_posix()} does not exist, will try to create it..."
|
||||
)
|
||||
data_dir.mkdir(parents=True)
|
||||
print(f"Tried to create {data_dir.absolute().as_posix()}")
|
||||
data_dir.chmod(0o775)
|
||||
print(f"Tried to change permissions to 775")
|
||||
# self.alias_df.to_pickle(self.alias_file_name + ".pkl")
|
||||
self.adj_df.to_pickle(self.adj_file_name + ".pkl")
|
||||
self.unit_df.to_pickle(self.unit_file_name + ".pkl")
|
||||
|
||||
def load(self):
|
||||
# if os.path.exists(self.alias_file_name + ".pkl"):
|
||||
# self.alias_df = pd.read_pickle(self.alias_file_name + ".pkl")
|
||||
if os.path.exists(self.adj_file_name + ".pkl"):
|
||||
self.adj_df = pd.read_pickle(self.adj_file_name + ".pkl")
|
||||
if os.path.exists(self.unit_file_name + ".pkl"):
|
||||
self.unit_df = pd.read_pickle(self.unit_file_name + ".pkl")
|
||||
|
||||
def append_run(
|
||||
self,
|
||||
runno,
|
||||
metadata={
|
||||
"type": "ascan",
|
||||
"name": "phi scan (001)",
|
||||
"scan_motor": "phi",
|
||||
"from": 1,
|
||||
"to": 2,
|
||||
"steps": 51,
|
||||
},
|
||||
):
|
||||
self.load()
|
||||
if len(self.adjustables) == 0:
|
||||
self._parse_parent_fewerparents()
|
||||
# dat = self._get_values()
|
||||
# dat.update(metadata)
|
||||
# dat["time"] = datetime.now()
|
||||
# run_df = DataFrame([dat.values()], columns=dat.keys(), index=[runno])
|
||||
# self.alias_df = self.alias_df.append(run_df)
|
||||
|
||||
dat = self._get_adjustable_values()
|
||||
dat["metadata"] = metadata
|
||||
dat["metadata"]["time"] = datetime.now()
|
||||
names = ["device", "adjustable"]
|
||||
multiindex = pd.MultiIndex.from_tuples(
|
||||
[(dev, adj) for dev in dat.keys() for adj in dat[dev].keys()], names=names
|
||||
)
|
||||
values = np.array([val for adjs in dat.values() for val in adjs.values()])
|
||||
run_df = DataFrame([values], columns=multiindex, index=[runno])
|
||||
self.adj_df = self.adj_df.append(run_df)
|
||||
multiindex_u = pd.MultiIndex.from_tuples(
|
||||
[(dev, adj) for dev in self.units.keys() for adj in self.units[dev].keys()],
|
||||
names=names,
|
||||
)
|
||||
values_u = np.array(
|
||||
[val for adjs in self.units.values() for val in adjs.values()]
|
||||
)
|
||||
self.unit_df = DataFrame([values_u], columns=multiindex_u, index=["units"])
|
||||
self._remove_duplicates()
|
||||
self.save()
|
||||
self.upload_all()
|
||||
|
||||
def append_pos(self, name=""):
|
||||
self.load()
|
||||
if len(self.adjustables) == 0:
|
||||
self._parse_parent_fewerparents()
|
||||
try:
|
||||
posno = int(self.adj_df.query('type == "pos"').index[-1].split("p")[1]) + 1
|
||||
except:
|
||||
posno = 0
|
||||
# dat = self._get_values()
|
||||
# dat.update([("name", name), ("type", "pos")])
|
||||
# dat["time"] = datetime.now()
|
||||
# pos_df = DataFrame([dat.values()], columns=dat.keys(), index=[f"p{posno}"])
|
||||
# self.alias_df = self.alias_df.append(pos_df)
|
||||
|
||||
dat = self._get_adjustable_values()
|
||||
dat["metadata"] = {"time": datetime.now(), "name": name, "type": "pos"}
|
||||
names = ["device", "adjustable"]
|
||||
multiindex = pd.MultiIndex.from_tuples(
|
||||
[(dev, adj) for dev in dat.keys() for adj in dat[dev].keys()], names=names
|
||||
)
|
||||
values = np.array([val for adjs in dat.values() for val in adjs.values()])
|
||||
pos_df = DataFrame([values], columns=multiindex, index=[f"p{posno}"])
|
||||
self.adj_df = self.adj_df.append(pos_df)
|
||||
multiindex_u = pd.MultiIndex.from_tuples(
|
||||
[(dev, adj) for dev in self.units.keys() for adj in self.units[dev].keys()],
|
||||
names=names,
|
||||
)
|
||||
values_u = np.array(
|
||||
[val for adjs in self.units.values() for val in adjs.values()]
|
||||
)
|
||||
self.unit_df = DataFrame([values_u], columns=multiindex_u, index=["units"])
|
||||
self.save()
|
||||
self.upload_all()
|
||||
|
||||
def upload_rt(self, worksheet="runtable", keys=None, df=None):
|
||||
"""
|
||||
This function uploads all entries of which "type" contains "scan" to the worksheet positions.
|
||||
keys takes a string of keys separated by a space, e.g. 'gps xrd las'. All columns, which contain
|
||||
any of these strings are uploaded. keys = None defaults to self.keys. keys = '' returns all columns
|
||||
"""
|
||||
self.load()
|
||||
self.gc = gspread.authorize(self._credentials)
|
||||
self.order_df()
|
||||
if keys is None:
|
||||
keys = self.keys
|
||||
|
||||
self.ws = self.gc.open_by_key(self._spreadsheet_key).worksheet(worksheet)
|
||||
if len(keys) > 0:
|
||||
keys = keys + " type"
|
||||
upload_df = self._query_by_keys(keys=keys, df=df)
|
||||
else:
|
||||
upload_df = df
|
||||
if df is None:
|
||||
upload_df = self.adj_df
|
||||
upload_df = upload_df[
|
||||
upload_df["metadata"]["type"].str.contains("scan", na=False)
|
||||
]
|
||||
gd.set_with_dataframe(self.ws, upload_df, include_index=True, col=2)
|
||||
gf_dataframe.format_with_dataframe(
|
||||
self.ws, upload_df, include_index=True, include_column_header=True, col=2
|
||||
)
|
||||
|
||||
def upload_pos(self, worksheet="positions", keys=None):
|
||||
"""
|
||||
This function uploads all entries with "type == pos" to the worksheet positions.
|
||||
keys takes a list of strin All columns, which contain any of these strings are uploaded.
|
||||
keys = None defaults to self.keys. keys = [] returns all columns
|
||||
"""
|
||||
self.load()
|
||||
self.gc = gspread.authorize(self._credentials)
|
||||
self.order_df()
|
||||
if keys is None:
|
||||
keys = self.keys
|
||||
|
||||
self.ws = self.gc.open_by_key(self._spreadsheet_key).worksheet(worksheet)
|
||||
if len(keys) > 0:
|
||||
keys = keys + " metadata"
|
||||
upload_df = self._query_by_keys(keys=keys)
|
||||
else:
|
||||
upload_df = self.adj_df
|
||||
upload_df = upload_df[
|
||||
upload_df["metadata"]["type"].str.contains("pos", na=False)
|
||||
]
|
||||
gd.set_with_dataframe(self.ws, upload_df, include_index=True, col=2)
|
||||
gf_dataframe.format_with_dataframe(
|
||||
self.ws, upload_df, include_index=True, include_column_header=True, col=2
|
||||
)
|
||||
|
||||
def _upload_all(self):
|
||||
try:
|
||||
self.upload_rt()
|
||||
self.upload_pos()
|
||||
except:
|
||||
print(
|
||||
f"Uploading of runtable to gsheet https://docs.google.com/spreadsheets/d/{self._spreadsheet_key}/ failed. Run run_table.upload_rt() for error traceback"
|
||||
)
|
||||
|
||||
def upload_all(self):
|
||||
rt = threading.Thread(target=self._upload_all)
|
||||
rt.start()
|
||||
|
||||
def _orderlist(self, mylist, key_order, orderlist=None):
|
||||
key_order = key_order.split(" ")
|
||||
if orderlist == None:
|
||||
index = np.concatenate(
|
||||
[np.where(np.array(mylist) == k)[0] for k in key_order if k in mylist]
|
||||
)
|
||||
# index = np.array([mylist.index(k) for k in key_order if k in mylist])
|
||||
else:
|
||||
index = np.concatenate(
|
||||
[
|
||||
np.where(np.array(orderlist) == k)[0]
|
||||
for k in key_order
|
||||
if k in orderlist
|
||||
]
|
||||
)
|
||||
curidx = np.arange(len(mylist))
|
||||
newidx = np.append(index, np.delete(curidx, index))
|
||||
return [mylist[n] for n in newidx]
|
||||
|
||||
def order_df(self, key_order=None):
|
||||
"""
|
||||
This function orders the columns of the stored dataframe by the given key_order.
|
||||
key_order is a string with consecutive keys such as 'name type pulse_id. It defaults to self.key_order'
|
||||
"""
|
||||
if key_order is None:
|
||||
key_order = self.key_order
|
||||
# self.alias_df = self.alias_df[
|
||||
# self._orderlist(list(self.alias_df.columns), key_order)
|
||||
# ]
|
||||
devs = [item[0] for item in list(self.adj_df.columns)]
|
||||
self.adj_df = self.adj_df[
|
||||
self._orderlist(list(self.adj_df.columns), key_order, orderlist=devs)
|
||||
]
|
||||
|
||||
def _get_adjustable_values(self, silent=True):
|
||||
"""
|
||||
This function gets the values of all adjustables in good adjustables and raises an error, when an adjustable is not connected anymore
|
||||
"""
|
||||
if silent:
|
||||
dat = {}
|
||||
for devname, dev in self.good_adjustables.items():
|
||||
dat[devname] = {}
|
||||
for adjname, adj in dev.items():
|
||||
bad_adjs = []
|
||||
try:
|
||||
dat[devname][adjname] = adj.get_current_value()
|
||||
except:
|
||||
print(
|
||||
f"run_table: getting value of {devname}.{adjname} failed, removing it from list of good adjustables"
|
||||
)
|
||||
bad_adjs.append(adjname)
|
||||
for ba in bad_adjs:
|
||||
if not devname in self.bad_adjustables.keys():
|
||||
self.bad_adjustables[devname] = {}
|
||||
self.bad_adjustables[devname][adjname] = self.good_adjustables[
|
||||
devname
|
||||
].pop(adjname)
|
||||
else:
|
||||
dat = {
|
||||
devname: {
|
||||
adjname: adj.get_current_value() for adjname, adj in dev.items()
|
||||
}
|
||||
for devname, dev in self.good_adjustables.items()
|
||||
}
|
||||
return dat
|
||||
|
||||
def subtract_df(self, devs, ind1, ind2):
|
||||
"""
|
||||
This function is used to subtract one dataframe from another to show changes between entries.
|
||||
devs='thc tht' would show the devices thc and tht and ind1=0, ind2='p0' the difference between
|
||||
run 0 and saved position 0.
|
||||
"""
|
||||
df1 = self.query(devs, [ind1])
|
||||
df1 = df1[[type(val) is not str for val in df1]]
|
||||
df2 = self.query(devs, [ind2])
|
||||
df2 = df2[[type(val) is not str for val in df2]]
|
||||
df2.columns = df1.columns
|
||||
return df1.subtract(df2)
|
||||
|
||||
def _get_all_adjustables(self, device, pp_name=None):
|
||||
if pp_name is not None:
|
||||
name = ".".join([pp_name, device.name])
|
||||
else:
|
||||
name = device.name
|
||||
self.adjustables[name] = {}
|
||||
for key in device.__dict__.keys():
|
||||
if ~np.any([s in key for s in self._parse_exclude_keys]):
|
||||
value = device.__dict__[key]
|
||||
if np.all(
|
||||
[
|
||||
~np.any(
|
||||
[
|
||||
s in str(type(value))
|
||||
for s in self._adj_exclude_class_types
|
||||
]
|
||||
),
|
||||
hasattr(value, "get_current_value"),
|
||||
]
|
||||
):
|
||||
self.adjustables[name][key] = value
|
||||
|
||||
if hasattr(device, "get_current_value"):
|
||||
self.adjustables[name][".".join([name, "self"])] = device
|
||||
|
||||
def _get_all_adjustables_fewerparents(
|
||||
self, device, adj_prefix=None, parent_name=None
|
||||
):
|
||||
if adj_prefix is not None:
|
||||
name = ".".join([adj_prefix, device.name])
|
||||
else:
|
||||
name = device.name
|
||||
for key in device.__dict__.keys():
|
||||
if ~np.any([s in key for s in self._parse_exclude_keys]):
|
||||
value = device.__dict__[key]
|
||||
if np.all(
|
||||
[
|
||||
~np.any(
|
||||
[
|
||||
s in str(type(value))
|
||||
for s in self._adj_exclude_class_types
|
||||
]
|
||||
),
|
||||
hasattr(value, "get_current_value"),
|
||||
]
|
||||
):
|
||||
if parent_name == device.name:
|
||||
self.adjustables[parent_name][key] = value
|
||||
else:
|
||||
self.adjustables[parent_name][".".join([name, key])] = value
|
||||
|
||||
if parent_name == device.name:
|
||||
if hasattr(device, "get_current_value"):
|
||||
self.adjustables[parent_name]["self"] = device
|
||||
|
||||
def _parse_child_instances_fewerparents(
|
||||
self, parent_class, adj_prefix=None, parent_name=None
|
||||
):
|
||||
if parent_name is None:
|
||||
parent_name = parent_class.name
|
||||
self._get_all_adjustables_fewerparents(parent_class, adj_prefix, parent_name)
|
||||
if parent_name is not parent_class.name:
|
||||
if adj_prefix is not None:
|
||||
adj_prefix = ".".join([adj_prefix, parent_class.name])
|
||||
else:
|
||||
adj_prefix = parent_class.name
|
||||
|
||||
sub_classes = []
|
||||
for key in parent_class.__dict__.keys():
|
||||
if ~np.any([s in key for s in self._parse_exclude_keys]):
|
||||
s_class = parent_class.__dict__[key]
|
||||
if np.all(
|
||||
[
|
||||
hasattr(s_class, "__dict__"),
|
||||
hasattr(s_class, "name"),
|
||||
s_class.__hash__ is not None,
|
||||
"eco" in str(type(s_class)),
|
||||
~np.any(
|
||||
[
|
||||
s in str(type(s_class))
|
||||
for s in self._parse_exclude_class_types
|
||||
]
|
||||
),
|
||||
]
|
||||
):
|
||||
sub_classes.append(s_class)
|
||||
return set(sub_classes).union(
|
||||
[
|
||||
s
|
||||
for c in sub_classes
|
||||
for s in self._parse_child_instances_fewerparents(
|
||||
c, adj_prefix, parent_name
|
||||
)
|
||||
]
|
||||
)
|
||||
|
||||
def _parse_parent_fewerparents(self, parent=None):
|
||||
if parent == None:
|
||||
parent = self.devices
|
||||
for key in parent.__dict__.keys():
|
||||
try:
|
||||
if ~np.any([s in key for s in self._parse_exclude_keys]):
|
||||
s_class = parent.__dict__[key]
|
||||
if np.all(
|
||||
[
|
||||
hasattr(s_class, "__dict__"),
|
||||
hasattr(s_class, "name"),
|
||||
s_class.__hash__ is not None,
|
||||
"eco" in str(type(s_class)),
|
||||
~np.any(
|
||||
[
|
||||
s in str(type(s_class))
|
||||
for s in self._parse_exclude_class_types
|
||||
]
|
||||
),
|
||||
]
|
||||
):
|
||||
self.adjustables[s_class.name] = {}
|
||||
self._parse_child_instances_fewerparents(s_class)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
print(key)
|
||||
# print(f"failed to parse {key} in runtable")
|
||||
for name, value in self._channels_ca.get_current_value().items():
|
||||
self.adjustables[f"env_{name}"] = {
|
||||
key: PvRecord(pvsetname=ch) for key, ch in value.items()
|
||||
}
|
||||
self._check_adjustables()
|
||||
|
||||
def _parse_child_instances(self, parent_class, pp_name=None):
|
||||
# try:
|
||||
self._get_all_adjustables(parent_class, pp_name)
|
||||
# except:
|
||||
# print(f'Getting adjustables from {parent_class.name} failed')
|
||||
# pass
|
||||
if pp_name is not None:
|
||||
pp_name = ".".join([pp_name, parent_class.name])
|
||||
else:
|
||||
pp_name = parent_class.name
|
||||
|
||||
sub_classes = []
|
||||
for key in parent_class.__dict__.keys():
|
||||
if ~np.any([s in key for s in self._parse_exclude_keys]):
|
||||
s_class = parent_class.__dict__[key]
|
||||
if np.all(
|
||||
[
|
||||
hasattr(s_class, "__dict__"),
|
||||
hasattr(s_class, "name"),
|
||||
s_class.__hash__ is not None,
|
||||
"eco" in str(type(s_class)),
|
||||
~np.any(
|
||||
[
|
||||
s in str(type(s_class))
|
||||
for s in self._parse_exclude_class_types
|
||||
]
|
||||
),
|
||||
]
|
||||
):
|
||||
sub_classes.append(s_class)
|
||||
return set(sub_classes).union(
|
||||
[s for c in sub_classes for s in self._parse_child_instances(c, pp_name)]
|
||||
)
|
||||
|
||||
def _parse_parent(self, parent=None):
|
||||
if parent == None:
|
||||
parent = self.devices
|
||||
for key in parent.__dict__.keys():
|
||||
try:
|
||||
if ~np.any([s in key for s in self._parse_exclude_keys]):
|
||||
s_class = parent.__dict__[key]
|
||||
if np.all(
|
||||
[
|
||||
hasattr(s_class, "__dict__"),
|
||||
hasattr(s_class, "name"),
|
||||
s_class.__hash__ is not None,
|
||||
"eco" in str(type(s_class)),
|
||||
~np.any(
|
||||
[
|
||||
s in str(type(s_class))
|
||||
for s in self._parse_exclude_class_types
|
||||
]
|
||||
),
|
||||
]
|
||||
):
|
||||
self._parse_child_instances(parent.__dict__[key])
|
||||
except Exception as e:
|
||||
print(e)
|
||||
print(key)
|
||||
# print(f"failed to parse {key} in runtable")
|
||||
for name, value in self._channels_ca.get_current_value().items():
|
||||
self.adjustables[f"env_{name}"] = {
|
||||
key: PvRecord(pvsetname=ch) for key, ch in value.items()
|
||||
}
|
||||
self._check_adjustables()
|
||||
|
||||
def _check_adjustables(self, check_for_current_none_values=False):
|
||||
good_adj = {}
|
||||
bad_adj = {}
|
||||
for device, adjs in self.adjustables.items():
|
||||
good_dev_adj = {}
|
||||
bad_dev_adj = {}
|
||||
for name, adj in adjs.items():
|
||||
if check_for_current_none_values and (adj.get_current_value() is None):
|
||||
bad_dev_adj[name] = adj
|
||||
else:
|
||||
good_dev_adj[name] = adj
|
||||
if len(good_dev_adj) > 0:
|
||||
good_adj[device] = good_dev_adj
|
||||
if len(bad_dev_adj) > 0:
|
||||
bad_adj[device] = bad_dev_adj
|
||||
self.good_adjustables = good_adj
|
||||
self.bad_adjustables = bad_adj
|
||||
|
||||
def set_alias_namespace(self, alias_namespace):
|
||||
aliases = [s.replace(".", "_") for s in alias_namespace.aliases]
|
||||
self._alias_namespace = alias_namespace
|
||||
self._pvs = dict(
|
||||
zip(
|
||||
aliases,
|
||||
np.array(
|
||||
[
|
||||
PV(ch, connection_timeout=0.05, auto_monitor=True)
|
||||
for ch in alias_namespace.channels
|
||||
]
|
||||
),
|
||||
)
|
||||
)
|
||||
|
||||
def get_alias_namespace(self):
|
||||
return self._alias_namespace
|
||||
|
||||
alias_namespace = property(get_alias_namespace, set_alias_namespace)
|
||||
|
||||
def __repr__(self):
|
||||
self.order_df()
|
||||
return_df = self._query_by_keys(self.keys)
|
||||
return return_df.T.__repr__()
|
||||
|
||||
|
||||
class Gsheet_API:
|
||||
def __init__(
|
||||
self,
|
||||
@@ -749,7 +80,8 @@ class Gsheet_API:
|
||||
def _append_to_gspread_key_df(self, gspread_key_df):
|
||||
if os.path.exists(self._keydf_fname):
|
||||
self._key_df = pd.read_pickle(self._keydf_fname)
|
||||
self._key_df = self._key_df.append(gspread_key_df)
|
||||
#deprecated: self._key_df = self._key_df.append(gspread_key_df)
|
||||
self._key_df = pd.concat([self._key_df, gspread_key_df])
|
||||
self._key_df.to_pickle(self._keydf_fname)
|
||||
else:
|
||||
self._key_df.to_pickle(self._keydf_fname)
|
||||
@@ -775,6 +107,7 @@ class Gsheet_API:
|
||||
{"keys": [spreadsheet.id]},
|
||||
index=[f"{exp_id}"],
|
||||
)
|
||||
print(gspread_key_df)
|
||||
spreadsheet_key = spreadsheet.id
|
||||
self._append_to_gspread_key_df(gspread_key_df)
|
||||
self._spreadsheet_key = spreadsheet_key
|
||||
@@ -977,8 +310,9 @@ class Run_Table2:
|
||||
self,
|
||||
runno,
|
||||
metadata,
|
||||
d={},
|
||||
):
|
||||
self._data.append_run(runno, metadata)
|
||||
self._data.append_run(runno, metadata, d=d)
|
||||
if self._google_sheet_api is not None:
|
||||
df = self._reduce_df()
|
||||
self._google_sheet_api.upload_all(df=df)
|
||||
@@ -994,6 +328,19 @@ class Run_Table2:
|
||||
|
||||
def to_dataframe(self):
|
||||
return DataFrame(self._data)
|
||||
###### diagnostic and convencience functions ######
|
||||
|
||||
def run_table_from_other_pgroup(pgroup):
|
||||
"""
|
||||
returns a run_table instance of the specified pgroup
|
||||
note: this does neither replace the current run_table nor switch the automatic appending of data to a new run_table or pgroup
|
||||
|
||||
usage: run_table_pxxx = run_table.run_table_from_other_pgroup('pxxx')
|
||||
"""
|
||||
return Run_Table2(data=f'/sf/bernina/data/{pgroup}/res/run_table/{pgroup}_runtable.pkl')
|
||||
|
||||
def check_timeouts(self, include_bad_adjustables=True, plot=True, repeats=1):
|
||||
return self._data.check_timeouts(include_bad_adjustables=include_bad_adjustables, plot=plot, repeats=repeats)
|
||||
|
||||
def _reduce_df(
|
||||
self,
|
||||
@@ -1001,11 +348,18 @@ class Run_Table2:
|
||||
):
|
||||
if keys is None:
|
||||
keys = self._google_sheet_api.gsheet_keys()
|
||||
dfs = [
|
||||
self.__dict__[key].to_dataframe()
|
||||
for key in keys.split(" ")
|
||||
if key in self.__dir__()
|
||||
]
|
||||
dfs = []
|
||||
for key in keys.split(" "):
|
||||
d = self
|
||||
add = True
|
||||
for k in key.split("."):
|
||||
if k in d.__dict__.keys():
|
||||
d = d.__dict__[k]
|
||||
else:
|
||||
add = False
|
||||
if all([hasattr(d, "to_dataframe"), add]):
|
||||
dfs.append(d.to_dataframe())
|
||||
|
||||
dfc = self._concatenate_dfs(dfs)
|
||||
return dfc
|
||||
|
||||
@@ -1042,6 +396,9 @@ class Run_Table2:
|
||||
def __repr__(self):
|
||||
return self.__str__()
|
||||
|
||||
def check_timeouts(self, include_bad_adjustables=True, plot=True, repeats=1):
|
||||
return self._data.check_timeouts(include_bad_adjustables=include_bad_adjustables, plot=plot, repeats=repeats)
|
||||
|
||||
|
||||
class Run_Table_DataFrame(DataFrame):
|
||||
def __init__(
|
||||
@@ -1052,6 +409,8 @@ class Run_Table_DataFrame(DataFrame):
|
||||
devices=None,
|
||||
name=None,
|
||||
):
|
||||
if type(data) is str:
|
||||
data = pd.read_pickle(data)
|
||||
super().__init__(data=data)
|
||||
|
||||
### Load devices to parse for adjustables ###
|
||||
@@ -1070,7 +429,7 @@ class Run_Table_DataFrame(DataFrame):
|
||||
self._parse_exclude_keys = "status_indicators settings_collection status_indicators_collection presets memory _elog _currentChange _flags __ alias namespace daq scan MasterEventSystem _motor Alias".split(
|
||||
" "
|
||||
)
|
||||
self._parse_exclude_class_types = "__ alias namespace daq scan MasterEventSystem _motor Alias AdjustablePv".split(
|
||||
self._parse_exclude_class_types = "__ alias namespace daq scan MasterEventSystem _motor Alias AdjustablePv Collection".split(
|
||||
" "
|
||||
)
|
||||
self._adj_exclude_class_types = (
|
||||
@@ -1131,24 +490,27 @@ class Run_Table_DataFrame(DataFrame):
|
||||
"to": 2,
|
||||
"steps": 51,
|
||||
},
|
||||
d={},
|
||||
):
|
||||
self.load()
|
||||
if len(self.adjustables) == 0:
|
||||
self._parse_parent_fewerparents()
|
||||
dat = self._get_adjustable_values()
|
||||
dat = self._get_adjustable_values(d=d)
|
||||
dat["metadata"] = metadata
|
||||
dat["metadata"]["time"] = datetime.now()
|
||||
names = ["device", "adjustable"]
|
||||
multiindex = pd.MultiIndex.from_tuples(
|
||||
[(dev, adj) for dev in dat.keys() for adj in dat[dev].keys()], names=names
|
||||
)
|
||||
values = np.array([val for adjs in dat.values() for val in adjs.values()])
|
||||
values = np.array([val for adjs in dat.values() for val in adjs.values()], dtype=object)
|
||||
index = np.array(
|
||||
[f"{dev}.{adj}" for dev, adjs in dat.items() for adj in adjs.keys()]
|
||||
)
|
||||
# run_df = DataFrame([values], columns=multiindex, index=[runno])
|
||||
run_df = DataFrame([values], columns=index, index=[runno])
|
||||
self.df = self.append(run_df)
|
||||
#deprecated: self.df = self.append(run_df)
|
||||
self.df = pd.concat([self.df, run_df])
|
||||
|
||||
self._remove_duplicates()
|
||||
# self.order_df()
|
||||
self.save()
|
||||
@@ -1169,19 +531,20 @@ class Run_Table_DataFrame(DataFrame):
|
||||
multiindex = pd.MultiIndex.from_tuples(
|
||||
[(dev, adj) for dev in dat.keys() for adj in dat[dev].keys()], names=names
|
||||
)
|
||||
values = np.array([val for adjs in dat.values() for val in adjs.values()])
|
||||
values = np.array([val for adjs in dat.values() for val in adjs.values()], dtype=object)
|
||||
index = np.array(
|
||||
[f"{dev}.{adj}" for dev, adjs in dat.items() for adj in adjs.keys()]
|
||||
)
|
||||
# pos_df = DataFrame([values], columns=multiindex, index=[f"p{posno}"])
|
||||
pos_df = DataFrame([values], columns=index, index=[f"p{posno}"])
|
||||
|
||||
self.df = self.append(pos_df)
|
||||
#deprecated: self.df = self.append(pos_df)
|
||||
self.df = pd.concat([self.df,pos_df])
|
||||
self._remove_duplicates()
|
||||
# self.order_df()
|
||||
self.save()
|
||||
|
||||
def _get_adjustable_values(self, silent=True):
|
||||
def _get_adjustable_values(self, silent=True, d={}):
|
||||
"""
|
||||
This function gets the values of all adjustables in good adjustables and raises an error, when an adjustable is not connected anymore
|
||||
"""
|
||||
@@ -1191,6 +554,9 @@ class Run_Table_DataFrame(DataFrame):
|
||||
dat[devname] = {}
|
||||
bad_adjs = []
|
||||
for adjname, adj in dev.items():
|
||||
if f'{devname}.{adjname}' in d.keys():
|
||||
dat[devname][adjname] = d[f'{devname}.{adjname}']
|
||||
continue
|
||||
try:
|
||||
dat[devname][adjname] = adj.get_current_value()
|
||||
except:
|
||||
@@ -1207,7 +573,7 @@ class Run_Table_DataFrame(DataFrame):
|
||||
else:
|
||||
dat = {
|
||||
devname: {
|
||||
adjname: adj.get_current_value() for adjname, adj in dev.items()
|
||||
adjname: d[f'{devname}.{adjname}'] if f'{devname}.{adjname}' in d.keys() else adj.get_current_value() for adjname, adj in dev.items()
|
||||
}
|
||||
for devname, dev in self.good_adjustables.items()
|
||||
}
|
||||
@@ -1239,7 +605,7 @@ class Run_Table_DataFrame(DataFrame):
|
||||
self.adjustables[name][".".join([name, "self"])] = device
|
||||
|
||||
def _get_all_adjustables_fewerparents(
|
||||
self, device, adj_prefix=None, parent_name=None
|
||||
self, device, adj_prefix=None, parent_name=None, verbose=False
|
||||
):
|
||||
if adj_prefix is not None:
|
||||
name = ".".join([adj_prefix, device.name])
|
||||
@@ -1262,6 +628,8 @@ class Run_Table_DataFrame(DataFrame):
|
||||
if parent_name == device.name:
|
||||
self.adjustables[parent_name][key] = value
|
||||
else:
|
||||
#print("GET ADJ", parent_name, name, key)
|
||||
|
||||
self.adjustables[parent_name][".".join([name, key])] = value
|
||||
|
||||
if parent_name == device.name:
|
||||
@@ -1269,17 +637,18 @@ class Run_Table_DataFrame(DataFrame):
|
||||
self.adjustables[parent_name]["self"] = device
|
||||
|
||||
def _parse_child_instances_fewerparents(
|
||||
self, parent_class, adj_prefix=None, parent_name=None
|
||||
self, parent_class, adj_prefix=None, parent_name=None, verbose=False
|
||||
):
|
||||
if parent_name is None:
|
||||
parent_name = own_name
|
||||
self._get_all_adjustables_fewerparents(parent_class, adj_prefix, parent_name)
|
||||
self._get_all_adjustables_fewerparents(parent_class, adj_prefix, parent_name, verbose=verbose)
|
||||
if parent_name is not parent_class.name:
|
||||
if adj_prefix is not None:
|
||||
adj_prefix = ".".join([adj_prefix, parent_class.name])
|
||||
else:
|
||||
adj_prefix = parent_class.name
|
||||
|
||||
|
||||
sub_classes = []
|
||||
sub_classnames = []
|
||||
for key in parent_class.__dict__.keys():
|
||||
@@ -1298,11 +667,13 @@ class Run_Table_DataFrame(DataFrame):
|
||||
for s in self._parse_exclude_class_types
|
||||
]
|
||||
),
|
||||
|
||||
]
|
||||
):
|
||||
if s_class.name == None:
|
||||
s_class.name = key
|
||||
sub_classes.append(s_class)
|
||||
if adj_prefix is None or ~np.any([key == s for s in ".".join([parent_name,adj_prefix]).split(".")]):
|
||||
if s_class.name == None:
|
||||
s_class.name = key
|
||||
sub_classes.append(s_class)
|
||||
return set(sub_classes).union(
|
||||
[
|
||||
s
|
||||
@@ -1313,7 +684,7 @@ class Run_Table_DataFrame(DataFrame):
|
||||
]
|
||||
)
|
||||
|
||||
def _parse_parent_fewerparents(self, parent=None):
|
||||
def _parse_parent_fewerparents(self, parent=None, verbose=False):
|
||||
if parent == None:
|
||||
parent = self.devices
|
||||
for key in parent.__dict__.keys():
|
||||
@@ -1336,7 +707,7 @@ class Run_Table_DataFrame(DataFrame):
|
||||
):
|
||||
self.adjustables[key] = {}
|
||||
self._parse_child_instances_fewerparents(
|
||||
s_class, parent_name=key
|
||||
s_class, parent_name=key, verbose=verbose
|
||||
)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
@@ -1407,13 +778,18 @@ class Run_Table_DataFrame(DataFrame):
|
||||
|
||||
self._check_adjustables()
|
||||
|
||||
def _check_adjustables(self, check_for_current_none_values=False):
|
||||
def _check_adjustables(self, check_for_current_none_values=True):
|
||||
good_adj = {}
|
||||
bad_adj = {}
|
||||
for device, adjs in self.adjustables.items():
|
||||
good_dev_adj = {}
|
||||
bad_dev_adj = {}
|
||||
for name, adj in adjs.items():
|
||||
try:
|
||||
adj.get_current_value()
|
||||
except Exception as e:
|
||||
print(f"get_current_value() method of {name} failed with {e}")
|
||||
continue
|
||||
if check_for_current_none_values and (adj.get_current_value() is None):
|
||||
bad_dev_adj[name] = adj
|
||||
else:
|
||||
@@ -1454,6 +830,48 @@ class Run_Table_DataFrame(DataFrame):
|
||||
self.df = self[self._orderlist(list(self.columns), key_order, orderlist=devs)]
|
||||
|
||||
|
||||
#### diagnostic and convenience functions ####
|
||||
def check_timeouts(self, include_bad_adjustables=True, repeats=1, plot=True):
|
||||
if len(self.adjustables) == 0:
|
||||
self._parse_parent_fewerparents()
|
||||
ts = []
|
||||
devs=[]
|
||||
def get_dev_adjs(dev):
|
||||
for k, adj in dev.items():
|
||||
val = adj.get_current_value()
|
||||
for k, dev in self.good_adjustables.items():
|
||||
def func(dev=dev):
|
||||
return get_dev_adjs(dev)
|
||||
t = timeit.timeit(func, number=repeats)
|
||||
ts.append(float(t))
|
||||
devs.append(k)
|
||||
print(k, t)
|
||||
idx = np.argsort(ts)
|
||||
self.times = [np.array(devs)[idx], np.array(ts)[idx]]
|
||||
print('recorded adjustable results stored in run_table._data.times')
|
||||
if include_bad_adjustables:
|
||||
for k, dev in self.bad_adjustables.items():
|
||||
def func(dev=dev):
|
||||
return get_dev_adjs(dev)
|
||||
t = timeit.timeit(func, number=repeats)
|
||||
ts.append(float(t))
|
||||
devs.append(k)
|
||||
print(k, t)
|
||||
idx = np.argsort(ts)
|
||||
print('rejected timed out adjustable results stored in run_table._data.times_rejected')
|
||||
self.times_rejected = [np.array(devs)[idx], np.array(ts)[idx]]
|
||||
|
||||
if plot:
|
||||
import pylab as plt
|
||||
fig, ax = plt.subplots(1)
|
||||
if include_bad_adjustables:
|
||||
plt.barh(self.times_rejected[0], self.times_rejected[1], color='red', label='rejected adjustables')
|
||||
plt.barh(self.times[0], self.times[1], label='recorded adjustables', color='seagreen')
|
||||
plt.xlabel('time (s)')
|
||||
plt.legend()
|
||||
|
||||
|
||||
|
||||
def name2obj(obj_parent, name, delimiter="."):
|
||||
if type(name) is str:
|
||||
name = name.split(delimiter)
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
from pathlib import Path
|
||||
|
||||
class DataFiles:
|
||||
def __init__(self,pgroup=None, data_path='/sf/bernina/data/'):
|
||||
self.pgroup = pgroup
|
||||
self.data_path = data_path
|
||||
self.raw = Path(self.data_path) / Path(pgroup) / Path('raw')
|
||||
|
||||
def get_available_runs(parse_numbers=True):
|
||||
self.raw
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ from ..elements.assembly import Assembly
|
||||
from .profile_monitors import Pprm_dsd
|
||||
from .intensity_monitors import SolidTargetDetectorPBPS_new_assembly
|
||||
import numpy as np
|
||||
from epics import PV
|
||||
|
||||
|
||||
class DownstreamDiagnostic(Assembly):
|
||||
@@ -24,9 +25,14 @@ class DownstreamDiagnostic(Assembly):
|
||||
self._append(
|
||||
MotorRecord, "SARES20-DSD:MOTOR_DSDY", name="ybase", is_setting=True
|
||||
)
|
||||
|
||||
|
||||
def get_xyposition_for_kb_angles_in_rad(self, theta_kbver, theta_kbhor):
|
||||
y = np.tan(2 * theta_kbver) * 7075
|
||||
x = np.tan(2 * theta_kbhor) / np.cos(2 * theta_kbver) * 6325
|
||||
return x, y
|
||||
|
||||
def home(self,**kwargs):
|
||||
self._run_cmd("python /ioc/qt/ESB_DSD_home.py SARES20-DSD", **kwargs)
|
||||
|
||||
def gui(self):
|
||||
self._run_cmd("caqtdm -noMsg -macro P=SARES20-DSD /ioc/qt/ESB_DSD_motors.ui")
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
from ..devices_general.motors import MotorRecord
|
||||
from eco.devices_general.pipelines_swissfel import Pipeline
|
||||
from ..devices_general.motors import MotorRecord, SmaractRecord
|
||||
from ..devices_general.detectors import FeDigitizer
|
||||
from ..epics.detector import DetectorPvDataStream
|
||||
from ..detector.detectors_psi import DetectorBsStream
|
||||
@@ -50,6 +51,388 @@ class FeDigitiza(Assembly):
|
||||
# ]
|
||||
|
||||
|
||||
class CalibrationRecord(Assembly):
|
||||
def __init__(self, pvbase, name=None):
|
||||
self.pvbase = pvbase
|
||||
super().__init__(name)
|
||||
self._append(
|
||||
AdjustablePv,
|
||||
self.pvbase + ".INPA",
|
||||
name="input_A",
|
||||
is_setting=True,
|
||||
is_display=True,
|
||||
)
|
||||
self._append(
|
||||
AdjustablePv,
|
||||
self.pvbase + ".INPB",
|
||||
name="input_B",
|
||||
is_setting=True,
|
||||
is_display=True,
|
||||
)
|
||||
self._append(
|
||||
AdjustablePv,
|
||||
self.pvbase + ".INPC",
|
||||
name="input_C",
|
||||
is_setting=True,
|
||||
is_display=True,
|
||||
)
|
||||
self._append(
|
||||
AdjustablePv,
|
||||
self.pvbase + ".INPD",
|
||||
name="input_D",
|
||||
is_setting=True,
|
||||
is_display=True,
|
||||
)
|
||||
self._append(
|
||||
AdjustablePv,
|
||||
self.pvbase + ".INPJ",
|
||||
name="input_J",
|
||||
is_setting=True,
|
||||
is_display=True,
|
||||
)
|
||||
|
||||
self._append(
|
||||
AdjustablePv,
|
||||
self.pvbase + ".E",
|
||||
name="const_E",
|
||||
is_setting=True,
|
||||
is_display=True,
|
||||
)
|
||||
self._append(
|
||||
AdjustablePv,
|
||||
self.pvbase + ".F",
|
||||
name="const_F",
|
||||
is_setting=True,
|
||||
is_display=True,
|
||||
)
|
||||
self._append(
|
||||
AdjustablePv,
|
||||
self.pvbase + ".G",
|
||||
name="const_G",
|
||||
is_setting=True,
|
||||
is_display=True,
|
||||
)
|
||||
self._append(
|
||||
AdjustablePv,
|
||||
self.pvbase + ".H",
|
||||
name="const_H",
|
||||
is_setting=True,
|
||||
is_display=True,
|
||||
)
|
||||
self._append(
|
||||
AdjustablePv,
|
||||
self.pvbase + ".I",
|
||||
name="const_I",
|
||||
is_setting=True,
|
||||
is_display=True,
|
||||
)
|
||||
self._append(
|
||||
AdjustablePv,
|
||||
self.pvbase + ".CALC",
|
||||
name="function",
|
||||
is_setting=True,
|
||||
is_display=True,
|
||||
)
|
||||
|
||||
|
||||
# class SolidTargetDetectorPBPSMonOpt(SolidTargetDetectorPBPS):
|
||||
# def __init__(self, *args, **kwargs):
|
||||
# ...
|
||||
|
||||
|
||||
class SolidTargetDetectorPBPS(Assembly):
|
||||
def __init__(
|
||||
self,
|
||||
pvname,
|
||||
# VME_crate=None,
|
||||
# pipeline=None,
|
||||
# link=None,
|
||||
channel_xpos=None,
|
||||
channel_ypos=None,
|
||||
channel_intensity=None,
|
||||
diode_channels_raw={},
|
||||
# ch_up=12,
|
||||
# ch_down=13,
|
||||
# ch_left=15,
|
||||
# ch_right=14,
|
||||
# elog=None,
|
||||
use_calibration=True,
|
||||
calibration_records=None,
|
||||
name=None,
|
||||
fe_digi_channels={},
|
||||
# calc=None,
|
||||
# calc_calib={},
|
||||
pipeline_computation=None,
|
||||
):
|
||||
super().__init__(name=name)
|
||||
self.pvname = pvname
|
||||
self._append(
|
||||
MotorRecord, pvname + ":MOTOR_X1", name="x_diodes", is_setting=True
|
||||
)
|
||||
self._append(
|
||||
MotorRecord, pvname + ":MOTOR_Y1", name="y_diodes", is_setting=True
|
||||
)
|
||||
self._append(
|
||||
MotorRecord, pvname + ":MOTOR_PROBE", name="target_y", is_setting=True
|
||||
)
|
||||
self._append(
|
||||
AdjustablePvEnum, pvname + ":PROBE_SP", name="target", is_setting=True
|
||||
)
|
||||
if channel_intensity:
|
||||
self._append(
|
||||
DetectorBsStream,
|
||||
channel_intensity,
|
||||
name="intensity",
|
||||
is_setting=False,
|
||||
)
|
||||
else:
|
||||
self._append(
|
||||
DetectorBsStream,
|
||||
pvname + ":INTENSITY",
|
||||
name="intensity",
|
||||
is_setting=False,
|
||||
)
|
||||
|
||||
if channel_xpos:
|
||||
self._append(DetectorBsStream, channel_xpos, name="xpos", is_setting=False)
|
||||
else:
|
||||
self._append(
|
||||
DetectorBsStream, pvname + ":XPOS", name="xpos", is_setting=False
|
||||
)
|
||||
if channel_ypos:
|
||||
self._append(DetectorBsStream, channel_ypos, name="ypos", is_setting=False)
|
||||
else:
|
||||
self._append(
|
||||
DetectorBsStream, pvname + ":YPOS", name="ypos", is_setting=False
|
||||
)
|
||||
|
||||
if diode_channels_raw:
|
||||
self._append(
|
||||
DetectorBsStream,
|
||||
diode_channels_raw["up"],
|
||||
name="signal_up_raw",
|
||||
is_setting=False,
|
||||
)
|
||||
self._append(
|
||||
DetectorBsStream,
|
||||
diode_channels_raw["down"],
|
||||
name="signal_down_raw",
|
||||
is_setting=False,
|
||||
)
|
||||
self._append(
|
||||
DetectorBsStream,
|
||||
diode_channels_raw["left"],
|
||||
name="signal_left_raw",
|
||||
is_setting=False,
|
||||
)
|
||||
self._append(
|
||||
DetectorBsStream,
|
||||
diode_channels_raw["right"],
|
||||
name="signal_right_raw",
|
||||
is_setting=False,
|
||||
)
|
||||
if fe_digi_channels:
|
||||
self._append(
|
||||
FeDigitiza,
|
||||
fe_digi_channels["left"],
|
||||
name="settings_diode_left",
|
||||
is_setting=True,
|
||||
)
|
||||
self._append(
|
||||
FeDigitiza,
|
||||
fe_digi_channels["right"],
|
||||
name="settings_diode_right",
|
||||
is_setting=True,
|
||||
)
|
||||
self._append(
|
||||
FeDigitiza,
|
||||
fe_digi_channels["up"],
|
||||
name="settings_diode_up",
|
||||
is_setting=True,
|
||||
)
|
||||
self._append(
|
||||
FeDigitiza,
|
||||
fe_digi_channels["down"],
|
||||
name="settings_diode_down",
|
||||
is_setting=True,
|
||||
)
|
||||
|
||||
if use_calibration:
|
||||
# Calibration calculation record
|
||||
|
||||
# Calibration
|
||||
if calibration_records:
|
||||
self._append(
|
||||
CalibrationRecord,
|
||||
calibration_records["intensity"],
|
||||
name="calib_intensity",
|
||||
is_setting=True,
|
||||
is_display=False,
|
||||
)
|
||||
self._append(
|
||||
CalibrationRecord,
|
||||
calibration_records["xpos"],
|
||||
name="calib_xpos",
|
||||
is_setting=True,
|
||||
is_display=False,
|
||||
)
|
||||
self._append(
|
||||
CalibrationRecord,
|
||||
calibration_records["ypos"],
|
||||
name="calib_ypos",
|
||||
is_setting=True,
|
||||
is_display=False,
|
||||
)
|
||||
|
||||
else:
|
||||
self._append(
|
||||
CalibrationRecord,
|
||||
pvname + ":INTENSITY",
|
||||
name="calib_intensity",
|
||||
is_setting=True,
|
||||
is_display=False,
|
||||
)
|
||||
self._append(
|
||||
CalibrationRecord,
|
||||
pvname + ":XPOS",
|
||||
name="calib_xpos",
|
||||
is_setting=True,
|
||||
is_display=False,
|
||||
)
|
||||
self._append(
|
||||
CalibrationRecord,
|
||||
pvname + ":YPOS",
|
||||
name="calib_ypos",
|
||||
is_setting=True,
|
||||
is_display=False,
|
||||
)
|
||||
if pipeline_computation:
|
||||
self._append(Pipeline, pipeline_computation,name='pipeline_comp', is_setting=True, is_display=False)
|
||||
|
||||
def get_calibration_values(self, seconds=5, return_data=False):
|
||||
self.x_diodes.set_target_value(0).wait()
|
||||
self.y_diodes.set_target_value(0).wait()
|
||||
ds = [
|
||||
self.signal_up_raw,
|
||||
self.signal_down_raw,
|
||||
self.signal_left_raw,
|
||||
self.signal_right_raw,
|
||||
]
|
||||
aqs = [d.acquire(seconds=seconds) for d in ds]
|
||||
data = [aq.wait() for aq in aqs]
|
||||
mean = [np.mean(td) for td in data]
|
||||
std = [np.std(td) for td in data]
|
||||
nsamples = [len(td) for td in data]
|
||||
|
||||
print(f"Got {nsamples} samples in {seconds} s.")
|
||||
norm_diodes = [1 / tm / 4 for tm in mean]
|
||||
if return_data:
|
||||
return data,norm_diodes
|
||||
return norm_diodes
|
||||
|
||||
def set_calibration_values(self, norm_diodes):
|
||||
self.calib_intensity.const_E.set_target_value(norm_diodes[0])
|
||||
self.calib_ypos.const_E.set_target_value(norm_diodes[0])
|
||||
self.calib_intensity.const_F.set_target_value(norm_diodes[1])
|
||||
self.calib_ypos.const_F.set_target_value(norm_diodes[1])
|
||||
self.calib_intensity.const_G.set_target_value(norm_diodes[2])
|
||||
self.calib_xpos.const_E.set_target_value(norm_diodes[2])
|
||||
self.calib_intensity.const_H.set_target_value(norm_diodes[3])
|
||||
self.calib_xpos.const_F.set_target_value(norm_diodes[3])
|
||||
|
||||
def get_calibration_values_position(
|
||||
self, calib_intensities, seconds=5, motion_range=0.2
|
||||
):
|
||||
self.x_diodes.set_limits(-motion_range / 2 - 0.1, +motion_range / 2 + 0.1)
|
||||
self.y_diodes.set_limits(-motion_range / 2 - 0.1, +motion_range / 2 + 0.1)
|
||||
self.x_diodes.set_target_value(0).wait()
|
||||
self.y_diodes.set_target_value(0).wait()
|
||||
raw = []
|
||||
for pos in [motion_range / 2, -motion_range / 2]:
|
||||
print(pos)
|
||||
self.x_diodes.set_target_value(pos).wait()
|
||||
aqs = [
|
||||
ts.acquire(seconds=seconds)
|
||||
for ts in [self.signal_left_raw, self.signal_right_raw]
|
||||
]
|
||||
vals = [
|
||||
np.mean(aq.wait()) * calib
|
||||
for aq, calib in zip(aqs, calib_intensities[0:2])
|
||||
]
|
||||
raw.append((vals[0] - vals[1]) / (vals[0] + vals[1]))
|
||||
xcalib = motion_range / np.diff(raw)[0]
|
||||
self.x_diodes.set_target_value(0).wait()
|
||||
raw = []
|
||||
for pos in [motion_range / 2, -motion_range / 2]:
|
||||
self.y_diodes.set_target_value(pos).wait()
|
||||
aqs = [
|
||||
ts.acquire(seconds=seconds)
|
||||
for ts in [self.signal_up_raw, self.signal_down_raw]
|
||||
]
|
||||
vals = [
|
||||
np.mean(aq.wait()) * calib
|
||||
for aq, calib in zip(aqs, calib_intensities[2:4])
|
||||
]
|
||||
raw.append((vals[0] - vals[1]) / (vals[0] + vals[1]))
|
||||
ycalib = motion_range / np.diff(raw)[0]
|
||||
self.y_diodes.set_target_value(0).wait()
|
||||
return xcalib, ycalib
|
||||
|
||||
def set_calibration_values_position(self, xcalib, ycalib):
|
||||
self.calib_xpos.const_I.set_target_value(xcalib)
|
||||
# self.calib_xpos.const_J.set_target_value(0)
|
||||
self.calib_ypos.const_I.set_target_value(ycalib)
|
||||
# self.calib_ypos.const_J.set_target_value(0)
|
||||
|
||||
def calibrate(self, seconds=5):
|
||||
c = self.get_calibration_values(seconds=seconds)
|
||||
self.set_calibration_values(c)
|
||||
xc, yc = self.get_calibration_values_position(c, seconds=seconds)
|
||||
self.set_calibration_values_position(xc, yc)
|
||||
|
||||
def set_gains(self, value):
|
||||
try:
|
||||
self.diode_up.gain.set(value)
|
||||
self.diode_down.gain.set(value)
|
||||
self.diode_left.gain.set(value)
|
||||
self.diode_right.gain.set(value)
|
||||
except:
|
||||
print("No diodes configured, can not change any gain!")
|
||||
|
||||
def get_available_gains(self):
|
||||
try:
|
||||
nu = self.diode_up.gain.names
|
||||
nd = self.diode_down.gain.names
|
||||
nl = self.diode_left.gain.names
|
||||
nr = self.diode_right.gain.names
|
||||
assert (
|
||||
nu == nd == nl == nr
|
||||
), "NB: the gain options of the four diodes are not equal!!!"
|
||||
return nu
|
||||
except:
|
||||
print("No diodes configured, can not change any gain!")
|
||||
|
||||
def get_gains(self):
|
||||
try:
|
||||
gains = dict()
|
||||
gains["up"] = (self.diode_up.gain.get_name(), self.diode_up.gain.get())
|
||||
gains["down"] = (
|
||||
self.diode_down.gain.get_name(),
|
||||
self.diode_down.gain.get(),
|
||||
)
|
||||
gains["left"] = (
|
||||
self.diode_left.gain.get_name(),
|
||||
self.diode_left.gain.get(),
|
||||
)
|
||||
gains["right"] = (
|
||||
self.diode_right.gain.get_name(),
|
||||
self.diode_right.gain.get(),
|
||||
)
|
||||
return gains
|
||||
except:
|
||||
print("No diodes configured, can not change any gain!")
|
||||
|
||||
|
||||
class SolidTargetDetectorPBPS_assi(Assembly):
|
||||
def __init__(
|
||||
self,
|
||||
@@ -340,108 +723,6 @@ class SolidTargetDetectorPBPS_new:
|
||||
# SAROP21-CVME-PBPS:Lnk10Ch15-WD-gain
|
||||
|
||||
|
||||
class SolidTargetDetectorPBPS:
|
||||
def __init__(
|
||||
self,
|
||||
Id,
|
||||
VME_crate=None,
|
||||
link=None,
|
||||
ch_up=12,
|
||||
ch_down=13,
|
||||
ch_left=15,
|
||||
ch_right=14,
|
||||
elog=None,
|
||||
name=None,
|
||||
):
|
||||
self.Id = Id
|
||||
self.name = name
|
||||
self.diode_x = MotorRecord(Id + ":MOTOR_X1", name="diode_x")
|
||||
self.diode_y = MotorRecord(Id + ":MOTOR_Y1", name="diode_y")
|
||||
self.target_pos = MotorRecord(Id + ":MOTOR_PROBE", name="target_pos")
|
||||
self.target = AdjustablePvEnum(Id + ":PROBE_SP", name="target")
|
||||
if VME_crate:
|
||||
self.diode_up = FeDigitizer("%s:Lnk%dCh%d" % (VME_crate, link, ch_up))
|
||||
self.diode_down = FeDigitizer("%s:Lnk%dCh%d" % (VME_crate, link, ch_down))
|
||||
self.diode_left = FeDigitizer("%s:Lnk%dCh%d" % (VME_crate, link, ch_left))
|
||||
self.diode_right = FeDigitizer("%s:Lnk%dCh%d" % (VME_crate, link, ch_right))
|
||||
|
||||
if self.name:
|
||||
self.alias = Alias(name)
|
||||
self.alias.append(self.diode_x.alias)
|
||||
self.alias.append(self.diode_y.alias)
|
||||
self.alias.append(self.target_pos.alias)
|
||||
self.alias.append(self.target.alias)
|
||||
|
||||
def __repr__(self):
|
||||
s = f"**Intensity monitor {self.name}**\n\n"
|
||||
|
||||
s += f"Target in: {self.target.get_current_value().name}\n\n"
|
||||
try:
|
||||
sd = "**Biasd voltage**\n"
|
||||
sd += " - Diode up: %.4f\n" % (sdelf.diode_up.get_biasd())
|
||||
sd += " - Diode down: %.4f\n" % (sdelf.diode_down.get_biasd())
|
||||
sd += " - Diode left: %.4f\n" % (sdelf.diode_left.get_biasd())
|
||||
sd += " - Diode right: %.4f\n" % (sdelf.diode_right.get_biasd())
|
||||
sd += "\n"
|
||||
|
||||
sd += "**Gain**\n"
|
||||
sd += " - Diode up: %i\n" % (sdelf.diode_up.gain.get())
|
||||
sd += " - Diode down: %i\n" % (sdelf.diode_down.gain.get())
|
||||
sd += " - Diode left: %i\n" % (sdelf.diode_left.gain.get())
|
||||
sd += " - Diode right: %i\n" % (sdelf.diode_right.gain.get())
|
||||
s += sd
|
||||
except:
|
||||
pass
|
||||
return s
|
||||
|
||||
def set_gains(self, value):
|
||||
try:
|
||||
self.diode_up.gain.set(value)
|
||||
self.diode_down.gain.set(value)
|
||||
self.diode_left.gain.set(value)
|
||||
self.diode_right.gain.set(value)
|
||||
except:
|
||||
print("No diodes configured, can not change any gain!")
|
||||
|
||||
def get_available_gains(self):
|
||||
try:
|
||||
nu = self.diode_up.gain.names
|
||||
nd = self.diode_down.gain.names
|
||||
nl = self.diode_left.gain.names
|
||||
nr = self.diode_right.gain.names
|
||||
assert (
|
||||
nu == nd == nl == nr
|
||||
), "NB: the gain options of the four diodes are not equal!!!"
|
||||
return nu
|
||||
except:
|
||||
print("No diodes configured, can not change any gain!")
|
||||
|
||||
def get_gains(self):
|
||||
try:
|
||||
gains = dict()
|
||||
gains["up"] = (self.diode_up.gain.get_name(), self.diode_up.gain.get())
|
||||
gains["down"] = (
|
||||
self.diode_down.gain.get_name(),
|
||||
self.diode_down.gain.get(),
|
||||
)
|
||||
gains["left"] = (
|
||||
self.diode_left.gain.get_name(),
|
||||
self.diode_left.gain.get(),
|
||||
)
|
||||
gains["right"] = (
|
||||
self.diode_right.gain.get_name(),
|
||||
self.diode_right.gain.get(),
|
||||
)
|
||||
return gains
|
||||
except:
|
||||
print("No diodes configured, can not change any gain!")
|
||||
|
||||
# SAROP21-CVME-PBPS:Lnk10Ch15-WD-gain
|
||||
|
||||
|
||||
from ..elements.assembly import Assembly
|
||||
|
||||
|
||||
class SolidTargetDetectorPBPS_new_assembly(Assembly):
|
||||
def __init__(
|
||||
self,
|
||||
@@ -714,7 +995,7 @@ class SolidTargetDetectorPBPS_assembly(Assembly):
|
||||
DetectorPvDataStream, calc["ypos"], name="ypos", is_setting=False
|
||||
)
|
||||
|
||||
def get_calibration_values(self, seconds=5):
|
||||
def get_calibration_values(self, seconds=5, return_data=False):
|
||||
self.x_diodes.set_target_value(0).wait()
|
||||
self.y_diodes.set_target_value(0).wait()
|
||||
ds = [self.signal_up, self.signal_down, self.signal_left, self.signal_right]
|
||||
@@ -723,6 +1004,8 @@ class SolidTargetDetectorPBPS_assembly(Assembly):
|
||||
mean = [np.mean(td) for td in data]
|
||||
std = [np.std(td) for td in data]
|
||||
norm_diodes = [1 / tm / 4 for tm in mean]
|
||||
if return_data:
|
||||
return data,norm_diodes
|
||||
return norm_diodes
|
||||
|
||||
def set_calibration_values(self, norm_diodes):
|
||||
@@ -839,3 +1122,253 @@ class SolidTargetDetectorPBPS_assembly(Assembly):
|
||||
return gains
|
||||
except:
|
||||
print("No diodes configured, can not change any gain!")
|
||||
|
||||
|
||||
class SolidTargetDetectorBerninaUSD(Assembly):
|
||||
def __init__(
|
||||
self,
|
||||
pv_targets,
|
||||
# VME_crate=None,
|
||||
# pipeline=None,
|
||||
# link=None,
|
||||
channel_xpos=None,
|
||||
channel_ypos=None,
|
||||
channel_intensity=None,
|
||||
diode_channels_raw={},
|
||||
# ch_up=12,
|
||||
# ch_down=13,
|
||||
# ch_left=15,
|
||||
# ch_right=14,
|
||||
# elog=None,
|
||||
use_calibration=True,
|
||||
calibration_records=None,
|
||||
name=None,
|
||||
# calc=None,
|
||||
# calc_calib={},
|
||||
):
|
||||
super().__init__(name=name)
|
||||
|
||||
self._append(
|
||||
SmaractRecord,
|
||||
pv_targets,
|
||||
name="target_x",
|
||||
is_setting=True,
|
||||
is_display=True,
|
||||
)
|
||||
if channel_intensity:
|
||||
self._append(
|
||||
DetectorBsStream,
|
||||
channel_intensity,
|
||||
name="intensity",
|
||||
is_setting=False,
|
||||
)
|
||||
|
||||
if channel_xpos:
|
||||
self._append(DetectorBsStream, channel_xpos, name="xpos", is_setting=False)
|
||||
# else:
|
||||
# self._append(
|
||||
# DetectorBsStream, pvname + ":XPOS", name="xpos", is_setting=False
|
||||
# )
|
||||
if channel_ypos:
|
||||
self._append(DetectorBsStream, channel_ypos, name="ypos", is_setting=False)
|
||||
# else:
|
||||
# self._append(
|
||||
# DetectorBsStream, pvname + ":YPOS", name="ypos", is_setting=False
|
||||
# )
|
||||
|
||||
if diode_channels_raw:
|
||||
self._append(
|
||||
DetectorBsStream,
|
||||
diode_channels_raw["up"],
|
||||
name="signal_up_raw",
|
||||
is_setting=False,
|
||||
)
|
||||
self._append(
|
||||
DetectorBsStream,
|
||||
diode_channels_raw["down"],
|
||||
name="signal_down_raw",
|
||||
is_setting=False,
|
||||
)
|
||||
self._append(
|
||||
DetectorBsStream,
|
||||
diode_channels_raw["left"],
|
||||
name="signal_left_raw",
|
||||
is_setting=False,
|
||||
)
|
||||
self._append(
|
||||
DetectorBsStream,
|
||||
diode_channels_raw["right"],
|
||||
name="signal_right_raw",
|
||||
is_setting=False,
|
||||
)
|
||||
|
||||
if use_calibration:
|
||||
# Calibration calculation record
|
||||
|
||||
# Calibration
|
||||
if calibration_records:
|
||||
self._append(
|
||||
CalibrationRecord,
|
||||
calibration_records["intensity"],
|
||||
name="calib_intensity",
|
||||
is_setting=True,
|
||||
is_display=False,
|
||||
)
|
||||
self._append(
|
||||
CalibrationRecord,
|
||||
calibration_records["xpos"],
|
||||
name="calib_xpos",
|
||||
is_setting=True,
|
||||
is_display=False,
|
||||
)
|
||||
self._append(
|
||||
CalibrationRecord,
|
||||
calibration_records["ypos"],
|
||||
name="calib_ypos",
|
||||
is_setting=True,
|
||||
is_display=False,
|
||||
)
|
||||
|
||||
# else:
|
||||
# self._append(
|
||||
# CalibrationRecord,
|
||||
# pvname + ":INTENSITY",
|
||||
# name="calib_intensity",
|
||||
# is_setting=True,
|
||||
# is_display=False,
|
||||
# )
|
||||
# self._append(
|
||||
# CalibrationRecord,
|
||||
# pvname + ":XPOS",
|
||||
# name="calib_xpos",
|
||||
# is_setting=True,
|
||||
# is_display=False,
|
||||
# )
|
||||
# self._append(
|
||||
# CalibrationRecord,
|
||||
# pvname + ":YPOS",
|
||||
# name="calib_ypos",
|
||||
# is_setting=True,
|
||||
# is_display=False,
|
||||
# )
|
||||
|
||||
def get_calibration_values(self, seconds=5):
|
||||
self.x_diodes.set_target_value(0).wait()
|
||||
self.y_diodes.set_target_value(0).wait()
|
||||
ds = [
|
||||
self.signal_up_raw,
|
||||
self.signal_down_raw,
|
||||
self.signal_left_raw,
|
||||
self.signal_right_raw,
|
||||
]
|
||||
aqs = [d.acquire(seconds=seconds) for d in ds]
|
||||
data = [aq.wait() for aq in aqs]
|
||||
mean = [np.mean(td) for td in data]
|
||||
std = [np.std(td) for td in data]
|
||||
nsamples = [len(td) for td in data]
|
||||
|
||||
print(f"Got {nsamples} samples in {seconds} s.")
|
||||
norm_diodes = [1 / tm / 4 for tm in mean]
|
||||
return norm_diodes
|
||||
|
||||
def set_calibration_values(self, norm_diodes):
|
||||
self.calib_intensity.const_E.set_target_value(norm_diodes[0])
|
||||
self.calib_ypos.const_E.set_target_value(norm_diodes[0])
|
||||
self.calib_intensity.const_F.set_target_value(norm_diodes[1])
|
||||
self.calib_ypos.const_F.set_target_value(norm_diodes[1])
|
||||
self.calib_intensity.const_G.set_target_value(norm_diodes[2])
|
||||
self.calib_xpos.const_E.set_target_value(norm_diodes[2])
|
||||
self.calib_intensity.const_H.set_target_value(norm_diodes[3])
|
||||
self.calib_xpos.const_F.set_target_value(norm_diodes[3])
|
||||
|
||||
def get_calibration_values_position(
|
||||
self, calib_intensities, seconds=5, motion_range=0.2
|
||||
):
|
||||
self.x_diodes.set_limits(-motion_range / 2 - 0.1, +motion_range / 2 + 0.1)
|
||||
self.y_diodes.set_limits(-motion_range / 2 - 0.1, +motion_range / 2 + 0.1)
|
||||
self.x_diodes.set_target_value(0).wait()
|
||||
self.y_diodes.set_target_value(0).wait()
|
||||
raw = []
|
||||
for pos in [motion_range / 2, -motion_range / 2]:
|
||||
print(pos)
|
||||
self.x_diodes.set_target_value(pos).wait()
|
||||
aqs = [
|
||||
ts.acquire(seconds=seconds)
|
||||
for ts in [self.signal_left_raw, self.signal_right_raw]
|
||||
]
|
||||
vals = [
|
||||
np.mean(aq.wait()) * calib
|
||||
for aq, calib in zip(aqs, calib_intensities[0:2])
|
||||
]
|
||||
raw.append((vals[0] - vals[1]) / (vals[0] + vals[1]))
|
||||
xcalib = motion_range / np.diff(raw)[0]
|
||||
self.x_diodes.set_target_value(0).wait()
|
||||
raw = []
|
||||
for pos in [motion_range / 2, -motion_range / 2]:
|
||||
self.y_diodes.set_target_value(pos).wait()
|
||||
aqs = [
|
||||
ts.acquire(seconds=seconds)
|
||||
for ts in [self.signal_up_raw, self.signal_down_raw]
|
||||
]
|
||||
vals = [
|
||||
np.mean(aq.wait()) * calib
|
||||
for aq, calib in zip(aqs, calib_intensities[2:4])
|
||||
]
|
||||
raw.append((vals[0] - vals[1]) / (vals[0] + vals[1]))
|
||||
ycalib = motion_range / np.diff(raw)[0]
|
||||
self.y_diodes.set_target_value(0).wait()
|
||||
return xcalib, ycalib
|
||||
|
||||
def set_calibration_values_position(self, xcalib, ycalib):
|
||||
self.calib_xpos.const_I.set_target_value(xcalib)
|
||||
self.calib_xpos.const_J.set_target_value(0)
|
||||
self.calib_ypos.const_I.set_target_value(ycalib)
|
||||
self.calib_ypos.const_J.set_target_value(0)
|
||||
|
||||
def calibrate(self, seconds=5):
|
||||
c = self.get_calibration_values(seconds=seconds)
|
||||
self.set_calibration_values(c)
|
||||
xc, yc = self.get_calibration_values_position(c, seconds=seconds)
|
||||
self.set_calibration_values_position(xc, yc)
|
||||
|
||||
def set_gains(self, value):
|
||||
try:
|
||||
self.diode_up.gain.set(value)
|
||||
self.diode_down.gain.set(value)
|
||||
self.diode_left.gain.set(value)
|
||||
self.diode_right.gain.set(value)
|
||||
except:
|
||||
print("No diodes configured, can not change any gain!")
|
||||
|
||||
def get_available_gains(self):
|
||||
try:
|
||||
nu = self.diode_up.gain.names
|
||||
nd = self.diode_down.gain.names
|
||||
nl = self.diode_left.gain.names
|
||||
nr = self.diode_right.gain.names
|
||||
assert (
|
||||
nu == nd == nl == nr
|
||||
), "NB: the gain options of the four diodes are not equal!!!"
|
||||
return nu
|
||||
except:
|
||||
print("No diodes configured, can not change any gain!")
|
||||
|
||||
def get_gains(self):
|
||||
try:
|
||||
gains = dict()
|
||||
gains["up"] = (self.diode_up.gain.get_name(), self.diode_up.gain.get())
|
||||
gains["down"] = (
|
||||
self.diode_down.gain.get_name(),
|
||||
self.diode_down.gain.get(),
|
||||
)
|
||||
gains["left"] = (
|
||||
self.diode_left.gain.get_name(),
|
||||
self.diode_left.gain.get(),
|
||||
)
|
||||
gains["right"] = (
|
||||
self.diode_right.gain.get_name(),
|
||||
self.diode_right.gain.get(),
|
||||
)
|
||||
return gains
|
||||
except:
|
||||
print("No diodes configured, can not change any gain!")
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
from eco.detector.detectors_psi import DetectorBsStream
|
||||
from ..devices_general.motors import MotorRecord, SmaractStreamdevice, SmaractRecord
|
||||
from ..devices_general.detectors import CameraCA, CameraBS
|
||||
from ..devices_general.cameras_swissfel import CameraBasler
|
||||
@@ -15,9 +16,15 @@ def addMotorRecordToSelf(self, Id=None, name=None):
|
||||
|
||||
|
||||
class Pprm(Assembly):
|
||||
def __init__(self, pvname, pvname_camera, name=None):
|
||||
def __init__(self, pvname, pvname_camera, name=None, in_target=1, bs_channels={}):
|
||||
super().__init__(name=name)
|
||||
self.pvname = pvname
|
||||
self.in_target = in_target
|
||||
|
||||
self._append(
|
||||
AdjustablePvEnum, self.pvname + ":PROBE_SP", name="target", is_setting=True
|
||||
)
|
||||
|
||||
self._append(
|
||||
MotorRecord,
|
||||
pvname_camera + ":MOTOR_PROBE",
|
||||
@@ -31,24 +38,32 @@ class Pprm(Assembly):
|
||||
camserver_alias=f"{name} ({pvname_camera})",
|
||||
name="camera",
|
||||
is_setting=True,
|
||||
is_display="recursive",
|
||||
)
|
||||
self._append(
|
||||
AdjustablePvEnum, self.pvname + ":LED", name="led", is_setting=True
|
||||
)
|
||||
self._append(
|
||||
AdjustablePvEnum, self.pvname + ":PROBE_SP", name="target", is_setting=True
|
||||
)
|
||||
for bscn,bscc in bs_channels.items():
|
||||
self._append(
|
||||
DetectorBsStream,
|
||||
bscc,
|
||||
name=bscn,
|
||||
is_setting=False,
|
||||
)
|
||||
|
||||
def movein(self, target=1):
|
||||
|
||||
def movein(self, target=None):
|
||||
if target == None:
|
||||
target = self.in_target
|
||||
self.target.set_target_value(target)
|
||||
|
||||
def moveout(self, target=0):
|
||||
self.target.set_target_value(target)
|
||||
|
||||
def __repr__(self):
|
||||
s = f"**Profile Monitor {self.name}**\n"
|
||||
s += f"Target in beam: {self.target.get_current_value().name}\n"
|
||||
return s
|
||||
# def __repr__(self):
|
||||
# s = f"**Profile Monitor {self.name}**\n"
|
||||
# s += f"Target in beam: {self.target.get_current_value().name}\n"
|
||||
# return s
|
||||
|
||||
|
||||
class Target_xyz(Assembly):
|
||||
@@ -93,7 +108,7 @@ class ProfKbBernina(Assembly):
|
||||
pvname_target_x="SARES20-MF2:MOT_1",
|
||||
pvname_target_y="SARES20-MF2:MOT_2",
|
||||
pvname_target_z="SARES20-MF2:MOT_3",
|
||||
pvname_mirror="SARES23:LIC11",
|
||||
pvname_mirror="SARES23-LIC:MOT_11",
|
||||
mirror_in=15,
|
||||
mirror_out=-5,
|
||||
pvname_zoom="SARES20-MF2:MOT_4",
|
||||
@@ -110,27 +125,10 @@ class ProfKbBernina(Assembly):
|
||||
pvname_z="SARES20-MF2:MOT_3",
|
||||
name="target_stages",
|
||||
is_display="recursive",
|
||||
is_setting=True,
|
||||
)
|
||||
self.target = self.target_stages.presets
|
||||
|
||||
self._append(
|
||||
MotorRecord,
|
||||
pvname_target_x,
|
||||
name="x_target",
|
||||
is_setting=True,
|
||||
)
|
||||
self._append(
|
||||
MotorRecord,
|
||||
pvname_target_y,
|
||||
name="y_target",
|
||||
is_setting=True,
|
||||
)
|
||||
self._append(
|
||||
MotorRecord,
|
||||
pvname_target_z,
|
||||
name="z_target",
|
||||
is_setting=True,
|
||||
)
|
||||
self._append(
|
||||
SmaractRecord,
|
||||
pvname_mirror,
|
||||
@@ -159,6 +157,8 @@ class ProfKbBernina(Assembly):
|
||||
self._append(
|
||||
MotorRecord, pvname_zoom, name="zoom", is_setting=True, is_display=True
|
||||
)
|
||||
ix = self.settings_collection._list.index(self.zoom.offset)
|
||||
self.settings_collection._list.pop(ix)
|
||||
|
||||
def movein_keep_target(self, wait=False):
|
||||
ch = self.mirror_in.set_target_value(1)
|
||||
@@ -173,18 +173,18 @@ class ProfKbBernina(Assembly):
|
||||
def movein(self, wait=False):
|
||||
ch = self.mirror_in.set_target_value(1)
|
||||
try:
|
||||
self.target_stages.presets.movein()
|
||||
self.presets.movein()
|
||||
except:
|
||||
print("No movein preset found for target stages.")
|
||||
print("No movein preset found for prof_kb.")
|
||||
if wait:
|
||||
ch.wait()
|
||||
|
||||
def moveout(self, wait=False):
|
||||
ch = self.mirror_in.set_target_value(0)
|
||||
try:
|
||||
self.target_stages.presets.moveout()
|
||||
self.presets.moveout()
|
||||
except:
|
||||
print("No moveout preset found for target stages.")
|
||||
print("No moveout preset found for prof_kb.")
|
||||
if wait:
|
||||
ch.wait()
|
||||
|
||||
|
||||
@@ -8,9 +8,17 @@ from ..devices_general.delay_stage import DelayStage
|
||||
from ..aliases import Alias, append_object_to_object
|
||||
from ..loptics.bernina_experiment import DelayTime
|
||||
from cam_server import PipelineClient
|
||||
from eco import Assembly
|
||||
|
||||
|
||||
class SpectralEncoder:
|
||||
class TargetStages(Assembly):
|
||||
def __init__(self,*args,name='target'):
|
||||
super().__init__(name=name)
|
||||
for df in args:
|
||||
self._append(MotorRecord,df[1],name=df[0], is_display=True, is_setting=True)
|
||||
|
||||
|
||||
class SpectralEncoder(Assembly):
|
||||
def __init__(
|
||||
self,
|
||||
pvname,
|
||||
@@ -20,36 +28,38 @@ class SpectralEncoder:
|
||||
"spect_tt": "SLAAR21-LMOT-M553:MOT",
|
||||
"retroreflector": "SLAAR21-LMOT-M561:MOT",
|
||||
},
|
||||
mirror_stages=None,
|
||||
):
|
||||
super().__init__(name=name)
|
||||
self.pvname = pvname
|
||||
self.name = name
|
||||
self.alias = Alias(name)
|
||||
append_object_to_object(
|
||||
self, MotorRecord, pvname + ":MOTOR_X1", name="x_target"
|
||||
)
|
||||
append_object_to_object(
|
||||
self, MotorRecord, pvname + ":MOTOR_Y1", name="y_target"
|
||||
)
|
||||
|
||||
self._append(
|
||||
TargetStages,
|
||||
('x',pvname + ":MOTOR_X1"),
|
||||
('y',pvname + ":MOTOR_Y1"),
|
||||
name='target_stages',
|
||||
is_display='recursive',
|
||||
is_setting=True,
|
||||
)
|
||||
|
||||
if delay_stages:
|
||||
for key, pv in delay_stages.items():
|
||||
tname = "delay_" + key + "_stg"
|
||||
append_object_to_object(self, MotorRecord, pv, name=tname)
|
||||
append_object_to_object(
|
||||
self, DelayTime, self.__dict__[tname], name="delay_" + key
|
||||
)
|
||||
|
||||
# self.delay = MotorRecord(self.Id + "-M424:MOT")
|
||||
# self.delayTime = DelayStage(self.delay)
|
||||
# self.data_reduction_client = PsenProcessingClient(
|
||||
# address=reduction_client_address
|
||||
# )
|
||||
self._append(MotorRecord, pv, name=tname, is_setting=True)
|
||||
self._append(
|
||||
DelayTime, self.__dict__[tname], name="delay_" + key
|
||||
)
|
||||
|
||||
if mirror_stages is not None:
|
||||
for key, pv in mirror_stages.items():
|
||||
self._append(MotorRecord, pv, name=key, is_setting=True)
|
||||
|
||||
# @property
|
||||
# def roi(self):
|
||||
# return self.data_reduction_client.get_roi_signal()
|
||||
|
||||
# @roi.setter
|
||||
# def roi(self, values):
|
||||
# def roi(self, values):tt_opt
|
||||
# self.data_reduction_client.set_roi_signal(values)
|
||||
|
||||
# @property
|
||||
@@ -60,15 +70,6 @@ class SpectralEncoder:
|
||||
# def roi_background(self, values):
|
||||
# self.data_reduction_client.set_roi_background(values)
|
||||
|
||||
def __repr__(self):
|
||||
s = [f"Status {self.name}"]
|
||||
s.append(str(self.x_target))
|
||||
s.append(str(self.y_target))
|
||||
# s.append(f"Data reduction is on")
|
||||
# s.append(f" roi {self.roi}")
|
||||
# s.append(f" roi_background {self.roi_background}")
|
||||
return "\n".join(s)
|
||||
|
||||
|
||||
class SpatialEncoder:
|
||||
def __init__(
|
||||
@@ -76,7 +77,7 @@ class SpatialEncoder:
|
||||
name=None,
|
||||
reduction_client_address="http://sf-daqsync-02:12003/",
|
||||
delay_stages={"spatial_tt": "SLAAR21-LMOT-M522:MOTOR_1"},
|
||||
pipeline_id="SARES20-CAMS142-M4_psen_db1",
|
||||
pipeline_id="SARES20-CAMS142-M4_psen_db",
|
||||
):
|
||||
self.name = name
|
||||
self.alias = Alias(name)
|
||||
|
||||
+23
-52
@@ -1,59 +1,30 @@
|
||||
from eco.elements.assembly import Assembly
|
||||
from ..aliases import Alias, append_object_to_object
|
||||
from ..devices_general.motors import MotorRecord
|
||||
from ..epics.adjustable import AdjustablePv, AdjustablePvEnum
|
||||
|
||||
|
||||
class Xspect:
|
||||
class Xspect(Assembly):
|
||||
def __init__(self, name=None):
|
||||
self.alias = Alias(name)
|
||||
append_object_to_object(
|
||||
self, MotorRecord, "SARFE10-PSSS055:MOTOR_X1", name="x_grating"
|
||||
)
|
||||
append_object_to_object(
|
||||
self, MotorRecord, "SARFE10-PSSS055:MOTOR_Y1", name="y_grating"
|
||||
)
|
||||
append_object_to_object(
|
||||
self, MotorRecord, "SARFE10-PSSS055:MOTOR_ROT_X1", name="rx_grating"
|
||||
)
|
||||
append_object_to_object(
|
||||
self, MotorRecord, "SARFE10-PSSS055:MOTOR_PROBE", name="transl_probe"
|
||||
)
|
||||
append_object_to_object(
|
||||
self, MotorRecord, "SARFE10-PSSS059:MOTOR_X2", name="x_girder"
|
||||
)
|
||||
append_object_to_object(
|
||||
self, MotorRecord, "SARFE10-PSSS059:MOTOR_X3", name="x_crystal"
|
||||
)
|
||||
append_object_to_object(
|
||||
self, MotorRecord, "SARFE10-PSSS059:MOTOR_Y3", name="y_crystal"
|
||||
)
|
||||
append_object_to_object(
|
||||
self, MotorRecord, "SARFE10-PSSS059:MOTOR_ROT_X3", name="rx_crystal"
|
||||
)
|
||||
append_object_to_object(
|
||||
self, MotorRecord, "SARFE10-PSSS059:MOTOR_Y4", name="y_alignment"
|
||||
)
|
||||
append_object_to_object(
|
||||
self, MotorRecord, "SARFE10-PSSS059:MOTOR_ROT_X4", name="rx_camera"
|
||||
)
|
||||
append_object_to_object(
|
||||
self, MotorRecord, "SARFE10-PSSS059:MOTOR_X5", name="x_camera"
|
||||
)
|
||||
append_object_to_object(
|
||||
self, AdjustablePvEnum, "SARFE10-PSSS055:GRATING_SP", name="grid_type"
|
||||
)
|
||||
append_object_to_object(
|
||||
self, AdjustablePvEnum, "SARFE10-PSSS059:CRYSTAL_SP", name="crystal_type"
|
||||
)
|
||||
append_object_to_object(
|
||||
self, AdjustablePvEnum, "SARFE10-PSSS055:PROBE_SP", name="probe"
|
||||
)
|
||||
append_object_to_object(
|
||||
self, AdjustablePv, "SARFE10-PSSS059:ENERGY", name="energy_center_setpoint"
|
||||
)
|
||||
append_object_to_object(
|
||||
self, AdjustablePv, "SARFE10-PSSS059:MOTOR_Z5", name="camera_z"
|
||||
)
|
||||
|
||||
|
||||
super().__init__(name=name)
|
||||
|
||||
self._append(MotorRecord, "SARFE10-PSSS055:MOTOR_X1", name="x_grating")
|
||||
self._append(MotorRecord, "SARFE10-PSSS055:MOTOR_Y1", name="y_grating")
|
||||
self._append(MotorRecord, "SARFE10-PSSS055:MOTOR_ROT_X1", name="rx_grating")
|
||||
self._append(MotorRecord, "SARFE10-PSSS055:MOTOR_PROBE", name="transl_probe")
|
||||
self._append(MotorRecord, "SARFE10-PSSS059:MOTOR_X2", name="x_girder")
|
||||
self._append(MotorRecord, "SARFE10-PSSS059:MOTOR_X3", name="x_crystal")
|
||||
self._append(MotorRecord, "SARFE10-PSSS059:MOTOR_Y3", name="y_crystal")
|
||||
self._append(MotorRecord, "SARFE10-PSSS059:MOTOR_ROT_X3", name="rx_crystal")
|
||||
self._append(MotorRecord, "SARFE10-PSSS059:MOTOR_Y4", name="y_alignment")
|
||||
self._append(MotorRecord, "SARFE10-PSSS059:MOTOR_ROT_X4", name="rx_camera")
|
||||
self._append(MotorRecord, "SARFE10-PSSS059:MOTOR_X5", name="x_camera")
|
||||
self._append(AdjustablePvEnum, "SARFE10-PSSS055:GRATING_SP", name="grid_type")
|
||||
self._append(
|
||||
AdjustablePvEnum, "SARFE10-PSSS059:CRYSTAL_SP", name="crystal_type"
|
||||
)
|
||||
self._append(AdjustablePvEnum, "SARFE10-PSSS055:PROBE_SP", name="probe")
|
||||
self._append(
|
||||
AdjustablePv, "SARFE10-PSSS059:ENERGY", name="energy_center_setpoint"
|
||||
)
|
||||
self._append(AdjustablePv, "SARFE10-PSSS059:MOTOR_Z5", name="camera_z")
|
||||
|
||||
+7
-157
@@ -12,157 +12,6 @@ import numpy as np
|
||||
from time import sleep
|
||||
|
||||
|
||||
class att_usd_targets(Assembly):
|
||||
def __init__(self, name=None, Id=None, alias_namespace=None, xp=None):
|
||||
super().__init__(name=name)
|
||||
self.Id = Id
|
||||
# self.name = name
|
||||
self.alias = Alias(name)
|
||||
self.E = None
|
||||
self.E_min = 1500
|
||||
self._sleeptime = 1
|
||||
self.motor_configuration = {
|
||||
"transl": {
|
||||
"id": "-LIC10",
|
||||
"pv_descr": " ",
|
||||
"type": 2,
|
||||
"sensor": 1,
|
||||
"speed": 250,
|
||||
"home_direction": "back",
|
||||
},
|
||||
}
|
||||
self._xp = xp
|
||||
self.E = None
|
||||
|
||||
for name, config in self.motor_configuration.items():
|
||||
self._append(
|
||||
SmaractStreamdevice,
|
||||
pvname=Id + config["id"],
|
||||
name=name,
|
||||
is_setting=True,
|
||||
is_display=False,
|
||||
)
|
||||
|
||||
Al = materials.Al
|
||||
self.targets = {
|
||||
"mat": np.array([Al, Al, Al, Al, Al, Al, Al, Al]),
|
||||
"d": np.array([0, 60, 160, 200, 300, 400, 500, 700]),
|
||||
"pos": np.array([-35, -25, -15, -5, 5, 15, 25, 35]),
|
||||
}
|
||||
|
||||
def _updateE(self, energy=None, check_once=False):
|
||||
while not energy:
|
||||
energy = PV("SARUN03-UIND030:FELPHOTENE").value
|
||||
energy = energy * 1000
|
||||
if energy < self.E_min:
|
||||
energy = None
|
||||
print(
|
||||
f"Machine photon energy is below {self.E_min} - waiting for the machine to recover"
|
||||
)
|
||||
sleep(self._sleeptime)
|
||||
self.E = energy
|
||||
print("Set energy to %s eV" % energy)
|
||||
return
|
||||
|
||||
def _calc_transmission(self):
|
||||
t = np.array(
|
||||
[
|
||||
np.exp(-d / mat.absorption_length(self.E))
|
||||
for d, mat in zip(self.targets["d"], self.targets["mat"])
|
||||
]
|
||||
)
|
||||
self.targets["t"] = t
|
||||
|
||||
def _find_nearest(self, a, a0):
|
||||
"Element in nd array `a` closest to the scalar value `a0`"
|
||||
idx = np.abs(a - a0).argmin()
|
||||
return idx, a[idx]
|
||||
|
||||
def set_transmission(self, value):
|
||||
self._updateE()
|
||||
self._calc_transmission()
|
||||
idx, t = self._find_nearest(self.targets["t"], value)
|
||||
pos = self.targets["pos"][idx]
|
||||
self._xp.close()
|
||||
self.transl.mv(pos)
|
||||
print(f"Set transmission to {t:0.2E} | Moving to target {idx} at pos {pos}")
|
||||
while abs(pos - self.transl.get_current_value()) > 0.1:
|
||||
sleep(0.1)
|
||||
print("transmission changed")
|
||||
self._xp.open()
|
||||
|
||||
def get_current_value(self):
|
||||
self._updateE()
|
||||
self._calc_transmission()
|
||||
idx, pos = self._find_nearest(
|
||||
self.targets["pos"], self.transl.get_current_value()
|
||||
)
|
||||
t = self.targets["t"][idx]
|
||||
return t
|
||||
|
||||
def set_stage_config(self):
|
||||
for name, config in self.motor_configuration.items():
|
||||
mot = self.__dict__[name]._device
|
||||
mot.put("NAME", config["pv_descr"])
|
||||
mot.put("STAGE_TYPE", config["type"])
|
||||
mot.put("SET_SENSOR_TYPE", config["sensor"])
|
||||
mot.put("CL_MAX_FREQ", config["speed"])
|
||||
sleep(0.5)
|
||||
mot.put("CALIBRATE.PROC", 1)
|
||||
|
||||
def home_smaract_stages(self, stages=None):
|
||||
if stages == None:
|
||||
stages = self.motor_configuration.keys()
|
||||
print("#### Positions before homing ####")
|
||||
print(self.__repr__())
|
||||
for name in stages:
|
||||
config = self.motor_configuration[name]
|
||||
mot = self.__dict__[name]._device
|
||||
print(
|
||||
"#### Homing {} in {} direction ####".format(
|
||||
name, config["home_direction"]
|
||||
)
|
||||
)
|
||||
sleep(1)
|
||||
if config["home_direction"] == "back":
|
||||
mot.put("FRM_BACK.PROC", 1)
|
||||
while mot.get("STATUS") == 7:
|
||||
sleep(1)
|
||||
if mot.get("GET_HOMED") == 0:
|
||||
print(
|
||||
"Homing failed, try homing {} in forward direction".format(name)
|
||||
)
|
||||
mot.put("FRM_FORW.PROC", 1)
|
||||
elif config["home_direction"] == "forward":
|
||||
mot.put("FRM_FORW.PROC", 1)
|
||||
while mot.get("STATUS") == 7:
|
||||
sleep(1)
|
||||
if mot.get("GET_HOMED") == 0:
|
||||
print(
|
||||
"Homing failed, try homing {} in backward direction".format(
|
||||
name
|
||||
)
|
||||
)
|
||||
mot.put("FRM_BACK.PROC", 1)
|
||||
|
||||
def get_adjustable_positions_str(self):
|
||||
ostr = "*****att_usd target position******\n"
|
||||
|
||||
for tkey, item in self.__dict__.items():
|
||||
if hasattr(item, "get_current_value"):
|
||||
pos = item.get_current_value()
|
||||
ostr += " " + tkey.ljust(17) + " : % 14g\n" % pos
|
||||
pos = self.get_current_value()
|
||||
ostr += " " + "Transmission".ljust(17) + " : % 14.02E\n" % pos
|
||||
return ostr
|
||||
|
||||
def __call__(self, *args, **kwargs):
|
||||
self.set_transmission(*args, **kwargs)
|
||||
|
||||
def __repr__(self):
|
||||
return self.get_adjustable_positions_str()
|
||||
|
||||
|
||||
class Att_usd(Assembly):
|
||||
"""This is an adjusted smaract record compatible version of the original att_usd by roman."""
|
||||
|
||||
@@ -172,8 +21,8 @@ class Att_usd(Assembly):
|
||||
self.E = None
|
||||
self.E_min = 1500
|
||||
self._sleeptime = 1
|
||||
self._append(SmaractRecord, "SARES23:LIC10", name="transl_2", is_setting=True)
|
||||
self._append(SmaractRecord, "SARES23:LIC3", name="transl_1", is_setting=True)
|
||||
self._append(SmaractRecord, "SARES23-LIC:MOT_10", name="transl_2", is_setting=True, is_display=True)
|
||||
self._append(SmaractRecord, "SARES23-LIC:MOT_3", name="transl_1", is_setting=True, is_display=True)
|
||||
self.motor_configuration = {
|
||||
"transl_2": {
|
||||
"id": "SARES23-LIC10",
|
||||
@@ -289,8 +138,9 @@ class Att_usd(Assembly):
|
||||
|
||||
def _updateE(self, energy=None, check_once=False):
|
||||
while not energy:
|
||||
energy = PV("SARUN03-UIND030:FELPHOTENE").value
|
||||
energy = energy * 1000
|
||||
energy = PV("SAROP21-ARAMIS:ENERGY").value
|
||||
if np.isnan(energy):
|
||||
energy = PV("SARUN:FELPHOTENE").value*1000
|
||||
if energy < self.E_min:
|
||||
energy = None
|
||||
print(
|
||||
@@ -298,7 +148,7 @@ class Att_usd(Assembly):
|
||||
)
|
||||
sleep(self._sleeptime)
|
||||
self.E = energy
|
||||
print("Set energy to %s eV" % energy)
|
||||
print("Calculating transmission for %s eV" % energy)
|
||||
return
|
||||
|
||||
def _calc_transmission(self):
|
||||
@@ -339,7 +189,7 @@ class Att_usd(Assembly):
|
||||
self.transl_2.set_target_value(p2)
|
||||
print(f"Set transmission to {t:0.2E} | Moving to pos {[p1, p2]}")
|
||||
while (abs(p1 - self.transl_1.get_current_value()) > 0.05) or (
|
||||
abs(p2 - self.transl_2.get_current_value() > 0.05)
|
||||
(abs(p2 - self.transl_2.get_current_value()) > 0.05)
|
||||
):
|
||||
sleep(0.1)
|
||||
print("transmission changed")
|
||||
|
||||
@@ -6,7 +6,7 @@ from ..aliases import Alias
|
||||
from ..elements.adjustable import AdjustableFS
|
||||
from ..epics.adjustable import AdjustablePvEnum
|
||||
from ..elements.assembly import Assembly
|
||||
|
||||
from numpy import isnan
|
||||
|
||||
class AttenuatorAramis:
|
||||
def __init__(
|
||||
@@ -45,8 +45,9 @@ class AttenuatorAramis:
|
||||
|
||||
def updateE(self, energy=None):
|
||||
while not energy:
|
||||
energy = PV("SARUN03-UIND030:FELPHOTENE").value
|
||||
energy = energy * 1000
|
||||
energy = PV("SAROP21-ARAMIS:ENERGY").value
|
||||
if isnan(energy):
|
||||
energy = PV("SARUN:FELPHOTENE").value*1000
|
||||
if energy < self.E_min:
|
||||
energy = None
|
||||
print(
|
||||
@@ -54,7 +55,7 @@ class AttenuatorAramis:
|
||||
)
|
||||
sleep(self._sleeptime)
|
||||
PV(self.Id + ":ENERGY").put(energy)
|
||||
print("Set energy to %s eV" % energy)
|
||||
print("Calculating transmission for %s eV" % energy)
|
||||
return
|
||||
|
||||
def set_transmission(self, value, energy=None):
|
||||
|
||||
+2
-1
@@ -358,7 +358,8 @@ class AlvraDCM_FEL:
|
||||
# self.IOCstatus = PV('ALVRA:running') # bool 0 running, 1 not running
|
||||
self._FELcoupling = PV("SGE-OP2E-ARAMIS:MODE_SP") # string "Off" or "e-beam"
|
||||
self._setEnergy = PV("SAROP11-ARAMIS:ENERGY_SP_USER") # float eV
|
||||
self._getEnergy = PV("SAROP11-ARAMIS:ENERGY") # float eV
|
||||
#self._getEnergy = PV("SAROP11-ARAMIS:ENERGY") # float eV
|
||||
self._getEnergy = PV("SAROP21-ODCM098:ENERGY") # float eV
|
||||
self.ebeamEnergy = PV("SARCL02-MBND100:P-READ") # float MeV/c
|
||||
# self.ebeamEnergySP = PV('ALVRA:Energy_SP') # float MeV
|
||||
self.dcmStop = PV("SAROP11-ODCM105:STOP.PROC") # stop the DCM motors
|
||||
|
||||
+181
-1
@@ -1,5 +1,7 @@
|
||||
from ..devices_general.motors import MotorRecord, MotorRecord_new
|
||||
from eco.elements.adjustable import AdjustableFS, AdjustableVirtual
|
||||
from ..epics.adjustable import AdjustablePv, AdjustablePvEnum
|
||||
from ..epics.detector import DetectorPvData
|
||||
from epics import PV
|
||||
from ..devices_general.utilities import Changer
|
||||
from time import sleep
|
||||
@@ -13,6 +15,7 @@ from ..elements.adjustable import (
|
||||
)
|
||||
from ..devices_general.utilities import Changer
|
||||
from ..elements.assembly import Assembly
|
||||
from eco.xoptics.dcm_pathlength_compensation import MonoTimecompensation
|
||||
|
||||
|
||||
@spec_convenience
|
||||
@@ -21,13 +24,42 @@ from ..elements.assembly import Assembly
|
||||
class DoubleCrystalMono(Assembly):
|
||||
def __init__(
|
||||
self,
|
||||
pvname,
|
||||
pvname=None,
|
||||
name=None,
|
||||
energy_sp="SAROP21-ARAMIS:ENERGY_SP",
|
||||
energy_rb="SAROP21-ARAMIS:ENERGY",
|
||||
fel=None,
|
||||
las=None,
|
||||
undulator_deadband_eV=None,
|
||||
):
|
||||
super().__init__(name=name)
|
||||
self._fel = fel
|
||||
self._las = las
|
||||
self.undulator_deadband_eV = undulator_deadband_eV
|
||||
self.pvname = pvname
|
||||
|
||||
self._append(
|
||||
AdjustablePvEnum,
|
||||
self.pvname + ":MODE",
|
||||
pvname_set=self.pvname + ":MODE_SP",
|
||||
name="mode",
|
||||
)
|
||||
|
||||
self._append(
|
||||
AdjustablePvEnum,
|
||||
self.pvname + ":CRYSTAL",
|
||||
pvname_set=self.pvname + ":CRYSTAL_SP",
|
||||
name="crystal",
|
||||
)
|
||||
|
||||
self._append(
|
||||
AdjustablePvEnum,
|
||||
self.pvname + ":DIFF_ORDER",
|
||||
name="diffraction_order",
|
||||
)
|
||||
|
||||
self._append(DcmConfig, self.pvname, name="mono_config")
|
||||
|
||||
self._append(
|
||||
MotorRecord_new,
|
||||
pvname + ":RX12",
|
||||
@@ -54,6 +86,15 @@ class DoubleCrystalMono(Assembly):
|
||||
pvname + ":RZ1",
|
||||
name="roll1",
|
||||
is_setting=True,
|
||||
has_park_pv=True,
|
||||
view_toplevel_only=True,
|
||||
)
|
||||
self._append(
|
||||
AdjustablePv,
|
||||
pvname + ":PIEZO1_VOLTAGE_SP",
|
||||
pvreadbackname=pvname + ":PIEZO1_VOLTAGE",
|
||||
name="roll1_piezo",
|
||||
is_setting=True,
|
||||
view_toplevel_only=True,
|
||||
)
|
||||
self._append(
|
||||
@@ -68,6 +109,15 @@ class DoubleCrystalMono(Assembly):
|
||||
pvname + ":RX2",
|
||||
name="pitch2",
|
||||
is_setting=True,
|
||||
has_park_pv=True,
|
||||
view_toplevel_only=True,
|
||||
)
|
||||
self._append(
|
||||
AdjustablePv,
|
||||
pvname + ":PIEZO2_VOLTAGE_SP",
|
||||
pvreadbackname=pvname + ":PIEZO2_VOLTAGE",
|
||||
name="pitch2_piezo",
|
||||
is_setting=True,
|
||||
view_toplevel_only=True,
|
||||
)
|
||||
self._append(
|
||||
@@ -77,7 +127,81 @@ class DoubleCrystalMono(Assembly):
|
||||
accuracy=0.5,
|
||||
name="energy",
|
||||
)
|
||||
self._append(
|
||||
DetectorPvData,
|
||||
energy_rb,
|
||||
name="readback",
|
||||
is_setting=False,
|
||||
is_display=False,
|
||||
)
|
||||
self.settings_collection.append(self)
|
||||
if self._fel is not None:
|
||||
self._append(
|
||||
AdjustableFS,
|
||||
"/photonics/home/gac-bernina/eco/configuration/mono_und_offset",
|
||||
name="mono_und_calib",
|
||||
default_value=[[6500, 0], [7100, 0]],
|
||||
is_setting=True,
|
||||
)
|
||||
|
||||
def en_set(en):
|
||||
ofs = np.array(self.mono_und_calib()).T
|
||||
fel_ofs = ofs[1][np.argmin(abs(ofs[0] - en))]
|
||||
e_und_curr = (
|
||||
self._fel.aramis_photon_energy_undulators.get_current_value()
|
||||
)
|
||||
|
||||
if (
|
||||
np.abs(en - (e_und_curr + fel_ofs) * 1000)
|
||||
< self.undulator_deadband_eV
|
||||
):
|
||||
return en, None
|
||||
else:
|
||||
return en, en / 1000 - fel_ofs
|
||||
|
||||
def en_get(monoen, felen):
|
||||
return monoen
|
||||
|
||||
self._append(
|
||||
AdjustableVirtual,
|
||||
[self.energy, self._fel.aramis_photon_energy_undulators],
|
||||
en_get,
|
||||
en_set,
|
||||
name="mono_und_energy",
|
||||
)
|
||||
if self._las is not None:
|
||||
self._append(
|
||||
MonoTimecompensation,
|
||||
self._las.delay_glob,
|
||||
self.mono_und_energy,
|
||||
"/sf/bernina/config/eco/reference_values/dcm_reference_timing.json",
|
||||
"/sf/bernina/config/eco/reference_values/dcm_reference_invert_delay.json",
|
||||
name="mono_und_energy_time_corrected",
|
||||
is_setting=False,
|
||||
is_display=True,
|
||||
)
|
||||
if self._las is not None:
|
||||
self._append(
|
||||
MonoTimecompensation,
|
||||
self._las.delay_glob,
|
||||
self.energy,
|
||||
"/sf/bernina/config/eco/reference_values/dcm_reference_timing.json",
|
||||
"/sf/bernina/config/eco/reference_values/dcm_reference_invert_delay.json",
|
||||
name="mono_time_corrected",
|
||||
is_setting=False,
|
||||
is_display=True,
|
||||
)
|
||||
|
||||
def add_mono_und_calibration_point(self):
|
||||
mono_energy = self.energy.get_current_value()
|
||||
fel_offset = (
|
||||
self.energy.get_current_value() / 1000
|
||||
- self._fel.aramis_photon_energy_undulators.get_current_value()
|
||||
)
|
||||
self.mono_und_calib.mvr([[mono_energy, fel_offset]])
|
||||
|
||||
def reset_mono_und_calibration(self):
|
||||
self.mono_und_calib.mv([])
|
||||
|
||||
def set_target_value(self, *args, **kwargs):
|
||||
return self.energy.set_target_value(*args, **kwargs)
|
||||
@@ -98,6 +222,62 @@ class DoubleCrystalMono(Assembly):
|
||||
self.energy._pvreadback.clear_callbacks()
|
||||
|
||||
|
||||
class DcmConfig(Assembly):
|
||||
def __init__(self, pvbase, name=None):
|
||||
super().__init__(name=name)
|
||||
self.pvbase = pvbase
|
||||
|
||||
self._append(DetectorPvData, self.pvbase + ":PITCH1_OFF", name="pitch1_offset")
|
||||
self._append(DetectorPvData, self.pvbase + ":ROLL1_OFF", name="roll1_offset")
|
||||
self._append(DetectorPvData, self.pvbase + ":PITCH2_OFF", name="pitch2_offset")
|
||||
self._append(DetectorPvData, self.pvbase + ":ROLL2_OFF", name="roll2_offset")
|
||||
self._append(DetectorPvData, self.pvbase + ":T2_OFF", name="gap_offset")
|
||||
self._append(DetectorPvData, self.pvbase + ":TX_OFF", name="x_offset")
|
||||
self._append(DetectorPvData, self.pvbase + ":T2_MIN", name="gap_min")
|
||||
self._append(DetectorPvData, self.pvbase + ":T2_MAX", name="gap_max")
|
||||
self._append(DcmConfigSet, self.pvbase, "CRY1", name="config_Si111")
|
||||
self._append(DcmConfigSet, self.pvbase, "CRY2", name="config_Si311")
|
||||
self._append(DcmConfigSet, self.pvbase, "CRY3", name="config_InSb111")
|
||||
|
||||
|
||||
class DcmConfigSet(Assembly):
|
||||
# SAROP21-ODCM098:PITCH1_CRY1_OFF
|
||||
def __init__(self, pvbase, par_set_name=None, name=None):
|
||||
super().__init__(name=name)
|
||||
self.pvbase = pvbase
|
||||
self.par_set_name = par_set_name
|
||||
self._append(
|
||||
AdjustablePv,
|
||||
self.pvbase + ":PITCH1_" + self.par_set_name + "_OFF",
|
||||
name="pitch1_offset",
|
||||
)
|
||||
self._append(
|
||||
AdjustablePv,
|
||||
self.pvbase + ":ROLL1_" + self.par_set_name + "_OFF",
|
||||
name="roll1_offset",
|
||||
)
|
||||
self._append(
|
||||
AdjustablePv,
|
||||
self.pvbase + ":PITCH2_" + self.par_set_name + "_OFF",
|
||||
name="pitch2_offset",
|
||||
)
|
||||
self._append(
|
||||
AdjustablePv,
|
||||
self.pvbase + ":ROLL2_" + self.par_set_name + "_OFF",
|
||||
name="roll2_offset",
|
||||
)
|
||||
self._append(
|
||||
AdjustablePv,
|
||||
self.pvbase + ":T2_" + self.par_set_name + "_OFF",
|
||||
name="gap_offset",
|
||||
)
|
||||
self._append(
|
||||
AdjustablePv,
|
||||
self.pvbase + ":TX_" + self.par_set_name + "_OFF",
|
||||
name="x_offset",
|
||||
)
|
||||
|
||||
|
||||
@spec_convenience
|
||||
@default_representation
|
||||
class EcolEnergy(Assembly):
|
||||
|
||||
@@ -3,6 +3,8 @@ import numpy as np
|
||||
from xrayutilities import materials
|
||||
from ..elements.adjustable import AdjustableFS, AdjustableVirtual
|
||||
from ..elements.assembly import Assembly
|
||||
from eco import Adjustable
|
||||
from eco.devices_general.motors import MotorRecord
|
||||
|
||||
|
||||
def energy2tthe(energy, hkl=(1, 1, 1), material=materials.Si):
|
||||
@@ -43,7 +45,11 @@ class MonoTimecompensation(Assembly):
|
||||
default_value=True,
|
||||
name="laser_delay_inverted",
|
||||
)
|
||||
self._laser_delay = laser_delay_seconds
|
||||
if isinstance(laser_delay_seconds, Adjustable):
|
||||
self._laser_delay = laser_delay_seconds
|
||||
else:
|
||||
raise Exception("issue getting laser delay for mono compensation")
|
||||
|
||||
self._mono_energy = mono_energy_eV
|
||||
self._append(
|
||||
AdjustableVirtual,
|
||||
|
||||
+29
-111
@@ -10,7 +10,7 @@ from numbers import Number
|
||||
from tabulate import tabulate
|
||||
|
||||
|
||||
class KBMirrorBernina_new(Assembly):
|
||||
class KBMirrorBernina(Assembly):
|
||||
def __init__(
|
||||
self,
|
||||
pvname_ver,
|
||||
@@ -26,6 +26,7 @@ class KBMirrorBernina_new(Assembly):
|
||||
d_target=1520.0,
|
||||
d_att=1420.0,
|
||||
d_prof_dsd=3725.0,
|
||||
d_plate_mondsd=3147.5,
|
||||
name=None,
|
||||
):
|
||||
"""All distances are from sample interaction point at straight beam (no kb deflection), the units are expected in mm"""
|
||||
@@ -37,6 +38,9 @@ class KBMirrorBernina_new(Assembly):
|
||||
self._append(
|
||||
KbHor, pvname_hor, name="hor", is_setting=True, is_display="recursive"
|
||||
)
|
||||
self._append(
|
||||
AdjustablePvEnum, "SAROP21-OKB:MODE_SP", name="mode", is_setting=False
|
||||
)
|
||||
self.diffractometer = diffractometer
|
||||
|
||||
self.usd_table = usd_table
|
||||
@@ -48,9 +52,10 @@ class KBMirrorBernina_new(Assembly):
|
||||
self.d_win1 = d_win1
|
||||
self.d_target = d_target
|
||||
self.d_prof_dsd = d_prof_dsd
|
||||
self.d_plate_mondsd = d_plate_mondsd
|
||||
|
||||
def calc_positions(self, the_kbver, the_kbhor):
|
||||
"""angles in rad"""
|
||||
"""angles in rad, positive only (i.e. describe incidence angles to KBs)"""
|
||||
pos_calc = {}
|
||||
pos_calc["y_kbhor"] = np.tan(2 * the_kbver) * np.abs(
|
||||
self.d_kbver - self.d_kbhor
|
||||
@@ -62,16 +67,25 @@ class KBMirrorBernina_new(Assembly):
|
||||
pos_calc["ry_hex"] = 2 * the_kbhor
|
||||
pos_calc["x_diff"] = np.tan(2 * the_kbhor) * np.abs(self.d_kbhor)
|
||||
pos_calc["y_diff"] = np.tan(2 * the_kbver) * np.abs(self.d_kbver)
|
||||
pos_calc["x_dsd"] = np.tan(2 * the_kbhor) * np.abs(
|
||||
pos_calc["x_prof_dsd"] = np.tan(2 * the_kbhor) * np.abs(
|
||||
self.d_kbhor + self.d_prof_dsd
|
||||
)
|
||||
pos_calc["y_dsd"] = np.tan(2 * the_kbver) * np.abs(
|
||||
pos_calc["y_prof_dsd"] = np.tan(2 * the_kbver) * np.abs(
|
||||
self.d_kbver + self.d_prof_dsd
|
||||
)
|
||||
pos_calc["x_plate_mon_dsd"] = np.tan(2 * the_kbhor) * np.abs(
|
||||
self.d_kbhor + self.d_plate_mondsd
|
||||
)
|
||||
pos_calc["y_plate_mon_dsd"] = np.tan(2 * the_kbver) * np.abs(
|
||||
self.d_kbver + self.d_plate_mondsd
|
||||
)
|
||||
return pos_calc
|
||||
|
||||
def calc_fwhm(self, fwhm_hor, fwhm_ver, z_focver=0, z_fochor=0, E_phot=None):
|
||||
"""E_phot in eV, length units in mm."""
|
||||
def calc_fwhm(
|
||||
self, fwhm_hor, fwhm_ver, z_focver=0, z_fochor=0, distances={}, E_phot=None
|
||||
):
|
||||
"""calculates beamsize at different locations based on the Beam size before kb focusing.
|
||||
E_phot in eV, length units in mm."""
|
||||
lam = constants.c * constants.h / constants.electron_volt / E_phot
|
||||
print(lam * 1e10)
|
||||
fwhm_fac = 1 / np.sqrt(2 * np.log(2)) # w = fwhm_fac*fwhm
|
||||
@@ -109,6 +123,13 @@ class KBMirrorBernina_new(Assembly):
|
||||
res["sample"] = (fwhm_z(z_fochor, w0_hor), fwhm_z(z_focver, w0_ver))
|
||||
# res['fwhm_kbver'] = (fwhm_z(self.d_kbver+z_fochor,w0_hor),fwhm_z(self.d_kbver+z_focver,w0_ver))
|
||||
# res['fwhm_kbhor'] = (fwhm_z(self.d_kbhor+z_fochor,w0_hor),fwhm_z(self.d_kbhor+z_focver,w0_ver))
|
||||
|
||||
for tdn, tdv in distances.items():
|
||||
res[tdn] = (
|
||||
fwhm_z(tdv + z_fochor, w0_hor),
|
||||
fwhm_z(tdv + z_focver, w0_ver),
|
||||
)
|
||||
|
||||
return res
|
||||
|
||||
def move_hex_for_kb_angles(self, the_kbver, the_kbhor):
|
||||
@@ -153,6 +174,8 @@ class KBMirrorBernina_new(Assembly):
|
||||
ocoo = self.usd_table.get_coordinates()
|
||||
odiffx = self.diffractometer.xbase.get_current_value()
|
||||
odiffy = self.diffractometer.ybase.get_current_value()
|
||||
|
||||
# TODO implement motions for the angles as well. ISSUE is that the rx motion somehow decreases the distance to the usd too much for the shurt bellows (as of Feb 27 2023).
|
||||
odiffrx = self.diffractometer.rxbase.get_current_value()
|
||||
odiffnu = self.diffractometer.nu.get_current_value()
|
||||
odiffmu = self.diffractometer.mu.get_current_value()
|
||||
@@ -263,111 +286,6 @@ class KBMirrorBernina_new(Assembly):
|
||||
return focpos_hor, focpos_ver, out
|
||||
|
||||
|
||||
class KBMirrorBernina:
|
||||
def __init__(
|
||||
self,
|
||||
kb_ver=None,
|
||||
kb_hor=None,
|
||||
usd_table=None,
|
||||
d_kbver=3350.0,
|
||||
d_kbhor=2600.0,
|
||||
d_hex=1600.0,
|
||||
d_win1=1945.0,
|
||||
d_win2=1330.0,
|
||||
d_target=1520.0,
|
||||
d_att=1420.0,
|
||||
):
|
||||
"""All distances are from sample interaction point at straight beam (no kb deflection), the units are expected in mm"""
|
||||
self.kb_ver = kb_ver
|
||||
self.kb_hor = kb_hor
|
||||
self.usd_table = usd_table
|
||||
self.d_kbver = d_kbver
|
||||
self.d_kbhor = d_kbhor
|
||||
self.d_hex = d_hex
|
||||
self.d_att = d_att
|
||||
self.d_win2 = d_win2
|
||||
self.d_win1 = d_win1
|
||||
self.d_target = d_target
|
||||
|
||||
def calc_positions(self, the_kbver, the_kbhor):
|
||||
"""angles in rad"""
|
||||
y_kbhor = np.tan(2 * the_kbver) * np.abs(self.d_kbver - self.d_kbhor)
|
||||
rx_kbhor = -2 * the_kbver
|
||||
y_hex = np.tan(2 * the_kbver) * np.abs(self.d_kbver - self.d_hex)
|
||||
x_hex = np.tan(2 * the_kbhor) * np.abs(self.d_kbhor - self.d_hex)
|
||||
rx_hex = rx_kbhor
|
||||
ry_hex = 2 * the_kbhor
|
||||
return {
|
||||
"y_kbhor": y_kbhor,
|
||||
"rx_kbhor": rx_kbhor,
|
||||
"x_hex": x_hex,
|
||||
"y_hex": y_hex,
|
||||
"rx_hex": rx_hex,
|
||||
"ry_hex": ry_hex,
|
||||
}
|
||||
|
||||
def calc_fwhm(self, fwhm_hor, fwhm_ver, z_focver=0, z_fochor=0, E_phot=None):
|
||||
"""E_phot in eV, length units in mm."""
|
||||
lam = constants.c * constants.h / constants.electron_volt / E_phot
|
||||
print(lam * 1e10)
|
||||
fwhm_fac = 1 / np.sqrt(2 * np.log(2)) # w = fwhm_fac*fwhm
|
||||
# div_ver = np.arctan(fwhm_ver*fwhm_fac/2/(self.d_kbver+z_focver)) #half divergence
|
||||
# div_hor = np.arctan(fwhm_hor*fwhm_fac/2/(self.d_kbhor+z_fochor))
|
||||
c = lam / np.pi * 1e3
|
||||
|
||||
w0 = lambda w, z: (
|
||||
w**2 - (w**4 - (2 * c * z) ** 2) ** 0.5
|
||||
) ** 0.5 / np.sqrt(2)
|
||||
w = lambda w0, z: (w0**2 + (c * z / w0) ** 2) ** 0.5
|
||||
zr = lambda w0: w0**2 / c
|
||||
|
||||
fwhm_z = lambda z, w0: w(w0, z) / fwhm_fac
|
||||
w0_hor = w0(fwhm_hor * fwhm_fac, self.d_kbhor + z_fochor)
|
||||
w0_ver = w0(fwhm_ver * fwhm_fac, self.d_kbver + z_focver)
|
||||
print(w0_hor)
|
||||
res = {}
|
||||
res["target"] = (
|
||||
fwhm_z(self.d_target + z_fochor, w0_hor),
|
||||
fwhm_z(self.d_target + z_focver, w0_ver),
|
||||
)
|
||||
res["win1"] = (
|
||||
fwhm_z(self.d_win1 + z_fochor, w0_hor),
|
||||
fwhm_z(self.d_win1 + z_focver, w0_ver),
|
||||
)
|
||||
res["win2"] = (
|
||||
fwhm_z(self.d_win2 + z_fochor, w0_hor),
|
||||
fwhm_z(self.d_win2 + z_focver, w0_ver),
|
||||
)
|
||||
res["att"] = (
|
||||
fwhm_z(self.d_att + z_fochor, w0_hor),
|
||||
fwhm_z(self.d_att + z_focver, w0_ver),
|
||||
)
|
||||
res["sample"] = (fwhm_z(z_fochor, w0_hor), fwhm_z(z_focver, w0_ver))
|
||||
# res['fwhm_kbver'] = (fwhm_z(self.d_kbver+z_fochor,w0_hor),fwhm_z(self.d_kbver+z_focver,w0_ver))
|
||||
# res['fwhm_kbhor'] = (fwhm_z(self.d_kbhor+z_fochor,w0_hor),fwhm_z(self.d_kbhor+z_focver,w0_ver))
|
||||
return res
|
||||
|
||||
def move_hex_for_kb_angles(self, the_kbver, the_kbhor):
|
||||
pos = self.calc_positions(the_kbver, the_kbhor)
|
||||
x = pos["x_hex"]
|
||||
y = pos["y_hex"]
|
||||
rx = pos["rx_hex"] * 180 / np.pi
|
||||
ry = pos["ry_hex"] * 180 / np.pi
|
||||
z = rz = 0.0
|
||||
ax, ay, az, arx, ary, arz = self.usd_table.get_coordinates()
|
||||
print(
|
||||
f"present upstream large hexapod position is (x/mm,y/mm,z/mm,rx/°,ry/°,rz/°) = ({ax:g},{ay:g},{az:g},{arx:g},{ary:g},{arz:g})"
|
||||
)
|
||||
print(
|
||||
f"moving to (x/mm,y/mm,z/mm,rx/°,ry/°,rz/°) = ({x:g},{y:g},{z:g},{rx:g},{ry:g},{rz:g})"
|
||||
)
|
||||
if not input("start moving upstream large hexapod? (y/n)") == "y":
|
||||
print("did nothing")
|
||||
return
|
||||
else:
|
||||
self.usd_table.move_to_coordinates(x, y, z, rx, ry, rz)
|
||||
|
||||
|
||||
def calc_focus_pos_intercept(size0, size1, distance):
|
||||
"""calculates the position of the focus based on simple intercept theorem.
|
||||
position is from where size 0 was measured, and the focus will be between the
|
||||
|
||||
+67
-10
@@ -3,6 +3,7 @@ from ..devices_general.motors import MotorRecord
|
||||
from ..elements.adjustable import AdjustableVirtual
|
||||
from ..epics.adjustable import AdjustablePv, AdjustablePvEnum
|
||||
import numpy as np
|
||||
from epics import PV
|
||||
|
||||
|
||||
class KbVer(Assembly):
|
||||
@@ -40,6 +41,7 @@ class KbVer(Assembly):
|
||||
lambda b1, b2: float(np.mean([b1, b2])),
|
||||
lambda mn: self._get_benders_set_mean(mn),
|
||||
name="bender_mean",
|
||||
unit="mm",
|
||||
is_setting=False,
|
||||
is_display=True,
|
||||
)
|
||||
@@ -49,6 +51,7 @@ class KbVer(Assembly):
|
||||
lambda b1, b2: float(np.diff([b1, b2])),
|
||||
lambda mn: self._get_benders_set_diff(mn),
|
||||
name="bender_diff",
|
||||
unit="mm",
|
||||
is_setting=False,
|
||||
is_display=True,
|
||||
)
|
||||
@@ -68,11 +71,37 @@ class KbVer(Assembly):
|
||||
)
|
||||
|
||||
#### actual motors ###
|
||||
self._append(MotorRecord, pvname + ":TY1", name="_Y1", is_setting=True)
|
||||
self._append(MotorRecord, pvname + ":TY2", name="_Y2", is_setting=True)
|
||||
self._append(MotorRecord, pvname + ":TY3", name="_Y3", is_setting=True)
|
||||
self._append(MotorRecord, pvname + ":TX1", name="_X1", is_setting=True)
|
||||
self._append(MotorRecord, pvname + ":TX2", name="_X2", is_setting=True)
|
||||
self._append(
|
||||
MotorRecord, pvname + ":TY1", name="_Y1", is_setting=True, is_display=False
|
||||
)
|
||||
self._append(
|
||||
MotorRecord, pvname + ":TY2", name="_Y2", is_setting=True, is_display=False
|
||||
)
|
||||
self._append(
|
||||
MotorRecord, pvname + ":TY3", name="_Y3", is_setting=True, is_display=False
|
||||
)
|
||||
self._append(
|
||||
MotorRecord, pvname + ":TX1", name="_X1", is_setting=True, is_display=False
|
||||
)
|
||||
self._append(
|
||||
MotorRecord, pvname + ":TX2", name="_X2", is_setting=True, is_display=False
|
||||
)
|
||||
self._pv_sync_world = PV(pvname + ":SYNC_AXES")
|
||||
self._pv_amp_reset = PV(pvname + ":RESET_AMP.PROC")
|
||||
self._pv_parkall = PV(pvname + "::KILL_ALL.PROC")
|
||||
self._pv_enable_all = PV(pvname + ":ENABLE_ALL.PROC")
|
||||
self._pv_sync_all_axes = PV(pvname + ":SYNC.PROC")
|
||||
self._pv_safety_on = PV(pvname + ":SAFETY_ON.PROC")
|
||||
self._pv_safety_off = PV(pvname + ":SAFETY_OFF.PROC")
|
||||
|
||||
def sync_world(self):
|
||||
self._pv_sync_world.put(1)
|
||||
|
||||
def sync_phys_axes(self):
|
||||
self._pv_sync_all_axes.put(1)
|
||||
|
||||
def park_all(self):
|
||||
self._pv_parkall.put(1)
|
||||
|
||||
def _get_bend_mean(self):
|
||||
return float(
|
||||
@@ -132,6 +161,7 @@ class KbHor(Assembly):
|
||||
lambda b1, b2: float(np.mean([b1, b2])),
|
||||
lambda mn: self._get_benders_set_mean(mn),
|
||||
name="bender_mean",
|
||||
unit="mm",
|
||||
is_setting=False,
|
||||
is_display=True,
|
||||
)
|
||||
@@ -141,6 +171,7 @@ class KbHor(Assembly):
|
||||
lambda b1, b2: float(np.diff([b1, b2])),
|
||||
lambda mn: self._get_benders_set_diff(mn),
|
||||
name="bender_diff",
|
||||
unit="mm",
|
||||
is_setting=False,
|
||||
is_display=True,
|
||||
)
|
||||
@@ -160,11 +191,37 @@ class KbHor(Assembly):
|
||||
)
|
||||
|
||||
#### actual motors ###
|
||||
self._append(MotorRecord, pvname + ":TY1", name="_Y1", is_setting=True)
|
||||
self._append(MotorRecord, pvname + ":TY2", name="_Y2", is_setting=True)
|
||||
self._append(MotorRecord, pvname + ":TY3", name="_Y3", is_setting=True)
|
||||
self._append(MotorRecord, pvname + ":TX1", name="_X1", is_setting=True)
|
||||
self._append(MotorRecord, pvname + ":TX2", name="_X2", is_setting=True)
|
||||
self._append(
|
||||
MotorRecord, pvname + ":TY1", name="_Y1", is_setting=True, is_display=False
|
||||
)
|
||||
self._append(
|
||||
MotorRecord, pvname + ":TY2", name="_Y2", is_setting=True, is_display=False
|
||||
)
|
||||
self._append(
|
||||
MotorRecord, pvname + ":TY3", name="_Y3", is_setting=True, is_display=False
|
||||
)
|
||||
self._append(
|
||||
MotorRecord, pvname + ":TX1", name="_X1", is_setting=True, is_display=False
|
||||
)
|
||||
self._append(
|
||||
MotorRecord, pvname + ":TX2", name="_X2", is_setting=True, is_display=False
|
||||
)
|
||||
self._pv_sync_world = PV(pvname + ":SYNC_AXES")
|
||||
self._pv_amp_reset = PV(pvname + ":RESET_AMP.PROC")
|
||||
self._pv_parkall = PV(pvname + "::KILL_ALL.PROC")
|
||||
self._pv_enable_all = PV(pvname + ":ENABLE_ALL.PROC")
|
||||
self._pv_sync_all_axes = PV(pvname + ":SYNC.PROC")
|
||||
self._pv_safety_on = PV(pvname + ":SAFETY_ON.PROC")
|
||||
self._pv_safety_off = PV(pvname + ":SAFETY_OFF.PROC")
|
||||
|
||||
def sync_world(self):
|
||||
self._pv_sync_world.put(1)
|
||||
|
||||
def sync_phys_axes(self):
|
||||
self._pv_sync_all_axes.put(1)
|
||||
|
||||
def park_all(self):
|
||||
self._pv_parkall.put(1)
|
||||
|
||||
def _get_bend_mean(self):
|
||||
return float(
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
from ..devices_general.motors import MotorRecord_new
|
||||
from ..epics.adjustable import AdjustablePv, AdjustablePvEnum
|
||||
from ..elements.assembly import Assembly
|
||||
from ..elements.adjustable import AdjustableVirtual
|
||||
import numpy as np
|
||||
|
||||
|
||||
class OffsetMirror(Assembly):
|
||||
@@ -46,3 +48,36 @@ class OffsetMirrorsBernina(Assembly):
|
||||
is_setting=True,
|
||||
is_display="recursive",
|
||||
)
|
||||
self._append(
|
||||
AdjustableVirtual,
|
||||
[self.mirr1.rz, self.mirr2.rz],
|
||||
lambda b1, b2: float(np.mean([b1, b2])),
|
||||
lambda mn: self._set_mean_2adj(mn, self.mirr1.rz, self.mirr2.rz),
|
||||
name="rz_mean",
|
||||
unit="mrad",
|
||||
is_setting=False,
|
||||
is_display=True,
|
||||
)
|
||||
|
||||
self._append(
|
||||
AdjustableVirtual,
|
||||
[self.mirr1.rz, self.mirr2.rz],
|
||||
lambda b1, b2: float(np.diff([b1, b2])),
|
||||
lambda mn: self._set_diff_2adj(mn, self.mirr1.rz, self.mirr2.rz),
|
||||
name="rz_diff",
|
||||
unit="mrad",
|
||||
is_setting=False,
|
||||
is_display=True,
|
||||
)
|
||||
|
||||
def _set_mean_2adj(self, val, adj0, adj1):
|
||||
mn = np.mean([adj0.get_current_value(), adj1.get_current_value()])
|
||||
df = val - mn
|
||||
return adj0.get_current_value() + df, adj1.get_current_value() + df
|
||||
|
||||
def _set_diff_2adj(self, val, adj0, adj1):
|
||||
df = val - np.diff([adj0.get_current_value(), adj1.get_current_value()])
|
||||
return (
|
||||
adj0.get_current_value() - df / 2,
|
||||
adj1.get_current_value() + df / 2,
|
||||
)
|
||||
|
||||
+2
-2
@@ -38,12 +38,12 @@ class Pulsepick:
|
||||
|
||||
def open(self):
|
||||
self._openclose.put(1)
|
||||
self._evrsrc.put(62)
|
||||
#self._evrsrc.put(62)
|
||||
print("Opened Pulse Picker")
|
||||
|
||||
def close(self):
|
||||
self._openclose.put(0)
|
||||
self._evrsrc.put(62)
|
||||
#self._evrsrc.put(62)
|
||||
print("Closed Pulse Picker")
|
||||
|
||||
def trigger(self):
|
||||
|
||||
Executable
+64
@@ -0,0 +1,64 @@
|
||||
from epics import PV
|
||||
from ..devices_general.utilities import Changer
|
||||
from time import sleep
|
||||
import numpy as np
|
||||
from ..devices_general.motors import MotorRecord
|
||||
|
||||
from ..aliases import Alias
|
||||
|
||||
|
||||
def addMotorRecordToSelf(self, name=None, Id=None):
|
||||
try:
|
||||
self.__dict__[name] = MotorRecord(Id, name=name)
|
||||
self.alias.append(self.__dict__[name].alias)
|
||||
except:
|
||||
print(f"Warning! Could not find motor {name} (Id:{Id})")
|
||||
|
||||
|
||||
class PulsePickerSwissfel(Assembly):
|
||||
def __init__(self, Id=None, evronoff=None, evrsrc=None, name=None):
|
||||
self.name = name
|
||||
self.alias = Alias(name)
|
||||
self.evrsrc = evrsrc
|
||||
self.evronoff = evronoff
|
||||
|
||||
self.Id = Id
|
||||
self._openclose = PV(self.evronoff)
|
||||
self._evrsrc = PV(self.evrsrc)
|
||||
addMotorRecordToSelf(self, Id=self.Id + ":MOTOR_X1", name="x")
|
||||
addMotorRecordToSelf(self, Id=self.Id + ":MOTOR_Y1", name="y")
|
||||
|
||||
def movein(self):
|
||||
self.x.set_target_value(4.45)
|
||||
self.y.set_target_value(-1.75)
|
||||
|
||||
def moveout(self):
|
||||
self.x.set_target_value(-5)
|
||||
self.y.set_target_value(-1.75)
|
||||
|
||||
def open(self):
|
||||
self._openclose.put(1)
|
||||
self._evrsrc.put(62)
|
||||
print("Opened Pulse Picker")
|
||||
|
||||
def close(self):
|
||||
self._openclose.put(0)
|
||||
self._evrsrc.put(62)
|
||||
print("Closed Pulse Picker")
|
||||
|
||||
def trigger(self):
|
||||
self._openclose.put(1)
|
||||
self._evrsrc.put(0)
|
||||
print("Set Pulse Picker to trigger (src 0 and output On)")
|
||||
|
||||
def get_status(self):
|
||||
stat = self._evrsrc.get()
|
||||
if stat == 62 and self._openclose.get() == 1:
|
||||
return "open"
|
||||
if self._openclose.get() == 0:
|
||||
return "closed"
|
||||
else:
|
||||
return "unknown"
|
||||
|
||||
def __repr__(self):
|
||||
return f"FEL pulse picker state {self.get_status()}."
|
||||
Executable → Regular
+149
-15
@@ -1,26 +1,124 @@
|
||||
from ..devices_general.motors import MotorRecord
|
||||
from enum import Enum
|
||||
from eco.elements.adjustable import AdjustableGetSet
|
||||
from eco.epics.adjustable import AdjustablePvEnum
|
||||
from ..devices_general.motors import MotorRecord, SmaractRecord
|
||||
from epics import PV
|
||||
from ..aliases import Alias, append_object_to_object
|
||||
from ..elements.assembly import Assembly
|
||||
|
||||
|
||||
class RefLaser_Aramis:
|
||||
def __init__(self, Id, elog=None, name=None, inpos=-18.947, outpos=-5):
|
||||
class RefLaser_BerninaUSD(Assembly):
|
||||
def __init__(
|
||||
self,
|
||||
pvname_mirrortranslation="SARES23-LIC:MOT_12",
|
||||
pvname_onoff="SARES21-CPCL-PS7071:LV_OMPV_1_CH1_SWITCH_SP",
|
||||
elog=None,
|
||||
name=None,
|
||||
):
|
||||
super().__init__(name=name)
|
||||
self.elog = elog
|
||||
# append_object_to_object(self,
|
||||
|
||||
self._append(
|
||||
SmaractRecord, pvname_mirrortranslation, name="x_mirror", is_setting=True
|
||||
)
|
||||
self._append(
|
||||
AdjustablePvEnum, pvname_onoff, name="laser_power", is_setting=True
|
||||
)
|
||||
|
||||
def movein(self, wait=False):
|
||||
|
||||
try:
|
||||
self.presets.movein()
|
||||
except:
|
||||
print("No movein preset found.")
|
||||
|
||||
def moveout(self, wait=False):
|
||||
try:
|
||||
self.presets.moveout()
|
||||
except:
|
||||
print("No moveout preset found.")
|
||||
|
||||
# self._append(
|
||||
# AdjustableGetSet,
|
||||
# self.get_in_status,
|
||||
# self.set,
|
||||
# name="state",
|
||||
# is_setting=False,
|
||||
# )
|
||||
|
||||
# self._append(MotorRecord, self.Id + ":MOTOR_1", name="mirror", is_setting=True)
|
||||
|
||||
# self._append(
|
||||
# RefLaserLaser,
|
||||
# self.Id,
|
||||
# name="laser",
|
||||
# is_setting=True,
|
||||
# is_display="recursive",
|
||||
# )
|
||||
# self._append(
|
||||
# RefLaserAperture,
|
||||
# "SAROP21-OLIR134",
|
||||
# name="aperture",
|
||||
# is_setting=True,
|
||||
# is_display="recursive",
|
||||
# )
|
||||
|
||||
# self._append(MotorRecord, pv_lir0 + ":MOTOR_MX", name="x_ap1", is_setting=True)
|
||||
# self._append(MotorRecord, pv_lir0 + ":MOTOR_MY", name="y_ap1", is_setting=True)
|
||||
# pv_lir1 = "SAROP21-OLIR138" # TODO hardcoded
|
||||
# self._append(MotorRecord, pv_lir1 + ":MOTOR_MX", name="x_ap2", is_setting=True)
|
||||
# self._append(MotorRecord, pv_lir1 + ":MOTOR_MY", name="y_ap2", is_setting=True)
|
||||
# self.mirror.set_limits(-20, 0)
|
||||
|
||||
|
||||
class RefLaser_Aramis(Assembly):
|
||||
def __init__(self, Id, elog=None, name=None, inpos=-19, outpos=-5):
|
||||
super().__init__(name=name)
|
||||
self.Id = Id
|
||||
self.elog = elog
|
||||
self.name = name
|
||||
# append_object_to_object(self,
|
||||
|
||||
self._inpos = inpos
|
||||
self._outpos = outpos
|
||||
self.mirrmotor = MotorRecord(self.Id + ":MOTOR_1")
|
||||
self.x_trans = MotorRecord(self.Id + ":MOTOR_X1")
|
||||
self.z_trans = MotorRecord(self.Id + ":MOTOR_Z1")
|
||||
self.x_rot = MotorRecord(self.Id + ":MOTOR_ROT_X1")
|
||||
self.z_rot = MotorRecord(self.Id + ":MOTOR_ROT_Z1")
|
||||
|
||||
self._append(
|
||||
AdjustableGetSet,
|
||||
self.get_in_status,
|
||||
self.set,
|
||||
name="state",
|
||||
is_setting=False,
|
||||
)
|
||||
|
||||
self._append(MotorRecord, self.Id + ":MOTOR_1", name="mirror", is_setting=True)
|
||||
|
||||
self._append(
|
||||
RefLaserLaser,
|
||||
self.Id,
|
||||
name="laser",
|
||||
is_setting=True,
|
||||
is_display="recursive",
|
||||
)
|
||||
self._append(
|
||||
RefLaserAperture,
|
||||
"SAROP21-OLIR134",
|
||||
name="aperture",
|
||||
is_setting=True,
|
||||
is_display="recursive",
|
||||
)
|
||||
|
||||
# self._append(MotorRecord, pv_lir0 + ":MOTOR_MX", name="x_ap1", is_setting=True)
|
||||
# self._append(MotorRecord, pv_lir0 + ":MOTOR_MY", name="y_ap1", is_setting=True)
|
||||
# pv_lir1 = "SAROP21-OLIR138" # TODO hardcoded
|
||||
# self._append(MotorRecord, pv_lir1 + ":MOTOR_MX", name="x_ap2", is_setting=True)
|
||||
# self._append(MotorRecord, pv_lir1 + ":MOTOR_MY", name="y_ap2", is_setting=True)
|
||||
self.mirror.set_limits(-20, 0)
|
||||
|
||||
def __call__(self, *args, **kwargs):
|
||||
self.set(*args, **kwargs)
|
||||
|
||||
def __str__(self):
|
||||
status = self.get_status()
|
||||
status = self.get_in_status()
|
||||
if status:
|
||||
return "Reflaser is In."
|
||||
elif status == False:
|
||||
@@ -28,14 +126,15 @@ class RefLaser_Aramis:
|
||||
elif status == None:
|
||||
return "Reflaser status not defined."
|
||||
|
||||
def get_status(self):
|
||||
v = self.mirrmotor.get_current_value()
|
||||
def get_in_status(self):
|
||||
v = self.mirror.get_current_value()
|
||||
if abs(v - self._inpos) < 0.2:
|
||||
isin = True
|
||||
elif abs(v - self._outpos) < 0.2:
|
||||
isin = False
|
||||
else:
|
||||
isin = None
|
||||
# return State(isin)
|
||||
return isin
|
||||
|
||||
def set(self, value):
|
||||
@@ -47,9 +146,9 @@ class RefLaser_Aramis:
|
||||
else:
|
||||
print("String %s not recognized!" % value)
|
||||
if value:
|
||||
self.mirrmotor.set_target_value(self._inpos)
|
||||
self.mirror.set_target_value(self._inpos)
|
||||
else:
|
||||
self.mirrmotor.set_target_value(self._outpos)
|
||||
self.mirror.set_target_value(self._outpos)
|
||||
|
||||
def movein(self):
|
||||
self.set("in")
|
||||
@@ -58,4 +157,39 @@ class RefLaser_Aramis:
|
||||
self.set("out")
|
||||
|
||||
def __repr__(self):
|
||||
return self.__str__()
|
||||
return self.__str__() + "\n" + super().__repr__()
|
||||
|
||||
|
||||
class RefLaserAperture(Assembly):
|
||||
def __init__(self, pvname, name=None):
|
||||
super().__init__(name=name)
|
||||
self._append(
|
||||
MotorRecord,
|
||||
pvname + ":MOTOR_MX",
|
||||
name="x",
|
||||
is_setting=True,
|
||||
is_display=True,
|
||||
)
|
||||
self._append(
|
||||
MotorRecord,
|
||||
pvname + ":MOTOR_MY",
|
||||
name="y",
|
||||
is_setting=True,
|
||||
is_display=True,
|
||||
)
|
||||
|
||||
|
||||
class RefLaserLaser(Assembly):
|
||||
def __init__(self, pvname, name=None):
|
||||
super().__init__(name=name)
|
||||
|
||||
self._append(MotorRecord, pvname + ":MOTOR_X1", name="x", is_setting=True)
|
||||
self._append(MotorRecord, pvname + ":MOTOR_Z1", name="z", is_setting=True)
|
||||
self._append(MotorRecord, pvname + ":MOTOR_ROT_X1", name="rx", is_setting=True)
|
||||
self._append(MotorRecord, pvname + ":MOTOR_ROT_Z1", name="rz", is_setting=True)
|
||||
|
||||
|
||||
class State(Enum):
|
||||
IN = 1
|
||||
OUT = 0
|
||||
UNDEFINED = None
|
||||
|
||||
@@ -1,75 +0,0 @@
|
||||
from ..devices_general.motors import MotorRecord
|
||||
from epics import PV
|
||||
from ..aliases import Alias, append_object_to_object
|
||||
from ..elements.assembly import Assembly
|
||||
|
||||
|
||||
class RefLaser_Aramis(Assembly):
|
||||
def __init__(self, Id, elog=None, name=None, inpos=-18.818, outpos=-5):
|
||||
super().__init__(name=name)
|
||||
self.Id = Id
|
||||
self.elog = elog
|
||||
# append_object_to_object(self,
|
||||
|
||||
self._inpos = inpos
|
||||
self._outpos = outpos
|
||||
self._append(MotorRecord, self.Id + ":MOTOR_1", name="mirror", is_setting=True)
|
||||
self._append(MotorRecord, self.Id + ":MOTOR_X1", name="x1", is_setting=True)
|
||||
self._append(MotorRecord, self.Id + ":MOTOR_Z1", name="z1", is_setting=True)
|
||||
self._append(
|
||||
MotorRecord, self.Id + ":MOTOR_ROT_X1", name="rx1", is_setting=True
|
||||
)
|
||||
self._append(
|
||||
MotorRecord, self.Id + ":MOTOR_ROT_Z1", name="rz1", is_setting=True
|
||||
)
|
||||
pv_lir0 = "SAROP21-OLIR136" # TODO hardcoded
|
||||
self._append(MotorRecord, pv_lir0 + ":MOTOR_MX", name="x_ap1", is_setting=True)
|
||||
self._append(MotorRecord, pv_lir0 + ":MOTOR_MY", name="y_ap1", is_setting=True)
|
||||
pv_lir1 = "SAROP21-OLIR138" # TODO hardcoded
|
||||
self._append(MotorRecord, pv_lir1 + ":MOTOR_MX", name="x_ap2", is_setting=True)
|
||||
self._append(MotorRecord, pv_lir1 + ":MOTOR_MY", name="y_ap2", is_setting=True)
|
||||
self.mirror.set_limits(-20, 0)
|
||||
|
||||
def __call__(self, *args, **kwargs):
|
||||
self.set(*args, **kwargs)
|
||||
|
||||
def __str__(self):
|
||||
status = self.get_in_status()
|
||||
if status:
|
||||
return "Reflaser is In."
|
||||
elif status == False:
|
||||
return "Reflaser is Out."
|
||||
elif status == None:
|
||||
return "Reflaser status not defined."
|
||||
|
||||
def get_in_status(self):
|
||||
v = self.mirror.get_current_value()
|
||||
if abs(v - self._inpos) < 0.2:
|
||||
isin = True
|
||||
elif abs(v - self._outpos) < 0.2:
|
||||
isin = False
|
||||
else:
|
||||
isin = None
|
||||
return isin
|
||||
|
||||
def set(self, value):
|
||||
if type(value) is str:
|
||||
if value.lower() == "in":
|
||||
value = True
|
||||
elif value.lower() == "out":
|
||||
value = False
|
||||
else:
|
||||
print("String %s not recognized!" % value)
|
||||
if value:
|
||||
self.mirror.set_target_value(self._inpos)
|
||||
else:
|
||||
self.mirror.set_target_value(self._outpos)
|
||||
|
||||
def movein(self):
|
||||
self.set("in")
|
||||
|
||||
def moveout(self):
|
||||
self.set("out")
|
||||
|
||||
def __repr__(self):
|
||||
return self.__str__() + "\n" + super().__repr__()
|
||||
+19
-19
@@ -329,15 +329,16 @@ class SlitBlades(Assembly):
|
||||
|
||||
|
||||
@addSlitRepr
|
||||
class SlitPosWidth:
|
||||
class SlitPosWidth(Assembly):
|
||||
def __init__(self, pvname, name=None, elog=None):
|
||||
self.name = name
|
||||
self.Id = pvname
|
||||
self.alias = Alias(name)
|
||||
append_object_to_object(self, MotorRecord, pvname + ":MOTOR_X", name="hpos")
|
||||
append_object_to_object(self, MotorRecord, pvname + ":MOTOR_Y", name="vpos")
|
||||
append_object_to_object(self, MotorRecord, pvname + ":MOTOR_W", name="hgap")
|
||||
append_object_to_object(self, MotorRecord, pvname + ":MOTOR_H", name="vgap")
|
||||
super().__init__(name=name)
|
||||
|
||||
self.pvname = pvname
|
||||
|
||||
self._append(MotorRecord, pvname + ":MOTOR_X", name="hpos")
|
||||
self._append(MotorRecord, pvname + ":MOTOR_Y", name="vpos")
|
||||
self._append(MotorRecord, pvname + ":MOTOR_W", name="hgap")
|
||||
self._append(MotorRecord, pvname + ":MOTOR_H", name="vgap")
|
||||
|
||||
def getblade(pos, gap, direction=1):
|
||||
return pos + direction * gap / 2
|
||||
@@ -367,8 +368,7 @@ class SlitPosWidth:
|
||||
[x + tx * self.vgap.get_current_value() for tx in [-1 / 2, 1 / 2]]
|
||||
)
|
||||
|
||||
append_object_to_object(
|
||||
self,
|
||||
self._append(
|
||||
AdjustableVirtual,
|
||||
[self.vpos, self.vgap],
|
||||
partial(getblade, direction=1),
|
||||
@@ -376,8 +376,7 @@ class SlitPosWidth:
|
||||
reset_current_value_to=True,
|
||||
name="up",
|
||||
)
|
||||
append_object_to_object(
|
||||
self,
|
||||
self._append(
|
||||
AdjustableVirtual,
|
||||
[self.vpos, self.vgap],
|
||||
partial(getblade, direction=-1),
|
||||
@@ -385,8 +384,7 @@ class SlitPosWidth:
|
||||
reset_current_value_to=True,
|
||||
name="down",
|
||||
)
|
||||
append_object_to_object(
|
||||
self,
|
||||
self._append(
|
||||
AdjustableVirtual,
|
||||
[self.hpos, self.hgap],
|
||||
partial(getblade, direction=1),
|
||||
@@ -394,8 +392,7 @@ class SlitPosWidth:
|
||||
reset_current_value_to=True,
|
||||
name="left",
|
||||
)
|
||||
append_object_to_object(
|
||||
self,
|
||||
self._append(
|
||||
AdjustableVirtual,
|
||||
[self.hpos, self.hgap],
|
||||
partial(getblade, direction=-1),
|
||||
@@ -844,10 +841,10 @@ class SlitBladesGeneral(Assembly):
|
||||
return tuple([tx + self.vpos.get_current_value() for tx in [-x / 2, x / 2]])
|
||||
|
||||
def sethpos(x):
|
||||
return tuple([tx + self.hgap.get_current_value() for tx in [-x / 2, x / 2]])
|
||||
return tuple([x + tx for tx in [-self.hgap.get_current_value()/2, self.hgap.get_current_value()/2]])
|
||||
|
||||
def setvpos(x):
|
||||
return tuple([tx + self.vgap.get_current_value() for tx in [-x / 2, x / 2]])
|
||||
return tuple([x + tx for tx in [-self.vgap.get_current_value()/2, self.vgap.get_current_value()/2]])
|
||||
|
||||
self._append(
|
||||
AdjustableVirtual,
|
||||
@@ -885,7 +882,10 @@ class SlitBladesGeneral(Assembly):
|
||||
def _apply_on_all_blades(self, method_name, *args, **kwargs):
|
||||
out = []
|
||||
for blade in self.blade_motors:
|
||||
out.append(blade.__dict__[method_name](*args, **kwargs))
|
||||
if method_name in blade.__dict__.keys():
|
||||
out.append(blade.__dict__[method_name](*args, **kwargs))
|
||||
else:
|
||||
out.append(blade.__getattribute__(method_name)(*args, **kwargs))
|
||||
return out
|
||||
|
||||
def home_all_blades(self):
|
||||
|
||||
Reference in New Issue
Block a user