Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
7e7a73c
added capability to save a stack frame by frame as it is being collec…
RussBerg Dec 30, 2025
5f976b2
fix filter string
RussBerg Dec 30, 2025
bac72ea
fix stop for energy_device
RussBerg Dec 30, 2025
7e7126d
btn colors
RussBerg Dec 30, 2025
3f830f9
open progressive stack file with SWMR enabled
RussBerg Dec 30, 2025
a1c5ed6
remove comment
RussBerg Dec 30, 2025
3dc44f7
cleanup, remove progress events code
RussBerg Dec 31, 2025
7e7cfeb
progress coming from sequence dict for the scan
RussBerg Dec 31, 2025
febf476
dont warn if osa tracking device does not exist just ignore
RussBerg Dec 31, 2025
b7db565
fix progress for pattern gen, also alarm if loaded image beyond fine …
RussBerg Dec 31, 2025
c3e6325
fixed issue where new data was just added to the current scene instea…
RussBerg Jan 13, 2026
8b9aba7
the current year is now automatically added to the data directory sp…
RussBerg Jan 13, 2026
6a3c2fb
commented print statements
RussBerg Jan 19, 2026
58420c9
updated to use BaseDevice
RussBerg Jan 19, 2026
9736508
remove comented line
RussBerg Jan 19, 2026
c2f9ecb
disable hdw accel until it can be tested again
RussBerg Jan 19, 2026
8093ec6
standardize name of shutter control combo box
RussBerg Jan 19, 2026
ff9f73b
increased snd rcv timeout
RussBerg Jan 19, 2026
2c2e8b8
log to debugging instead of the user UI log
RussBerg Jan 19, 2026
865d326
remove scan time files
RussBerg Jan 26, 2026
b0b71d5
tighter checking on 3820 status, E712 hdw testing but not enabled, nx…
RussBerg Jan 26, 2026
bd52e0f
add metadata to progressive scan data file
RussBerg Jan 26, 2026
6d1f23f
fix filter string, removed prefix char
RussBerg Jan 26, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 12 additions & 4 deletions bcm/devices/ophyd/pi_e712.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@

from ophyd import Component as Cpt, EpicsSignal, Device
from ophyd.status import DeviceStatus, SubscriptionStatus
from cls.utils.log import get_module_logger

_logger = get_module_logger(__name__)

class E712WGDevice(Device):
run = Cpt(EpicsSignal, "ExecWavgen", kind="omitted", put_complete=True)
Expand All @@ -18,12 +21,17 @@ def trigger(self):

def check_value(*, old_value, value, **kwargs):
"Return True when the acquisition is complete, False otherwise."
#print(f"E712WGDevice: trigger: old_value={old_value} value={value}")
return (old_value == 0 and value == 1)
#print(f"E712WGDevice: trigger: check_value: old_value={old_value} value={value} returning [{(old_value == 1 and value == 0)}]")
sts = (old_value == 1 and value == 0)
if sts:
_logger.debug(f"E712WGDevice: trigger: check_value: Wavegen is [{old_value},{value}] !!!! STOPPED !!!!")
else:
_logger.debug(f"E712WGDevice: trigger: check_value: Wavegen is [{old_value},{value}] ### Running ###")
#return (old_value == 0 and value == 1)
return sts

status = SubscriptionStatus(self.run, check_value, settle_time=10.0)

self.run.put(1, wait=True)
self.run.set(1) # Ensure run is set to 1 before subscribing

return status

Expand Down
266 changes: 161 additions & 105 deletions bcm/devices/ophyd/qt/data_emitters.py

Large diffs are not rendered by default.

203 changes: 78 additions & 125 deletions bcm/devices/ophyd/sis3820_scalar.py
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ def calc_cur_progress(self, row, col):
calculate the current progress, 0-100% oer image
"""
percent = (row/self.num_rows) * 100.0
return(percent)
return percent

def set_sequence_map(self, map):
"""
Expand Down Expand Up @@ -236,25 +236,9 @@ def get_all_channel_names(self):
a convienience function to return the names of all the sis3820 channels,
primarily used to tell the parent UI what names to populate a detector selection form with
"""
return(self.channel_names)

def kickoff(self):
# base class call to kickoff will call set_finished() on the status
self.twoD_data = None
#_logger.info(f"kickoff: self.twoD_data = None ")
st = super().kickoff() #this sets the parents _acquiring attr to True

def check_value(*, old_value, value, **kwargs):
"Return True when the acquisition is complete, False otherwise."
return (old_value == 0 and value == 1)

status = SubscriptionStatus(self.run, check_value)

self.run.put(1)
return self.channel_names


#return st
return status

# def complete(self):
# # base class call to complete will call set_finished() on the status
Expand All @@ -272,9 +256,9 @@ def check_value(*, old_value, value, **kwargs):
def is_running(self):
run = self.run.get()
if run:
return(True)
return True
else:
return(False)
return False

def set_dwell(self, dwell):
"""
Expand Down Expand Up @@ -442,75 +426,69 @@ def process_sis3820_data(self, kwargs):
if self.row == 0:
fix_first_point = True

# if self.ignore_even_data_points:
# remove_last = False
# else:
# remove_last = True
#
# remove_first = False

#stripped_dat = sis3820_remove_row_change_extra_point(dat, ignore_even_data_points=self.ignore_even_data_points, fix_first_point=fix_first_point, remove_first=remove_first, remove_last=remove_last)
stripped_dat = sis3820_remove_row_change_extra_point(dat,
ignore_even_data_points=self.ignore_even_data_points,
fix_first_point=fix_first_point,
remove_first=self.remove_first_point,
remove_last=self.remove_last_point)

# if ch_num == 0:
# print(f"sis3820_scalar.py: process_sis3820_data: chan 0 data: raw", dat)
# print(f"sis3820_scalar.py: process_sis3820_data: chan 0 data: STRIPPED", stripped_dat)
# print()
# print(dat.shape)
# print(stripped_dat.shape)
if self.is_spec_scan:
#generate the correct channel name with spid
chan_nm = gen_complete_spec_chan_name(chan_nm, self.spec_spid)
data_dct[chan_nm] = stripped_dat

row_chan_dct = {}
row_chan_dct[self.row] = data_dct
# keep this data for collect to process
if self.twoD_data is None:
_logger.debug(f"twoD_data should not be None here")
self.twoD_data = {}

self.twoD_data[self.row] = data_dct

if self.enable_progress_emit:
percent = self.calc_cur_progress(self.row, self.col)
if self.seq_cntr in self.seq_map:
percent = self.seq_map[self.seq_cntr]["prog"]
img_num = self.seq_map[self.seq_cntr]["img_num"]
ev_idx = self.seq_map[self.seq_cntr]["ev_idx"]
pol_idx = self.seq_map[self.seq_cntr]["pol_idx"]
row = self.seq_map[self.seq_cntr]["row"]
col = self.seq_map[self.seq_cntr]["col"]

row_chan_dct = {}
#row_chan_dct[self.row] = data_dct
row_chan_dct[row] = data_dct

# keep this data for collect to process
#if self.twoD_data is None:
if row == 0:
#_logger.debug(f"twoD_data should not be None here")
# _logger.debug(
# f"process_sis3820_data(): [{self.seq_cntr}] resetting it as dict for row=[{row}]")
self.twoD_data = {}

#self.twoD_data[self.row] = data_dct
self.twoD_data[row] = data_dct

set_prog_dict(self._prog_dct, sp_id=0, percent=percent, cur_img_idx=img_num, ev_idx=ev_idx,
pol_idx=pol_idx)
plot_dct = make_counter_to_plotter_com_dct(self.row, self.col, data_dct, is_point=self.is_pxp_scan, prog_dct=self._prog_dct)
self.seq_cntr += 1
pol_idx=pol_idx)
self._prog_dct['self.seq_cntr'] = self.seq_cntr

else:
plot_dct = make_counter_to_plotter_com_dct(self.row, self.col, data_dct, is_point=self.is_pxp_scan, prog_dct={})
plot_dct = make_counter_to_plotter_com_dct(row=row, col=col, val=data_dct, is_point=self.is_pxp_scan, prog_dct=self._prog_dct)
self.seq_cntr += 1
self.new_plot_data.emit(plot_dct)
#_logger.debug(f"process_sis3820_data(): [{self.seq_cntr}] emitted new plot data for row=[{row}] col=[{col}] percent=[{percent}] img_num=[{img_num}]")

self.new_plot_data.emit(plot_dct)

self.increment_indexes()

def set_config(self, rows, cols, is_pxp_scan=False, is_e712_wg_scan=False, pxp_single_trig=False):
"""
configure the SIS3820 for a particular scan type
"""
self.abort_scan()
self.init_indexs()
self.seq_cntr = 0
self.num_rows = rows
self.num_cols = cols
self.is_pxp_scan = is_pxp_scan
self.enable_progress_emit = True
if is_pxp_scan and not is_e712_wg_scan:
self.enable_progress_emit = False
#all point by point scans, det, osa etc
self.ignore_even_data_points = False
self.num_acqs.put(1)
# make it 2 counts as first in buffer is always huge and inaccurate
#self.num_acqs_per_trig.put(2)
self.num_acqs_per_trig.put(1)
elif pxp_single_trig:
self.enable_progress_emit = True
self.num_cols = 0 # this forces self.row to increment each iteration of the sequence when self.increment_indexes
# point scan by Ptychography
self.ignore_even_data_points = False
Expand All @@ -519,7 +497,6 @@ def set_config(self, rows, cols, is_pxp_scan=False, is_e712_wg_scan=False, pxp_s
self.num_acqs_per_trig.put(rows * cols)

elif is_pxp_scan and is_e712_wg_scan:
self.enable_progress_emit = True
self.num_cols = 0 #this forces self.row to increment each iteration of the sequence when self.increment_indexes
# point scan
self.ignore_even_data_points = True
Expand All @@ -528,15 +505,13 @@ def set_config(self, rows, cols, is_pxp_scan=False, is_e712_wg_scan=False, pxp_s
self.num_acqs_per_trig.put(rows * cols)

elif not is_pxp_scan and is_e712_wg_scan:
self.enable_progress_emit = True
#line scan
#cols = cols + SIS3820_EXTRA_PNTS
self.ignore_even_data_points = False
cols = cols + SIS3820_EXTRA_PNTS
self.num_acqs.put(cols)
self.num_acqs_per_trig.put(rows * cols)
else:
self.enable_progress_emit = False
#coarseImage scan
self.ignore_even_data_points = False
self.num_acqs.put(cols + SIS3820_EXTRA_PNTS)
Expand Down Expand Up @@ -613,9 +588,9 @@ def is_chan_enabled(self, chan_name):
attr = getattr(self, attr_ch_nm)
en = attr.get()
if en:
return(True)
return True
else:
return(False)
return False

def enable_channel(self, chan_name, en):
"""
Expand All @@ -632,7 +607,7 @@ def enable_channel(self, chan_name, en):
def get_chan_num_from_name(self, nm):
nm = nm.replace("DNM_","")
chan = int(nm.replace('SIS3820_CHAN_',''))
return(chan)
return chan

def get_enabled_chans(self, update_map=True):
'''
Expand Down Expand Up @@ -883,66 +858,7 @@ def read(self):

self.increment_indexes()
# print(dct)
return(dct)
# def read(self):
# '''
# if the current scan is lxl then I need to have an
# '''
# # print('SIS3820ScalarDevice: read called')
# # return(self.waveform_rbv.get())
#
#
# #line data
# self.rawData = self.waveform_rbv.get()
# # note the first data point in the array returned is the number of enabled channels
# if hasattr(self.rawData, "shape"):
# _nsamples, = self.rawData.shape
# en_chan_nums, en_chan_nms, en_chan_fbk_attrs = self.get_enabled_chans()
# num_chans = len(en_chan_nums)
# if _nsamples == 0:
# dct = {
# self.name + '_waveform_rbv': {
# "value": [0],
# "timestamp": time.time(),
# "chan_nms": en_chan_nms,
# "chan_nums": en_chan_nums,
# "chan_dct": {},
# "col": int(self.col),
# "row": int(self.row),
#
# }
# }
# return(dct)
# #print("self.rawdata.shape", self.rawData.shape)
# data = self.rawData[1:]
# if self.return_2D_data:
# #self.twoD_data contains a dictionary using the row number as the key to a dictionary whose
# # keys are the channel names and values are 1 rows worth of points
# dct = {}
# # append each rows data to that channels total data
# for row_num, data_dct in self.twoD_data.items():
# for k in data_dct.keys():
# if k not in dct.keys():
# dct[k] = []
# dct[k] += list(data_dct[k])
#
# #return a dict of channels with 1D data
# _data = dct
# else:
# _data = self.read_process_sis3820_data(data)
#
# dct = {
# self.name + '_waveform_rbv': {
# "value": _data,
# "timestamp": time.time(),
# # "chan_dct": self.read_process_sis3820_data(data),
# }
# }
#
# self.increment_indexes()
# return(dct)


return dct

def read_process_sis3820_data(self, arr):
"""
Expand Down Expand Up @@ -985,7 +901,7 @@ def read_process_sis3820_data(self, arr):
#print(f"SIS3820: read() channel name to {chan_nm}")
data_dct[chan_nm] = stripped_dat

return(data_dct)
return data_dct


def describe_collect(self):
Expand Down Expand Up @@ -1050,6 +966,7 @@ def collect(self):
self._collected_data = None

if self._pivot:
# return a single event
for attr, data in collected.items():
name = getattr(self, attr).name
for ts, value in zip(data["timestamp"], data["value"]):
Expand All @@ -1059,21 +976,57 @@ def collect(self):
data={name: value},
)
# print('collect: ', d)
# _logger.debug(
# f"------------ if self._pivot:: collect called [{self._russ_collect_counter}] times, dict size is [{len(d)}]---------------- ")
yield d

else:
# return all events as an array
for attr, data in collected.items():
d = dict(
time=time.time(),
timestamps={attr: data["timestamp"]},
#data={attr: data['value']},
data={attr: self.merge_row_data_into_2d()},
data={attr: self.merge_twoD_data_row_data_into_2d()},
)
self.twoD_data = None
#_logger.info(f"collect: self.twoD_data = None ")
# _logger.debug(f"collect: resetting self.twoD_data = None ")
# self.twoD_data = None

yield d

# def trigger(self):
# def check_value(*, old_value, value, **kwargs):
# print("SIS3820: check_value before if")
# #"Mark status as finished when the acquisition is complete."
# if old_value == 1 and value == 0:
# print("SIS3820: calling status.set_finished()")
# status.set_finished()
# # Clear the subscription.
# self.run.clear_sub(check_value)
#
# status = DeviceStatus(self.run)
# self.run.subscribe(check_value)
# self.run.set(1)
# print("SIS3820: setting run to 1, returning status")
# return status

# def trigger(self):
# def check_value(*, old_value, value, **kwargs):
# "Return True when the run is complete, False otherwise."
# return (old_value == 1 and value == 0)
#
# status = SubscriptionStatus(self.run, check_value)
# self.run.set(1)
# return status

# def complete(self):
# def check_value(*, old_value, value, **kwargs):
# #"Return True when the run is complete, False otherwise."
# return (old_value == 1 and value == 0)
#
# status = SubscriptionStatus(self.run, check_value)
# #self.run.set(1)
# return status

def sis3820_remove_row_change_extra_point(chan_data, ignore_even_data_points=False, fix_first_point=False, remove_first=False, remove_last=False):
"""
Expand Down
2 changes: 1 addition & 1 deletion bcm/devices/ophyd/stxm_sample_mtr.py
Original file line number Diff line number Diff line change
Expand Up @@ -321,7 +321,7 @@ def do_interferometer_check(self):

d_rng = math.fabs(cfbk - ffbk)
if d_rng > self.min_interfer_reset_range:
print(f"do_interferometer_check: (delta range coarse to fine fbk) {d_rng} > {self.min_interfer_reset_range}(MIN_INTERFER_RESET_RANGE_UM) range too large Resetting interferometer")
_logger.info(f"do_interferometer_check: (delta range coarse to fine fbk) {d_rng:.3f} > {self.min_interfer_reset_range} (MIN_INTERFER_RESET_RANGE_UM) range too large Resetting interferometer")
self.reset_interferometers()

#if we did a reset, loop here until the feedbacks match
Expand Down
2 changes: 1 addition & 1 deletion bcm/devices/sim/energy_dev.py
Original file line number Diff line number Diff line change
Expand Up @@ -508,7 +508,7 @@ def set(self, val):
st.set_finished()
return st

def stop(self):
def stop(self, success=True):
# self.close()
# self.is_open = False
if hasattr(self.a0_dev, "stop"):
Expand Down
Loading