def __init__(self, name='scan0', arches=[], data_file='scan0', scan_data=pd.DataFrame(), mg_args={'wavelength': 1e-10}, bai_1d_args={}, bai_2d_args={}): # TODO: add docstring for init super().__init__() self.name = name if arches: self.arches = pd.Series(arches, index=[a.idx for a in arches]) else: self.arches = pd.Series() self.data_file = data_file self.scan_data = scan_data self.mg_args = mg_args self.multi_geo = MultiGeometry([a.integrator for a in arches], **mg_args) self.bai_1d_args = bai_1d_args self.bai_2d_args = bai_2d_args self.mgi_1d_I = 0 self.mgi_1d_2theta = 0 self.mgi_1d_q = 0 self.mgi_2d_I = 0 self.mgi_2d_2theta = 0 self.mgi_2d_q = 0 self.file_lock = Condition() self.sphere_lock = Condition() self.bai_1d = int_1d_data() self.bai_2d = int_2d_data()
def __init__(self): self.headermodel = None self.selectionmodel = None self.multiAI = MultiGeometry([]) self.AIs = dict() widget = ParameterTree() energy = SimpleParameter(name='Energy', type='float', value=10000, siPrefix=True, suffix='eV') wavelength = SimpleParameter(name='Wavelength', type='float', value=1.239842e-6 / 10000, siPrefix=True, suffix='m') self.parameter = Parameter(name="Device Profiles", type='group', children=[energy, wavelength]) widget.setParameters(self.parameter, showTop=False) icon = QIcon(str(path('icons/calibrate.png'))) super(DeviceProfiles, self).__init__(icon, "Device Profiles", widget) self.parameter.sigValueChanged.connect(self.sigRequestRedraw) self.parameter.sigValueChanged.connect(self.sigRequestReduce) self.parameter.sigTreeStateChanged.connect(self.simulateCalibrant) self.parameter.sigTreeStateChanged.connect(self.genAIs) self.parameter.sigValueChanged.connect(self.simulateCalibrant)
def __init__(self): self.headermodel = None self.selectionmodel = None self.multiAI = MultiGeometry([]) self.AIs = dict() self._changes = [] self.isSilent = False energy = SimpleParameter(name='Energy', type='float', value=10000, siPrefix=True, suffix='eV') wavelength = SimpleParameter(name='Wavelength', type='float', value=1.239842e-6 / 10000, siPrefix=True, suffix='m') icon = QIcon(str(path('icons/calibrate.png'))) super(DeviceProfiles, self).__init__(icon, "Device Profiles", [energy, wavelength], addText='New Device') self.sigTreeStateChanged.connect(self.stateChanged)
def set_multi_geo(self, **args): """Sets the MultiGeometry instance stored in the arch. args: see pyFAI.multiple_geometry.MultiGeometry """ with self.sphere_lock: self.multi_geo = MultiGeometry([a.integrator for a in self.arches], **args) self.mg_args = args
def set_multi_geo(self, **args): """Sets the MultiGeometry instance stored in the arch. args: see pyFAI.multiple_geometry.MultiGeometry. If no args are passed, uses mg_args attribute. Otherwise, updates mg_args and uses passed arguments. """ self.mg_args.update(args) with self.sphere_lock: self.multi_geo = MultiGeometry([a.integrator for a in self.arches], **self.mg_args)
def createMg (aifiles = None): if (aifiles == None): root = Tk() aifiles = filedialog.askopenfilenames(parent=root, title='Choose multiple files') aifiles = root.tk.splitlist(aifiles) print (aifiles) root.destroy() ais = [] for file in aifiles: ais.append(pyFAI.load(file)) mg = MultiGeometry(ais, unit = "2th_deg", radial_range= (25,75) ) print (mg) return (mg)
def add_arch(self, arch=None, calculate=True, update=True, get_sd=True, set_mg=True, **kwargs): """Adds new arch to sphere. args: arch: EwaldArch instance, arch to be added. Recommended to always pass a copy of an arch with the arch.copy method calculate: whether to run the arch's calculate methods after adding update: bool, if True updates the bai_int attribute get_sd: bool, if True tries to get scan data from arch set_mg: bool, if True sets the MultiGeometry attribute. Takes a long time, especially with longer lists. Recommended to run set_multi_geo method after all arches are loaded. returns None """ with self.sphere_lock: if arch is None: arch = EwaldArch(**kwargs) if calculate: arch.integrate_1d(**self.bai_1d_args) # arch.integrate_2d(**self.bai_2d_args) arch.file_lock = self.file_lock self.arches = self.arches.append(pd.Series(arch, index=[arch.idx])) self.arches.sort_index(inplace=True) if arch.scan_info and get_sd: ser = pd.Series(arch.scan_info, dtype='float64') if list(self.scan_data.columns): try: self.scan_data.loc[arch.idx] = ser except ValueError: print('Mismatched columns') else: self.scan_data = pd.DataFrame(arch.scan_info, index=[arch.idx], dtype='float64') self.scan_data.sort_index(inplace=True) if update: self._update_bai_1d(arch) # self._update_bai_2d(arch) if set_mg: self.multi_geo = MultiGeometry( [a.integrator for a in self.arches], **self.mg_args)
def cake_saxs(inpaints, ais, masks, radial_range=(0, 60), azimuth_range=(-90, 90), npt_rad=250, npt_azim=250): """ Unwrapp the stitched image from q-space to 2theta-Chi space (Radial-Azimuthal angle) Parameters: ----------- :param inpaints: List of 2D inpainted images :type inpaints: List of ndarray :param ais: List of AzimuthalIntegrator/Transform generated using pyGIX/pyFAI which contain the information about the experiment geometry :type ais: list of AzimuthalIntegrator / TransformIntegrator :param masks: List of 2D image (same dimension as inpaints) :type masks: List of ndarray :param radial_range: minimum and maximum of the radial range in degree :type radial_range: Tuple :param azimuth_range: minimum and maximum of the 2th range in degree :type azimuth_range: Tuple :param npt_rad: number of point in the radial range :type npt_rad: int :param npt_azim: number of point in the azimuthal range :type npt_azim: int """ mg = MultiGeometry(ais, unit='q_A^-1', radial_range=radial_range, azimuth_range=azimuth_range, wavelength=None, empty=0.0, chi_disc=180) cake, q, chi = mg.integrate2d(lst_data=inpaints, npt_rad=npt_rad, npt_azim=npt_azim, correctSolidAngle=True, lst_mask=masks) return cake, q, chi[::-1]
def __init__(self): self.headermodel = None self.selectionmodel = None self.multiAI = MultiGeometry([]) self.AIs = dict() energy = SimpleParameter(name='Energy', type='float', value=10000, siPrefix=True, suffix='eV') wavelength = SimpleParameter(name='Wavelength', type='float', value=1.239842e-6 / 10000, siPrefix=True, suffix='m') incidentAngle = SimpleParameter(name='Incident Angle', type='float', value=90, siPrefix=False, suffix=u'°', limits=(0, 90)) reflection = SimpleParameter(name='Reflection', type='int', value=0, siPrefix=False, limits=(0, 1), step=1) icon = QIcon(str(path('icons/calibrate.png'))) super(DeviceProfiles, self).__init__(icon, "Device Profiles", [energy, wavelength, incidentAngle, reflection], addText='New Device') self.sigTreeStateChanged.connect(self.simulateCalibrant) self.sigTreeStateChanged.connect(self.genAIs) self.sigTreeStateChanged.connect(self.geometryChanged) self.sigGeometryChanged.connect(self.save)
def integrate_rad_saxs(inpaints, ais, masks, radial_range=(0, 40), azimuth_range=(0, 90), npt=2000): """ Radial integration of transmission data using the pyFAI multigeometry module Parameters: ----------- :param inpaints: List of 2D inpainted images :type inpaints: List of ndarray :param ais: List of AzimuthalIntegrator/Transform generated using pyGIX/pyFAI which contain the information about the experiment geometry :type ais: list of AzimuthalIntegrator / TransformIntegrator :param masks: List of 2D image (same dimension as inpaints) :type masks: List of ndarray :param radial_range: minimum and maximum of the radial range in degree :type radial_range: Tuple :param azimuth_range: minimum and maximum of the 2th range in degree :type azimuth_range: Tuple :param npt: number of point of the final 1D profile :type npt: int """ mg = MultiGeometry(ais, unit='q_A^-1', radial_range=radial_range, azimuth_range=azimuth_range, wavelength=None, empty=-1, chi_disc=180) q, i_rad = mg.integrate1d(lst_data=inpaints, npt=npt, correctSolidAngle=True, lst_mask=masks) return q, i_rad
def setUp(self): unittest.TestCase.setUp(self) self.data = fabio.open(UtilsTest.getimage("1788/moke.tif")).data self.lst_data = [ self.data[:250, :300], self.data[250:, :300], self.data[:250, 300:], self.data[250:, 300:] ] self.det = Detector(1e-4, 1e-4) self.det.max_shape = (500, 600) self.sub_det = Detector(1e-4, 1e-4) self.sub_det.max_shape = (250, 300) self.ai = AzimuthalIntegrator(0.1, 0.03, 0.03, detector=self.det) self.range = (0, 23) self.ais = [ AzimuthalIntegrator(0.1, 0.030, 0.03, detector=self.sub_det), AzimuthalIntegrator(0.1, 0.005, 0.03, detector=self.sub_det), AzimuthalIntegrator(0.1, 0.030, 0.00, detector=self.sub_det), AzimuthalIntegrator(0.1, 0.005, 0.00, detector=self.sub_det), ] self.mg = MultiGeometry(self.ais, radial_range=self.range, unit="2th_deg") self.N = 390
def run_integration(configFile, peak_detection_ratio=0.1): Run = RunInit(configFile) params = Run.params mask = fabio.open(params.maskFile).data number_of_run = Run.number_of_run image_extension = params.image_extension img_folder = params.img_folder img_prefix = params.img_prefix img_digit = int(params.img_digit) poni_files = params.poni_files img_begin = np.asarray(params.img_begin) img_end = np.asarray(params.img_end) Qlength = [ np.sqrt((Run.all_Q0[r]**2).sum(axis=2)) for r in range(number_of_run) ] m = np.array([q.min() for q in Qlength]) M = np.array([q.max() for q in Qlength]) Qmin = m.min() Qmax = M.max() print("Q min = %f" % Qmin) print("Q max = %f" % Qmax) maxipix = pyFAI.detector_factory("Maxipix_5x1") ais = [pyFAI.load(pf) for pf in poni_files] for ai in ais: ai.detector = maxipix wl = ai.wavelength * 1e10 tth_min = np.degrees(np.arcsin(Qmin * wl / 4 / np.pi)) * 2 tth_max = np.degrees(np.arcsin(Qmax * wl / 4 / np.pi)) * 2 print("tth min = %f" % tth_min) print("tth max = %f" % tth_max) allData = Run.allData_allRun mg = MultiGeometry(poni_files, radial_range=(tth_min, tth_max)) phi_points = allData.shape[1] bin_pts = 1000 I_tot = np.zeros(bin_pts) num_threads = _NUM_THREADS # """ for j in range(0, phi_points, num_threads): threads = [] for i in range(j, j + num_threads): if i < phi_points: img_data = allData[:, i, :, :] thr = Integrator(mg, i, img_data, mask, bin_pts) thr.start() threads.append(thr) for thr in threads: thr.join() I_tot += thr.I # """ I_tot = I_tot / phi_points q_tth = np.linspace(Qmin, Qmax, bin_pts) tth_q = np.linspace(tth_min, tth_max, bin_pts) outData = np.vstack([tth_q, q_tth, I_tot]) outData = outData.T outFile = splitext(configFile)[0] + "_Integrated_intensity_Q.dat" np.savetxt(outFile, outData, header=str("2Theta (deg) \t Q (1/A) \t Intensity"), fmt="%6.4f") (tth_peak, I_peak) = get_maxima(thr.tth, I_tot, threshold=peak_detection_ratio) tth_peak = np.asarray(tth_peak) Q_shell = 4 * np.pi * np.sin(np.radians(tth_peak / 2)) / wl Qout = np.vstack([tth_peak, Q_shell]) Qout = Qout.T outFile2 = splitext(configFile)[0] + "_tth_Q_peaks.dat" np.savetxt(outFile2, Qout, fmt="%6.4f", header=str("Q max = %.4f\n2Theta (deg) \t Q value (1/A)" % Qmax)) print("TTH peaks: ") print(tth_peak) fig = figure() ax = fig.add_subplot(111) ax.plot(thr.tth, I_tot, lw=2) ax.plot(tth_peak, I_peak, "ro") # for x in tth_peak: # ax.axvline(x, color="r", lw=1) ax.set_xlabel("2Theta (deg)") ax.set_ylabel("Summed intensity (a.u.)") title = splitext(configFile)[0] + " integrated intensity over phi scan" ax.set_title(title) show() saveImg = splitext(configFile)[0] + "_integrated_intensity.png" fig.savefig(saveImg)
def __init__(self, name='scan0', arches=[], data_file=None, scan_data=pd.DataFrame(), mg_args={'wavelength': 1e-10}, bai_1d_args={}, bai_2d_args={}, static=False, gi=False, th_mtr='th', overall_raw=0, single_img=False, global_mask=None, poni_dict={}): """name: string, name of sphere object. arches: list of EwaldArch object, data to intialize with data_file: str, path to hdf5 file where data is stored scan_data: DataFrame, scan metadata mg_args: dict, arguments for Multigeometry. Must include at least 'wavelength' attribute in Angstroems bai_1d_args: dict, arguments for the integrate1d method of pyFAI AzimuthalIntegrator bai_2d_args: dict, arguments for the integrate2d method of pyFAI AzimuthalIntegrator """ super().__init__() self.file_lock = Condition() if name is None: self.name = os.path.split(data_file)[-1].split('.')[0] else: self.name = name if data_file is None: self.data_file = name + ".hdf5" else: self.data_file = data_file self.static = static self.gi = gi self.th_mtr = th_mtr self.single_img = single_img if arches: self.arches = ArchSeries(self.data_file, self.file_lock, arches, static=self.static, gi=self.gi) else: self.arches = ArchSeries(self.data_file, self.file_lock, static=self.static, gi=self.gi) self.scan_data = scan_data self.mg_args = mg_args self.multi_geo = MultiGeometry([a.integrator for a in arches], **mg_args) self.bai_1d_args = bai_1d_args self.bai_2d_args = bai_2d_args self.mgi_1d = int_1d_data() self.mgi_2d = int_2d_data() self.sphere_lock = Condition(_PyRLock()) if self.static: self.bai_1d = int_1d_data_static() self.bai_2d = int_2d_data_static() else: self.bai_1d = int_1d_data() self.bai_2d = int_2d_data() self.overall_raw = overall_raw self.global_mask = global_mask self.poni_dict = poni_dict
def add_arch(self, arch=None, calculate=True, update=True, get_sd=True, set_mg=True, **kwargs): """Adds new arch to sphere. args: arch: EwaldArch instance, arch to be added. Recommended to always pass a copy of an arch with the arch.copy method or intialize with kwargs calculate: whether to run the arch's calculate methods after adding update: bool, if True updates the bai_1d and bai_2d attributes get_sd: bool, if True tries to get scan data from arch set_mg: bool, if True sets the MultiGeometry attribute. Takes a long time, especially with longer lists. Recommended to run set_multi_geo method after all arches are loaded. kwargs: If arch is None, used to intialize the EwaldArch, see EwaldArch for arguments. returns None """ with self.sphere_lock: if arch is None: arch = EwaldArch(**kwargs) if calculate: arch.integrate_1d(global_mask=self.global_mask, **self.bai_1d_args) arch.integrate_2d(global_mask=self.global_mask, **self.bai_2d_args) arch.file_lock = self.file_lock self.arches = self.arches.append(pd.Series(arch, index=[arch.idx])) self.arches.sort_index(inplace=True) if arch.scan_info and get_sd: ser = pd.Series(arch.scan_info, dtype='float64') if list(self.scan_data.columns): try: self.scan_data.loc[arch.idx] = ser except ValueError: print('Mismatched columns') else: self.scan_data = pd.DataFrame(arch.scan_info, index=[arch.idx], dtype='float64') self.scan_data.sort_index(inplace=True) with self.file_lock: with utils.catch_h5py_file(self.data_file, 'a') as file: compression = 'lzf' if self.static: compression = None utils.dataframe_to_h5(self.scan_data, file, 'scan_data', compression) if update: self._update_bai_1d(arch) self._update_bai_2d(arch) if set_mg: self.multi_geo = MultiGeometry( [a.integrator for a in self.arches], **self.mg_args) self.overall_raw += arch.map_raw
def plot_100k(files, centerx, centery, sdd, name, wavelength=.992e-10, Qchidir='./plots/'): """ Return Q,I and save the Q-Chi plot to Qchidir. Takes a list of filenames (use find_scans), centerx and centery, the sdd (in meters), wavelength (in meters), sample name, and the directory to save a Q-chi image. """ import pyFAI from pyFAI.multi_geometry import MultiGeometry from copy import deepcopy import numpy as np import matplotlib.pyplot as plt # Check this is right? The mono energy should be in the spec file (no filetype) w1 = wavelength # Create a new detector. You should also be able to import the pilatus 100k from pyFAI.detectors # but be careful, this has the angles defined differently (i.e.: positive tth = negative rot2) det = pyFAI.detectors.Detector(172e-6, 172e-6) det.max_shape = (487, 195) poni1 = (487 - centerx) * 172e-6 poni2 = centery * 172e-6 # Define ai for scan 1 ai = pyFAI.AzimuthalIntegrator(dist=sdd, poni1=poni1, poni2=poni2, detector=det) ai.set_wavelength(w1) # If you want to play with tilts, set the initial ai.rot1, rot2, rot3 here. ai.rot1 = 0 * np.pi / 180 ai.rot2 = -6 * np.pi / 180 ai.rot3 = 0 * np.pi / 180 imgs = [] ais = [] step = 1 * np.pi / 180 # For each scan, move rot2 and create a new ai using deepcopy for i in range(54): fn = files[i] img = read_raw_100k(fn) my_ai = deepcopy(ai) my_ai.rot2 -= i * step imgs.append(img) ais.append(my_ai) if i == 5: plt.imshow(img, origin='lower') mg = MultiGeometry(ais, unit="q_A^-1", radial_range=(0.5, 5)) Q, I = mg.integrate1d(imgs, 5000) # This creates and plots a Q-chi image sns.set_style("white") I2D, Q2D, chi = mg.integrate2d(imgs, 1000, 360) fig2 = plt.figure(figsize=(10, 6)) plt.imshow(I2D[245:295], origin="lower", extent=[Q2D.min(), Q2D.max(), 0, chi.max()], aspect='auto', cmap='hot') plt.xlabel('Q / $\\AA ^{-1}$', fontsize=20) plt.tick_params(axis='x', which='major', labelsize=16) plt.ylabel('chi / $\\AA ^{-1}$', fontsize=20) plt.tick_params(axis='y', which='major', labelsize=16) plt.xlim(0.5, 2.5) plt.title("{} Q vs chi".format(name), fontsize=24) figname = "{}_Q_chi.png".format(name) plt.savefig(Qchidir + figname) plt.close(fig2) return Q, I