diff --git a/scripts/_LDRD_Kafka.py b/scripts/_LDRD_Kafka.py index 53ac759..387b8ea 100644 --- a/scripts/_LDRD_Kafka.py +++ b/scripts/_LDRD_Kafka.py @@ -4,6 +4,8 @@ import numpy as np import pandas as pd import importlib +import time +import pprint import _data_export as de from _plot_helper import plot_uvvis @@ -24,7 +26,7 @@ def _qserver_inputs(): qserver_list=[ 'zmq_control_addr', 'zmq_info_addr', - 'dummy_qserver', 'is_iteration', 'pos', + 'dummy_qserver', 'is_iteration', 'pos', 'use_OAm', 'name_by_prefix', 'prefix', 'pump_list', 'precursor_list', 'syringe_mater_list', 'syringe_list', 'target_vol_list', 'sample', @@ -142,6 +144,12 @@ def __init__(self, parameters_list, xlsx_fn, sheet_name='inputs', is_kafka=False pass + ## Reset attributes of keys in _kafka_process() to empty lists for next event + def reset_kafka_process(self): + for key in _kafka_process(): + setattr(self, key, []) + + def auto_rate_list(self, pump_list, new_points, fix_Br_ratio): """Auto transfer the predicted rates in new_points to a rate_list for qserver @@ -168,7 +176,7 @@ def auto_rate_list(self, pump_list, new_points, fix_Br_ratio): - def macro_agent(self, qserver_process, RM, check_target=False, use_OAm=False, is_1st=False): + def macro_agent(self, qserver_process, RM, check_target=False, is_1st=False): """macro to build agent, make optimization, and update agent_data This macro will @@ -185,6 +193,7 @@ def macro_agent(self, qserver_process, RM, check_target=False, use_OAm=False, is qserver_process (_LDRD_Kafka.xlsx_to_inputs, optional): qserver parameters read from xlsx. RM (REManagerAPI): Run Engine Manager API. check_target (bool, optional): Check if peak emission reaches peak target. Defaults to False. + is_ist (bool, optional): Check if it is the first precidciton. If yes, skip build agent. Returns: dict: new_points predicted by self.agent @@ -194,6 +203,27 @@ def macro_agent(self, qserver_process, RM, check_target=False, use_OAm=False, is peak_target = self.inputs.peak_target[0] peak_tolerance = self.inputs.peak_target[1] + + if check_target: + peak_diff = abs(self.PL_fitting['peak_emission'] - peak_target) + meet_target = (peak_diff <= peak_tolerance) + if meet_target: + print(f'\nTarget peak: {self.inputs.peak_target[0]} nm vs. Current peak: {self.PL_fitting["peak_emission"]} nm\n') + print(f'\nReach the target, stop iteration, stop all pumps, and wash the loop.\n') + + ### Stop all infusing pumps and wash loop + sq = importlib.import_module("_synthesis_queue_RM") + sq.wash_tube_queue2(qin.pump_list, qin.wash_tube, 'ul/min', + zmq_control_addr=qin.zmq_control_addr[0], + zmq_info_addr=qin.zmq_info_addr[0]) + + inst1 = BInst("queue_stop") + RM.item_add(inst1, pos='front') + self.agent_iteration.append(False) + + else: + self.agent_iteration.append(True) + if is_1st: pass else: @@ -201,7 +231,7 @@ def macro_agent(self, qserver_process, RM, check_target=False, use_OAm=False, is self.agent = build_agent( peak_target = peak_target, agent_data_path = self.inputs.agent_data_path[0], - use_OAm = use_OAm) + use_OAm = qin.use_OAm[0]) if len(self.agent.table) < 2: acq_func = "qr" @@ -235,26 +265,7 @@ def macro_agent(self, qserver_process, RM, check_target=False, use_OAm=False, is self.agent_data.update({'agent_target': agent_target}) self.agent_data.update({'posterior_mean': post_mean}) self.agent_data.update({'posterior_stddev': post_stddev}) - - if check_target and meet_target: - peak_diff = abs(self.PL_fitting['peak_emission'] - peak_target) - meet_target = (peak_diff <= peak_tolerance) - print(f'\nTarget peak: {self.inputs.peak_target[0]} nm vs. Current peak: {self.PL_fitting["peak_emission"]} nm\n') - print(f'\nReach the target, stop iteration, stop all pumps, and wash the loop.\n') - - ### Stop all infusing pumps and wash loop - sq = importlib.import_module("_synthesis_queue_RM") - sq.wash_tube_queue2(qin.pump_list, qin.wash_tube, 'ul/min', - zmq_control_addr=qin.zmq_control_addr[0], - zmq_info_addr=qin.zmq_info_addr[0]) - - inst1 = BInst("queue_stop") - RM.item_add(inst1, pos='front') - self.agent_iteration.append(False) - else: - self.agent_iteration.append(True) - return new_points @@ -350,7 +361,7 @@ def macro_03_stop_queue_uid(sefl, RM): - def macro_04_dummy_pdf(sefl): + def macro_04_dummy_pdf(self): """macro to setup a dummy pdf data for testing, used in kafka consumer while self.inputs.dummy_pdf[0] is True @@ -364,11 +375,11 @@ def macro_04_dummy_pdf(sefl): self.iq_data['df']: iq_df """ self.iq_data = {} - iq_array = pd.read_csv(self.iq_fn[-1], skiprows=1, names=['q', 'I(q)'], sep=' ').to_numpy().T + iq_array = pd.read_csv(self.inputs.iq_fn[-1], skiprows=1, names=['q', 'I(q)'], sep=' ').to_numpy().T # self.iq_data.append(iq_array[0]) # self.iq_data.append(iq_array[1]) # self.iq_data.append(iq_array) - iq_df = pd.read_csv(self.iq_fn[-1], skiprows=1, names=['q', 'I(q)'], sep=' ') + iq_df = pd.read_csv(self.inputs.iq_fn[-1], skiprows=1, names=['q', 'I(q)'], sep=' ') # self.iq_data.append(iq_df) iq_data = { 'Q':iq_array[0], @@ -554,6 +565,7 @@ def macro_08_no_fitting_pdf(self): # self.gr_fitting.append(gr_fit_arrary) # self.gr_fitting.append(gr_fit_df) + self.pdf_property = {} pdf_property={'Br_ratio': np.nan, 'Br_size': np.nan} self.pdf_property.update(pdf_property) @@ -600,11 +612,11 @@ def macro_10_good_bad(self, stream_name): This macro will 1. Identify a good or bad PL peak in 'take_a_uvvis' and 'fluorescence' 2. Update self.PL_goodbad - self.PL_goodbad['wavelength']: wavelenght (nm) of PL - self.PL_goodbad['intensity']: intensity of PL - self.PL_goodbad['data_id']: f'{t0[0]}_{t0[1]}_{metadata_dic["uid"][:8]}' - self.PL_goodbad['peak']: peaks from scipy.find_peaks - self.PL_goodbad['prop']: properties from scipy.find_peaks + self.PL_goodbad['wavelength']: wavelenght (nm) of PL + self.PL_goodbad['percentile_mean']: intensity of PL (percentile_mean) + self.PL_goodbad['data_id']: f'{t0[0]}_{t0[1]}_{metadata_dic["uid"][:8]}' + self.PL_goodbad['peak']: peaks from scipy.find_peaks + self.PL_goodbad['prop']: properties from scipy.find_peaks Args: stream_name (str): the stream name in scan doc to identify scan plan @@ -632,7 +644,7 @@ def macro_10_good_bad(self, stream_name): percent_range=[30, 100]) self.PL_goodbad = {} - PL_goodbad = { 'wavelength':np.asarray(x0), 'intensity':np.asarray(y0), + PL_goodbad = { 'wavelength':np.asarray(x0), 'percentile_mean':np.asarray(y0), 'data_id':data_id, 'peak':peak, 'prop':prop} self.PL_goodbad.update(PL_goodbad) @@ -645,7 +657,7 @@ def macro_11_absorbance(self, stream_name): 1. Apply a 2D line to fit the baseline of absorption spectra 2. Update self.abs_data self.abs_data['wavelength']: wavelenght of absorbance nm - self.abs_data['absorbance']: absorbance array (percentile_mean) + self.abs_data['percentile_mean']: absorbance array (percentile_mean) self.abs_data['offset']: absorbance array offset 3. Update self.abs_fitting self.abs_fitting['fit_function']: da.line_2D @@ -663,7 +675,7 @@ def macro_11_absorbance(self, stream_name): print(f'\n*** start to check absorbance at 365b nm in stream: {stream_name} is positive or not***\n') # abs_array = qepro_dic['QEPro_output'][1:].mean(axis=0) abs_array = abs_per.mean(axis=0) - wavelength = qepro_dic['QEPro_x_axis'][0] + wavelength = self.qepro_dic['QEPro_x_axis'][0] popt_abs01, _ = da.fit_line_2D(wavelength, abs_array, da.line_2D, x_range=[205, 240], plot=False) popt_abs02, _ = da.fit_line_2D(wavelength, abs_array, da.line_2D, x_range=[750, 950], plot=False) @@ -674,10 +686,10 @@ def macro_11_absorbance(self, stream_name): abs_array_offset = abs_array - da.line_2D(wavelength, *popt_abs) print(f'\nFitting function for baseline offset: {da.line_2D}\n') - ff_abs={'fit_function': da.line_2D, 'curve_fit': popt_abs} + ff_abs={'fit_function': da.line_2D, 'curve_fit': popt_abs, 'percentile_mean':abs_array} self.abs_data = {} - self.abs_data.update({'wavelength':wavelength, 'absorbance':abs_array, 'offset':abs_array_offset}) + self.abs_data.update({'wavelength':wavelength, 'percentile_mean':abs_array, 'offset':abs_array_offset}) self.abs_fitting = {} self.abs_fitting.update(ff_abs) @@ -701,12 +713,12 @@ def macro_12_PL_fitting(self): self.PL_fitting['wavelength']: wavelenght (nm) of PL between 400 ~ 800 nm self.PL_fitting['intensity']: intensity of PL (nm) between 400 ~ 800 nm self.PL_fitting['shifted_peak_idx']: peak index between 400 ~ 800 nm - + self.PL_fitting['percentile_mean']: intensity of PL (percentile_mean) """ x, y, p, f_fit, popt = da._fitting_in_kafka( self.PL_goodbad['wavelength'], - self.PL_goodbad['intensity'], + self.PL_goodbad['percentile_mean'], self.PL_goodbad['data_id'], self.PL_goodbad['peak'], self.PL_goodbad['prop'], @@ -717,7 +729,7 @@ def macro_12_PL_fitting(self): r2_idx2, _ = da.find_nearest(x, popt[1] + 3*popt[2]) r_2 = da.r_square(x[r2_idx1:r2_idx2], y[r2_idx1:r2_idx2], fitted_y[r2_idx1:r2_idx2], y_low_limit=0) - metadata_dic["r_2"] = r_2 + self.metadata_dic["r_2"] = r_2 if 'gauss' in f_fit.__name__: constant = 2.355 @@ -738,8 +750,8 @@ def macro_12_PL_fitting(self): ff={'fit_function': f_fit, 'curve_fit': popt, 'fwhm': fwhm, 'peak_emission': peak_emission, - 'wavelength': x, 'intensity': y, - 'shifted_peak_idx': p} + 'wavelength': x, 'intensity': y, 'shifted_peak_idx': p, + 'percentile_mean': self.PL_goodbad['percentile_mean']} self.PL_fitting = {} self.PL_fitting.update(ff) @@ -764,6 +776,7 @@ def macro_13_PLQY(self): x = self.PL_fitting['wavelength'] y = self.PL_fitting['intensity'] peak_emission = self.PL_fitting['peak_emission'] + fwhm = self.PL_fitting['fwhm'] PL_integral_s = integrate.simpson(y) ## Find absorbance at 365 nm from absorbance stream @@ -788,7 +801,7 @@ def macro_13_PLQY(self): def macro_14_upate_agent(self): - """macro to update agent_data in type of dict for exporting as json and wirte to sandbox + """macro to update agent_data in type of dict for exporting This macro will 1. Update self.agent_data with @@ -800,7 +813,7 @@ def macro_14_upate_agent(self): """ - ## Creat agent_data in type of dict for exporting as json and wirte to sandbox + ## Creat agent_data in type of dict for exporting if 'agent_target' in self.agent_data.keys(): pass else: @@ -847,7 +860,7 @@ def macro_15_save_data(self, stream_name): df['wavelength_nm'] = x0 df['absorbance_mean'] = self.abs_data['absorbance'] df['absorbance_offset'] = self.abs_data['offset'] - df['fluorescence_mean'] = self.PL_goodbad['intensity'] + df['fluorescence_mean'] = self.PL_goodbad['percentile_mean'] f_fit = self.PL_fitting['fit_function'] popt = self.PL_fitting['curve_fit'] df['fluorescence_fitting'] = f_fit(x0, *popt) @@ -880,8 +893,8 @@ def macro_16_num_good(self, stream_name): stream_name (str): the stream name in scan doc to identify scan plan """ - type_peak = type(kafka_process.PL_goodbad['peak']) - type_prop = type(kafka_process.PL_goodbad['prop']) + type_peak = type(self.PL_goodbad['peak']) + type_prop = type(self.PL_goodbad['prop']) ## Append good/bad idetified results if stream_name == 'take_a_uvvis': @@ -897,8 +910,8 @@ def macro_16_num_good(self, stream_name): print('\n*** export, identify good/bad, fitting complete ***\n') print(f"\n*** {self.sample_type} of uid: {self.uid[:8]} has: ***\n" - f"{self.optical_property = }***\n" - f"{self.pdf_property = }***\n") + f"*** {self.optical_property = } ***\n" + f"*** {self.pdf_property = } ***\n") def macro_17_add_queue(self, stream_name, qserver_process, RM): @@ -955,12 +968,12 @@ def macro_17_add_queue(self, stream_name, qserver_process, RM): RM.queue_start() ## Add predicted new points from ML agent into qserver - elif (stream_name == 'fluorescence') and (self.inputs.USE_AGENT_iterate[0]) and (self.inputs.agent_iteration[-1]): + elif (stream_name == 'fluorescence') and (self.inputs.USE_AGENT_iterate[0]) and (self.agent_iteration[-1]): print('*** Add new points from agent to the fron of qsever ***\n') new_points = self.macro_agent(qserver_process, RM, check_target=True) - print(f'*** New points from agent: {new_points} ***\n') + print(f'*** New points from agent:\n {pprint.pformat(new_points, indent=1)} ***\n') rate_list = self.auto_rate_list(qin.pump_list, new_points, self.inputs.fix_Br_ratio) diff --git a/scripts/_synthesis_queue_RM.py b/scripts/_synthesis_queue_RM.py index 76a0f93..0ac834d 100644 --- a/scripts/_synthesis_queue_RM.py +++ b/scripts/_synthesis_queue_RM.py @@ -203,7 +203,7 @@ def synthesis_queue_xlsx(parameter_obj): ## 6. Start xray_uvvis bundle plan to take real data ('pe1c' or 'det') - scanplan = BPlan('xray_uvvis_plan', det1, det2, + scanplan = BPlan('xray_uvvis_plan2', det1, det2, num_abs=num_abs, num_flu=num_flu, sample_type=sample[i], @@ -211,8 +211,7 @@ def synthesis_queue_xlsx(parameter_obj): correction_type='Reference', pump_list=pump_list, precursor_list=precursor_list, - mixer=mixer, - dilute_pump=pump_list[-1]) + mixer=mixer) RM.item_add(scanplan, pos=pos) ## 6.1 sleep 20 seconds for stopping @@ -424,7 +423,7 @@ def synthesis_queue( ## 6. Start xray_uvvis bundle plan to take real data ('pe1c' or 'det') - scanplan = BPlan('xray_uvvis_plan', det1, 'qepro', + scanplan = BPlan('xray_uvvis_plan2', det1, 'qepro', num_abs=num_abs, num_flu=num_flu, sample_type=sample[i], @@ -432,8 +431,7 @@ def synthesis_queue( correction_type='Reference', pump_list=pump_list, precursor_list=precursor_list, - mixer=mixer, - dilute_pump=pump_list[-1]) + mixer=mixer) RM.item_add(scanplan, pos=pos) ## 6.1 sleep 20 seconds for stopping @@ -647,8 +645,7 @@ def synthesis_queue3( correction_type='Reference', pump_list=pump_list, precursor_list=precursor_list, - mixer=mixer, - dilute_pump=pump_list[-1]) + mixer=mixer) RM.item_add(scanplan, pos=pos) ## 6.1 sleep 20 seconds for stopping diff --git a/scripts/inputs_qserver_kafka_v2.xlsx b/scripts/inputs_qserver_kafka_v2.xlsx index 38112e5..163640a 100644 Binary files a/scripts/inputs_qserver_kafka_v2.xlsx and b/scripts/inputs_qserver_kafka_v2.xlsx differ diff --git a/scripts/kafka_consumer_iterate_1LL09_v2.py b/scripts/kafka_consumer_iterate_1LL09_v2.py index bb7adef..fb1465c 100644 --- a/scripts/kafka_consumer_iterate_1LL09_v2.py +++ b/scripts/kafka_consumer_iterate_1LL09_v2.py @@ -58,7 +58,7 @@ RM = REManagerAPI(zmq_control_addr=qin.zmq_control_addr[0], zmq_info_addr=qin.zmq_info_addr[0]) ## Make the first prediction from kafka_process.agent -first_points = kafka_process.macro_agent(qserver_process, RM, check_target=False, use_OAm=False, is_1st=True) +first_points = kafka_process.macro_agent(qserver_process, RM, check_target=False, is_1st=True) rate_list = kafka_process.auto_rate_list(qin.pump_list, first_points, kin.fix_Br_ratio) if kin.post_dilute[0]: rate_list.append(sum(rate_list)*kin.post_dilute[1]) @@ -185,7 +185,7 @@ def print_message(consumer, doctype, doc): ## Plot data, Agent prediction ## ## Export data, Save data to tiled ## ################################################### - if name == 'stop': + if name == 'stop': RM.queue_stop() print('\n*** qsever stop for data export, identification, and fitting ***\n') print(f"{datetime.datetime.now().isoformat()} documents {name}\n" @@ -208,6 +208,10 @@ def print_message(consumer, doctype, doc): for stream_name in stream_list: kafka_process.stream_list.append(stream_name) + ## When 'take_a_uvvis' not in stream_list, no need to wait for data process + ## since next task in queue is washing loop. So start queue + if 'take_a_uvvis' not in kafka_process.stream_list: + RM.queue_start() ## Set good/bad data condictions to the corresponding sample kh = kin.key_height[0] @@ -307,11 +311,13 @@ def print_message(consumer, doctype, doc): kafka_process.macro_10_good_bad(stream_name) label_uid = f'{kafka_process.uid[0:8]}_{kafka_process.metadata_dic["sample_type"]}' - u.plot_average_good(kafka_process.PL_goodbad['x0'], kafka_process.PL_goodbad['y0'], label=label_uid, clf_limit=9) + u.plot_average_good(kafka_process.PL_goodbad['wavelength'], + kafka_process.PL_goodbad['percentile_mean'], + label=label_uid, clf_limit=9) ## Skip peak fitting if qepro type is absorbance - if qepro_dic['QEPro_spectrum_type'][0] == 3: + if kafka_process.qepro_dic['QEPro_spectrum_type'][0] == 3: print(f"\n*** No need to carry out fitting for {stream_name} in uid: {kafka_process.uid[:8]} ***\n") ## macro_12 ~ macro_16 @@ -331,13 +337,17 @@ def print_message(consumer, doctype, doc): kafka_process.macro_12_PL_fitting() ## Calculate PLQY for fluorescence stream - if (stream_name == 'fluorescence') and (PLQY[0]==1): + if (stream_name == 'fluorescence') and (kin.PLQY[0]==1): ## macro_13_PLQY: calculate integral of PL peak, PLQY and update optical_property kafka_process.macro_13_PLQY() label_uid = f'{kafka_process.uid[0:8]}_{kafka_process.metadata_dic["sample_type"]}' u.plot_CsPbX3(kafka_process.PL_fitting['wavelength'], kafka_process.PL_fitting['intensity'], kafka_process.PL_fitting['peak_emission'], label=label_uid, clf_limit=9) + + ## macro_14_agent_data: Creat agent_data in type of dict for exporting + kafka_process.macro_14_upate_agent() + else: kafka_process.plqy_dic ={} kafka_process.optical_property = {} @@ -351,8 +361,6 @@ def print_message(consumer, doctype, doc): fill_between=True) print(f'\n** plot fitting results complete**\n') - ## macro_14_agent_data: Creat agent_data in type of dict for exporting as json and wirte to sandbox - kafka_process.macro_14_upate_agent() ## macro_15_save_data: Save processed data and agent data kafka_process.macro_15_save_data(stream_name) diff --git a/scripts/kafka_consumer_iterate_XPD_v2.py b/scripts/kafka_consumer_iterate_XPD_v2.py index 6fcd114..7d6531e 100644 --- a/scripts/kafka_consumer_iterate_XPD_v2.py +++ b/scripts/kafka_consumer_iterate_XPD_v2.py @@ -58,7 +58,7 @@ RM = REManagerAPI(zmq_control_addr=qin.zmq_control_addr[0], zmq_info_addr=qin.zmq_info_addr[0]) ## Make the first prediction from kafka_process.agent -first_points = kafka_process.macro_agent(qserver_process, RM, check_target=False, use_OAm=False, is_1st=True) +first_points = kafka_process.macro_agent(qserver_process, RM, check_target=False, is_1st=True) rate_list = kafka_process.auto_rate_list(qin.pump_list, first_points, kin.fix_Br_ratio) if kin.post_dilute[0]: rate_list.append(sum(rate_list)*kin.post_dilute[1]) @@ -345,11 +345,13 @@ def print_message(consumer, doctype, doc): kafka_process.macro_10_good_bad(stream_name) label_uid = f'{kafka_process.uid[0:8]}_{kafka_process.metadata_dic["sample_type"]}' - u.plot_average_good(kafka_process.PL_goodbad['x0'], kafka_process.PL_goodbad['y0'], label=label_uid, clf_limit=9) + u.plot_average_good(kafka_process.PL_goodbad['wavelength'], + kafka_process.PL_goodbad['percentile_mean'], + label=label_uid, clf_limit=9) ## Skip peak fitting if qepro type is absorbance - if qepro_dic['QEPro_spectrum_type'][0] == 3: + if kafka_process.qepro_dic['QEPro_spectrum_type'][0] == 3: print(f"\n*** No need to carry out fitting for {stream_name} in uid: {kafka_process.uid[:8]} ***\n") ## macro_12 ~ macro_16 @@ -369,13 +371,17 @@ def print_message(consumer, doctype, doc): kafka_process.macro_12_PL_fitting() ## Calculate PLQY for fluorescence stream - if (stream_name == 'fluorescence') and (PLQY[0]==1): + if (stream_name == 'fluorescence') and (kin.PLQY[0]==1): ## macro_13_PLQY: calculate integral of PL peak, PLQY and update optical_property kafka_process.macro_13_PLQY() label_uid = f'{kafka_process.uid[0:8]}_{kafka_process.metadata_dic["sample_type"]}' u.plot_CsPbX3(kafka_process.PL_fitting['wavelength'], kafka_process.PL_fitting['intensity'], kafka_process.PL_fitting['peak_emission'], label=label_uid, clf_limit=9) + + ## macro_14_agent_data: Creat agent_data in type of dict for exporting + kafka_process.macro_14_upate_agent() + else: kafka_process.plqy_dic ={} kafka_process.optical_property = {} @@ -388,9 +394,6 @@ def print_message(consumer, doctype, doc): peak=kafka_process.PL_fitting['shifted_peak_idx'], fill_between=True) print(f'\n** plot fitting results complete**\n') - - ## macro_14_agent_data: Creat agent_data in type of dict for exporting as json and wirte to sandbox - kafka_process.macro_14_upate_agent() ## macro_15_save_data: Save processed data and agent data kafka_process.macro_15_save_data(stream_name) diff --git a/startup/32-bundle-plan.py b/startup/32-bundle-plan.py index bf047b7..9994899 100644 --- a/startup/32-bundle-plan.py +++ b/startup/32-bundle-plan.py @@ -5,6 +5,135 @@ # RE.msg_hook = ts_msg_hook + + +def xray_uvvis_plan2(det1, det2, *args, md=None, num_abs=10, num_flu=10, sample_type = 'test', + pump_list=None, precursor_list=None, mixer=None, note=None, **kwargs): + """Trigger the two detctors (det1: pe1c, det2: qepro): det2 first and then det1. + + Generate a scan containing three stream names: ['scattering', 'absorbance', 'fluorescence'] + + Args: + det1 (ophyd.Device): xray detector (example: pe1c) + det2 (ophyd.Device): Uv-Vis detector (example: qepro) + md (dict, optional): metadata. + num_abs (int, optional): numbers of absorption spectra + num_flu (int, optional): numbers of fluorescence spectra + sample_type (str, optional): sample name + pump_list (list, optional): list of pumps as ophyd.Device (example: [dds1_p1, dds1_p2, dds2_p1, dds2_p2]) + precursor_list (list, optional): list of precursors name (example: ['CsPbOA', 'TOABr', 'ZnI2', 'Toluene']) + mixer (list, optional): list of mixers (example: ['30 cm', '60 cm']) + note (str, optional): addtional info. Defaults to None. + """ + if (pump_list != None and precursor_list != None): + _md = {"pumps" : [pump.name for pump in pump_list], + "precursors" : precursor_list, + "infuse_rate" : [pump.read_infuse_rate.get() for pump in pump_list], + "infuse_rate_unit" : [pump.read_infuse_rate_unit.get() for pump in pump_list], + "pump_status" : [pump.status.get() for pump in pump_list], + "uvvis" :[det2.integration_time.get(), det2.num_spectra.get(), det2.buff_capacity.get()], + "mixer": mixer, + "sample_type": sample_type, + "sample_name": sample_type, + "detectors": [det1.name, det2.name], + "note" : note if note else "None"} + _md.update(md or {}) + dilute_pump = pump_list[-1] + + if (pump_list == None and precursor_list == None): + _md = { "uvvis" :[det2.integration_time.get(), det2.num_spectra.get(), det2.buff_capacity.get()], + "mixer": ['exsitu measurement'], + "sample_type": sample_type, + "sample_name": sample_type, + "detectors": [det1.name, det2.name], + "note" : note if note else "None"} + _md.update(md or {}) + + + @bpp.stage_decorator([det1, det2]) + @bpp.run_decorator(md=_md) + def trigger_two_detectors(): # TODO: rename appropriately + ret = {} + + # TODO: write your fast procedure here, don't use bp.count/bp.scan here as they open separate runs. + # Use `trigger_and_read` instead. + # Tested on 2023/02/16: bps.trigger works for qepro + + + # For absorbance: spectrum_type='Absorbtion', correction_type='Reference' + # For fluorescence: spectrum_type='Corrected Sample', correction_type='Dark' + + ## Start to collecting absrobtion + # t0 = time.time() + spectrum_type='Absorbtion' + correction_type='Reference' + if LED.get()=='Low' and UV_shutter.get()=='High' and det2.correction.get()==correction_type and det2.spectrum_type.get()==spectrum_type: + pass + else: + # yield from bps.abs_set(qepro.correction, correction_type, wait=True) + # yield from bps.abs_set(qepro.spectrum_type, spectrum_type, wait=True) + yield from bps.mv(det2.correction, correction_type, det2.spectrum_type, spectrum_type) + yield from bps.mv(LED, 'Low', UV_shutter, 'High') + yield from bps.sleep(2) + + for i in range(num_abs): + yield from bps.trigger(det2, wait=True) + + yield from bps.create(name="absorbance") + reading = (yield from bps.read(det2)) + # print(f"reading = {reading}") + ret.update(reading) + yield from bps.save() # TODO: check if it's needed, most likely yes. + # yield from bps.sleep(2) + + + ## Start to collecting fluorescence + spectrum_type='Corrected Sample' + correction_type='Dark' + if LED.get()=='High' and UV_shutter.get()=='Low' and det2.correction.get()==correction_type and det2.spectrum_type.get()==spectrum_type: + pass + else: + # yield from bps.abs_set(qepro.correction, correction_type, wait=True) + # yield from bps.abs_set(qepro.syield from bps.sleep(xray_time)pectrum_type, spectrum_type, wait=True) + yield from bps.mv(det2.correction, correction_type, det2.spectrum_type, spectrum_type) + yield from bps.mv(LED, 'High', UV_shutter, 'Low') + yield from bps.sleep(2) + + for i in range(num_flu): # TODO: fix the number of triggers + yield from bps.trigger(det2, wait=True) + + yield from bps.create(name="fluorescence") + reading = (yield from bps.read(det2)) + # print(f"reading = {reading}") + ret.update(reading) + yield from bps.save() # TODO: check if it's needed, most likely yes. + # yield from bps.sleep(2) + + yield from bps.mv(LED, 'Low', UV_shutter, 'Low') + + if (pump_list != None) and (precursor_list != None): + yield from stop_group([dilute_pump]) + + print(f'\nUV-Vis acquisition finished and stop infusing of {dilute_pump.name} for toluene dilution\n') + + + ## Start to collecting scattering + yield from bps.trigger(det1, wait=True) + # yield from bps.sleep(det1_time) + yield from bps.create(name="scattering") + reading = (yield from bps.read(det1)) + print(f"reading = {reading}") + ret.update(reading) + yield from bps.save() + + + yield from trigger_two_detectors() + + + + + + def xray_uvvis_plan(det1, det2, *args, md=None, num_abs=10, num_flu=10, sample_type = 'test', pump_list=None, precursor_list=None, mixer=None, note=None, **kwargs): @@ -14,17 +143,19 @@ def xray_uvvis_plan(det1, det2, *args, md=None, num_abs=10, num_flu=10, sample_t "infuse_rate" : [pump.read_infuse_rate.get() for pump in pump_list], "infuse_rate_unit" : [pump.read_infuse_rate_unit.get() for pump in pump_list], "pump_status" : [pump.status.get() for pump in pump_list], - "uvvis" :[qepro.integration_time.get(), qepro.num_spectra.get(), qepro.buff_capacity.get()], + "uvvis" :[det2.integration_time.get(), det2.num_spectra.get(), det2.buff_capacity.get()], "mixer": mixer, - "sample_type": sample_type, + "sample_type": sample_type, + "sample_name": sample_type, "detectors": [det1.name, det2.name], "note" : note if note else "None"} _md.update(md or {}) if (pump_list == None and precursor_list == None): - _md = { "uvvis" :[qepro.integration_time.get(), qepro.num_spectra.get(), qepro.buff_capacity.get()], + _md = { "uvvis" :[det2.integration_time.get(), det2.num_spectra.get(), det2.buff_capacity.get()], "mixer": ['exsitu measurement'], - "sample_type": sample_type, + "sample_type": sample_type, + "sample_name": sample_type, "detectors": [det1.name, det2.name], "note" : note if note else "None"} _md.update(md or {}) @@ -49,12 +180,12 @@ def trigger_two_detectors(): # TODO: rename appropriately # t0 = time.time() spectrum_type='Absorbtion' correction_type='Reference' - if LED.get()=='Low' and UV_shutter.get()=='High' and qepro.correction.get()==correction_type and qepro.spectrum_type.get()==spectrum_type: + if LED.get()=='Low' and UV_shutter.get()=='High' and det2.correction.get()==correction_type and det2.spectrum_type.get()==spectrum_type: pass else: # yield from bps.abs_set(qepro.correction, correction_type, wait=True) # yield from bps.abs_set(qepro.spectrum_type, spectrum_type, wait=True) - yield from bps.mv(qepro.correction, correction_type, qepro.spectrum_type, spectrum_type) + yield from bps.mv(det2.correction, correction_type, det2.spectrum_type, spectrum_type) yield from bps.sleep(1) yield from bps.mv(LED, 'Low', UV_shutter, 'High') yield from bps.sleep(1) @@ -75,12 +206,12 @@ def trigger_two_detectors(): # TODO: rename appropriately ## Start to collecting fluorescence spectrum_type='Corrected Sample' correction_type='Dark' - if LED.get()=='High' and UV_shutter.get()=='Low' and qepro.correction.get()==correction_type and qepro.spectrum_type.get()==spectrum_type: + if LED.get()=='High' and UV_shutter.get()=='Low' and det2.correction.get()==correction_type and det2.spectrum_type.get()==spectrum_type: pass else: # yield from bps.abs_set(qepro.correction, correction_type, wait=True) # yield from bps.abs_set(qepro.spectrum_type, spectrum_type, wait=True) - yield from bps.mv(qepro.correction, correction_type, qepro.spectrum_type, spectrum_type) + yield from bps.mv(det2.correction, correction_type, det2.spectrum_type, spectrum_type) yield from bps.sleep(1) yield from bps.mv(LED, 'High', UV_shutter, 'Low') yield from bps.sleep(1) @@ -113,16 +244,6 @@ def trigger_two_detectors(): # TODO: rename appropriately - - - - - - - - - - def xray_uvvis_plan3(det1, det2, *args, md=None, num_abs=10, num_flu=10, sample_type = 'test', pump_list=None, precursor_list=None, mixer=None, note=None, **kwargs): @@ -132,7 +253,7 @@ def xray_uvvis_plan3(det1, det2, *args, md=None, num_abs=10, num_flu=10, sample_ "infuse_rate" : [pump.read_infuse_rate.get() for pump in pump_list], "infuse_rate_unit" : [pump.read_infuse_rate_unit.get() for pump in pump_list], "pump_status" : [pump.status.get() for pump in pump_list], - "uvvis" :[qepro.integration_time.get(), qepro.num_spectra.get(), qepro.buff_capacity.get()], + "uvvis" :[det2.integration_time.get(), det2.num_spectra.get(), det2.buff_capacity.get()], "mixer": mixer, "sample_type": sample_type, "detectors": [det1.name, det2.name], @@ -140,7 +261,7 @@ def xray_uvvis_plan3(det1, det2, *args, md=None, num_abs=10, num_flu=10, sample_ _md.update(md or {}) if (pump_list == None and precursor_list == None): - _md = { "uvvis" :[qepro.integration_time.get(), qepro.num_spectra.get(), qepro.buff_capacity.get()], + _md = { "uvvis" :[det2.integration_time.get(), det2.num_spectra.get(), det2.buff_capacity.get()], "mixer": ['exsitu measurement'], "sample_type": sample_type, "detectors": [det1.name, det2.name], @@ -167,12 +288,12 @@ def trigger_two_detectors(): # TODO: rename appropriately # t0 = time.time() spectrum_type='Absorbtion' correction_type='Reference' - if LED.get()=='Low' and UV_shutter.get()=='High' and qepro.correction.get()==correction_type and qepro.spectrum_type.get()==spectrum_type: + if LED.get()=='Low' and UV_shutter.get()=='High' and det2.correction.get()==correction_type and det2.spectrum_type.get()==spectrum_type: pass else: # yield from bps.abs_set(qepro.correction, correction_type, wait=True) # yield from bps.abs_set(qepro.spectrum_type, spectrum_type, wait=True) - yield from bps.mv(qepro.correction, correction_type, qepro.spectrum_type, spectrum_type) + yield from bps.mv(det2.correction, correction_type, det2.spectrum_type, spectrum_type) yield from bps.sleep(1) yield from bps.mv(LED, 'Low', UV_shutter, 'High') yield from bps.sleep(1) @@ -193,12 +314,12 @@ def trigger_two_detectors(): # TODO: rename appropriately ## Start to collecting fluorescence spectrum_type='Corrected Sample' correction_type='Dark' - if LED.get()=='High' and UV_shutter.get()=='Low' and qepro.correction.get()==correction_type and qepro.spectrum_type.get()==spectrum_type: + if LED.get()=='High' and UV_shutter.get()=='Low' and det2.correction.get()==correction_type and det2.spectrum_type.get()==spectrum_type: pass else: # yield from bps.abs_set(qepro.correction, correction_type, wait=True) # yield from bps.abs_set(qepro.spectrum_type, spectrum_type, wait=True) - yield from bps.mv(qepro.correction, correction_type, qepro.spectrum_type, spectrum_type) + yield from bps.mv(det2.correction, correction_type, det2.spectrum_type, spectrum_type) yield from bps.sleep(1) yield from bps.mv(LED, 'High', UV_shutter, 'Low') yield from bps.sleep(1) diff --git a/startup/existing_plans_and_devices.yaml b/startup/existing_plans_and_devices.yaml index b6000f4..abf1ed7 100644 --- a/startup/existing_plans_and_devices.yaml +++ b/startup/existing_plans_and_devices.yaml @@ -3121,6 +3121,70 @@ existing_plans: name: kwargs properties: is_generator: true + xray_uvvis_plan2: + description: 'Trigger the two detctors (det1: pe1c, det2: qepro): det2 first and + then det1.' + module: __main__ + name: xray_uvvis_plan2 + parameters: + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: det1 + - kind: + name: POSITIONAL_OR_KEYWORD + value: 1 + name: det2 + - kind: + name: VAR_POSITIONAL + value: 2 + name: args + - default: None + kind: + name: KEYWORD_ONLY + value: 3 + name: md + - default: '10' + kind: + name: KEYWORD_ONLY + value: 3 + name: num_abs + - default: '10' + kind: + name: KEYWORD_ONLY + value: 3 + name: num_flu + - default: '''test''' + kind: + name: KEYWORD_ONLY + value: 3 + name: sample_type + - default: None + kind: + name: KEYWORD_ONLY + value: 3 + name: pump_list + - default: None + kind: + name: KEYWORD_ONLY + value: 3 + name: precursor_list + - default: None + kind: + name: KEYWORD_ONLY + value: 3 + name: mixer + - default: None + kind: + name: KEYWORD_ONLY + value: 3 + name: note + - kind: + name: VAR_KEYWORD + value: 4 + name: kwargs + properties: + is_generator: true xray_uvvis_plan3: module: __main__ name: xray_uvvis_plan3