after trigo
This commit is contained in:
@@ -0,0 +1,559 @@
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# likely never worked ...
|
||||
# def _wait_for_tasks(scan, **kwargs):
|
||||
# print("checking remaining tasks from previous scan ...")
|
||||
# for task in scan.remaining_tasks:
|
||||
# task.join()
|
||||
# print("... done.")
|
||||
|
||||
class CounterStatusInitNamespaceToDAQ:
|
||||
def __init__(self, namespace=None, daq=None):
|
||||
self.namespace = namespace
|
||||
self.daq = daq
|
||||
|
||||
def callback_start_scan(self,scan=None, append_status_info=True):
|
||||
if not append_status_info:
|
||||
return
|
||||
namespace_status = namespace.get_status(base=None)
|
||||
stat = {"status_run_start": namespace_status}
|
||||
scan.status = stat
|
||||
|
||||
def callback_start_step(self, scan=None, append_status_info=True):
|
||||
pass
|
||||
def callback_end_step(self, scan=None, append_status_info=True):
|
||||
pass
|
||||
def callback_end_scan(self, scan=None, append_status_info=True):
|
||||
pass
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def _write_namespace_status_to_scan(
|
||||
scan, daq=daq, namespace=namespace, append_status_info=True, end_scan=True, **kwargs
|
||||
):
|
||||
if not append_status_info:
|
||||
return
|
||||
if end_scan:
|
||||
namespace_status = namespace.get_status(base=None)
|
||||
scan.status["status_run_end"] = namespace_status
|
||||
if (not end_scan) and not (len(scan.values_done) == 1):
|
||||
return
|
||||
if hasattr(scan, "daq_run_number"):
|
||||
runno = scan.daq_run_number
|
||||
else:
|
||||
runno = daq.get_last_run_number()
|
||||
pgroup = daq.pgroup
|
||||
tmpdir = Path(f"/sf/bernina/data/{pgroup}/res/tmp/stat_run{runno:04d}")
|
||||
tmpdir.mkdir(exist_ok=True, parents=True)
|
||||
try:
|
||||
tmpdir.chmod(0o775)
|
||||
except:
|
||||
pass
|
||||
|
||||
statusfile = tmpdir / Path("status.json")
|
||||
if not statusfile.exists():
|
||||
with open(statusfile, "w") as f:
|
||||
json.dump(scan.status, f, sort_keys=True, cls=NumpyEncoder, indent=4)
|
||||
else:
|
||||
with open(statusfile, "r+") as f:
|
||||
f.seek(0)
|
||||
json.dump(scan.status, f, sort_keys=True, cls=NumpyEncoder, indent=4)
|
||||
f.truncate()
|
||||
print("Wrote status with seek truncate!")
|
||||
if not statusfile.group() == statusfile.parent.group():
|
||||
shutil.chown(statusfile, group=statusfile.parent.group())
|
||||
|
||||
response = daq.append_aux(
|
||||
statusfile.resolve().as_posix(),
|
||||
pgroup=pgroup,
|
||||
run_number=runno,
|
||||
)
|
||||
print("####### transfer status #######")
|
||||
print(response.json())
|
||||
print("###############################")
|
||||
scan.scan_info["scan_parameters"]["status"] = "aux/status.json"
|
||||
|
||||
|
||||
def _write_namespace_aliases_to_scan(scan, daq=daq, force=False, **kwargs):
|
||||
if force or (len(scan.values_done) == 1):
|
||||
namespace_aliases = namespace.alias.get_all()
|
||||
if hasattr(scan, "daq_run_number"):
|
||||
runno = scan.daq_run_number
|
||||
else:
|
||||
runno = daq.get_last_run_number()
|
||||
pgroup = daq.pgroup
|
||||
tmpdir = Path(f"/sf/bernina/data/{pgroup}/res/tmp/aliases_run{runno:04d}")
|
||||
tmpdir.mkdir(exist_ok=True, parents=True)
|
||||
try:
|
||||
tmpdir.chmod(0o775)
|
||||
except:
|
||||
pass
|
||||
aliasfile = tmpdir / Path("aliases.json")
|
||||
if not Path(aliasfile).exists():
|
||||
with open(aliasfile, "w") as f:
|
||||
json.dump(
|
||||
namespace_aliases, f, sort_keys=True, cls=NumpyEncoder, indent=4
|
||||
)
|
||||
else:
|
||||
with open(aliasfile, "r+") as f:
|
||||
f.seek(0)
|
||||
json.dump(
|
||||
namespace_aliases, f, sort_keys=True, cls=NumpyEncoder, indent=4
|
||||
)
|
||||
f.truncate()
|
||||
if not aliasfile.group() == aliasfile.parent.group():
|
||||
shutil.chown(aliasfile, group=aliasfile.parent.group())
|
||||
|
||||
scan.remaining_tasks.append(
|
||||
Thread(
|
||||
target=daq.append_aux,
|
||||
args=[aliasfile.resolve().as_posix()],
|
||||
kwargs=dict(pgroup=pgroup, run_number=runno),
|
||||
)
|
||||
)
|
||||
# DEBUG
|
||||
print(
|
||||
f"Sending scan_info_rel.json in {Path(aliasfile).parent.stem} to run number {runno}."
|
||||
)
|
||||
scan.remaining_tasks[-1].start()
|
||||
# response = daq.append_aux(
|
||||
# aliasfile.resolve().as_posix(),
|
||||
# pgroup=pgroup,
|
||||
# run_number=runno,
|
||||
# )
|
||||
print("####### transfer aliases started #######")
|
||||
# print(response.json())
|
||||
# print("################################")
|
||||
scan.scan_info["scan_parameters"]["aliases"] = "aux/aliases.json"
|
||||
|
||||
|
||||
def _message_end_scan(scan, **kwargs):
|
||||
print(f"Finished run {scan.run_number}.")
|
||||
if hasattr(scan, "daq_run_number"):
|
||||
runno_daq_saved = scan.daq_run_number
|
||||
print(f"daq_run_number is run {runno_daq_saved}.")
|
||||
|
||||
try:
|
||||
runno = daq.get_last_run_number()
|
||||
print(f"daq last run number is run {runno}.")
|
||||
except:
|
||||
pass
|
||||
|
||||
try:
|
||||
e = pyttsx3.init()
|
||||
e.say(f"Finished run {scan.run_number}.")
|
||||
e.runAndWait()
|
||||
e.stop()
|
||||
except:
|
||||
print("Audio output failed.")
|
||||
|
||||
|
||||
# def _copy_scan_info_to_raw(scan, daq=daq):
|
||||
# run_number = daq.get_last_run_number()
|
||||
# pgroup = daq.pgroup
|
||||
# print(f"Copying info file to run {run_number} to the raw directory of {pgroup}.")
|
||||
# response = daq.append_aux(
|
||||
# scan.scan_info_filename, pgroup=pgroup, run_number=run_number
|
||||
# )
|
||||
# print(f"Status: {response.json()['status']} Message: {response.json()['message']}")
|
||||
|
||||
|
||||
def _create_general_run_info(scan, daq=daq, **kwargs):
|
||||
with open(scan.scan_info_filename, "r") as f:
|
||||
si = json.load(f)
|
||||
|
||||
info = {}
|
||||
# general info, potentially automatically filled
|
||||
info["general"] = {}
|
||||
# individual data filled by daq/writers/user through api
|
||||
info["start"] = {}
|
||||
info["end"] = {}
|
||||
info["steps"] = []
|
||||
|
||||
|
||||
def _copy_scan_info_to_raw(scan, daq=daq, **kwargs):
|
||||
t_start = time.time()
|
||||
|
||||
scan.writeScanInfo()
|
||||
|
||||
# get data that should come later from api or similar.
|
||||
run_directory = list(
|
||||
Path(f"/sf/bernina/data/{daq.pgroup}/raw").glob(f"run{scan.run_number:04d}*")
|
||||
)[0].as_posix()
|
||||
with open(scan.scan_info_filename, "r") as f:
|
||||
si = json.load(f)
|
||||
|
||||
# correct some data in there (relative paths for now)
|
||||
from os.path import relpath
|
||||
|
||||
newfiles = []
|
||||
for files in si["scan_files"]:
|
||||
newfiles.append([relpath(file, run_directory) for file in files])
|
||||
|
||||
si["scan_files"] = newfiles
|
||||
|
||||
# save temprary file and send then to raw
|
||||
if hasattr(scan, "daq_run_number"):
|
||||
runno = scan.daq_run_number
|
||||
else:
|
||||
runno = daq.get_last_run_number()
|
||||
pgroup = daq.pgroup
|
||||
tmpdir = Path(f"/sf/bernina/data/{pgroup}/res/tmp/info_run{runno:04d}")
|
||||
tmpdir.mkdir(exist_ok=True, parents=True)
|
||||
try:
|
||||
tmpdir.chmod(0o775)
|
||||
except:
|
||||
pass
|
||||
scaninfofile = tmpdir / Path("scan_info_rel.json")
|
||||
if not Path(scaninfofile).exists():
|
||||
with open(scaninfofile, "w") as f:
|
||||
json.dump(si, f, sort_keys=True, cls=NumpyEncoder, indent=4)
|
||||
else:
|
||||
with open(scaninfofile, "r+") as f:
|
||||
f.seek(0)
|
||||
json.dump(si, f, sort_keys=True, cls=NumpyEncoder, indent=4)
|
||||
f.truncate()
|
||||
if not scaninfofile.group() == scaninfofile.parent.group():
|
||||
shutil.chown(scaninfofile, group=scaninfofile.parent.group())
|
||||
# print(f"Copying info file to run {runno} to the raw directory of {pgroup}.")
|
||||
|
||||
scan.remaining_tasks.append(
|
||||
Thread(
|
||||
target=daq.append_aux,
|
||||
args=[scaninfofile.as_posix()],
|
||||
kwargs=dict(pgroup=pgroup, run_number=runno),
|
||||
)
|
||||
)
|
||||
# DEBUG
|
||||
print(
|
||||
f"Sending scan_info_rel.json in {Path(scaninfofile).parent.stem} to run number {runno}."
|
||||
)
|
||||
scan.remaining_tasks[-1].start()
|
||||
# response = daq.append_aux(scaninfofile.as_posix(), pgroup=pgroup, run_number=runno)
|
||||
# print(f"Status: {response.json()['status']} Message: {response.json()['message']}")
|
||||
# print(
|
||||
# f"--> creating and copying file took{time.time()-t_start} s, presently adding to deadtime."
|
||||
# )
|
||||
|
||||
|
||||
from eco.detector import Jungfrau
|
||||
|
||||
|
||||
def _copy_selected_JF_pedestals_to_raw(
|
||||
scan, daq=daq, copy_selected_JF_pedestals_to_raw=True, **kwargs
|
||||
):
|
||||
def copy_to_aux(daq, scan):
|
||||
if hasattr(scan, "daq_run_number"):
|
||||
runno = scan.daq_run_number
|
||||
else:
|
||||
runno = daq.get_last_run_number()
|
||||
|
||||
pgroup = daq.pgroup
|
||||
|
||||
for jf_id in daq.channels["channels_JF"]():
|
||||
jf = Jungfrau(jf_id, name="noname", pgroup_adj=config_bernina.pgroup)
|
||||
print(
|
||||
f"Copying {jf_id} pedestal to run {runno} in the raw directory of {pgroup}."
|
||||
)
|
||||
response = daq.append_aux(
|
||||
jf.get_present_pedestal_filename_in_run(intempdir=True),
|
||||
pgroup=pgroup,
|
||||
run_number=runno,
|
||||
)
|
||||
print(
|
||||
f"Status: {response.json()['status']} Message: {response.json()['message']}"
|
||||
)
|
||||
print(
|
||||
f"Copying {jf_id} gainmap to run {runno} in the raw directory of {pgroup}."
|
||||
)
|
||||
|
||||
response = daq.append_aux(
|
||||
jf.get_present_gain_filename_in_run(intempdir=True),
|
||||
pgroup=pgroup,
|
||||
run_number=runno,
|
||||
)
|
||||
print(
|
||||
f"Status: {response.json()['status']} Message: {response.json()['message']}"
|
||||
)
|
||||
|
||||
if copy_selected_JF_pedestals_to_raw:
|
||||
scan.remaining_tasks.append(Thread(target=copy_to_aux, args=[daq, scan]))
|
||||
scan.remaining_tasks[-1].start()
|
||||
|
||||
|
||||
def _increment_daq_run_number(scan, daq=daq, **kwargs):
|
||||
try:
|
||||
daq_last_run_number = daq.get_last_run_number()
|
||||
if int(scan.run_number) is int(daq_last_run_number) + 1:
|
||||
print("############ incremented ##########")
|
||||
daq_run_number = daq.get_next_run_number()
|
||||
else:
|
||||
daq_run_number = daq_last_run_number
|
||||
if int(scan.run_number) is not int(daq_run_number):
|
||||
print(
|
||||
f"Difference in run number between eco {int(scan.run_number)} and daq {int(daq_run_number)}: using run number {int(scan.run_number)}"
|
||||
)
|
||||
if int(scan.run_number) > int(daq_run_number):
|
||||
n = int(scan.run_number) - int(daq_run_number)
|
||||
print("Increasing daq run_number")
|
||||
for i in range(n):
|
||||
rn = daq.get_next_run_number()
|
||||
print(rn)
|
||||
scan.daq_run_number = rn
|
||||
else:
|
||||
scan.daq_run_number = daq_run_number
|
||||
|
||||
except Exception as e:
|
||||
print(e)
|
||||
|
||||
|
||||
class Monitor:
|
||||
def __init__(self, pvname, start_immediately=True):
|
||||
self.data = {}
|
||||
self.print = False
|
||||
self.pv = PV(pvname)
|
||||
self.cb_index = None
|
||||
if start_immediately:
|
||||
self.start_callback()
|
||||
|
||||
def start_callback(self):
|
||||
self.cb_index = self.pv.add_callback(self.append)
|
||||
|
||||
def stop_callback(self):
|
||||
self.pv.remove_callback(self.cb_index)
|
||||
|
||||
def append(self, pvname=None, value=None, timestamp=None, **kwargs):
|
||||
if not (pvname in self.data):
|
||||
self.data[pvname] = []
|
||||
ts_local = time.time()
|
||||
self.data[pvname].append(
|
||||
{"value": value, "timestamp": timestamp, "timestamp_local": ts_local}
|
||||
)
|
||||
if self.print:
|
||||
print(
|
||||
f"{pvname}: {value}; time: {timestamp}; time_local: {ts_local}; diff: {ts_local-timestamp}"
|
||||
)
|
||||
|
||||
|
||||
import traceback
|
||||
|
||||
|
||||
def append_scan_monitors(
|
||||
scan,
|
||||
daq=daq,
|
||||
custom_monitors={},
|
||||
**kwargs,
|
||||
):
|
||||
scan.monitors = {}
|
||||
for adj in scan.adjustables:
|
||||
try:
|
||||
tname = adj.alias.get_full_name()
|
||||
except Exception:
|
||||
tname = adj.name
|
||||
traceback.print_exc()
|
||||
try:
|
||||
scan.monitors[tname] = Monitor(adj.pvname)
|
||||
except Exception:
|
||||
print(f"Could not add CA monitor for {tname}")
|
||||
traceback.print_exc()
|
||||
try:
|
||||
rname = adj.readback.alias.get_full_name()
|
||||
except Exception:
|
||||
print("no readback configured")
|
||||
traceback.print_exc()
|
||||
try:
|
||||
scan.monitors[rname] = Monitor(adj.readback.pvname)
|
||||
except Exception:
|
||||
print(f"Could not add CA readback monitor for {tname}")
|
||||
traceback.print_exc()
|
||||
|
||||
for tname, tobj in custom_monitors.items():
|
||||
try:
|
||||
if type(tobj) is str:
|
||||
tmonpv = tobj
|
||||
scan.monitors[tname] = Monitor(tmonpv)
|
||||
print(f"Added custom monitor for {tname}")
|
||||
except Exception:
|
||||
print(f"Could not add custom monitor for {tname}")
|
||||
traceback.print_exc()
|
||||
try:
|
||||
tname = daq.pulse_id.alias.get_full_name()
|
||||
scan.monitors[tname] = Monitor(daq.pulse_id.pvname)
|
||||
except Exception:
|
||||
print(f"Could not add daq.pulse_id monitor")
|
||||
traceback.print_exc()
|
||||
|
||||
|
||||
def end_scan_monitors(scan, daq=daq, **kwargs):
|
||||
for tmon in scan.monitors:
|
||||
scan.monitors[tmon].stop_callback()
|
||||
|
||||
monitor_result = {tmon: scan.monitors[tmon].data for tmon in scan.monitors}
|
||||
|
||||
#######
|
||||
# get data that should come later from api or similar.
|
||||
run_directory = list(
|
||||
Path(f"/sf/bernina/data/{daq.pgroup}/raw").glob(f"run{scan.run_number:04d}*")
|
||||
)[0].as_posix()
|
||||
|
||||
# correct some data in there (relative paths for now)
|
||||
from os.path import relpath
|
||||
|
||||
# save temprary file and send then to raw
|
||||
if hasattr(scan, "daq_run_number"):
|
||||
runno = scan.daq_run_number
|
||||
else:
|
||||
runno = daq.get_last_run_number()
|
||||
pgroup = daq.pgroup
|
||||
tmpdir = Path(f"/sf/bernina/data/{pgroup}/res/tmp/info_run{runno:04d}")
|
||||
tmpdir.mkdir(exist_ok=True, parents=True)
|
||||
try:
|
||||
tmpdir.chmod(0o775)
|
||||
except:
|
||||
pass
|
||||
scanmonitorfile = tmpdir / Path("scan_monitor.pkl")
|
||||
if not Path(scanmonitorfile).exists():
|
||||
with open(scanmonitorfile, "wb") as f:
|
||||
pickle.dump(monitor_result, f)
|
||||
|
||||
print(f"Copying monitor file to run {runno} to the raw directory of {pgroup}.")
|
||||
response = daq.append_aux(
|
||||
scanmonitorfile.as_posix(), pgroup=pgroup, run_number=runno
|
||||
)
|
||||
print(f"Status: {response.json()['status']} Message: {response.json()['message']}")
|
||||
|
||||
# scan.monitors = None
|
||||
|
||||
|
||||
def _init_all(scan, append_status_info=True, **kwargs):
|
||||
if not append_status_info:
|
||||
return
|
||||
namespace.init_all(silent=False)
|
||||
|
||||
|
||||
callbacks_start_scan = []
|
||||
callbacks_start_scan.append(_init_all)
|
||||
callbacks_start_scan.append(_wait_for_tasks)
|
||||
callbacks_start_scan.append(_append_namesace_status_to_scan)
|
||||
callbacks_start_scan.append(_increment_daq_run_number)
|
||||
callbacks_start_scan.append(append_scan_monitors)
|
||||
callbacks_end_step = []
|
||||
callbacks_end_step.append(_copy_scan_info_to_raw)
|
||||
callbacks_end_step.append(_write_namespace_aliases_to_scan)
|
||||
callbacks_end_step.append(
|
||||
lambda scan, daq=daq, namespace=namespace, append_status_info=True, end_scan=True, **kwargs: _write_namespace_status_to_scan(
|
||||
scan,
|
||||
daq=daq,
|
||||
namespace=namespace,
|
||||
append_status_info=append_status_info,
|
||||
end_scan=False,
|
||||
**kwargs,
|
||||
)
|
||||
)
|
||||
callbacks_end_scan = []
|
||||
callbacks_end_scan.append(_write_namespace_status_to_scan)
|
||||
callbacks_end_scan.append(_copy_scan_info_to_raw)
|
||||
callbacks_end_scan.append(
|
||||
lambda scan, daq=daq, force=True, **kwargs: _write_namespace_aliases_to_scan(
|
||||
scan, daq=daq, force=force, **kwargs
|
||||
)
|
||||
)
|
||||
callbacks_end_scan.append(_copy_selected_JF_pedestals_to_raw)
|
||||
callbacks_end_scan.append(end_scan_monitors)
|
||||
callbacks_end_scan.append(_message_end_scan)
|
||||
|
||||
# >>>> Extract for run_table and elog
|
||||
|
||||
|
||||
# if self._run_table or self._elog:
|
||||
def _create_metadata_structure_start_scan(
|
||||
scan, run_table=run_table, elog=elog, append_status_info=True, **kwargs
|
||||
):
|
||||
runname = os.path.basename(scan.fina).split(".")[0]
|
||||
runno = int(runname.split("run")[1].split("_")[0])
|
||||
metadata = {
|
||||
"type": "scan",
|
||||
"name": runname.split("_", 1)[1],
|
||||
"scan_info_file": scan.scan_info_filename,
|
||||
}
|
||||
for n, adj in enumerate(scan.adjustables):
|
||||
nname = None
|
||||
nId = None
|
||||
if hasattr(adj, "Id"):
|
||||
nId = adj.Id
|
||||
if hasattr(adj, "name"):
|
||||
nname = adj.name
|
||||
|
||||
metadata.update(
|
||||
{
|
||||
f"scan_motor_{n}": nname,
|
||||
f"from_motor_{n}": scan.values_todo[0][n],
|
||||
f"to_motor_{n}": scan.values_todo[-1][n],
|
||||
f"id_motor_{n}": nId,
|
||||
}
|
||||
)
|
||||
if np.mean(np.diff(scan.pulses_per_step)) < 1:
|
||||
pulses_per_step = scan.pulses_per_step[0]
|
||||
else:
|
||||
pulses_per_step = scan.pulses_per_step
|
||||
metadata.update(
|
||||
{
|
||||
"steps": len(scan.values_todo),
|
||||
"pulses_per_step": pulses_per_step,
|
||||
"counters": [daq.name for daq in scan.counterCallers],
|
||||
}
|
||||
)
|
||||
|
||||
try:
|
||||
try:
|
||||
metadata.update({"scan_command": get_ipython().user_ns["In"][-1]})
|
||||
except:
|
||||
print("Count not retrieve ipython scan command!")
|
||||
|
||||
message_string = f"#### Run {runno}"
|
||||
if metadata["name"]:
|
||||
message_string += f': {metadata["name"]}\n'
|
||||
else:
|
||||
message_string += "\n"
|
||||
|
||||
if "scan_command" in metadata.keys():
|
||||
message_string += "`" + metadata["scan_command"] + "`\n"
|
||||
message_string += "`" + metadata["scan_info_file"] + "`\n"
|
||||
elog_ids = elog.post(
|
||||
message_string,
|
||||
Title=f'Run {runno}: {metadata["name"]}',
|
||||
text_encoding="markdown",
|
||||
)
|
||||
scan._elog_id = elog_ids[1]
|
||||
metadata.update({"elog_message_id": scan._elog_id})
|
||||
metadata.update(
|
||||
{"elog_post_link": scan._elog.elogs[1]._log._url + str(scan._elog_id)}
|
||||
)
|
||||
except:
|
||||
print("Elog posting failed with:")
|
||||
traceback.print_exc()
|
||||
if not append_status_info:
|
||||
return
|
||||
d = {}
|
||||
## use values from status for run_table
|
||||
try:
|
||||
status = scan.status["status_run_start"]
|
||||
d = status["settings"]
|
||||
d.update(status["status"])
|
||||
except:
|
||||
print("Tranferring values from status to run_table did not work")
|
||||
t_start_rt = time.time()
|
||||
try:
|
||||
run_table.append_run(runno, metadata=metadata, d=d)
|
||||
except:
|
||||
print("WARNING: issue adding data to run table")
|
||||
print(f"RT appending: {time.time()-t_start_rt:.3f} s")
|
||||
|
||||
|
||||
# <<<< Extract for run table and elog
|
||||
callbacks_start_scan.append(_create_metadata_structure_start_scan)
|
||||
@@ -87,6 +87,8 @@ class Daq(Assembly):
|
||||
|
||||
@pgroup.setter
|
||||
def pgroup(self, value):
|
||||
if isinstance(self._pgroup, Adjustable):
|
||||
return self._pgroup.set_target_value().wait()
|
||||
self._pgroup = value
|
||||
|
||||
def acquire(self, file_name=None, Npulses=100, acq_pars={}):
|
||||
@@ -376,3 +378,12 @@ def validate_response(resp):
|
||||
# }
|
||||
|
||||
# r = requests.post(f'{broker_address}/retrieve_from_buffers',json=parameters, timeout=TIMEOUT_DAQ).json()
|
||||
|
||||
|
||||
|
||||
|
||||
#### >>> TODO implment >>>
|
||||
|
||||
|
||||
|
||||
#### <<< TODO implment <<<
|
||||
|
||||
+30
-5
@@ -139,6 +139,7 @@ class Scan:
|
||||
def doNextStep(self, step_info=None, verbose=True):
|
||||
# for call in self.callbacks_start_step:
|
||||
# call()
|
||||
t_step_start = time()
|
||||
if self.checker:
|
||||
first_check = time()
|
||||
checker_unhappy = False
|
||||
@@ -159,10 +160,14 @@ 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)
|
||||
|
||||
dt_callbacks_step_start = time()-t_step_start
|
||||
|
||||
if not len(self.values_todo) > 0:
|
||||
return False
|
||||
values_step = self.values_todo[0]
|
||||
@@ -171,16 +176,20 @@ class Scan:
|
||||
"Starting scan step %d of %d"
|
||||
% (self.nextStep + 1, len(self.values_todo) + len(self.values_done))
|
||||
)
|
||||
ms = []
|
||||
|
||||
fina = self.get_filename(self.nextStep)
|
||||
t_adj_start = time()
|
||||
ms = []
|
||||
for adj, tv in zip(self.adjustables, values_step):
|
||||
ms.append(adj.set_target_value(tv))
|
||||
for tm in ms:
|
||||
tm.wait()
|
||||
dt_adj = time()-t_adj_start
|
||||
|
||||
# settling
|
||||
sleep(self.settling_time)
|
||||
|
||||
t_ctr_start = time()
|
||||
readbacks_step = []
|
||||
adjs_name = []
|
||||
adjs_offset = []
|
||||
@@ -225,26 +234,42 @@ class Scan:
|
||||
for ta in acs:
|
||||
ta.wait()
|
||||
filenames.extend(ta.file_names)
|
||||
dt_ctr = time() - t_ctr_start
|
||||
|
||||
if verbose:
|
||||
print("Done with acquisition")
|
||||
|
||||
### >>> Callback end
|
||||
t_callbacks_step_end = time()
|
||||
if self.checker:
|
||||
if not self.checker.stop_and_analyze():
|
||||
return True
|
||||
if callable(step_info):
|
||||
tstepinfo = step_info()
|
||||
else:
|
||||
tstepinfo = step_info
|
||||
tstepinfo = {}
|
||||
self.values_done.append(self.values_todo.pop(0))
|
||||
self.pulses_done.append(self.pulses_per_step.pop(0))
|
||||
self.readbacks.append(readbacks_step)
|
||||
|
||||
if self.callbacks_end_step:
|
||||
for caller in self.callbacks_end_step:
|
||||
caller(self, **self.callbacks_kwargs)
|
||||
dt_callbacks_step_end = time() - t_callbacks_step_end
|
||||
### <<<< Callback end
|
||||
|
||||
tstepinfo['times'] = {
|
||||
"callbacks_step_start":dt_callbacks_step_start,
|
||||
"adjustables" : dt_adj,
|
||||
"counters" : dt_ctr,
|
||||
"callbacks_step_end": dt_callbacks_step_end,
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
@@ -38,7 +38,7 @@ class Acquisition:
|
||||
if self._thread.ident is None:
|
||||
return "waiting"
|
||||
else:
|
||||
if self._thread.isAlive():
|
||||
if self._thread.is_alive():
|
||||
return "acquiring"
|
||||
else:
|
||||
return "done"
|
||||
|
||||
+89
-12
@@ -1239,6 +1239,8 @@ namespace.append_obj(
|
||||
# module_name="eco.acquisition.epics_data",
|
||||
# )
|
||||
|
||||
|
||||
## TODO pgroup non adjustable/dynamically changeable!
|
||||
namespace.append_obj(
|
||||
"Scans",
|
||||
name="scans_epics",
|
||||
@@ -1289,6 +1291,8 @@ namespace.append_obj(
|
||||
lazy=True,
|
||||
)
|
||||
|
||||
|
||||
#TODO: need to check if the value property actually works here for the pgroup in the run table to make is dynamic!
|
||||
namespace.append_obj(
|
||||
"Run_Table2",
|
||||
name="run_table",
|
||||
@@ -1870,6 +1874,7 @@ namespace.append_obj(
|
||||
name="checker",
|
||||
)
|
||||
|
||||
# TODO resove scans pgroup sensitivity! Clearly non dynamic.
|
||||
namespace.append_obj(
|
||||
"Scans",
|
||||
data_base_dir="scan_data",
|
||||
@@ -2191,25 +2196,51 @@ class Incoupling(Assembly):
|
||||
def __init__(self, name=None):
|
||||
super().__init__(name=name)
|
||||
self._append(SmaractRecord, "SARES23-LIC:MOT_13", name="ry", is_setting=True)
|
||||
self._append(SmaractRecord, "SARES23-LIC:MOT_16", name="rx", is_setting=True)
|
||||
self._append(SmaractRecord, "SARES23-USR:MOT_4", name="rx", is_setting=True)
|
||||
self._append(SmaractRecord, "SARES23-LIC:MOT_15", name="y", is_setting=True)
|
||||
self._append(MotorRecord, "SARES20-MF2:MOT_5", name="x",is_setting=True)
|
||||
self._append(SmaractRecord, "SARES23-USR:MOT_2", name="focus_pos",is_setting=True)
|
||||
self._append(SmaractRecord, "SARES23-USR:MOT_3", name="eos_focus",is_setting=True)
|
||||
|
||||
|
||||
self._append(AnalogOutput, 'SLAAR21-LDIO-LAS6991:DAC06_VOLTS',name='eos_fb_rx', is_setting=True)
|
||||
self._append(AnalogOutput, 'SLAAR21-LDIO-LAS6991:DAC05_VOLTS',name='eos_fb_ry', is_setting=True)
|
||||
|
||||
self._append(AnalogOutput, 'SLAAR21-LDIO-LAS6991:DAC09_VOLTS',name='nir_mirr1_ry', is_setting=True)
|
||||
self._append(AnalogOutput, 'SLAAR21-LDIO-LAS6991:DAC10_VOLTS',name='nir_mirr1_rx', is_setting=True)
|
||||
|
||||
self._append(AnalogOutput, 'SLAAR21-LDIO-LAS6991:DAC11_VOLTS',name='nir_mirr2_ry', is_setting=True)
|
||||
self._append(AnalogOutput, 'SLAAR21-LDIO-LAS6991:DAC12_VOLTS',name='nir_mirr2_rx', is_setting=True)
|
||||
|
||||
self._append(
|
||||
AdjustablePv,
|
||||
pvsetname="SLAAR21-LCAM-C561:FIT2_REQUIRED.PROC",
|
||||
name="eos_fb_setpoint_rq",
|
||||
accuracy=1,
|
||||
is_setting=True,
|
||||
)
|
||||
self._append(
|
||||
AdjustablePv,
|
||||
pvsetname="SLAAR21-LCAM-C561:FIT2_DEFAULT.PROC",
|
||||
name="eos_fb_setpoint_df",
|
||||
accuracy=1,
|
||||
is_setting=True,
|
||||
)
|
||||
self._append(
|
||||
AdjustablePv,
|
||||
pvsetname="SLAAR21-LTIM01-EVR0:CALCW.A",
|
||||
name="eos_fd_enable",
|
||||
accuracy=1,
|
||||
is_setting=True,
|
||||
)
|
||||
try:
|
||||
self.motor_configuration_thorlabs = {
|
||||
"polarizer": {
|
||||
"pvname": "SLAAR21-LMOT-ELL3",
|
||||
},
|
||||
"hwp": {
|
||||
"pvname": "SLAAR21-LMOT-ELL5",
|
||||
},
|
||||
"block": {
|
||||
"nir_block": {
|
||||
"pvname": "SLAAR21-LMOT-ELL2",
|
||||
},
|
||||
"nd_filter": {
|
||||
"eos_block": {
|
||||
"pvname": "SLAAR21-LMOT-ELL4",
|
||||
},
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
### thorlabs piezo motors ###
|
||||
@@ -2222,6 +2253,18 @@ class Incoupling(Assembly):
|
||||
)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
# self._append(AdjustableVirtual,
|
||||
# [self.crystal, self.hwp],
|
||||
# self.thz_pol_get,
|
||||
# self.thz_pol_set,
|
||||
# name="thz_polarization",
|
||||
# )
|
||||
|
||||
# def thz_pol_set(self, val):
|
||||
# return 1.0 * val, 1.0 / 2 * val
|
||||
|
||||
# def thz_pol_get(self, val, val2):
|
||||
# return 1.0 * val2
|
||||
|
||||
namespace.append_obj(
|
||||
Incoupling,
|
||||
@@ -2394,6 +2437,39 @@ namespace.append_obj(
|
||||
# THz,
|
||||
# lazy=True,
|
||||
# name="thz",
|
||||
# self._append(
|
||||
# AdjustableVirtual,
|
||||
# [self.crystal_ROT, self.thz_wp],
|
||||
# self.thz_pol_get,
|
||||
# self.thz_pol_set,
|
||||
# name="",
|
||||
# )
|
||||
# # self.thz_polarization = AdjustableVirtual(
|
||||
# # [self.crystal_ROT, self.thz_wp],
|
||||
# # self.thz_pol_get,
|
||||
# # self.thz_pol_set,
|
||||
# # name="thz_polarization",
|
||||
# # )
|
||||
# self._append(
|
||||
# AdjustableVirtual,
|
||||
# [self.delay_thz, self.delay_800_pump],
|
||||
# self.delay_get,
|
||||
# self.delay_set,
|
||||
# name="combined_delay",
|
||||
# )
|
||||
|
||||
# # self.combined_delay = AdjustableVirtual(
|
||||
# # [self.delay_thz, self.delay_800_pump],
|
||||
# # self.delay_get,
|
||||
# # self.delay_set,
|
||||
# # name="combined_delay",
|
||||
# # )
|
||||
|
||||
# def thz_pol_set(self, val):
|
||||
# return 1.0 * val, 1.0 / 2 * val
|
||||
|
||||
# def thz_pol_get(self, val, val2):
|
||||
# return 1.0 * val2
|
||||
# )
|
||||
|
||||
# class THz_in_air(Assembly):
|
||||
@@ -2775,6 +2851,7 @@ namespace.append_obj(
|
||||
|
||||
|
||||
# try to append pgroup folder to path !!!!! This caused eco to run in a timeout without error traceback !!!!!
|
||||
# TODO pgroup non dynamic here!
|
||||
try:
|
||||
import sys
|
||||
from ..utilities import TimeoutPath
|
||||
@@ -2906,7 +2983,7 @@ class IlluminatorsLasers(Assembly):
|
||||
self._append(
|
||||
MpodChannel,
|
||||
pvbase="SARES21-PS7071",
|
||||
channel_number=5,
|
||||
channel_number=3,
|
||||
name="illumination_inline",
|
||||
)
|
||||
self._append(
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from data_api import get_data, search
|
||||
# from data_api import get_data, search
|
||||
from ..epics.detector import DetectorPvDataStream
|
||||
from fnmatch import translate
|
||||
import datetime, dateutil
|
||||
|
||||
@@ -324,7 +324,8 @@ class CameraBasler(Assembly):
|
||||
camserver_alias=camserver_alias,
|
||||
camserver_group=camserver_group,
|
||||
name="config_cs",
|
||||
is_display=False,
|
||||
is_display="recursive",
|
||||
is_setting=True
|
||||
)
|
||||
|
||||
self.config_cs.set_alias()
|
||||
|
||||
@@ -1283,12 +1283,15 @@ class MotorRecord(Assembly):
|
||||
if not step_value:
|
||||
step_value = pv.get()
|
||||
print(f"Tweaking {self.name} at step size {step_value}", end="\r")
|
||||
start_value = self.get_current_value()
|
||||
|
||||
# help = "q = exit; up = step*2; down = step/2, left = neg dir, right = pos dir\n"
|
||||
# help = help + "g = go abs, s = set"
|
||||
help = "q = exit; up = step*2; down = step/2, left = neg dir, right = pos dir\n"
|
||||
help = help + "g = go abs, s = set"
|
||||
help = help + "g = go abs, s = start value, r = reset current value to"
|
||||
print(f"tweaking {self.name}")
|
||||
print(help)
|
||||
print(f"Starting at {self.get_current_value()}")
|
||||
print(f"Starting at {start_value}")
|
||||
step_value = float(step_value)
|
||||
oldstep = 0
|
||||
k = KeyPress()
|
||||
@@ -1323,6 +1326,9 @@ class MotorRecord(Assembly):
|
||||
pvf.put(1)
|
||||
elif k.isl():
|
||||
pvr.put(1)
|
||||
elif k.iskey("s"):
|
||||
self.set_target_value(start_value)
|
||||
p.print(value=self.get_current_value())
|
||||
elif k.iskey("g"):
|
||||
print("enter absolute position (char to abort go to)")
|
||||
sys.stdout.flush()
|
||||
@@ -1333,7 +1339,7 @@ class MotorRecord(Assembly):
|
||||
except:
|
||||
print("value cannot be converted to float, exit go to mode ...")
|
||||
sys.stdout.flush()
|
||||
elif k.iskey("s"):
|
||||
elif k.iskey("r"):
|
||||
print("enter new set value (char to abort setting)")
|
||||
sys.stdout.flush()
|
||||
v = sys.stdin.readline()
|
||||
@@ -1341,15 +1347,17 @@ class MotorRecord(Assembly):
|
||||
v = float(v[0:-1])
|
||||
self.reset_current_value_to(v)
|
||||
except:
|
||||
print("value cannot be converted to float, exit go to mode ...")
|
||||
print("value cannot be converted to float, exit reset mode ...")
|
||||
sys.stdout.flush()
|
||||
elif k.isq():
|
||||
break
|
||||
else:
|
||||
print(help)
|
||||
self.clear_value_callback(index=ind_callback)
|
||||
print("\r", end="")
|
||||
print(f"final position: {self.get_current_value()}")
|
||||
print(f"final tweak step: {pv.get()}")
|
||||
# print('\033[K',"the info",sep='',flush=True)
|
||||
|
||||
def tweak(self, *args, **kwargs):
|
||||
return self._tweak_ioc(*args, **kwargs)
|
||||
|
||||
@@ -49,6 +49,8 @@ class PowerBrickComm:
|
||||
parstring.strip("\n")
|
||||
setstring = parstring + "=" + str(value)
|
||||
return self.pbsshcom.iawrite(setstring)
|
||||
|
||||
# def set_hmz
|
||||
|
||||
|
||||
class PowerBrickChannelPars(Assembly):
|
||||
|
||||
@@ -40,6 +40,7 @@ pars_StatusMotorListCtrl = {
|
||||
("EncLoss", "r"),
|
||||
("HomeInProgress", "r"),
|
||||
("HomeComplete", "r"),
|
||||
("HomeOffset", "r"),
|
||||
("TriggerMove", "r"),
|
||||
("DacLimit", "r"),
|
||||
("SoftLimit", "r"),
|
||||
|
||||
@@ -118,7 +118,10 @@ class MpodChannel(Assembly):
|
||||
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)
|
||||
name='ramp_down', is_setting=True)
|
||||
self._append(AdjustablePv,
|
||||
self.pvbase+f':{self._module_string}_CH{self.channel_number}_MEAS_OUT_A',
|
||||
name='current', is_setting=False, is_display=True)
|
||||
self._append(MpodStatus,self.pvbase, self.channel_number, self._module_string, name='flags')
|
||||
|
||||
def get_current_value(self,*args,**kwargs):
|
||||
|
||||
@@ -8,6 +8,7 @@ class Changer:
|
||||
self._changer = changer
|
||||
self._stopper = stopper
|
||||
self._thread = PropagatingThread(target=self._changer, args=(target,))
|
||||
# self._thread = Thread(target=self._changer, args=(target,))
|
||||
if not hold:
|
||||
self._thread.start()
|
||||
|
||||
|
||||
@@ -139,6 +139,34 @@ class AnalogOutput(Assembly):
|
||||
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=False,
|
||||
)
|
||||
self._append(
|
||||
AdjustablePv,
|
||||
self.pvname + ".ESLO",
|
||||
name="linear_calibration_slope",
|
||||
is_setting=True,
|
||||
is_display=False,
|
||||
)
|
||||
|
||||
def get_current_value(self):
|
||||
return self.value.get_current_value()
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
|
||||
|
||||
|
||||
# single acquisition class
|
||||
class Acquisition:
|
||||
def __init__(
|
||||
self,
|
||||
parent=None,
|
||||
acquire=lambda: None,
|
||||
acquisition_kwargs={},
|
||||
hold=True,
|
||||
stopper=None,
|
||||
get_result=lambda: None,
|
||||
):
|
||||
self.acquisition_kwargs = acquisition_kwargs
|
||||
for key, val in acquisition_kwargs.items():
|
||||
self.__dict__[key] = val
|
||||
self._stopper = stopper
|
||||
self._get_result = get_result
|
||||
if acquire:
|
||||
self.set_acquire_foo(acquire, hold=hold)
|
||||
|
||||
def set_acquire_foo(self, acquire, hold=True):
|
||||
self._acquire = acquire
|
||||
self._thread = PropagatingThread(target=self._acquire)
|
||||
if not hold:
|
||||
self._thread.start()
|
||||
|
||||
def wait(self):
|
||||
self._thread.join()
|
||||
return self._get_result()
|
||||
|
||||
def start(self):
|
||||
self._thread.start()
|
||||
|
||||
def status(self):
|
||||
if self._thread.ident is None:
|
||||
return "waiting"
|
||||
else:
|
||||
if self._thread.is_alive():
|
||||
return "acquiring"
|
||||
else:
|
||||
return "done"
|
||||
|
||||
def stop(self):
|
||||
self._stopper()
|
||||
@@ -82,7 +82,7 @@ def spec_convenience(Adj):
|
||||
try:
|
||||
self._currentChange = self.set_target_value(value)
|
||||
self._currentChange.wait()
|
||||
except KeyboardInterrupt:
|
||||
except (KeyboardInterrupt,SystemExit):
|
||||
self._currentChange.stop()
|
||||
return self._currentChange
|
||||
|
||||
@@ -101,9 +101,12 @@ def spec_convenience(Adj):
|
||||
self._currentChange = self.set_target_value(
|
||||
value + startvalue, *args, **kwargs
|
||||
)
|
||||
print("spec conven")
|
||||
self._currentChange.wait()
|
||||
except KeyboardInterrupt:
|
||||
|
||||
except (KeyboardInterrupt,SystemExit):
|
||||
self._currentChange.stop()
|
||||
|
||||
return self._currentChange
|
||||
|
||||
Adj.mv = mv
|
||||
@@ -292,7 +295,7 @@ def update_changes(Adj):
|
||||
cb_id = self.add_value_callback(cbfoo)
|
||||
self._currentChange = self.set_target_value(value)
|
||||
self._currentChange.wait()
|
||||
except KeyboardInterrupt:
|
||||
except (KeyboardInterrupt, SystemExit):
|
||||
self._currentChange.stop()
|
||||
print(f"\nAborted change at (~) {self.get_current_value():1.5g}")
|
||||
finally:
|
||||
@@ -641,14 +644,15 @@ class AdjustableVirtual:
|
||||
)
|
||||
|
||||
def check_target_value_within_limits(self, value):
|
||||
in_lims = []
|
||||
in_lims = [True]
|
||||
values = self._foo_set_target_value_current_value(value)
|
||||
if not hasattr(values, "__iter__"):
|
||||
values = (values,)
|
||||
|
||||
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))
|
||||
if not val is None:
|
||||
in_lims.append((lim_low < val) and (val < lim_high))
|
||||
return all(in_lims)
|
||||
|
||||
def reset_current_value_to(self, value):
|
||||
@@ -847,7 +851,7 @@ class Tweak:
|
||||
self.thread = None
|
||||
|
||||
def print(self):
|
||||
if self.thread and self.thread.isAlive():
|
||||
if self.thread and self.thread.is_alive():
|
||||
return
|
||||
else:
|
||||
self.thread = Thread(target=self.print_foo)
|
||||
|
||||
@@ -7,8 +7,8 @@ from tabulate import tabulate
|
||||
import sys, colorama
|
||||
try:
|
||||
from inspect import getargspec
|
||||
except:
|
||||
from inspect import getfullargspec
|
||||
except: # for python 3.12
|
||||
from inspect import getfullargspec as getargspec
|
||||
|
||||
import eco
|
||||
from ansi2html import Ansi2HTMLConverter
|
||||
|
||||
@@ -28,3 +28,17 @@ class ValueUpdateMonitorable(Protocol):
|
||||
class InitialisationWaitable(Protocol):
|
||||
def _wait_for_initialisation(self):
|
||||
...
|
||||
|
||||
@runtime_checkable
|
||||
class Counter:
|
||||
def acquire(self):
|
||||
...
|
||||
def start(self):
|
||||
...
|
||||
def stop(self):
|
||||
...
|
||||
|
||||
|
||||
# file_name=fina, Npulses=self.pulses_per_step[0], acq_pars=acq_pars):
|
||||
)
|
||||
|
||||
@@ -431,14 +431,6 @@ class GPS(Assembly):
|
||||
|
||||
append_diffractometer_modules(self, configuration)
|
||||
|
||||
if configuration.diffcalc():
|
||||
self._append(
|
||||
Crystals,
|
||||
diffractometer_you=self,
|
||||
name="diffcalc",
|
||||
is_setting=False,
|
||||
is_display=False,
|
||||
)
|
||||
for jf_id, jf_name in configuration.jfs():
|
||||
self._append(
|
||||
Jungfrau,
|
||||
@@ -468,6 +460,14 @@ class GPS(Assembly):
|
||||
is_setting=False,
|
||||
is_display=True,
|
||||
)
|
||||
if configuration.diffcalc():
|
||||
self._append(
|
||||
Crystals,
|
||||
diffractometer_you=self,
|
||||
name="diffcalc",
|
||||
is_setting=False,
|
||||
is_display=False,
|
||||
)
|
||||
|
||||
if recspace_conv is not None:
|
||||
module_name, Conv_name = recspace_conv.split(":")
|
||||
|
||||
@@ -145,6 +145,13 @@ class StaeubliTx200(Assembly):
|
||||
try:
|
||||
import bernina_urdf
|
||||
self._urdf = bernina_urdf.models.Tx200_Ceiling(jf_id=robot_config.jf_id())
|
||||
if robot_config.vis_gps():
|
||||
try:
|
||||
self._urdf.__dict__['gps'] = bernina_urdf.models.GPS()
|
||||
from epics import PV
|
||||
self._gps_motors = [PV(f'SARES22-GPS:MOT_{m}.RBV') for m in ['TX', 'TY', 'RX', 'NY_RY2TH', 'MY_RYTH', 'HEX_TX', 'HEX_RX']]
|
||||
except Exception as e:
|
||||
print(f"Adding visual model of GPS failed with {e}")
|
||||
self._append(
|
||||
AdjustableFS,
|
||||
f"/sf/bernina/config/eco/reference_values/robot_auto_update_simulation.json",
|
||||
@@ -603,10 +610,13 @@ class StaeubliTx200(Assembly):
|
||||
|
||||
def show(self):
|
||||
self._urdf.sim.show()
|
||||
if 'gps' in self._urdf.__dict__.keys():
|
||||
self._urdf.sim.vis.add(self._urdf.__dict__['gps'])
|
||||
|
||||
######## Helper functions ##########
|
||||
def _auto_updater_simulation(self): #
|
||||
while True:
|
||||
gpss = None
|
||||
js = np.array(
|
||||
[
|
||||
self._cache["pos"][k]
|
||||
@@ -616,11 +626,22 @@ class StaeubliTx200(Assembly):
|
||||
if np.any([j is None for j in js]):
|
||||
time.sleep(1)
|
||||
continue
|
||||
if "_gps_motors" in self.__dict__.keys():
|
||||
try:
|
||||
gpss = np.array([m.value if not 'MOT_RX.RBV' in m.pvname else np.arctan(m.value / 1146) * 180 / np.pi for m in self._gps_motors ])
|
||||
except Exception as e:
|
||||
print(e)
|
||||
if self.auto_update_simulation():
|
||||
change = False
|
||||
if not np.all(js.round(3) == self._urdf.sim.pos.round(3)):
|
||||
self._urdf.sim.pos = js
|
||||
if self._urdf.sim._vis_running():
|
||||
self._urdf.sim.vis.step(0)
|
||||
change = True
|
||||
if (gpss is not None)&('gps' in self._urdf.__dict__.keys()):
|
||||
if not np.all(gpss.round(3) == self._urdf.gps.sim.pos.round(3)):
|
||||
self._urdf.gps.sim.pos = gpss
|
||||
change = True
|
||||
if self._urdf.sim._vis_running() and change:
|
||||
self._urdf.sim.vis.step(0)
|
||||
time.sleep(0.05)
|
||||
|
||||
def _get_on_poll_info(self):
|
||||
|
||||
@@ -2,6 +2,7 @@ from eco.xoptics.attenuator_safety_bernina import AttenuatorSafetyBernina
|
||||
from scipy import constants
|
||||
from eco.devices_general.powersockets import MpodChannel
|
||||
from eco.devices_general.wago import AnalogOutput
|
||||
from eco.devices_general.cameras_swissfel import CameraBasler
|
||||
from eco.epics.detector import DetectorPvDataStream
|
||||
import sys
|
||||
|
||||
@@ -88,18 +89,55 @@ class THzVirtualStages(Assembly):
|
||||
self.offset_mirr_z.mv(self._mz())
|
||||
self.offset_par_z.mv(self._pz())
|
||||
|
||||
class THz_cameras(Assembly):
|
||||
def __init__(self, name=None, camera_config={}):
|
||||
super().__init__(name=name)
|
||||
for name, cfg in camera_config.items():
|
||||
self._append(
|
||||
CameraBasler,
|
||||
cfg["pvname"],
|
||||
camserver_alias = "THC_" + name,
|
||||
name=name,
|
||||
is_setting=True,
|
||||
is_display="recursive",
|
||||
)
|
||||
self.__dict__[name].serial_no.mv(cfg["serial_number"])
|
||||
|
||||
class High_field_thz_chamber(Assembly):
|
||||
def __init__(
|
||||
self,
|
||||
delay_offset_detector = None,
|
||||
thc_x_adjustable=None,
|
||||
name=None,
|
||||
configuration=[],
|
||||
illumination_mpod=None,
|
||||
helium_control_valve=None,
|
||||
):
|
||||
super().__init__(name=name)
|
||||
self.delay_offset_detector = delay_offset_detector
|
||||
self._thc_x_adjustable = thc_x_adjustable
|
||||
self.par_out_pos = [-20, -9.5]
|
||||
self.camera_configuration = {
|
||||
"inline": {
|
||||
"pvname": "SARES20-CAMS142-M2",
|
||||
"serial_number": 23067644,
|
||||
},
|
||||
"sideview_45": {
|
||||
"pvname": "SARES20-CAMS142-M3",
|
||||
"serial_number": 23075971,
|
||||
},
|
||||
}
|
||||
self.motor_configuration = {
|
||||
"inline_mirror": {
|
||||
"id": "SARES23-USR:MOT_1",
|
||||
"pv_descr": "THz Chamber Inline_Mirror",
|
||||
"direction": 1,
|
||||
"sensor": 1,
|
||||
"speed": 250,
|
||||
"offset": 2.150241,
|
||||
"home_direction": "back",
|
||||
"kwargs": {"accuracy": 0.01},
|
||||
},
|
||||
"rx": {
|
||||
# "id": "SARES23-USR:MOT_13",
|
||||
"id": "SARES23-USR:MOT_16",
|
||||
@@ -194,6 +232,14 @@ class High_field_thz_chamber(Assembly):
|
||||
"home_direction": "forward",
|
||||
},
|
||||
}
|
||||
|
||||
### Cameras ###
|
||||
self._append(
|
||||
THz_cameras,
|
||||
name="camera",
|
||||
camera_config=self.camera_configuration,
|
||||
)
|
||||
|
||||
### lakeshore temperatures ####
|
||||
self._append(
|
||||
AdjustablePv,
|
||||
@@ -219,20 +265,7 @@ class High_field_thz_chamber(Assembly):
|
||||
name="temp_gishield",
|
||||
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():
|
||||
self._append(
|
||||
SmaractRecord,
|
||||
@@ -255,6 +288,40 @@ class High_field_thz_chamber(Assembly):
|
||||
name="delay_x_center",
|
||||
)
|
||||
|
||||
self._append(
|
||||
MotorRecord,
|
||||
pvname="SLAAR21-LMOT-M522:MOTOR_1",
|
||||
name="delaystage_thz",
|
||||
is_setting=True,
|
||||
is_display=False,
|
||||
is_status=True,
|
||||
)
|
||||
self._append(
|
||||
DelayTime,
|
||||
self.delaystage_thz,
|
||||
name="delay_thz",
|
||||
offset_detector=self.delay_offset_detector,
|
||||
is_setting=False,
|
||||
is_display=True,
|
||||
is_status=True,
|
||||
)
|
||||
if self._thc_x_adjustable is not None:
|
||||
|
||||
def movexcomp(x):
|
||||
delay = self.delay_thz.get_current_value()
|
||||
dx = x - self._thc_x_adjustable.get_current_value()
|
||||
new_delay = delay + dx / 1000 / constants.c
|
||||
return x, new_delay
|
||||
|
||||
self._append(
|
||||
AdjustableVirtual,
|
||||
[self._thc_x_adjustable, self.delay_thz],
|
||||
lambda x, delay_thz: x,
|
||||
movexcomp,
|
||||
name="thcx_delaycomp",
|
||||
is_setting=False,
|
||||
)
|
||||
|
||||
if "cube" in configuration:
|
||||
for name, config in self.motor_configuration_cube.items():
|
||||
self._append(
|
||||
|
||||
@@ -139,7 +139,7 @@ class HexapodPI(Assembly):
|
||||
),
|
||||
reset_current_value_to=False,
|
||||
change_simultaneously=False,
|
||||
check_limits=False,
|
||||
check_limits=True,
|
||||
append_aliases=True,
|
||||
unit="mm",
|
||||
name="y",
|
||||
|
||||
@@ -198,6 +198,7 @@ class AdjustablePv:
|
||||
""" 0: moving 1: move done"""
|
||||
change_done = 1
|
||||
if self.accuracy is not None:
|
||||
|
||||
if (
|
||||
np.abs(
|
||||
self.get_current_value(readback=False)
|
||||
@@ -221,9 +222,8 @@ class AdjustablePv:
|
||||
)
|
||||
|
||||
self._pv.put(value)
|
||||
time.sleep(0.1)
|
||||
while self.get_change_done() == 0:
|
||||
time.sleep(0.1)
|
||||
time.sleep(0.01)
|
||||
|
||||
def set_target_value(self, value, hold=False):
|
||||
"""Adjustable convention"""
|
||||
|
||||
+43
-2
@@ -48,8 +48,12 @@ class DetectorPvData(Assembly):
|
||||
else:
|
||||
return self.readback.get_current_value()
|
||||
|
||||
# def get_current_value_callback(self):
|
||||
# pass
|
||||
def get_current_value_callback(self, foo='accumulate',collector = [], run_once=True, print_output=False):
|
||||
if hasattr(self, "_pv"):
|
||||
return CallbackEpics(self,self._pv,foo=foo,collector=collector, run_once=run_once, print_output=print_output)
|
||||
# else:
|
||||
# raise Exception('the object does not have a _pv')
|
||||
|
||||
|
||||
def __call__(self):
|
||||
return self.get_current_value()
|
||||
@@ -249,3 +253,40 @@ class DetectorPvDataStream(Assembly):
|
||||
|
||||
def get_current_value(self, **kwargs):
|
||||
return self._pv.get(**kwargs)
|
||||
|
||||
class CallbackEpics:
|
||||
def __init__(self,pv,foo='accumulate',collector = [], run_once=True, print_output=False):
|
||||
self.pv = pv
|
||||
if collector is not None:
|
||||
self.data = collector
|
||||
|
||||
if foo=='accumulate':
|
||||
foo = self.accumulate_values
|
||||
self.foo = foo
|
||||
self.run_once = run_once
|
||||
self.print = print_output
|
||||
|
||||
def start(self):
|
||||
self.cb_index = self.pv.add_callback(self.foo,run_once=True,)
|
||||
|
||||
def stop(self):
|
||||
self.pv.remove_callback(self.cb_index)
|
||||
|
||||
def __enter__(self):
|
||||
self.start()
|
||||
return self
|
||||
|
||||
def __exit__(self, exc_type, exc_val, exc_tb):
|
||||
self.stop()
|
||||
|
||||
def accumulate_values(self, pvname=None, value=None, timestamp=None, **kwargs):
|
||||
# if not self.data:
|
||||
# self.data = []
|
||||
ts_local = time()
|
||||
self.data.append(
|
||||
{"value": value, "timestamp_ioc": timestamp, "timestamp_local": ts_local}
|
||||
)
|
||||
if self.print:
|
||||
print(
|
||||
f"{pvname}: {value}; time_ioc: {timestamp}; time_local: {ts_local}; diff: {ts_local-timestamp}"
|
||||
)
|
||||
|
||||
@@ -1120,6 +1120,12 @@ class LaserBernina(Assembly):
|
||||
name="delaystage_m2",
|
||||
is_setting=True,
|
||||
)
|
||||
self._append(
|
||||
MotorRecord,
|
||||
"SLAAR21-LMOT-M533:MOT",
|
||||
name="hwp_compressor",
|
||||
is_setting=True,
|
||||
)
|
||||
self._append(
|
||||
DelayTime,
|
||||
self.delaystage_pump,
|
||||
@@ -1301,14 +1307,14 @@ class PositionMonitors(Assembly):
|
||||
# is_display="recursive",
|
||||
# is_status=True,
|
||||
# )
|
||||
# self._append(
|
||||
# CameraPositionMonitor,
|
||||
# "SLAAR21-LCAM-CS841",
|
||||
# # name="table2_position",
|
||||
# name="timing_drift",
|
||||
# is_display="recursive",
|
||||
# is_status=True,
|
||||
# )
|
||||
self._append(
|
||||
CameraPositionMonitor,
|
||||
"SLAAR21-LCAM-CS841",
|
||||
# name="table2_position",
|
||||
name="timing_drift",
|
||||
is_display="recursive",
|
||||
is_status=True,
|
||||
)
|
||||
self._append(
|
||||
CameraPositionMonitor,
|
||||
"SLAAR21-LCAM-C561",
|
||||
|
||||
@@ -248,12 +248,33 @@ class MasterEventSystem(Assembly):
|
||||
def __repr__(self):
|
||||
return self.status(printit=False)
|
||||
|
||||
class EvrSequencer(Assembly):
|
||||
def __init__(self, pv_base, name=None):
|
||||
super().__init__(name=name)
|
||||
try:
|
||||
self._append(AdjustablePvEnum, pv_base + ':SEQ_SOURCE', name='source', is_display=True, is_setting=True)
|
||||
self._append(AdjustablePvEnum, pv_base + ':SEQ_SNUMPD', name='pulser_number', is_display=True, is_setting=True)
|
||||
self._append(DetectorPvData, pv_base + ':SEQ_RUNNING', name='is_running', is_display=True)
|
||||
self._append(AdjustablePvEnum, pv_base + ':Seq-Ena-Sel', name='enabled', is_display=True, is_setting=True)
|
||||
self._append(DetectorPvData, pv_base + ':SEQ_SELECT_FREQ', name='frequency', is_display=True)
|
||||
except:
|
||||
print(f'The evr sequencer of {pv_base} is likely old type')
|
||||
self._append(AdjustableMemory, None, name='frequency', is_display=True)
|
||||
|
||||
self._append(AdjustablePvEnum, pv_base + ':Seq-RunMode-Sel', name='mode', is_display=True, is_setting=True)
|
||||
|
||||
|
||||
self._append(AdjustablePv, pv_base + ':SEQ_DELAY', name='delay', is_display=True, is_setting=True)
|
||||
self._append(AdjustablePv, pv_base + ':SEQ_REPS', name='repetitions', is_display=True, is_setting=True)
|
||||
self._append(AdjustablePv, pv_base + ':SEQ_MULTIPLIER', name='freq_multiplier', is_display=True, is_setting=True)
|
||||
|
||||
|
||||
class EvrPulser(Assembly):
|
||||
def __init__(self, pv_base, event_master, name=None):
|
||||
def __init__(self, pv_base, event_master, parent_evr=None, name=None):
|
||||
super().__init__(name=name)
|
||||
self.pv_base = pv_base
|
||||
self._event_master = event_master
|
||||
self._parent_evr = parent_evr
|
||||
|
||||
self._append(
|
||||
AdjustablePvString, pv_base + "-Name-I", name="description", is_display=True
|
||||
@@ -329,10 +350,13 @@ class EvrPulser(Assembly):
|
||||
|
||||
@property
|
||||
def _eventcode(self):
|
||||
try:
|
||||
return self._event_master.event_codes[self.eventcode.get_current_value()]
|
||||
except KeyError:
|
||||
return None
|
||||
if self.eventcode.get_current_value() == 27:
|
||||
return self._parent_evr.sequencer
|
||||
else:
|
||||
try:
|
||||
return self._event_master.event_codes[self.eventcode.get_current_value()]
|
||||
except KeyError:
|
||||
return None
|
||||
|
||||
|
||||
class DummyPulser(Assembly):
|
||||
@@ -527,12 +551,17 @@ class EventReceiver(Assembly):
|
||||
):
|
||||
super().__init__(name=name)
|
||||
self.pvname = pvname
|
||||
|
||||
self._append(EvrSequencer,self.pvname,name='sequencer', is_display=True, is_setting=True)
|
||||
|
||||
|
||||
pulsers = []
|
||||
for n in range(n_pulsers):
|
||||
self._append(
|
||||
EvrPulser,
|
||||
f"{self.pvname}:Pul{n}",
|
||||
event_master,
|
||||
parent_evr=self,
|
||||
name=f"pulser{n}",
|
||||
is_setting=True,
|
||||
is_display=False,
|
||||
@@ -564,6 +593,8 @@ class EventReceiver(Assembly):
|
||||
# to._pulsers = self.pulsers
|
||||
self.outputs = outputs
|
||||
|
||||
|
||||
|
||||
self._append(
|
||||
AdjustablePv,
|
||||
self.pvname + ":SYSRESET",
|
||||
|
||||
@@ -11,12 +11,13 @@ plt.ion()
|
||||
|
||||
|
||||
class TtProcessor:
|
||||
def __init__(self, Nbg=10, channel_proj = "SARES20-CAMS142-M5.roi_signal_x_profile"):
|
||||
def __init__(self, Nbg=10, ref_code=25, channel_proj = "SARES20-CAMS142-M5.roi_signal_x_profile"):
|
||||
self.channel_proj = channel_proj
|
||||
self.bg = deque([], Nbg)
|
||||
self.sig = deque([], 1)
|
||||
self.pos = deque([], 1)
|
||||
self.amp = deque([], 1)
|
||||
self.ref_code=ref_code
|
||||
self.spec_ppd = deque([], 1)
|
||||
self.accumulator = Thread(target=self.run_continuously)
|
||||
self.accumulator.start()
|
||||
@@ -41,7 +42,7 @@ class TtProcessor:
|
||||
codes = m.data.data["SAR-CVME-TIFALL5:EvtSet"].value
|
||||
if codes is None:
|
||||
continue
|
||||
is_reference = codes[25] == 1
|
||||
is_reference = codes[self.ref_code] == 1
|
||||
try:
|
||||
if (lastgoodix - ix) > 1:
|
||||
print(f"missed {lastgoodix-ix-1} events!")
|
||||
|
||||
@@ -178,14 +178,12 @@ class TimetoolBerninaUSD(Assembly):
|
||||
AdjustablePv,
|
||||
pvsetname="SLAAR21-LFEEDBACK1:TARGET1",
|
||||
name="feedback_setpoint",
|
||||
accuracy=10,
|
||||
is_setting=True,
|
||||
)
|
||||
self._append(
|
||||
AdjustablePv,
|
||||
pvsetname="SLAAR21-LFEEDBACK1:ENABLE",
|
||||
name="feedback_enabled",
|
||||
accuracy=10,
|
||||
is_setting=True,
|
||||
)
|
||||
self._append(
|
||||
|
||||
@@ -540,6 +540,11 @@ class Namespace(Assembly):
|
||||
print(f"Initialisation took {time()-starttime} seconds")
|
||||
|
||||
if (not silent) and print_times:
|
||||
try:
|
||||
from collections import Iterable
|
||||
except:
|
||||
import collections.abc
|
||||
collections.Iterable = collections.abc.Iterable
|
||||
from ascii_graph import Pyasciigraph
|
||||
|
||||
gr = Pyasciigraph()
|
||||
|
||||
@@ -397,18 +397,35 @@ class DiffGeometryYou(Assembly):
|
||||
|
||||
### use robot motors if robot is in config
|
||||
if cfg.robot():
|
||||
self._append(
|
||||
AdjustableFS,
|
||||
f"/photonics/home/gac-bernina/eco/configuration/crystals/move_robot",
|
||||
name="move_robot",
|
||||
default_value=True,
|
||||
is_setting=False,
|
||||
)
|
||||
def rob_get(a): return a
|
||||
def rob_set(a):
|
||||
if self.move_robot():
|
||||
return [a]
|
||||
else:
|
||||
return None
|
||||
gam_rob = AdjustableVirtual([self.diffractometer.gamma_robot],rob_get, rob_set, name="gamma_robot", check_limits=True)
|
||||
del_rob = AdjustableVirtual([self.diffractometer.delta_robot],rob_get, rob_set, name="delta_robot", check_limits=True)
|
||||
get_lims = lambda a: a
|
||||
gam_rob.get_limits = get_lims(self.diffractometer.gamma_robot.get_limits)
|
||||
del_rob.get_limits = get_lims(self.diffractometer.delta_robot.get_limits)
|
||||
adjustables_dict.update(
|
||||
{
|
||||
"gamma": self.diffractometer.gamma_robot,
|
||||
"delta": self.diffractometer.delta_robot,
|
||||
"gamma": gam_rob,
|
||||
"delta": del_rob,
|
||||
}
|
||||
)
|
||||
### add the phi constraint to thc as phi_wobble if thc is in config
|
||||
if cfg.thc():
|
||||
import eco.bernina as b
|
||||
|
||||
thc = b.__dict__["thc"]
|
||||
thc.phi_wobble = self.constraints.phi
|
||||
def phi_wobble_get(a): return a
|
||||
def phi_wobble_set(a): return [a]
|
||||
self.diffractometer.thc._append(AdjustableVirtual, [self.constraints.phi], phi_wobble_get, phi_wobble_set, name='phi_wobble')
|
||||
if cfg.kappa():
|
||||
adjs = ["gamma", "mu", "delta", "eta_kap", "kappa", "phi_kap"]
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from time import sleep
|
||||
from time import sleep, time
|
||||
import sys, select
|
||||
from threading import Thread
|
||||
|
||||
@@ -32,9 +32,9 @@ class TimeoutPath:
|
||||
def __str__(self) -> str:
|
||||
return str(self._path)
|
||||
|
||||
|
||||
class PropagatingThread(Thread):
|
||||
def run(self):
|
||||
run_start = time()
|
||||
self.exc = None
|
||||
try:
|
||||
if hasattr(self, "_Thread__target"):
|
||||
@@ -44,6 +44,7 @@ class PropagatingThread(Thread):
|
||||
)
|
||||
else:
|
||||
self.ret = self._target(*self._args, **self._kwargs)
|
||||
|
||||
except BaseException as e:
|
||||
self.exc = e
|
||||
|
||||
|
||||
@@ -0,0 +1,177 @@
|
||||
from time import sleep
|
||||
import sys, select
|
||||
from threading import Thread
|
||||
|
||||
from concurrent.futures import ThreadPoolExecutor, TimeoutError
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
import numpy as np
|
||||
import matplotlib.pyplot as plt
|
||||
from numbers import Number
|
||||
|
||||
class TimeoutPath:
|
||||
executor = ThreadPoolExecutor(max_workers=1)
|
||||
|
||||
def __init__(self, *args, timeout: float = 1, **kwargs):
|
||||
self._path = Path(*args, **kwargs)
|
||||
self.timeout = timeout
|
||||
|
||||
def exists(self) -> bool:
|
||||
future = TimeoutPath.executor.submit(self._path.exists)
|
||||
try:
|
||||
return future.result(self.timeout)
|
||||
except TimeoutError:
|
||||
return False
|
||||
|
||||
def get_path(self) -> Path:
|
||||
return self._path
|
||||
|
||||
def __getattr__(self, name: str) -> Any:
|
||||
return getattr(self._path, name)
|
||||
|
||||
def __str__(self) -> str:
|
||||
return str(self._path)
|
||||
|
||||
|
||||
class PropagatingThread(Thread):
|
||||
def run(self):
|
||||
self.exc = None
|
||||
try:
|
||||
if hasattr(self, "_Thread__target"):
|
||||
# Thread uses name mangling prior to Python 3.
|
||||
self.ret = self._Thread__target(
|
||||
*self._Thread__args, **self._Thread__kwargs
|
||||
)
|
||||
else:
|
||||
self.ret = self._target(*self._args, **self._kwargs)
|
||||
except BaseException as e:
|
||||
self.exc = e
|
||||
|
||||
def join(self):
|
||||
super(PropagatingThread, self).join()
|
||||
if self.exc:
|
||||
raise self.exc
|
||||
return self.ret
|
||||
|
||||
def isiter(a):
|
||||
try:
|
||||
iter(a)
|
||||
return True
|
||||
except TypeError:
|
||||
return False
|
||||
|
||||
def roundto(v,interval):
|
||||
return np.rint(v/interval)*interval
|
||||
|
||||
def linlog_intervals(*args, verbose=True, plot=False):
|
||||
"""Get linearly and logarithmically spaced arrays from providing limits and intervals or number of intervals.
|
||||
Example usages:
|
||||
linlog_intervals(-1e-12,('lin',.1e-12),2e-12,('log',2e-12),1e-6,('lin',4),5e-6)
|
||||
|
||||
Args:
|
||||
*args : limits and specifications of intervals,
|
||||
limits are numbers,
|
||||
specifications tuples of strings 'lin' or 'log'
|
||||
and the definition if interval.
|
||||
A integer is interpretet as number of intervals within the limits,
|
||||
a float is interpreted asinterval size,
|
||||
where in log definition, the size of the first (smallest) interval is matched.
|
||||
verbose (bool, optional): _description_. Defaults to True.
|
||||
plot (bool, optional): _description_. Defaults to False.
|
||||
|
||||
Raises:
|
||||
Exception: _description_
|
||||
Exception: _description_
|
||||
Exception: _description_
|
||||
|
||||
Returns:
|
||||
numpy ndarray: 1D array of intervals.
|
||||
"""
|
||||
limits = []
|
||||
idefs = []
|
||||
last_lim = False
|
||||
for arg in args:
|
||||
if not last_lim and isinstance(arg,Number):
|
||||
limits.append(arg)
|
||||
last_lim = True
|
||||
elif last_lim and isiter(arg):
|
||||
idefs.append(arg)
|
||||
last_lim = False
|
||||
else:
|
||||
raise Exception('Limits need to follow interval description and vice versa')
|
||||
if verbose:
|
||||
print(limits,idefs)
|
||||
if not len(limits)==len(idefs)+1:
|
||||
raise Exception('need exactly one more limit than interval definitions!')
|
||||
|
||||
a = []
|
||||
for i,idef in enumerate(idefs):
|
||||
tlims = limits[i:i+2]
|
||||
if np.diff(tlims)<=0:
|
||||
raise Exception('number limits should increasing!')
|
||||
if isinstance(a,np.ndarray):
|
||||
if np.isclose(a[-1],tlims[0]):
|
||||
a = a[:-1]
|
||||
a = [a]
|
||||
|
||||
|
||||
if idef[0] == 'lin':
|
||||
if type(idef[1]) is int:
|
||||
a.append(np.linspace(*tlims,idef[1]+1))
|
||||
if type(idef[1]) is float:
|
||||
a.append(np.arange(tlims[0],tlims[1]+idef[1],idef[1]))
|
||||
if verbose:
|
||||
print(f'From {tlims[0]:5g} to {a[-1][-1]:5g}: {len(a[-1])-1} linear intervals of {np.mean(np.diff(a[-1])):5g} size')
|
||||
if plot:
|
||||
plt.plot(np.arange(len(np.hstack(a))-len(a[-1]), len(np.hstack(a))),a[-1],'db', mfc='none')
|
||||
if idef[0] == 'log':
|
||||
tlims = np.asarray(tlims)
|
||||
if type(idef[1]) is int:
|
||||
a.append(np.logspace(*np.log10(tlims),idef[1]+1))
|
||||
if type(idef[1]) is float:
|
||||
intlog = np.log10(tlims[0]+idef[1])-np.log10(tlims[0])
|
||||
a.append(10**np.arange(np.log10(tlims[0]),np.log10(tlims[1]),intlog))
|
||||
if verbose:
|
||||
intervals = np.diff(np.log10(a[-1]))
|
||||
|
||||
print(f'From {tlims[0]:5g} to {a[-1][-1]:5g}: {len(a[-1])-1} logarithmic intervals between {np.min(intervals):5g} and {np.max(intervals):5g} in sizes.')
|
||||
if plot:
|
||||
plt.plot(np.arange(len(np.hstack(a))-len(a[-1]), len(np.hstack(a))),a[-1],'or',mfc='none')
|
||||
|
||||
if verbose:
|
||||
if not np.isclose(a[-1][-1],tlims[1]):
|
||||
print(f' NB: given limit {tlims[1]:5g} computes off by {tlims[1]-a[-1][-1]:5g} from last element!')
|
||||
|
||||
|
||||
|
||||
a = np.hstack(a)
|
||||
if plot:
|
||||
plt.plot(np.arange(len(a)),a,'.k')
|
||||
if verbose:
|
||||
print(f'{len(a)} elements in total.')
|
||||
return a
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# TODO
|
||||
|
||||
# _wait_strs = '\|/-\|/-'
|
||||
|
||||
# class WaitInput:
|
||||
# def __init__(self,text,wait_time=5,update_interval=1):
|
||||
# self.text = text
|
||||
# self.wait_time=wait_time
|
||||
|
||||
|
||||
# def start(self):
|
||||
# resttime = self.wait_time
|
||||
# while resttime>0:
|
||||
# print(f"You have {resttime} seconds to answer!")
|
||||
# i, o, e = select.select( [sys.stdin], [], [], 2 )
|
||||
|
||||
# if (i):
|
||||
# print("You said", sys.stdin.readline().strip())
|
||||
# else:
|
||||
# print("You said nothing!")
|
||||
Reference in New Issue
Block a user