def main(): c = Calibration() c.parse() c.read_pixelsSize() c.preprocess() c.gui_peakPicker() six.moves.input("Press enter to quit")
def img_calibration(img, wavelength, calibrant='Ni', detector='perkin_elmer', calib_ref_fp=None, **kwargs): """Function to calibrate experimental geometry for an image Parameters ---------- img : ndarray 2D powder diffraction image from calibrant wavelength : float x-ray wavelength in angstrom. calibrant : str, optional calibrant being used, default is 'Ni'. input could be "full file path" to customized d-spacing file with ".D" extension or one of pre-defined calibrant names. List of pre-defined calibrant names: ['NaCl', 'AgBh', 'quartz', 'Si_SRM640', 'Ni', 'Si_SRM640d', 'Si_SRM640a', 'alpha_Al2O3', 'LaB6_SRM660b', 'TiO2', 'CrOx', 'LaB6_SRM660c', 'CeO2', 'Si_SRM640c', 'CuO', 'Si_SRM640e', 'PBBA', 'ZnO', 'Si', 'C14H30O', 'cristobaltite', 'LaB6_SRM660a', 'Au', 'Cr2O3', 'Si_SRM640b', 'LaB6', 'Al', 'mock'] detector : str or pyFAI.detector.Detector instance, optional. detector used to collect data. default value is 'perkin-elmer'. other allowed values are in pyFAI documentation. calib_ref_fp : str, optional full file path to where the native pyFAI calibration information will be saved. Default to current working directory. kwargs: Additional keyword argument for calibration. please refer to pyFAI documentation for all options. Returns ------- ai : pyFAI.AzimuthalIntegrator instance of AzimuthalIntegrator. Can be used to integrate 2D images directly. Examples -------- calib Ni image with pyFAI default ``Ni.D`` d-spacing with wavlength 0.1823 angstrom >>> import tifffile as tif >>> ni_img = tif.imread('<path_to_img_file>') >>> ai = img_calibration(ni_img, 0.1823) calib Ni image with pyFAI customized ``myNi.D`` d-spacing with wavlength 0.1823 angstrom >>> import tifffile as tif >>> ni_img = tif.imread('<path_to_img_file>') >>> ai = img_calibration(ni_img, 0.1823, 'path/to/myNi.D') integrate image right after calibration >>> import matplotlib.pyplot as plt >>> npt = 1482 # just a number for demonstration >>> q, Iq = ai.integrate1d(ni_img, npt, unit="q_nm^-1") >>> plt.plot(q, Iq) References --------- pyFAI documentation: http://pyfai.readthedocs.io/en/latest/ """ wavelength *= 10**-10 if isinstance(calibrant, list): calibrant = Calibrant(dSpacing=calibrant, wavelength=wavelength) # configure calibration instance c = Calibration(calibrant=calibrant, detector=detector, wavelength=wavelength) # pyFAI calibration calib_c, timestr = _calibration(img, c, calib_ref_fp, **kwargs) # TODO: apply polarization correction and recalibrate? return calib_c, calib_c.ai
def run_calibration(exposure=5, dark_sub_bool=True, calibrant=None, phase_info=None, wavelength=None, detector=None, *, RE_instance=None, parallel=True, **kwargs): """function to run entire calibration process. Entire process includes: 1. collect calibration image, 2. trigger pyFAI interactive calibration process, 3. store calibration parameters as a yaml file calibration parameters will be saved under xpdUser/config_base/ and this set of parameters will be injected as metadata to subsequent scans until you perform this process again Parameters ---------- exposure : int, optional total exposure time in sec. default is 5s dark_sub_bool : bool, optional option of turn on/off dark subtraction on this calibration image. default is True. calibrant : str, optional calibrant being used, default is 'Ni'. input could be full file path to customized d-spacing file with ".D" extension or one of pre-defined calibrant names. List of pre-defined calibrant names is: ['NaCl', 'AgBh', 'quartz', 'Si_SRM640', 'Ni', 'Si_SRM640d', 'Si_SRM640a', 'alpha_Al2O3', 'LaB6_SRM660b', 'TiO2', 'CrOx', 'LaB6_SRM660c', 'CeO2', 'Si_SRM640c', 'CuO', 'Si_SRM640e', 'PBBA', 'ZnO', 'Si', 'C14H30O', 'cristobaltite', 'LaB6_SRM660a', 'Au', 'Cr2O3', 'Si_SRM640b', 'LaB6', 'Al', 'mock'] phase_info : str, optional phase infomation of calibrant, which is required to data reduction process. This field will be parsed with the same logic as the one used in parsing spreadsheet information. For detailed information, please visit: http://xpdacq.github.io/usb_Running.html#phase-string If both ``calibrant`` and ``phase_info`` arguments are not provided, this field will be defaulted to ``Ni``. wavelength : float, optional x-ray wavelength in angstrom. default to value stored in existing Beamtime object detector : str or pyFAI.detector.Detector instance, optional. detector used to collect data. default value is 'perkin-elmer'. other allowed values are in pyFAI documentation. RE_instance : bluesky.run_engine.RunEngine instance, optional instance of run engine. Default is xrun. Do not change under normal circumstances. parallel : bool, optional Tag for whether run the calibration step in a separte process. Running in parallel in principle yields better resource allocation. Default is ``True``, only change to ``False`` if error is raised. kwargs: Additional keyword argument for calibration. please refer to pyFAI documentation for all options. Note ---- Details about peak-picking gui from pyFAI documentaion http://pyfai.readthedocs.io/en/latest/usage/cookbook/calibrate.html#start-pyfai-calibration_md """ # default information if detector is None: detector = "perkin_elmer" sample_md = _sample_name_phase_info_configuration(calibrant, phase_info, "calib") if calibrant is None: calibrant = os.path.join(glbl["usrAnalysis_dir"], "Ni24.D") # collect & pull subtracted image if RE_instance is None: xrun_name = _REQUIRED_OBJ_LIST[0] RE_instance = _check_obj(xrun_name) # will raise error if not exists img, fn_template = _collect_img( exposure, dark_sub_bool, sample_md, "calib", RE_instance, detector=detector, calibrant=calibrant, ) print("INFO: Please navigate to the analysis terminal to complete " "the interactive calibration process.\nYou may find the " "the analysis terminal similar to data acquisition terminal" "(current terminal) except there is information about the " "analysis pipeline printed") print("INFO: For a quick guide on the interactive calibration " "process, please visit our web-doc at:\n" "https://xpdacq.github.io/xpdAcq/usb_Running.html#calib-manual\n") if not parallel: # backup when pipeline fails # get wavelength from bt if wavelength is None: bt_fp = os.path.join(glbl["yaml_dir"], "bt_bt.yml") if not os.path.isfile(bt_fp): raise FileNotFoundError("Can't find your Beamtime yaml file.\n" "Did you accidentally delete it? " "Please contact beamline staff " "ASAP") bto = Beamtime.from_yaml(open(bt_fp)) wavelength = float(bto.wavelength) * 10**(-10) # configure calibration instance c = Calibration(calibrant=calibrant, detector=detector, wavelength=wavelength) # pyFAI calibration calib_c, timestr = _calibration(img, c, fn_template, **kwargs) assert calib_c.calibrant.wavelength == wavelength # save param for xpdAcq yaml_name = glbl["calib_config_name"] calib_yml_fp = os.path.join(glbl["config_base"], glbl["calib_config_name"]) _save_calib_param(calib_c, timestr, calib_yml_fp)
def calibration(img, calibrant_file=None, wavelength=None, calib_collection_uid=None, save_file_name=None, detector=None, gaussian=None): """ run calibration process on a image with geometry correction software current backend is ``pyFAI``. Parameters ---------- img : ndarray image to be calibrated calibrant_file : str, optional calibrant file being used, default is 'Ni.D' under xpdUser/userAnalysis/ wavelength : flot, optional current of x-ray wavelength, in angstrom. Default value is read out from existing xpdacq.Beamtime object calibration_collection_uid : str, optional uid of calibration collection. default is generated from run calibration save_file_name : str, optional file name for yaml that carries resultant calibration parameters detector : pyfai.detector.Detector, optional. instance of detector which defines pixel size in x- and y-direction. Default is set to Perkin Elmer detector gaussian : int, optional gaussian width between rings, Default is 100. """ # default params interactive = True dist = 0.1 _check_obj(_REQUIRED_OBJ_LIST) ips = get_ipython() bto = ips.ns_table['user_global']['bt'] xrun = ips.ns_table['user_global']['xrun'] calibrant = Calibrant() # d-spacing if calibrant_file is not None: calibrant.load_file(calibrant_file) calibrant_name = os.path.split(calibrant_file)[1] calibrant_name = os.path.splitext(calibrant_name)[0] else: calibrant.load_file(os.path.join(glbl.usrAnalysis_dir, 'Ni.D')) calibrant_name = 'Ni' # wavelength if wavelength is None: _wavelength = bto['bt_wavelength'] else: _wavelength = wavelength calibrant.wavelength = _wavelength * 10 ** (-10) # detector if detector is None: detector = Perkin() # calibration timestr = _timestampstr(time.time()) basename = '_'.join(['pyFAI_calib', calibrant_name, timestr]) w_name = os.path.join(glbl.config_base, basename) # poni name c = Calibration(wavelength=calibrant.wavelength, detector=detector, calibrant=calibrant, gaussianWidth=gaussian) c.gui = interactive c.basename = w_name c.pointfile = w_name + ".npt" c.ai = AzimuthalIntegrator(dist=dist, detector=detector, wavelength=calibrant.wavelength) c.peakPicker = PeakPicker(img, reconst=True, mask=detector.mask, pointfile=c.pointfile, calibrant=calibrant, wavelength=calibrant.wavelength) # method=method) if gaussian is not None: c.peakPicker.massif.setValleySize(gaussian) else: c.peakPicker.massif.initValleySize() if interactive: c.peakPicker.gui(log=True, maximize=True, pick=True) update_fig(c.peakPicker.fig) c.gui_peakPicker() c.ai.setPyFAI(**c.geoRef.getPyFAI()) c.ai.wavelength = c.geoRef.wavelength return c.ai
def run_calibration(exposure=60, calibrant_file=None, wavelength=None, detector=None, gaussian=None): """ function to run entire calibration process. Entire process includes: collect calibration image, trigger pyFAI calibration process, store calibration parameters as a yaml file under xpdUser/config_base/ and inject uid of calibration image to following scans, until this function is run again. Parameters ---------- exposure : int, optional total exposure time in sec. Default is 60s calibrant_name : str, optional name of calibrant used, different calibrants correspond to different d-spacing profiles. Default is 'Ni'. User can assign different calibrant, given d-spacing file path presents wavelength : flot, optional current of x-ray wavelength, in angstrom. Default value is read out from existing xpdacq.Beamtime object detector : pyfai.detector.Detector, optional. instance of detector which defines pxiel size in x- and y-direction. Default is set to Perkin Elmer detector gaussian : int, optional gaussian width between rings, Default is 100. """ # default params interactive = True dist = 0.1 _check_obj(_REQUIRED_OBJ_LIST) ips = get_ipython() bto = ips.ns_table['user_global']['bt'] prun = ips.ns_table['user_global']['prun'] # print('*** current beamtime info = {} ***'.format(bto.md)) calibrant = Calibrant() # d-spacing if calibrant_file is not None: calibrant.load_file(calibrant_file) calibrant_name = os.path.split(calibrant_file)[1] calibrant_name = os.path.splitext(calibrant_name)[0] else: calibrant.load_file(os.path.join(glbl.usrAnalysis_dir, 'Ni24.D')) calibrant_name = 'Ni' # wavelength if wavelength is None: _wavelength = bto['bt_wavelength'] else: _wavelength = wavelength calibrant.wavelength = _wavelength * 10 ** (-10) # detector if detector is None: detector = Perkin() # scan # simplified version of Sample object calib_collection_uid = str(uuid.uuid4()) calibration_dict = {'sample_name':calibrant_name, 'sample_composition':{calibrant_name :1}, 'is_calibration': True, 'calibration_collection_uid': calib_collection_uid} prun_uid = prun(calibration_dict, ScanPlan(bto, ct, exposure)) light_header = glbl.db[prun_uid[-1]] # last one is always light dark_uid = light_header.start['sc_dk_field_uid'] dark_header = glbl.db[dark_uid] # unknown signature of get_images dark_img = np.asarray( get_images(dark_header, glbl.det_image_field)).squeeze() # dark_img = np.asarray(glbl.get_images(dark_header, glbl.det_image_field)).squeeze() for ev in glbl.get_events(light_header, fill=True): img = ev['data'][glbl.det_image_field] img -= dark_img # calibration timestr = _timestampstr(time.time()) basename = '_'.join(['pyFAI_calib', calibrant_name, timestr]) w_name = os.path.join(glbl.config_base, basename) # poni name c = Calibration(wavelength=calibrant.wavelength, detector=detector, calibrant=calibrant, gaussianWidth=gaussian) c.gui = interactive c.basename = w_name c.pointfile = w_name + ".npt" c.ai = AzimuthalIntegrator(dist=dist, detector=detector, wavelength=calibrant.wavelength) c.peakPicker = PeakPicker(img, reconst=True, mask=detector.mask, pointfile=c.pointfile, calibrant=calibrant, wavelength=calibrant.wavelength) # method=method) if gaussian is not None: c.peakPicker.massif.setValleySize(gaussian) else: c.peakPicker.massif.initValleySize() if interactive: c.peakPicker.gui(log=True, maximize=True, pick=True) update_fig(c.peakPicker.fig) c.gui_peakPicker() c.ai.setPyFAI(**c.geoRef.getPyFAI()) c.ai.wavelength = c.geoRef.wavelength # update until next time glbl.calib_config_dict = c.ai.getPyFAI() Fit2D_dict = c.ai.getFit2D() glbl.calib_config_dict.update(Fit2D_dict) glbl.calib_config_dict.update({'file_name':basename}) glbl.calib_config_dict.update({'time':timestr}) # FIXME: need a solution for selecting desired calibration image # based on calibration_collection_uid later glbl.calib_config_dict.update({'calibration_collection_uid': calib_collection_uid}) # write yaml yaml_name = glbl.calib_config_name with open(os.path.join(glbl.config_base, yaml_name), 'w') as f: yaml.dump(glbl.calib_config_dict, f) return c.ai