Пример #1
0
 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()
Пример #2
0
    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
Пример #3
0
    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)
Пример #4
0
    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)
Пример #5
0
    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)
Пример #6
0
    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)
Пример #7
0
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]
Пример #8
0
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 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)
Пример #10
0
 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
Пример #11
0
 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
Пример #12
0
    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)
Пример #13
0
class TestMultiGeometry(unittest.TestCase):
    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 tearDown(self):
        unittest.TestCase.tearDown(self)
        self.data = None
        self.lst_data = None
        self.det = None
        self.sub_det = None
        self.ai = None
        self.ais = None
        self.mg = None

    def test_integrate1d(self):
        tth_ref, I_ref = self.ai.integrate1d(self.data, radial_range=self.range, npt=self.N, unit="2th_deg", method="splitpixel")
        obt = self.mg.integrate1d(self.lst_data, self.N)
        tth_obt, I_obt = obt
        self.assertEqual(abs(tth_ref - tth_obt).max(), 0, "Bin position is the same")
        # intensity need to be scaled by solid angle 1e-4*1e-4/0.1**2 = 1e-6
        delta = (abs(I_obt * 1e6 - I_ref).max())
        self.assertLessEqual(delta, 5e-5, "Intensity is the same delta=%s" % delta)

    def test_integrate2d(self):
        ref = self.ai.integrate2d(self.data, self.N, 360, radial_range=self.range, azimuth_range=(-180, 180), unit="2th_deg", method="splitpixel", all=True)
        obt = self.mg.integrate2d(self.lst_data, self.N, 360, all=True)
        self.assertEqual(abs(ref["radial"] - obt["radial"]).max(), 0, "Bin position is the same")
        self.assertEqual(abs(ref["azimuthal"] - obt["azimuthal"]).max(), 0, "Bin position is the same")
        # intensity need to be scaled by solid angle 1e-4*1e-4/0.1**2 = 1e-6
        delta = abs(obt["I"] * 1e6 - ref["I"])[obt["count"] >= 1]  # restict on valid pixel
        delta_cnt = abs(obt["count"] - ref["count"])
        delta_sum = abs(obt["sum"] * 1e6 - ref["sum"])
        if delta.max() > 1:
            logger.warning("TestMultiGeometry.test_integrate2d gave intensity difference of %s" % delta.max())
            if logger.level <= logging.DEBUG:
                from matplotlib import pyplot as plt
                f = plt.figure()
                a1 = f.add_subplot(2, 2, 1)
                a1.imshow(ref["sum"])
                a2 = f.add_subplot(2, 2, 2)
                a2.imshow(obt["sum"])
                a3 = f.add_subplot(2, 2, 3)
                a3.imshow(delta_sum)
                a4 = f.add_subplot(2, 2, 4)
                a4.plot(delta_sum.sum(axis=0))
                f.show()
                raw_input()

        self.assertLess(delta_cnt.max(), 0.001, "pixel count is the same delta=%s" % delta_cnt.max())
        self.assertLess(delta_sum.max(), 0.03, "pixel sum is the same delta=%s" % delta_sum.max())
        self.assertLess(delta.max(), 0.004, "pixel intensity is the same (for populated pixels) delta=%s" % delta.max())
Пример #14
0
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)
Пример #15
0
    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
Пример #16
0
class TestMultiGeometry(unittest.TestCase):
    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 tearDown(self):
        unittest.TestCase.tearDown(self)
        self.data = None
        self.lst_data = None
        self.det = None
        self.sub_det = None
        self.ai = None
        self.ais = None
        self.mg = None

    def test_integrate1d(self):
        tth_ref, I_ref = self.ai.integrate1d(self.data,
                                             radial_range=self.range,
                                             npt=self.N,
                                             unit="2th_deg",
                                             method="splitpixel")
        obt = self.mg.integrate1d(self.lst_data, self.N)
        tth_obt, I_obt = obt
        self.assertEqual(
            abs(tth_ref - tth_obt).max(), 0, "Bin position is the same")
        # intensity need to be scaled by solid angle 1e-4*1e-4/0.1**2 = 1e-6
        delta = (abs(I_obt * 1e6 - I_ref).max())
        self.assert_(delta < 5e-5, "Intensity is the same delta=%s" % delta)

    def test_integrate2d(self):
        ref = self.ai.integrate2d(self.data,
                                  self.N,
                                  360,
                                  radial_range=self.range,
                                  azimuth_range=(-180, 180),
                                  unit="2th_deg",
                                  method="splitpixel",
                                  all=True)
        obt = self.mg.integrate2d(self.lst_data, self.N, 360, all=True)
        self.assertEqual(
            abs(ref["radial"] - obt["radial"]).max(), 0,
            "Bin position is the same")
        self.assertEqual(
            abs(ref["azimuthal"] - obt["azimuthal"]).max(), 0,
            "Bin position is the same")
        # intensity need to be scaled by solid angle 1e-4*1e-4/0.1**2 = 1e-6
        delta = abs(obt["I"] * 1e6 -
                    ref["I"])[obt["count"] >= 1e-6]  # restrict on valid pixel
        delta_cnt = abs(obt["count"] - ref["count"])
        delta_sum = abs(obt["sum"] * 1e6 - ref["sum"])
        if delta.max() > 0:
            logger.warning(
                "TestMultiGeometry.test_integrate2d gave intensity difference of %s"
                % delta.max())
            if logger.level <= logging.DEBUG:
                from matplotlib import pyplot as plt
                f = plt.figure()
                a1 = f.add_subplot(2, 2, 1)
                a1.imshow(ref["sum"])
                a2 = f.add_subplot(2, 2, 2)
                a2.imshow(obt["sum"])
                a3 = f.add_subplot(2, 2, 3)
                a3.imshow(delta_sum)
                a4 = f.add_subplot(2, 2, 4)
                a4.plot(delta_sum.sum(axis=0))
                f.show()
                raw_input()

        self.assert_(delta_cnt.max() < 0.001,
                     "pixel count is the same delta=%s" % delta_cnt.max())
        self.assert_(delta_sum.max() < 0.03,
                     "pixel sum is the same delta=%s" % delta_sum.max())
        self.assert_(
            delta.max() < 0.004,
            "pixel intensity is the same (for populated pixels) delta=%s" %
            delta.max())
Пример #17
0
    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
Пример #18
0
class EwaldSphere:
    """Class for storing multiple arch objects, and stores a MultiGeometry
    integrator from pyFAI.

    Attributes:
        arches: ArchSeries, list of arches indexed by their idx value
        bai_1d: int_1d_data object, stores result of 1d integration
        bai_1d_args: dict, arguments for invidivual arch integrate1d
            method
        bai_2d: int_2d_data object, stores result of 2d integration
        bai_2d_args: dict, arguments for invidivual arch integrate2d
            method
        data_file: str, file to save data to
        file_lock: lock for ensuring one writer to hdf5 file
        mg_args: arguments for MultiGeometry constructor
        mgi_1d: int_1d_data object, stores result from multigeometry
            integrate1d method
        mgi_2d: int_2d_data object, stores result from multigeometry
            integrate2d method
        multi_geo: MultiGeometry instance
        name: str, name of the sphere
        scan_data: DataFrame, stores all scan metadata
        sphere_lock: lock for modifying data in sphere

    Methods:
        add_arch: adds new arch and optionally updates other data
        by_arch_integrate_1d: Runs 1 dimensional integration of each
            arch individually and sums the result, stored in bai_1d
        by_arch_integrate_2d: Runs 2 dimensional integration of each
            arch individually and sums the result, stored in bai_2d
        load_from_h5: loads data from hdf5 file
        set_multi_geo: sets the MultiGeometry instance
        multigeometry_integrate_1d: wrapper for MultiGeometry
            integrate1d method, result stored in mgi_1d
        multigeometry_integrate_2d: wrapper for MultiGeometry
            integrate2d method, result stored in mgi_2d
        save_bai_1d: Saves only bai_1d to the data_file
        save_bai_2d: Saves only bai_2d to the data_file
        save_to_h5: saves data to hdf5 file
        set_multi_geo: instatiates the multigeometry object, or
            overrides it if it already exists.
    """
    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 reset(self):
        """Resets all held data objects to blank state, called when all
        new data is going to be loaded or when a sphere needs to be
        purged of old data.
        """
        with self.sphere_lock:
            self.scan_data = pd.DataFrame()
            self.mgi_1d = int_1d_data()
            self.mgi_2d = int_2d_data()
            self.arches = ArchSeries(self.data_file,
                                     self.file_lock,
                                     static=self.static,
                                     gi=self.gi)
            self.global_mask = None
            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 = 0

    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 by_arch_integrate_1d(self, **args):
        """Integrates all arches individually, then sums the results for
        the overall integration result.

        args: see EwaldArch.integrate_1d. If any args are passed, the
            bai_1d_args dictionary is also updated with the new args.
            If no args are passed, uses bai_1d_args attribute.
        """
        if not args:
            args = self.bai_1d_args
        else:
            self.bai_1d_args = args.copy()
        with self.sphere_lock:
            if self.static:
                self.bai_1d = int_1d_data_static()
            else:
                self.bai_1d = int_1d_data()

            for arch in self.arches:
                arch.integrate_1d(global_mask=self.global_mask, **args)
                self.arches[arch.idx] = arch
                self._update_bai_1d(arch)

    def by_arch_integrate_2d(self, **args):
        """Integrates all arches individually, then sums the results for
        the overall integration result.

        args: see EwaldArch.integrate_2d. If any args are passed, the
            bai_2d_args dictionary is also updated with the new args.
            If no args are passed, uses bai_2d_args attribute.
        """
        if not args:
            args = self.bai_2d_args
        else:
            self.bai_2d_args = args.copy()
        with self.sphere_lock:
            if self.static:
                self.bai_2d = int_2d_data_static()
            else:
                self.bai_2d = int_2d_data()

            for arch in self.arches:
                arch.integrate_2d(global_mask=self.global_mask, **args)
                self.arches[arch.idx] = arch
                self._update_bai_2d(arch)

    def _update_bai_1d(self, arch):
        """helper function to update overall bai variables.
        """
        with self.sphere_lock:
            try:
                assert list(self.bai_1d.raw.shape) == list(
                    arch.int_1d.raw.shape)
            except (AssertionError, AttributeError):
                if not self.static:
                    self.bai_1d.raw = np.zeros(arch.int_1d.raw.shape)
                    self.bai_1d.pcount = np.zeros(arch.int_1d.pcount.shape)
                self.bai_1d.norm = np.zeros(arch.int_1d.norm.shape)
                self.bai_1d.sigma = np.zeros(arch.int_1d.norm.shape)
                self.bai_1d.sigma_raw = np.zeros(arch.int_1d.norm.shape)
            try:
                self.bai_1d += arch.int_1d
                self.bai_1d.ttheta = arch.int_1d.ttheta
                self.bai_1d.q = arch.int_1d.q
            except AttributeError:
                pass
            self.save_bai_1d()

    def _update_bai_2d(self, arch):
        """helper function to update overall bai variables.
        """
        with self.sphere_lock:
            try:
                # assert self.bai_2d.raw.shape == arch.int_2d.raw.shape
                if self.static:
                    assert self.bai_2d.i_qChi.shape == arch.int_2d.i_qChi.shape
                else:
                    assert self.bai_2d.norm.shape == arch.int_2d.norm.shape
            except (AssertionError, AttributeError):
                if self.static:
                    self.bai_2d.i_qChi = np.zeros(arch.int_2d.i_qChi.shape)
                    self.bai_2d.i_tthChi = np.zeros(arch.int_2d.i_tthChi.shape)
                    self.bai_2d.i_QxyQz = np.zeros(arch.int_2d.i_QxyQz.shape)
                else:
                    self.bai_2d.norm = np.zeros(arch.int_2d.norm.shape)
                    self.bai_2d.raw = np.zeros(arch.int_2d.raw.shape)
                    self.bai_2d.pcount = np.zeros(arch.int_2d.pcount.shape)
                    self.bai_2d.sigma = np.zeros(arch.int_2d.norm.shape)
                    self.bai_2d.sigma_raw = np.zeros(arch.int_2d.norm.shape)
            try:
                self.bai_2d.ttheta = arch.int_2d.ttheta
                self.bai_2d.q = arch.int_2d.q
                self.bai_2d.chi = arch.int_2d.chi
                if not self.static:
                    self.bai_2d += arch.int_2d
                else:
                    self.bai_2d.i_qChi += arch.int_2d.i_qChi
                    self.bai_2d.i_tthChi += arch.int_2d.i_tthChi
                    self.bai_2d.i_QxyQz += arch.int_2d.i_QxyQz
                    self.bai_2d.qz = arch.int_2d.qz
                    self.bai_2d.qxy = arch.int_2d.qxy
            except AttributeError:
                pass
            self.save_bai_2d()

    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 multigeometry_integrate_1d(self, monitor=None, **kwargs):
        """Wrapper for integrate1d method of MultiGeometry.

        args:
            monitor: channel with normalization value
            kwargs: see MultiGeometry.integrate1d

        returns:
            result: result from MultiGeometry.integrate1d
        """
        with self.sphere_lock:
            lst_mask = [a.get_mask() for a in self.arches]
            if monitor is None:
                try:
                    result = self.multi_geo.integrate1d(
                        [a.map_norm for a in self.arches],
                        lst_mask=lst_mask,
                        **kwargs)
                except Exception as e:
                    print(e)
                    print('Exception 1')
                    result = self.multi_geo.integrate1d(
                        [a.map_raw for a in self.arches],
                        lst_mask=lst_mask,
                        **kwargs)
            else:
                result = self.multi_geo.integrate1d(
                    [a.map_raw for a in self.arches],
                    lst_mask=lst_mask,
                    normalization_factor=list(self.scan_data[monitor]),
                    **kwargs)

            self.mgi_1d.from_result(result, self.multi_geo.wavelength)
        return result

    def multigeometry_integrate_2d(self, monitor=None, **kwargs):
        """Wrapper for integrate1d method of MultiGeometry.

        args:
            monitor: channel with normalization value
            kwargs: see MultiGeometry.integrate1d

        returns:
            result: result from MultiGeometry.integrate1d
        """
        with self.sphere_lock:
            lst_mask = [a.get_mask() for a in self.arches]
            if monitor is None:
                try:
                    result = self.multi_geo.integrate2d(
                        [a.map_raw / a.map_norm for a in self.arches],
                        lst_mask=lst_mask,
                        **kwargs)
                except Exception as e:
                    print(e)
                    print('Exception 2')
                    result = self.multi_geo.integrate2d(
                        [a.map_raw for a in self.arches],
                        lst_mask=lst_mask,
                        **kwargs)
            else:
                result = self.multi_geo.integrate2d(
                    [a.map_raw for a in self.arches],
                    lst_mask=lst_mask,
                    normalization_factor=list(self.scan_data[monitor]),
                    **kwargs)

            self.mgi_2d.from_result(result, self.multi_geo.wavelength)
        return result

    def save_to_h5(self, replace=False, *args, **kwargs):
        """Saves data to hdf5 file.

        args:
            replace: bool, if True file is truncated prior to writing
                data.
            arches: list, list of arch ids to save. Deprecated.
            data_onle: bool, if true only saves the scan_data attribute
                and does not save mg_args, bai_1d_args, or bai_2d_args.
            compression: str, what compression algorithm to pass to
                h5py. See h5py documentation for acceptable compression
                algorithms.
        """
        if replace:
            mode = 'w'
        else:
            mode = 'a'
        with self.file_lock:
            with utils.catch_h5py_file(self.data_file, mode) as file:
                self._save_to_h5(file, *args, **kwargs)

    def _save_to_h5(self,
                    grp,
                    arches=None,
                    data_only=False,
                    compression='lzf'):
        """Actual function for saving data, run with the file open and
            holding the file_lock.
        """
        if self.static:
            compression = None
        with self.sphere_lock:
            grp.attrs['type'] = 'EwaldSphere'

            if data_only:
                lst_attr = [
                    "scan_data",
                    "global_mask",
                    "overall_raw",
                ]
            else:
                lst_attr = [
                    "scan_data", "global_mask", "mg_args", "bai_1d_args",
                    "bai_2d_args", "overall_raw", "static", "gi", "th_mtr",
                    "single_img", "poni_dict"
                ]
            utils.attributes_to_h5(self,
                                   grp,
                                   lst_attr,
                                   compression=compression)

            keys = ('bai_1d', 'bai_2d', 'mgi_1d', 'mgi_2d')
            if self.static:
                keys = ('bai_1d', 'bai_2d')
            for key in keys:
                if key not in grp:
                    grp.create_group(key)
            self.bai_1d.to_hdf5(grp['bai_1d'], compression)
            self.bai_2d.to_hdf5(grp['bai_2d'], compression)
            if not self.static:
                self.mgi_1d.to_hdf5(grp['mgi_1d'], compression)
                self.mgi_2d.to_hdf5(grp['mgi_2d'], compression)

    def load_from_h5(self, replace=True, mode='r', *args, **kwargs):
        """Loads data stored in hdf5 file.

        args:
            data_only: bool, if True only loads the scan_data attribute
                and does not load mg_args, bai_1d_args, or bai_2d_args.
            set_mg: bool, if True instantiates the Multigeometry
                object.
        """
        with self.file_lock:
            if replace:
                self.reset()
            with utils.catch_h5py_file(self.data_file, mode=mode) as file:
                self._load_from_h5(file, *args, **kwargs)

    def _load_from_h5(self, grp, data_only=False, set_mg=True):
        """Actual function for loading data, run with the file open and
            holding the file_lock.
        """
        with self.sphere_lock:
            if 'type' in grp.attrs:
                if grp.attrs['type'] == 'EwaldSphere':
                    for arch in grp['arches']:
                        if int(arch) not in self.arches.index:
                            self.arches.index.append(int(arch))

                    self.arches.sort_index(inplace=True)

                    if data_only:
                        lst_attr = [
                            "scan_data",
                            "overall_raw",
                        ]
                        utils.h5_to_attributes(self, grp, lst_attr)
                    else:
                        lst_attr = [
                            "scan_data", "mg_args", "bai_1d_args",
                            "bai_2d_args", "overall_raw", "static", "gi",
                            "th_mtr", "single_img", "poni_dict"
                        ]
                        utils.h5_to_attributes(self, grp, lst_attr)
                        self._set_args(self.bai_1d_args)
                        self._set_args(self.bai_2d_args)

                        if not self.static:
                            self._set_args(self.mg_args)
                    if "global_mask" in grp:
                        utils.h5_to_attributes(self, grp, ["global_mask"])
                    else:
                        self.global_mask = None

                    self.bai_1d.from_hdf5(grp['bai_1d'])
                    self.bai_2d.from_hdf5(grp['bai_2d'])
                    if not self.static:
                        self.mgi_1d.from_hdf5(grp['mgi_1d'])
                        self.mgi_2d.from_hdf5(grp['mgi_2d'])
                        if set_mg:
                            self.set_multi_geo(**self.mg_args)

    def set_datafile(self,
                     fname,
                     name=None,
                     keep_current_data=False,
                     save_args={},
                     load_args={}):
        """Sets the data_file. If file exists and has data, loads in the
        data. Otherwise, creates new file and resets self.

        args:
            fname: str, new data file
            name: str or None, new name. If None, name is obtained from
                fname.
            keep_current_data: bool, if True overwrites any existing
                data in the file. Otherwise, current data is either
                overwritten by data in file or deleted if no data
                exists, except any args dicts which are untouched.
            save_args: dict, arguments to be passed to save_to_h5
            load_args: dict, arguments to be passed to load_from_h5
        """
        with self.sphere_lock:
            self.data_file = fname
            if name is None:
                self.name = os.path.split(fname)[-1].split('.')[0]
            else:
                self.name = name
            if keep_current_data:
                self.save_to_h5(replace=True, **save_args)
            else:
                if os.path.exists(fname):
                    self.load_from_h5(replace=True, **load_args)
                else:
                    self.reset()
                    self.save_to_h5(replace=True, **save_args)

    def save_bai_1d(self, compression='lzf'):
        """Function to save only the bai_1d object.

        args:
            compression: str, what compression algorithm to pass to
                h5py. See h5py documentation for acceptable compression
                algorithms.
        """
        compression = None
        if self.static:
            compression = None
        with self.file_lock:
            with utils.catch_h5py_file(self.data_file, 'a') as file:
                self.bai_1d.to_hdf5(file['bai_1d'], compression=compression)

    def save_bai_2d(self, compression='lzf'):
        """Function to save only the bai_2d object.

        args:
            compression: str, what compression algorithm to pass to
                h5py. See h5py documentation for acceptable compression
                algorithms.
        """
        compression = None
        if self.static:
            compression = None
        with self.file_lock:
            with utils.catch_h5py_file(self.data_file, 'a') as file:
                self.bai_2d.to_hdf5(file['bai_2d'], compression=compression)

    def _set_args(self, args):
        """Ensures any range args are lists.
        """
        for arg in args:
            if 'range' in arg:
                if args[arg] is not None:
                    args[arg] = list(args[arg])
Пример #19
0
class EwaldSphere(PawsPlugin):
    """Class for storing multiple arch objects, and stores a MultiGeometry
    integrator from pyFAI.

    Attributes:
        name: str, name of the sphere
        arches: Series, list of arches indexed by their idx value
        data_file: str, file to save data to
        scan_data: DataFrame, stores all scan metadata
        mg_args: arguments for MultiGeometry constructor
        multi_geo: MultiGeometry instance
        bai_1d_args: dict, arguments for invidivual arch integrate1d method
        bai_2d_args: not implemented
        mgi_1d_I: array, intensity from MultiGeometry based integration
        mgi_1d_2theta: array, two theta from MultiGeometry based integration
        mgi_1d_q: array, q data from MultiGeometry based integration
        mgi_2d_I: not implemented
        mgi_2d_2theta: not implemented
        mgi_2d_q: not implemented
        file_lock: lock for ensuring one writer to hdf5 file
        sphere_lock: lock for modifying data in sphere
        bai_1d: int_1d_data object for by-arch integration
        bai_2d: not implemented

    Methods:
        add_arch: adds new arch and optionally updates other data
        by_arch_integrate_1d: integrates each arch individually and sums them
        set_multi_geo: sets the MultiGeometry instance
        multigeometry_integrate_1d: wrapper for MultiGeometry integrate1d
            method
        save_to_h5: saves data to hdf5 file
        load_from_h5: loads data from hdf5 file
    """
    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 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 by_arch_integrate_1d(self, **args):
        """Integrates all arches individually, then sums the results for
        the overall integration result.

        args: see EwaldArch.integrate_1d
        """
        if not args:
            args = self.bai_1d_args
        else:
            self.bai_1d_args = args.copy()
        with self.sphere_lock:
            self.bai_1d = int_1d_data()
            for arch in self.arches:
                arch.integrate_1d(**args)
                self._update_bai_1d(arch)

    def _update_bai_1d(self, arch):
        """helper function to update overall bai variables.
        """
        self.bai_1d.raw += arch.int_1d.raw
        self.bai_1d.pcount += arch.int_1d.pcount
        self.bai_1d.norm = pawstools.div0(self.bai_1d.raw, self.bai_1d.pcount)
        self.bai_1d.ttheta = arch.int_1d.ttheta
        self.bai_1d.q = arch.int_1d.q

    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 multigeometry_integrate_1d(self, monitor=None, **kwargs):
        """Wrapper for integrate1d method of MultiGeometry.

        args:
            monitor: channel with normalization value
            kwargs: see MultiGeometry.integrate1d

        returns:
            result: result from MultiGeometry.integrate1d
        """
        with self.sphere_lock:
            lst_mask = [a.mask for a in self.arches]
            if monitor is None:
                try:
                    result = self.multi_geo.integrate1d(
                        [a.map_norm for a in self.arches],
                        lst_mask=lst_mask,
                        **kwargs)
                except Exception as e:
                    print(e)
                    result = self.multi_geo.integrate1d(
                        [a.map_raw for a in self.arches],
                        lst_mask=lst_mask,
                        **kwargs)
            else:
                result = self.multi_geo.integrate1d(
                    [a.map_raw for a in self.arches],
                    lst_mask=lst_mask,
                    normalization_factor=list(self.scan_data[monitor]),
                    **kwargs)

            self.mgi_1d_I = result.intensity

            self.mgi_1d_2theta, self.mgi_1d_q = parse_unit(
                result, self.multi_geo.wavelength)
        return result

    def save_to_h5(self, file, arches=None, data_only=False, replace=False):
        """Saves data to hdf5 file.

        args:
            file: h5py file or group object
        """
        with self.file_lock:
            if self.name in file:
                if replace:
                    del (file[self.name])
                    grp = file.create_group(self.name)
                    grp.create_group('arches')
                else:
                    grp = file[self.name]
                    if 'arches' not in grp:
                        grp.create_group('arches')
            else:
                grp = file.create_group(self.name)
                grp.create_group('arches')

            if arches is None:
                for arch in self.arches:
                    arch.save_to_h5(grp['arches'])
            else:
                for arch in self.arches[list(
                        set(self.arches.index).intersection(set(arches)))]:
                    arch.save_to_h5(grp['arches'])
            if data_only:
                lst_attr = [
                    "scan_data", "mgi_1d_q", "mgi_1d_I", "mgi_2d_2theta",
                    "mgi_2d_q", "mgi_2d_I"
                ]
            else:
                lst_attr = [
                    "data_file", "scan_data", "mg_args", "bai_1d_args",
                    "bai_2d_args", "mgi_1d_2theta", "mgi_1d_q", "mgi_1d_I",
                    "mgi_2d_2theta", "mgi_2d_q", "mgi_2d_I"
                ]
            pawstools.attributes_to_h5(self, grp, lst_attr)
            for key in ('bai_1d', 'bai_2d'):
                if key not in grp:
                    grp.create_group(key)
            pawstools.attributes_to_h5(self.bai_1d, grp['bai_1d'])
            pawstools.attributes_to_h5(self.bai_2d, grp['bai_2d'])

    def load_from_h5(self, file):
        """Loads data from hdf5 file.

        args:
            file: h5py file or group object
        """
        with self.file_lock:
            with self.sphere_lock:
                if self.name not in file:
                    print("No data can be found")
                grp = file[self.name]

                self.arches = pd.Series()
                for key in grp['arches'].keys():
                    arch = EwaldArch(idx=int(key))
                    arch.load_from_h5(grp['arches'])
                    self.add_arch(arch.copy(),
                                  calculate=False,
                                  update=False,
                                  get_sd=False,
                                  set_mg=False)

                lst_attr = [
                    "data_file", "scan_data", "mg_args", "bai_1d_args",
                    "bai_2d_args", "mgi_1d_2theta", "mgi_1d_q", "mgi_1d_I",
                    "mgi_2d_2theta", "mgi_2d_q", "mgi_2d_I"
                ]
                pawstools.h5_to_attributes(self, grp, lst_attr)
                pawstools.h5_to_attributes(self.bai_1d, grp['bai_1d'])
                pawstools.h5_to_attributes(self.bai_2d, grp['bai_2d'])
                self.set_multi_geo(**self.mg_args)
Пример #20
0
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