Exemplo n.º 1
0
class MaskDialog(BaseDialog):

    def __init__(self, parent=None):
        super(MaskDialog, self).__init__(parent)
        self.select_entry(self.choose_entry)
        self.parameters = GridParameters()
        self.parameters.add('mask', 'pilatus_mask/entry/mask', 'Mask Path')
        self.action_buttons(('Save Mask', self.save_mask))
        self.set_layout(self.entry_layout, self.parameters.grid(), 
                        self.action_buttons(('Save Mask', self.save_mask)), 
                        self.close_buttons())
        self.set_title('Mask Data')

    def save_mask(self):
        try:
            mask = self.treeview.tree[self.parameters['mask'].value]
            if mask.dtype != np.bool:
                raise NeXusError('Mask must be a Boolean array')
            elif len(mask.shape) == 1:
                raise NeXusError('Mask must be at least two-dimensional')
            elif len(mask.shape) > 2:
                mask = mask[0]                
            self.entry['instrument/detector/pixel_mask'] = mask
            self.entry['instrument/detector/pixel_mask_applied'] = False
        except NeXusError as error:
            report_error('Applying Mask', error)
Exemplo n.º 2
0
class SampleDialog(BaseDialog):

    def __init__(self, parent=None):
        super(SampleDialog, self).__init__(parent)

        self.sample = GridParameters()
        self.sample.add('sample', 'sample', 'Sample Name')
        self.sample.add('label', 'label', 'Sample Label')

        self.set_layout(self.directorybox('Choose Experiment Directory',
                                          default=False), 
                        self.sample.grid(header=False),
                        self.close_buttons(save=True))

        self.set_title('New Sample')

    def accept(self):
        home_directory = self.get_directory()
        self.mainwindow.default_directory = home_directory
        sample_directory = os.path.join(home_directory, 
                                        self.sample['sample'].value,
                                        self.sample['label'].value)
        if not os.path.exists(sample_directory):
            os.makedirs(sample_directory)
        super(SampleDialog, self).accept()
Exemplo n.º 3
0
class SettingsDialog(NXDialog):
    def __init__(self, parent=None):
        super().__init__(parent)
        try:
            self.settings = NXSettings()
            default_directory = self.settings.directory
        except NeXusError:
            self.settings = None
            default_directory = ""
        self.set_layout(
            self.directorybox('Choose Settings Directory',
                              suggestion=default_directory),
            self.close_layout(save=True))
        if self.settings:
            self.define_parameters()
        self.set_title('New Settings')

    def choose_directory(self):
        super().choose_directory()
        directory = self.get_directory()
        self.settings = NXSettings(directory=directory)
        self.define_parameters()

    def define_parameters(self):
        self.refine_parameters = GridParameters()
        defaults = self.settings.settings['nxrefine']
        for p in defaults:
            self.refine_parameters.add(p, defaults[p], p)
        self.reduce_parameters = GridParameters()
        defaults = self.settings.settings['nxreduce']
        for p in defaults:
            self.reduce_parameters.add(p, defaults[p], p)
        if self.layout.count() == 2:
            self.layout.insertLayout(
                1, self.refine_parameters.grid(header=False, title='NXRefine'))
            self.layout.insertLayout(
                2, self.reduce_parameters.grid(header=False, title='NXReduce'))

    def accept(self):
        try:
            for p in self.refine_parameters:
                self.settings.set('nxrefine', p,
                                  self.refine_parameters[p].value)
            for p in self.reduce_parameters:
                self.settings.set('nxreduce', p,
                                  self.reduce_parameters[p].value)
            self.settings.save()
            super().accept()
        except Exception as error:
            report_error("Defining New Settings", error)
Exemplo n.º 4
0
class EnergyDialog(BaseDialog):

    def __init__(self, parent=None):
        super(EnergyDialog, self).__init__(parent)

        layout = QtGui.QVBoxLayout()

        self.select_entry()
        self.parameters = GridParameters()
        self.parameters.add('m1', self.entry['monitor1/distance'], 
                            'Monitor 1 Distance')
        self.parameters.add('m2', self.entry['monitor2/distance'], 
                            'Monitor 2 Distance')
        self.parameters.add('Ei', self.entry['instrument/monochromator/energy'], 
                            'Incident Energy')
        self.parameters.add('mod', self.entry['instrument/source/distance'], 
                            'Moderator Distance')
        layout.addLayout(self.entry_layout)
        layout.addLayout(self.parameters.grid())
        layout.addLayout(self.action_buttons(('Get Ei', self.get_ei)))
        layout.addWidget(self.close_buttons(save=True))
        self.setLayout(layout)
        self.setWindowTitle('Get Incident Energy')

        self.m1 = self.entry['monitor1']
        self.m2 = self.entry['monitor2'] 

    @property
    def m1_distance(self):
        return self.parameters['m1'].value - self.moderator_distance

    @property
    def m2_distance(self):
        return self.parameters['m2'].value - self.moderator_distance

    @property
    def Ei(self):
        return self.parameters['Ei'].value

    @property
    def moderator_distance(self):
        return self.parameters['mod'].value

    def get_ei(self):
        t = 2286.26 * self.m1_distance / np.sqrt(self.Ei)
        m1_time = self.m1[t-200.0:t+200.0].moment()
        t = 2286.26 * self.m2_distance / np.sqrt(self.Ei)
        m2_time = self.m2[t-200.0:t+200.0].moment()
        self.parameters['Ei'].value = (2286.26 * (self.m2_distance - self.m1_distance) /
                                       (m2_time - m1_time))**2

    def accept(self):
        try:
            self.parameters['Ei'].save()
        except NeXusError as error:
            report_error("Getting Incident Energy", error)
        super(EnergyDialog, self).accept()
Exemplo n.º 5
0
class EnergyDialog(NXDialog):
    def __init__(self, parent=None):

        super().__init__(parent)

        self.select_entry()
        self.parameters = GridParameters()
        self.parameters.add('m1', self.entry['monitor1/distance'],
                            'Monitor 1 Distance')
        self.parameters.add('m2', self.entry['monitor2/distance'],
                            'Monitor 2 Distance')
        self.parameters.add('Ei',
                            self.entry['instrument/monochromator/energy'],
                            'Incident Energy')
        self.parameters.add('mod', self.entry['instrument/source/distance'],
                            'Moderator Distance')
        action_buttons = self.action_buttons(('Get Ei', self.get_ei))
        self.set_layout(self.entry_layout, self.parameters.grid(),
                        action_buttons, self.close_buttons(save=True))
        self.set_title('Get Incident Energy')

        self.m1 = self.entry['monitor1']
        self.m2 = self.entry['monitor2']

    @property
    def m1_distance(self):
        return self.parameters['m1'].value - self.moderator_distance

    @property
    def m2_distance(self):
        return self.parameters['m2'].value - self.moderator_distance

    @property
    def Ei(self):
        return self.parameters['Ei'].value

    @property
    def moderator_distance(self):
        return self.parameters['mod'].value

    def get_ei(self):
        t = 2286.26 * self.m1_distance / np.sqrt(self.Ei)
        m1_time = self.m1[t - 200.0:t + 200.0].moment()
        t = 2286.26 * self.m2_distance / np.sqrt(self.Ei)
        m2_time = self.m2[t - 200.0:t + 200.0].moment()
        self.parameters['Ei'].value = (2286.26 *
                                       (self.m2_distance - self.m1_distance) /
                                       (m2_time - m1_time))**2

    def accept(self):
        try:
            self.parameters['Ei'].save()
        except NeXusError as error:
            report_error("Getting Incident Energy", error)
        super().accept()
Exemplo n.º 6
0
class SampleDialog(BaseDialog):
    def __init__(self, parent=None):
        super(SampleDialog, self).__init__(parent)

        self.sample = GridParameters()
        self.sample.add('sample', 'sample', 'Sample Name')
        self.sample.add('label', 'label', 'Sample Label')

        self.set_layout(
            self.directorybox('Choose Experiment Directory', default=False),
            self.sample.grid(header=False), self.close_buttons(save=True))

        self.set_title('New Sample')

    def accept(self):
        home_directory = self.get_directory()
        self.mainwindow.default_directory = home_directory
        sample_directory = os.path.join(home_directory,
                                        self.sample['sample'].value,
                                        self.sample['label'].value)
        if not os.path.exists(sample_directory):
            os.makedirs(sample_directory)
        super(SampleDialog, self).accept()
Exemplo n.º 7
0
class ExperimentDialog(NXDialog):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.parameters = GridParameters()
        self.parameters.add('experiment', 'experiment', 'Experiment')

        self.set_layout(
            self.directorybox('Choose Home Directory', default=False),
            self.parameters.grid(header=False), self.close_layout(save=True))
        self.set_title('New Experiment')

    def accept(self):
        try:
            home_directory = self.get_directory()
            experiment_directory = os.path.join(
                home_directory, self.parameters['experiment'].value)
            if not os.path.exists(experiment_directory):
                os.makedirs(experiment_directory)
            self.mainwindow.default_directory = experiment_directory
            configuration_directory = os.path.join(experiment_directory,
                                                   'configurations')
            if not os.path.exists(configuration_directory):
                os.makedirs(configuration_directory)
            task_directory = os.path.join(experiment_directory, 'tasks')
            if not os.path.exists(task_directory):
                os.makedirs(task_directory)
            nxdb = NXDatabase(os.path.join(task_directory, 'nxdatabase.db'))
            calibration_directory = os.path.join(experiment_directory,
                                                 'calibrations')
            if not os.path.exists(calibration_directory):
                os.makedirs(calibration_directory)
            script_directory = os.path.join(experiment_directory, 'scripts')
            if not os.path.exists(script_directory):
                os.makedirs(script_directory)
            super().accept()
        except Exception as error:
            report_error("Defining New Experiment", error)
Exemplo n.º 8
0
class EnergyDialog(BaseDialog):
    def __init__(self, parent=None):
        super(EnergyDialog, self).__init__(parent)

        self.select_entry()
        self.parameters = GridParameters()
        self.parameters.add("m1", self.entry["monitor1/distance"], "Monitor 1 Distance")
        self.parameters.add("m2", self.entry["monitor2/distance"], "Monitor 2 Distance")
        self.parameters.add("Ei", self.entry["instrument/monochromator/energy"], "Incident Energy")
        self.parameters.add("mod", self.entry["instrument/source/distance"], "Moderator Distance")
        action_buttons = self.action_buttons(("Get Ei", self.get_ei))
        self.set_layout(self.entry_layout, self.parameters.grid(), action_buttons, self.close_buttons(save=True))
        self.set_title("Get Incident Energy")

        self.m1 = self.entry["monitor1"]
        self.m2 = self.entry["monitor2"]

    @property
    def m1_distance(self):
        return self.parameters["m1"].value - self.moderator_distance

    @property
    def m2_distance(self):
        return self.parameters["m2"].value - self.moderator_distance

    @property
    def Ei(self):
        return self.parameters["Ei"].value

    @property
    def moderator_distance(self):
        return self.parameters["mod"].value

    def get_ei(self):
        t = 2286.26 * self.m1_distance / np.sqrt(self.Ei)
        m1_time = self.m1[t - 200.0 : t + 200.0].moment()
        t = 2286.26 * self.m2_distance / np.sqrt(self.Ei)
        m2_time = self.m2[t - 200.0 : t + 200.0].moment()
        self.parameters["Ei"].value = (2286.26 * (self.m2_distance - self.m1_distance) / (m2_time - m1_time)) ** 2

    def accept(self):
        try:
            self.parameters["Ei"].save()
        except NeXusError as error:
            report_error("Getting Incident Energy", error)
        super(EnergyDialog, self).accept()
Exemplo n.º 9
0
class RefineLatticeDialog(NXDialog):
    def __init__(self, parent=None):
        super().__init__(parent)

        self.select_entry(self.choose_entry)

        self.refine = NXRefine()
        self.parameters = GridParameters()
        self.parameters.add('symmetry', self.refine.symmetries, 'Symmetry',
                            None, self.set_lattice_parameters)
        self.parameters.add('a',
                            self.refine.a,
                            'Unit Cell - a (Ang)',
                            False,
                            slot=self.set_lattice_parameters)
        self.parameters.add('b',
                            self.refine.b,
                            'Unit Cell - b (Ang)',
                            False,
                            slot=self.set_lattice_parameters)
        self.parameters.add('c',
                            self.refine.c,
                            'Unit Cell - c (Ang)',
                            False,
                            slot=self.set_lattice_parameters)
        self.parameters.add('alpha',
                            self.refine.alpha,
                            'Unit Cell - alpha (deg)',
                            False,
                            slot=self.set_lattice_parameters)
        self.parameters.add('beta',
                            self.refine.beta,
                            'Unit Cell - beta (deg)',
                            False,
                            slot=self.set_lattice_parameters)
        self.parameters.add('gamma',
                            self.refine.gamma,
                            'Unit Cell - gamma (deg)',
                            False,
                            slot=self.set_lattice_parameters)
        self.parameters.add('wavelength', self.refine.wavelength,
                            'Wavelength (Ang)', False)
        self.parameters.add('distance', self.refine.distance, 'Distance (mm)',
                            False)
        self.parameters.add('yaw', self.refine.yaw, 'Yaw (deg)', False)
        self.parameters.add('pitch', self.refine.pitch, 'Pitch (deg)', False)
        self.parameters.add('roll', self.refine.roll, 'Roll (deg)')
        self.parameters.add('xc', self.refine.xc, 'Beam Center - x', False)
        self.parameters.add('yc', self.refine.yc, 'Beam Center - y', False)
        self.parameters.add('phi', self.refine.phi, 'Phi Start (deg)', False)
        self.parameters.add('phi_step', self.refine.phi_step, 'Phi Step (deg)')
        self.parameters.add('chi', self.refine.chi, 'Chi (deg)', False)
        self.parameters.add('omega', self.refine.omega, 'Omega (deg)', False)
        self.parameters.add('twotheta', self.refine.twotheta,
                            'Two Theta (deg)')
        self.parameters.add('gonpitch', self.refine.gonpitch,
                            'Goniometer Pitch (deg)', False)
        self.parameters.add('polar', self.refine.polar_max,
                            'Max. Polar Angle (deg)', None, self.set_polar_max)
        self.parameters.add('polar_tolerance', self.refine.polar_tolerance,
                            'Polar Angle Tolerance')
        self.parameters.add('peak_tolerance', self.refine.peak_tolerance,
                            'Peak Angle Tolerance')
        self.parameters.grid()
        self.set_symmetry()

        self.refine_buttons = self.action_buttons(
            ('Refine Angles', self.refine_angles),
            ('Refine HKLs', self.refine_hkls),
            ('Restore', self.restore_parameters),
            ('Reset', self.reset_parameters))

        self.orientation_buttons = self.action_buttons(
            ('Refine Orientation Matrix', self.refine_orientation),
            ('Remove Orientation Matrix', self.remove_orientation))

        self.lattice_buttons = self.action_buttons(
            ('Plot', self.plot_lattice), ('List', self.list_peaks),
            ('Update', self.update_scaling), ('Save', self.write_parameters))

        self.set_layout(self.entry_layout, self.close_layout())

        self.parameters.grid_layout.setVerticalSpacing(1)
        self.layout.setSpacing(2)

        self.set_title('Refining Lattice')

        self.peaks_box = None
        self.table_model = None
        self.orient_box = None
        self.update_box = None
        self.fit_report = []

    def choose_entry(self):
        try:
            refine = NXRefine(self.entry)
            if refine.xp is None:
                raise NeXusError("No peaks in entry")
        except NeXusError as error:
            report_error("Refining Lattice", error)
            return
        self.refine = refine
        self.set_title(f"Refining {self.refine.name}")
        if self.layout.count() == 2:
            self.insert_layout(1, self.parameters.grid_layout)
            self.insert_layout(2, self.refine_buttons)
            self.insert_layout(3, self.orientation_buttons)
            self.insert_layout(4, self.parameters.report_layout())
            self.insert_layout(5, self.lattice_buttons)
        self.update_parameters()
        self.update_table()

    def report_score(self):
        try:
            self.status_message.setText(f'Score: {self.refine.score():.4f}')
            if self.peaks_box in self.mainwindow.dialogs:
                self.status_text.setText(f'Score: {self.refine.score():.4f}')
        except Exception as error:
            pass

    def update_parameters(self):
        self.parameters['a'].value = self.refine.a
        self.parameters['b'].value = self.refine.b
        self.parameters['c'].value = self.refine.c
        self.parameters['alpha'].value = self.refine.alpha
        self.parameters['beta'].value = self.refine.beta
        self.parameters['gamma'].value = self.refine.gamma
        self.parameters['wavelength'].value = self.refine.wavelength
        self.parameters['distance'].value = self.refine.distance
        self.parameters['yaw'].value = self.refine.yaw
        self.parameters['pitch'].value = self.refine.pitch
        self.parameters['roll'].value = self.refine.roll
        self.parameters['xc'].value = self.refine.xc
        self.parameters['yc'].value = self.refine.yc
        self.parameters['phi'].value = self.refine.phi
        self.parameters['phi_step'].value = self.refine.phi_step
        self.parameters['chi'].value = self.refine.chi
        self.parameters['omega'].value = self.refine.omega
        self.parameters['twotheta'].value = self.refine.twotheta
        self.parameters['gonpitch'].value = self.refine.gonpitch
        self.parameters['polar'].value = self.refine.polar_max
        self.parameters['polar_tolerance'].value = self.refine.polar_tolerance
        self.parameters['peak_tolerance'].value = self.refine.peak_tolerance
        self.parameters['symmetry'].value = self.refine.symmetry
        try:
            self.refine.polar_angles, self.refine.azimuthal_angles = \
                self.refine.calculate_angles(self.refine.xp, self.refine.yp)
        except Exception:
            pass
        self.report_score()

    def transfer_parameters(self):
        self.refine.a, self.refine.b, self.refine.c, \
            self.refine.alpha, self.refine.beta, self.refine.gamma = \
            self.get_lattice_parameters()
        self.refine.set_symmetry()
        self.refine.wavelength = self.get_wavelength()
        self.refine.distance = self.get_distance()
        self.refine.yaw, self.refine.pitch, self.refine.roll = self.get_tilts()
        self.refine.xc, self.refine.yc = self.get_centers()
        self.refine.phi, self.refine.phi_step = self.get_phi()
        self.refine.chi, self.refine.omega, self.refine.twotheta, \
            self.refine.gonpitch = self.get_angles()
        self.refine.polar_max = self.get_polar_max()
        self.refine.polar_tolerance = self.get_polar_tolerance()
        self.refine.peak_tolerance = self.get_peak_tolerance()

    def write_parameters(self):
        if self.entry.nxfilemode == 'r':
            display_message("NeXus file opened as readonly")
            return
        elif ('nxrefine' in self.entry
              or 'orientation_matrix' in self.entry['instrument/detector']):
            if not self.confirm_action('Overwrite existing refinement?'):
                return
        self.transfer_parameters()
        polar_angles, azimuthal_angles = self.refine.calculate_angles(
            self.refine.xp, self.refine.yp)
        self.refine.write_angles(polar_angles, azimuthal_angles)
        self.refine.write_parameters()
        reduce = NXReduce(self.entry)
        reduce.record_start('nxrefine')
        reduce.record('nxrefine', fit_report='\n'.join(self.fit_report))
        reduce.logger.info('Orientation refined in NeXpy')
        reduce.record_end('nxrefine')
        root = self.entry.nxroot
        entries = [
            entry for entry in root.entries
            if entry != 'entry' and entry != self.entry.nxname
        ]
        if entries and self.confirm_action(
                f'Copy orientation to other entries? ({", ".join(entries)})',
                answer='yes'):
            om = self.entry['instrument/detector/orientation_matrix']
            for entry in entries:
                root[entry]['instrument/detector/orientation_matrix'] = om
        self.define_data()
        if len(self.paths) > 0:
            self.update_scaling()

    def update_scaling(self):
        self.define_data()
        if len(self.paths) == 0:
            display_message("Refining Lattice", "No data groups to update")
        if self.update_box in self.mainwindow.dialogs:
            try:
                self.update_box.close()
            except Exception:
                pass
        self.update_box = NXDialog(parent=self)
        self.update_box.set_title('Update Scaling Factors')
        self.update_box.setMinimumWidth(300)
        self.update_box.set_layout(
            self.paths.grid(header=('', 'Data Groups', '')),
            self.update_box.close_layout())
        self.update_box.close_box.accepted.connect(self.update_data)
        self.update_box.show()

    def define_data(self):
        def is_valid(data):
            try:
                valid_axes = [['Ql', 'Qk', 'Qh'], ['l', 'k', 'h'],
                              ['z', 'y', 'x']]
                axis_names = [axis.nxname for axis in data.nxaxes]
                return axis_names in valid_axes
            except Exception:
                return False

        root = self.entry.nxroot
        self.paths = GridParameters()
        i = 0
        for entry in root.NXentry:
            for data in [d for d in entry.NXdata if is_valid(d)]:
                i += 1
                self.paths.add(i, data.nxpath, i, True, width=200)

    def update_data(self):
        try:
            for path in [
                    self.paths[p].value for p in self.paths
                    if self.paths[p].vary
            ]:
                data = self.entry.nxroot[path]
                if [axis.nxname for axis in data.nxaxes] == ['z', 'y', 'x']:
                    lp = self.refine.lattice_parameters
                else:
                    lp = self.refine.reciprocal_lattice_parameters
                for i, axis in enumerate(data.nxaxes):
                    data[axis.nxname].attrs['scaling_factor'] = lp[2 - i]
                data.attrs['angles'] = lp[5:2:-1]
            self.update_box.close()
        except NeXusError as error:
            report_error("Updating Groups", error)

    def get_symmetry(self):
        return self.parameters['symmetry'].value

    def set_symmetry(self):
        self.refine.symmetry = self.get_symmetry()
        self.refine.set_symmetry()
        self.update_parameters()
        if self.refine.symmetry == 'cubic':
            self.parameters['b'].vary = False
            self.parameters['c'].vary = False
            self.parameters['alpha'].vary = False
            self.parameters['beta'].vary = False
            self.parameters['gamma'].vary = False
        elif self.refine.symmetry == 'tetragonal':
            self.parameters['b'].vary = False
            self.parameters['alpha'].vary = False
            self.parameters['beta'].vary = False
            self.parameters['gamma'].vary = False
        elif self.refine.symmetry == 'orthorhombic':
            self.parameters['alpha'].vary = False
            self.parameters['beta'].vary = False
            self.parameters['gamma'].vary = False
        elif self.refine.symmetry == 'hexagonal':
            self.parameters['b'].vary = False
            self.parameters['alpha'].vary = False
            self.parameters['beta'].vary = False
            self.parameters['gamma'].vary = False
        elif self.refine.symmetry == 'monoclinic':
            self.parameters['alpha'].vary = False
            self.parameters['gamma'].vary = False

    def get_lattice_parameters(self):
        return (self.parameters['a'].value, self.parameters['b'].value,
                self.parameters['c'].value, self.parameters['alpha'].value,
                self.parameters['beta'].value, self.parameters['gamma'].value)

    def set_lattice_parameters(self):
        symmetry = self.get_symmetry()
        if symmetry == 'cubic':
            self.parameters['b'].value = self.parameters['a'].value
            self.parameters['c'].value = self.parameters['a'].value
            self.parameters['alpha'].value = 90.0
            self.parameters['beta'].value = 90.0
            self.parameters['gamma'].value = 90.0
            self.parameters['a'].enable(vary=True)
            self.parameters['b'].disable(vary=False)
            self.parameters['c'].disable(vary=False)
            self.parameters['alpha'].disable(vary=False)
            self.parameters['beta'].disable(vary=False)
            self.parameters['gamma'].disable(vary=False)
        elif symmetry == 'tetragonal':
            self.parameters['b'].value = self.parameters['a'].value
            self.parameters['alpha'].value = 90.0
            self.parameters['beta'].value = 90.0
            self.parameters['gamma'].value = 90.0
            self.parameters['a'].enable(vary=True)
            self.parameters['b'].disable(vary=False)
            self.parameters['c'].enable(vary=True)
            self.parameters['alpha'].disable(vary=False)
            self.parameters['beta'].disable(vary=False)
            self.parameters['gamma'].disable(vary=False)
        elif symmetry == 'orthorhombic':
            self.parameters['alpha'].value = 90.0
            self.parameters['beta'].value = 90.0
            self.parameters['gamma'].value = 90.0
            self.parameters['a'].enable(vary=True)
            self.parameters['b'].enable(vary=True)
            self.parameters['c'].enable(vary=True)
            self.parameters['alpha'].disable(vary=False)
            self.parameters['beta'].disable(vary=False)
            self.parameters['gamma'].disable(vary=False)
        elif symmetry == 'hexagonal':
            self.parameters['b'].value = self.parameters['a'].value
            self.parameters['alpha'].value = 90.0
            self.parameters['beta'].value = 90.0
            self.parameters['gamma'].value = 120.0
            self.parameters['a'].enable(vary=True)
            self.parameters['b'].disable(vary=False)
            self.parameters['c'].enable(vary=True)
            self.parameters['alpha'].disable(vary=False)
            self.parameters['beta'].disable(vary=False)
            self.parameters['gamma'].disable(vary=False)
        elif symmetry == 'monoclinic':
            self.parameters['alpha'].value = 90.0
            self.parameters['gamma'].value = 90.0
            self.parameters['a'].enable(vary=True)
            self.parameters['b'].enable(vary=True)
            self.parameters['c'].enable(vary=True)
            self.parameters['alpha'].disable(vary=False)
            self.parameters['beta'].enable(vary=True)
            self.parameters['gamma'].disable(vary=False)
        else:
            self.parameters['a'].enable(vary=True)
            self.parameters['b'].enable(vary=True)
            self.parameters['c'].enable(vary=True)
            self.parameters['alpha'].enable(vary=True)
            self.parameters['beta'].enable(vary=True)
            self.parameters['gamma'].enable(vary=True)

    def get_wavelength(self):
        return self.parameters['wavelength'].value

    def get_distance(self):
        return self.parameters['distance'].value

    def get_tilts(self):
        return (self.parameters['yaw'].value, self.parameters['pitch'].value,
                self.parameters['roll'].value)

    def get_centers(self):
        return self.parameters['xc'].value, self.parameters['yc'].value

    def get_phi(self):
        return (self.parameters['phi'].value,
                self.parameters['phi_step'].value)

    def get_angles(self):
        return (self.parameters['chi'].value, self.parameters['omega'].value,
                self.parameters['twotheta'].value,
                self.parameters['gonpitch'].value)

    def get_polar_max(self):
        return self.parameters['polar'].value

    def set_polar_max(self):
        self.refine.polar_max = self.get_polar_max()

    def get_polar_tolerance(self):
        return self.parameters['polar_tolerance'].value

    def get_peak_tolerance(self):
        return self.parameters['peak_tolerance'].value

    def get_hkl_tolerance(self):
        try:
            return np.float32(self.tolerance_box.text())
        except Exception:
            return self.refine.hkl_tolerance

    def plot_lattice(self):
        self.transfer_parameters()
        self.set_polar_max()
        self.plot_peaks()
        self.plot_rings()

    def plot_peaks(self):
        try:
            x, y = (self.refine.xp[self.refine.idx],
                    self.refine.yp[self.refine.idx])
            polar_angles, azimuthal_angles = self.refine.calculate_angles(x, y)
            if polar_angles[0] > polar_angles[-1]:
                polar_angles = polar_angles[::-1]
                azimuthal_angles = azimuthal_angles[::-1]
            azimuthal_field = NXfield(azimuthal_angles, name='azimuthal_angle')
            azimuthal_field.long_name = 'Azimuthal Angle'
            polar_field = NXfield(polar_angles, name='polar_angle')
            polar_field.long_name = 'Polar Angle'
            plotview = get_plotview()
            plotview.plot(NXdata(azimuthal_field,
                                 polar_field,
                                 title=f'{self.refine.name} Peak Angles'),
                          xmax=self.get_polar_max())
        except NeXusError as error:
            report_error('Plotting Lattice', error)

    def plot_rings(self):
        plotview = get_plotview()
        plotview.vlines(self.refine.two_thetas,
                        colors='r',
                        linestyles='dotted')
        plotview.draw()

    @property
    def refined(self):
        refined = {}
        for p in self.parameters:
            if self.parameters[p].vary:
                refined[p] = True
        return refined

    def refine_angles(self):
        self.parameters.status_message.setText('Fitting...')
        self.parameters.status_message.repaint()
        self.mainwindow.app.app.processEvents()
        self.parameters['phi'].vary = False
        self.transfer_parameters()
        self.set_lattice_parameters()
        try:
            self.refine.refine_angles(**self.refined)
        except NeXusError as error:
            report_error('Refining Lattice', error)
            self.parameters.status_message.setText('')
            return
        self.parameters.result = self.refine.result
        self.parameters.fit_report = self.refine.fit_report
        self.fit_report.append(self.refine.fit_report)
        self.update_parameters()
        self.parameters.status_message.setText(self.parameters.result.message)
        self.update_table()

    def refine_hkls(self):
        self.parameters.status_message.setText('Fitting...')
        self.parameters.status_message.repaint()
        self.mainwindow.app.app.processEvents()
        self.transfer_parameters()
        try:
            self.refine.refine_hkls(**self.refined)
        except NeXusError as error:
            report_error('Refining Lattice', error)
            self.parameters.status_message.setText('')
            return
        self.parameters.result = self.refine.result
        self.parameters.fit_report = self.refine.fit_report
        self.fit_report.append(self.refine.fit_report)
        self.update_parameters()
        self.parameters.status_message.setText(self.parameters.result.message)
        self.update_table()

    def refine_orientation(self):
        self.parameters.status_message.setText('Fitting...')
        self.parameters.status_message.repaint()
        self.mainwindow.app.app.processEvents()
        self.transfer_parameters()
        self.refine.refine_orientation_matrix()
        self.parameters.result = self.refine.result
        self.parameters.fit_report = self.refine.fit_report
        self.fit_report.append(self.refine.fit_report)
        self.update_parameters()
        self.parameters.status_message.setText(self.parameters.result.message)
        self.update_table()

    def remove_orientation(self):
        self.refine.Umat = None
        self.report_score()

    def restore_parameters(self):
        self.refine.restore_parameters()
        self.update_parameters()
        try:
            self.fit_report.pop()
        except IndexError:
            pass

    def reset_parameters(self):
        self.refine.read_parameters()
        self.update_parameters()
        self.set_symmetry()
        try:
            self.fit_report.pop()
        except IndexError:
            pass

    def list_peaks(self):
        if self.peaks_box in self.mainwindow.dialogs:
            self.update_table()
            return
        self.peaks_box = NXDialog(self)
        self.peaks_box.setMinimumWidth(600)
        self.peaks_box.setMinimumHeight(600)
        header = [
            'i', 'x', 'y', 'z', 'Polar', 'Azi', 'Intensity', 'H', 'K', 'L',
            'Diff'
        ]
        peak_list = self.refine.get_peaks()
        self.refine.assign_rings()
        self.rings = self.refine.make_rings()
        self.ring_list = self.refine.get_ring_list()
        if self.refine.primary is None:
            self.refine.primary = 0
        if self.refine.secondary is None:
            self.refine.secondary = 1
        self.primary_box = NXLineEdit(self.refine.primary,
                                      width=80,
                                      align='right')
        self.secondary_box = NXLineEdit(self.refine.secondary,
                                        width=80,
                                        align='right')
        orient_button = NXPushButton('Orient', self.choose_peaks)
        orient_layout = self.make_layout(NXLabel('Primary'),
                                         self.primary_box,
                                         NXLabel('Secondary'),
                                         self.secondary_box,
                                         'stretch',
                                         orient_button,
                                         align='right')

        self.table_view = QtWidgets.QTableView()
        self.table_model = NXTableModel(self, peak_list, header)
        self.table_view.setModel(self.table_model)
        self.table_view.resizeColumnsToContents()
        self.table_view.horizontalHeader().stretchLastSection()
        self.table_view.setSelectionBehavior(
            QtWidgets.QAbstractItemView.SelectRows)
        self.table_view.doubleClicked.connect(self.plot_peak)
        self.table_view.setSortingEnabled(True)
        self.table_view.sortByColumn(0, QtCore.Qt.AscendingOrder)
        self.status_text = NXLabel(f'Score: {self.refine.score():.4f}')
        self.tolerance_box = NXLineEdit(self.refine.hkl_tolerance,
                                        width=80,
                                        slot=self.update_table,
                                        align='right')
        self.tolerance_box.setMaxLength(5)
        export_button = NXPushButton('Export', self.export_peaks)
        save_button = NXPushButton('Save', self.save_orientation)
        close_button = NXPushButton('Close', self.close_peaks_box)
        close_layout = self.make_layout(self.status_text, 'stretch',
                                        NXLabel('Threshold'),
                                        self.tolerance_box, 'stretch',
                                        export_button, save_button,
                                        close_button)
        self.peaks_box.set_layout(orient_layout, self.table_view, close_layout)
        self.peaks_box.set_title(f'{self.refine.name} Peak Table')
        self.peaks_box.adjustSize()
        self.peaks_box.show()
        self.plotview = None

    def update_table(self):
        if self.peaks_box not in self.mainwindow.dialogs:
            return
        elif self.table_model is None:
            self.close_peaks_box()
            self.list_peaks()
        self.transfer_parameters()
        self.refine.hkl_tolerance = self.get_hkl_tolerance()
        self.table_model.peak_list = self.refine.get_peaks()
        self.refine.assign_rings()
        self.ring_list = self.refine.get_ring_list()
        rows, columns = len(self.table_model.peak_list), 11
        self.table_model.dataChanged.emit(
            self.table_model.createIndex(0, 0),
            self.table_model.createIndex(rows - 1, columns - 1))
        self.table_view.resizeColumnsToContents()
        self.peaks_box.set_title(f'{self.refine.name} Peak Table')
        self.peaks_box.adjustSize()
        self.peaks_box.setVisible(True)
        self.report_score()

    def plot_peak(self):
        row = self.table_view.currentIndex().row()
        data = self.entry.data
        i, x, y, z = [
            self.table_view.model().peak_list[row][i] for i in range(4)
        ]
        signal = data.nxsignal
        xmin, xmax = max(0, x - 200), min(x + 200, signal.shape[2])
        ymin, ymax = max(0, y - 200), min(y + 200, signal.shape[1])
        zmin, zmax = max(0, z - 20), min(z + 20, signal.shape[0])
        zslab = np.s_[zmin:zmax, ymin:ymax, xmin:xmax]
        if 'Peak Plot' in self.plotviews:
            self.plotview = self.plotviews['Peak Plot']
        else:
            self.plotview = NXPlotView('Peak Plot')
        self.plotview.plot(data[zslab], log=True)
        self.plotview.ax.set_title(f'{data.nxtitle}: Peak {i}')
        self.plotview.ztab.maxbox.setValue(z)
        self.plotview.aspect = 'equal'
        self.plotview.crosshairs(x, y, color='r', linewidth=0.5)

    @property
    def primary(self):
        return int(self.primary_box.text())

    @property
    def secondary(self):
        return int(self.secondary_box.text())

    def choose_peaks(self):
        try:
            if self.orient_box in self.mainwindow.dialogs:
                self.orient_box.close()
        except Exception:
            pass
        self.orient_box = NXDialog(self)
        self.peak_parameters = GridParameters()
        self.peak_parameters.add('primary',
                                 self.primary,
                                 'Primary',
                                 readonly=True)
        self.peak_parameters.add('secondary',
                                 self.secondary,
                                 'Secondary',
                                 readonly=True)
        self.peak_parameters.add('angle',
                                 self.refine.angle_peaks(
                                     self.primary, self.secondary),
                                 'Angle (deg)',
                                 readonly=True)
        self.peak_parameters.add('primary_hkl',
                                 self.ring_list[self.refine.rp[self.primary]],
                                 'Primary HKL',
                                 slot=self.choose_secondary_grid)
        self.orient_box.set_layout(
            self.peak_parameters.grid(header=False, spacing=5),
            self.action_buttons(('Orient', self.orient)),
            self.orient_box.close_buttons(close=True))
        self.orient_box.set_title('Orient Lattice')
        self.orient_box.show()
        try:
            self.setup_secondary_grid()
        except NeXusError as error:
            report_error("Refining Lattice", error)
            self.orient_box.close()

    def setup_secondary_grid(self):
        ps_angle = self.refine.angle_peaks(self.primary, self.secondary)
        n_phkl = len(self.ring_list[self.refine.rp[self.primary]])
        self.hkl_parameters = [GridParameters() for i in range(n_phkl)]
        min_diff = self.get_peak_tolerance()
        min_p = None
        min_hkl = None
        for i in range(n_phkl):
            phkl = eval(self.peak_parameters['primary_hkl'].box.items()[i])
            for hkls in self.rings[self.refine.rp[self.secondary]][1]:
                for hkl in hkls:
                    hkl_angle = self.refine.angle_hkls(phkl, hkl)
                    diff = abs(ps_angle - hkl_angle)
                    if diff < self.get_peak_tolerance():
                        self.hkl_parameters[i].add(str(hkl),
                                                   hkl_angle,
                                                   str(hkl),
                                                   vary=False,
                                                   readonly=True)
                        if diff < min_diff:
                            min_diff = diff
                            min_p = i
                            min_hkl = str(hkl)
            self.orient_box.insert_layout(
                i + 1, self.hkl_parameters[i].grid(
                    header=['HKL', 'Angle (deg)', 'Select'], spacing=5))
        if min_hkl is None:
            raise NeXusError("No matching peaks found")
        self.peak_parameters['primary_hkl'].box.setCurrentIndex(min_p)
        self.hkl_parameters[min_p][min_hkl].vary = True
        self.choose_secondary_grid()

    def choose_secondary_grid(self):
        box = self.peak_parameters['primary_hkl'].box
        for i in [i for i in range(box.count()) if i != box.currentIndex()]:
            self.hkl_parameters[i].hide_grid()
        self.hkl_parameters[box.currentIndex()].show_grid()

    @property
    def primary_hkl(self):
        return eval(self.peak_parameters['primary_hkl'].value)

    @property
    def secondary_hkl(self):
        for hkls in self.hkl_parameters:
            for hkl in hkls:
                if hkls[hkl].vary is True:
                    return eval(hkls[hkl].name)

    def orient(self):
        self.refine.primary = self.primary
        self.refine.secondary = self.secondary
        self.refine.Umat = self.refine.get_UBmat(self.primary, self.secondary,
                                                 self.primary_hkl,
                                                 self.secondary_hkl)
        self.update_table()

    def export_peaks(self):
        peaks = list(
            zip(*[
                p for p in self.table_model.peak_list
                if p[-1] < self.get_hkl_tolerance()
            ]))
        idx = NXfield(peaks[0], name='index')
        x = NXfield(peaks[1], name='x')
        y = NXfield(peaks[2], name='y')
        z = NXfield(peaks[3], name='z')
        pol = NXfield(peaks[4], name='polar_angle', units='degree')
        azi = NXfield(peaks[5], name='azimuthal_angle', units='degree')
        polarization = self.refine.get_polarization()
        intensity = NXfield(peaks[6] / polarization[y, x], name='intensity')
        H = NXfield(peaks[7], name='H', units='rlu')
        K = NXfield(peaks[8], name='K', units='rlu')
        L = NXfield(peaks[9], name='L', units='rlu')
        diff = NXfield(peaks[10], name='diff')
        peaks_data = NXdata(intensity, idx, diff, H, K, L, pol, azi, x, y, z)
        export_dialog = ExportDialog(peaks_data, parent=self)
        export_dialog.show()

    def save_orientation(self):
        self.write_parameters()

    def close_peaks_box(self):
        try:
            self.peaks_box.close()
        except Exception:
            pass
        self.peaks_box = None

    def accept(self):
        if 'transform' not in self.entry:
            if self.confirm_action("Set up transforms?", answer="yes"):
                self.treeview.select_node(self.entry)
                from . import transform_data
                transform_data.show_dialog()
        super().accept()
Exemplo n.º 10
0
class ConvertDialog(BaseDialog):

    def __init__(self, parent=None):
        super(ConvertDialog, self).__init__(parent)
        layout = QtGui.QVBoxLayout()
        self.select_entry()
        self.parameters = GridParameters()
        self.parameters.add('Ei', self.entry['instrument/monochromator/energy'],
                            'Incident Energy')
        self.parameters.add('dQ', self.round(np.sqrt(self.Ei/2)/50), 'Q Step')
        self.parameters.add('dE', self.round(self.Ei/50), 'Energy Step')
        layout.addLayout(self.entry_layout)
        layout.addLayout(self.parameters.grid())
        layout.addLayout(self.action_buttons(('Plot', self.plot_data),
                                             ('Save', self.save_data)))
        layout.addWidget(self.close_buttons())
        self.setLayout(layout)
        self.setWindowTitle('Converting to (Q,E)')

    @property
    def Ei(self):
        return self.parameters['Ei'].value

    @property
    def dQ(self):
        return self.parameters['dQ'].value

    @property
    def dE(self):
        return self.parameters['dE'].value

    def read_parameters(self):
        self.L1 = - self.entry['sample/distance']
        self.L2 = np.mean(self.entry['instrument/detector/distance'])
        self.m1 = self.entry['monitor1']
        self.t_m1 = self.m1.moment()
        self.d_m1 = self.entry['monitor1/distance']

    def convert_tof(self, tof):
        ki = np.sqrt(self.Ei / 2.0721)
        ts = self.t_m1 + 1588.254 * (self.L1 - self.d_m1) / ki
        kf = 1588.254 * self.L2 / (tof - ts)
        eps = self.Ei - 2.0721*kf**2
        return eps

    def convert_QE(self):
        """Convert S(phi,eps) to S(Q,eps)"""

        self.read_parameters()

        Ei = self.Ei
        dQ = self.dQ
        dE = self.dE

        pol, tof = centers(self.entry['data'].nxsignal, self.entry['data'].nxaxes)
        en = self.convert_tof(tof)

        idx_max = min(np.where(np.abs(en-0.75*Ei)<0.1)[0])

        en = en[:idx_max]

        data = self.entry['data'].nxsignal.nxdata[:,:idx_max]
        if self.entry['data'].nxerrors:
            errors = self.entry['data'].nxerrors.nxdata[:]

        Q = np.zeros((len(pol), len(en)))
        E = np.zeros((len(pol), len(en)))

        for i in range(0,len(pol)):
            p = pol[i]
            Q[i,:] = np.array(np.sqrt((2*Ei - en - 2*np.sqrt(Ei*(Ei-en))
                               * np.cos(p*np.pi/180.0))/2.0721))
            E[i,:] = np.array(en)

        s = Q.shape
        Qin = Q.reshape(s[0]*s[1])
        Ein = E.reshape(s[0]*s[1])
        datain = data.reshape(s[0]*s[1])
        if self.entry['data'].nxerrors:
            errorsin = errors.reshape(s[0]*s[1])

        qmin = Q.min()
        qmax = Q.max()
        emin = E.min()
        emax = E.max()
        NQ = int((qmax-qmin)/dQ) + 1
        NE = int((emax-emin)/dE) + 1
        Qb = np.linspace(qmin, qmax, NQ)
        Eb = np.linspace(emin, emax, NE)
        #histogram and normalize 
        norm, nbin = np.histogramdd((Ein,Qin), bins=(Eb,Qb))
        hist, hbin = np.histogramdd((Ein,Qin), bins=(Eb,Qb), weights=datain)
        if self.entry['data'].nxerrors:
            histe, hbin = np.histogramdd((Ein,Qin), bins=(Eb,Qb), weights=errorsin*errorsin)
            histe = histe**0.5
            err = histe/norm

        I = NXfield(hist/norm, name='S(Q,E)')

        Qb = NXfield(Qb[:-1]+dQ/2., name='Q')
        Eb = NXfield(Eb[:-1]+dE/2., name='E')

        result = NXdata(I, (Eb, Qb))
        if self.entry.data.nxerrors:
            result.errors = NXfield(err)
        return result

    def round(self, x, prec=2, base=.05):
        return round(base * round(float(x)/base), prec)

    def plot_data(self):
        self.convert_QE().plot()

    def save_data(self):
        self.entry['sqe'] = self.convert_QE()
Exemplo n.º 11
0
class RefineLatticeDialog(BaseDialog):
    def __init__(self, parent=None):
        super(RefineLatticeDialog, self).__init__(parent)

        self.select_entry(self.choose_entry)

        self.refine = NXRefine()
        self.parameters = GridParameters()
        self.parameters.add('symmetry', self.refine.symmetries, 'Symmetry',
                            None, self.set_lattice_parameters)
        self.parameters.add('a',
                            self.refine.a,
                            'Unit Cell - a (Ang)',
                            False,
                            slot=self.set_lattice_parameters)
        self.parameters.add('b',
                            self.refine.b,
                            'Unit Cell - b (Ang)',
                            False,
                            slot=self.set_lattice_parameters)
        self.parameters.add('c',
                            self.refine.c,
                            'Unit Cell - c (Ang)',
                            False,
                            slot=self.set_lattice_parameters)
        self.parameters.add('alpha',
                            self.refine.alpha,
                            'Unit Cell - alpha (deg)',
                            False,
                            slot=self.set_lattice_parameters)
        self.parameters.add('beta',
                            self.refine.beta,
                            'Unit Cell - beta (deg)',
                            False,
                            slot=self.set_lattice_parameters)
        self.parameters.add('gamma',
                            self.refine.gamma,
                            'Unit Cell - gamma (deg)',
                            False,
                            slot=self.set_lattice_parameters)
        self.parameters.add('wavelength', self.refine.wavelength,
                            'Wavelength (Ang)', False)
        self.parameters.add('distance', self.refine.distance, 'Distance (mm)',
                            False)
        self.parameters.add('yaw', self.refine.yaw, 'Yaw (deg)', False)
        self.parameters.add('pitch', self.refine.pitch, 'Pitch (deg)', False)
        self.parameters.add('roll', self.refine.roll, 'Roll (deg)')
        self.parameters.add('xc', self.refine.xc, 'Beam Center - x', False)
        self.parameters.add('yc', self.refine.yc, 'Beam Center - y', False)
        self.parameters.add('phi', self.refine.phi, 'Phi Start (deg)', False)
        self.parameters.add('phi_step', self.refine.phi_step, 'Phi Step (deg)')
        self.parameters.add('chi', self.refine.chi, 'Chi (deg)', False)
        self.parameters.add('omega', self.refine.omega, 'Omega (deg)', False)
        self.parameters.add('twotheta', self.refine.twotheta,
                            'Two Theta (deg)')
        self.parameters.add('gonpitch', self.refine.gonpitch,
                            'Goniometer Pitch (deg)', False)
        self.parameters.add('polar', self.refine.polar_max,
                            'Max. Polar Angle (deg)', None, self.set_polar_max)
        self.parameters.add('polar_tolerance', self.refine.polar_tolerance,
                            'Polar Angle Tolerance')
        self.parameters.add('peak_tolerance', self.refine.peak_tolerance,
                            'Peak Angle Tolerance')
        self.set_symmetry()

        self.refine_buttons = self.action_buttons(
            ('Refine Angles', self.refine_angles),
            ('Refine HKLs', self.refine_hkls),
            ('Restore', self.restore_parameters),
            ('Reset', self.reset_parameters))

        self.orientation_button = self.action_buttons(
            ('Refine Orientation Matrix', self.refine_orientation))

        self.lattice_buttons = self.action_buttons(
            ('Plot', self.plot_lattice), ('List', self.list_peaks),
            ('Save', self.write_parameters))

        self.set_layout(self.entry_layout, self.parameters.grid(),
                        self.refine_buttons, self.orientation_button,
                        self.parameters.report_layout(), self.lattice_buttons,
                        self.close_layout())

        self.parameters.grid_layout.setVerticalSpacing(1)
        self.layout.setSpacing(2)

        self.set_title('Refining Lattice')

        self.peaks_box = None
        self.table_model = None
        self.fit_report = []

    def choose_entry(self):
        self.refine = NXRefine(self.entry)
        self.update_parameters()
        if self.peaks_box:
            self.update_table()

    def report_score(self):
        try:
            self.status_message.setText('Score: %.4f' % self.refine.score())
        except Exception as error:
            pass

    def update_parameters(self):
        self.parameters['a'].value = self.refine.a
        self.parameters['b'].value = self.refine.b
        self.parameters['c'].value = self.refine.c
        self.parameters['alpha'].value = self.refine.alpha
        self.parameters['beta'].value = self.refine.beta
        self.parameters['gamma'].value = self.refine.gamma
        self.parameters['wavelength'].value = self.refine.wavelength
        self.parameters['distance'].value = self.refine.distance
        self.parameters['yaw'].value = self.refine.yaw
        self.parameters['pitch'].value = self.refine.pitch
        self.parameters['roll'].value = self.refine.roll
        self.parameters['xc'].value = self.refine.xc
        self.parameters['yc'].value = self.refine.yc
        self.parameters['phi'].value = self.refine.phi
        self.parameters['phi_step'].value = self.refine.phi_step
        self.parameters['chi'].value = self.refine.chi
        self.parameters['omega'].value = self.refine.omega
        self.parameters['twotheta'].value = self.refine.twotheta
        self.parameters['gonpitch'].value = self.refine.gonpitch
        self.parameters['polar'].value = self.refine.polar_max
        self.parameters['polar_tolerance'].value = self.refine.polar_tolerance
        self.parameters['symmetry'].value = self.refine.symmetry
        try:
            self.refine.polar_angles, self.refine.azimuthal_angles = \
                self.refine.calculate_angles(self.refine.xp, self.refine.yp)
        except Exception:
            pass
        self.report_score()

    def transfer_parameters(self):
        self.refine.a, self.refine.b, self.refine.c, \
            self.refine.alpha, self.refine.beta, self.refine.gamma = \
                self.get_lattice_parameters()
        self.refine.set_symmetry()
        self.refine.wavelength = self.get_wavelength()
        self.refine.distance = self.get_distance()
        self.refine.yaw, self.refine.pitch, self.refine.roll = self.get_tilts()
        self.refine.xc, self.refine.yc = self.get_centers()
        self.refine.phi, self.refine.phi_step = self.get_phi()
        self.refine.chi, self.refine.omega, self.refine.twotheta, \
            self.refine.gonpitch = self.get_angles()
        self.refine.polar_max = self.get_polar_max()
        self.refine.polar_tol = self.get_tolerance()

    def write_parameters(self):
        self.transfer_parameters()
        polar_angles, azimuthal_angles = self.refine.calculate_angles(
            self.refine.xp, self.refine.yp)
        self.refine.write_angles(polar_angles, azimuthal_angles)
        self.refine.write_parameters()
        reduce = NXReduce(self.entry)
        reduce.record('nxrefine', fit_report='\n'.join(self.fit_report))
        root = self.entry.nxroot
        entries = [entry for entry in root.entries if entry != 'entry']
        if entries and self.confirm_action(
                'Copy orientation to other entries? (%s)' %
            (', '.join(entries))):
            om = self.entry['instrument/detector/orientation_matrix']
            for entry in entries:
                root[entry]['instrument/detector/orientation_matrix'] = om

    def get_symmetry(self):
        return self.parameters['symmetry'].value

    def set_symmetry(self):
        self.refine.symmetry = self.get_symmetry()
        self.refine.set_symmetry()
        self.update_parameters()
        if self.refine.symmetry == 'cubic':
            self.parameters['b'].vary = False
            self.parameters['c'].vary = False
            self.parameters['alpha'].vary = False
            self.parameters['beta'].vary = False
            self.parameters['gamma'].vary = False
        elif self.refine.symmetry == 'tetragonal':
            self.parameters['b'].vary = False
            self.parameters['alpha'].vary = False
            self.parameters['beta'].vary = False
            self.parameters['gamma'].vary = False
        elif self.refine.symmetry == 'orthorhombic':
            self.parameters['alpha'].vary = False
            self.parameters['beta'].vary = False
            self.parameters['gamma'].vary = False
        elif self.refine.symmetry == 'hexagonal':
            self.parameters['b'].vary = False
            self.parameters['alpha'].vary = False
            self.parameters['beta'].vary = False
            self.parameters['gamma'].vary = False
        elif self.refine.symmetry == 'monoclinic':
            self.parameters['alpha'].vary = False
            self.parameters['gamma'].vary = False

    def get_lattice_parameters(self):
        return (self.parameters['a'].value, self.parameters['b'].value,
                self.parameters['c'].value, self.parameters['alpha'].value,
                self.parameters['beta'].value, self.parameters['gamma'].value)

    def set_lattice_parameters(self):
        symmetry = self.get_symmetry()
        if symmetry == 'cubic':
            self.parameters['b'].value = self.parameters['a'].value
            self.parameters['c'].value = self.parameters['a'].value
            self.parameters['alpha'].value = 90.0
            self.parameters['beta'].value = 90.0
            self.parameters['gamma'].value = 90.0
            self.parameters['a'].enable(vary=True)
            self.parameters['b'].disable(vary=False)
            self.parameters['c'].disable(vary=False)
            self.parameters['alpha'].disable(vary=False)
            self.parameters['beta'].disable(vary=False)
            self.parameters['gamma'].disable(vary=False)
        elif symmetry == 'tetragonal':
            self.parameters['b'].value = self.parameters['a'].value
            self.parameters['alpha'].value = 90.0
            self.parameters['beta'].value = 90.0
            self.parameters['gamma'].value = 90.0
            self.parameters['a'].enable(vary=True)
            self.parameters['b'].disable(vary=False)
            self.parameters['c'].enable(vary=True)
            self.parameters['alpha'].disable(vary=False)
            self.parameters['beta'].disable(vary=False)
            self.parameters['gamma'].disable(vary=False)
        elif symmetry == 'orthorhombic':
            self.parameters['alpha'].value = 90.0
            self.parameters['beta'].value = 90.0
            self.parameters['gamma'].value = 90.0
            self.parameters['a'].enable(vary=True)
            self.parameters['b'].enable(vary=True)
            self.parameters['c'].enable(vary=True)
            self.parameters['alpha'].disable(vary=False)
            self.parameters['beta'].disable(vary=False)
            self.parameters['gamma'].disable(vary=False)
        elif symmetry == 'hexagonal':
            self.parameters['b'].value = self.parameters['a'].value
            self.parameters['alpha'].value = 90.0
            self.parameters['beta'].value = 90.0
            self.parameters['gamma'].value = 120.0
            self.parameters['a'].enable(vary=True)
            self.parameters['b'].disable(vary=False)
            self.parameters['c'].enable(vary=True)
            self.parameters['alpha'].disable(vary=False)
            self.parameters['beta'].disable(vary=False)
            self.parameters['gamma'].disable(vary=False)
        elif symmetry == 'monoclinic':
            self.parameters['alpha'].value = 90.0
            self.parameters['gamma'].value = 90.0
            self.parameters['a'].enable(vary=True)
            self.parameters['b'].enable(vary=True)
            self.parameters['c'].enable(vary=True)
            self.parameters['alpha'].disable(vary=False)
            self.parameters['beta'].enable(vary=True)
            self.parameters['gamma'].disable(vary=False)
        else:
            self.parameters['a'].enable(vary=True)
            self.parameters['b'].enable(vary=True)
            self.parameters['c'].enable(vary=True)
            self.parameters['alpha'].enable(vary=True)
            self.parameters['beta'].enable(vary=True)
            self.parameters['gamma'].enable(vary=True)

    def get_wavelength(self):
        return self.parameters['wavelength'].value

    def get_distance(self):
        return self.parameters['distance'].value

    def get_tilts(self):
        return (self.parameters['yaw'].value, self.parameters['pitch'].value,
                self.parameters['roll'].value)

    def get_centers(self):
        return self.parameters['xc'].value, self.parameters['yc'].value

    def get_phi(self):
        return (self.parameters['phi'].value,
                self.parameters['phi_step'].value)

    def get_angles(self):
        return (self.parameters['chi'].value, self.parameters['omega'].value,
                self.parameters['twotheta'].value,
                self.parameters['gonpitch'].value)

    def get_polar_max(self):
        return self.parameters['polar'].value

    def set_polar_max(self):
        self.refine.polar_max = self.get_polar_max()

    def get_tolerance(self):
        return self.parameters['polar_tolerance'].value

    def get_hkl_tolerance(self):
        try:
            return np.float32(self.tolerance_box.text())
        except Exception:
            return self.refine.hkl_tolerance

    def plot_lattice(self):
        self.transfer_parameters()
        self.set_polar_max()
        self.plot_peaks()
        self.plot_rings()

    def plot_peaks(self):
        try:
            x, y = (self.refine.xp[self.refine.idx],
                    self.refine.yp[self.refine.idx])
            polar_angles, azimuthal_angles = self.refine.calculate_angles(x, y)
            if polar_angles[0] > polar_angles[-1]:
                polar_angles = polar_angles[::-1]
                azimuthal_angles = azimuthal_angles[::-1]
            azimuthal_field = NXfield(azimuthal_angles, name='azimuthal_angle')
            azimuthal_field.long_name = 'Azimuthal Angle'
            polar_field = NXfield(polar_angles, name='polar_angle')
            polar_field.long_name = 'Polar Angle'
            plotview = get_plotview()
            plotview.plot(
                NXdata(azimuthal_field, polar_field, title='Peak Angles'))
        except NeXusError as error:
            report_error('Plotting Lattice', error)

    def plot_rings(self, polar_max=None):
        if polar_max is None:
            polar_max = self.refine.polar_max
        peaks = self.refine.calculate_rings(polar_max)
        plotview = get_plotview()
        plotview.vlines(peaks, colors='r', linestyles='dotted')
        plotview.draw()

    @property
    def refined(self):
        refined = {}
        for p in self.parameters:
            if self.parameters[p].vary:
                refined[p] = True
        return refined

    def refine_angles(self):
        self.parameters.status_message.setText('Fitting...')
        self.parameters.status_message.repaint()
        self.mainwindow.app.app.processEvents()
        self.parameters['phi'].vary = False
        self.transfer_parameters()
        self.set_symmetry()
        self.refine.refine_angles(**self.refined)
        self.parameters.result = self.refine.result
        self.parameters.fit_report = self.refine.fit_report
        self.fit_report.append(self.refine.fit_report)
        self.update_parameters()
        self.parameters.status_message.setText(self.parameters.result.message)
        if self.peaks_box and self.peaks_box.isVisible():
            self.update_table()

    def refine_hkls(self):
        self.parameters.status_message.setText('Fitting...')
        self.parameters.status_message.repaint()
        self.mainwindow.app.app.processEvents()
        self.set_symmetry()
        self.transfer_parameters()
        self.refine.refine_hkls(**self.refined)
        self.parameters.result = self.refine.result
        self.parameters.fit_report = self.refine.fit_report
        self.fit_report.append(self.refine.fit_report)
        self.update_parameters()
        self.parameters.status_message.setText(self.parameters.result.message)
        if self.peaks_box and self.peaks_box.isVisible():
            self.update_table()

    def refine_orientation(self):
        self.parameters.status_message.setText('Fitting...')
        self.parameters.status_message.repaint()
        self.mainwindow.app.app.processEvents()
        self.transfer_parameters()
        self.refine.refine_orientation_matrix()
        self.parameters.result = self.refine.result
        self.parameters.fit_report = self.refine.fit_report
        self.fit_report.append(self.refine.fit_report)
        self.update_parameters()
        self.parameters.status_message.setText(self.parameters.result.message)
        if self.peaks_box and self.peaks_box.isVisible():
            self.update_table()

    def restore_parameters(self):
        self.refine.restore_parameters()
        self.update_parameters()
        try:
            self.fit_report.pop()
        except IndexError:
            pass

    def reset_parameters(self):
        self.refine.read_parameters()
        self.update_parameters()
        self.set_symmetry()
        try:
            self.fit_report.pop()
        except IndexError:
            pass

    def list_peaks(self):
        if self.peaks_box is not None and self.table_model is not None:
            self.update_table()
            return
        self.peaks_box = BaseDialog(self)
        self.peaks_box.setMinimumWidth(600)
        self.peaks_box.setMinimumHeight(600)
        header = [
            'i', 'x', 'y', 'z', 'Polar', 'Azi', 'Intensity', 'H', 'K', 'L',
            'Diff'
        ]
        peak_list = self.refine.get_peaks()
        self.refine.assign_rings()
        self.rings = self.refine.get_ring_hkls()
        orient_layout = QtWidgets.QHBoxLayout()
        if self.refine.primary is None:
            self.refine.primary = 0
        if self.refine.secondary is None:
            self.refine.secondary = 1
        self.primary_box = QtWidgets.QLineEdit(str(self.refine.primary))
        self.primary_box.setAlignment(QtCore.Qt.AlignRight)
        self.primary_box.setFixedWidth(80)
        self.secondary_box = QtWidgets.QLineEdit(str(self.refine.secondary))
        self.secondary_box.setAlignment(QtCore.Qt.AlignRight)
        self.secondary_box.setFixedWidth(80)
        orient_button = QtWidgets.QPushButton('Orient')
        orient_button.clicked.connect(self.orient)

        orient_layout.addStretch()
        orient_layout.addWidget(QtWidgets.QLabel('Primary'))
        orient_layout.addWidget(self.primary_box)
        orient_layout.addWidget(QtWidgets.QLabel('Secondary'))
        orient_layout.addWidget(self.secondary_box)
        orient_layout.addStretch()
        orient_layout.addWidget(orient_button)

        self.table_view = QtWidgets.QTableView()
        self.table_model = NXTableModel(self, peak_list, header)
        self.table_view.setModel(self.table_model)
        self.table_view.resizeColumnsToContents()
        self.table_view.horizontalHeader().stretchLastSection()
        self.table_view.setSelectionBehavior(
            QtWidgets.QAbstractItemView.SelectRows)
        self.table_view.doubleClicked.connect(self.plot_peak)
        self.table_view.setSortingEnabled(True)
        self.table_view.sortByColumn(0, QtCore.Qt.AscendingOrder)
        layout = QtWidgets.QVBoxLayout()
        layout.addLayout(orient_layout)
        layout.addWidget(self.table_view)
        close_layout = QtWidgets.QHBoxLayout()
        self.status_text = QtWidgets.QLabel('Score: %.4f' %
                                            self.refine.score())
        self.tolerance_box = QtWidgets.QLineEdit(str(
            self.refine.hkl_tolerance))
        self.tolerance_box.setAlignment(QtCore.Qt.AlignRight)
        self.tolerance_box.setMaxLength(5)
        self.tolerance_box.editingFinished.connect(self.update_table)
        self.tolerance_box.setFixedWidth(80)
        save_button = QtWidgets.QPushButton('Save Orientation')
        save_button.clicked.connect(self.save_orientation)
        close_button = QtWidgets.QPushButton('Close Window')
        close_button.clicked.connect(self.close_peaks_box)
        close_layout.addWidget(self.status_text)
        close_layout.addStretch()
        close_layout.addWidget(QtWidgets.QLabel('Threshold'))
        close_layout.addWidget(self.tolerance_box)
        close_layout.addStretch()
        close_layout.addWidget(save_button)
        close_layout.addStretch()
        close_layout.addWidget(close_button)
        layout.addLayout(close_layout)
        self.peaks_box.setLayout(layout)
        self.peaks_box.setWindowTitle('%s Peak Table' % self.entry.nxtitle)
        self.peaks_box.adjustSize()
        self.peaks_box.show()
        self.plotview = None

    def update_table(self):
        if self.peaks_box is None:
            self.list_peaks()
        self.transfer_parameters()
        self.refine.hkl_tolerance = self.get_hkl_tolerance()
        self.table_model.peak_list = self.refine.get_peaks()
        self.refine.assign_rings()
        self.rings = self.refine.get_ring_hkls()
        rows, columns = len(self.table_model.peak_list), 11
        self.table_model.dataChanged.emit(
            self.table_model.createIndex(0, 0),
            self.table_model.createIndex(rows - 1, columns - 1))
        self.table_view.resizeColumnsToContents()
        self.status_text.setText('Score: %.4f' % self.refine.score())
        self.peaks_box.setWindowTitle('%s Peak Table' % self.entry.nxtitle)
        self.peaks_box.setVisible(True)

    def plot_peak(self):
        row = self.table_view.currentIndex().row()
        data = self.entry.data
        i, x, y, z = [
            self.table_view.model().peak_list[row][i] for i in range(4)
        ]
        signal = data.nxsignal
        xmin, xmax = max(0, x - 200), min(x + 200, signal.shape[2])
        ymin, ymax = max(0, y - 200), min(y + 200, signal.shape[1])
        zmin, zmax = max(0, z - 20), min(z + 20, signal.shape[0])
        zslab = np.s_[zmin:zmax, ymin:ymax, xmin:xmax]
        if self.plotview is None:
            self.plotview = NXPlotView('Peak Plot')
        self.plotview.plot(data[zslab], log=True)
        self.plotview.ax.set_title('%s: Peak %s' % (data.nxtitle, i))
        self.plotview.ztab.maxbox.setValue(z)
        self.plotview.aspect = 'equal'
        self.plotview.crosshairs(x, y, color='r', linewidth=0.5)

    def orient(self):
        self.refine.primary = int(self.primary_box.text())
        self.refine.secondary = int(self.secondary_box.text())
        self.refine.Umat = (
            self.refine.get_UBmat(self.refine.primary, self.refine.secondary) *
            self.refine.Bimat)
        self.update_table()

    def save_orientation(self):
        self.write_parameters()

    def close_peaks_box(self):
        self.peaks_box.close()
        self.peaks_box = None
Exemplo n.º 12
0
class ConfigurationDialog(NXDialog):
    def __init__(self, parent=None):
        super().__init__(parent)

        self.settings = NXSettings().settings

        self.configuration_file = NXroot()
        self.configuration_file['entry'] = NXentry()

        self.detectors = {}
        self.entries = {}

        self.setup_groups()
        self.setup_configuration()
        self.setup_analysis()
        self.setup_scan()
        self.setup_instrument()

        self.set_layout(
            self.directorybox('Choose Experiment Directory', default=False),
            self.configuration.grid(header=False),
            self.analysis.grid(header=False, title='Analysis Settings'),
            self.scan.grid(header=False, title='Scan Settings'),
            self.instrument.grid(header=False, title='Detector Settings'))
        self.set_title('New Configuration')

    def setup_groups(self):
        entry = self.configuration_file['entry']
        entry['nxreduce'] = NXparameters()
        entry['instrument'] = NXinstrument()
        entry['instrument/monochromator'] = NXmonochromator()
        entry['instrument/goniometer'] = NXgoniometer()
        entry['instrument/detector'] = NXdetector()

    def setup_configuration(self):
        default = self.settings['nxrefine']
        entry = self.configuration_file['entry']
        entry['instrument/monochromator/wavelength'] = NXfield(
            default['wavelength'], dtype=np.float32)
        entry['instrument/monochromator/wavelength'].attrs['units'] = (
            'Angstroms')
        entry['instrument/monochromator/energy'] = NXfield(12.398419739640717 /
                                                           0.5,
                                                           dtype=np.float32)
        entry['instrument/monochromator/energy'].attrs['units'] = 'keV'
        entry['instrument/goniometer'] = NXgoniometer()
        entry['instrument/detector'] = NXdetector()
        self.configuration = GridParameters()
        self.configuration.add('configuration', 'configuration',
                               'Configuration Filename')
        self.configuration.add('wavelength',
                               entry['instrument/monochromator/wavelength'],
                               'Wavelength (Å)')

    def setup_analysis(self):
        default = self.settings['nxreduce']
        entry = self.configuration_file['entry']
        entry['nxreduce/threshold'] = NXfield(default['threshold'],
                                              dtype=float)
        entry['nxreduce/monitor'] = NXfield(default['monitor'])
        entry['nxreduce/norm'] = NXfield(default['norm'], dtype=float)
        entry['nxreduce/first_frame'] = NXfield(default['first'], dtype=int)
        entry['nxreduce/last_frame'] = NXfield(default['last'], dtype=int)
        entry['nxreduce/radius'] = NXfield(default['radius'], dtype=float)
        self.analysis = GridParameters()
        self.analysis.add('threshold', entry['nxreduce/threshold'],
                          'Peak Threshold')
        self.analysis.add('first', entry['nxreduce/first_frame'],
                          'First Frame')
        self.analysis.add('last', entry['nxreduce/last_frame'], 'Last Frame')
        self.analysis.add('monitor', ['monitor1', 'monitor2'],
                          'Normalization Monitor')
        self.analysis['monitor'].value = default['monitor']
        self.analysis.add('norm', entry['nxreduce/norm'],
                          'Normalization Value')
        self.analysis.add('radius', entry['nxreduce/radius'],
                          'Punch Radius (Å)')

    def setup_scan(self):
        default = self.settings['nxrefine']
        entry = self.configuration_file['entry']
        entry['instrument/goniometer/chi'] = (NXfield(default['chi'],
                                                      dtype=float))
        entry['instrument/goniometer/chi'].attrs['units'] = 'degree'
        entry['instrument/goniometer/phi'] = (NXfield(default['phi'],
                                                      dtype=float))
        entry['instrument/goniometer/phi'].attrs['step'] = (NXfield(
            default['phi_step'], dtype=float))
        entry['instrument/goniometer/phi'].attrs['end'] = (NXfield(
            default['phi_end'], dtype=float))
        entry['instrument/goniometer/phi'].attrs['units'] = 'degree'
        entry['instrument/detector/frame_time'] = (NXfield(
            1 / float(default['frame_rate']), dtype=float))
        self.scan = GridParameters()
        self.scan.add('chi', default['chi'], 'Chi (deg)')
        self.scan.add('phi_start', default['phi'], 'Phi Start (deg)')
        self.scan.add('phi_end', default['phi_end'], 'Phi End (deg)')
        self.scan.add('phi_step', default['phi_step'], 'Phi Step (deg)')
        self.scan.add('frame_rate', default['frame_rate'], 'Frame Rate (Hz)')

    def setup_instrument(self):
        default = self.settings['nxrefine']
        entry = self.configuration_file['entry']
        entry['instrument/detector/distance'] = NXfield(default['distance'],
                                                        dtype=float)
        entry['instrument/detector/distance'].attrs['units'] = 'mm'
        self.instrument = GridParameters()
        self.instrument.add('distance', entry['instrument/detector/distance'],
                            'Detector Distance (mm)')
        detector_list = sorted(
            list(set([detector().name
                      for detector in ALL_DETECTORS.values()])))
        self.instrument.add('detector', detector_list, 'Detector')
        self.instrument['detector'].value = 'Pilatus CdTe 2M'
        self.instrument.add('positions', [0, 1, 2, 3, 4, 5, 6, 7, 8],
                            'Number of Detector Positions',
                            slot=self.set_entries)
        self.instrument['positions'].value = '0'

    def setup_entry(self, position):
        default = self.settings['nxrefine']
        entry = NXentry()
        self.detectors[position] = GridParameters()
        self.detectors[position].add('x', default['x'], 'Translation - x (mm)')
        self.detectors[position].add('y', default['y'], 'Translation - y (mm)')
        self.detectors[position].add('omega', default['omega'], 'Omega (deg)')
        self.configuration_file[f'f{position}'] = entry

    def get_detector(self):
        for detector in ALL_DETECTORS:
            if (ALL_DETECTORS[detector]().name ==
                    self.instrument['detector'].value):
                return ALL_DETECTORS[detector]()

    @property
    def positions(self):
        return int(self.instrument['positions'].value)

    @property
    def position(self):
        try:
            return int(self.entry_box.currentText())
        except ValueError:
            return 1

    def set_entries(self):
        self.entry_box = self.select_box(
            [str(i) for i in range(1, self.positions + 1)],
            slot=self.choose_position)
        self.entry_layout = self.make_layout(
            self.labels('Position', header=True), self.entry_box)
        self.add_layout(self.entry_layout)
        for position in range(1, self.positions + 1):
            self.setup_entry(position)
            self.add_layout(self.detectors[position].grid(header=False))
            if position != 1:
                self.detectors[position].hide_grid()
        self.add_layout(self.close_buttons(save=True))

    def choose_position(self):
        for i in self.detectors:
            self.detectors[i].hide_grid()
        if self.position in self.detectors:
            self.detectors[self.position].show_grid()

    def get_parameters(self):
        entry = self.configuration_file['entry']
        entry['nxreduce/threshold'] = self.analysis['threshold'].value
        entry['nxreduce/first_frame'] = self.analysis['first'].value
        entry['nxreduce/last_frame'] = self.analysis['last'].value
        entry['nxreduce/monitor'] = self.analysis['monitor'].value
        entry['nxreduce/norm'] = self.analysis['norm'].value
        entry['nxreduce/radius'] = self.analysis['radius'].value
        entry['instrument/monochromator/wavelength'] = (
            self.configuration['wavelength'].value)
        entry['instrument/monochromator/energy'] = (
            12.398419739640717 / self.configuration['wavelength'].value)
        detector = self.get_detector()
        entry['instrument/detector/description'] = detector.name
        entry['instrument/detector/distance'] = (
            self.instrument['distance'].value)
        entry['instrument/detector/pixel_size'] = detector.pixel1 * 1000
        entry['instrument/detector/pixel_size'].attrs['units'] = 'mm'
        entry['instrument/detector/pixel_mask'] = detector.mask
        entry['instrument/detector/shape'] = detector.shape
        entry['instrument/detector/yaw'] = 0.0
        entry['instrument/detector/pitch'] = 0.0
        entry['instrument/detector/roll'] = 0.0
        for position in range(1, self.positions + 1):
            entry = self.configuration_file[f'f{position}']
            entry['instrument'] = self.configuration_file['entry/instrument']
            entry['instrument/detector/translation_x'] = (
                self.detectors[position]['x'].value)
            entry['instrument/detector/translation_x'].attrs['units'] = 'mm'
            entry['instrument/detector/translation_y'] = (
                self.detectors[position]['y'].value)
            entry['instrument/detector/translation_y'].attrs['units'] = 'mm'
            if self.scan['frame_rate'].value > 0.0:
                entry['instrument/detector/frame_time'] = (
                    1.0 / self.scan['frame_rate'].value)
            else:
                entry['instrument/detector/frame_time'] = 0.1
            entry['instrument/detector/frame_time'].attrs['units'] = 's'
            entry['instrument/goniometer/phi'] = self.scan['phi_start'].value
            entry['instrument/goniometer/phi'].attrs['step'] = (
                self.scan['phi_step'].value)
            entry['instrument/goniometer/phi'].attrs['end'] = (
                self.scan['phi_end'].value)
            entry['instrument/goniometer/chi'] = self.scan['chi'].value
            entry['instrument/goniometer/omega'] = (
                self.detectors[position]['omega'].value)

    def accept(self):
        try:
            experiment_directory = self.get_directory()
            configuration_directory = os.path.join(experiment_directory,
                                                   'configurations')
            self.mainwindow.default_directory = experiment_directory
            self.get_parameters()
            self.configuration_file.save(
                os.path.join(
                    configuration_directory,
                    self.configuration['configuration'].value + '.nxs'))
            self.treeview.tree.load(self.configuration_file.nxfilename, 'rw')
            super().accept()
        except Exception as error:
            report_error("Defining New Configuration", error)
Exemplo n.º 13
0
class CalculateDialog(BaseDialog):

    def __init__(self, parent=None):
        super(CalculateDialog, self).__init__(parent)
        
        self.select_entry(self.choose_entry)

        self.refine = NXRefine(self.entry)
        self.refine.read_parameters()

        self.parameters = GridParameters()
        self.parameters.add('wavelength', self.refine.wavelength, 'Wavelength (Ang)')
        self.parameters.add('distance', self.refine.distance, 'Detector Distance (mm)')
        self.parameters.add('xc', self.refine.xc, 'Beam Center - x')
        self.parameters.add('yc', self.refine.yc, 'Beam Center - y')
        self.parameters.add('pixel', self.refine.pixel_size, 'Pixel Size (mm)')
        action_buttons = self.action_buttons(('Plot', self.plot_lattice),
                                             ('Save', self.write_parameters))
        self.set_layout(self.entry_layout, self.parameters.grid(), 
                        action_buttons, self.close_buttons())
        self.set_title('Calculate Angles')

    def choose_entry(self):
        self.refine = NXRefine(self.entry)
        self.update_parameters()

    def update_parameters(self):
        self.parameters['wavelength'].value = self.refine.wavelength
        self.parameters['distance'].value = self.refine.distance
        self.parameters['xc'].value = self.refine.xc
        self.parameters['yc'].value = self.refine.yc
        self.parameters['pixel'].value = self.refine.pixel_size

    def get_wavelength(self):
        return self.parameters['wavelength'].value

    def get_distance(self):
        return self.parameters['distance'].value

    def get_centers(self):
        return self.parameters['xc'].value, self.parameters['yc'].value

    def get_pixel_size(self):
        return self.parameters['pixel'].value

    def get_parameters(self):
        self.refine.wavelength = self.get_wavelength()
        self.refine.distance = self.get_distance()
        self.refine.xc, self.refine.yc = self.get_centers()
        self.refine.pixel_size = self.get_pixel_size()
        self.refine.yaw = self.refine.pitch = self.refine.roll = None

    def plot_lattice(self):
        try:
            self.get_parameters()
            self.plot_peaks(self.refine.xp, self.refine.yp)
        except NeXusError as error:
            report_error('Calculating Angles', error)

    def plot_peaks(self, x, y):
        try:
            polar_angles, azimuthal_angles = self.refine.calculate_angles(x, y)
            if polar_angles[0] > polar_angles[-1]:
                polar_angles = polar_angles[::-1]
                azimuthal_angles = azimuthal_angles[::-1]
            azimuthal_field = NXfield(azimuthal_angles, name='azimuthal_angle')
            azimuthal_field.long_name = 'Azimuthal Angle'
            polar_field = NXfield(polar_angles, name='polar_angle')
            polar_field.long_name = 'Polar Angle'
            plotview = get_plotview()
            plotview.plot(NXdata(azimuthal_field, polar_field, title='Peak Angles'))
        except NeXusError as error:
            report_error('Plotting Lattice', error)

    def write_parameters(self):
        try:
            self.get_parameters()
            polar_angles, azimuthal_angles = self.refine.calculate_angles(
                                                 self.refine.xp, self.refine.yp)
            self.refine.write_angles(polar_angles, azimuthal_angles)
            self.refine.write_parameters()
        except NeXusError as error:
            report_error('Calculating Angles', error)
Exemplo n.º 14
0
class Mask3DDialog(BaseDialog):

    def __init__(self, parent=None):
        super(Mask3DDialog, self).__init__(parent)

        self.select_entry(self.choose_entry)

        self.parameters = GridParameters()
        self.parameters.add('radius', 200, 'Radius')
        self.parameters.add('width', 3, 'Frame Width')
        self.set_layout(self.entry_layout, 
                        self.parameters.grid(),
                        self.action_buttons(('Calculate 3D Mask', self.calculate_mask)),
                        self.progress_layout(save=True))
        self.progress_bar.setVisible(False)
        self.progress_bar.setValue(0)
        self.set_title('Calculate 3D Mask')
        self.reduce = None

    def choose_entry(self):
        self.reduce = NXReduce(self.entry)

    @property
    def radius(self):
        return self.parameters['radius'].value

    @property
    def width(self):
        return self.parameters['width'].value

    def calculate_mask(self):
        self.check_lock(self.reduce.wrapper_file)
        self.thread = QtCore.QThread()
        self.reduce = NXReduce(self.entry, radius=self.radius, width=self.width,
                               mask=True, overwrite=True, gui=True)
        self.reduce.moveToThread(self.thread)
        self.reduce.start.connect(self.start_progress)
        self.reduce.update.connect(self.update_progress)
        self.reduce.result.connect(self.calculate_mask)
        self.reduce.stop.connect(self.stop)
        self.thread.started.connect(self.reduce.nxfind)
        self.thread.start(QtCore.QThread.LowestPriority)

    def check_lock(self, file_name):
        try:
            with Lock(file_name, timeout=2):
                pass
        except LockException as error:
            if self.confirm_action('Clear lock?', str(error)):
                Lock(file_name).release()

    def calculate_mask(self, mask):
        self.mask = mask

    def stop(self):
        self.stop_progress()
        if self.thread and self.thread.isRunning():
            self.reduce.stopped = True
            self.thread.exit()

    def accept(self):
        try:
            with Lock(self.reduce.wrapper_file):
                self.reduce.write_peaks(self.peaks)
        except LockException as error:
            if self.confirm_action('Clear lock?', str(error)):
                Lock(self.reduce.wrapper_file).release()
        if self.thread:
            self.stop()
        super(Mask3DDialog, self).accept()

    def reject(self):
        if self.thread:
            self.stop()
        super(Mask3DDialog, self).reject()
Exemplo n.º 15
0
class MaximumDialog(NXDialog):
    def __init__(self, parent=None):
        super().__init__(parent)

        self.select_entry(self.choose_entry)

        self.parameters = GridParameters()
        self.parameters.add('first', '', 'First Frame')
        self.parameters.add('last', '', 'Last Frame')

        self.output = NXLabel('Maximum Value:')
        self.set_layout(
            self.entry_layout, self.output, self.parameters.grid(),
            self.action_buttons(('Find Maximum', self.find_maximum)),
            self.progress_layout(save=True))
        self.progress_bar.setVisible(False)
        self.progress_bar.setValue(0)
        self.set_title('Find Maximum Value')
        self.reduce = None

    def choose_entry(self):
        self.reduce = NXReduce(self.entry)
        self.maximum = self.reduce.maximum
        if self.reduce.first:
            self.parameters['first'].value = self.reduce.first
        if self.reduce.last:
            self.parameters['last'].value = self.reduce.last

    @property
    def first(self):
        try:
            _first = np.int32(self.parameters['first'].value)
            if _first >= 0:
                return _first
            else:
                return None
        except Exception as error:
            return None

    @property
    def last(self):
        try:
            _last = np.int32(self.parameters['last'].value)
            if _last > 0:
                return _last
            else:
                return None
        except Exception as error:
            return None

    @property
    def maximum(self):
        return np.float(self.output.text().split()[-1])

    @maximum.setter
    def maximum(self, value):
        self.output.setText(f'Maximum Value: {value}')

    def find_maximum(self):
        if is_file_locked(self.reduce.data_file):
            return
        self.start_thread()
        self.reduce = NXReduce(self.entry,
                               first=self.first,
                               last=self.last,
                               maxcount=True,
                               overwrite=True,
                               gui=True)
        self.reduce.moveToThread(self.thread)
        self.reduce.start.connect(self.start_progress)
        self.reduce.update.connect(self.update_progress)
        self.reduce.result.connect(self.get_maximum)
        self.reduce.stop.connect(self.stop)
        self.thread.started.connect(self.reduce.nxmax)
        self.thread.finished.connect(self.stop)
        self.thread.start(QtCore.QThread.LowestPriority)

    def get_maximum(self, maximum):
        self.maximum = maximum

    def stop(self):
        self.stop_progress()
        if self.thread and self.thread.isRunning():
            self.reduce.stopped = True
        self.stop_thread()

    def accept(self):
        try:
            self.reduce.write_maximum(self.maximum)
            self.reduce.record('nxmax',
                               maximum=self.maximum,
                               first_frame=self.first,
                               last_frame=self.last)
            self.reduce.record_end('nxmax')
            self.stop()
            super().accept()
        except Exception as error:
            report_error("Finding Maximum", error)

    def reject(self):
        self.stop()
        super().reject()
Exemplo n.º 16
0
class ScanDialog(BaseDialog):

    def __init__(self, parent=None):
        super(ScanDialog, self).__init__(parent)

        self.config_file = None
        self.positions = 1
        self.entries = {}

        self.directory_box = self.directorybox('Choose Experiment Directory',
                                               self.choose_directory,
                                               default=False)
        self.configuration_box = self.select_configuration()
        self.configuration_layout = self.make_layout(
            self.action_buttons(('Choose Experiment Configuration', 
                                 self.choose_configuration)),
            self.configuration_box)
        self.sample_box = self.select_sample()
        self.sample_layout = self.make_layout(
            self.action_buttons(('Choose Sample', self.choose_sample)),
            self.sample_box)
        self.scan_box = self.select_box(['1'], slot=self.choose_position)
        self.setup_scans()

        self.set_layout(self.directory_box,
                        self.configuration_layout,
                        self.sample_layout,
                        self.scan.grid(header=False),
                        self.make_layout(self.labels('Position'), self.scan_box),
                        self.entries[1].grid(header=False),
                        self.entries[2].grid(header=False),
                        self.entries[3].grid(header=False),
                        self.entries[4].grid(header=False),
                        self.entries[5].grid(header=False),
                        self.action_buttons(('Make Scan File', self.make_scan)),
                        self.close_buttons(close=True))

        for i in self.entries:
            self.entries[i].hide_grid()
        self.entries[1].show_grid()
        self.set_title('New Scan')

    @property
    def configuration(self):
        return self.configuration_box.currentText()

    @property
    def sample(self):
        return self.sample_box.currentText().split('/')[0]

    @property
    def label(self):
        return self.sample_box.currentText().split('/')[1]

    @property
    def position(self):
        try:
            return int(self.scan_box.currentText())
        except ValueError:
            return 1

    def choose_directory(self):
        super(ScanDialog, self).choose_directory()
        self.mainwindow.default_directory = self.get_directory()
        self.setup_directory()

    def setup_directory(self):
        self.configuration_box.clear()
        configurations = self.get_configurations()
        for configuration in configurations:
            self.configuration_box.addItem(configuration)
        self.choose_configuration()
        self.sample_box.clear()
        samples = self.get_samples()
        for sample in samples:
            self.sample_box.addItem(sample)
        self.sample_box.adjustSize()
        self.choose_sample()

    def select_configuration(self):
        return self.select_box(self.get_configurations())

    def get_configurations(self):
        home_directory = self.get_directory()
        if (os.path.exists(home_directory) and 
            'configurations' in os.listdir(home_directory)):
            return [f for f in 
                    os.listdir(os.path.join(home_directory, 'configurations'))
                    if f.endswith('.nxs')]
        else:
            return []

    def choose_configuration(self):
        home_directory = self.get_directory()
        config_file = os.path.join(home_directory, 'configurations',
                                   self.configuration)
        if os.path.exists(config_file):
            self.config_file = nxload(config_file)
            self.positions = len(self.config_file.entries) - 1
            self.scan_box.clear()
            for position in range(1, self.positions+1):
                self.scan_box.addItem('%d' % position)
            self.scan_box.setCurrentIndex(0)
            self.copy_configuration()

    def select_sample(self):
        return self.select_box(self.get_samples())
        
    def get_samples(self):
        home_directory = self.get_directory()
        if (os.path.exists(home_directory) and 
            'configurations' in os.listdir(home_directory)):
            sample_directories = [f for f in os.listdir(home_directory)
                                  if (not f.startswith('.') and
                                      os.path.isdir(
                                        os.path.join(home_directory, f)))]
        else:
            return []
        samples = []
        for sample_directory in sample_directories:
            label_directories = [f for f in 
                os.listdir(os.path.join(home_directory, sample_directory))
                if os.path.isdir(os.path.join(home_directory, sample_directory, f))]
            for label_directory in label_directories:
                samples.append(os.path.join(sample_directory, label_directory))
        return [sample.strip() for sample in samples]
                        
    def choose_sample(self):
        pass
                
    def setup_scans(self):
        self.scan = GridParameters()
        self.scan.add('scan', 'scan', 'Scan Label')
        self.scan.add('temperature', 300.0, 'Temperature (K)')
        self.scan.add('phi_start', -5.0, 'Phi Start (deg)')
        self.scan.add('phi_end', 360.0, 'Phi End (deg)')
        self.scan.add('phi_step', 0.1, 'Phi Step (deg)')
        self.scan.add('frame_rate', 10, 'Frame Rate (Hz)')
        
        for position in range(1, 6):
            self.setup_position(position)

    def setup_position(self, position):
        self.entries[position] = GridParameters()
        self.entries[position].add('chi', -90.0, 'Chi (deg)')
        self.entries[position].add('omega', 0.0, 'Omega (deg)')
        self.entries[position].add('x', 0.0, 'Translation - x (mm)')
        self.entries[position].add('y', 0.0, 'Translation - y (mm)')
        self.entries[position].add('linkfile', 'f%d.h5' % position, 'Detector Filename')
        self.entries[position].add('linkpath', '/entry/data/data', 'Detector Data Path')

    def choose_position(self):
        for i in self.entries:
            self.entries[i].hide_grid()
        if self.position in self.entries:
            self.entries[self.position].show_grid()

    def copy_configuration(self):
        self.scan_file = NXroot()
        for entry in self.config_file.entries:
            self.scan_file[entry] = self.config_file[entry]
        self.read_parameters()

    def read_parameters(self):
        for position in range(1, self.positions+1):
            entry = self.scan_file['f%d' % position]
            self.entries[position]['x'].value = entry['instrument/detector/translation_x']
            self.entries[position]['y'].value = entry['instrument/detector/translation_y']

    def get_parameters(self):
        entry = self.scan_file['entry']
        if 'sample' not in entry:
            entry['sample'] = NXsample()
        entry['sample/name'] = self.sample
        entry['sample/label'] = self.label
        entry['sample/temperature'] = self.scan['temperature'].value
        entry['sample/temperature'].attrs['units'] = 'K'
        y_size, x_size = entry['instrument/detector/shape'].nxvalue
        scan = self.scan['scan'].value
        for position in range(1, self.positions+1):
            entry = self.scan_file['f%d' % position]
            entry.makelink(self.scan_file['entry/sample'])
            phi_start = self.scan['phi_start'].value
            phi_end = self.scan['phi_end'].value
            phi_step = self.scan['phi_step'].value
            chi = self.entries[position]['chi'].value
            omega = self.entries[position]['omega'].value
            frame_rate = self.scan['frame_rate'].value
            if 'goniometer' not in entry['instrument']:
                entry['instrument/goniometer'] = NXgoniometer()
            entry['instrument/goniometer/phi'] = phi_start
            entry['instrument/goniometer/phi_set'] = phi_start
            entry['instrument/goniometer/phi'].attrs['step'] = phi_step
            entry['instrument/goniometer/phi'].attrs['end'] = phi_end
            entry['instrument/goniometer/chi'] = chi
            entry['instrument/goniometer/chi_set'] = chi
            entry['instrument/goniometer/omega'] = omega
            entry['instrument/goniometer/omega_set'] = omega
            if frame_rate > 0.0:
                entry['instrument/detector/frame_time'] = 1.0 / frame_rate
            linkpath = self.entries[position]['linkpath'].value
            linkfile = os.path.join(scan, self.entries[position]['linkfile'].value)
            entry['data'] = NXdata()
            entry['data'].nxsignal = NXlink(linkpath, linkfile) 
            entry['data/x_pixel'] = np.arange(x_size, dtype=np.int32)
            entry['data/y_pixel'] = np.arange(y_size, dtype=np.int32)
            entry['data/frame_number'] = np.arange(
                (phi_end-phi_start)/phi_step, dtype=np.int32)
            entry['data'].nxaxes = [entry['data/frame_number'],
                                    entry['data/y_pixel'],
                                    entry['data/x_pixel']]

    def make_scan(self):
        home_directory = self.get_directory()
        self.mainwindow.default_directory = home_directory
        sample_directory = os.path.join(home_directory, self.sample)
        label_directory = os.path.join(home_directory, self.sample, self.label)
        scan_directory = os.path.join(label_directory, self.scan['scan'].value)
        scan_name = self.sample+'_'+self.scan['scan'].value
        try: 
            os.makedirs(scan_directory)
        except Exception:
            pass
        self.copy_configuration()
        self.get_parameters()
        self.scan_file.save(os.path.join(label_directory, scan_name+'.nxs'))
        self.treeview.tree.load(self.scan_file.nxfilename, 'r')
Exemplo n.º 17
0
class CalibrateDialog(NXDialog):

    def __init__(self, parent=None):
        super().__init__(parent)

        self.plotview = None
        self.data = None
        self.counts = None
        self.points = []
        self.pattern_geometry = None
        self.cake_geometry = None
        self.polarization = None
        self.is_calibrated = False
        self.phi_max = -np.pi

        cstr = str(ALL_CALIBRANTS)
        calibrants = sorted(cstr[cstr.index(':')+2:].split(', '))
        self.parameters = GridParameters()
        self.parameters.add('calibrant', calibrants, 'Calibrant')
        self.parameters['calibrant'].value = 'CeO2'
        self.parameters.add('wavelength', 0.5, 'Wavelength (Ang)', False)
        self.parameters.add('distance', 100.0, 'Detector Distance (mm)', True)
        self.parameters.add('xc', 512, 'Beam Center - x', True)
        self.parameters.add('yc', 512, 'Beam Center - y', True)
        self.parameters.add('yaw', 0.0, 'Yaw (degrees)', True)
        self.parameters.add('pitch', 0.0, 'Pitch (degrees)', True)
        self.parameters.add('roll', 0.0, 'Roll (degrees)', True)
        self.parameters.add('search_size', 10, 'Search Size (pixels)')
        self.rings_box = self.select_box([f'Ring{i}' for i in range(1, 21)])
        self.set_layout(self.select_entry(self.choose_entry),
                        self.progress_layout(close=True))
        self.set_title('Calibrating Powder')

    def choose_file(self):
        super().choose_file()
        powder_file = self.get_filename()
        if powder_file:
            self.data = load_image(powder_file)
            self.counts = self.data.nxsignal.nxvalue
            self.plot_data()

    def choose_entry(self):
        if self.layout.count() == 2:
            self.insert_layout(
                1, self.filebox('Choose Powder Calibration File'))
            self.insert_layout(2, self.parameters.grid(header=False))
            self.insert_layout(
                3, self.action_buttons(('Select Points', self.select),
                                       ('Autogenerate Rings', self.auto),
                                       ('Clear Points', self.clear_points)))
            self.insert_layout(4, self.make_layout(self.rings_box))
            self.insert_layout(
                5, self.action_buttons(('Calibrate', self.calibrate),
                                       ('Plot Cake', self.plot_cake),
                                       ('Restore', self.restore_parameters),
                                       ('Save', self.save_parameters)))
        self.parameters['wavelength'].value = (
            self.entry['instrument/monochromator/wavelength'])
        detector = self.entry['instrument/detector']
        self.parameters['distance'].value = detector['distance']
        self.parameters['yaw'].value = detector['yaw']
        self.parameters['pitch'].value = detector['pitch']
        self.parameters['roll'].value = detector['roll']
        if 'beam_center_x' in detector:
            self.parameters['xc'].value = detector['beam_center_x']
        if 'beam_center_y' in detector:
            self.parameters['yc'].value = detector['beam_center_y']
        self.pixel_size = (
            self.entry['instrument/detector/pixel_size'].nxvalue * 1e-3)
        self.pixel_mask = self.entry['instrument/detector/pixel_mask'].nxvalue
        self.ring = self.selected_ring
        if 'calibration' in self.entry['instrument']:
            self.data = self.entry['instrument/calibration']
            self.counts = self.data.nxsignal.nxvalue
            self.plot_data()
        else:
            self.close_plots()

    @property
    def search_size(self):
        return int(self.parameters['search_size'].value)

    @property
    def selected_ring(self):
        return int(self.rings_box.currentText()[4:]) - 1

    @property
    def ring_color(self):
        colors = ['r', 'b', 'g', 'c', 'm'] * 4
        return colors[self.ring]

    def plot_data(self):
        if self.plotview is None:
            if 'Powder Calibration' in plotviews:
                self.plotview = plotviews['Powder Calibration']
            else:
                self.plotview = NXPlotView('Powder Calibration')
        self.plotview.plot(self.data, log=True)
        self.plotview.aspect = 'equal'
        self.plotview.ytab.flipped = True
        self.clear_points()

    def on_button_press(self, event):
        self.plotview.make_active()
        if event.inaxes:
            self.xp, self.yp = event.x, event.y
        else:
            self.xp, self.yp = 0, 0

    def on_button_release(self, event):
        self.ring = self.selected_ring
        if event.inaxes:
            if abs(event.x - self.xp) > 5 or abs(event.y - self.yp) > 5:
                return
            x, y = self.plotview.inverse_transform(event.xdata, event.ydata)
            for i, point in enumerate(self.points):
                circle = point[0]
                if circle.shape.contains_point(
                        self.plotview.ax.transData.transform((x, y))):
                    circle.remove()
                    for circle in point[2]:
                        circle.remove()
                    del self.points[i]
                    return
            self.add_points(x, y)

    def circle(self, idx, idy, alpha=1.0):
        return self.plotview.circle(idx, idy, self.search_size,
                                    facecolor=self.ring_color, edgecolor='k',
                                    alpha=alpha)

    def select(self):
        self.plotview.cidpress = self.plotview.mpl_connect(
            'button_press_event', self.on_button_press)
        self.plotview.cidrelease = self.plotview.mpl_connect(
            'button_release_event', self.on_button_release)

    def auto(self):
        xc, yc = self.parameters['xc'].value, self.parameters['yc'].value
        wavelength = self.parameters['wavelength'].value
        distance = self.parameters['distance'].value * 1e-3
        self.start_progress((0, self.selected_ring+1))
        for ring in range(self.selected_ring+1):
            self.update_progress(ring)
            if len([p for p in self.points if p[3] == ring]) > 0:
                continue
            self.ring = ring
            theta = 2 * np.arcsin(wavelength /
                                  (2*self.calibrant.dSpacing[ring]))
            r = distance * np.tan(theta) / self.pixel_size
            phi = self.phi_max = -np.pi
            while phi < np.pi:
                x, y = np.int(xc + r*np.cos(phi)), np.int(yc + r*np.sin(phi))
                if ((x > 0 and x < self.data.x.max()) and
                    (y > 0 and y < self.data.y.max()) and
                        not self.pixel_mask[y, x]):
                    self.add_points(x, y, phi)
                    phi = self.phi_max + 0.2
                else:
                    phi = phi + 0.2
        self.stop_progress()

    def add_points(self, x, y, phi=0.0):
        xc, yc = self.parameters['xc'].value, self.parameters['yc'].value
        idx, idy = self.find_peak(x, y)
        points = [(idy, idx)]
        circles = []
        massif = Massif(self.counts)
        extra_points = massif.find_peaks((idy, idx))
        for point in extra_points:
            points.append(point)
            circles.append(self.circle(point[1], point[0], alpha=0.3))
        phis = np.array([np.arctan2(p[0]-yc, p[1]-xc) for p in points])
        if phi < -0.5*np.pi:
            phis[np.where(phis > 0.0)] -= 2 * np.pi
        self.phi_max = max(*phis, self.phi_max)
        self.points.append([self.circle(idx, idy), points, circles, self.ring])

    def find_peak(self, x, y):
        s = self.search_size
        left = int(np.round(x - s * 0.5))
        if left < 0:
            left = 0
        top = int(np.round(y - s * 0.5))
        if top < 0:
            top = 0
        region = self.counts[top:(top+s), left:(left+s)]
        idy, idx = np.where(region == region.max())
        idx = left + idx[0]
        idy = top + idy[0]
        return idx, idy

    def clear_points(self):
        for i, point in enumerate(self.points):
            circle = point[0]
            circle.remove()
            for circle in point[2]:
                circle.remove()
        self.points = []

    @property
    def calibrant(self):
        return ALL_CALIBRANTS[self.parameters['calibrant'].value]

    @property
    def point_array(self):
        points = []
        for point in self.points:
            for p in point[1]:
                points.append((p[0], p[1], point[3]))
        return np.array(points)

    def prepare_parameters(self):
        self.parameters.set_parameters()
        self.wavelength = self.parameters['wavelength'].value * 1e-10
        self.distance = self.parameters['distance'].value * 1e-3
        self.yaw = np.radians(self.parameters['yaw'].value)
        self.pitch = np.radians(self.parameters['pitch'].value)
        self.roll = np.radians(self.parameters['roll'].value)
        self.xc = self.parameters['xc'].value
        self.yc = self.parameters['yc'].value

    def calibrate(self):
        self.prepare_parameters()
        self.orig_pixel1 = self.pixel_size
        self.orig_pixel2 = self.pixel_size
        self.pattern_geometry = GeometryRefinement(self.point_array,
                                                   dist=self.distance,
                                                   wavelength=self.wavelength,
                                                   pixel1=self.pixel_size,
                                                   pixel2=self.pixel_size,
                                                   calibrant=self.calibrant)
        self.refine()
        self.create_cake_geometry()
        self.pattern_geometry.reset()

    def refine(self):
        self.pattern_geometry.data = self.point_array

        if self.parameters['wavelength'].vary:
            self.pattern_geometry.refine2()
            fix = []
        else:
            fix = ['wavelength']
        if not self.parameters['distance'].vary:
            fix.append('dist')
        self.pattern_geometry.refine2_wavelength(fix=fix)
        self.read_parameters()
        self.is_calibrated = True
        self.create_cake_geometry()
        self.pattern_geometry.reset()

    def create_cake_geometry(self):
        self.cake_geometry = AzimuthalIntegrator()
        pyFAI_parameter = self.pattern_geometry.getPyFAI()
        pyFAI_parameter['wavelength'] = self.pattern_geometry.wavelength
        self.cake_geometry.setPyFAI(dist=pyFAI_parameter['dist'],
                                    poni1=pyFAI_parameter['poni1'],
                                    poni2=pyFAI_parameter['poni2'],
                                    rot1=pyFAI_parameter['rot1'],
                                    rot2=pyFAI_parameter['rot2'],
                                    rot3=pyFAI_parameter['rot3'],
                                    pixel1=pyFAI_parameter['pixel1'],
                                    pixel2=pyFAI_parameter['pixel2'])
        self.cake_geometry.wavelength = pyFAI_parameter['wavelength']

    def plot_cake(self):
        if 'Cake Plot' in plotviews:
            plotview = plotviews['Cake Plot']
        else:
            plotview = NXPlotView('Cake Plot')
        if not self.is_calibrated:
            raise NeXusError('No refinement performed')
        res = self.cake_geometry.integrate2d(self.counts,
                                             1024, 1024,
                                             method='csr',
                                             unit='2th_deg',
                                             correctSolidAngle=True)
        self.cake_data = NXdata(res[0],
                                (NXfield(res[2], name='azimumthal_angle'),
                                 NXfield(res[1], name='polar_angle')))
        self.cake_data['title'] = 'Cake Plot'
        plotview.plot(self.cake_data, log=True)
        wavelength = self.parameters['wavelength'].value
        polar_angles = [2 * np.degrees(np.arcsin(wavelength/(2*d)))
                        for d in self.calibrant.dSpacing]
        plotview.vlines([polar_angle for polar_angle in polar_angles
                         if polar_angle < plotview.xaxis.max],
                        linestyle=':', color='r')

    def read_parameters(self):
        pyFAI = self.pattern_geometry.getPyFAI()
        fit2d = self.pattern_geometry.getFit2D()
        self.parameters['wavelength'].value = (
            self.pattern_geometry.wavelength * 1e10)
        self.parameters['distance'].value = pyFAI['dist'] * 1e3
        self.parameters['yaw'].value = np.degrees(pyFAI['rot1'])
        self.parameters['pitch'].value = np.degrees(pyFAI['rot2'])
        self.parameters['roll'].value = np.degrees(pyFAI['rot3'])
        self.parameters['xc'].value = fit2d['centerX']
        self.parameters['yc'].value = fit2d['centerY']

    def restore_parameters(self):
        self.parameters.restore_parameters()

    def save_parameters(self):
        if not self.is_calibrated:
            raise NeXusError('No refinement performed')
        elif 'calibration' in self.entry['instrument']:
            if confirm_action(
                    "Do you want to overwrite existing calibration data?"):
                del self.entry['instrument/calibration']
            else:
                return
        self.entry['instrument/calibration'] = self.data
        if 'refinement' in self.entry['instrument/calibration']:
            if confirm_action('Overwrite previous refinement?'):
                del self.entry['instrument/calibration/refinement']
            else:
                return
        self.entry['instrument/calibration/calibrant'] = (
            self.parameters['calibrant'].value)
        process = NXprocess()
        process.program = 'pyFAI'
        process.version = pyFAI.version
        process.parameters = NXcollection()
        process.parameters['Detector'] = (
            self.entry['instrument/detector/description'])
        pyFAI_parameter = self.pattern_geometry.getPyFAI()
        process.parameters['PixelSize1'] = pyFAI_parameter['pixel1']
        process.parameters['PixelSize2'] = pyFAI_parameter['pixel2']
        process.parameters['Distance'] = pyFAI_parameter['dist']
        process.parameters['Poni1'] = pyFAI_parameter['poni1']
        process.parameters['Poni2'] = pyFAI_parameter['poni2']
        process.parameters['Rot1'] = pyFAI_parameter['rot1']
        process.parameters['Rot2'] = pyFAI_parameter['rot2']
        process.parameters['Rot3'] = pyFAI_parameter['rot3']
        process.parameters['Wavelength'] = pyFAI_parameter['wavelength']
        self.entry['instrument/calibration/refinement'] = process
        self.entry['instrument/monochromator/wavelength'] = (
            self.parameters['wavelength'].value)
        self.entry['instrument/monochromator/energy'] = (
            12.398419739640717 / self.parameters['wavelength'].value)
        detector = self.entry['instrument/detector']
        detector['distance'] = self.parameters['distance'].value
        detector['yaw'] = self.parameters['yaw'].value
        detector['pitch'] = self.parameters['pitch'].value
        detector['roll'] = self.parameters['roll'].value
        detector['beam_center_x'] = self.parameters['xc'].value
        detector['beam_center_y'] = self.parameters['yc'].value
        try:
            detector['polarization'] = self.pattern_geometry.polarization(
                factor=0.99, shape=detector['mask'].shape)
        except Exception:
            pass

    def close_plots(self):
        if 'Powder Calibration' in plotviews:
            plotviews['Powder Calibration'].close()
        if 'Cake Plot' in plotviews:
            plotviews['Cake Plot'].close()

    def closeEvent(self, event):
        self.close_plots()
        event.accept()

    def accept(self):
        super().accept()
        self.close_plots()

    def reject(self):
        super().reject()
        self.close_plots()
Exemplo n.º 18
0
class LatticeDialog(NXDialog):
    def __init__(self, parent=None):
        super().__init__(parent)

        self.select_root(self.choose_entry)

        self.refine = NXRefine()

        self.parameters = GridParameters()
        self.parameters.add('space_group',
                            self.refine.space_group,
                            'Space Group',
                            slot=self.set_groups)
        self.parameters.add('laue_group', self.refine.laue_groups,
                            'Laue Group')
        self.parameters.add('symmetry',
                            self.refine.symmetries,
                            'Symmetry',
                            slot=self.set_lattice_parameters)
        self.parameters.add('centring', self.refine.centrings, 'Cell Centring')
        self.parameters.add('a',
                            self.refine.a,
                            'Unit Cell - a (Ang)',
                            slot=self.set_lattice_parameters)
        self.parameters.add('b',
                            self.refine.b,
                            'Unit Cell - b (Ang)',
                            slot=self.set_lattice_parameters)
        self.parameters.add('c',
                            self.refine.c,
                            'Unit Cell - c (Ang)',
                            slot=self.set_lattice_parameters)
        self.parameters.add('alpha',
                            self.refine.alpha,
                            'Unit Cell - alpha (deg)',
                            slot=self.set_lattice_parameters)
        self.parameters.add('beta',
                            self.refine.beta,
                            'Unit Cell - beta (deg)',
                            slot=self.set_lattice_parameters)
        self.parameters.add('gamma',
                            self.refine.gamma,
                            'Unit Cell - gamma (deg)',
                            slot=self.set_lattice_parameters)
        self.parameters['laue_group'].value = self.refine.laue_group
        self.parameters['symmetry'].value = self.refine.symmetry
        self.parameters['centring'].value = self.refine.centring
        self.import_button = NXPushButton('Import CIF', self.import_cif)
        self.import_checkbox = NXCheckBox('Update Lattice Parameters')
        self.set_layout(self.root_layout, self.close_buttons(save=True))
        self.set_title('Defining Lattice')

    def choose_entry(self):
        self.refine = NXRefine(self.root['entry'])
        if self.layout.count() == 2:
            self.insert_layout(1, self.parameters.grid(header=False))
            if sgtbx:
                self.insert_layout(
                    2,
                    self.make_layout(self.import_button,
                                     self.import_checkbox,
                                     align='center'))
        self.update_parameters()

    def import_cif(self):
        filename = getOpenFileName(self, 'Open CIF File')
        if os.path.exists(filename):
            cif_info = cif.reader(file_path=filename).model()
            for c in cif_info:
                s = cif_info[c]
                if '_cell_length_a' in s:
                    break

            def value(text):
                if '(' in text:
                    return float(text[:text.index('(')])
                else:
                    return float(text)

            if self.import_checkbox.isChecked():
                self.refine.a = value(s['_cell_length_a'])
                self.refine.b = value(s['_cell_length_b'])
                self.refine.c = value(s['_cell_length_c'])
            self.refine.alpha = value(s['_cell_angle_alpha'])
            self.refine.beta = value(s['_cell_angle_beta'])
            self.refine.gamma = value(s['_cell_angle_gamma'])
            if '_space_group_IT_number' in s:
                sgi = sgtbx.space_group_info(s['_space_group_IT_number'])
            elif '_symmetry_Int_Tables_number' in s:
                sgi = sgtbx.space_group_info(s['_symmetry_Int_Tables_number'])
            elif '_space_group_name_H-M_alt' in s:
                sgi = sgtbx.space_group_info(s['_space_group_name_H-M_alt'])
            elif '_symmetry_space_group_name_H-M' in s:
                sgi = sgtbx.space_group_info(
                    s['_symmetry_space_group_name_H-M'])
            elif '_space_group_name_Hall' in s:
                sgi = sgtbx.space_group_info('hall: ' +
                                             s['_space_group_name_Hall'])
            elif '_symmetry_space_group_name_Hall' in s:
                sgi = sgtbx.space_group_info(
                    'hall: ' + s['_symmetry_space_group_name_Hall'])
            else:
                sgi = None
            if sgi:
                self.refine.space_group = sgi.type().lookup_symbol()
                self.refine.symmetry = sgi.group().crystal_system().lower()
                self.refine.laue_group = sgi.group().laue_group_type()
                self.refine.centring = self.refine.space_group[0]
            self.update_parameters()

    def update_parameters(self):
        self.parameters['space_group'].value = self.refine.space_group
        self.parameters['laue_group'].value = self.refine.laue_group
        self.parameters['symmetry'].value = self.refine.symmetry
        self.parameters['centring'].value = self.refine.centring
        self.parameters['a'].value = self.refine.a
        self.parameters['b'].value = self.refine.b
        self.parameters['c'].value = self.refine.c
        self.parameters['alpha'].value = self.refine.alpha
        self.parameters['beta'].value = self.refine.beta
        self.parameters['gamma'].value = self.refine.gamma

    def set_groups(self):
        if self.space_group:
            try:
                if isinstance(self.space_group, float):
                    sgi = sgtbx.space_group_info(int(self.space_group))
                else:
                    sgi = sgtbx.space_group_info(self.space_group)
            except RuntimeError as error:
                report_error("Defining Lattice", error)
                return
            try:
                self.refine.space_group = sgi.type().lookup_symbol()
                self.refine.symmetry = sgi.group().crystal_system().lower()
                self.refine.laue_group = sgi.group().laue_group_type()
                self.refine.centring = self.refine.space_group[0]
                self.update_parameters()
            except Exception:
                pass

    @property
    def space_group(self):
        return self.parameters['space_group'].value

    @property
    def laue_group(self):
        return self.parameters['laue_group'].value

    def get_symmetry(self):
        return self.parameters['symmetry'].value

    def get_centring(self):
        return self.parameters['centring'].value

    def get_lattice_parameters(self):
        return (self.parameters['a'].value, self.parameters['b'].value,
                self.parameters['c'].value, self.parameters['alpha'].value,
                self.parameters['beta'].value, self.parameters['gamma'].value)

    def set_lattice_parameters(self):
        symmetry = self.get_symmetry()
        if symmetry == 'cubic':
            self.parameters['b'].value = self.parameters['a'].value
            self.parameters['c'].value = self.parameters['a'].value
            self.parameters['alpha'].value = 90.0
            self.parameters['beta'].value = 90.0
            self.parameters['gamma'].value = 90.0
        elif symmetry == 'tetragonal':
            self.parameters['b'].value = self.parameters['a'].value
            self.parameters['alpha'].value = 90.0
            self.parameters['beta'].value = 90.0
            self.parameters['gamma'].value = 90.0
        elif symmetry == 'orthorhombic':
            self.parameters['alpha'].value = 90.0
            self.parameters['beta'].value = 90.0
            self.parameters['gamma'].value = 90.0
        elif symmetry == 'hexagonal':
            self.parameters['b'].value = self.parameters['a'].value
            self.parameters['alpha'].value = 90.0
            self.parameters['beta'].value = 90.0
            self.parameters['gamma'].value = 120.0
        elif symmetry == 'monoclinic':
            self.parameters['alpha'].value = 90.0
            self.parameters['gamma'].value = 90.0

    def get_parameters(self):
        (self.refine.a, self.refine.b, self.refine.c, self.refine.alpha,
         self.refine.beta, self.refine.gamma) = (self.get_lattice_parameters())
        self.refine.space_group = self.space_group
        self.refine.laue_group = self.laue_group
        self.refine.symmetry = self.get_symmetry()
        self.refine.centring = self.get_centring()

    def write_parameters(self):
        self.get_parameters()
        self.refine.write_parameters(sample=True)

    def accept(self):
        try:
            self.write_parameters()
            super().accept()
        except NeXusError as error:
            report_error("Defining Lattice", error)
Exemplo n.º 19
0
class MakeDialog(BaseDialog):

    def __init__(self, parent=None):
        super(MakeDialog, self).__init__(parent)
        self.scans = None
        self.set_layout(self.directorybox("Choose Sample Directory",
                                          self.choose_sample),
                        self.textboxes(('Scan Command', 'Pil2Mscan')),
                        self.action_buttons(('Select All', self.select_scans),
                                            ('Reverse All', self.reverse_scans),
                                            ('Clear All', self.clear_scans),
                                            ('Make Scan Macro', self.make_scans)),
                        self.close_buttons(close=True))
        self.set_title('Make Scans')

    def choose_sample(self):
        super(MakeDialog, self).choose_directory()
        self.sample_directory = self.get_directory()
        self.experiment_directory = os.path.dirname(os.path.dirname(self.sample_directory))
        self.macro_directory = os.path.join(self.experiment_directory, 'macros')
        self.label = os.path.basename(self.sample_directory)
        self.sample = os.path.basename(os.path.dirname(self.sample_directory))
        self.experiment = os.path.basename(self.experiment_directory)
        self.experiment_path = self.experiment
        self.scan_path = os.path.join(self.experiment, self.sample, self.label)
        self.setup_scans()

    def setup_scans(self):
        if self.scans:
            self.scans.delete_grid()
        self.scans = GridParameters()
        all_files = [self.sample+'_'+d+'.nxs' 
                    for d in os.listdir(self.sample_directory) 
                    if os.path.isdir(os.path.join(self.sample_directory, d))]
        filenames = sorted([f for f in all_files 
                    if os.path.exists(os.path.join(self.sample_directory, f))], 
                    key=natural_sort)
        for i, f in enumerate(filenames):
            scan = 'f%d' % i
            self.scans.add(scan, i+1, f, True, self.update_scans)
            self.scans[scan].checkbox.stateChanged.connect(self.update_scans)
        self.insert_layout(2, self.scans.grid(header=False))

    @property
    def scan_list(self):
        scan_list = []
        for scan in self.scans.values():
            if scan.checkbox.isChecked() and scan.value > 0:
                scan_list.append(scan)
            else:
                scan.value = 0
        return sorted(scan_list, key=attrgetter('value'))

    def update_scans(self):
        scan_list = self.scan_list
        scan_number = 0
        for scan in scan_list:
            scan_number += 1
            scan.value = scan_number                        
        for scan in self.scans.values():
            if scan.checkbox.isChecked() and scan.value == 0:
                scan.value = scan_number + 1
                scan_number += 1        

    def select_scans(self):
        for i, scan in enumerate(self.scans):
            self.scans[scan].value = i+1
            self.scans[scan].checkbox.setChecked(True)

    def reverse_scans(self):
        for i, scan in enumerate(reversed(self.scan_list)):
            scan.value = i+1
            scan.checkbox.setChecked(True)

    def clear_scans(self):
        for scan in self.scans:
            self.scans[scan].value = 0
            self.scans[scan].checkbox.setChecked(False)

    def make_scans(self):
        scans = [scan.label.text() for scan in self.scan_list]  
        scan_command = self.textbox['Scan Command'].text()
        scan_parameters = ['#command path filename temperature detx dety ' + 
                           'phi_start phi_step phi_end chi omega frame_rate']
        for scan in self.scan_list:
            nexus_file = scan.label.text()
            root = nxload(os.path.join(self.sample_directory, nexus_file))
            temperature = root.entry.sample.temperature
            base_name = os.path.basename(os.path.splitext(nexus_file)[0])
            scan_dir = base_name.replace(self.sample+'_', '')
            for entry in [root[e] for e in root if e != 'entry']:
                if 'phi_set' in entry['instrument/goniometer']:
                    phi_start = entry['instrument/goniometer/phi_set']
                else:
                    phi_start = entry['instrument/goniometer/phi']
                phi_step = entry['instrument/goniometer/phi'].attrs['step']
                phi_end = entry['instrument/goniometer/phi'].attrs['end']
                if 'chi_set' in entry['instrument/goniometer']:
                    chi = entry['instrument/goniometer/chi_set']
                else:
                    chi = entry['instrument/goniometer/chi']
                if 'omega_set' in entry['instrument/goniometer']:
                    omega = entry['instrument/goniometer/omega_set']
                else:
                    omega = entry['instrument/goniometer/omega']
                dx = entry['instrument/detector/translation_x']
                dy = entry['instrument/detector/translation_y']
                if ('frame_time' in entry['instrument/detector'] and
                    entry['instrument/detector/frame_time'] > 0.0):
                    frame_rate = 1.0 / entry['instrument/detector/frame_time']
                else:
                    frame_rate = 10.0                        
                scan_file = entry.nxname
                if scan_command == 'Pil2Mscan':
                    scan_parameters.append(
                        '%s %s %s %.6g %.6g %.6g %.6g %.6g %.6g %.6g %.6g %.6g'
                        % (scan_command, os.path.join(self.scan_path, scan_dir),
                           scan_file, temperature, dx, dy, 
                           phi_start, phi_step, phi_end,
                           chi, omega, frame_rate))
            if scan_command == 'Pil2Mstring':
                scan_parameters.append('Pil2Mstring("%s")' % scan_dir)
            elif scan_command != 'Pil2Mscan':
                scan_parameters.append('%s %s' % (scan_command, temperature))
        if not os.path.exists(self.macro_directory):
            os.mkdir(os.path.join(self.experiment_directory, 'macros'))
        macro_filter = ';;'.join(("SPEC Macro (*.mac)", "Any Files (*.* *)"))
        macro = getSaveFileName(self, 'Open Macro', self.macro_directory,
                                macro_filter)
        if macro:
            with open(macro, 'w') as f:
                f.write('\n'.join(scan_parameters))
Exemplo n.º 20
0
class MaximumDialog(BaseDialog):

    def __init__(self, parent=None):
        super(MaximumDialog, self).__init__(parent)

        self.select_entry(self.choose_entry)

        self.parameters = GridParameters()
        self.parameters.add('first', '', 'First Frame')
        self.parameters.add('last', '', 'Last Frame')

        self.output = QtWidgets.QLabel('Maximum Value:')
        self.set_layout(self.entry_layout, self.output,
                        self.parameters.grid(),
                        self.action_buttons(('Find Maximum', self.find_maximum)),
                        self.progress_layout(save=True))
        self.progress_bar.setVisible(False)
        self.progress_bar.setValue(0)
        self.set_title('Find Maximum Value')
        self.reduce = None

    def choose_entry(self):
        self.reduce = NXReduce(self.entry)
        self.maximum = self.reduce.maximum
        if self.reduce.first:
            self.parameters['first'].value = self.reduce.first
        if self.reduce.last:
            self.parameters['last'].value = self.reduce.last

    @property
    def first(self):
        try:
            _first = np.int32(self.parameters['first'].value)
            if _first >= 0:
                return _first
            else:
                return None
        except Exception as error:
            return None

    @property
    def last(self):
        try:
            _last = np.int32(self.parameters['last'].value)
            if _last > 0:
                return _last
            else:
                return None
        except Exception as error:
            return None

    @property
    def maximum(self):
        return np.float(self.output.text().split()[-1])

    @maximum.setter
    def maximum(self, value):
        self.output.setText('Maximum Value: %s' % value)

    def find_maximum(self):
        self.check_lock(self.reduce.data_file)
        self.start_thread()
        self.reduce = NXReduce(self.entry, first=self.first, last=self.last,
                               maxcount=True, overwrite=True, gui=True)
        self.reduce.moveToThread(self.thread)
        self.reduce.start.connect(self.start_progress)
        self.reduce.update.connect(self.update_progress)
        self.reduce.result.connect(self.get_maximum)
        self.reduce.stop.connect(self.stop)
        self.thread.started.connect(self.reduce.nxmax)
        self.thread.finished.connect(self.stop)
        self.thread.start(QtCore.QThread.LowestPriority)

    def check_lock(self, file_name):
        try:
            with Lock(file_name, timeout=2):
                pass
        except LockException as error:
            if self.confirm_action('Clear lock?', str(error)):
                Lock(file_name).release()

    def get_maximum(self, maximum):
        self.maximum = maximum

    def stop(self):
        self.stop_progress()
        if self.thread and self.thread.isRunning():
            self.reduce.stopped = True
        self.stop_thread()

    def accept(self):
        try:
            with Lock(self.reduce.wrapper_file):
                self.reduce.write_maximum(self.maximum)
        except LockException as error:
            if self.confirm_action('Clear lock?', str(error)):
                Lock(self.reduce.wrapper_file).release()
        self.stop()
        super(MaximumDialog, self).accept()

    def reject(self):
        self.stop()
        super(MaximumDialog, self).reject()
Exemplo n.º 21
0
class ParametersDialog(NXDialog):

    def __init__(self, parent=None):
        super().__init__(parent)

        self.select_root(self.choose_root)

        default = NXSettings().settings['nxreduce']
        self.parameters = GridParameters()
        self.parameters.add('threshold', default['threshold'],
                            'Peak Threshold')
        self.parameters.add('first', default['first'], 'First Frame')
        self.parameters.add('last', default['last'], 'Last Frame')
        self.parameters.add('monitor', ['monitor1', 'monitor2'],
                            'Normalization Monitor')
        self.parameters['monitor'].value = default['monitor']
        self.parameters.add('norm', default['norm'], 'Normalization Value')
        self.parameters.add('radius', default['radius'], 'Punch Radius (Å)')
        self.parameters.add('qmax', default['qmax'], 'Maximum Taper Q (Å-1)')

        self.set_layout(self.root_layout,
                        self.close_buttons(save=True))
        self.set_title('Choose Parameters')

    def choose_root(self):
        self.entries = [self.root[entry]
                        for entry in self.root if entry != 'entry']
        if self.layout.count() == 2:
            self.layout.insertLayout(1, self.parameters.grid(header=False))
        self.read_parameters()

    def read_parameters(self):
        if 'nxreduce' in self.root['entry']:
            reduce = self.root['entry/nxreduce']
            if 'threshold' in reduce:
                self.parameters['threshold'].value = reduce['threshold']
            if 'first_frame' in reduce:
                self.parameters['first'].value = reduce['first_frame']
            if 'last_frame' in reduce:
                self.parameters['last'].value = reduce['last_frame']
            if 'monitor' in reduce:
                self.parameters['monitor'].value = reduce['monitor']
            if 'norm' in reduce:
                self.parameters['norm'].value = reduce['norm']
            if 'radius' in reduce:
                self.parameters['radius'].value = reduce['radius']
            if 'qmax' in reduce:
                self.parameters['qmax'].value = reduce['qmax']
        else:
            try:
                reduce = NXReduce(self.entries[0])
                if reduce.first:
                    self.parameters['first'].value = reduce.first
                if reduce.last:
                    self.parameters['last'].value = reduce.last
                if reduce.threshold:
                    self.parameters['threshold'].value = reduce.threshold
                if reduce.monitor:
                    self.parameters['monitor'].value = reduce.monitor
                if reduce.norm:
                    self.parameters['norm'].value = reduce.norm
                if reduce.radius:
                    self.parameters['radius'].value = reduce.radius
                if reduce.qmax:
                    self.parameters['qmax'].value = reduce.qmax
            except Exception:
                pass

    def write_parameters(self):
        if 'nxreduce' not in self.root['entry']:
            self.root['entry/nxreduce'] = NXparameters()
        self.root['entry/nxreduce/threshold'] = self.threshold
        self.root['entry/nxreduce/first_frame'] = self.first
        self.root['entry/nxreduce/last_frame'] = self.last
        self.root['entry/nxreduce/monitor'] = self.monitor
        self.root['entry/nxreduce/norm'] = self.norm
        self.root['entry/nxreduce/radius'] = self.radius
        self.root['entry/nxreduce/qmax'] = self.qmax

    @property
    def threshold(self):
        return float(self.parameters['threshold'].value)

    @property
    def first(self):
        return int(self.parameters['first'].value)

    @property
    def last(self):
        return int(self.parameters['last'].value)

    @property
    def monitor(self):
        return self.parameters['monitor'].value

    @property
    def norm(self):
        return float(self.parameters['norm'].value)

    @property
    def radius(self):
        return float(self.parameters['radius'].value)

    @property
    def qmax(self):
        return float(self.parameters['qmax'].value)

    def accept(self):
        try:
            self.write_parameters()
            super().accept()
        except NeXusError as error:
            report_error(error)
Exemplo n.º 22
0
class CalibrateDialog(BaseDialog):
    def __init__(self, parent=None):
        super(CalibrateDialog, self).__init__(parent)

        self.plotview = None
        self.data = None
        self.counts = None
        self.points = []
        self.pattern_geometry = None
        self.cake_geometry = None
        self.is_calibrated = False

        cstr = str(ALL_CALIBRANTS)
        calibrants = sorted(cstr[cstr.index(':') + 2:].split(', '))
        self.parameters = GridParameters()
        self.parameters.add('calibrant', calibrants, 'Calibrant')
        self.parameters['calibrant'].value = 'CeO2'
        self.parameters.add('wavelength', 0.5, 'Wavelength (Ang)', False)
        self.parameters.add('distance', 100.0, 'Detector Distance (mm)', True)
        self.parameters.add('xc', 512, 'Beam Center - x', True)
        self.parameters.add('yc', 512, 'Beam Center - y', True)
        self.parameters.add('yaw', 0.0, 'Yaw (degrees)', True)
        self.parameters.add('pitch', 0.0, 'Pitch (degrees)', True)
        self.parameters.add('roll', 0.0, 'Roll (degrees)', True)
        self.parameters.add('search_size', 10, 'Search Size (pixels)')
        rings = ['Ring1', 'Ring2', 'Ring3', 'Ring4', 'Ring5']
        self.rings_box = self.select_box(rings)
        self.set_layout(
            self.select_entry(self.choose_entry),
            self.action_buttons(('Plot Calibration', self.plot_data)),
            self.parameters.grid(header=False),
            self.make_layout(
                self.action_buttons(('Select Points', self.select)),
                self.rings_box),
            self.action_buttons(('Calibrate', self.calibrate),
                                ('Plot Cake', self.plot_cake),
                                ('Restore', self.restore_parameters),
                                ('Save', self.save_parameters)),
            self.close_buttons(close=True))
        self.set_title('Calibrating Powder')

    def choose_entry(self):
        if 'calibration' not in self.entry['instrument']:
            raise NeXusError('Please load calibration data to this entry')
        self.update_parameters()
        self.plot_data()

    def update_parameters(self):
        self.parameters['wavelength'].value = self.entry[
            'instrument/monochromator/wavelength']
        detector = self.entry['instrument/detector']
        self.parameters['distance'].value = detector['distance']
        self.parameters['yaw'].value = detector['yaw']
        self.parameters['pitch'].value = detector['pitch']
        self.parameters['roll'].value = detector['roll']
        if 'beam_center_x' in detector:
            self.parameters['xc'].value = detector['beam_center_x']
        if 'beam_center_y' in detector:
            self.parameters['yc'].value = detector['beam_center_y']
        self.data = self.entry['instrument/calibration']
        self.counts = self.data.nxsignal.nxvalue

    @property
    def search_size(self):
        return int(self.parameters['search_size'].value)

    @property
    def ring(self):
        return int(self.rings_box.currentText()[-1]) - 1

    @property
    def ring_color(self):
        colors = ['r', 'b', 'g', 'c', 'm']
        return colors[self.ring]

    def plot_data(self):
        if self.plotview is None:
            if 'Powder Calibration' in plotviews:
                self.plotview = plotviews['Powder Calibration']
            else:
                self.plotview = NXPlotView('Powder Calibration')
        self.plotview.plot(self.data, log=True)
        self.plotview.aspect = 'equal'
        self.plotview.ytab.flipped = True
        self.clear_peaks()

    def on_button_press(self, event):
        self.plotview.make_active()
        if event.inaxes:
            self.xp, self.yp = event.x, event.y
        else:
            self.xp, self.yp = 0, 0

    def on_button_release(self, event):
        if event.inaxes:
            if abs(event.x - self.xp) > 5 or abs(event.y - self.yp) > 5:
                return
            x, y = self.plotview.inverse_transform(event.xdata, event.ydata)
            for i, point in enumerate(self.points):
                circle = point[0]
                if circle.contains_point(
                        self.plotview.ax.transData.transform((x, y))):
                    circle.remove()
                    for circle in point[2]:
                        circle.remove()
                    del self.points[i]
                    return
            idx, idy = self.find_peak(x, y)
            points = [(idy, idx)]
            circles = []
            massif = Massif(self.counts)
            extra_points = massif.find_peaks((idy, idx))
            for point in extra_points:
                points.append(point)
                circles.append(self.circle(point[1], point[0], alpha=0.3))
            self.points.append(
                [self.circle(idx, idy), points, circles, self.ring])

    def circle(self, idx, idy, alpha=1.0):
        return self.plotview.circle(idx,
                                    idy,
                                    self.search_size,
                                    facecolor=self.ring_color,
                                    edgecolor='k',
                                    alpha=alpha)

    def select(self):
        self.plotview.cidpress = self.plotview.mpl_connect(
            'button_press_event', self.on_button_press)
        self.plotview.cidrelease = self.plotview.mpl_connect(
            'button_release_event', self.on_button_release)

    def find_peak(self, x, y):
        s = self.search_size
        left = int(np.round(x - s * 0.5))
        if left < 0:
            left = 0
        top = int(np.round(y - s * 0.5))
        if top < 0:
            top = 0
        region = self.counts[top:(top + s), left:(left + s)]
        idy, idx = np.where(region == region.max())
        idx = left + idx[0]
        idy = top + idy[0]
        return idx, idy

    def clear_peaks(self):
        self.points = []

    @property
    def calibrant(self):
        return ALL_CALIBRANTS[self.parameters['calibrant'].value]

    @property
    def point_array(self):
        points = []
        for point in self.points:
            for p in point[1]:
                points.append((p[0], p[1], point[3]))
        return np.array(points)

    def prepare_parameters(self):
        self.parameters.set_parameters()
        self.wavelength = self.parameters['wavelength'].value * 1e-10
        self.distance = self.parameters['distance'].value * 1e-3
        self.yaw = np.radians(self.parameters['yaw'].value)
        self.pitch = np.radians(self.parameters['pitch'].value)
        self.roll = np.radians(self.parameters['roll'].value)
        self.pixel_size = self.entry[
            'instrument/detector/pixel_size'].nxvalue * 1e-3
        self.xc = self.parameters['xc'].value
        self.yc = self.parameters['yc'].value

    def calibrate(self):
        self.prepare_parameters()
        self.orig_pixel1 = self.pixel_size
        self.orig_pixel2 = self.pixel_size
        self.pattern_geometry = GeometryRefinement(self.point_array,
                                                   dist=self.distance,
                                                   wavelength=self.wavelength,
                                                   pixel1=self.pixel_size,
                                                   pixel2=self.pixel_size,
                                                   calibrant=self.calibrant)
        self.refine()
        self.create_cake_geometry()
        self.pattern_geometry.reset()

    def refine(self):
        self.pattern_geometry.data = self.point_array

        if self.parameters['wavelength'].vary:
            self.pattern_geometry.refine2()
            fix = []
        else:
            fix = ['wavelength']
        if not self.parameters['distance'].vary:
            fix.append('dist')
        self.pattern_geometry.refine2_wavelength(fix=fix)
        self.read_parameters()
        self.is_calibrated = True
        self.create_cake_geometry()
        self.pattern_geometry.reset()

    def create_cake_geometry(self):
        self.cake_geometry = AzimuthalIntegrator()
        pyFAI_parameter = self.pattern_geometry.getPyFAI()
        pyFAI_parameter['wavelength'] = self.pattern_geometry.wavelength
        self.cake_geometry.setPyFAI(dist=pyFAI_parameter['dist'],
                                    poni1=pyFAI_parameter['poni1'],
                                    poni2=pyFAI_parameter['poni2'],
                                    rot1=pyFAI_parameter['rot1'],
                                    rot2=pyFAI_parameter['rot2'],
                                    rot3=pyFAI_parameter['rot3'],
                                    pixel1=pyFAI_parameter['pixel1'],
                                    pixel2=pyFAI_parameter['pixel2'])
        self.cake_geometry.wavelength = pyFAI_parameter['wavelength']

    def plot_cake(self):
        if 'Cake Plot' in plotviews:
            plotview = plotviews['Cake Plot']
        else:
            plotview = NXPlotView('Cake Plot')
        if not self.is_calibrated:
            raise NeXusError('No refinement performed')
        res = self.cake_geometry.integrate2d(self.counts,
                                             1024,
                                             1024,
                                             method='csr',
                                             unit='2th_deg',
                                             correctSolidAngle=True)
        self.cake_data = NXdata(res[0],
                                (NXfield(res[2], name='azimumthal_angle'),
                                 NXfield(res[1], name='polar_angle')))
        self.cake_data['title'] = self.entry['instrument/calibration/title']
        plotview.plot(self.cake_data, log=True)
        wavelength = self.parameters['wavelength'].value
        polar_angles = [
            2 * np.degrees(np.arcsin(wavelength / (2 * d)))
            for d in self.calibrant.dSpacing
        ]
        plotview.vlines([
            polar_angle
            for polar_angle in polar_angles if polar_angle < plotview.xaxis.max
        ],
                        linestyle=':',
                        color='r')

    def read_parameters(self):
        pyFAI = self.pattern_geometry.getPyFAI()
        fit2d = self.pattern_geometry.getFit2D()
        self.parameters[
            'wavelength'].value = self.pattern_geometry.wavelength * 1e10
        self.parameters['distance'].value = pyFAI['dist'] * 1e3
        self.parameters['yaw'].value = np.degrees(pyFAI['rot1'])
        self.parameters['pitch'].value = np.degrees(pyFAI['rot2'])
        self.parameters['roll'].value = np.degrees(pyFAI['rot3'])
        self.parameters['xc'].value = fit2d['centerX']
        self.parameters['yc'].value = fit2d['centerY']

    def restore_parameters(self):
        self.parameters.restore_parameters()

    def save_parameters(self):
        if not self.is_calibrated:
            raise NeXusError('No refinement performed')
        elif 'refinement' in self.entry['instrument/calibration']:
            if confirm_action('Overwrite previous refinement?'):
                del self.entry['instrument/calibration/refinement']
            else:
                return
        self.entry['instrument/calibration/calibrant'] = self.parameters[
            'calibrant'].value
        process = NXprocess()
        process.program = 'pyFAI'
        process.version = pyFAI.version
        process.parameters = NXcollection()
        process.parameters['Detector'] = self.entry[
            'instrument/detector/description']
        pyFAI_parameter = self.pattern_geometry.getPyFAI()
        process.parameters['PixelSize1'] = pyFAI_parameter['pixel1']
        process.parameters['PixelSize2'] = pyFAI_parameter['pixel2']
        process.parameters['Distance'] = pyFAI_parameter['dist']
        process.parameters['Poni1'] = pyFAI_parameter['poni1']
        process.parameters['Poni2'] = pyFAI_parameter['poni2']
        process.parameters['Rot1'] = pyFAI_parameter['rot1']
        process.parameters['Rot2'] = pyFAI_parameter['rot2']
        process.parameters['Rot3'] = pyFAI_parameter['rot3']
        process.parameters['Wavelength'] = pyFAI_parameter['wavelength']
        self.entry['instrument/calibration/refinement'] = process
        self.entry['instrument/monochromator/wavelength'] = self.parameters[
            'wavelength'].value
        self.entry[
            'instrument/monochromator/energy'] = 12.398419739640717 / self.parameters[
                'wavelength'].value
        detector = self.entry['instrument/detector']
        detector['distance'] = self.parameters['distance'].value
        detector['yaw'] = self.parameters['yaw'].value
        detector['pitch'] = self.parameters['pitch'].value
        detector['roll'] = self.parameters['roll'].value
        detector['beam_center_x'] = self.parameters['xc'].value
        detector['beam_center_y'] = self.parameters['yc'].value

    def reject(self):
        super(CalibrateDialog, self).reject()
        if 'Powder Calibration' in plotviews:
            plotviews['Powder Calibration'].close_view()
        if 'Cake Plot' in plotviews:
            plotviews['Cake Plot'].close_view()
Exemplo n.º 23
0
class FindDialog(BaseDialog):

    def __init__(self, parent=None):
        super(FindDialog, self).__init__(parent)

        self.select_entry(self.choose_entry)

        self.parameters = GridParameters()
        self.parameters.add('threshold', '', 'Threshold')
        self.parameters.add('first', '', 'First Frame')
        self.parameters.add('last', '', 'Last Frame')
        find_layout = QtWidgets.QHBoxLayout()
        self.find_button = QtWidgets.QPushButton('Find Peaks')
        self.find_button.clicked.connect(self.find_peaks)
        self.peak_count = QtWidgets.QLabel()
        self.peak_count.setVisible(False)
        find_layout.addStretch()
        find_layout.addWidget(self.find_button)
        find_layout.addWidget(self.peak_count)
        find_layout.addStretch()
        self.set_layout(self.entry_layout, 
                        self.parameters.grid(),
                        find_layout,
                        self.progress_layout(save=True))
        self.progress_bar.setVisible(False)
        self.progress_bar.setValue(0)
        self.set_title('Find Peaks')
        self.reduce = None

    def choose_entry(self):
        self.reduce = NXReduce(self.entry)
        if self.reduce.first:
            self.parameters['first'].value = self.reduce.first
        if self.reduce.last:
            self.parameters['last'].value = self.reduce.last
        else:
            try:
                self.parameters['last'].value = len(self.entry.data.nxaxes[0])
            except Exception:
                pass
        if self.reduce.threshold:
            self.parameters['threshold'].value = self.reduce.threshold

    @property
    def threshold(self):
        try:
            _threshold = np.int32(self.parameters['threshold'].value)
            if _threshold > 0.0:
                return _threshold
            else:
                return None
        except Exception:
            return None

    @property
    def first(self):
        try:
            _first = np.int32(self.parameters['first'].value)
            if _first >= 0:
                return _first
            else:
                return None
        except Exception as error:
            return None

    @property
    def last(self):
        try:
            _last = np.int32(self.parameters['last'].value)
            if _last > 0:
                return _last
            else:
                return None
        except Exception as error:
            return None

    def find_peaks(self):
        self.check_lock(self.reduce.data_file)
        self.start_thread()
        self.reduce = NXReduce(self.entry, threshold=self.threshold, 
                               first=self.first, last=self.last,
                               find=True, overwrite=True, gui=True)
        self.reduce.moveToThread(self.thread)
        self.reduce.start.connect(self.start_progress)
        self.reduce.update.connect(self.update_progress)
        self.reduce.result.connect(self.get_peaks)
        self.reduce.stop.connect(self.stop)
        self.thread.started.connect(self.reduce.nxfind)
        self.thread.start(QtCore.QThread.LowestPriority)

    def check_lock(self, file_name):
        try:
            with Lock(file_name, timeout=2):
                pass
        except LockException as error:
            if self.confirm_action('Clear lock?', str(error)):
                Lock(file_name).release()

    def get_peaks(self, peaks):
        self.peaks = peaks
        self.peak_count.setText('%s peaks found' % len(self.peaks))
        self.peak_count.setVisible(True)

    def stop(self):
        self.stop_progress()
        if self.thread and self.thread.isRunning():
            self.reduce.stopped = True
        self.stop_thread()

    def accept(self):
        try:
            with Lock(self.reduce.wrapper_file):
                self.reduce.write_peaks(self.peaks)
        except LockException as error:
            if self.confirm_action('Clear lock?', str(error)):
                Lock(self.reduce.wrapper_file).release()
        self.stop()
        super(FindDialog, self).accept()

    def reject(self):
        self.stop()
        super(FindDialog, self).reject()
Exemplo n.º 24
0
class LatticeDialog(BaseDialog):
    def __init__(self, parent=None):
        super(LatticeDialog, self).__init__(parent)

        self.select_entry(self.choose_entry)

        self.refine = NXRefine()

        self.parameters = GridParameters()
        self.parameters.add('symmetry',
                            self.refine.symmetries,
                            'Symmetry',
                            slot=self.set_lattice_parameters)
        self.parameters.add('centring', self.refine.centrings, 'Cell Centring')
        self.parameters.add('a',
                            self.refine.a,
                            'Unit Cell - a (Ang)',
                            slot=self.set_lattice_parameters)
        self.parameters.add('b',
                            self.refine.b,
                            'Unit Cell - b (Ang)',
                            slot=self.set_lattice_parameters)
        self.parameters.add('c',
                            self.refine.c,
                            'Unit Cell - c (Ang)',
                            slot=self.set_lattice_parameters)
        self.parameters.add('alpha',
                            self.refine.alpha,
                            'Unit Cell - alpha (deg)',
                            slot=self.set_lattice_parameters)
        self.parameters.add('beta',
                            self.refine.beta,
                            'Unit Cell - beta (deg)',
                            slot=self.set_lattice_parameters)
        self.parameters.add('gamma',
                            self.refine.gamma,
                            'Unit Cell - gamma (deg)',
                            slot=self.set_lattice_parameters)
        self.parameters['symmetry'].value = self.refine.symmetry
        self.parameters['centring'].value = self.refine.centring
        action_buttons = self.action_buttons(('Plot', self.plot_lattice),
                                             ('Save', self.write_parameters))
        self.set_layout(self.entry_layout, self.parameters.grid(),
                        action_buttons, self.close_buttons())
        self.set_title('Defining Lattice')

    def choose_entry(self):
        self.refine = NXRefine(self.entry)
        self.update_parameters()

    def update_parameters(self):
        self.parameters['symmetry'].value = self.refine.symmetry
        self.parameters['centring'].value = self.refine.centring
        self.parameters['a'].value = self.refine.a
        self.parameters['b'].value = self.refine.b
        self.parameters['c'].value = self.refine.c
        self.parameters['alpha'].value = self.refine.alpha
        self.parameters['beta'].value = self.refine.beta
        self.parameters['gamma'].value = self.refine.gamma

    def get_symmetry(self):
        return self.parameters['symmetry'].value

    def get_centring(self):
        return self.parameters['centring'].value

    def get_lattice_parameters(self):
        return (self.parameters['a'].value, self.parameters['b'].value,
                self.parameters['c'].value, self.parameters['alpha'].value,
                self.parameters['beta'].value, self.parameters['gamma'].value)

    def set_lattice_parameters(self):
        symmetry = self.get_symmetry()
        if symmetry == 'cubic':
            self.parameters['b'].value = self.parameters['a'].value
            self.parameters['c'].value = self.parameters['a'].value
            self.parameters['alpha'].value = 90.0
            self.parameters['beta'].value = 90.0
            self.parameters['gamma'].value = 90.0
        elif symmetry == 'tetragonal':
            self.parameters['b'].value = self.parameters['a'].value
            self.parameters['alpha'].value = 90.0
            self.parameters['beta'].value = 90.0
            self.parameters['gamma'].value = 90.0
        elif symmetry == 'orthorhombic':
            self.parameters['alpha'].value = 90.0
            self.parameters['beta'].value = 90.0
            self.parameters['gamma'].value = 90.0
        elif symmetry == 'hexagonal':
            self.parameters['b'].value = self.parameters['a'].value
            self.parameters['alpha'].value = 90.0
            self.parameters['beta'].value = 90.0
            self.parameters['gamma'].value = 120.0
        elif symmetry == 'monoclinic':
            self.parameters['alpha'].value = 90.0
            self.parameters['gamma'].value = 90.0

    def get_parameters(self):
        (self.refine.a, self.refine.b, self.refine.c, self.refine.alpha,
         self.refine.beta, self.refine.gamma) = (self.get_lattice_parameters())
        self.refine.symmetry = self.get_symmetry()
        self.refine.centring = self.get_centring()

    def plot_lattice(self):
        try:
            self.get_parameters()
            self.plot_peaks(self.refine.xp, self.refine.yp)
            polar_min, polar_max = plotview.xaxis.get_limits()
            self.plot_rings(polar_max)
        except NeXusError as error:
            report_error('Plotting Lattice', error)

    def write_parameters(self):
        try:
            self.get_parameters()
            self.refine.write_parameters()
        except NeXusError as error:
            report_error('Defining Lattice', error)

    def plot_peaks(self, x, y):
        try:
            polar_angles, azimuthal_angles = self.refine.calculate_angles(x, y)
            if polar_angles[0] > polar_angles[-1]:
                polar_angles = polar_angles[::-1]
                azimuthal_angles = azimuthal_angles[::-1]
            azimuthal_field = NXfield(azimuthal_angles, name='azimuthal_angle')
            azimuthal_field.long_name = 'Azimuthal Angle'
            polar_field = NXfield(polar_angles, name='polar_angle')
            polar_field.long_name = 'Polar Angle'
            plotview = get_plotview()
            plotview.plot(
                NXdata(azimuthal_field, polar_field, title='Peak Angles'))
        except NeXusError as error:
            report_error('Plotting Lattice', error)

    def plot_rings(self, polar_max=None):
        if polar_max is None:
            polar_max = self.refine.polar_max
        peaks = self.refine.calculate_rings(polar_max)
        plotview = get_plotview()
        plotview.vlines(peaks, colors='r', linestyles='dotted')
        plotview.draw()
Exemplo n.º 25
0
class CalibrateDialog(BaseDialog):

    def __init__(self, parent=None):
        super(CalibrateDialog, self).__init__(parent)

        self.plotview = None
        self.data = None
        self.counts = None
        self.points = []
        self.pattern_geometry = None
        self.cake_geometry = None
        self.is_calibrated = False    

        cstr = str(ALL_CALIBRANTS)
        calibrants = sorted(cstr[cstr.index(':')+2:].split(', '))
        self.parameters = GridParameters()
        self.parameters.add('calibrant', calibrants, 'Calibrant')
        self.parameters['calibrant'].value = 'CeO2'
        self.parameters.add('wavelength', 0.5, 'Wavelength (Ang)', False)
        self.parameters.add('distance', 100.0, 'Detector Distance (mm)', True)
        self.parameters.add('xc', 512, 'Beam Center - x', True)
        self.parameters.add('yc', 512, 'Beam Center - y', True)
        self.parameters.add('yaw', 0.0, 'Yaw (degrees)', True)
        self.parameters.add('pitch', 0.0, 'Pitch (degrees)', True)
        self.parameters.add('roll', 0.0, 'Roll (degrees)', True)
        self.parameters.add('search_size', 10, 'Search Size (pixels)')
        rings = ['Ring%s' % i for i in range(1,21)]
        self.rings_box = self.select_box(rings)
        self.set_layout(self.select_entry(self.choose_entry),
                        self.action_buttons(('Plot Calibration', self.plot_data)),
                        self.parameters.grid(header=False),
                        self.make_layout(
                            self.action_buttons(('Select Points', self.select)),
                            self.rings_box),
                        self.action_buttons(('Calibrate', self.calibrate),
                                            ('Plot Cake', self.plot_cake),
                                            ('Restore', self.restore_parameters),
                                            ('Save', self.save_parameters)), 
                        self.close_buttons(close=True))
        self.set_title('Calibrating Powder')

    def choose_entry(self):
        if 'calibration' not in self.entry['instrument']:
            raise NeXusError('Please load calibration data to this entry')
        self.update_parameters()
        self.plot_data()

    def update_parameters(self):
        self.parameters['wavelength'].value = self.entry['instrument/monochromator/wavelength']
        detector = self.entry['instrument/detector']
        self.parameters['distance'].value = detector['distance']
        self.parameters['yaw'].value = detector['yaw']
        self.parameters['pitch'].value = detector['pitch']
        self.parameters['roll'].value = detector['roll']
        if 'beam_center_x' in detector:
            self.parameters['xc'].value = detector['beam_center_x']
        if 'beam_center_y' in detector:
            self.parameters['yc'].value = detector['beam_center_y']
        self.data = self.entry['instrument/calibration']
        self.counts = self.data.nxsignal.nxvalue


    @property
    def search_size(self):
        return int(self.parameters['search_size'].value)

    @property
    def ring(self):
        return int(self.rings_box.currentText()[4:]) - 1

    @property
    def ring_color(self):
        colors = ['r', 'b', 'g', 'c', 'm'] * 4
        return colors[self.ring]

    def plot_data(self):
        if self.plotview is None:
            if 'Powder Calibration' in plotviews:
                self.plotview = plotviews['Powder Calibration']
            else:
                self.plotview = NXPlotView('Powder Calibration')
        self.plotview.plot(self.data, log=True)
        self.plotview.aspect='equal'
        self.plotview.ytab.flipped = True
        self.clear_peaks()

    def on_button_press(self, event):
        self.plotview.make_active()
        if event.inaxes:
            self.xp, self.yp = event.x, event.y
        else:
            self.xp, self.yp = 0, 0

    def on_button_release(self, event):
        if event.inaxes:
            if abs(event.x - self.xp) > 5 or abs(event.y - self.yp) > 5:
                return
            x, y = self.plotview.inverse_transform(event.xdata, event.ydata)
            for i, point in enumerate(self.points):
                circle = point[0]
                if circle.contains_point(self.plotview.ax.transData.transform((x,y))):
                    circle.remove()
                    for circle in point[2]:
                        circle.remove()
                    del self.points[i]
                    return
            idx, idy = self.find_peak(x, y)
            points = [(idy, idx)]
            circles = []
            massif = Massif(self.counts)
            extra_points = massif.find_peaks((idy, idx))
            for point in extra_points:
                points.append(point)
                circles.append(self.circle(point[1], point[0], alpha=0.3))
            self.points.append([self.circle(idx, idy), points, circles, self.ring])

    def circle(self, idx, idy, alpha=1.0):
        return self.plotview.circle(idx, idy, self.search_size,
                                    facecolor=self.ring_color, edgecolor='k',
                                    alpha=alpha)

    def select(self):
        self.plotview.cidpress = self.plotview.mpl_connect(
                                    'button_press_event', self.on_button_press)
        self.plotview.cidrelease = self.plotview.mpl_connect(
                                    'button_release_event', self.on_button_release)

    def find_peak(self, x, y):
        s = self.search_size
        left = int(np.round(x - s * 0.5))
        if left < 0:
            left = 0
        top = int(np.round(y - s * 0.5))
        if top < 0:
            top = 0
        region = self.counts[top:(top+s),left:(left+s)]
        idy, idx = np.where(region == region.max())
        idx = left + idx[0]
        idy = top + idy[0]
        return idx, idy

    def clear_peaks(self):
        self.points = []
        
    @property
    def calibrant(self):
        return ALL_CALIBRANTS[self.parameters['calibrant'].value]

    @property
    def point_array(self):
        points = []
        for point in self.points:
            for p in point[1]:
                points.append((p[0], p[1], point[3]))
        return np.array(points)

    def prepare_parameters(self):
        self.parameters.set_parameters()
        self.wavelength = self.parameters['wavelength'].value * 1e-10
        self.distance = self.parameters['distance'].value * 1e-3
        self.yaw = np.radians(self.parameters['yaw'].value)
        self.pitch = np.radians(self.parameters['pitch'].value)
        self.roll = np.radians(self.parameters['roll'].value)
        self.pixel_size = self.entry['instrument/detector/pixel_size'].nxvalue * 1e-3
        self.xc = self.parameters['xc'].value
        self.yc = self.parameters['yc'].value

    def calibrate(self):
        self.prepare_parameters()
        self.orig_pixel1 = self.pixel_size
        self.orig_pixel2 = self.pixel_size
        self.pattern_geometry = GeometryRefinement(self.point_array,
                                                   dist=self.distance,
                                                   wavelength=self.wavelength,
                                                   pixel1=self.pixel_size,
                                                   pixel2=self.pixel_size,
                                                   calibrant=self.calibrant)
        self.refine()
        self.create_cake_geometry()
        self.pattern_geometry.reset()

    def refine(self):
        self.pattern_geometry.data = self.point_array

        if self.parameters['wavelength'].vary:
            self.pattern_geometry.refine2()
            fix = []
        else:
            fix = ['wavelength']
        if not self.parameters['distance'].vary:
            fix.append('dist')
        self.pattern_geometry.refine2_wavelength(fix=fix)
        self.read_parameters()
        self.is_calibrated = True
        self.create_cake_geometry()
        self.pattern_geometry.reset()

    def create_cake_geometry(self):
        self.cake_geometry = AzimuthalIntegrator()
        pyFAI_parameter = self.pattern_geometry.getPyFAI()
        pyFAI_parameter['wavelength'] = self.pattern_geometry.wavelength
        self.cake_geometry.setPyFAI(dist=pyFAI_parameter['dist'],
                                    poni1=pyFAI_parameter['poni1'],
                                    poni2=pyFAI_parameter['poni2'],
                                    rot1=pyFAI_parameter['rot1'],
                                    rot2=pyFAI_parameter['rot2'],
                                    rot3=pyFAI_parameter['rot3'],
                                    pixel1=pyFAI_parameter['pixel1'],
                                    pixel2=pyFAI_parameter['pixel2'])
        self.cake_geometry.wavelength = pyFAI_parameter['wavelength']

    def plot_cake(self):
        if 'Cake Plot' in plotviews:
            plotview = plotviews['Cake Plot']
        else:
            plotview = NXPlotView('Cake Plot')    
        if not self.is_calibrated:
            raise NeXusError('No refinement performed')
        res = self.cake_geometry.integrate2d(self.counts, 
                                             1024, 1024,
                                             method='csr',
                                             unit='2th_deg',
                                             correctSolidAngle=True)
        self.cake_data = NXdata(res[0], (NXfield(res[2], name='azimumthal_angle'),
                                         NXfield(res[1], name='polar_angle')))
        self.cake_data['title'] = self.entry['instrument/calibration/title']
        plotview.plot(self.cake_data, log=True)
        wavelength = self.parameters['wavelength'].value
        polar_angles = [2 * np.degrees(np.arcsin(wavelength/(2*d)))
                        for d in self.calibrant.dSpacing]
        plotview.vlines([polar_angle for polar_angle in polar_angles 
                         if polar_angle < plotview.xaxis.max], 
                        linestyle=':', color='r')

    def read_parameters(self):
        pyFAI = self.pattern_geometry.getPyFAI()
        fit2d = self.pattern_geometry.getFit2D()
        self.parameters['wavelength'].value = self.pattern_geometry.wavelength * 1e10
        self.parameters['distance'].value = pyFAI['dist'] * 1e3
        self.parameters['yaw'].value = np.degrees(pyFAI['rot1'])
        self.parameters['pitch'].value = np.degrees(pyFAI['rot2'])
        self.parameters['roll'].value = np.degrees(pyFAI['rot3'])
        self.parameters['xc'].value = fit2d['centerX']
        self.parameters['yc'].value = fit2d['centerY']

    def restore_parameters(self):
        self.parameters.restore_parameters()

    def save_parameters(self):
        if not self.is_calibrated:
            raise NeXusError('No refinement performed')
        elif 'refinement' in self.entry['instrument/calibration']:
            if confirm_action('Overwrite previous refinement?'):
                del self.entry['instrument/calibration/refinement']
            else:
                return
        self.entry['instrument/calibration/calibrant'] = self.parameters['calibrant'].value
        process = NXprocess()
        process.program = 'pyFAI'
        process.version = pyFAI.version
        process.parameters = NXcollection()
        process.parameters['Detector'] = self.entry['instrument/detector/description']
        pyFAI_parameter = self.pattern_geometry.getPyFAI()
        process.parameters['PixelSize1'] =  pyFAI_parameter['pixel1']
        process.parameters['PixelSize2'] =  pyFAI_parameter['pixel2']
        process.parameters['Distance'] =  pyFAI_parameter['dist']
        process.parameters['Poni1'] =  pyFAI_parameter['poni1']
        process.parameters['Poni2'] =  pyFAI_parameter['poni2']
        process.parameters['Rot1'] =  pyFAI_parameter['rot1']
        process.parameters['Rot2'] =  pyFAI_parameter['rot2']
        process.parameters['Rot3'] =  pyFAI_parameter['rot3']
        process.parameters['Wavelength'] =  pyFAI_parameter['wavelength']
        self.entry['instrument/calibration/refinement'] = process
        self.entry['instrument/monochromator/wavelength'] = self.parameters['wavelength'].value
        self.entry['instrument/monochromator/energy'] = 12.398419739640717 / self.parameters['wavelength'].value 
        detector = self.entry['instrument/detector']
        detector['distance'] = self.parameters['distance'].value
        detector['yaw'] = self.parameters['yaw'].value
        detector['pitch'] = self.parameters['pitch'].value
        detector['roll'] = self.parameters['roll'].value
        detector['beam_center_x'] = self.parameters['xc'].value
        detector['beam_center_y'] = self.parameters['yc'].value

    def reject(self):
        super(CalibrateDialog, self).reject()
        if 'Powder Calibration' in plotviews:
            plotviews['Powder Calibration'].close_view()
        if 'Cake Plot' in plotviews:
            plotviews['Cake Plot'].close_view()
Exemplo n.º 26
0
class OrientationDialog(BaseDialog):
    def __init__(self, parent=None):
        super(OrientationDialog, self).__init__(parent)

        self.select_entry(self.choose_entry)

        self.refine = NXRefine(self.entry)
        self.refine.read_parameters()

        self.parameters = GridParameters()
        self.parameters.add('phi_start', self.refine.phi, 'Phi Start (deg)')
        self.parameters.add('phi_step', self.refine.phi_step, 'Phi Step (deg)')
        self.parameters.add('chi', self.refine.chi, 'Chi (deg)')
        self.parameters.add('omega', self.refine.omega, 'Omega (deg)')
        self.parameters.add('polar', self.refine.polar_max,
                            'Max. Polar Angle (deg)')
        self.parameters.add('polar_tolerance', self.refine.polar_tolerance,
                            'Polar Angle Tolerance')
        self.parameters.add('peak_tolerance', self.refine.peak_tolerance,
                            'Peak Angle Tolerance')
        action_buttons = self.action_buttons(
            ('Generate Grains', self.generate_grains),
            ('List Peaks', self.list_peaks))
        self.grain_layout = QtWidgets.QHBoxLayout()
        self.grain_combo = QtWidgets.QComboBox()
        self.grain_combo.setSizeAdjustPolicy(
            QtWidgets.QComboBox.AdjustToContents)
        self.grain_combo.currentIndexChanged.connect(self.set_grain)
        self.grain_textbox = QtWidgets.QLabel()
        self.grain_layout.addWidget(self.grain_combo)
        self.grain_layout.addStretch()
        self.grain_layout.addWidget(self.grain_textbox)
        bottom_layout = QtWidgets.QHBoxLayout()
        self.result_textbox = QtWidgets.QLabel()
        bottom_layout.addWidget(self.result_textbox)
        bottom_layout.addStretch()
        bottom_layout.addWidget(self.close_buttons())
        self.set_layout(self.entry_layout, self.parameters.grid(),
                        action_buttons, bottom_layout)
        self.set_title('Defining Orientation')

    def choose_entry(self):
        self.refine = NXRefine(self.entry)
        self.update_parameters()

    def update_parameters(self):
        self.parameters['phi_start'].value = self.refine.phi
        self.parameters['phi_step'].value = self.refine.phi_step
        self.parameters['chi'].value = self.refine.chi
        self.parameters['omega'].value = self.refine.omega
        self.parameters['polar'].value = self.refine.polar_max
        self.parameters['polar_tolerance'].value = self.refine.polar_tolerance
        self.parameters['peak_tolerance'].value = self.refine.peak_tolerance

    def get_phi(self):
        return (self.parameters['phi_start'].value,
                self.parameters['phi_step'].value)

    def set_phi(self):
        self.refine.phi_start, self.refine.phi_step = self.get_phi()

    def get_chi(self):
        return self.parameters['chi'].value

    def set_chi(self):
        self.refine.chi = self.get_chi()

    def get_omega(self):
        return self.parameters['omega'].value

    def set_omega(self):
        self.refine.omega = self.get_omega()

    @property
    def polar_max(self):
        return self.parameters['polar'].value

    def set_polar_max(self):
        self.refine.polar_max = self.polar_max

    def get_polar_tolerance(self):
        return self.parameters['polar_tolerance'].value

    def set_polar_tolerance(self):
        self.refine.polar_tolerance = self.get_polar_tolerance()

    def get_peak_tolerance(self):
        return self.parameters['peak_tolerance'].value

    def set_peak_tolerance(self):
        self.refine.peak_tolerance = self.get_peak_tolerance()

    def generate_grains(self):
        self.set_polar_max()
        self.refine.generate_grains()
        if self.refine.grains is not None:
            self.layout.insertLayout(2, self.grain_layout)
        self.grain_combo.clear()
        for i in range(len(self.refine.grains)):
            self.grain_combo.addItem('Grain %s' % i)
        self.grain_combo.setCurrentIndex(0)
        self.set_grain()

    def set_grain(self):
        try:
            grain = self.refine.grains[self.get_grain()]
            self.grain_textbox.setText('%s peaks; Score: %.4f' %
                                       (len(grain), grain.score))
            self.refine.Umat = grain.Umat
            self.refine.primary = grain.primary
            self.refine.secondary = grain.secondary
            self.get_score()
        except:
            self.grain_textbox.setText('')

    def get_grain(self):
        return int(self.grain_combo.currentText().split()[-1])

    def list_peaks(self):
        self.refine.phi = self.get_phi()
        self.refine.chi = self.get_chi()
        self.refine.omega = self.get_omega()
        if self.refine.grains is not None:
            grain = self.refine.grains[self.get_grain()]
            self.refine.Umat = grain.Umat
            self.list_orientations()
        else:
            self.list_orientations()

    def get_score(self):
        if self.refine.Umat is not None:
            self.score = self.refine.score()
            self.result_textbox.setText('%s peaks; Score: %.4f' %
                                        (len(self.refine.idx), self.score))

    def list_orientations(self):
        message_box = BaseDialog(self)
        message_box.setMinimumWidth(600)
        message_box.setMinimumHeight(600)
        header = [
            'i', 'x', 'y', 'z', 'Polar', 'Azi', 'Intensity', 'H', 'K', 'L',
            'Diff'
        ]
        peak_list = self.refine.get_peaks()
        self.refine.assign_rings()
        self.rings = self.refine.get_ring_hkls()
        orient_layout = QtWidgets.QHBoxLayout()
        if self.refine.primary is None:
            self.refine.primary = 0
        if self.refine.secondary is None:
            self.refine.secondary = 1
        self.primary_box = QtWidgets.QLineEdit(str(self.refine.primary))
        self.primary_box.setAlignment(QtCore.Qt.AlignRight)
        self.primary_box.setFixedWidth(80)
        self.secondary_box = QtWidgets.QLineEdit(str(self.refine.secondary))
        self.secondary_box.setAlignment(QtCore.Qt.AlignRight)
        self.secondary_box.setFixedWidth(80)
        orient_button = QtWidgets.QPushButton('Orient')
        orient_button.clicked.connect(self.orient)
        refine_button = QtWidgets.QPushButton('Refine')
        refine_button.clicked.connect(self.refine_orientation)
        restore_button = QtWidgets.QPushButton('Restore')
        restore_button.clicked.connect(self.restore_orientation)
        orient_layout.addStretch()
        orient_layout.addWidget(QtWidgets.QLabel('Primary'))
        orient_layout.addWidget(self.primary_box)
        orient_layout.addWidget(QtWidgets.QLabel('Secondary'))
        orient_layout.addWidget(self.secondary_box)
        orient_layout.addStretch()
        orient_layout.addWidget(orient_button)
        orient_layout.addWidget(refine_button)
        orient_layout.addWidget(restore_button)

        grid = QtWidgets.QGridLayout()
        grid.setSpacing(10)
        self.lattice = GridParameters()
        self.lattice.add('a', self.refine.a, 'a', False)
        self.lattice.add('b', self.refine.b, 'b', False)
        self.lattice.add('c', self.refine.c, 'c', False)
        self.lattice.add('alpha', self.refine.alpha, 'alpha', False)
        self.lattice.add('beta', self.refine.beta, 'beta', False)
        self.lattice.add('gamma', self.refine.gamma, 'gamma', False)
        p = self.lattice['a']
        p.box.setFixedWidth(80)
        label, value, checkbox = p.label, p.value, p.vary
        grid.addWidget(p.label, 0, 0, QtCore.Qt.AlignRight)
        grid.addWidget(p.box, 0, 1, QtCore.Qt.AlignHCenter)
        grid.addWidget(p.checkbox, 0, 2, QtCore.Qt.AlignHCenter)
        p = self.lattice['b']
        p.box.setFixedWidth(80)
        label, value, checkbox = p.label, p.value, p.vary
        grid.addWidget(p.label, 0, 3, QtCore.Qt.AlignRight)
        grid.addWidget(p.box, 0, 4, QtCore.Qt.AlignHCenter)
        grid.addWidget(p.checkbox, 0, 5, QtCore.Qt.AlignHCenter)
        p = self.lattice['c']
        p.box.setFixedWidth(80)
        label, value, checkbox = p.label, p.value, p.vary
        grid.addWidget(p.label, 0, 6, QtCore.Qt.AlignRight)
        grid.addWidget(p.box, 0, 7, QtCore.Qt.AlignHCenter)
        grid.addWidget(p.checkbox, 0, 8, QtCore.Qt.AlignHCenter)
        p = self.lattice['alpha']
        p.box.setFixedWidth(80)
        label, value, checkbox = p.label, p.value, p.vary
        grid.addWidget(p.label, 1, 0, QtCore.Qt.AlignRight)
        grid.addWidget(p.box, 1, 1, QtCore.Qt.AlignHCenter)
        grid.addWidget(p.checkbox, 1, 2, QtCore.Qt.AlignHCenter)
        p = self.lattice['beta']
        p.box.setFixedWidth(80)
        label, value, checkbox = p.label, p.value, p.vary
        grid.addWidget(p.label, 1, 3, QtCore.Qt.AlignRight)
        grid.addWidget(p.box, 1, 4, QtCore.Qt.AlignHCenter)
        grid.addWidget(p.checkbox, 1, 5, QtCore.Qt.AlignHCenter)
        p = self.lattice['gamma']
        p.box.setFixedWidth(80)
        label, value, checkbox = p.label, p.value, p.vary
        grid.addWidget(p.label, 1, 6, QtCore.Qt.AlignRight)
        grid.addWidget(p.box, 1, 7, QtCore.Qt.AlignHCenter)
        grid.addWidget(p.checkbox, 1, 8, QtCore.Qt.AlignHCenter)
        self.table_view = QtWidgets.QTableView()
        self.table_model = NXTableModel(self, peak_list, header)
        self.table_view.setModel(self.table_model)
        self.table_view.resizeColumnsToContents()
        self.table_view.horizontalHeader().stretchLastSection()
        self.table_view.setSelectionBehavior(
            QtWidgets.QAbstractItemView.SelectRows)
        self.table_view.doubleClicked.connect(self.plot_peak)
        self.table_view.setSortingEnabled(True)
        self.table_view.sortByColumn(0, QtCore.Qt.AscendingOrder)
        layout = QtWidgets.QVBoxLayout()
        layout.addLayout(orient_layout)
        layout.addLayout(grid)
        layout.addWidget(self.table_view)
        close_layout = QtWidgets.QHBoxLayout()
        self.status_text = QtWidgets.QLabel('Score: %.4f' %
                                            self.refine.score())
        self.tolerance_box = QtWidgets.QLineEdit(str(
            self.refine.hkl_tolerance))
        self.tolerance_box.setAlignment(QtCore.Qt.AlignRight)
        self.tolerance_box.setMaxLength(5)
        self.tolerance_box.editingFinished.connect(self.update_table)
        self.tolerance_box.setFixedWidth(80)
        save_button = QtWidgets.QPushButton('Save Orientation')
        save_button.clicked.connect(self.save_orientation)
        close_button = QtWidgets.QPushButton('Close Window')
        close_button.clicked.connect(message_box.close)
        close_layout.addWidget(self.status_text)
        close_layout.addStretch()
        close_layout.addWidget(QtWidgets.QLabel('Threshold'))
        close_layout.addWidget(self.tolerance_box)
        close_layout.addStretch()
        close_layout.addWidget(save_button)
        close_layout.addStretch()
        close_layout.addWidget(close_button)
        layout.addLayout(close_layout)
        message_box.setLayout(layout)
        message_box.setWindowTitle('%s Peak Table' % self.entry.nxtitle)
        message_box.adjustSize()
        message_box.show()
        self.plotview = None

    def plot_peak(self):
        row = self.table_view.currentIndex().row()
        data = self.entry.data
        x, y, z = [
            self.table_view.model().peak_list[row][i] for i in range(1, 4)
        ]
        xmin, xmax = max(0, x - 200), min(x + 200, data.nxsignal.shape[2])
        ymin, ymax = max(0, y - 200), min(y + 200, data.nxsignal.shape[1])
        zmin, zmax = max(0, z - 200), min(z + 200, data.nxsignal.shape[0])
        zslab = np.s_[z, ymin:ymax, xmin:xmax]
        if self.plotview is None:
            self.plotview = NXPlotView('X-Y Projection')
        self.plotview.plot(data[zslab], log=True)
        self.plotview.crosshairs(x, y)

    def orient(self):
        self.refine.primary = int(self.primary_box.text())
        self.refine.secondary = int(self.secondary_box.text())
        self.refine.Umat = self.refine.get_UBmat(self.refine.primary,
                                                 self.refine.secondary) \
                           * self.refine.Bimat
        self.update_table()

    def refine_orientation(self):
        idx = self.refine.idx
        intensities = self.refine.intensity[idx]
        sigma = np.average(intensities) / intensities
        p0 = self.set_parameters(idx)

        def diffs(p):
            self.get_parameters(p)
            UBimat = np.linalg.inv(self.refine.UBmat)
            Q = [UBimat * self.Gvec[i] for i in idx]
            dQ = Q - np.rint(Q)
            return np.array([
                np.linalg.norm(self.refine.Bmat * np.matrix(dQ[i]))
                for i in idx
            ]) / sigma

        popt, C, info, msg, success = leastsq(diffs, p0, full_output=1)
        self.get_parameters(popt)
        self.update_lattice()
        self.update_table()
        self.status_text.setText('Score: %.4f' % self.refine.score())

    def restore_orientation(self):
        self.refine.Umat = self.Umat
        for par in self.lattice.values():
            par.value = par.init_value
        self.update_table()

    def update_table(self):
        self.refine.hkl_tolerance = np.float32(self.tolerance_box.text())
        self.table_model.peak_list = self.refine.get_peaks()
        rows, columns = len(self.table_model.peak_list), 11
        self.table_model.dataChanged.emit(
            self.table_model.createIndex(0, 0),
            self.table_model.createIndex(rows - 1, columns - 1))
        self.status_text.setText('Score: %.4f' % self.refine.score())

    def update_lattice(self):
        self.lattice['a'].value = self.refine.a
        self.lattice['b'].value = self.refine.b
        self.lattice['c'].value = self.refine.c
        self.lattice['alpha'].value = self.refine.alpha
        self.lattice['beta'].value = self.refine.beta
        self.lattice['gamma'].value = self.refine.gamma

    def set_parameters(self, idx):
        x, y, z = self.refine.xp[idx], self.refine.yp[idx], self.refine.zp[idx]
        self.Gvec = [
            self.refine.Gvec(xx, yy, zz) for xx, yy, zz in zip(x, y, z)
        ]
        self.Umat = self.refine.Umat
        pars = []
        for par in self.lattice.values():
            par.init_value = par.value
            if par.vary:
                pars.append(par.value)
        p0 = np.zeros(shape=(len(pars) + 9), dtype=np.float32)
        p0[:len(pars)] = pars
        p0[len(pars):] = np.ravel(self.refine.Umat)
        return p0

    def get_parameters(self, p):
        i = 0
        for par in self.lattice.values():
            if par.vary:
                par.value = p[i]
                i += 1
        self.refine.a, self.refine.b, self.refine.c, \
            self.refine.alpha, self.refine.beta, self.refine.gamma = \
                [par.value for par in self.lattice.values()]
        self.refine.set_symmetry()
        self.refine.Umat = np.matrix(p[i:]).reshape(3, 3)

    def save_orientation(self):
        self.write_parameters()

    def write_parameters(self):
        try:
            self.refine.write_parameters()
        except NeXusError as error:
            report_error('Defining Orientation', error)
Exemplo n.º 27
0
class MakeDialog(BaseDialog):
    def __init__(self, parent=None):
        super(MakeDialog, self).__init__(parent)
        self.scans = None
        self.set_layout(
            self.directorybox("Choose Sample Directory", self.choose_sample),
            self.textboxes(('Scan Command', 'Pil2Mscan')),
            self.action_buttons(('Select All', self.select_scans),
                                ('Reverse All', self.reverse_scans),
                                ('Clear All', self.clear_scans),
                                ('Make Scan Macro', self.make_scans)),
            self.close_buttons(close=True))
        self.set_title('Make Scans')

    def choose_sample(self):
        super(MakeDialog, self).choose_directory()
        self.sample_directory = self.get_directory()
        self.experiment_directory = os.path.dirname(
            os.path.dirname(self.sample_directory))
        self.macro_directory = os.path.join(self.experiment_directory,
                                            'macros')
        self.label = os.path.basename(self.sample_directory)
        self.sample = os.path.basename(os.path.dirname(self.sample_directory))
        self.experiment = os.path.basename(self.experiment_directory)
        self.experiment_path = self.experiment
        self.scan_path = os.path.join(self.experiment, self.sample, self.label)
        self.setup_scans()

    def setup_scans(self):
        if self.scans:
            self.scans.delete_grid()
        self.scans = GridParameters()
        all_files = [
            self.sample + '_' + d + '.nxs'
            for d in os.listdir(self.sample_directory)
            if os.path.isdir(os.path.join(self.sample_directory, d))
        ]
        filenames = sorted([
            f for f in all_files
            if os.path.exists(os.path.join(self.sample_directory, f))
        ],
                           key=natural_sort)
        for i, f in enumerate(filenames):
            scan = 'f%d' % i
            self.scans.add(scan, i + 1, f, True, self.update_scans)
            self.scans[scan].checkbox.stateChanged.connect(self.update_scans)
        self.insert_layout(2, self.scans.grid(header=False))

    @property
    def scan_list(self):
        scan_list = []
        for scan in self.scans.values():
            if scan.checkbox.isChecked() and scan.value > 0:
                scan_list.append(scan)
            else:
                scan.value = 0
        return sorted(scan_list, key=attrgetter('value'))

    def update_scans(self):
        scan_list = self.scan_list
        scan_number = 0
        for scan in scan_list:
            scan_number += 1
            scan.value = scan_number
        for scan in self.scans.values():
            if scan.checkbox.isChecked() and scan.value == 0:
                scan.value = scan_number + 1
                scan_number += 1

    def select_scans(self):
        for i, scan in enumerate(self.scans):
            self.scans[scan].value = i + 1
            self.scans[scan].checkbox.setChecked(True)

    def reverse_scans(self):
        for i, scan in enumerate(reversed(self.scan_list)):
            scan.value = i + 1
            scan.checkbox.setChecked(True)

    def clear_scans(self):
        for scan in self.scans:
            self.scans[scan].value = 0
            self.scans[scan].checkbox.setChecked(False)

    def make_scans(self):
        scans = [scan.label.text() for scan in self.scan_list]
        scan_command = self.textbox['Scan Command'].text()
        scan_parameters = [
            '#command path filename temperature detx dety ' +
            'phi_start phi_step phi_end chi omega frame_rate'
        ]
        for scan in self.scan_list:
            nexus_file = scan.label.text()
            root = nxload(os.path.join(self.sample_directory, nexus_file))
            temperature = root.entry.sample.temperature
            base_name = os.path.basename(os.path.splitext(nexus_file)[0])
            scan_dir = base_name.replace(self.sample + '_', '')
            for entry in [root[e] for e in root if e != 'entry']:
                if 'phi_set' in entry['instrument/goniometer']:
                    phi_start = entry['instrument/goniometer/phi_set']
                else:
                    phi_start = entry['instrument/goniometer/phi']
                phi_step = entry['instrument/goniometer/phi'].attrs['step']
                phi_end = entry['instrument/goniometer/phi'].attrs['end']
                if 'chi_set' in entry['instrument/goniometer']:
                    chi = entry['instrument/goniometer/chi_set']
                else:
                    chi = entry['instrument/goniometer/chi']
                if 'omega_set' in entry['instrument/goniometer']:
                    omega = entry['instrument/goniometer/omega_set']
                else:
                    omega = entry['instrument/goniometer/omega']
                dx = entry['instrument/detector/translation_x']
                dy = entry['instrument/detector/translation_y']
                if ('frame_time' in entry['instrument/detector']
                        and entry['instrument/detector/frame_time'] > 0.0):
                    frame_rate = 1.0 / entry['instrument/detector/frame_time']
                else:
                    frame_rate = 10.0
                scan_file = entry.nxname
                if scan_command == 'Pil2Mscan':
                    scan_parameters.append(
                        '%s %s %s %.6g %.6g %.6g %.6g %.6g %.6g %.6g %.6g %.6g'
                        %
                        (scan_command, os.path.join(self.scan_path, scan_dir),
                         scan_file, temperature, dx, dy, phi_start, phi_step,
                         phi_end, chi, omega, frame_rate))
            if scan_command == 'Pil2Mstring':
                scan_parameters.append('Pil2Mstring("%s")' % scan_dir)
            elif scan_command != 'Pil2Mscan':
                scan_parameters.append('%s %s' % (scan_command, temperature))
        if not os.path.exists(self.macro_directory):
            os.mkdir(os.path.join(self.experiment_directory, 'macros'))
        macro_filter = ';;'.join(("SPEC Macro (*.mac)", "Any Files (*.* *)"))
        macro = getSaveFileName(self, 'Open Macro', self.macro_directory,
                                macro_filter)
        if macro:
            with open(macro, 'w') as f:
                f.write('\n'.join(scan_parameters))
Exemplo n.º 28
0
class MaximumDialog(BaseDialog):
    def __init__(self, parent=None):
        super(MaximumDialog, self).__init__(parent)

        self.select_entry(self.choose_entry)

        self.parameters = GridParameters()
        self.parameters.add('first', '', 'First Frame')
        self.parameters.add('last', '', 'Last Frame')

        self.output = QtWidgets.QLabel('Maximum Value:')
        self.set_layout(
            self.entry_layout, self.output, self.parameters.grid(),
            self.action_buttons(('Find Maximum', self.find_maximum)),
            self.progress_layout(save=True))
        self.progress_bar.setVisible(False)
        self.progress_bar.setValue(0)
        self.set_title('Find Maximum Value')
        self.reduce = None

    def choose_entry(self):
        self.reduce = NXReduce(self.entry)
        self.maximum = self.reduce.maximum
        if self.reduce.first:
            self.parameters['first'].value = self.reduce.first
        if self.reduce.last:
            self.parameters['last'].value = self.reduce.last

    @property
    def first(self):
        try:
            _first = np.int32(self.parameters['first'].value)
            if _first >= 0:
                return _first
            else:
                return None
        except Exception as error:
            return None

    @property
    def last(self):
        try:
            _last = np.int32(self.parameters['last'].value)
            if _last > 0:
                return _last
            else:
                return None
        except Exception as error:
            return None

    @property
    def maximum(self):
        return np.float(self.output.text().split()[-1])

    @maximum.setter
    def maximum(self, value):
        self.output.setText('Maximum Value: %s' % value)

    def find_maximum(self):
        self.check_lock(self.reduce.data_file)
        self.start_thread()
        self.reduce = NXReduce(self.entry,
                               first=self.first,
                               last=self.last,
                               maxcount=True,
                               overwrite=True,
                               gui=True)
        self.reduce.moveToThread(self.thread)
        self.reduce.start.connect(self.start_progress)
        self.reduce.update.connect(self.update_progress)
        self.reduce.result.connect(self.get_maximum)
        self.reduce.stop.connect(self.stop)
        self.thread.started.connect(self.reduce.nxmax)
        self.thread.finished.connect(self.stop)
        self.thread.start(QtCore.QThread.LowestPriority)

    def check_lock(self, file_name):
        try:
            with Lock(file_name, timeout=2):
                pass
        except LockException as error:
            if self.confirm_action('Clear lock?', str(error)):
                Lock(file_name).release()

    def get_maximum(self, maximum):
        self.maximum = maximum

    def stop(self):
        self.stop_progress()
        if self.thread and self.thread.isRunning():
            self.reduce.stopped = True
        self.stop_thread()

    def accept(self):
        try:
            with Lock(self.reduce.wrapper_file):
                self.reduce.write_maximum(self.maximum)
        except LockException as error:
            if self.confirm_action('Clear lock?', str(error)):
                Lock(self.reduce.wrapper_file).release()
        self.stop()
        super(MaximumDialog, self).accept()

    def reject(self):
        self.stop()
        super(MaximumDialog, self).reject()
Exemplo n.º 29
0
class ScanDialog(BaseDialog):

    def __init__(self, parent=None):
        super(ScanDialog, self).__init__(parent)

        self.scan_file = NXroot()
        self.scan_file['entry'] = NXentry()

        self.detectors = {}
        self.entries = {}

        self.setup_sample()
        self.setup_instrument()

        self.set_layout(self.directorybox('Choose Data Directory'), 
                        self.sample.grid(header=False), 
                        self.instrument.grid(header=False))
        self.set_title('New Scan')

    def setup_sample(self):
        self.scan_file['entry/sample'] = NXsample()
        self.scan_file['entry/sample/name'] = 'sample'
        self.scan_file['entry/sample/label'] = 'label'
        self.scan_file['entry/sample/temperature'] = NXfield(300.0, dtype=np.float32)
        self.scan_file['entry/sample/temperature'].attrs['units'] = 'K'
        self.sample = GridParameters()
        self.sample.add('sample', self.scan_file['entry/sample/name'], 'Sample Name')
        self.sample.add('label', self.scan_file['entry/sample/label'], 'Sample Label')
        self.sample.add('scan', 'scan', 'Scan Label')
        self.sample.add('temperature', self.scan_file['entry/sample/temperature'], 'Temperature (K)')

    def setup_instrument(self):
        entry = self.scan_file['entry']
        entry.instrument = NXinstrument()
        entry.instrument.monochromator = NXmonochromator()
        entry.instrument.detector = NXdetector()
        entry['instrument/monochromator/wavelength'] = NXfield(0.5, dtype=np.float32)
        entry['instrument/monochromator/wavelength'].attrs['units'] = 'Angstroms'
        entry['instrument/detector/distance'] = NXfield(100.0, dtype=np.float32)
        entry['instrument/detector/distance'].attrs['units'] = 'mm'
        entry['instrument/detector/pixel_size'] = NXfield(0.172, dtype=np.float32)
        entry['instrument/detector/pixel_size'].attrs['units'] = 'mm'
        self.instrument = GridParameters()
        self.instrument.add('wavelength', entry['instrument/monochromator/wavelength'], 'Wavelength (Ang)')
        self.instrument.add('distance', entry['instrument/detector/distance'], 'Detector Distance (mm)')
        self.instrument.add('pixel', entry['instrument/detector/pixel_size'], 'Pixel Size (mm)')
        self.instrument.add('positions', [0,1,2,3,4], 'Number of Detector Positions', slot=self.set_entries)
        self.instrument['positions'].value = '0'

    def setup_entry(self, position):
        entry = self.scan_file['f%s' % position] = NXentry()
        entry.instrument = NXinstrument()
        entry.instrument.detector = NXdetector()
        entry.instrument.monochromator = NXmonochromator()
        entry['instrument/detector/beam_center_x'] = NXfield(1024.0, dtype=np.float32)
        entry['instrument/detector/beam_center_y'] = NXfield(1024.0, dtype=np.float32)
        self.detectors[position] = GridParameters()
        self.detectors[position].add('xc', entry['instrument/detector/beam_center_x'], 'Beam Center - x')
        self.detectors[position].add('yc', entry['instrument/detector/beam_center_y'], 'Beam Center - y')

    @property
    def positions(self):
        return int(self.instrument['positions'].value)
 
    def set_entries(self):
        for position in range(1,self.positions+1):
            self.setup_entry(position)
            self.layout.addLayout(self.detectors[position].grid(header=False, title='Position %s'%position))
        self.layout.addWidget(self.close_buttons(save=True))

    def get_parameters(self):
        entry = self.scan_file['entry']
        entry['sample/name'] = self.sample['sample'].value
        entry['sample/label'] = self.sample['label'].value
        entry['sample/temperature'] = self.sample['temperature'].value
        entry['instrument/monochromator/wavelength'] = self.instrument['wavelength'].value
        entry['instrument/detector/distance'] = self.instrument['distance'].value
        entry['instrument/detector/pixel_size'] = self.instrument['pixel'].value
        for position in range(1, self.positions+1):
            entry = self.scan_file['f%s' % position]
            entry['instrument/monochromator/wavelength'] = self.instrument['wavelength'].value
            entry['instrument/detector/distance'] = self.instrument['distance'].value
            entry['instrument/detector/pixel_size'] = self.instrument['pixel'].value
            entry['instrument/detector/beam_center_x'] = self.detectors[position]['xc'].value
            entry['instrument/detector/beam_center_y'] = self.detectors[position]['yc'].value
            entry.makelink(self.scan_file['entry/sample'])

    def accept(self):
        home_directory = self.get_directory()
        sample_directory = os.path.join(home_directory, self.sample['sample'].value)
        label_directory = os.path.join(home_directory, self.sample['sample'].value, self.sample['label'].value)
        scan_directory = os.path.join(label_directory, self.sample['scan'].value)
        scan_name = self.sample['sample'].value+'_'+self.sample['scan'].value
        try: 
            os.makedirs(scan_directory)
            for position in range(1, self.positions+1):
                os.mkdir(os.path.join(scan_directory, 'f%s' % position))
        except Exception:
            pass
        self.get_parameters()
        self.scan_file.save(os.path.join(label_directory, scan_name+'.nxs'))
        self.treeview.tree.load(self.scan_file.nxfilename, 'rw')
        super(ScanDialog, self).accept()
Exemplo n.º 30
0
class ParametersDialog(BaseDialog):

    def __init__(self, parent=None):
        super(ParametersDialog, self).__init__(parent)

        self.select_root(self.choose_root)

        self.parameters = GridParameters()
        self.parameters.add('threshold', '', 'Threshold')
        self.parameters.add('first', 25, 'First Frame')
        self.parameters.add('last', 3625, 'Last Frame')
        self.parameters.add('radius', 200, 'Radius')
        self.parameters.add('width', 3, 'Frame Width')
        self.parameters.add('norm', '', 'Normalization')

        self.set_layout(self.root_layout,
                        self.parameters.grid(),
                        self.close_buttons(save=True))
        self.set_title('Choose Parameters')

    def choose_root(self):
        self.entries = [self.root[entry] 
                        for entry in self.root if entry != 'entry']
        self.update_parameters()

    def update_parameters(self):
        reduce = NXReduce(self.entries[0])
        if reduce.first:
            self.parameters['first'].value = reduce.first
        if reduce.last:
            self.parameters['last'].value = reduce.last
        if reduce.threshold:
            self.parameters['threshold'].value = reduce.threshold
        if reduce.radius:
            self.parameters['radius'].value = reduce.radius
        if reduce.width:
            self.parameters['width'].value = reduce.width        
        if reduce.norm:
            self.parameters['norm'].value = reduce.norm

    def write_parameters(self, entry):
        if 'peaks' not in entry:
            entry['peaks'] = NXreflections()
        if self.first:
            entry['peaks'].attrs['first'] = np.int(self.first)
        elif 'first' in entry['peaks'].attrs:
            del entry['peaks'].attrs['first']
        if self.last:
            entry['peaks'].attrs['last'] = np.int(self.last)
        elif 'last' in entry['peaks'].attrs:
            del entry['peaks'].attrs['last']
        if self.threshold:
            entry['peaks'].attrs['threshold'] = self.threshold
        elif 'threshold' in entry['peaks'].attrs:
            del entry['peaks'].attrs['threshold']
        if self.radius:
            entry['peaks'].attrs['radius'] = np.int(self.radius)
        elif 'radius' in entry['peaks'].attrs:
            del entry['peaks'].attrs['radius']
        if self.width:
            entry['peaks'].attrs['width'] = np.int(self.width)
        elif 'width' in entry['peaks'].attrs:
            del entry['peaks'].attrs['width']
        if self.norm:
            entry['peaks'].attrs['norm'] = self.norm
        elif 'norm' in entry['peaks'].attrs:
            del entry['peaks'].attrs['norm']

    def get_value(self, key):
        value = self.parameters[key].value
        if isinstance(value, float) and value <= 0:
            return None
        elif isinstance(value, str):
            return None
        else:
            return value
    
    @property
    def threshold(self):
        return self.get_value('threshold')

    @property
    def first(self):
        return self.get_value('first')

    @property
    def last(self):
        return self.get_value('last')

    @property
    def radius(self):
        return self.get_value('radius')

    @property
    def width(self):
        return self.get_value('width')

    @property
    def norm(self):
        return self.get_value('norm')

    def accept(self):
        for entry in self.entries:
            self.write_parameters(entry)
        super(ParametersDialog, self).accept()
Exemplo n.º 31
0
class ExperimentDialog(BaseDialog):
    def __init__(self, parent=None):
        super(ExperimentDialog, self).__init__(parent)

        self.experiment_file = NXroot()
        self.experiment_file['entry'] = NXentry()

        self.detectors = {}
        self.entries = {}

        self.setup_instrument()

        self.set_layout(
            self.directorybox('Choose Experiment Directory', default=False),
            self.instrument.grid(header=False))
        self.set_title('New Experiment')

    def setup_instrument(self):
        entry = self.experiment_file['entry']
        entry.instrument = NXinstrument()
        entry.instrument.monochromator = NXmonochromator()
        entry.instrument.detector = NXdetector()
        entry['instrument/monochromator/wavelength'] = NXfield(
            0.5, dtype=np.float32)
        entry['instrument/monochromator/wavelength'].attrs[
            'units'] = 'Angstroms'
        entry['instrument/monochromator/energy'] = NXfield(12.398419739640717 /
                                                           0.5,
                                                           dtype=np.float32)
        entry['instrument/monochromator/energy'].attrs['units'] = 'keV'
        entry['instrument/detector/distance'] = NXfield(100.0,
                                                        dtype=np.float32)
        entry['instrument/detector/distance'].attrs['units'] = 'mm'
        self.instrument = GridParameters()
        self.instrument.add('experiment', 'experiment', 'Experiment Name')
        self.instrument.add('wavelength',
                            entry['instrument/monochromator/wavelength'],
                            'Wavelength (Ang)')
        self.instrument.add('distance', entry['instrument/detector/distance'],
                            'Detector Distance (mm)')
        detector_list = sorted(
            list(set([detector().name
                      for detector in ALL_DETECTORS.values()])))
        self.instrument.add('detector', detector_list, 'Detector')
        self.instrument['detector'].value = 'Pilatus CdTe 2M'
        self.instrument.add('positions', [0, 1, 2, 3, 4],
                            'Number of Detector Positions',
                            slot=self.set_entries)
        self.instrument['positions'].value = '0'

    def setup_entry(self, position):
        entry = NXentry()
        self.detectors[position] = GridParameters()
        self.detectors[position].add('x', 0.0, 'Translation - x (mm)')
        self.detectors[position].add('y', 0.0, 'Translation - y (mm)')
        self.experiment_file['f%s' % position] = entry

    def get_detector(self):
        for detector in ALL_DETECTORS:
            if ALL_DETECTORS[detector](
            ).name == self.instrument['detector'].value:
                return ALL_DETECTORS[detector]()

    @property
    def positions(self):
        return int(self.instrument['positions'].value)

    def set_entries(self):
        for position in range(1, self.positions + 1):
            self.setup_entry(position)
            self.layout.addLayout(self.detectors[position].grid(
                header=False, title='Position %s' % position))
        self.layout.addWidget(self.close_buttons(save=True))

    def get_parameters(self):
        entry = self.experiment_file['entry']
        entry['instrument/monochromator/wavelength'] = self.instrument[
            'wavelength'].value
        entry[
            'instrument/monochromator/energy'] = 12.398419739640717 / self.instrument[
                'wavelength'].value
        detector = self.get_detector()
        entry['instrument/detector/description'] = detector.name
        entry['instrument/detector/distance'] = self.instrument[
            'distance'].value
        entry['instrument/detector/pixel_size'] = detector.pixel1 * 1000
        entry['instrument/detector/pixel_size'].attrs['units'] = 'mm'
        entry['instrument/detector/pixel_mask'] = detector.mask
        entry['instrument/detector/shape'] = detector.shape
        entry['instrument/detector/yaw'] = 0.0
        entry['instrument/detector/pitch'] = 0.0
        entry['instrument/detector/roll'] = 0.0
        for position in range(1, self.positions + 1):
            entry = self.experiment_file['f%s' % position]
            entry['instrument'] = self.experiment_file['entry/instrument']
            entry['instrument/detector/translation_x'] = self.detectors[
                position]['x'].value
            entry['instrument/detector/translation_x'].attrs['units'] = 'mm'
            entry['instrument/detector/translation_y'] = self.detectors[
                position]['y'].value
            entry['instrument/detector/translation_y'].attrs['units'] = 'mm'
            entry['instrument/detector/frame_time'] = 0.1
            entry['instrument/detector/frame_time'].attrs['units'] = 'seconds'

    def accept(self):
        try:
            home_directory = self.get_directory()
            self.mainwindow.default_directory = home_directory
            self.get_parameters()
            configuration_directory = os.path.join(home_directory,
                                                   'configurations')
            if not os.path.exists(configuration_directory):
                os.makedirs(configuration_directory)
            self.experiment_file.save(
                os.path.join(configuration_directory,
                             self.instrument['experiment'].value + '.nxs'))
            task_directory = os.path.join(home_directory, 'tasks')
            if not os.path.exists(task_directory):
                os.makedirs(task_directory)
            calibration_directory = os.path.join(home_directory,
                                                 'calibrations')
            if not os.path.exists(calibration_directory):
                os.makedirs(calibration_directory)
            self.treeview.tree.load(self.experiment_file.nxfilename, 'rw')
            super(ExperimentDialog, self).accept()
        except Exception as error:
            report_error("Defining New Experiment", error)
Exemplo n.º 32
0
class OrientationDialog(BaseDialog):

    def __init__(self, parent=None):
        super(OrientationDialog, self).__init__(parent)

        self.select_entry(self.choose_entry)

        self.refine = NXRefine(self.entry)
        self.refine.read_parameters()

        self.parameters = GridParameters()
        self.parameters.add('phi_start', self.refine.phi, 'Phi Start (deg)')
        self.parameters.add('phi_step', self.refine.phi_step, 'Phi Step (deg)')
        self.parameters.add('chi', self.refine.chi, 'Chi (deg)')
        self.parameters.add('omega', self.refine.omega, 'Omega (deg)')
        self.parameters.add('polar', self.refine.polar_max, 
                            'Max. Polar Angle (deg)')
        self.parameters.add('polar_tolerance', self.refine.polar_tolerance, 
                            'Polar Angle Tolerance')
        self.parameters.add('peak_tolerance', self.refine.peak_tolerance, 
                            'Peak Angle Tolerance')
        action_buttons = self.action_buttons(
                             ('Generate Grains', self.generate_grains),
                             ('List Peaks', self.list_peaks))
        self.grain_layout = QtWidgets.QHBoxLayout()
        self.grain_combo = QtWidgets.QComboBox()
        self.grain_combo.setSizeAdjustPolicy(QtWidgets.QComboBox.AdjustToContents)
        self.grain_combo.currentIndexChanged.connect(self.set_grain)
        self.grain_textbox = QtWidgets.QLabel()
        self.grain_layout.addWidget(self.grain_combo)
        self.grain_layout.addStretch()
        self.grain_layout.addWidget(self.grain_textbox)
        bottom_layout = QtWidgets.QHBoxLayout()
        self.result_textbox = QtWidgets.QLabel()
        bottom_layout.addWidget(self.result_textbox)
        bottom_layout.addStretch()
        bottom_layout.addWidget(self.close_buttons())
        self.set_layout(self.entry_layout, self.parameters.grid(), 
                        action_buttons, bottom_layout)
        self.set_title('Defining Orientation')

    def choose_entry(self):
        self.refine = NXRefine(self.entry)
        self.update_parameters()

    def update_parameters(self):
        self.parameters['phi_start'].value = self.refine.phi
        self.parameters['phi_step'].value = self.refine.phi_step
        self.parameters['chi'].value = self.refine.chi
        self.parameters['omega'].value = self.refine.omega
        self.parameters['polar'].value = self.refine.polar_max
        self.parameters['polar_tolerance'].value = self.refine.polar_tolerance
        self.parameters['peak_tolerance'].value = self.refine.peak_tolerance

    def get_phi(self):
        return (self.parameters['phi_start'].value,
                self.parameters['phi_step'].value) 

    def set_phi(self):
        self.refine.phi_start, self.refine.phi_step = self.get_phi() 

    def get_chi(self):
        return self.parameters['chi'].value

    def set_chi(self):
        self.refine.chi = self.get_chi() 

    def get_omega(self):
        return self.parameters['omega'].value 

    def set_omega(self):
        self.refine.omega = self.get_omega() 

    @property
    def polar_max(self):
        return self.parameters['polar'].value

    def set_polar_max(self):
        self.refine.polar_max = self.polar_max

    def get_polar_tolerance(self):
        return self.parameters['polar_tolerance'].value

    def set_polar_tolerance(self):
        self.refine.polar_tolerance = self.get_polar_tolerance()

    def get_peak_tolerance(self):
        return self.parameters['peak_tolerance'].value

    def set_peak_tolerance(self):
        self.refine.peak_tolerance = self.get_peak_tolerance()

    def generate_grains(self):
        self.set_polar_max()
        self.refine.generate_grains()
        if self.refine.grains is not None:
            self.layout.insertLayout(2, self.grain_layout)
        self.grain_combo.clear()
        for i in range(len(self.refine.grains)):
            self.grain_combo.addItem('Grain %s' % i)
        self.grain_combo.setCurrentIndex(0)
        self.set_grain()

    def set_grain(self):
        try:
            grain = self.refine.grains[self.get_grain()]
            self.grain_textbox.setText('%s peaks; Score: %.4f' 
                                       % (len(grain), grain.score))
            self.refine.Umat = grain.Umat
            self.refine.primary = grain.primary
            self.refine.secondary = grain.secondary
            self.get_score()
        except:
            self.grain_textbox.setText('')

    def get_grain(self):
        return int(self.grain_combo.currentText().split()[-1])

    def list_peaks(self):
        self.refine.phi = self.get_phi()
        self.refine.chi = self.get_chi()
        self.refine.omega = self.get_omega()
        if self.refine.grains is not None:
            grain = self.refine.grains[self.get_grain()]
            self.refine.Umat = grain.Umat
            self.list_orientations()
        else:
            self.list_orientations()

    def get_score(self):
        if self.refine.Umat is not None:
            self.score = self.refine.score()
            self.result_textbox.setText('%s peaks; Score: %.4f'
                                        % (len(self.refine.idx), self.score))

    def list_orientations(self):
        message_box = BaseDialog(self)
        message_box.setMinimumWidth(600)
        message_box.setMinimumHeight(600)
        header = ['i', 'x', 'y', 'z', 'Polar', 'Azi', 'Intensity',
                  'H', 'K', 'L', 'Diff']
        peak_list = self.refine.get_peaks()
        self.refine.assign_rings()
        self.rings = self.refine.get_ring_hkls()
        orient_layout = QtWidgets.QHBoxLayout()
        if self.refine.primary is None:
            self.refine.primary = 0
        if self.refine.secondary is None:
            self.refine.secondary = 1
        self.primary_box = QtWidgets.QLineEdit(str(self.refine.primary))
        self.primary_box.setAlignment(QtCore.Qt.AlignRight)
        self.primary_box.setFixedWidth(80)
        self.secondary_box = QtWidgets.QLineEdit(str(self.refine.secondary))
        self.secondary_box.setAlignment(QtCore.Qt.AlignRight)
        self.secondary_box.setFixedWidth(80)
        orient_button = QtWidgets.QPushButton('Orient')
        orient_button.clicked.connect(self.orient)
        refine_button = QtWidgets.QPushButton('Refine')
        refine_button.clicked.connect(self.refine_orientation)
        restore_button = QtWidgets.QPushButton('Restore')
        restore_button.clicked.connect(self.restore_orientation)
        orient_layout.addStretch()
        orient_layout.addWidget(QtWidgets.QLabel('Primary'))
        orient_layout.addWidget(self.primary_box)
        orient_layout.addWidget(QtWidgets.QLabel('Secondary'))
        orient_layout.addWidget(self.secondary_box)
        orient_layout.addStretch()
        orient_layout.addWidget(orient_button)     
        orient_layout.addWidget(refine_button)
        orient_layout.addWidget(restore_button)

        grid = QtWidgets.QGridLayout()
        grid.setSpacing(10)
        self.lattice = GridParameters()
        self.lattice.add('a', self.refine.a, 'a', False)
        self.lattice.add('b', self.refine.b, 'b', False)
        self.lattice.add('c', self.refine.c, 'c', False)
        self.lattice.add('alpha', self.refine.alpha, 'alpha', False)
        self.lattice.add('beta', self.refine.beta, 'beta', False)
        self.lattice.add('gamma', self.refine.gamma, 'gamma', False)
        p = self.lattice['a']
        p.box.setFixedWidth(80)
        label, value, checkbox = p.label, p.value, p.vary
        grid.addWidget(p.label, 0, 0, QtCore.Qt.AlignRight)
        grid.addWidget(p.box, 0, 1, QtCore.Qt.AlignHCenter)
        grid.addWidget(p.checkbox, 0, 2, QtCore.Qt.AlignHCenter)
        p = self.lattice['b']
        p.box.setFixedWidth(80)
        label, value, checkbox = p.label, p.value, p.vary
        grid.addWidget(p.label, 0, 3, QtCore.Qt.AlignRight)
        grid.addWidget(p.box, 0, 4, QtCore.Qt.AlignHCenter)
        grid.addWidget(p.checkbox, 0, 5, QtCore.Qt.AlignHCenter)
        p = self.lattice['c']
        p.box.setFixedWidth(80)
        label, value, checkbox = p.label, p.value, p.vary
        grid.addWidget(p.label, 0, 6, QtCore.Qt.AlignRight)
        grid.addWidget(p.box, 0, 7, QtCore.Qt.AlignHCenter)
        grid.addWidget(p.checkbox, 0, 8, QtCore.Qt.AlignHCenter)
        p = self.lattice['alpha']
        p.box.setFixedWidth(80)
        label, value, checkbox = p.label, p.value, p.vary
        grid.addWidget(p.label, 1, 0, QtCore.Qt.AlignRight)
        grid.addWidget(p.box, 1, 1, QtCore.Qt.AlignHCenter)
        grid.addWidget(p.checkbox, 1, 2, QtCore.Qt.AlignHCenter)
        p = self.lattice['beta']
        p.box.setFixedWidth(80)
        label, value, checkbox = p.label, p.value, p.vary
        grid.addWidget(p.label, 1, 3, QtCore.Qt.AlignRight)
        grid.addWidget(p.box, 1, 4, QtCore.Qt.AlignHCenter)
        grid.addWidget(p.checkbox, 1, 5, QtCore.Qt.AlignHCenter)
        p = self.lattice['gamma']
        p.box.setFixedWidth(80)
        label, value, checkbox = p.label, p.value, p.vary
        grid.addWidget(p.label, 1, 6, QtCore.Qt.AlignRight)
        grid.addWidget(p.box, 1, 7, QtCore.Qt.AlignHCenter)
        grid.addWidget(p.checkbox, 1, 8, QtCore.Qt.AlignHCenter)
        self.table_view = QtWidgets.QTableView()
        self.table_model = NXTableModel(self, peak_list, header)
        self.table_view.setModel(self.table_model)
        self.table_view.resizeColumnsToContents()
        self.table_view.horizontalHeader().stretchLastSection()
        self.table_view.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
        self.table_view.doubleClicked.connect(self.plot_peak)
        self.table_view.setSortingEnabled(True)
        self.table_view.sortByColumn(0, QtCore.Qt.AscendingOrder)
        layout = QtWidgets.QVBoxLayout()
        layout.addLayout(orient_layout)
        layout.addLayout(grid)
        layout.addWidget(self.table_view)
        close_layout = QtWidgets.QHBoxLayout()
        self.status_text = QtWidgets.QLabel('Score: %.4f' % self.refine.score())
        self.tolerance_box = QtWidgets.QLineEdit(str(self.refine.hkl_tolerance))
        self.tolerance_box.setAlignment(QtCore.Qt.AlignRight)
        self.tolerance_box.setMaxLength(5)
        self.tolerance_box.editingFinished.connect(self.update_table)
        self.tolerance_box.setFixedWidth(80)
        save_button = QtWidgets.QPushButton('Save Orientation')
        save_button.clicked.connect(self.save_orientation)
        close_button = QtWidgets.QPushButton('Close Window')
        close_button.clicked.connect(message_box.close)
        close_layout.addWidget(self.status_text)
        close_layout.addStretch()
        close_layout.addWidget(QtWidgets.QLabel('Threshold'))
        close_layout.addWidget(self.tolerance_box)
        close_layout.addStretch()
        close_layout.addWidget(save_button)
        close_layout.addStretch()
        close_layout.addWidget(close_button)
        layout.addLayout(close_layout)
        message_box.setLayout(layout)
        message_box.setWindowTitle('%s Peak Table' % self.entry.nxtitle)
        message_box.adjustSize()
        message_box.show()
        self.plotview = None

    def plot_peak(self):
        row = self.table_view.currentIndex().row()
        data = self.entry.data
        x, y, z = [self.table_view.model().peak_list[row][i] for i in range(1, 4)]
        xmin, xmax = max(0,x-200), min(x+200,data.nxsignal.shape[2])
        ymin, ymax = max(0,y-200), min(y+200,data.nxsignal.shape[1])
        zmin, zmax = max(0,z-200), min(z+200,data.nxsignal.shape[0])
        zslab=np.s_[z,ymin:ymax,xmin:xmax]
        if self.plotview is None:
            self.plotview = NXPlotView('X-Y Projection')
        self.plotview.plot(data[zslab], log=True)
        self.plotview.crosshairs(x, y)

    def orient(self):
        self.refine.primary = int(self.primary_box.text())
        self.refine.secondary = int(self.secondary_box.text())
        self.refine.Umat = self.refine.get_UBmat(self.refine.primary, 
                                                 self.refine.secondary) \
                           * self.refine.Bimat
        self.update_table()

    def refine_orientation(self):
        idx = self.refine.idx
        intensities = self.refine.intensity[idx]
        sigma = np.average(intensities) / intensities
        p0 = self.set_parameters(idx)
        def diffs(p):
            self.get_parameters(p)
            UBimat = np.linalg.inv(self.refine.UBmat)
            Q = [UBimat * self.Gvec[i] for i in idx]
            dQ = Q - np.rint(Q)
            return np.array([np.linalg.norm(self.refine.Bmat*np.matrix(dQ[i])) 
                             for i in idx]) / sigma
        popt, C, info, msg, success = leastsq(diffs, p0, full_output=1)
        self.get_parameters(popt)
        self.update_lattice()
        self.update_table()
        self.status_text.setText('Score: %.4f' % self.refine.score())

    def restore_orientation(self):
        self.refine.Umat = self.Umat
        for par in self.lattice.values():
            par.value = par.init_value
        self.update_table()

    def update_table(self):
        self.refine.hkl_tolerance = np.float32(self.tolerance_box.text())
        self.table_model.peak_list = self.refine.get_peaks()
        rows, columns = len(self.table_model.peak_list), 11
        self.table_model.dataChanged.emit(self.table_model.createIndex(0, 0),
                                          self.table_model.createIndex(rows-1, columns-1))
        self.status_text.setText('Score: %.4f' % self.refine.score())

    def update_lattice(self):
        self.lattice['a'].value = self.refine.a
        self.lattice['b'].value = self.refine.b
        self.lattice['c'].value = self.refine.c
        self.lattice['alpha'].value = self.refine.alpha
        self.lattice['beta'].value = self.refine.beta
        self.lattice['gamma'].value = self.refine.gamma

    def set_parameters(self, idx):
        x, y, z = self.refine.xp[idx], self.refine.yp[idx], self.refine.zp[idx]
        self.Gvec = [self.refine.Gvec(xx,yy,zz) for xx,yy,zz in zip(x,y,z)]
        self.Umat = self.refine.Umat
        pars = []
        for par in self.lattice.values():
            par.init_value = par.value
            if par.vary:
                pars.append(par.value)
        p0 = np.zeros(shape=(len(pars)+9), dtype=np.float32)
        p0[:len(pars)] = pars
        p0[len(pars):] = np.ravel(self.refine.Umat)
        return p0

    def get_parameters(self, p):
        i = 0
        for par in self.lattice.values():
            if par.vary:
                par.value = p[i]
                i += 1
        self.refine.a, self.refine.b, self.refine.c, \
            self.refine.alpha, self.refine.beta, self.refine.gamma = \
                [par.value for par in self.lattice.values()]
        self.refine.set_symmetry()
        self.refine.Umat = np.matrix(p[i:]).reshape(3,3)

    def save_orientation(self):
        self.write_parameters()

    def write_parameters(self):
        try:
            self.refine.write_parameters()
        except NeXusError as error:
            report_error('Defining Orientation', error)
Exemplo n.º 33
0
class CalculateDialog(NXDialog):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.select_entry(self.choose_entry)

        self.refine = NXRefine()

        self.parameters = GridParameters()
        self.parameters.add('wavelength', self.refine.wavelength,
                            'Wavelength (Ang)')
        self.parameters.add('distance', self.refine.distance,
                            'Detector Distance (mm)')
        self.parameters.add('xc', self.refine.xc, 'Beam Center - x')
        self.parameters.add('yc', self.refine.yc, 'Beam Center - y')
        self.parameters.add('pixel', self.refine.pixel_size, 'Pixel Size (mm)')
        self.action_buttons = self.action_buttons(
            ('Plot', self.plot_lattice), ('Save', self.write_parameters))
        self.set_layout(self.entry_layout, self.close_buttons())
        self.set_title('Calculate Angles')

    def choose_entry(self):
        self.refine = NXRefine(self.entry)
        if 'peaks' in self.entry:
            if self.layout.count() == 2:
                self.insert_layout(1, self.parameters.grid(header=False))
                self.insert_layout(2, self.action_buttons)
            self.update_parameters()
        else:
            self.display_message("Calculating Angles",
                                 "No peaks have been found in this entry")

    def update_parameters(self):
        self.parameters['wavelength'].value = self.refine.wavelength
        self.parameters['distance'].value = self.refine.distance
        self.parameters['xc'].value = self.refine.xc
        self.parameters['yc'].value = self.refine.yc
        self.parameters['pixel'].value = self.refine.pixel_size

    def get_wavelength(self):
        return self.parameters['wavelength'].value

    def get_distance(self):
        return self.parameters['distance'].value

    def get_centers(self):
        return self.parameters['xc'].value, self.parameters['yc'].value

    def get_pixel_size(self):
        return self.parameters['pixel'].value

    def get_parameters(self):
        self.refine.wavelength = self.get_wavelength()
        self.refine.distance = self.get_distance()
        self.refine.xc, self.refine.yc = self.get_centers()
        self.refine.pixel_size = self.get_pixel_size()
        self.refine.yaw = self.refine.pitch = self.refine.roll = None

    def plot_lattice(self):
        try:
            self.get_parameters()
            self.plot_peaks(self.refine.xp, self.refine.yp)
        except NeXusError as error:
            report_error("Calculating Angles", error)

    def plot_peaks(self, x, y):
        try:
            polar_angles, azimuthal_angles = self.refine.calculate_angles(x, y)
            if polar_angles[0] > polar_angles[-1]:
                polar_angles = polar_angles[::-1]
                azimuthal_angles = azimuthal_angles[::-1]
            azimuthal_field = NXfield(azimuthal_angles, name='azimuthal_angle')
            azimuthal_field.long_name = 'Azimuthal Angle'
            polar_field = NXfield(polar_angles, name='polar_angle')
            polar_field.long_name = 'Polar Angle'
            plotview = get_plotview()
            plotview.plot(
                NXdata(azimuthal_field, polar_field, title='Peak Angles'))
        except NeXusError as error:
            report_error("Plotting Lattice", error)

    def write_parameters(self):
        try:
            self.get_parameters()
            polar_angles, azimuthal_angles = self.refine.calculate_angles(
                self.refine.xp, self.refine.yp)
            self.refine.write_angles(polar_angles, azimuthal_angles)
            self.refine.write_parameters()
        except NeXusError as error:
            report_error("Calculating Angles", error)
Exemplo n.º 34
0
class ScanDialog(NXDialog):

    def __init__(self, parent=None):
        super().__init__(parent)

        self.config_file = None
        self.positions = 1
        self.entries = {}

        self.settings = NXSettings()

        self.directory_box = self.directorybox('Choose Experiment Directory',
                                               self.choose_directory,
                                               default=False)
        self.sample_box = self.select_sample()
        self.sample_layout = self.make_layout(
            self.action_buttons(('Choose Sample', self.choose_sample)),
            self.sample_box)
        self.configuration_box = self.select_configuration()
        self.configuration_layout = self.make_layout(
            self.action_buttons(('Choose Experiment Configuration',
                                 self.choose_configuration)),
            self.configuration_box)
        self.scan_box = self.select_box(['1'], slot=self.choose_position)
        self.scan_layout = self.make_layout(
            self.labels('Position', header=True), self.scan_box)
        self.set_layout(self.directory_box,
                        self.close_buttons(close=True))

        self.set_title('New Scan')

    @property
    def configuration(self):
        return self.configuration_box.currentText()

    @property
    def sample(self):
        return self.sample_box.currentText().split('/')[0]

    @property
    def label(self):
        return self.sample_box.currentText().split('/')[1]

    @property
    def position(self):
        try:
            return int(self.scan_box.currentText())
        except ValueError:
            return 1

    def choose_directory(self):
        super().choose_directory()
        self.mainwindow.default_directory = self.get_directory()
        self.setup_directory()
        self.insert_layout(1, self.sample_layout)

    def setup_directory(self):
        self.sample_box.clear()
        samples = self.get_samples()
        for sample in samples:
            self.sample_box.addItem(sample)
        self.sample_box.adjustSize()
        configurations = self.get_configurations()
        self.configuration_box.clear()
        for configuration in configurations:
            self.configuration_box.addItem(configuration)

    def select_sample(self):
        return self.select_box(self.get_samples())

    def get_samples(self):
        home_directory = self.get_directory()
        if os.path.exists(home_directory):
            sample_directories = [f for f in os.listdir(home_directory)
                                  if (not f.startswith('.') and
                                      os.path.isdir(
                                      os.path.join(home_directory, f)))]
        else:
            return []
        samples = []
        for sample_directory in sample_directories:
            label_directories = [
                f
                for f in os.listdir(
                    os.path.join(home_directory, sample_directory))
                if os.path.isdir(
                    os.path.join(home_directory, sample_directory, f))]
            for label_directory in label_directories:
                samples.append(os.path.join(sample_directory, label_directory))
        return [sample.strip() for sample in samples]

    def choose_sample(self):
        self.insert_layout(2, self.configuration_layout)

    def select_configuration(self):
        return self.select_box(self.get_configurations())

    def get_configurations(self):
        home_directory = self.get_directory()
        if (os.path.exists(home_directory) and
                'configurations' in os.listdir(home_directory)):
            return sorted(
                [f
                 for f in os.listdir(
                     os.path.join(home_directory, 'configurations'))
                 if f.endswith('.nxs')])
        else:
            return []

    def choose_configuration(self):
        home_directory = self.get_directory()
        config_file = os.path.join(home_directory, 'configurations',
                                   self.configuration)
        if os.path.exists(config_file):
            self.config_file = nxload(config_file)
            self.positions = len(self.config_file.entries) - 1
            self.scan_box.clear()
            for position in range(1, self.positions+1):
                self.scan_box.addItem(f'{position}')
            self.scan_box.setCurrentIndex(0)
            self.copy_configuration()
        self.setup_scans()
        self.read_parameters()
        self.insert_layout(3, self.scan.grid(header=False))
        self.insert_layout(4, self.scan_layout)
        for p in range(1, self.positions+1):
            self.insert_layout(p+4, self.entries[p].grid_layout)
        self.insert_layout(self.positions+5,
                           self.action_buttons(('Make Scan File',
                                                self.make_scan)))

    def setup_scans(self):
        default = self.settings['nxrefine']
        self.scan = GridParameters()
        self.scan.add('scan', 'scan', 'Scan Label')
        self.scan.add('temperature', 300.0, 'Temperature (K)')
        self.scan.add('phi_start', default['phi'], 'Phi Start (deg)')
        self.scan.add('phi_end', default['phi_end'], 'Phi End (deg)')
        self.scan.add('phi_step', default['phi_step'], 'Phi Step (deg)')
        self.scan.add('frame_rate', default['frame_rate'], 'Frame Rate (Hz)')

        for position in range(1, self.positions+1):
            self.setup_position(position)

    def setup_position(self, position):
        default = self.settings['nxrefine']
        self.entries[position] = GridParameters()
        self.entries[position].add('chi', default['chi'], 'Chi (deg)')
        self.entries[position].add('omega', default['omega'], 'Omega (deg)')
        self.entries[position].add('x', default['x'], 'Translation - x (mm)')
        self.entries[position].add('y', default['y'], 'Translation - y (mm)')
        self.entries[position].add('linkfile', f'f{position:d}.h5',
                                   'Detector Filename')
        self.entries[position].add(
            'linkpath', '/entry/data/data', 'Detector Data Path')
        self.entries[position].grid(header=False)
        if position != 1:
            self.entries[position].hide_grid()

    def choose_position(self):
        for i in self.entries:
            self.entries[i].hide_grid()
        if self.position in self.entries:
            self.entries[self.position].show_grid()

    def copy_configuration(self):
        self.scan_file = NXroot()
        for entry in self.config_file.entries:
            self.scan_file[entry] = self.config_file[entry]

    def read_parameters(self):
        for position in range(1, self.positions+1):
            entry = self.scan_file[f'f{position:d}']
            if 'instrument/goniometer/chi' in entry:
                self.entries[position]['chi'].value = (
                    entry['instrument/goniometer/chi'])
            if 'instrument/goniometer/omega' in entry:
                self.entries[position]['omega'].value = (
                    entry['instrument/goniometer/omega'])
            if 'instrument/detector/translation_x' in entry:
                self.entries[position]['x'].value = (
                    entry['instrument/detector/translation_x'])
            if 'instrument/detector/translation_y' in entry:
                self.entries[position]['y'].value = (
                    entry['instrument/detector/translation_y'])

    def get_parameters(self):
        entry = self.scan_file['entry']
        if 'sample' not in entry:
            entry['sample'] = NXsample()
        entry['sample/name'] = self.sample
        entry['sample/label'] = self.label
        entry['sample/temperature'] = self.scan['temperature'].value
        entry['sample/temperature'].attrs['units'] = 'K'
        y_size, x_size = entry['instrument/detector/shape'].nxvalue
        scan = self.scan['scan'].value
        for position in range(1, self.positions+1):
            entry = self.scan_file[f'f{position:d}']
            entry.makelink(self.scan_file['entry/sample'])
            phi_start = self.scan['phi_start'].value
            phi_end = self.scan['phi_end'].value
            phi_step = self.scan['phi_step'].value
            chi = self.entries[position]['chi'].value
            omega = self.entries[position]['omega'].value
            frame_rate = self.scan['frame_rate'].value
            if 'goniometer' not in entry['instrument']:
                entry['instrument/goniometer'] = NXgoniometer()
            entry['instrument/goniometer/phi'] = phi_start
            entry['instrument/goniometer/phi_set'] = phi_start
            entry['instrument/goniometer/phi'].attrs['step'] = phi_step
            entry['instrument/goniometer/phi'].attrs['end'] = phi_end
            entry['instrument/goniometer/chi'] = chi
            entry['instrument/goniometer/chi_set'] = chi
            entry['instrument/goniometer/omega'] = omega
            entry['instrument/goniometer/omega_set'] = omega
            if frame_rate > 0.0:
                entry['instrument/detector/frame_time'] = 1.0 / frame_rate
            linkpath = self.entries[position]['linkpath'].value
            linkfile = os.path.join(
                scan, self.entries[position]['linkfile'].value)
            entry['data'] = NXdata()
            entry['data'].nxsignal = NXlink(linkpath, linkfile)
            entry['data/x_pixel'] = np.arange(x_size, dtype=np.int32)
            entry['data/y_pixel'] = np.arange(y_size, dtype=np.int32)
            entry['data/frame_number'] = np.arange(
                (phi_end-phi_start)/phi_step, dtype=np.int32)
            entry['data'].nxaxes = [entry['data/frame_number'],
                                    entry['data/y_pixel'],
                                    entry['data/x_pixel']]

    def make_scan(self):
        home_directory = self.get_directory()
        self.mainwindow.default_directory = home_directory
        sample_directory = os.path.join(home_directory, self.sample)
        label_directory = os.path.join(home_directory, self.sample, self.label)
        scan_directory = os.path.join(
            label_directory, str(self.scan['scan'].value))
        scan_name = self.sample+'_'+self.scan['scan'].value
        try:
            os.makedirs(scan_directory)
        except Exception:
            pass
        self.copy_configuration()
        self.get_parameters()
        self.scan_file.save(os.path.join(label_directory, scan_name+'.nxs'))
        self.treeview.tree.load(self.scan_file.nxfilename, 'r')
Exemplo n.º 35
0
class Mask3DDialog(BaseDialog):
    def __init__(self, parent=None):
        super(Mask3DDialog, self).__init__(parent)

        self.select_entry(self.choose_entry)

        self.parameters = GridParameters()
        self.parameters.add('radius', 200, 'Radius')
        self.parameters.add('width', 3, 'Frame Width')
        self.set_layout(
            self.entry_layout, self.parameters.grid(),
            self.action_buttons(('Calculate 3D Mask', self.calculate_mask)),
            self.progress_layout(save=True))
        self.progress_bar.setVisible(False)
        self.progress_bar.setValue(0)
        self.set_title('Calculate 3D Mask')
        self.reduce = None

    def choose_entry(self):
        self.reduce = NXReduce(self.entry)

    @property
    def radius(self):
        return self.parameters['radius'].value

    @property
    def width(self):
        return self.parameters['width'].value

    def calculate_mask(self):
        self.check_lock(self.reduce.wrapper_file)
        self.thread = QtCore.QThread()
        self.reduce = NXReduce(self.entry,
                               radius=self.radius,
                               width=self.width,
                               mask=True,
                               overwrite=True,
                               gui=True)
        self.reduce.moveToThread(self.thread)
        self.reduce.start.connect(self.start_progress)
        self.reduce.update.connect(self.update_progress)
        self.reduce.result.connect(self.calculate_mask)
        self.reduce.stop.connect(self.stop)
        self.thread.started.connect(self.reduce.nxfind)
        self.thread.start(QtCore.QThread.LowestPriority)

    def check_lock(self, file_name):
        try:
            with Lock(file_name, timeout=2):
                pass
        except LockException as error:
            if self.confirm_action('Clear lock?', str(error)):
                Lock(file_name).release()

    def calculate_mask(self, mask):
        self.mask = mask

    def stop(self):
        self.stop_progress()
        if self.thread and self.thread.isRunning():
            self.reduce.stopped = True
            self.thread.exit()

    def accept(self):
        try:
            with Lock(self.reduce.wrapper_file):
                self.reduce.write_peaks(self.peaks)
        except LockException as error:
            if self.confirm_action('Clear lock?', str(error)):
                Lock(self.reduce.wrapper_file).release()
        if self.thread:
            self.stop()
        super(Mask3DDialog, self).accept()

    def reject(self):
        if self.thread:
            self.stop()
        super(Mask3DDialog, self).reject()
Exemplo n.º 36
0
class FindDialog(NXDialog):
    def __init__(self, parent=None):
        super().__init__(parent)

        self.select_entry(self.choose_entry)

        default = NXSettings().settings['nxreduce']
        self.parameters = GridParameters()
        self.parameters.add('threshold', default['threshold'], 'Threshold')
        self.parameters.add('first', default['first'], 'First Frame')
        self.parameters.add('last', default['last'], 'Last Frame')
        self.parameters.add('min_pixels', default['min_pixels'],
                            'Minimum Pixels in Peak')
        self.parameters.grid()
        self.find_button = NXPushButton('Find Peaks', self.find_peaks)
        self.find_layout = self.make_layout(self.action_buttons(
            ('Find Peaks', self.find_peaks), ('List Peaks', self.list_peaks)),
                                            align='center')
        self.set_layout(self.entry_layout,
                        self.close_layout(save=True, progress=True))
        self.set_title('Find Peaks')
        self.reduce = None
        self.refine = None
        self.peaks_box = None

    def choose_entry(self):
        if self.layout.count() == 2:
            self.insert_layout(1, self.parameters.grid_layout)
            self.insert_layout(2, self.find_layout)
        self.reduce = NXReduce(self.entry)
        self.refine = NXRefine(self.entry)
        self.refine.polar_max = self.refine.two_theta_max()
        if self.reduce.first is not None:
            self.parameters['first'].value = self.reduce.first
        if self.reduce.last:
            self.parameters['last'].value = self.reduce.last
        else:
            try:
                self.parameters['last'].value = self.reduce.shape[0]
            except Exception:
                pass
        self.parameters['threshold'].value = self.reduce.threshold

    @property
    def threshold(self):
        try:
            return int(self.parameters['threshold'].value)
        except Exception as error:
            report_error("Finding Peaks", error)

    @property
    def first(self):
        try:
            return int(self.parameters['first'].value)
        except Exception as error:
            report_error("Finding Peaks", error)

    @property
    def last(self):
        try:
            return int(self.parameters['last'].value)
        except Exception as error:
            report_error("Finding Peaks", error)

    @property
    def min_pixels(self):
        try:
            return int(self.parameters['min_pixels'].value)
        except Exception as error:
            report_error("Finding Peaks", error)

    def find_peaks(self):
        if is_file_locked(self.reduce.data_file):
            return
        self.start_thread()
        self.reduce = NXReduce(self.entry,
                               threshold=self.threshold,
                               first=self.first,
                               last=self.last,
                               min_pixels=self.min_pixels,
                               find=True,
                               overwrite=True,
                               gui=True)
        self.reduce.moveToThread(self.thread)
        self.reduce.start.connect(self.start_progress)
        self.reduce.update.connect(self.update_progress)
        self.reduce.result.connect(self.get_peaks)
        self.reduce.stop.connect(self.stop)
        self.thread.started.connect(self.reduce.nxfind)
        self.thread.start()

    def get_peaks(self, peaks):
        self.peaks = peaks
        self.status_message.setText(f'{len(self.peaks)} peaks found')
        self.status_message.setVisible(True)
        self.refine.xp = np.array([peak.x for peak in peaks])
        self.refine.yp = np.array([peak.y for peak in peaks])
        self.refine.zp = np.array([peak.z for peak in peaks])
        self.refine.intensity = np.array([peak.intensity for peak in peaks])
        self.refine.polar_angle, self.refine.azimuthal_angle = (
            self.refine.calculate_angles(self.refine.xp, self.refine.yp))
        self.update_table()

    def stop(self):
        self.stop_progress()
        if self.thread and self.thread.isRunning():
            self.reduce.stopped = True
        self.stop_thread()

    def list_peaks(self):
        if self.peaks_box in self.mainwindow.dialogs:
            self.update_table()
            return
        self.peaks_box = NXDialog(self)
        self.peaks_box.setMinimumWidth(600)
        self.peaks_box.setMinimumHeight(600)
        header = [
            'i', 'x', 'y', 'z', 'Polar', 'Azi', 'Intensity', 'H', 'K', 'L',
            'Diff'
        ]
        peak_list = self.refine.get_peaks()
        self.table_view = QtWidgets.QTableView()
        self.table_model = NXTableModel(self, peak_list, header)
        self.table_view.setModel(self.table_model)
        self.table_view.resizeColumnsToContents()
        self.table_view.horizontalHeader().stretchLastSection()
        self.table_view.setSelectionBehavior(
            QtWidgets.QAbstractItemView.SelectRows)
        self.table_view.doubleClicked.connect(self.plot_peak)
        self.table_view.setSortingEnabled(True)
        self.table_view.sortByColumn(0, QtCore.Qt.AscendingOrder)
        self.peaks_box.set_layout(self.table_view,
                                  self.close_buttons(close=True))
        self.peaks_box.set_title(f'{self.refine.name} Peak Table')
        self.peaks_box.adjustSize()
        self.peaks_box.show()
        self.plotview = None

    def update_table(self):
        if self.peaks_box not in self.mainwindow.dialogs:
            return
        elif self.table_model is None:
            self.close_peaks_box()
            self.list_peaks()
        self.table_model.peak_list = self.refine.get_peaks()
        rows, columns = len(self.table_model.peak_list), 11
        self.table_model.dataChanged.emit(
            self.table_model.createIndex(0, 0),
            self.table_model.createIndex(rows - 1, columns - 1))
        self.table_view.resizeColumnsToContents()
        self.peaks_box.set_title(f'{self.refine.name} Peak Table')
        self.peaks_box.adjustSize()
        self.peaks_box.setVisible(True)

    def plot_peak(self):
        row = self.table_view.currentIndex().row()
        data = self.entry.data
        i, x, y, z = [
            self.table_view.model().peak_list[row][i] for i in range(4)
        ]
        signal = data.nxsignal
        xmin, xmax = max(0, x - 200), min(x + 200, signal.shape[2])
        ymin, ymax = max(0, y - 200), min(y + 200, signal.shape[1])
        zmin, zmax = max(0, z - 20), min(z + 20, signal.shape[0])
        zslab = np.s_[zmin:zmax, ymin:ymax, xmin:xmax]
        if 'Peak Plot' in self.plotviews:
            self.plotview = self.plotviews['Peak Plot']
        else:
            self.plotview = NXPlotView('Peak Plot')
        self.plotview.plot(data[zslab], log=True)
        self.plotview.ax.set_title(f'{data.nxtitle}: Peak {i}')
        self.plotview.ztab.maxbox.setValue(z)
        self.plotview.aspect = 'equal'
        self.plotview.crosshairs(x, y, color='r', linewidth=0.5)

    def close_peaks_box(self):
        try:
            self.peaks_box.close()
        except Exception:
            pass
        self.peaks_box = None

    def accept(self):
        try:
            self.reduce.write_peaks(self.peaks)
            self.reduce.record('nxfind',
                               threshold=self.threshold,
                               first_frame=self.first,
                               last_frame=self.last,
                               min_pixels=self.min_pixels,
                               peak_number=len(self.peaks))
            self.reduce.record_end('nxfind')
            super().accept()
        except Exception as error:
            report_error("Finding Peaks", error)

    def reject(self):
        self.stop()
        super().reject()
Exemplo n.º 37
0
class ExperimentDialog(BaseDialog):

    def __init__(self, parent=None):
        super(ExperimentDialog, self).__init__(parent)

        self.experiment_file = NXroot()
        self.experiment_file['entry'] = NXentry()

        self.detectors = {}
        self.entries = {}

        self.setup_instrument()

        self.set_layout(self.directorybox('Choose Home Directory'), 
                        self.instrument.grid(header=False))
        self.set_title('New Experiment')

    def setup_instrument(self):
        entry = self.experiment_file['entry']
        entry.instrument = NXinstrument()
        entry.instrument.monochromator = NXmonochromator()
        entry.instrument.detector = NXdetector()
        entry['instrument/monochromator/wavelength'] = NXfield(0.5, dtype=np.float32)
        entry['instrument/monochromator/wavelength'].attrs['units'] = 'Angstroms'
        entry['instrument/detector/distance'] = NXfield(100.0, dtype=np.float32)
        entry['instrument/detector/distance'].attrs['units'] = 'mm'
        entry['instrument/detector/pixel_size'] = NXfield(0.172, dtype=np.float32)
        entry['instrument/detector/pixel_size'].attrs['units'] = 'mm'
        self.instrument = GridParameters()
        self.instrument.add('wavelength', entry['instrument/monochromator/wavelength'], 'Wavelength (Ang)')
        self.instrument.add('distance', entry['instrument/detector/distance'], 'Detector Distance (mm)')
        self.instrument.add('pixel', entry['instrument/detector/pixel_size'], 'Pixel Size (mm)')
        self.instrument.add('positions', [0,1,2,3,4], 'Number of Detector Positions', slot=self.set_entries)
        self.instrument['positions'].value = '0'

    def setup_entry(self, position):
        entry = self.experiment_file['f%s' % position] = NXentry()
        entry.instrument = NXinstrument()
        entry.instrument.detector = NXdetector()
        entry.instrument.monochromator = NXmonochromator()
        entry['instrument/detector/beam_center_x'] = NXfield(1024.0, dtype=np.float32)
        entry['instrument/detector/beam_center_y'] = NXfield(1024.0, dtype=np.float32)
        self.detectors[position] = GridParameters()
        self.detectors[position].add('xc', entry['instrument/detector/beam_center_x'], 'Beam Center - x')
        self.detectors[position].add('yc', entry['instrument/detector/beam_center_y'], 'Beam Center - y')

    @property
    def positions(self):
        return int(self.instrument['positions'].value)
 
    def set_entries(self):
        for position in range(1,self.positions+1):
            self.setup_entry(position)
            self.layout.addLayout(self.detectors[position].grid(header=False, title='Position %s'%position))
        self.layout.addWidget(self.close_buttons(save=True))

    def get_parameters(self):
        entry = self.experiment_file['entry']
        entry['instrument/monochromator/wavelength'] = self.instrument['wavelength'].value
        entry['instrument/detector/distance'] = self.instrument['distance'].value
        entry['instrument/detector/pixel_size'] = self.instrument['pixel'].value
        for position in range(1, self.positions+1):
            entry = self.experiment_file['f%s' % position]
            entry['instrument/monochromator/wavelength'] = self.instrument['wavelength'].value
            entry['instrument/detector/distance'] = self.instrument['distance'].value
            entry['instrument/detector/pixel_size'] = self.instrument['pixel'].value
            entry['instrument/detector/beam_center_x'] = self.detectors[position]['xc'].value
            entry['instrument/detector/beam_center_y'] = self.detectors[position]['yc'].value
            entry.makelink(self.experiment_file['entry/sample'])

    def accept(self):
        try:
            home_directory = self.get_directory()
            self.get_parameters()
            self.experiment_file.save(os.path.join(home_directory, experiment+'.nxs'))
            self.treeview.tree.load(self.experiment_file.nxfilename, 'rw')
            super(ExperimentDialog, self).accept()
        except NeXusError as error:
            report_error("Defining New Experiment", error)
Exemplo n.º 38
0
class RefineLatticeDialog(BaseDialog):

    def __init__(self, parent=None):
        super(RefineLatticeDialog, self).__init__(parent)

        self.select_entry(self.choose_entry)

        self.refine = NXRefine(self.entry)
        self.refine.read_parameters()

        self.parameters = GridParameters()
        self.parameters.add('symmetry', self.refine.symmetries, 'Symmetry', 
                            None, self.set_symmetry)
        self.parameters.add('a', self.refine.a, 'Unit Cell - a (Ang)', True)
        self.parameters.add('b', self.refine.b, 'Unit Cell - b (Ang)', True)
        self.parameters.add('c', self.refine.c, 'Unit Cell - c (Ang)', True)
        self.parameters.add('alpha', self.refine.alpha, 'Unit Cell - alpha (deg)', False)
        self.parameters.add('beta', self.refine.beta, 'Unit Cell - beta (deg)', False)
        self.parameters.add('gamma', self.refine.gamma, 'Unit Cell - gamma (deg)', False)
        self.parameters.add('wavelength', self.refine.wavelength, 'Wavelength (Ang)', False)
        self.parameters.add('distance', self.refine.distance, 'Distance (mm)', False)
        self.parameters.add('yaw', self.refine.yaw, 'Yaw (deg)', False)
        self.parameters.add('pitch', self.refine.pitch, 'Pitch (deg)', False)
        self.parameters.add('roll', self.refine.roll, 'Roll (deg)')
        self.parameters.add('xc', self.refine.xc, 'Beam Center - x', False)
        self.parameters.add('yc', self.refine.yc, 'Beam Center - y', False)
        self.parameters.add('phi_start', self.refine.phi_start, 'Phi Start (deg)', False)
        self.parameters.add('phi_step', self.refine.phi_step, 'Phi Step (deg)')
        self.parameters.add('chi_start', self.refine.chi_start, 'Chi Start (deg)', False)
        self.parameters.add('chi_step', self.refine.chi_step, 'Chi Step (deg)')
        self.parameters.add('omega_start', self.refine.omega_start, 'Omega Start (deg)', False)
        self.parameters.add('omega_step', self.refine.omega_step, 'Omega Step (deg)')
        self.parameters.add('polar', self.refine.polar_max, 
                            'Max. Polar Angle (deg)', None, self.set_polar_max)
        self.parameters.add('polar_tolerance', self.refine.polar_tolerance, 'Polar Angle Tolerance')
        self.parameters.add('peak_tolerance', self.refine.peak_tolerance, 'Peak Angle Tolerance')
        self.parameters.add('orientation_matrix', False, 'Orientation Matrix', False)

        self.refine_buttons = self.action_buttons(
                                  ('Refine Angles', self.refine_angles),
                                  ('Refine HKLs', self.refine_hkls),
                                  ('Restore', self.restore_parameters),
                                  ('Reset', self.reset_parameters))

        self.lattice_buttons = self.action_buttons(
                                   ('Plot', self.plot_lattice),
                                   ('List', self.list_peaks),
                                   ('Save', self.write_parameters))

        self.set_layout(self.entry_layout, self.parameters.grid(), 
                        self.refine_buttons, self.lattice_buttons,
                        self.close_buttons())

        self.parameters.grid_layout.setVerticalSpacing(1)
                                
        self.set_title('Refining Lattice')

        self.parameters['symmetry'].value = self.refine.symmetry
        self.set_symmetry()

        self.peaks_box = None
        
    def choose_entry(self):
        self.refine = NXRefine(self.entry)
        self.update_parameters()

    def update_parameters(self):
        self.parameters['a'].value = self.refine.a
        self.parameters['b'].value = self.refine.b
        self.parameters['c'].value = self.refine.c
        self.parameters['alpha'].value = self.refine.alpha
        self.parameters['beta'].value = self.refine.beta
        self.parameters['gamma'].value = self.refine.gamma
        self.parameters['wavelength'].value = self.refine.wavelength
        self.parameters['distance'].value = self.refine.distance
        self.parameters['yaw'].value = self.refine.yaw
        self.parameters['pitch'].value = self.refine.pitch
        self.parameters['roll'].value = self.refine.roll
        self.parameters['xc'].value = self.refine.xc
        self.parameters['yc'].value = self.refine.yc
        self.parameters['phi_start'].value = self.refine.phi_start
        self.parameters['phi_step'].value = self.refine.phi_step
        self.parameters['chi_start'].value = self.refine.chi_start
        self.parameters['chi_step'].value = self.refine.chi_step
        self.parameters['omega_start'].value = self.refine.omega_start
        self.parameters['omega_step'].value = self.refine.omega_step
        self.parameters['polar'].value = self.refine.polar_max
        self.parameters['polar_tolerance'].value = self.refine.polar_tolerance
        try:
            self.refine.polar_angles, self.refine.azimuthal_angles = \
                self.refine.calculate_angles(self.refine.xp, self.refine.yp)
        except Exception:
            pass

    def transfer_parameters(self):
        self.refine.a, self.refine.b, self.refine.c, \
            self.refine.alpha, self.refine.beta, self.refine.gamma = \
                self.get_lattice_parameters()
        self.refine.set_symmetry()
        self.refine.wavelength = self.get_wavelength()
        self.refine.distance = self.get_distance()
        self.refine.yaw, self.refine.pitch, self.refine.roll = self.get_tilts()
        self.refine.xc, self.refine.yc = self.get_centers()
        self.refine.phi_start, self.refine.phi_step = self.get_phi()
        self.refine.chi_start, self.refine.chi_step = self.get_chi()
        self.refine.omega_start, self.refine.omega_step = self.get_omega()
        self.refine.polar_max = self.get_polar_max()
        self.refine.polar_tol = self.get_tolerance()
        self.refine.polar_angles

    def write_parameters(self):
        self.transfer_parameters()
        polar_angles, azimuthal_angles = self.refine.calculate_angles(
                                             self.refine.xp, self.refine.yp)
        self.refine.write_angles(polar_angles, azimuthal_angles)
        self.refine.write_parameters()

    def get_symmetry(self):
        return self.parameters['symmetry'].value

    def set_symmetry(self):
        self.refine.symmetry = self.get_symmetry()
        self.refine.set_symmetry()
        self.update_parameters()
        if self.refine.symmetry == 'cubic':
            self.parameters['b'].vary = False
            self.parameters['c'].vary = False
            self.parameters['alpha'].vary = False
            self.parameters['beta'].vary = False
            self.parameters['gamma'].vary = False
        elif self.refine.symmetry == 'tetragonal':
            self.parameters['b'].vary = False
            self.parameters['alpha'].vary = False
            self.parameters['beta'].vary = False
            self.parameters['gamma'].vary = False
        elif self.refine.symmetry == 'orthorhombic':
            self.parameters['alpha'].vary = False
            self.parameters['beta'].vary = False
            self.parameters['gamma'].vary = False
        elif self.refine.symmetry == 'hexagonal':
            self.parameters['b'].vary = False
            self.parameters['alpha'].vary = False
            self.parameters['beta'].vary = False
            self.parameters['gamma'].vary = False
        elif self.refine.symmetry == 'monoclinic':
            self.parameters['alpha'].vary = False
            self.parameters['gamma'].vary = False

    def get_lattice_parameters(self):
        return (self.parameters['a'].value,
                self.parameters['b'].value,
                self.parameters['c'].value,
                self.parameters['alpha'].value,
                self.parameters['beta'].value,
                self.parameters['gamma'].value)

    def get_wavelength(self):
        return self.parameters['wavelength'].value

    def get_distance(self):
        return self.parameters['distance'].value

    def get_tilts(self):
        return (self.parameters['yaw'].value,
                self.parameters['pitch'].value,
                self.parameters['roll'].value)

    def get_centers(self):
        return self.parameters['xc'].value, self.parameters['yc'].value

    def get_polar_max(self):
        return self.parameters['polar'].value

    def set_polar_max(self):
        self.refine.polar_max = self.get_polar_max()

    def get_tolerance(self):
        return self.parameters['polar_tolerance'].value

    def get_phi(self):
        return (self.parameters['phi_start'].value, 
                self.parameters['phi_step'].value)

    def get_chi(self):
        return (self.parameters['chi_start'].value, 
                self.parameters['chi_step'].value)

    def get_omega(self):
        return (self.parameters['omega_start'].value, 
                self.parameters['omega_step'].value)

    def get_hkl_tolerance(self):
        try:
            return np.float32(self.tolerance_box.text())
        except Exception:
            return self.refine.hkl_tolerance

    def plot_lattice(self):
        self.transfer_parameters()
        self.set_polar_max()
        self.plot_peaks()
        self.plot_rings()

    def plot_peaks(self):
        try:
            x, y = self.refine.xp[self.refine.idx], self.refine.yp[self.refine.idx]
            polar_angles, azimuthal_angles = self.refine.calculate_angles(x, y)
            if polar_angles[0] > polar_angles[-1]:
                polar_angles = polar_angles[::-1]
                azimuthal_angles = azimuthal_angles[::-1]
            azimuthal_field = NXfield(azimuthal_angles, name='azimuthal_angle')
            azimuthal_field.long_name = 'Azimuthal Angle'
            polar_field = NXfield(polar_angles, name='polar_angle')
            polar_field.long_name = 'Polar Angle'
            plotview = get_plotview()
            plotview.plot(NXdata(azimuthal_field, polar_field, title='Peak Angles'))
        except NeXusError as error:
            report_error('Plotting Lattice', error)

    def plot_rings(self, polar_max=None):
        if polar_max is None:
            polar_max = self.refine.polar_max
        peaks = self.refine.calculate_rings(polar_max)
        plotview = get_plotview()
        plotview.vlines(peaks, colors='r', linestyles='dotted')
        plotview.draw()
    
    def plot_peak(self, i):
        x, y, z = self.refine.xp[i], self.refine.yp[i], self.refine.zp[i]/10.0
        xmin, xmax = max(0,int(x)-200), min(int(x)+200,data.v.shape[2])
        ymin, ymax = max(0,int(y)-200), min(int(y)+200,data.v.shape[1])
        zmin, zmax = max(0.0,z-20.0), min(z+20.0, 360.0)
        xslab=np.s_[zmin:zmax,ymin:ymax,x]
        yslab=np.s_[zmin:zmax,y,xmin:xmax]
        zslab=np.s_[z,ymin:ymax,xmin:xmax]
        pvz.plot(data[zslab], log=True)
        pvz.crosshairs(x, y)
        pvy.plot(data[yslab], log=True)
        pvy.crosshairs(x, z)
        pvx.plot(data[xslab], log=True)
        pvx.crosshairs(y, z)

    def refine_angles(self):
        self.parameters['orientation_matrix'].vary = False
        self.parameters['phi_start'].vary = False
        self.parameters['chi_start'].vary = False
        self.parameters['omega_start'].vary = False
        self.parameters.refine_parameters(self.angle_residuals)
        self.update_parameters()

    def angle_residuals(self, p):
        self.parameters.get_parameters(p)
        self.transfer_parameters()
        polar_angles, _ = self.refine.calculate_angles(self.refine.x, self.refine.y)
        rings = self.refine.calculate_rings()
        residuals = np.array([find_nearest(rings, polar_angle) - polar_angle 
                              for polar_angle in polar_angles])
        return np.sum(residuals**2)

    def refine_hkls(self):
        self.parameters.refine_parameters(self.hkl_residuals)
        self.update_parameters()
        if self.peaks_box is None:
            self.list_peaks()
        else:
            self.update_table()

    def hkl_residuals(self, p):
        self.parameters.get_parameters(p)
        self.transfer_parameters()
        return self.refine.score(self.refine.idx)

    def restore_parameters(self):
        self.parameters.restore_parameters()
        self.transfer_parameters()

    def reset_parameters(self):
        self.refine.read_parameters()
        self.update_parameters()

    def list_peaks(self):
        if self.peaks_box is not None:
            self.update_table()
            return
        self.peaks_box = BaseDialog(self)
        self.peaks_box.setMinimumWidth(600)
        self.peaks_box.setMinimumHeight(600)
        header = ['i', 'x', 'y', 'z', 'Polar', 'Azi', 'Intensity',
                  'H', 'K', 'L', 'Diff']
        peak_list = self.refine.get_peaks()
        self.refine.assign_rings()
        self.rings = self.refine.get_ring_hkls()
        orient_layout = QtGui.QHBoxLayout()
        if self.refine.primary is None:
            self.refine.primary = 0
        if self.refine.secondary is None:
            self.refine.secondary = 1
        self.primary_box = QtGui.QLineEdit(str(self.refine.primary))
        self.primary_box.setAlignment(QtCore.Qt.AlignRight)
        self.primary_box.setFixedWidth(80)
        self.secondary_box = QtGui.QLineEdit(str(self.refine.secondary))
        self.secondary_box.setAlignment(QtCore.Qt.AlignRight)
        self.secondary_box.setFixedWidth(80)
        orient_button = QtGui.QPushButton('Orient')
        orient_button.clicked.connect(self.orient)

        orient_layout.addStretch()
        orient_layout.addWidget(QtGui.QLabel('Primary'))
        orient_layout.addWidget(self.primary_box)
        orient_layout.addWidget(QtGui.QLabel('Secondary'))
        orient_layout.addWidget(self.secondary_box)
        orient_layout.addStretch()
        orient_layout.addWidget(orient_button)     
 
        self.table_view = QtGui.QTableView()
        self.table_model = NXTableModel(self, peak_list, header)
        self.table_view.setModel(self.table_model)
        self.table_view.resizeColumnsToContents()
        self.table_view.horizontalHeader().stretchLastSection()
        self.table_view.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows)
        self.table_view.doubleClicked.connect(self.plot_peak)
        self.table_view.setSortingEnabled(True)
        self.table_view.sortByColumn(0, QtCore.Qt.AscendingOrder)
        layout = QtGui.QVBoxLayout()
        layout.addLayout(orient_layout)
        layout.addWidget(self.table_view)
        close_layout = QtGui.QHBoxLayout()
        self.status_text = QtGui.QLabel('Score: %.4f' % self.refine.score())
        self.tolerance_box = QtGui.QLineEdit(str(self.refine.hkl_tolerance))
        self.tolerance_box.setAlignment(QtCore.Qt.AlignRight)
        self.tolerance_box.setMaxLength(5)
        self.tolerance_box.editingFinished.connect(self.update_table)
        self.tolerance_box.setFixedWidth(80)
        save_button = QtGui.QPushButton('Save Orientation')
        save_button.clicked.connect(self.save_orientation)
        close_button = QtGui.QPushButton('Close Window')
        close_button.clicked.connect(self.close_peaks_box)
        close_layout.addWidget(self.status_text)
        close_layout.addStretch()
        close_layout.addWidget(QtGui.QLabel('Threshold'))
        close_layout.addWidget(self.tolerance_box)
        close_layout.addStretch()
        close_layout.addWidget(save_button)
        close_layout.addStretch()
        close_layout.addWidget(close_button)
        layout.addLayout(close_layout)
        self.peaks_box.setLayout(layout)
        self.peaks_box.setWindowTitle('%s Peak Table' % self.entry.nxtitle)
        self.peaks_box.adjustSize()
        self.peaks_box.show()
        self.plotview = None

    def update_table(self):
        self.transfer_parameters()
        self.refine.hkl_tolerance = self.get_hkl_tolerance()
        self.table_model.peak_list = self.refine.get_peaks()
        rows, columns = len(self.table_model.peak_list), 11
        self.table_model.dataChanged.emit(self.table_model.createIndex(0, 0),
                                          self.table_model.createIndex(rows-1, columns-1))
        self.status_text.setText('Score: %.4f' % self.refine.score())


    def plot_peak(self):
        row = self.table_view.currentIndex().row()
        data = self.entry.data
        x, y, z = [self.table_view.model().peak_list[row][i] for i in range(1, 4)]
        xmin, xmax = max(0,x-200), min(x+200,data.nxsignal.shape[2])
        ymin, ymax = max(0,y-200), min(y+200,data.nxsignal.shape[1])
        zmin, zmax = max(0,z-200), min(z+200,data.nxsignal.shape[0])
        zslab=np.s_[z,ymin:ymax,xmin:xmax]
        if self.plotview is None:
            self.plotview = NXPlotView('X-Y Projection')
        self.plotview.plot(data[zslab], log=True)
        self.plotview.crosshairs(x, y)

    def orient(self):
        self.refine.primary = int(self.primary_box.text())
        self.refine.secondary = int(self.secondary_box.text())
        self.refine.Umat = self.refine.get_UBmat(self.refine.primary, 
                                                 self.refine.secondary) \
                           * self.refine.Bimat
        self.update_table()

    def save_orientation(self):
        self.write_parameters()

    def close_peaks_box(self):
        self.peaks_box.close()
        self.peaks_box = None
Exemplo n.º 39
0
class PrepareDialog(NXDialog):
    def __init__(self, parent=None):
        super().__init__(parent)

        self.select_entry(self.choose_entry)

        default = NXSettings().settings['nxreduce']
        self.parameters = GridParameters()
        self.parameters.add('first', default['first'], 'First Frame')
        self.parameters.add('last', default['last'], 'Last Frame')
        self.parameters.add('threshold1', '2', 'Threshold 1')
        self.parameters.add('horizontal1', '11', 'Horizontal Size 1')
        self.parameters.add('threshold2', '0.8', 'Threshold 2')
        self.parameters.add('horizontal2', '51', 'Horizontal Size 2')
        self.parameters.grid()
        self.prepare_button = NXPushButton('Prepare Mask', self.prepare_mask)
        self.plot_button = NXPushButton('Plot Mask', self.plot_mask)
        self.prepare_layout = self.make_layout(self.prepare_button,
                                               self.plot_button,
                                               align='center')
        self.plot_button.setVisible(False)
        self.set_layout(self.entry_layout,
                        self.close_layout(save=True, progress=True))
        self.set_title('Prepare 3D Mask')
        self.reduce = None
        self.mask = None
        self.plotview = None

    def choose_entry(self):
        if self.layout.count() == 2:
            self.insert_layout(1, self.parameters.grid_layout)
            self.insert_layout(2, self.prepare_layout)
        self.reduce = NXReduce(self.entry)
        self.parameters['first'].value = self.reduce.first
        self.parameters['last'].value = self.reduce.last

    @property
    def first(self):
        try:
            return int(self.parameters['first'].value)
        except Exception as error:
            report_error("Preparing Mask", error)

    @property
    def last(self):
        try:
            return int(self.parameters['last'].value)
        except Exception as error:
            report_error("Preparing Mask", error)

    @property
    def threshold1(self):
        try:
            return float(self.parameters['threshold1'].value)
        except Exception as error:
            report_error("Preparing Mask", error)

    @property
    def horizontal1(self):
        try:
            return int(self.parameters['horizontal1'].value)
        except Exception as error:
            report_error("Preparing Mask", error)

    @property
    def threshold2(self):
        try:
            return float(self.parameters['threshold2'].value)
        except Exception as error:
            report_error("Preparing Mask", error)

    @property
    def horizontal2(self):
        try:
            return int(self.parameters['horizontal2'].value)
        except Exception as error:
            report_error("Preparing Mask", error)

    def prepare_mask(self):
        if is_file_locked(self.reduce.data_file):
            return
        self.start_thread()
        self.reduce = NXReduce(self.entry,
                               prepare=True,
                               first=self.first,
                               last=self.last,
                               overwrite=True,
                               gui=True)
        self.reduce.mask_parameters['threshold_1'] = self.threshold1
        self.reduce.mask_parameters['threshold_1'] = self.threshold1
        self.reduce.mask_parameters['horizontal_size_1'] = self.horizontal1
        self.reduce.mask_parameters['threshold_2'] = self.threshold2
        self.reduce.mask_parameters['horizontal_size_2'] = self.horizontal2
        self.reduce.moveToThread(self.thread)
        self.reduce.start.connect(self.start_progress)
        self.reduce.update.connect(self.update_progress)
        self.reduce.result.connect(self.get_mask)
        self.reduce.stop.connect(self.stop)
        self.thread.started.connect(self.reduce.nxprepare)
        self.thread.start()

    def get_mask(self, mask):
        self.mask = mask
        self.status_message.setText("Mask complete")
        self.status_message.setVisible(True)
        self.plot_button.setVisible(True)

    def plot_mask(self):
        self.plotview = NXPlotView('3D Mask')
        self.plotview.plot(
            NXdata(self.mask,
                   self.reduce.data.nxaxes,
                   title=f"3D Mask: {self.reduce.name}"))

    def stop(self):
        self.stop_progress()
        if self.thread and self.thread.isRunning():
            self.reduce.stopped = True
        self.stop_thread()

    def accept(self):
        try:
            if self.mask is None:
                raise NeXusError("No mask has been created")
            elif self.entry.nxfilemode == 'r':
                raise NeXusError("NeXus file opened as readonly")
            self.reduce.write_mask(self.mask)
            self.reduce.record('nxprepare',
                               masked_file=self.reduce.mask_file,
                               threshold1=self.threshold1,
                               horizontal1=self.horizontal1,
                               threshold2=self.threshold2,
                               horizontal2=self.horizontal2,
                               process='nxprepare_mask')
            self.reduce.record_end('nxprepare')
            super().accept()
        except Exception as error:
            report_error("Preparing Mask", error)

    def reject(self):
        self.stop()
        super().reject()
Exemplo n.º 40
0
class ConvertDialog(NXDialog):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.select_entry()
        self.parameters = GridParameters()
        self.parameters.add('Ei',
                            self.entry['instrument/monochromator/energy'],
                            'Incident Energy')
        self.parameters.add('dQ', self.round(np.sqrt(self.Ei / 2) / 50),
                            'Q Step')
        self.parameters.add('dE', self.round(self.Ei / 50), 'Energy Step')
        self.set_layout(
            self.entry_layout, self.parameters.grid(),
            self.action_buttons(
                ('Plot', self.plot_data), ('Save', self.save_data)),
            self.close_buttons())
        self.setWindowTitle('Converting to (Q,E)')

    @property
    def Ei(self):
        return self.parameters['Ei'].value

    @property
    def dQ(self):
        return self.parameters['dQ'].value

    @property
    def dE(self):
        return self.parameters['dE'].value

    def read_parameters(self):
        self.L1 = -self.entry['sample/distance']
        self.L2 = np.mean(self.entry['instrument/detector/distance'])
        self.m1 = self.entry['monitor1']
        self.t_m1 = self.m1.moment()
        self.d_m1 = self.entry['monitor1/distance']

    def convert_tof(self, tof):
        ki = np.sqrt(self.Ei / 2.0721)
        ts = self.t_m1 + 1588.254 * (self.L1 - self.d_m1) / ki
        kf = 1588.254 * self.L2 / (tof - ts)
        eps = self.Ei - 2.0721 * kf**2
        return eps

    def convert_QE(self):
        """Convert S(phi,eps) to S(Q,eps)"""

        self.read_parameters()

        Ei = self.Ei
        dQ = self.dQ
        dE = self.dE

        signal = self.entry['data'].nxsignal
        pol = centers(self.entry['data/polar_angle'], signal.shape[0])
        tof = centers(self.entry['data/time_of_flight'], signal.shape[1])
        en = self.convert_tof(tof)

        idx_max = min(np.where(np.abs(en - 0.75 * Ei) < 0.1)[0])

        en = en[:idx_max]

        data = signal.nxdata[:, :idx_max]
        if self.entry['data'].nxerrors:
            errors = self.entry['data'].nxerrors.nxdata[:]

        Q = np.zeros((len(pol), len(en)))
        E = np.zeros((len(pol), len(en)))

        for i in range(0, len(pol)):
            p = pol[i]
            Q[i, :] = np.array(
                np.sqrt(
                    (2 * Ei - en -
                     2 * np.sqrt(Ei * (Ei - en)) * np.cos(p * np.pi / 180.0)) /
                    2.0721))
            E[i, :] = np.array(en)

        s = Q.shape
        Qin = Q.reshape(s[0] * s[1])
        Ein = E.reshape(s[0] * s[1])
        datain = data.reshape(s[0] * s[1])
        if self.entry['data'].nxerrors:
            errorsin = errors.reshape(s[0] * s[1])

        qmin = Q.min()
        qmax = Q.max()
        emin = E.min()
        emax = E.max()
        NQ = int((qmax - qmin) / dQ) + 1
        NE = int((emax - emin) / dE) + 1
        Qb = np.linspace(qmin, qmax, NQ)
        Eb = np.linspace(emin, emax, NE)
        # histogram and normalize
        norm, nbin = np.histogramdd((Ein, Qin), bins=(Eb, Qb))
        hist, hbin = np.histogramdd((Ein, Qin), bins=(Eb, Qb), weights=datain)
        if self.entry['data'].nxerrors:
            histe, hbin = np.histogramdd((Ein, Qin),
                                         bins=(Eb, Qb),
                                         weights=errorsin * errorsin)
            histe = histe**0.5
            err = histe / norm

        Ib = NXfield(hist / norm, name='S(Q,E)')

        Qb = NXfield(Qb[:-1] + dQ / 2., name='Q')
        Eb = NXfield(Eb[:-1] + dE / 2., name='E')

        result = NXdata(Ib, (Eb, Qb))
        if self.entry.data.nxerrors:
            result.errors = NXfield(err)
        return result

    def round(self, x, prec=2, base=.05):
        return round(base * round(float(x) / base), prec)

    def plot_data(self):
        self.convert_QE().plot()

    def save_data(self):
        self.entry['sqe'] = self.convert_QE()
Exemplo n.º 41
0
class ExperimentDialog(BaseDialog):

    def __init__(self, parent=None):
        super(ExperimentDialog, self).__init__(parent)

        self.experiment_file = NXroot()
        self.experiment_file['entry'] = NXentry()

        self.detectors = {}
        self.entries = {}

        self.setup_instrument()

        self.set_layout(self.directorybox('Choose Experiment Directory', default=False), 
                        self.instrument.grid(header=False))
        self.set_title('New Experiment')

    def setup_instrument(self):
        entry = self.experiment_file['entry']
        entry.instrument = NXinstrument()
        entry.instrument.monochromator = NXmonochromator()
        entry.instrument.detector = NXdetector()
        entry['instrument/monochromator/wavelength'] = NXfield(0.5, dtype=np.float32)
        entry['instrument/monochromator/wavelength'].attrs['units'] = 'Angstroms'
        entry['instrument/monochromator/energy'] = NXfield(12.398419739640717/0.5, dtype=np.float32)
        entry['instrument/monochromator/energy'].attrs['units'] = 'keV'
        entry['instrument/detector/distance'] = NXfield(100.0, dtype=np.float32)
        entry['instrument/detector/distance'].attrs['units'] = 'mm'
        self.instrument = GridParameters()
        self.instrument.add('experiment', 'experiment', 'Experiment Name')
        self.instrument.add('wavelength', entry['instrument/monochromator/wavelength'], 'Wavelength (Ang)')
        self.instrument.add('distance', entry['instrument/detector/distance'], 'Detector Distance (mm)')
        detector_list = sorted(list(set([detector().name for detector in ALL_DETECTORS.values()])))
        self.instrument.add('detector', detector_list, 'Detector')
        self.instrument['detector'].value = 'Pilatus CdTe 2M'
        self.instrument.add('positions', [0,1,2,3,4], 'Number of Detector Positions', slot=self.set_entries)
        self.instrument['positions'].value = '0'

    def setup_entry(self, position):
        entry = NXentry()
        self.detectors[position] = GridParameters()
        self.detectors[position].add('x', 0.0, 'Translation - x (mm)')
        self.detectors[position].add('y', 0.0, 'Translation - y (mm)')
        self.experiment_file['f%s' % position] = entry

    def get_detector(self):
        for detector in ALL_DETECTORS:
            if ALL_DETECTORS[detector]().name == self.instrument['detector'].value:
                return ALL_DETECTORS[detector]()

    @property
    def positions(self):
        return int(self.instrument['positions'].value)
 
    def set_entries(self):
        for position in range(1,self.positions+1):
            self.setup_entry(position)
            self.layout.addLayout(self.detectors[position].grid(header=False, title='Position %s'%position))
        self.layout.addWidget(self.close_buttons(save=True))

    def get_parameters(self):
        entry = self.experiment_file['entry']
        entry['instrument/monochromator/wavelength'] = self.instrument['wavelength'].value
        entry['instrument/monochromator/energy'] = 12.398419739640717 /  self.instrument['wavelength'].value
        detector = self.get_detector()
        entry['instrument/detector/description'] = detector.name
        entry['instrument/detector/distance'] = self.instrument['distance'].value
        entry['instrument/detector/pixel_size'] = detector.pixel1 * 1000
        entry['instrument/detector/pixel_size'].attrs['units'] = 'mm'
        entry['instrument/detector/pixel_mask'] = detector.mask
        entry['instrument/detector/shape'] = detector.shape
        entry['instrument/detector/yaw'] = 0.0
        entry['instrument/detector/pitch'] = 0.0
        entry['instrument/detector/roll'] = 0.0
        for position in range(1, self.positions+1):
            entry = self.experiment_file['f%s' % position]
            entry['instrument'] = self.experiment_file['entry/instrument']
            entry['instrument/detector/translation_x'] = self.detectors[position]['x'].value
            entry['instrument/detector/translation_x'].attrs['units'] = 'mm'
            entry['instrument/detector/translation_y'] = self.detectors[position]['y'].value
            entry['instrument/detector/translation_y'].attrs['units'] = 'mm'
            entry['instrument/detector/frame_time'] = 0.1
            entry['instrument/detector/frame_time'].attrs['units'] = 'seconds'

    def accept(self):
        try:
            home_directory = self.get_directory()
            self.mainwindow.default_directory = home_directory
            self.get_parameters()
            configuration_directory = os.path.join(home_directory, 'configurations')
            if not os.path.exists(configuration_directory):
                os.makedirs(configuration_directory)
            self.experiment_file.save(os.path.join(configuration_directory,
                                                   self.instrument['experiment'].value+'.nxs'))
            task_directory = os.path.join(home_directory, 'tasks')
            if not os.path.exists(task_directory):
                os.makedirs(task_directory)
            calibration_directory = os.path.join(home_directory, 'calibrations')
            if not os.path.exists(calibration_directory):
                os.makedirs(calibration_directory)
            self.treeview.tree.load(self.experiment_file.nxfilename, 'rw')
            super(ExperimentDialog, self).accept()
        except Exception as error:
            report_error("Defining New Experiment", error)
Exemplo n.º 42
0
class LatticeDialog(BaseDialog):

    def __init__(self, parent=None):
        super(LatticeDialog, self).__init__(parent)

        self.select_entry(self.choose_entry)

        self.refine = NXRefine()

        self.parameters = GridParameters()
        self.parameters.add('symmetry', self.refine.symmetries, 'Symmetry',
                            slot=self.set_lattice_parameters)
        self.parameters.add('centring', self.refine.centrings, 'Cell Centring')
        self.parameters.add('a', self.refine.a, 'Unit Cell - a (Ang)',
                            slot=self.set_lattice_parameters)
        self.parameters.add('b', self.refine.b, 'Unit Cell - b (Ang)',
                            slot=self.set_lattice_parameters)
        self.parameters.add('c', self.refine.c, 'Unit Cell - c (Ang)',
                            slot=self.set_lattice_parameters)
        self.parameters.add('alpha', self.refine.alpha, 'Unit Cell - alpha (deg)', 
                            slot=self.set_lattice_parameters)
        self.parameters.add('beta', self.refine.beta, 'Unit Cell - beta (deg)',
                            slot=self.set_lattice_parameters)
        self.parameters.add('gamma', self.refine.gamma, 'Unit Cell - gamma (deg)', 
                            slot=self.set_lattice_parameters)
        self.parameters['symmetry'].value = self.refine.symmetry
        self.parameters['centring'].value = self.refine.centring
        action_buttons = self.action_buttons(('Plot', self.plot_lattice),
                                             ('Save', self.write_parameters))
        self.set_layout(self.entry_layout, self.parameters.grid(), 
                        action_buttons, self.close_buttons())
        self.set_title('Defining Lattice')

    def choose_entry(self):
        self.refine = NXRefine(self.entry)
        self.update_parameters()

    def update_parameters(self):
        self.parameters['symmetry'].value = self.refine.symmetry
        self.parameters['centring'].value = self.refine.centring
        self.parameters['a'].value = self.refine.a
        self.parameters['b'].value = self.refine.b
        self.parameters['c'].value = self.refine.c
        self.parameters['alpha'].value = self.refine.alpha
        self.parameters['beta'].value = self.refine.beta
        self.parameters['gamma'].value = self.refine.gamma

    def get_symmetry(self):
        return self.parameters['symmetry'].value

    def get_centring(self):
        return self.parameters['centring'].value

    def get_lattice_parameters(self):
        return (self.parameters['a'].value,
                self.parameters['b'].value,
                self.parameters['c'].value,
                self.parameters['alpha'].value,
                self.parameters['beta'].value,
                self.parameters['gamma'].value)

    def set_lattice_parameters(self):
        symmetry = self.get_symmetry()
        if symmetry == 'cubic':
            self.parameters['b'].value = self.parameters['a'].value
            self.parameters['c'].value = self.parameters['a'].value
            self.parameters['alpha'].value = 90.0
            self.parameters['beta'].value = 90.0
            self.parameters['gamma'].value = 90.0
        elif symmetry == 'tetragonal':
            self.parameters['b'].value = self.parameters['a'].value
            self.parameters['alpha'].value = 90.0
            self.parameters['beta'].value = 90.0
            self.parameters['gamma'].value = 90.0
        elif symmetry == 'orthorhombic':
            self.parameters['alpha'].value = 90.0
            self.parameters['beta'].value = 90.0
            self.parameters['gamma'].value = 90.0
        elif symmetry == 'hexagonal':
            self.parameters['b'].value = self.parameters['a'].value
            self.parameters['alpha'].value = 90.0
            self.parameters['beta'].value = 90.0
            self.parameters['gamma'].value = 120.0
        elif symmetry == 'monoclinic':
            self.parameters['alpha'].value = 90.0
            self.parameters['gamma'].value = 90.0

    def get_parameters(self):
        (self.refine.a, self.refine.b, self.refine.c, 
         self.refine.alpha, self.refine.beta, self.refine.gamma) = (
            self.get_lattice_parameters())
        self.refine.symmetry = self.get_symmetry()
        self.refine.centring = self.get_centring()

    def plot_lattice(self):
        try:
            self.get_parameters()
            self.plot_peaks(self.refine.xp, self.refine.yp)
            polar_min, polar_max = plotview.xaxis.get_limits()
            self.plot_rings(polar_max)
        except NeXusError as error:
            report_error('Plotting Lattice', error)

    def write_parameters(self):
        try:
            self.get_parameters()
            self.refine.write_parameters()
        except NeXusError as error:
            report_error('Defining Lattice', error)

    def plot_peaks(self, x, y):
        try:
            polar_angles, azimuthal_angles = self.refine.calculate_angles(x, y)
            if polar_angles[0] > polar_angles[-1]:
                polar_angles = polar_angles[::-1]
                azimuthal_angles = azimuthal_angles[::-1]
            azimuthal_field = NXfield(azimuthal_angles, name='azimuthal_angle')
            azimuthal_field.long_name = 'Azimuthal Angle'
            polar_field = NXfield(polar_angles, name='polar_angle')
            polar_field.long_name = 'Polar Angle'
            plotview = get_plotview()
            plotview.plot(NXdata(azimuthal_field, polar_field, title='Peak Angles'))
        except NeXusError as error:
            report_error('Plotting Lattice', error)

    def plot_rings(self, polar_max=None):
        if polar_max is None:
            polar_max = self.refine.polar_max
        peaks = self.refine.calculate_rings(polar_max)
        plotview = get_plotview()
        plotview.vlines(peaks, colors='r', linestyles='dotted')
        plotview.draw()
Exemplo n.º 43
0
class FindDialog(BaseDialog):
    def __init__(self, parent=None):
        super(FindDialog, self).__init__(parent)

        self.select_entry(self.choose_entry)

        try:
            threshold = np.float32(self.entry.data.attrs["maximum"]) / 20
            max_frame = np.int32(len(self.entry.data.nxaxes[0]))
        except Exception:
            threshold = 5000
            max_frame = 0

        self.parameters = GridParameters()
        self.parameters.add("threshold", threshold, "Threshold")
        self.parameters.add("min", 0, "First Frame")
        self.parameters.add("max", max_frame, "Last Frame")
        self.parameters.add("pixel_tolerance", 50, "Pixel Tolerance")
        self.parameters.add("frame_tolerance", 10, "Frame Tolerance")
        find_layout = QtGui.QHBoxLayout()
        self.find_button = QtGui.QPushButton("Find Peaks")
        self.find_button.clicked.connect(self.find_peaks)
        self.peak_count = QtGui.QLabel()
        self.peak_count.setVisible(False)
        find_layout.addStretch()
        find_layout.addWidget(self.find_button)
        find_layout.addWidget(self.peak_count)
        find_layout.addStretch()
        self.set_layout(self.entry_layout, self.parameters.grid(), find_layout)
        self.set_title("Find Peaks")

        self.npk = 0
        try:
            self.parameters["max"].value = self.entry["data"].nxsignal.shape[0]
            self.parameters["threshold"].value = self.entry["data"].attrs["maximum"] / 20
        except Exception:
            pass

    def choose_entry(self):
        try:
            self.parameters["threshold"].value = self.entry["data"].attrs["maximum"] / 20
            self.parameters["max"].value = len(self.entry.data.nxaxes[0])
        except Exception:
            pass

    def get_threshold(self):
        return self.parameters["threshold"].value

    def get_limits(self):
        return np.int32(self.parameters["min"].value), np.int32(self.parameters["max"].value)

    def get_tolerance(self):
        """
        Return pixel and frame tolerances from the text boxes.
        
        Note that the pixel tolerance is squared to save square-root 
        calculations in peak comparisons.
        """
        return (self.parameters["pixel_tolerance"].value, self.parameters["frame_tolerance"].value)

    def find_peaks(self):

        field = self.entry["data"].nxsignal
        try:
            self.mask = self.entry["instrument/detector/pixel_mask"]
        except NeXusError:
            self.mask = None

        self.layout.removeWidget(self.find_button)
        self.find_button.setVisible(False)
        if len(field.shape) == 2:
            self.layout.addWidget(self.close_buttons(save=True))
        elif len(field.shape) > 2:
            self.layout.addLayout(self.progress_layout(save=True))

        threshold = self.get_threshold()
        self.blim = np.zeros(field.shape[-2:], np.int32)
        self.verbose = 0

        lio = labelimage(field.shape[-2:], flipper=flip1)
        allpeaks = []
        if len(field.shape) == 2:
            res = None
        else:
            chunk_size = field.nxfile[field.nxpath].chunks[0]
            z_min, z_max = self.get_limits()
            pixel_tolerance, frame_tolerance = self.get_tolerance()
            self.progress_bar.setRange(z_min, z_max)
            for i in range(0, field.shape[0], chunk_size):
                try:
                    if i + chunk_size > z_min and i < z_max:
                        self.progress_bar.setValue(i)
                        self.update_progress()
                        v = field[i : i + chunk_size, :, :].nxdata
                        for j in range(chunk_size):
                            if i + j >= z_min and i + j <= z_max:
                                omega = np.float32(i + j)
                                lio.peaksearch(v[j], threshold, omega)
                                if lio.res is not None:
                                    blob_moments(lio.res)
                                    for k in range(lio.res.shape[0]):
                                        res = lio.res[k]
                                        peak = NXpeak(
                                            res[0],
                                            res[22],
                                            res[23],
                                            res[24],
                                            omega,
                                            res[27],
                                            res[26],
                                            res[29],
                                            threshold,
                                            pixel_tolerance,
                                            frame_tolerance,
                                        )
                                        if peak.isvalid(self.mask):
                                            allpeaks.append(peak)
                except IndexError as error:
                    pass

        if not allpeaks:
            self.reject()
            report_error("Finding peaks", "No peaks found")
        allpeaks = sorted(allpeaks)

        self.progress_bar.reset()
        self.progress_bar.setRange(z_min, z_max)

        merged_peaks = []
        for z in range(z_min, z_max + 1):
            self.progress_bar.setValue(z)
            self.update_progress()
            frame = [peak for peak in allpeaks if peak.z == z]
            if not merged_peaks:
                merged_peaks.extend(frame)
            else:
                for peak1 in frame:
                    combined = False
                    for peak2 in last_frame:
                        if peak1 == peak2:
                            for idx in range(len(merged_peaks)):
                                if peak1 == merged_peaks[idx]:
                                    break
                            peak1.combine(merged_peaks[idx])
                            merged_peaks[idx] = peak1
                            combined = True
                            break
                    if not combined:
                        reversed_peaks = [p for p in reversed(merged_peaks) if p.z >= peak1.z - frame_tolerance]
                        for peak2 in reversed_peaks:
                            if peak1 == peak2:
                                for idx in range(len(merged_peaks)):
                                    if peak1 == merged_peaks[idx]:
                                        break
                                peak1.combine(merged_peaks[idx])
                                merged_peaks[idx] = peak1
                                combined = True
                                break
                        if not combined:
                            merged_peaks.append(peak1)

            if frame:
                last_frame = frame

        merged_peaks = sorted(merged_peaks)
        for peak in merged_peaks:
            peak.merge()

        merged_peaks = sorted(merged_peaks)
        self.peaks = merged_peaks

        self.progress_bar.setVisible(False)

        self.peak_count.setText("%s peaks found" % len(self.peaks))
        self.peak_count.setVisible(True)

    def accept(self):
        try:
            if "peaks" in self.entry.entries:
                del self.entry["peaks"]
            self.entry.peaks = NXdata()
            shape = (len(self.peaks),)
            self.entry.peaks.npixels = NXfield([peak.np for peak in self.peaks], dtype=np.float32)
            self.entry.peaks.intensity = NXfield([peak.intensity for peak in self.peaks], dtype=np.float32)
            self.entry.peaks.x = NXfield([peak.x for peak in self.peaks], dtype=np.float32)
            self.entry.peaks.y = NXfield([peak.y for peak in self.peaks], dtype=np.float32)
            self.entry.peaks.z = NXfield([peak.z for peak in self.peaks], dtype=np.float32)
            self.entry.peaks.sigx = NXfield([peak.sigx for peak in self.peaks], dtype=np.float32)
            self.entry.peaks.sigy = NXfield([peak.sigy for peak in self.peaks], dtype=np.float32)
            self.entry.peaks.covxy = NXfield([peak.covxy for peak in self.peaks], dtype=np.float32)
            super(FindDialog, self).accept()
        except NeXusError as error:
            report_error("Finding peaks", error)