diff --git a/psi_device.py b/psi_device.py index d9621b5..5c7ee43 100644 --- a/psi_device.py +++ b/psi_device.py @@ -125,11 +125,16 @@ class Jungfrau: self._pv_pulse_id.connect() except NameError as e: _log.critical(f'Jungfrau not connected: {e}') + self.n_pulses_run = None - self.bsdata_scalar = 1 + + self.image_pulse_mask = None + self.images_per_cycle = None + self.pulses_per_cycle = None + self.motion_mode = None - self.block_size_to_jungfrau = 1000 - self.block_size_to_slic = 1000 + + self.block_size_to_slic = None def config(self,**kwargs): if getattr(self,'_sim',False): @@ -149,13 +154,18 @@ class Jungfrau: sync_mode=dt_misc['sync_mode'] sync_flag=dt_misc['sync_flag'] self.n_pulses_run = None + self.image_pulse_mask = None + self.images_per_cycle = None + self.pulses_per_cycle = None + self.block_size_to_slic = None + self.block_size_to_jungfrau = None #print(kwargs) motion_mode = kwargs['mode'] self.motion_mode = motion_mode + if loc['jungfraujoch']: try: - #self.jfj = JFJ("http://sf-daq-2:5232") old port - self.jfj = JFJ("http://sf-daq-2:8080") #new port + self.jfj = JFJ("http://sf-daq-2:8080") self.detectors=None _log.info(f'JungFrauJoch connected') print('JungFrauJoch connected') @@ -163,12 +173,8 @@ class Jungfrau: self.jfj = None _log.critical(f'JungfrauJoch not connected: {e}') is_scan_step=False - else: - self.jfj = None - _log.info(f'JungFrauJoch is not in use') - print('JungFrauJoch not in use') -# # no JFJ block +# JFJ comment block # if loc['jungfraujoch']: # self.jfj = None # self.detectors = None @@ -178,7 +184,7 @@ class Jungfrau: # self.jfj = None # _log.info(f'JungFrauJoch is not in use') # print('JungFrauJoch not in use') -# # no JFJ block +# JFJ comment block #if sync_flag==0: if motion_mode == 1 or motion_mode == 3: @@ -226,7 +232,7 @@ class Jungfrau: cta.seq[216] = no_trigger_sequence * cta_multiplier # x-ray_shutter # image label (on or off)1 cta.seq[219] = xray_sequence * cta_multiplier # detector trigger self.n_pulses_run = len(cta.seq[200])*repetitions - self.bsdata_scalar = self.n_pulses_run/number_of_appertures + #print(on_off_ratio,cta_multiplier,int(cta_multiplier/on_off_ratio),len(cta.seq[200]),len(cta.seq[214]),len(cta.seq[215]),len(cta.seq[216]),len(cta.seq[219])) #self.motion_mode = 5 elif motion_mode==6: @@ -261,99 +267,348 @@ class Jungfrau: cta.seq[215] = [0] * apperture_group_size * 2 + [0,] * (transition_pulses - 1) # trigger (laser_shutter or droplet ejector) cta.seq[216] = [0] * apperture_group_size * 2 + [0,] * (transition_pulses -1) # image label (on or off)1 cta.seq[219] = xray_sequence # detector trigger - self.n_pulses_run = len(cta.seq[200])*number_of_apperture_groups cta.cfg.repetitions = number_of_apperture_groups # number of repeitions is now number of times we repeat the loop self.images=number_of_apperture_groups*apperture_group_size - #self.bsdata_scalar = self.n_pulses_run/number_of_appertures - data_collection_block_scaler = max(1, int(1000/apperture_group_size)) - self.block_size_to_jungfrau = data_collection_block_scaler*apperture_group_size - self.block_size_to_slic = data_collection_block_scaler*len(cta.seq[200]) print(f"length of sequence = {len(cta.seq[200])}") print(f"apperture in group = {apperture_group_size}") print(f"number_of_apperture_groups = {number_of_apperture_groups}") #print(f"n_pulses = {self.n_pulses_run} and n_appertures and images = {number_of_appertures}") - #print(f"so a scalar of {self.bsdata_scalar}") - print(f"using a data_collection_block_scaler of {data_collection_block_scaler}") - print(f"block_size for slic {self.block_size_to_slic}") - print(f"block size for jungfrau {self.block_size_to_jungfrau}") - elif motion_mode==7: print("mode 7 selected - stop-go-and-return") ssz = kwargs['ssz'] +# if ssz[1] > 2: +# raise(ValueError(f"mode 7 row mode only supports y block size <= 2 (got {ssz[1]})")) if kwargs['tmove']==0: wait_pulses=0 else: wait_pulses=kwargs['twait']//kwargs['tmove'] + + if ssz[0]==2 and ssz[1]>1: + print("running super-row block") + + apperture_group_size=ssz[0]*ssz[1] + + number_of_sub_blocks=repetitions//ssz[0] + + number_of_super_blocks=cta_multiplier//ssz[1] + + startup_sequence=[0,0] + + sub_block_transition_pulses=ssz[0]-1 + + super_block_transition_pulses=ssz[1]-4 + + aperture_sequence=[0,]*wait_pulses+[1,] + + droplet_sequence=([1,]+[0,]*wait_pulses)*(on_off_ratio-1) + + no_droplet_sequence=([0,]+[0,]*wait_pulses) + + xray_return_sequence=aperture_sequence*apperture_group_size + + xray_dark_sequence=[0,]*len(xray_return_sequence) + + trigger_dark_sequence=(droplet_sequence+no_droplet_sequence)*(apperture_group_size//on_off_ratio) + + trigger_return_sequence=[0,]*len(xray_return_sequence) + + image_dark_sequence=[0,]*len(xray_return_sequence) + + image_on_sequence=([0,]*wait_pulses+[1,])*(on_off_ratio-1) + + image_off_sequence=([0,]*wait_pulses+[0,]) + + image_return_sequence=(image_on_sequence+image_off_sequence)*(apperture_group_size//on_off_ratio) + + sub_block_transition_sequence=[0,]*(sub_block_transition_pulses-1) + + super_block_transition_sequence=[0,]*super_block_transition_pulses + + sub_block_xray_sequence=( + xray_dark_sequence+ + xray_return_sequence+ + sub_block_transition_sequence + ) + + sub_block_trigger_sequence=( + trigger_dark_sequence+ + trigger_return_sequence+ + sub_block_transition_sequence + ) + + sub_block_image_sequence=( + image_dark_sequence+ + image_return_sequence+ + sub_block_transition_sequence + ) + + forward_super_block_xray_sequence=( + sub_block_xray_sequence*number_of_sub_blocks+ + super_block_transition_sequence + ) + + forward_super_block_trigger_sequence=( + sub_block_trigger_sequence*number_of_sub_blocks+ + super_block_transition_sequence + ) + + forward_super_block_image_sequence=( + sub_block_image_sequence*number_of_sub_blocks+ + super_block_transition_sequence + ) + + cta.seq[200]=( + startup_sequence+ + forward_super_block_xray_sequence+ + forward_super_block_xray_sequence + ) + + cta.seq[215]=( + startup_sequence+ + forward_super_block_trigger_sequence+ + forward_super_block_trigger_sequence + ) + + cta.seq[216]=( + startup_sequence+ + forward_super_block_image_sequence+ + forward_super_block_image_sequence + ) + + cta.seq[219]=cta.seq[200] + + cta.seq[214]=[1,]+[0,]*(len(cta.seq[200])-1) + + print(f"cta sequence length = {len(cta.seq[200])}") + print(f"cta sequence parity = {len(cta.seq[200])%2}") + + cta.cfg.repetitions=number_of_super_blocks//2 + + self.images=number_of_sub_blocks*number_of_super_blocks*apperture_group_size + + print(f"length of sequence = {len(cta.seq[200])}") + print(f"apperture in group = {apperture_group_size}") + print(f"number_of_sub_blocks = {number_of_sub_blocks}") + print(f"number_of_super_blocks = {number_of_super_blocks}") + print(f"sub_block_transition_pulses = {sub_block_transition_pulses}") + print(f"super_block_transition_pulses = {super_block_transition_pulses}") + print(f"wait_pulses = {wait_pulses}") + print(f"n_pulses_run = {self.n_pulses_run}") +# print(f"using a data_collection_block_scaler of {data_collection_block_scaler}") + print(f"block_size for slic {self.block_size_to_slic}") + print(f"block size for jungfrau {self.block_size_to_jungfrau}") if ssz[1]==grid_cnt[1]: print("running column code block") - apperture_group_size = ssz[0] * ssz[1] + apperture_group_size=ssz[0]*ssz[1] number_of_apperture_groups=(repetitions//ssz[0])*(cta_multiplier//ssz[1]) print(f"number_of_apperture_groups = {number_of_apperture_groups}") - aperture_sequence = [0,] * wait_pulses + [1,] - xray_on_sequence = aperture_sequence * apperture_group_size - xray_off_sequence = ([0,] * (wait_pulses + 1)) * apperture_group_size - xray_sequence = xray_off_sequence + xray_on_sequence - cta.seq[200] = xray_sequence - cta.seq[214] = [1,] + [0,] * (len(xray_sequence) - 1) + transition_pulses=ssz[0]-2 + startup_sequence=[0,0] + aperture_sequence=[0,]*wait_pulses+[1,] + xray_on_sequence=aperture_sequence*apperture_group_size + xray_off_sequence=([0,]*(wait_pulses+1))*apperture_group_size + transition_sequence=[0,]*transition_pulses + xray_sequence=xray_off_sequence+xray_on_sequence+transition_sequence + cta.seq[200]=startup_sequence+xray_sequence + cta.seq[214]=[1,]+[0,]*(len(cta.seq[200])-1) + if run["triggered"]: - if on_off_ratio > apperture_group_size: - on_off_ratio = apperture_group_size - trigger_on = ([1,] + [0,] * wait_pulses) * (on_off_ratio - 1) - trigger_off = ([0,] + [0,] * wait_pulses) - trigger_aperture_sequence = (trigger_on + trigger_off) * (apperture_group_size // on_off_ratio) - trigger_return_sequence = [0,] * ((wait_pulses + 1) * apperture_group_size) - cta.seq[215] = trigger_aperture_sequence + trigger_return_sequence - image_off_sequence = [0,] * ((wait_pulses + 1) * apperture_group_size) - image_on = ([0,] * wait_pulses + [1,]) * (on_off_ratio - 1) - image_off = ([0,] * wait_pulses + [0,]) - image_return_sequence = (image_on + image_off) * (apperture_group_size // on_off_ratio) - cta.seq[216] = image_off_sequence + image_return_sequence + + if on_off_ratio>apperture_group_size: + on_off_ratio=apperture_group_size + + trigger_on=([1,]+[0,]*wait_pulses)*(on_off_ratio-1) + trigger_off=([0,]+[0,]*wait_pulses) + trigger_aperture_sequence=(trigger_on+trigger_off)*(apperture_group_size//on_off_ratio) + trigger_return_sequence=[0,]*((wait_pulses+1)*apperture_group_size) + trigger_transition_sequence=[0,]*transition_pulses + cta.seq[215]=startup_sequence+trigger_aperture_sequence+trigger_return_sequence+trigger_transition_sequence + image_off_sequence=[0,]*((wait_pulses+1)*apperture_group_size) + image_on=([0,]*wait_pulses+[1,])*(on_off_ratio-1) + image_off=([0,]*wait_pulses+[0,]) + image_return_sequence=(image_on+image_off)*(apperture_group_size//on_off_ratio) + image_transition_sequence=[0,]*transition_pulses + cta.seq[216]=startup_sequence+image_off_sequence+image_return_sequence+image_transition_sequence else: - no_trigger_sequence = [0,] * len(xray_sequence) - cta.seq[215] = no_trigger_sequence - cta.seq[216] = no_trigger_sequence + no_trigger_sequence=[0,]*len(xray_sequence) + cta.seq[215]=no_trigger_sequence + cta.seq[216]=no_trigger_sequence - cta.seq[219] = xray_sequence - self.n_pulses_run = len(cta.seq[200]) * number_of_apperture_groups - cta.cfg.repetitions = number_of_apperture_groups - self.images = number_of_apperture_groups * apperture_group_size - self.bsdata_scalar = self.n_pulses_run / number_of_appertures - data_collection_block_scaler = max(1, round(1000/apperture_group_size)) - self.block_size_to_jungfrau = data_collection_block_scaler * apperture_group_size - self.block_size_to_slic = data_collection_block_scaler * len(cta.seq[200]) + cta.seq[219]=cta.seq[200] + cta.cfg.repetitions=number_of_apperture_groups + self.images=number_of_apperture_groups*apperture_group_size print(f"length of sequence = {len(cta.seq[200])}") print(f"apperture in group = {apperture_group_size}") print(f"number_of_apperture_groups = {number_of_apperture_groups}") + print(f"transition_pulses = {transition_pulses}") print(f"wait_pulses = {wait_pulses}") print(f"n_pulses_run = {self.n_pulses_run}") - print(f"using a data_collection_block_scaler of {data_collection_block_scaler}") - print(f"block_size for slic {self.block_size_to_slic}") - print(f"block size for jungfrau {self.block_size_to_jungfrau}") else: _log.info('not mode 5 or 6') #need to add on off ratio # no extra rows 1:1 #self.motion_mode = 4 - cta.seq[214]=[1,]+[0,]*(cta_multiplier-1) #start motion cta.seq[200]=[1,]*cta_multiplier #uncomment me for normal operation #cta.seq[200]=[1,0,]*(cta_multiplier//2) # x-ray_shutter cta.seq[219]=[1,]*cta_multiplier #trigger detector if run["triggered"]: #cta.seq[215]=[1,0,]*(cta_multiplier//2) # Trigger 1:1 + _log.info('Oi John, you left the light on! From Martin') cta.seq[215]=[1,]*cta_multiplier # shutter always open + _log.info('event 215 is on for every pulse in mode 4, and 216 is assuming light:dark is 1:1') cta.seq[216]=[1,0,]*(cta_multiplier//2) # Label image light dark 1:1 #change back to 1,0 for normal on off measurements self.n_pulses_run = len(cta.seq[200])*repetitions - self.bsdata_scalar=1 cta.seq.upload() + + try: + + # -------------------------------------------------------- + # detector exposure topology + # -------------------------------------------------------- + + self.image_pulse_mask = [ + int(x) == 1 for x in cta.seq[219] + ] + + self.images_per_cycle = sum( + self.image_pulse_mask + ) + + self.pulses_per_cycle = len( + self.image_pulse_mask + ) + + if self.images_per_cycle == 0: + + raise ValueError( + "No detector images found in cta.seq[219]" + ) + + jf_block_size = run['block_size'] + + # -------------------------------------------------------- + # total dataset pulse count + # -------------------------------------------------------- + + total_required_cycles = ceil( + self.images / self.images_per_cycle + ) + + total_required_pulses = ( + total_required_cycles * + self.pulses_per_cycle + ) + + self.n_pulses_run = ( + total_required_pulses + ) + # TEMP HARD FIX FOR MODE 7 + if motion_mode == 7: + self.n_pulses_run *= 2 + + # -------------------------------------------------------- + # MODE 4 + # + # continuous acquisition + # 1 pulse = 1 image + # -------------------------------------------------------- + + if motion_mode == 4: + + self.block_size_to_slic = ( + jf_block_size + ) + + # -------------------------------------------------------- + # small sparse acquisition + # + # whole dataset fits in one file + # -------------------------------------------------------- + + elif self.images <= jf_block_size: + + self.block_size_to_slic = ( + total_required_pulses + ) + # TEMP HARD FIX FOR MODE 7 + if motion_mode == 7: + self.block_size_to_slic *= 2 + + # -------------------------------------------------------- + # large sparse acquisition + # -------------------------------------------------------- + + else: + + cycles_per_jfj_block = ceil( + jf_block_size / + self.images_per_cycle + ) + + self.block_size_to_slic = ( + cycles_per_jfj_block * + self.pulses_per_cycle + ) + + print( + f"motion_mode = {motion_mode}" + ) + + print( + f"images = {self.images}" + ) + + print( + f"images_per_cycle = " + f"{self.images_per_cycle}" + ) + + print( + f"pulses_per_cycle = " + f"{self.pulses_per_cycle}" + ) + + print( + f"total_required_cycles = " + f"{total_required_cycles}" + ) + + print( + f"total_required_pulses = " + f"{total_required_pulses}" + ) + + print( + f"n_pulses_run = " + f"{self.n_pulses_run}" + ) + + print( + f"block_size_to_slic = " + f"{self.block_size_to_slic}" + ) + + except Exception as e: + + _log.warning( + f'failed to build pulse/image mapping: {e}' + ) + + self.image_pulse_mask = None + self.images_per_cycle = None + self.pulses_per_cycle = None + + self.block_size_to_slic = None + self._daq=CTAAcquisition(cta, loc['end_station'], loc['p_group'], default_detectors=detectors, default_channels=bs_channels, default_pvs=pv_channels, rate_multiplicator=1, append_user_tag_to_data_dir=True)#, timeout=30) @@ -431,31 +686,87 @@ class Jungfrau: header_appendix['trigger_event'] = trigger_event header_appendix['laser_pulse_energy'] = trigger_delay header_appendix['file_prefix'] = f'run{run_number:04}-{user_tag}' - if self.motion_mode == 6: - self.jfj.acquire(beam_x_pxl = loc['beam_x'], beam_y_pxl = loc['beam_y'], detector_distance_mm = detector_distance_mm, incident_energy_keV = loc['incident_energy_kev'], transmission = transmission, - sample_name = sample_name, run_number = run_number, file_prefix = jfj_file_prefix, experiment_group=pgroup, ntrigger = self.images, images_per_file = self.block_size_to_jungfrau, - unit_cell=unit_cell, space_group_number=daq_uc['space_group_number'], - header_appendix=header_appendix - ) - else: - self.jfj.acquire(beam_x_pxl = loc['beam_x'], beam_y_pxl = loc['beam_y'], detector_distance_mm = detector_distance_mm, incident_energy_keV = loc['incident_energy_kev'], transmission = transmission, - sample_name = sample_name, run_number = run_number, file_prefix = jfj_file_prefix, experiment_group=pgroup, ntrigger = self.images, images_per_file = images_per_file, - unit_cell=unit_cell, space_group_number=daq_uc['space_group_number'], - header_appendix=header_appendix - ) + try: + self.jfj.acquire( + beam_x_pxl = loc['beam_x'], + beam_y_pxl = loc['beam_y'], + detector_distance_mm = detector_distance_mm, + incident_energy_keV = loc['incident_energy_kev'], + transmission = transmission, + sample_name = sample_name, + run_number = run_number, + file_prefix = jfj_file_prefix, + experiment_group = pgroup, + ntrigger = self.images, + images_per_file = images_per_file, + unit_cell = unit_cell, + space_group_number = daq_uc['space_group_number'], + header_appendix = header_appendix + ) + except Exception as e: + + _log.warning('error in priming JFJoch continuing, if not debugging motion be warned JFJoch not on or an error') + _log.error(f'JFJoch exception rasied as: {e}') + _log.info('JFJ primed') else: is_scan_step=False - block_size = int(run['block_size']*self.bsdata_scalar) #scales block_size for bsdata acquisition only - #_log.info(f'The multiplier of the block size is {self.bsdata_scalar}, new block size is {block_size}') - print(f'The multiplier of the block size is {self.bsdata_scalar}, new block size is {block_size}') - if type(self._daq) is CTAAcquisition: - if self.motion_mode == 6: - self._daq.acquire(user_tag, n_pulses=max(n_pulses_run, self.block_size_to_slic), n_block_size=self.block_size_to_slic, wait=False, cell_name=run['cell_name'], is_scan_step=is_scan_step) - else: - self._daq.acquire(user_tag, n_pulses=max(n_pulses_run, block_size), n_block_size=block_size, wait=False, cell_name=run['cell_name'], is_scan_step=is_scan_step) + + if self.block_size_to_slic: + + block_size = self.block_size_to_slic + + print( + f'using exact pulse/image mapping: ' + f'block_size_to_slic = {block_size}' + ) + else: - self._daq.acquire(user_tag, n_pulses=max(n_pulses_run, block_size), n_repeat=ceil(n_pulses_run/block_size), wait=False, cell_name=run['cell_name'], is_scan_step=is_scan_step) + + block_size = run['block_size'] + + print(f'using simple block size = {block_size}') + + if type(self._daq) is CTAAcquisition: + + if self.block_size_to_slic: + + self._daq.acquire( + user_tag, + n_pulses=max( + n_pulses_run, + self.block_size_to_slic + ), + n_block_size=self.block_size_to_slic, + wait=False, + cell_name=run['cell_name'], + is_scan_step=is_scan_step + ) + + else: + + self._daq.acquire( + user_tag, + n_pulses=max( + n_pulses_run, + block_size + ), + n_block_size=block_size, + wait=False, + cell_name=run['cell_name'], + is_scan_step=is_scan_step + ) + + else: + + self._daq.acquire( + user_tag, + n_pulses=max(n_pulses_run, block_size), + n_repeat=ceil(n_pulses_run/block_size), + wait=False, cell_name=run['cell_name'], + is_scan_step=is_scan_step + ) + cfg.setValue(AppCfg.DAQ_RUN,run) is_scan_step=False