BS data now found correctly
This commit is contained in:
+344
-174
@@ -12,6 +12,7 @@ import sys
|
||||
import time
|
||||
import zmq
|
||||
import re
|
||||
import glob
|
||||
from pathlib import Path
|
||||
|
||||
from loguru import logger
|
||||
@@ -23,7 +24,7 @@ import receive_msg
|
||||
#sys.path.insert(0, os.path.expanduser('/sf/cristallina/applications/mx/jungfraujoch_openapi_python/sf_datafiles'))
|
||||
#from sfdata import SFDataFiles
|
||||
#define log file place:
|
||||
LOG_FILENAME = time.strftime("/sf/cristallina/data/p23083/res/clara_%Y%m.log")
|
||||
LOG_FILENAME = time.strftime("/sf/cristallina/data/p23523/res/clara_%Y%m.log")
|
||||
|
||||
|
||||
logger.add(LOG_FILENAME, level="INFO", rotation="100MB")
|
||||
@@ -72,54 +73,71 @@ def to_json(obj):
|
||||
"""
|
||||
return json.dumps(obj, default=lambda obj: obj.__dict__, indent=4)
|
||||
|
||||
|
||||
def wait_for_dataset(h5file, dataset_path, timeout=60, check_interval=0.1):
|
||||
def wait_for_dataset(
|
||||
filepath,
|
||||
dataset_path,
|
||||
timeout=60,
|
||||
check_interval=0.1
|
||||
):
|
||||
"""
|
||||
Wait until an HDF5 dataset exists and contains data.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
h5file : h5py.File
|
||||
Open HDF5 file handle
|
||||
dataset_path : str
|
||||
Path to dataset inside HDF5 file
|
||||
timeout : float
|
||||
Max wait time in seconds
|
||||
check_interval : float
|
||||
Time between checks in seconds
|
||||
|
||||
Wait until an HDF5 dataset becomes readable.
|
||||
|
||||
Handles:
|
||||
- incomplete HDF5 metadata
|
||||
- delayed writer flushes
|
||||
- unstable object headers
|
||||
- live DAQ writing
|
||||
|
||||
Returns
|
||||
-------
|
||||
dataset
|
||||
The HDF5 dataset object
|
||||
|
||||
Raises
|
||||
------
|
||||
TimeoutError
|
||||
If dataset does not become available in time
|
||||
np.ndarray
|
||||
Dataset contents
|
||||
"""
|
||||
|
||||
|
||||
start = time.time()
|
||||
attempt = 0
|
||||
|
||||
while True:
|
||||
try:
|
||||
if dataset_path in h5file:
|
||||
ds = h5file[dataset_path]
|
||||
|
||||
# Optional: ensure dataset is populated
|
||||
if ds.shape[0] > 0:
|
||||
return ds
|
||||
h5file = None
|
||||
|
||||
try:
|
||||
|
||||
h5file = h5py.File(filepath, "r")
|
||||
|
||||
data = h5file[dataset_path][:]
|
||||
|
||||
h5file.close()
|
||||
|
||||
return data
|
||||
|
||||
except Exception as e:
|
||||
logger.info(f"Waiting for dataset {dataset_path}: {e}")
|
||||
|
||||
attempt += 1
|
||||
|
||||
if attempt % 100 == 0:
|
||||
|
||||
logger.info(
|
||||
f"Still waiting for dataset "
|
||||
f"{dataset_path} "
|
||||
f"in {filepath}: {e}"
|
||||
)
|
||||
|
||||
try:
|
||||
h5file.close()
|
||||
except:
|
||||
pass
|
||||
|
||||
if time.time() - start > timeout:
|
||||
|
||||
raise TimeoutError(
|
||||
f"Timeout waiting for dataset {dataset_path}"
|
||||
f"Timeout waiting for dataset "
|
||||
f"{dataset_path}"
|
||||
)
|
||||
|
||||
time.sleep(check_interval)
|
||||
|
||||
|
||||
# --------class with functions-----
|
||||
|
||||
|
||||
@@ -443,202 +461,340 @@ class CollectedH5:
|
||||
|
||||
return output_file_path
|
||||
|
||||
def find_matching_bsdata(self, pulseids_JF, data_dir):
|
||||
"""
|
||||
Search all BSDATA files and find pulse ID matches
|
||||
with the current Jungfrau acquisition.
|
||||
"""
|
||||
|
||||
matched_results = []
|
||||
|
||||
bsdata_files = sorted(
|
||||
glob.glob(
|
||||
os.path.join(data_dir, "acq*.BSDATA.h5")
|
||||
)
|
||||
)
|
||||
|
||||
logger.info(
|
||||
f"Searching {len(bsdata_files)} BSDATA files"
|
||||
)
|
||||
|
||||
for bsfile in bsdata_files:
|
||||
|
||||
logger.info(f"Checking BSDATA file: {bsfile}")
|
||||
|
||||
try:
|
||||
|
||||
bsdata = h5py.File(bsfile, "r")
|
||||
|
||||
pulseids_BS = wait_for_dataset(
|
||||
bsdata,
|
||||
"/SAR-CVME-TIFALL6:EvtSet/pulse_id",
|
||||
timeout=60,
|
||||
check_interval=0.1
|
||||
)[:]
|
||||
|
||||
evt_set = wait_for_dataset(
|
||||
bsdata,
|
||||
"/SAR-CVME-TIFALL6:EvtSet/data",
|
||||
timeout=60,
|
||||
check_interval=0.1
|
||||
)[:]
|
||||
|
||||
inters, ind_JF, ind_BS = np.intersect1d(
|
||||
pulseids_JF,
|
||||
pulseids_BS,
|
||||
return_indices=True
|
||||
)
|
||||
|
||||
logger.info(
|
||||
f"{os.path.basename(bsfile)} "
|
||||
f"matched {len(inters)} pulse IDs"
|
||||
)
|
||||
|
||||
if len(inters) > 0:
|
||||
|
||||
matched_results.append(
|
||||
(
|
||||
evt_set,
|
||||
ind_JF,
|
||||
ind_BS,
|
||||
bsfile
|
||||
)
|
||||
)
|
||||
|
||||
bsdata.close()
|
||||
|
||||
except Exception as e:
|
||||
|
||||
logger.info(
|
||||
f"Could not process BSDATA file "
|
||||
f"{bsfile}: {e}"
|
||||
)
|
||||
|
||||
logger.info(
|
||||
f"Found {len(matched_results)} "
|
||||
f"matching BSDATA files"
|
||||
)
|
||||
|
||||
return matched_results
|
||||
|
||||
def create_list_file(self):
|
||||
"""
|
||||
Function to generate a list file with the path of the input H5 file
|
||||
:return:None
|
||||
"""
|
||||
|
||||
import glob
|
||||
|
||||
print('writing list files')
|
||||
#Assemble path for raw data
|
||||
|
||||
# Assemble path for raw data
|
||||
pgroup = str(self.message["experiment_group"])
|
||||
raw = "raw"
|
||||
data = "data"
|
||||
filen = str(self.message["filename"])
|
||||
|
||||
file_path = slash / filen
|
||||
|
||||
# write to cell file in output folder
|
||||
run_number = self.message["run_number"]
|
||||
acq_number = self.message["file_number"]
|
||||
|
||||
name = f'run{run_number:04}_acq{acq_number:04}'
|
||||
|
||||
#f = open(name + ".list", "w")
|
||||
#f.write(str(file_path))
|
||||
#f.close()
|
||||
bsdata_name = Path(filen[:-15]+'.BSDATA.h5')
|
||||
jf_path = file_path
|
||||
|
||||
bsdata_path = slash / bsdata_name
|
||||
|
||||
logger.info("Waiting for bs_data to exist")
|
||||
start_t = time.time()
|
||||
|
||||
while not bsdata_path.exists():
|
||||
current_t = time.time()
|
||||
elapsed_t = current_t-start_t
|
||||
|
||||
if elapsed_t > 600:
|
||||
print("Wait for BSdata exceeds 10 minutes. Exiting loop")
|
||||
break
|
||||
|
||||
time.sleep(1)
|
||||
|
||||
try:
|
||||
time.sleep(10)
|
||||
#bsdata = SFDataFiles(bsdata_path)
|
||||
bsdata = h5py.File(bsdata_path, "r") #r"/sf/cristallina/data/p21630/raw/run0065-lov_movestop_normal_1/data/acq0001.BSDATA.h5"
|
||||
except Exception as e:
|
||||
print(f"didn't open bsdata due to error {e}") #_logger.error(f"Cannot open {data_file} (due to {e})")
|
||||
return
|
||||
|
||||
pulseids_BS = wait_for_dataset(
|
||||
bsdata,
|
||||
"/SAR-CVME-TIFALL6:EvtSet/pulse_id",
|
||||
timeout=600,
|
||||
check_interval=0.1
|
||||
)[:]
|
||||
|
||||
evt_set = wait_for_dataset(
|
||||
bsdata,
|
||||
"/SAR-CVME-TIFALL6:EvtSet/data",
|
||||
timeout=600,
|
||||
check_interval=0.1
|
||||
)[:]
|
||||
|
||||
jf_path= file_path
|
||||
master_path = slash / Path(filen[:-19]+'_master.h5')
|
||||
master_path = slash / Path(filen[:-19] + '_master.h5')
|
||||
print(master_path)
|
||||
file_exists = os.path.exists(master_path)
|
||||
st = time.perf_counter()
|
||||
while not file_exists:
|
||||
time.sleep(1)
|
||||
file_exists = os.path.exists(master_path)
|
||||
if time.perf_counter()-st > 1800:
|
||||
print('Wait for acq master exceeded 30 minutes!!!')
|
||||
break
|
||||
time.sleep(1)
|
||||
file_exists = os.path.exists(master_path)
|
||||
if time.perf_counter() - st > 1800:
|
||||
print('Wait for acq master exceeded 30 minutes!!!')
|
||||
break
|
||||
|
||||
try:
|
||||
|
||||
try:
|
||||
print(f"JF file path = {jf_path}, file_path = {file_path}")
|
||||
|
||||
print(os.path.exists(jf_path))
|
||||
x = h5py.File(jf_path, "r")
|
||||
#data = SFDataFiles(bsdata_path, jf_path)
|
||||
|
||||
pulseids_JF = wait_for_dataset(
|
||||
jf_path,
|
||||
"/entry/xfel/pulseID",
|
||||
timeout=600,
|
||||
check_interval=0.1
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
print(f"didn't open {jf_path} due to error {e}") #_logger.error(f"Cannot open {data_file} (due to {e})")
|
||||
|
||||
print(f"didn't open {jf_path} due to error {e}")
|
||||
|
||||
return
|
||||
pulseids_JF = wait_for_dataset(
|
||||
x,
|
||||
"/entry/xfel/pulseID",
|
||||
timeout=600,
|
||||
check_interval=0.1
|
||||
)[:]
|
||||
|
||||
n_pulse_id = len(pulseids_JF) #- maybe not needed ?
|
||||
|
||||
index_dark = []
|
||||
index_light = []
|
||||
blanks = []
|
||||
#print(evt_set)
|
||||
index_dark = set()
|
||||
index_light = set()
|
||||
blanks = set()
|
||||
|
||||
_inters, ind_JF, ind_BS = np.intersect1d(pulseids_JF, pulseids_BS, return_indices=True)
|
||||
#evt_set = evt_set[ind_BS]
|
||||
#print(len(evt_set))
|
||||
|
||||
#print(min(ind_BS),max(ind_BS),len(ind_BS))
|
||||
# -----------------------------------------------------------------
|
||||
# Wait for expected BSDATA file for this acquisition
|
||||
# -----------------------------------------------------------------
|
||||
|
||||
for idx_JF, idx_BS in zip(ind_JF, ind_BS):
|
||||
events = evt_set[idx_BS]
|
||||
|
||||
trigger_event = int(self.message["user_data"]["trigger_event"])
|
||||
data_dir = os.path.dirname(str(file_path))
|
||||
|
||||
if trigger_event == 63:
|
||||
|
||||
if events[trigger_event] and events[200]:
|
||||
index_dark.append(idx_JF)
|
||||
bsdata_name = Path(
|
||||
filen[:-15] + '.BSDATA.h5'
|
||||
)
|
||||
|
||||
elif events[200]:
|
||||
index_light.append(idx_JF)
|
||||
bsdata_path = slash / bsdata_name
|
||||
|
||||
else:
|
||||
blanks.append(idx_JF)
|
||||
logger.info(
|
||||
f"Waiting for BSDATA file: {bsdata_path}"
|
||||
)
|
||||
|
||||
else:
|
||||
start_t = time.time()
|
||||
|
||||
if events[trigger_event] and events[200]:
|
||||
index_light.append(idx_JF)
|
||||
while not bsdata_path.exists():
|
||||
|
||||
elif events[200]:
|
||||
index_dark.append(idx_JF)
|
||||
elapsed_t = time.time() - start_t
|
||||
|
||||
else:
|
||||
blanks.append(idx_JF)
|
||||
if elapsed_t > 600:
|
||||
|
||||
logger.info(
|
||||
"Wait for BSDATA exceeded 10 minutes"
|
||||
)
|
||||
|
||||
#for i in range(n_pulse_id):
|
||||
break
|
||||
|
||||
# p = pulseids_JF[i]
|
||||
# q = pulseids_BS[i]
|
||||
# if p != q:
|
||||
# #event_i = np.where(pulseids_JF == q)[0] for normal detector
|
||||
# event_i = np.where(pulseids_BS == p)[0][0]#[::2] #[0][0]
|
||||
# #event_i = i
|
||||
# else:
|
||||
# event_i=i#
|
||||
time.sleep(0.1)
|
||||
|
||||
# events=evt_set[event_i]
|
||||
#print(events)
|
||||
#print(len(events))
|
||||
#print(event_i)
|
||||
#print(p,q)
|
||||
#print(i)
|
||||
logger.info(
|
||||
"Expected BSDATA file appeared"
|
||||
)
|
||||
|
||||
# trigger_event = int(self.message["user_data"]["trigger_event"])
|
||||
# -----------------------------------------------------------------
|
||||
# Search ALL BSDATA files for matching pulse IDs
|
||||
# -----------------------------------------------------------------
|
||||
|
||||
# if self.message["user_data"]["trigger_flag"]:
|
||||
# if events[trigger_event] and events[200]:
|
||||
# index_light.append(i)
|
||||
bsdata_files = sorted(
|
||||
glob.glob(
|
||||
os.path.join(data_dir, "acq*.BSDATA.h5")
|
||||
)
|
||||
)
|
||||
|
||||
# elif events[200]:
|
||||
# index_dark.append(i)
|
||||
logger.info(
|
||||
f"Found {len(bsdata_files)} BSDATA files"
|
||||
)
|
||||
|
||||
# else:
|
||||
# blanks.append(i)
|
||||
for bsfile in bsdata_files:
|
||||
|
||||
logger.info(f"Checking BSDATA file: {bsfile}")
|
||||
|
||||
try:
|
||||
|
||||
pulseids_BS = wait_for_dataset(
|
||||
bsfile,
|
||||
"/SAR-CVME-TIFALL6:EvtSet/pulse_id",
|
||||
timeout=30,
|
||||
check_interval=0.1
|
||||
)[:]
|
||||
|
||||
evt_set = wait_for_dataset(
|
||||
bsfile,
|
||||
"/SAR-CVME-TIFALL6:EvtSet/data",
|
||||
timeout=30,
|
||||
check_interval=0.1
|
||||
)[:]
|
||||
|
||||
# ---------------------------------------------------------
|
||||
# Match pulse IDs
|
||||
# ---------------------------------------------------------
|
||||
|
||||
inters, ind_JF, ind_BS = np.intersect1d(
|
||||
pulseids_JF,
|
||||
pulseids_BS,
|
||||
return_indices=True
|
||||
)
|
||||
|
||||
logger.info(
|
||||
f"{os.path.basename(bsfile)} "
|
||||
f"matched {len(inters)} pulse IDs"
|
||||
)
|
||||
|
||||
trigger_event = int(
|
||||
self.message["user_data"]["trigger_event"]
|
||||
)
|
||||
|
||||
# ---------------------------------------------------------
|
||||
# Sort light / dark / blank
|
||||
# ---------------------------------------------------------
|
||||
|
||||
for idx_JF, idx_BS in zip(ind_JF, ind_BS):
|
||||
|
||||
events = evt_set[idx_BS]
|
||||
|
||||
if trigger_event == 63:
|
||||
|
||||
if events[trigger_event] and events[200]:
|
||||
|
||||
index_dark.add(idx_JF)
|
||||
|
||||
elif events[200]:
|
||||
|
||||
index_light.add(idx_JF)
|
||||
|
||||
else:
|
||||
|
||||
blanks.add(idx_JF)
|
||||
|
||||
else:
|
||||
|
||||
if events[trigger_event] and events[200]:
|
||||
|
||||
index_light.add(idx_JF)
|
||||
|
||||
elif events[200]:
|
||||
|
||||
index_dark.add(idx_JF)
|
||||
|
||||
else:
|
||||
|
||||
blanks.add(idx_JF)
|
||||
|
||||
except Exception as e:
|
||||
|
||||
logger.info(
|
||||
f"Could not process BSDATA file "
|
||||
f"{bsfile}: {e}"
|
||||
)
|
||||
|
||||
bsdata.close()
|
||||
x.close()
|
||||
|
||||
acq_dark = []
|
||||
acq_light = []
|
||||
acq_blank = []
|
||||
acq_blank = []
|
||||
|
||||
delim = "//"
|
||||
|
||||
|
||||
if index_dark:
|
||||
for frame_number in index_dark:
|
||||
acq_dark.append(f"{jf_path} {delim}{frame_number}")
|
||||
|
||||
file_off = name+'_off.list'
|
||||
|
||||
logger.info(f"List of dark frames : {file_off} , {len(index_dark)} frames")
|
||||
|
||||
|
||||
for frame_number in sorted(index_dark):
|
||||
|
||||
acq_dark.append(
|
||||
f"{jf_path} {delim}{frame_number}"
|
||||
)
|
||||
|
||||
file_off = name + '_off.list'
|
||||
|
||||
logger.info(
|
||||
f"List of dark frames : "
|
||||
f"{file_off} , {len(index_dark)} frames"
|
||||
)
|
||||
|
||||
with open(file_off, "w") as f_list:
|
||||
|
||||
for frame in acq_dark:
|
||||
print(f"{frame}", file = f_list)
|
||||
|
||||
print(f"{frame}", file=f_list)
|
||||
|
||||
if index_light:
|
||||
for frame_number in index_light:
|
||||
acq_light.append(f"{jf_path} {delim}{frame_number}")
|
||||
file_on = name+'_on.list'
|
||||
logger.info(f"List of light frames : {file_on} , {len(index_light)} frames")
|
||||
|
||||
for frame_number in sorted(index_light):
|
||||
|
||||
acq_light.append(
|
||||
f"{jf_path} {delim}{frame_number}"
|
||||
)
|
||||
|
||||
file_on = name + '_on.list'
|
||||
|
||||
logger.info(
|
||||
f"List of light frames : "
|
||||
f"{file_on} , {len(index_light)} frames"
|
||||
)
|
||||
|
||||
with open(file_on, "w") as f_list:
|
||||
|
||||
for frame in acq_light:
|
||||
print(f"{frame}", file = f_list)
|
||||
|
||||
print(f"{frame}", file=f_list)
|
||||
|
||||
if blanks:
|
||||
for frame_number in blanks:
|
||||
acq_blank.append(f"{jf_path} {delim}{frame_number}")
|
||||
file_blank = name+'_blank.list'
|
||||
with open(file_blank, "w") as f_list:
|
||||
for frame in acq_blank:
|
||||
print(f"{frame}", file = f_list)
|
||||
|
||||
|
||||
for frame_number in sorted(blanks):
|
||||
|
||||
acq_blank.append(
|
||||
f"{jf_path} {delim}{frame_number}"
|
||||
)
|
||||
|
||||
file_blank = name + '_blank.list'
|
||||
|
||||
with open(file_blank, "w") as f_list:
|
||||
|
||||
for frame in acq_blank:
|
||||
|
||||
print(f"{frame}", file=f_list)
|
||||
|
||||
return None
|
||||
|
||||
def create_slurm_script(self,trigger, geometry_file_path):
|
||||
@@ -766,12 +922,25 @@ class CollectedH5:
|
||||
# sub.run(["sbatch", "run_SLURM"])
|
||||
|
||||
try:
|
||||
slurm_out = sub.run(["sbatch", "run_SLURM_" + trigger ], capture_output=True)
|
||||
time.sleep(1)
|
||||
txt = slurm_out.stdout.decode().split()
|
||||
# grep the slurm number
|
||||
slurm_out = sub.run(
|
||||
["sbatch", "run_SLURM_" + trigger],
|
||||
capture_output=True,
|
||||
text=True
|
||||
)
|
||||
|
||||
logger.info(f"sbatch stdout: {slurm_out.stdout}")
|
||||
logger.info(f"sbatch stderr: {slurm_out.stderr}")
|
||||
|
||||
txt = slurm_out.stdout.split()
|
||||
|
||||
if len(txt) == 0:
|
||||
raise RuntimeError(
|
||||
f"sbatch returned empty stdout. stderr={slurm_out.stderr}"
|
||||
)
|
||||
|
||||
logger.info(f"submitted batch job number: {txt[-1]}")
|
||||
self.message["SlurmJobID_" + trigger] = str(txt[-1])
|
||||
|
||||
except Exception as e:
|
||||
logger.info("Could not submit SLURM job: {}".format(e))
|
||||
|
||||
@@ -855,7 +1024,8 @@ if __name__ == "__main__":
|
||||
context = zmq.Context()
|
||||
subscriber = context.socket(zmq.SUB)
|
||||
#subscriber.connect("tcp://sf-broker-01.psi.ch:5555")
|
||||
subscriber.connect("tcp://sf-daqtest-01.psi.ch:5401")
|
||||
#subscriber.connect("tcp://sf-daqtest-01.psi.ch:5401")
|
||||
subscriber.connect("tcp://sf-daq-2.psi.ch:5401")
|
||||
subscriber.setsockopt_string(zmq.SUBSCRIBE, "")
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user