Ejemplo n.º 1
0
    def __init__(
            self,
            idx=None,
            map_raw=None,
            poni=None,
            mask=None,
            scan_info={},
            ai_args={},
            file_lock=Condition(),
            # poni_file=None, static=False, poni_dict=None,
            static=False,
            poni_dict=None,
            gi=False,
            th_mtr='th',
            tilt_angle=0):
        # pylint: disable=too-many-arguments
        """idx: int, name of the arch.
        map_raw: numpy array, raw image data
        poni: PONI object, calibration data
        mask: None or numpy array, indices of pixels to mask
        scan_info: dict, metadata about scan
        ai_args: dict, args to be fed to azimuthalIntegrator constructor
        file_lock: Condition, lock for file access.
        """
        super(EwaldArch, self).__init__()
        self.idx = idx
        self.map_raw = map_raw
        if poni is None:
            self.poni = PONI()
        else:
            self.poni = poni
        # self.poni_file = poni_file
        self.poni_dict = poni_dict
        if mask is None and map_raw is not None:
            self.mask = np.arange(map_raw.size)[map_raw.flatten() < 0]
        else:
            self.mask = mask
        self.scan_info = scan_info
        self.ai_args = ai_args
        self.file_lock = file_lock

        self.static = static
        self.gi = gi
        self.th_mtr = th_mtr
        self.tilt_angle = tilt_angle

        self.integrator = self.setup_integrator()

        self.arch_lock = Condition()
        self.map_norm = 1

        if self.static:
            self.int_1d = int_1d_data_static()
            self.int_2d = int_2d_data_static()
        else:
            self.int_1d = int_1d_data()
            self.int_2d = int_2d_data()
Ejemplo n.º 2
0
 def reset(self):
     """Clears all data, resets to a default EwaldArch.
     """
     self.idx = None
     self.map_raw = None
     self.poni = PONI()
     # self.poni_file = None
     self.poni_dict = None
     self.mask = None
     self.scan_info = {}
     self.integrator = self.setup_integrator()
     self.map_norm = 1
     if self.static:
         self.int_1d = int_1d_data_static()
         self.int_2d = int_2d_data_static()
     else:
         self.int_1d = int_1d_data()
         self.int_2d = int_2d_data()
Ejemplo n.º 3
0
    def load_from_h5(self, file, load_2d=True):
        """Loads data from hdf5 file and sets attributes.

        args:
            file: h5py file or group object
        """
        with self.file_lock:
            with self.arch_lock:
                if str(self.idx) not in file:
                    print("No data can be found")
                else:
                    grp = file[str(self.idx)]
                    if 'type' in grp.attrs:
                        if grp.attrs['type'] == 'EwaldArch':
                            lst_attr = [
                                "map_raw", "mask", "map_norm", "scan_info",
                                "ai_args", "gi", "static", "poni_dict"
                                # "poni_file", "gi", "static", "poni_dict"
                            ]
                            utils.h5_to_attributes(self, grp, lst_attr)
                            self.int_1d.from_hdf5(grp['int_1d'])
                            if load_2d:
                                self.int_2d.from_hdf5(grp['int_2d'])
                            self.poni = PONI.from_yamdict(
                                utils.h5_to_dict(grp['poni']))

                            # if self.poni_file is not None:
                            if self.poni_dict is not None:
                                self.integrator = create_ai_from_dict(
                                    self.poni_dict)
                                # if not self.gi:
                                #     self.integrator = pyFAI.load(self.poni_file)
                                #     self.integrator._rot3 -= np.deg2rad(90)
                                # else:
                                #     pFAI = pyFAI.load(self.poni_file)
                                #     calib_pars = dict(
                                #         dist=pFAI.dist, poni1=pFAI.poni1, poni2=pFAI.poni2,
                                #         rot1=pFAI.rot1, rot2=pFAI.rot2, rot3=pFAI.rot3,
                                #         wavelength=pFAI.wavelength, detector=pFAI.detector)
                                #     self.integrator = pygix.Transform(**calib_pars)
                                #     self.integrator.sample_orientation = 3  # 1 is horizontal, 2 is vertical
                                #     self.integrator.incident_angle = 1  # incident angle in deg
                                #     self.integrator.tilt_angle = 0  # tilt angle of sample in deg (misalignment in "chi")

                            else:
                                self.integrator = AzimuthalIntegrator(
                                    dist=self.poni.dist,
                                    poni1=self.poni.poni1,
                                    poni2=self.poni.poni2,
                                    rot1=self.poni.rot1,
                                    rot2=self.poni.rot2,
                                    rot3=self.poni.rot3,
                                    wavelength=self.poni.wavelength,
                                    detector=self.poni.detector,
                                    **self.ai_args)
Ejemplo n.º 4
0
 def _set_base(self):
     """Adjusts base calibration based on where calibration was
     performed.
     """
     base = PONI.from_ponifile(self.inputs['poni_file'])
     for key, val in self.inputs['calib_rotations'].items():
         try:
             r = getattr(base, key) - val
         except TypeError:
             r = getattr(base, key)
         setattr(base, key, r)
     self.base = base
Ejemplo n.º 5
0
def make_sphere(calib_path, poni_file, stepsize, user, image_path, spec_path,
                spec_name, scan_number):
    tth, i0 = SPECread(spec_path + spec_name, scan_number)
    xmax_global = 0.0
    xmin_global = 180.0
    times = {'overall': [], 'creation': [], 'int': [], 'add': []}
    detector = pyFAI.detectors.Detector(172e-6, 172e-6)
    data_file_path = os.path.join(xdart_dir,
                                  "tests/test_data/spec_pd100k/test_save.h5")
    sphere = EwaldSphere(data_file=data_file_path)
    sphere.save_to_h5(replace=True)
    poni = PONI.from_ponifile(os.path.join(calib_path, poni_file))
    for k in range(1, len(tth)):
        start = time.time()
        filename = (image_path + user + spec_name + "_scan" +
                    str(scan_number) + "_" + str(k).zfill(4) + ".raw")
        map_raw = read_RAW(filename)
        map_raw = map_raw.T
        mask = np.where(map_raw < 0, 1, 0)
        rot2 = np.radians(-tth[k])
        poni.rot2 = rot2
        start_c = time.time()
        arch = EwaldArch(idx=k,
                         map_raw=map_raw,
                         poni=poni,
                         scan_info={'i0': i0[k]})
        times['creation'].append(time.time() - start_c)
        start_i = time.time()
        arch.integrate_1d(numpoints=18000,
                          monitor='i0',
                          radial_range=[0, 180],
                          unit=units.TTH_DEG,
                          correctSolidAngle=False,
                          method='csr')
        arch.integrate_2d(npt_rad=1000,
                          npt_azim=1000,
                          monitor='i0',
                          radial_range=[0, 30],
                          azimuth_range=[70, 110],
                          method='csr')
        times['int'].append(time.time() - start_i)
        start_a = time.time()
        sphere.add_arch(arch.copy(), calculate=False, set_mg=False)
        sphere.save_to_h5(arches=[k], data_only=True, replace=False)
        times['add'].append(time.time() - start_a)

        times['overall'].append(time.time() - start)
    return sphere
Ejemplo n.º 6
0
    def run(self):
        """Main method of operation, calculates values for new PONI
        object.
        
        returns:
            outputs: dict, values to create a PONI object.
        """
        if self.base is None:
            self._set_base()
        poni = PONI.from_ponifile(self.inputs['poni_file'])

        for key, val in self.inputs['rotations'].items():
            if val is not None:
                r = np.radians(-self.inputs['spec_dict'][val]) + getattr(
                    self.base, key)
                setattr(poni, key, r)

        self.outputs.update(poni.to_dict())

        return self.outputs
Ejemplo n.º 7
0
    def _main(self):
        """Checks for commands in queue, sends back updates through
        signal queue, and catches errors. Calls wrangle method for
        reading in data, then performs integration.
        """
        # ic()
        # Initialize sphere and save to disk, send update for new scan
        sphere = EwaldSphere(self.scan_name,
                             data_file=self.fname,
                             **self.sphere_args)
        sphere.global_mask = self.mask
        with self.file_lock:
            sphere.save_to_h5(replace=True)
            self.signal_q.put(('new_scan', None))

        # Operation instantiated within process to avoid conflicts with locks
        make_poni = MakePONI()
        make_poni.inputs.update(self.mp_inputs)

        # full spec path grabbed from lsf_inputs
        # TODO: just give full spec path as argument
        spec_path = os.path.join(self.lsf_inputs['spec_file_path'],
                                 self.lsf_inputs['spec_file_name'])

        # Enter main loop
        i = 0
        pause = False
        start = time.time()
        while True:
            # Check for commands, or wait if paused
            if not self.command_q.empty() or pause:
                command = self.command_q.get()
                print(command)
                if command == 'stop':
                    break
                elif command == 'continue':
                    pause = False
                elif command == 'pause':
                    pause = True
                    continue

            # ic(i, spec_path)
            # Get result from wrangle
            try:
                flag, data = self.wrangle(i, spec_path, make_poni)
            # Errors associated with image not yet taken
            except (KeyError, FileNotFoundError, AttributeError, ValueError):
                elapsed = time.time() - start
                if elapsed > self.timeout:
                    self.signal_q.put(('message', "Timeout occurred"))
                    self.signal_q.put(('TERMINATE', None))
                    break
                else:
                    continue
            start = time.time()

            # Unpack data and load into sphere
            # TODO: Test how long integrating vs io takes
            if flag == 'image':
                idx, map_raw, scan_info, poni = data
                arch = EwaldArch(idx,
                                 map_raw,
                                 PONI.from_yamdict(poni),
                                 scan_info=scan_info)

                # integrate image to 1d and 2d arrays
                arch.integrate_1d(global_mask=self.mask, **sphere.bai_1d_args)
                arch.integrate_2d(global_mask=self.mask, **sphere.bai_2d_args)

                # Add arch copy to sphere, save to file
                with self.file_lock:
                    sphere.add_arch(arch=arch.copy(),
                                    calculate=False,
                                    update=True,
                                    get_sd=True,
                                    set_mg=False)
                    sphere.save_to_h5(data_only=True, replace=False)

                self.signal_q.put(('message', f'Image {i} integrated'))
                self.signal_q.put(('update', idx))
                i += 1

            # Check if terminate signal sent
            elif flag == 'TERMINATE' and data is None:
                self.signal_q.put(('TERMINATE', None))
                break

        # If loop ends, signal terminate to parent thread.
        self.signal_q.put(('TERMINATE', None))
Ejemplo n.º 8
0
    def run(self):
        """Main method. Takes in file paths from queues fed by watcher,
        reads in the metadata from pdi file and image data from raw
        file. Integrates data and stores it in hdf5 file.
        """
        # TODO: This should be _main not run

        # Initialize MakePONI
        self.scan_name = None
        make_poni = MakePONI()
        make_poni.inputs.update(self.mp_inputs)

        # Main loop.
        while True:
            # Check queues for new file paths
            for key, q in self.queues.items():
                added = q.get()
                self.signal_q.put(('message', added))
                if added == 'BREAK':
                    self.signal_q.put(('TERMINATE', None))
                    return
                elif key == 'pdi':
                    pdi_file = added
                elif key == 'raw':
                    raw_file = added
                    print(added)

            # Parse file for scan name
            scan_name, i = self.parse_file(raw_file)

            # If new scan has started, create new sphere object
            if scan_name != self.scan_name:
                self.scan_name = scan_name
                sphere = EwaldSphere(name=scan_name,
                                     data_file=os.path.join(
                                         self.out_dir, scan_name + ".hdf5"),
                                     **self.sphere_args)
                sphere.save_to_h5(replace=True)
                self.signal_q.put(
                    ('new_scan', (sphere.name, sphere.data_file)))
            while True:
                # Looks for relevant data, loops until it is found or a
                # timeout occurs
                try:
                    arr = self.read_raw(raw_file)

                    # Get pdi name from raw name, ensures one for one
                    raw_fname = os.path.basename(raw_file)
                    #pdi_path = os.path.dirname(pdi_file)
                    pdi_file = os.path.join(self.pdi_dir, f'{raw_fname}.pdi')

                    print(pdi_file)

                    image_meta = self.read_pdi(pdi_file)

                    make_poni.inputs['spec_dict'] = copy.deepcopy(image_meta)

                    poni = copy.deepcopy(make_poni.run())
                    break

                except (KeyError, FileNotFoundError, AttributeError,
                        ValueError) as e:
                    # Handle exceptions related to files not being
                    # ready yet
                    print(type(e))
                    traceback.print_tb(e.__traceback__)

            with self.file_lock:
                # Add data to sphere
                sphere.add_arch(calculate=True,
                                update=True,
                                get_sd=True,
                                set_mg=False,
                                idx=i,
                                map_raw=arr,
                                poni=PONI.from_yamdict(poni),
                                scan_info=image_meta)
            self.signal_q.put(('update', i))
Ejemplo n.º 9
0
class EwaldArch():
    """Class for storing area detector data collected in
    X-ray diffraction experiments.

    Attributes:
        ai_args: dict, arguments passed to AzimuthalIntegrator
        arch_lock: Condition, threading lock used to ensure only one
            process can access data at a time
        file_lock: Condition, lock to ensure only one writer to
            data file
        idx: int, integer name of arch
        int_1d: int_1d_data/_static object from containers (for scanning/static detectors)
        int_2d: int_2d_data/_static object from containers (for scanning/static detectors)
        integrator: AzimuthalIntegrator object from pyFAI
        map_raw: numpy 2d array of the unprocessed image data
        map_norm: float, normalization constant
        mask: numpy array of indeces to be masked in array.
        poni: poni data for integration
        poni_file: raw poni_file name with path used for static detector integration
        poni_dict: poni_file information saved in dictionary
        scan_info: dict, information from any relevant motors and
            sensors
        static: bool, flag to specify if detector is static
        gi: bool, flag to specify if scattering geometry is grazing incidence
        th_mtr: str, the motor that controls sample rotation in gi mode
        tilt_angle: float, chi offset in gi geometry

    Methods:
        copy: create copy of arch
        get_mask: return mask array to feed into integrate1d
        integrate_1d: integrate the image data, results stored in
            int_1d_data
        integrate_2d: integrate the image data, results stored in
            int_2d_data
        load_from_h5: load data from hdf5 file
        save_to_h5: save data to hdf5 file
        set_integrator: set new integrator
        set_map_raw: replace raw data
        set_mask: replace mask data
        set_poni: replace poni object
        set_scan_info: replace scan_info
    """

    # pylint: disable=too-many-instance-attributes

    def __init__(
            self,
            idx=None,
            map_raw=None,
            poni=None,
            mask=None,
            scan_info={},
            ai_args={},
            file_lock=Condition(),
            # poni_file=None, static=False, poni_dict=None,
            static=False,
            poni_dict=None,
            gi=False,
            th_mtr='th',
            tilt_angle=0):
        # pylint: disable=too-many-arguments
        """idx: int, name of the arch.
        map_raw: numpy array, raw image data
        poni: PONI object, calibration data
        mask: None or numpy array, indices of pixels to mask
        scan_info: dict, metadata about scan
        ai_args: dict, args to be fed to azimuthalIntegrator constructor
        file_lock: Condition, lock for file access.
        """
        super(EwaldArch, self).__init__()
        self.idx = idx
        self.map_raw = map_raw
        if poni is None:
            self.poni = PONI()
        else:
            self.poni = poni
        # self.poni_file = poni_file
        self.poni_dict = poni_dict
        if mask is None and map_raw is not None:
            self.mask = np.arange(map_raw.size)[map_raw.flatten() < 0]
        else:
            self.mask = mask
        self.scan_info = scan_info
        self.ai_args = ai_args
        self.file_lock = file_lock

        self.static = static
        self.gi = gi
        self.th_mtr = th_mtr
        self.tilt_angle = tilt_angle

        self.integrator = self.setup_integrator()

        self.arch_lock = Condition()
        self.map_norm = 1

        if self.static:
            self.int_1d = int_1d_data_static()
            self.int_2d = int_2d_data_static()
        else:
            self.int_1d = int_1d_data()
            self.int_2d = int_2d_data()

    def setup_integrator(self):
        """Sets up integrator object"""
        # if self.poni_file is not None:
        if self.poni_dict is not None:
            # poni_dict = get_poni_dict(self.poni_file)
            integrator = create_ai_from_dict(self.poni_dict, self.gi)
            # if not self.gi:
            #     integrator = pyFAI.load(self.poni_file)
            #     integrator._rot3 -= np.deg2rad(90)
            # else:
            #     pFAI = pyFAI.load(self.poni_file)
            #     calib_pars = dict(
            #         dist=pFAI.dist, poni1=pFAI.poni1, poni2=pFAI.poni2,
            #         rot1=pFAI.rot1, rot2=pFAI.rot2, rot3=pFAI.rot3,
            #         wavelength=pFAI.wavelength, detector=pFAI.detector)
            #     integrator = pygix.Transform(**calib_pars)
            #     integrator.sample_orientation = 3  # 1 is horizontal, 2 is vertical

        else:
            integrator = AzimuthalIntegrator(dist=self.poni.dist,
                                             poni1=self.poni.poni1,
                                             poni2=self.poni.poni2,
                                             rot1=self.poni.rot1,
                                             rot2=self.poni.rot2,
                                             rot3=self.poni.rot3,
                                             wavelength=self.poni.wavelength,
                                             detector=self.poni.detector,
                                             **self.ai_args)
        return integrator

    def reset(self):
        """Clears all data, resets to a default EwaldArch.
        """
        self.idx = None
        self.map_raw = None
        self.poni = PONI()
        # self.poni_file = None
        self.poni_dict = None
        self.mask = None
        self.scan_info = {}
        self.integrator = self.setup_integrator()
        self.map_norm = 1
        if self.static:
            self.int_1d = int_1d_data_static()
            self.int_2d = int_2d_data_static()
        else:
            self.int_1d = int_1d_data()
            self.int_2d = int_2d_data()

    def get_mask(self, global_mask=None):
        if global_mask is not None:
            mask_idx = np.unique(np.append(self.mask, global_mask))
            mask_idx.sort()
        else:
            mask_idx = self.mask
        mask = np.zeros(self.map_raw.size, dtype=int)
        try:
            mask[mask_idx] = 1
            return mask.reshape(self.map_raw.shape)
        except IndexError:
            print('Mask File Shape Mismatch')
            return mask

    def integrate_1d(self,
                     numpoints=10000,
                     radial_range=None,
                     monitor=None,
                     unit=units.TTH_DEG,
                     global_mask=None,
                     **kwargs):
        """Wrapper for integrate1d method of AzimuthalIntegrator from pyFAI.
        Returns result and also stores the data in the int_1d object.

        args:
            numpoints: int, number of points in final array
            radial_range: tuple or list, lower and upper end of integration
            monitor: str, keyword for normalization counter in scan_info
            unit: pyFAI unit for integration, units.TTH_DEG, units.Q_A,
                '2th_deg', or 'q_A^-1'
            kwargs: other keywords to be passed to integrate1d, see pyFAI docs.

        returns:
            result: integrate1d result from pyFAI.
        """
        if (not self.static) and (radial_range is None):
            radial_range = [0, 180]

        with self.arch_lock:
            if self.static:
                self.map_norm = 1
            elif monitor is not None:
                self.map_norm = self.scan_info[monitor]

            if self.mask is None:
                self.mask = np.arange(
                    self.map_raw.size)[self.map_raw.flatten() < 0]

            if not self.gi:
                result = self.integrator.integrate1d(
                    self.map_raw / self.map_norm,
                    numpoints,
                    unit=unit,
                    radial_range=radial_range,
                    mask=self.get_mask(global_mask),
                    **kwargs)

                wavelength = self.poni.wavelength
                if self.static:
                    wavelength = self.integrator.wavelength
                self.int_1d.from_result(result, wavelength, unit=unit)
            else:
                pg_args = [
                    'process', 'filename', 'correctSolidAngle', 'variance',
                    'error_model', 'dummy', 'delta_dummy',
                    'polarization_factor', 'dark', 'flat', 'method', 'safe',
                    'normalization_factor'
                ]
                pg_args = {k: v for (k, v) in kwargs.items() if k in pg_args}

                # incident angle in deg
                try:
                    self.integrator.incident_angle = self.scan_info[
                        self.th_mtr]
                except KeyError:
                    pass
                # tilt angle of sample in deg (misalignment in "chi")
                self.integrator.tilt_angle = self.tilt_angle

                Intensity, qAxis = self.integrator.integrate_1d(
                    self.map_raw / self.map_norm,
                    numpoints,
                    unit='q_A^-1',
                    p0_range=radial_range,
                    p1_range=kwargs['azimuth_range'],
                    mask=self.get_mask(global_mask),
                    **pg_args)
                result = Integrate1dResult(qAxis, Intensity)

                self.int_1d.from_result(result,
                                        self.integrator.wavelength,
                                        unit='q_A^-1')

        # q = result.radial
        # return result

    def integrate_2d(self,
                     npt_rad=1000,
                     npt_azim=1000,
                     monitor=None,
                     radial_range=None,
                     azimuth_range=None,
                     x_range=None,
                     y_range=None,
                     unit=units.TTH_DEG,
                     global_mask=None,
                     **kwargs):
        """Wrapper for integrate2d method of AzimuthalIntegrator from pyFAI.
        Returns result and also stores the data in the int_2d object.

        args:
            npt_rad: int, number of points in radial dimension. If
                None, will take number from the shape of map_norm
            npt_azim: int, number of points in azimuthal dimension. If
                None, will take number from the shape of map_norm
            radial_range: tuple or list, lower and upper end of integration
            azimuth_range: tuple or list, lower and upper end of integration
                in azimuthal direction
            monitor: str, keyword for normalization counter in scan_info
            unit: pyFAI unit for integration, units.TTH_DEG, units.Q_A,
                '2th_deg', or 'q_A^-1'
            kwargs: other keywords to be passed to integrate2d, see pyFAI docs.

        returns:
            result: integrate2d result from pyFAI.
        """
        if (not self.static) and (radial_range is None):
            radial_range = [0, 180]
        if (not self.static) and (azimuth_range is None):
            azimuth_range = [-180, 180]

        with self.arch_lock:
            if monitor is not None:
                if self.static:
                    self.map_norm = 1
                else:
                    self.map_norm = self.scan_info[monitor]

            if self.mask is None:
                self.mask = np.arange(
                    self.map_raw.size)[self.map_raw.flatten() < 0]

            if npt_rad is None:
                npt_rad = self.map_raw.shape[0]

            if npt_azim is None:
                npt_azim = self.map_raw.shape[1]

            if not self.gi:
                result = self.integrator.integrate2d(
                    self.map_raw / self.map_norm,
                    npt_rad,
                    npt_azim,
                    unit=unit,
                    mask=self.get_mask(global_mask),
                    radial_range=radial_range,
                    azimuth_range=azimuth_range,
                    **kwargs)
                wavelength = self.poni.wavelength
                if self.static:
                    wavelength = self.integrator.wavelength
                self.int_2d.from_result(result, wavelength, unit=unit)
            else:
                pg_args = [
                    'filename', 'correctSolidAngle', 'variance', 'error_model',
                    'dummy', 'delta_dummy', 'polarization_factor', 'dark',
                    'flat', 'method', 'safe', 'normalization_factor'
                ]
                pg_args = {k: v for (k, v) in kwargs.items() if k in pg_args}

                # incident angle in deg
                self.integrator.incident_angle = self.scan_info[self.th_mtr]
                # tilt angle of sample in deg (misalignment in "chi")
                self.integrator.tilt_angle = self.tilt_angle

                if unit == '2th_deg':
                    radial_range = self.convert_radial_range(
                        radial_range, self.integrator.wavelength)

                # Transform to polar (Q-Chi) coordinates
                i_qchi, Q, Chi = self.integrator.transform_image(
                    self.map_raw,
                    process='polar',
                    npt=(npt_rad, npt_azim),
                    x_range=radial_range,
                    y_range=azimuth_range,
                    unit='q_A^-1',
                    mask=self.get_mask(global_mask),
                    all=False,
                    **pg_args)
                result = Integrate2dResult(i_qchi, Q, Chi)

                # Transform to reciprocal (Qz-Qxy) coordinates
                i_QxyQz, qxy, qz = self.integrator.transform_image(
                    self.map_raw,
                    process='reciprocal',
                    npt=(npt_rad, npt_azim),
                    x_range=x_range,
                    y_range=y_range,
                    unit='q_A^-1',
                    mask=self.get_mask(),
                    all=False,
                    **pg_args)

                self.int_2d.from_result(result,
                                        self.integrator.wavelength,
                                        unit=unit,
                                        i_QxyQz=np.flipud(i_QxyQz),
                                        qz=qz,
                                        qxy=qxy)

    def set_integrator(self, **args):
        """Sets AzimuthalIntegrator with new arguments.

        args:
            args: see pyFAI for acceptable arguments for the integrator
                constructor.

        returns:
            None
        """

        with self.arch_lock:
            self.ai_args = args
            self.integrator = self.setup_integrator()

    def set_map_raw(self, new_data):
        with self.arch_lock:
            self.map_raw = new_data
            if self.mask is None:
                self.mask = np.arange(new_data.size)[new_data.flatten() < 0]

    def set_poni(self, new_data):
        with self.arch_lock:
            self.poni = new_data

    def set_mask(self, new_data):
        with self.arch_lock:
            self.mask = new_data

    def set_scan_info(self, new_data):
        with self.arch_lock:
            self.scan_info = new_data

    @staticmethod
    def convert_radial_range(radial_range, wavelength):
        """Convert radial range from Q (AA-1) to 2Th (deg)"""
        if radial_range is None:
            return None

        radial_range = np.asarray(radial_range)
        radial_range = (4 * np.pi / (wavelength * 1e10)) *\
            np.sin(np.radians(radial_range / 2))

        return radial_range

    def save_to_h5(self, file, compression='lzf'):
        """Saves data to hdf5 file using h5py as backend.

        args:
            file: h5py group or file object.

        returns:
            None
        """
        if self.static:
            compression = None
        with self.file_lock:
            if str(self.idx) in file:
                grp = file[str(self.idx)]
            else:
                grp = file.create_group(str(self.idx))
            grp.attrs['type'] = 'EwaldArch'
            lst_attr = [
                "map_raw",
                "mask",
                "map_norm",
                "scan_info",
                "ai_args",
                # "poni_file", "gi", "static", "poni_dict"
                "gi",
                "static",
                "poni_dict"
            ]
            utils.attributes_to_h5(self,
                                   grp,
                                   lst_attr,
                                   compression=compression)
            if 'int_1d' not in grp:
                grp.create_group('int_1d')
            self.int_1d.to_hdf5(grp['int_1d'], compression)
            if 'int_2d' not in grp:
                grp.create_group('int_2d')
            self.int_2d.to_hdf5(grp['int_2d'], compression)
            if 'poni' not in grp:
                grp.create_group('poni')
            utils.dict_to_h5(self.poni.to_dict(), grp, 'poni')

    def load_from_h5(self, file, load_2d=True):
        """Loads data from hdf5 file and sets attributes.

        args:
            file: h5py file or group object
        """
        with self.file_lock:
            with self.arch_lock:
                if str(self.idx) not in file:
                    print("No data can be found")
                else:
                    grp = file[str(self.idx)]
                    if 'type' in grp.attrs:
                        if grp.attrs['type'] == 'EwaldArch':
                            lst_attr = [
                                "map_raw", "mask", "map_norm", "scan_info",
                                "ai_args", "gi", "static", "poni_dict"
                                # "poni_file", "gi", "static", "poni_dict"
                            ]
                            utils.h5_to_attributes(self, grp, lst_attr)
                            self.int_1d.from_hdf5(grp['int_1d'])
                            if load_2d:
                                self.int_2d.from_hdf5(grp['int_2d'])
                            self.poni = PONI.from_yamdict(
                                utils.h5_to_dict(grp['poni']))

                            # if self.poni_file is not None:
                            if self.poni_dict is not None:
                                self.integrator = create_ai_from_dict(
                                    self.poni_dict)
                                # if not self.gi:
                                #     self.integrator = pyFAI.load(self.poni_file)
                                #     self.integrator._rot3 -= np.deg2rad(90)
                                # else:
                                #     pFAI = pyFAI.load(self.poni_file)
                                #     calib_pars = dict(
                                #         dist=pFAI.dist, poni1=pFAI.poni1, poni2=pFAI.poni2,
                                #         rot1=pFAI.rot1, rot2=pFAI.rot2, rot3=pFAI.rot3,
                                #         wavelength=pFAI.wavelength, detector=pFAI.detector)
                                #     self.integrator = pygix.Transform(**calib_pars)
                                #     self.integrator.sample_orientation = 3  # 1 is horizontal, 2 is vertical
                                #     self.integrator.incident_angle = 1  # incident angle in deg
                                #     self.integrator.tilt_angle = 0  # tilt angle of sample in deg (misalignment in "chi")

                            else:
                                self.integrator = AzimuthalIntegrator(
                                    dist=self.poni.dist,
                                    poni1=self.poni.poni1,
                                    poni2=self.poni.poni2,
                                    rot1=self.poni.rot1,
                                    rot2=self.poni.rot2,
                                    rot3=self.poni.rot3,
                                    wavelength=self.poni.wavelength,
                                    detector=self.poni.detector,
                                    **self.ai_args)

    def copy(self, include_2d=True):
        """Returns a copy of self.
        """
        arch_copy = EwaldArch(
            copy.deepcopy(self.idx),
            None,
            copy.deepcopy(self.poni),
            None,
            copy.deepcopy(self.scan_info),
            copy.deepcopy(self.ai_args),
            self.file_lock,
            poni_dict=copy.deepcopy(self.poni_dict),
            # self.file_lock, poni_file=copy.deepcopy(self.poni_file), poni_dict=copy.deepcopy(self.poni_dict),
            static=copy.deepcopy(self.static),
            gi=copy.deepcopy(self.gi),
            th_mtr=copy.deepcopy(self.th_mtr))
        arch_copy.integrator = copy.deepcopy(self.integrator)
        arch_copy.arch_lock = Condition()
        arch_copy.int_1d = copy.deepcopy(self.int_1d)
        if include_2d:
            arch_copy.map_raw = copy.deepcopy(self.map_raw)
            arch_copy.mask = copy.deepcopy(self.mask),
            arch_copy.map_norm = copy.deepcopy(self.map_norm)
            arch_copy.int_2d = copy.deepcopy(self.int_2d)

        return arch_copy