Esempio n. 1
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
Esempio n. 2
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()
Esempio n. 3
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)
Esempio n. 4
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
Esempio n. 5
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)
Esempio n. 6
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()