Пример #1
0
def plot_avg_xas_single(bin_xas, detector):

    plotview = NXPlotView()

    if detector == "I0":
        y_array = bin_xas.i0
    elif detector == "TEY":
        y_array = bin_xas.tey
    elif detector == "DIODE" or detector == "PD1":
        y_array = bin_xas.diode
    elif detector == "PFY_SDD1":
        y_array = bin_xas.pfy_sdd1
    elif detector == "PFY_SDD2":
        y_array = bin_xas.pfy_sdd2
    elif detector == "PFY_SDD3":
        y_array = bin_xas.pfy_sdd3
    elif detector == "PFY_SDD4":
        y_array = bin_xas.pfy_sdd4
    else:
        return "Invalid dividend name"

    plotview.figure.clf()
    ax = plotview.figure.gca()
    ax.axes.get_xaxis().set_visible(True)
    ax.axes.get_yaxis().set_visible(True)

    ax.plot(bin_xas.energy, y_array)
    ax.set_xlabel('Energy (eV)')
    ax.set_ylabel(detector)
    plotview.draw()
Пример #2
0
 def plot_data(self):
     if self.plotview is None:
         if 'Powder Calibration' in plotviews:
             self.plotview = plotviews['Powder Calibration']
         else:
             self.plotview = NXPlotView('Powder Calibration')
     self.plotview.plot(self.data, log=True)
     self.plotview.aspect = 'equal'
     self.plotview.ytab.flipped = True
     self.clear_peaks()
Пример #3
0
 def load_file(self):
     self.data = load_image(self.get_filename())
     if self.plotview is None:
         if 'Powder Calibration' in plotviews:
             self.plotview = plotviews['Powder Calibration']
         else:
             self.plotview = NXPlotView('Powder Calibration')
     self.plotview.plot(self.data, log=True)
     self.plotview.aspect = 'equal'
     self.plotview.ytab.flipped = True
Пример #4
0
 def plot_data(self):
     if self.plotview is None:
         if 'Mask Editor' in plotviews:
             self.plotview = plotviews['Mask Editor']
         else:
             self.plotview = NXPlotView('Mask Editor')
     self.plotview.plot(self.data, log=True)
     self.plotview.aspect='equal'
     self.plotview.ytab.flipped = True
     self.plotview.draw()
Пример #5
0
 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)
Пример #6
0
 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)
Пример #7
0
 def load_file(self):
     self.data = load_image(self.get_filename())
     if self.plotview is None:
         if 'Powder Calibration' in plotviews:
             self.plotview = plotviews['Powder Calibration']
         else:
             self.plotview = NXPlotView('Powder Calibration')
     self.plotview.plot(self.data, log=True)
     self.plotview.aspect='equal'
     self.plotview.ytab.flipped = True         
Пример #8
0
 def plot_data(self):
     if self.plotview is None:
         if 'Powder Calibration' in plotviews:
             self.plotview = plotviews['Powder Calibration']
         else:
             self.plotview = NXPlotView('Powder Calibration')
     self.plotview.plot(self.data, log=True)
     self.plotview.aspect='equal'
     self.plotview.ytab.flipped = True
     self.clear_peaks()
Пример #9
0
 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)
Пример #10
0
 def plot_cake(self):
     if 'Cake Plot' in plotviews:
         plotview = plotviews['Cake Plot']
     else:
         plotview = NXPlotView('Cake Plot')
     if not self.is_calibrated:
         raise NeXusError('No refinement performed')
     res = self.cake_geometry.integrate2d(self.counts,
                                          1024,
                                          1024,
                                          method='csr',
                                          unit='2th_deg',
                                          correctSolidAngle=True)
     self.cake_data = NXdata(res[0],
                             (NXfield(res[2], name='azimumthal_angle'),
                              NXfield(res[1], name='polar_angle')))
     self.cake_data['title'] = self.entry['instrument/calibration/title']
     plotview.plot(self.cake_data, log=True)
     wavelength = self.parameters['wavelength'].value
     polar_angles = [
         2 * np.degrees(np.arcsin(wavelength / (2 * d)))
         for d in self.calibrant.dSpacing
     ]
     plotview.vlines([
         polar_angle
         for polar_angle in polar_angles if polar_angle < plotview.xaxis.max
     ],
                     linestyle=':',
                     color='r')
Пример #11
0
def eem(multi_xas, name):
    start_time = time.time()

    # matplotlib.rcParams['figure.figsize'] = (14, 10)

    name = name.upper()
    if name == "SDD1":
        intensity = multi_xas.sdd1
        # intensity = np.array(intensity)
    elif name == "SDD2":
        intensity = multi_xas.sdd2
        # intensity = np.array(intensity)
    elif name == "SDD3":
        intensity = multi_xas.sdd3
        # intensity = np.array(intensity)
    elif name == "SDD4":
        intensity = multi_xas.sdd4
        # intensity = np.array(intensity)
    else:
        return "Invalid name for the intensity of EEM"

    energy_array = np.array(multi_xas.energy)
    num_of_points = len(energy_array)
    num_of_emission_bins = len(intensity[0])

    bin_num_for_x = np.zeros(shape=(num_of_points, num_of_emission_bins))
    for i in range(num_of_points):
        bin_num_for_x[i].fill(energy_array[i])

    bin_num_for_y = np.zeros(shape=(num_of_points, num_of_emission_bins))
    bin_num_for_y[0:] = np.arange(10, (num_of_emission_bins + 1) * 10, 10)

    v_max = max(intensity[0])
    for i in range(1, num_of_points):
        temp_max = max(intensity[i])
        if temp_max > v_max:
            v_max = temp_max
    # print ("v_max: ", v_max)

    intensity = np.array(intensity)
    plotview = NXPlotView()
    plotview.figure.clf()
    ax = plotview.figure.gca()
    ax.axes.get_xaxis().set_visible(True)
    ax.axes.get_yaxis().set_visible(True)
    # print("--- %s seconds ---" % (time.time() - start_time))
    ax.scatter(bin_num_for_x,
               bin_num_for_y,
               c=intensity,
               s=7,
               linewidths=0,
               vmax=v_max,
               vmin=0)
    print("--- %s seconds ---" % (time.time() - start_time))
    ax.set_xlabel('Incident Energy (eV)')
    ax.set_ylabel('Emission Energy (eV)')
    ax.set_title("Excitation Emission Matrix")
    plotview.grid()
    plotview.draw()
    print("--- %s seconds ---" % (time.time() - start_time))
Пример #12
0
 def plot_cake(self):
     if 'Cake Plot' in plotviews:
         plotview = plotviews['Cake Plot']
     else:
         plotview = NXPlotView('Cake Plot')    
     if not self.is_calibrated:
         raise NeXusError('No refinement performed')
     res = self.cake_geometry.integrate2d(self.counts, 
                                          1024, 1024,
                                          method='csr',
                                          unit='2th_deg',
                                          correctSolidAngle=True)
     self.cake_data = NXdata(res[0], (NXfield(res[2], name='azimumthal_angle'),
                                      NXfield(res[1], name='polar_angle')))
     self.cake_data['title'] = self.entry['instrument/calibration/title']
     plotview.plot(self.cake_data, log=True)
     wavelength = self.parameters['wavelength'].value
     polar_angles = [2 * np.degrees(np.arcsin(wavelength/(2*d)))
                     for d in self.calibrant.dSpacing]
     plotview.vlines([polar_angle for polar_angle in polar_angles 
                      if polar_angle < plotview.xaxis.max], 
                     linestyle=':', color='r')
Пример #13
0
class LoadDialog(BaseDialog):
    def __init__(self, parent=None):
        super(LoadDialog, self).__init__(parent)

        self.plotview = None
        self.data = None

        self.set_layout(self.filebox('Choose Powder Calibration File'),
                        self.action_buttons(('Load File', self.load_file)),
                        self.select_entry(), self.close_buttons(save=True))
        self.set_title('Loading Calibration')

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

    def accept(self):
        if self.data is None:
            self.reject()
        else:
            if 'calibration' in self.entry['instrument']:
                if confirm_action(
                        "Do you want to overwrite existing calibration data?"):
                    del self.entry['instrument/calibration']
                else:
                    self.reject()
                    return
            self.entry['instrument/calibration'] = self.data
            super(LoadDialog, self).accept()
        if 'Powder Calibration' in plotviews and self.plotview == plotviews[
                'Powder Calibration']:
            self.plotview.close_view()

    def reject(self):
        super(LoadDialog, self).reject()
        if 'Powder Calibration' in plotviews and self.plotview == plotviews[
                'Powder Calibration']:
            self.plotview.close_view()
Пример #14
0
class LoadDialog(BaseDialog):

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

        self.plotview = None
        self.data = None

        self.set_layout(self.filebox('Choose Powder Calibration File'),
                        self.action_buttons(('Load File', self.load_file)),
                        self.select_entry(),
                        self.close_buttons(save=True))
        self.set_title('Loading Calibration')

    def load_file(self):
        self.data = load_image(self.get_filename())
        if self.plotview is None:
            if 'Powder Calibration' in plotviews:
                self.plotview = plotviews['Powder Calibration']
            else:
                self.plotview = NXPlotView('Powder Calibration')
        self.plotview.plot(self.data, log=True)
        self.plotview.aspect='equal'
        self.plotview.ytab.flipped = True         
        
    def accept(self):
        if self.data is None:
            self.reject()
        else:
            if 'calibration' in self.entry['instrument']:
                if confirm_action(
                        "Do you want to overwrite existing calibration data?"):
                    del self.entry['instrument/calibration']
                else:
                    self.reject()
                    return
            self.entry['instrument/calibration'] = self.data
            super(LoadDialog, self).accept()
        if 'Powder Calibration' in plotviews and self.plotview == plotviews['Powder Calibration']:
            self.plotview.close_view()

    def reject(self):
        super(LoadDialog, self).reject()
        if 'Powder Calibration' in plotviews and self.plotview == plotviews['Powder Calibration']:
            self.plotview.close_view()
Пример #15
0
def plot_normalized(xas, dividend, divisor):

    plotview = NXPlotView()

    # convert the string to uppercase
    dividend = dividend.upper()
    divisor = divisor.upper()

    if dividend == "I0":
        dividend_array = xas.i0
    elif dividend == "TEY":
        dividend_array = xas.tey
    elif dividend == "DIODE" or dividend == "PD1":
        dividend_array = xas.diode
    elif dividend == "PFY_SDD1":
        dividend_array = xas.pfy_sdd1
    elif dividend == "PFY_SDD2":
        dividend_array = xas.pfy_sdd2
    elif dividend == "PFY_SDD3":
        dividend_array = xas.pfy_sdd3
    elif dividend == "PFY_SDD4":
        dividend_array = xas.pfy_sdd4
    else:
        return "Invalid dividend name"

    if divisor == "I0":
        divisor_array = xas.i0
    elif divisor == "TEY":
        divisor_array = xas.tey
    elif divisor == "DIODE" or divisor == "PD1":
        divisor_array = xas.diode
    elif divisor == "PFY_SDD1":
        divisor_array = xas.pfy_sdd1
    elif divisor == "PFY_SDD2":
        divisor_array = xas.pfy_sdd2
    elif divisor == "PFY_SDD3":
        divisor_array = xas.pfy_sdd3
    elif divisor == "PFY_SDD4":
        divisor_array = xas.pfy_sdd4
    else:
        return "Invalid divisor name"

    normalized_array = np.array(dividend_array) / np.array(divisor_array)

    # the old code using Matplotlib to plot diagrams
    # plt.figure()
    # plt.plot(xas.energy, normalized_array)
    # str_y_axis = StringIO()
    # str_y_axis.write(dividend + ' / ' + divisor)
    # plt.ylabel(str_y_axis.getvalue())
    # plt.title("Averaged %s / Averaged %s" % (dividend, divisor))

    plotview.figure.clf()
    ax = plotview.figure.gca()
    ax.axes.get_xaxis().set_visible(True)
    ax.axes.get_yaxis().set_visible(True)

    ax.plot(xas.energy, normalized_array)
    ax.set_xlabel('Energy (eV)')
    str_y_axis = StringIO()
    str_y_axis.write(dividend + ' / ' + divisor)
    ax.set_ylabel(str_y_axis.getvalue())
    ax.set_title("Averaged %s / Averaged %s" % (dividend, divisor))

    plotview.draw()

    return xas.energy, normalized_array
Пример #16
0
def plot_avg_xas_all(bin_xas):
    """
    Generate all plots (matplotlib figures) for averaged data at once
    :return: None
    """
    print("Plotting average XAS.")
    # matplotlib.rcParams['figure.figsize'] = (14, 22)

    plotview = NXPlotView()

    plotview.setMinimumHeight(200)
    plotview.resize(1400, 800)
    plotview.figure.clf()

    en = bin_xas.energy
    i0 = bin_xas.i0
    tey = bin_xas.tey
    diode = bin_xas.diode
    pfy_sdd1 = bin_xas.pfy_sdd1
    pfy_sdd2 = bin_xas.pfy_sdd2
    pfy_sdd3 = bin_xas.pfy_sdd3
    pfy_sdd4 = bin_xas.pfy_sdd4

    plt.subplot(2, 4, 1)
    plt.plot(en, tey)
    # add lable for x and y axis
    plt.xlabel('Energy (eV)')
    plt.ylabel('TEY')
    # add title of the figure
    plt.title('Binned(Averaged) TEY')

    plt.subplot(2, 4, 2)
    plt.plot(en, i0)
    plt.xlabel('Energy (eV)')
    plt.ylabel('I0')
    plt.title('Binned(Averaged) I0')

    plt.subplot(2, 4, 3)
    plt.plot(en, diode)
    plt.xlabel('Energy (eV)')
    plt.ylabel('Diode')
    plt.title('Binned(Averaged) Diode')

    plt.subplot(2, 4, 5)
    plt.plot(en, pfy_sdd1)
    plt.xlabel('Energy (eV)')
    plt.ylabel('PFY_SDD1')
    plt.title('Binned(Averaged) PFY_SDD1')

    plt.subplot(2, 4, 6)
    plt.plot(en, pfy_sdd2)
    plt.xlabel('Energy (eV)')
    plt.ylabel('PFY_SDD2')
    plt.title('Binned(Averaged) PFY_SDD2')

    plt.subplot(2, 4, 7)
    plt.plot(en, pfy_sdd3)
    plt.xlabel('Energy (eV)')
    plt.ylabel('PFY_SDD3')
    plt.title('Binned(Averaged) PFY_SDD3')

    plt.subplot(2, 4, 8)
    plt.plot(en, pfy_sdd4)
    plt.xlabel('Energy (eV)')
    plt.ylabel('PFY_SDD4')
    plt.title('Binned(Averaged) PFY_SDD4')

    plt.tight_layout()
    # use plotview from Nexpy to generate plots
    plotview.figure = plt
    plotview.tab_widget.removeTab(0)
    plotview.tab_widget.removeTab(0)
    plotview.draw()
Пример #17
0
    def summary_plot(self, name):
        start_time = time.time()
        # matplotlib.rcParams['figure.figsize'] = (13, 10)

        # select intensity
        name = name.upper()
        if name == "TEY":
            intensity = self.tey
        elif name == "I0" or name == "IO":
            intensity = self.i0
        elif name == "DIODE" or name == "PD1":
            intensity = self.diode
        elif name == "PFY_SDD1":
            intensity = self.pfy_sdd1
        elif name == "PFY_SDD2":
            intensity = self.pfy_sdd2
        elif name == "PFY_SDD3":
            intensity = self.pfy_sdd3
        elif name == "PFY_SDD4":
            intensity = self.pfy_sdd4
        else:
            return "Invalid name for the intensity of summary plot"

        total_cscan_num = len(self.energy)
        # print (total_cscan_num)

        # show the plot in Nexpy, similar to figure.show()
        plotview = NXPlotView()

        # setup the size of figure and pop-up window
        plotview.setMinimumHeight(200)
        if total_cscan_num > 10:
            ratio = total_cscan_num / 10
        else:
            ratio = 1
        plotview.resize(700, 280 * ratio)
        plotview.figure.clf()

        # setup axis
        ax = plotview.figure.gca()
        ax.axes.get_xaxis().set_visible(True)
        ax.axes.get_yaxis().set_visible(True)

        print("--- %s seconds ---" % (time.time() - start_time))

        energy_tuple = np.array(self.energy[0][:])
        intensity_tuple = np.array(intensity[0][:])
        scan_num_tuple = np.zeros(len(self.energy[0]))
        scan_num_tuple.fill(1)

        # prepare data as tuples for x, y, and color of scatter plot
        for i in range(1, total_cscan_num):
            scan_num_list = np.zeros(len(self.energy[i]))
            scan_num_list.fill(i + 1)
            scan_num_tuple = np.concatenate([scan_num_tuple, scan_num_list])
            energy_tuple = np.concatenate(
                [energy_tuple, np.array(self.energy[i][:])])
            intensity_tuple = np.concatenate(
                [intensity_tuple, np.array(intensity[i][:])])
            # comment out the old way to generate scatter plot
            #plt.scatter(self.energy[i][:], scan_num_list, c=intensity[i][:], s=140, linewidths=0, marker='s')

        # print("--- %s seconds ---" % (time.time() - start_time))
        # main function call to generate color scatter plot
        ax.scatter(energy_tuple,
                   scan_num_tuple,
                   c=intensity_tuple,
                   s=140,
                   linewidths=0,
                   marker='s')
        # this locator puts ticks at regular intervals
        loc = plticker.MultipleLocator(base=1.0)
        # set regular ticks interval
        ax.yaxis.set_major_locator(loc)
        # set the limitation of y axis
        ax.set_ylim(ymin=0, ymax=total_cscan_num + 1)
        # manipulate the ytick labels
        t = np.arange(len(self.selected_scan_entry)) + 1.0
        ax.set_yticks(t)
        ax.set_yticklabels(self.selected_scan_entry)
        # add title of the figure
        ax.set_title("Summary Plot (Intensity: %s)" % (name))
        # add labels for x and y axis
        ax.set_xlabel('Incident Energy(eV)')
        ax.set_ylabel('Scan Entry')
        # set limit of y axis
        print("selected_scan_entry: ", self.selected_scan_entry)

        plotview.grid(True)
        plotview.draw()
        print("--- %s seconds ---" % (time.time() - start_time))
Пример #18
0
class MaskDialog(BaseDialog):

    def __init__(self, parent=None):
        super(MaskDialog, self).__init__(parent)
        
        self.plotview = None
        self.shapes = []
        
        self.select_entry(self.choose_entry)
        self.shape_box = self.select_box(['Rectangle', 'Circle'])
        self.set_layout(self.entry_layout, 
                        self.make_layout(
                            self.action_buttons(('Add Shape', self.add_shape)),
                            self.shape_box),
                        self.close_buttons(save=True))
        self.set_title('Mask Data')

    def choose_entry(self):
        if 'calibration' not in self.entry['instrument']:
            raise NeXusError('Please load calibration data to this entry')
        self.data = self.entry['instrument/calibration']
        self.counts = self.data.nxsignal.nxvalue
        self.mask = self.entry['instrument/detector/pixel_mask'].nxvalue
        self.plot_data()
        shape = self.data.nxsignal.shape

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

    def add_shape(self):
        self.plotview.deactivate()
        xlo, xhi = self.plotview.xaxis.lo, self.plotview.xaxis.hi
        ylo, yhi = self.plotview.yaxis.lo, self.plotview.yaxis.hi
        xc, yc = xlo + 0.5 * (xhi - xlo), ylo + 0.5 * (yhi - ylo)
        r = (xhi - xlo) / 4
        if self.shape_box.currentText() == 'Rectangle':
            self.shapes.append(NXrectangle(xc-r, yc-r, 2*r, 2*r,
                                           border_tol=0.1, plotview=self.plotview,
                                           facecolor='r', edgecolor='k',
                                           linewidth=1, alpha=0.3))
        else:
            self.shapes.append(NXcircle(xc, yc, r, border_tol=0.1, 
                                        plotview=self.plotview,
                                        facecolor='r', edgecolor='k',
                                        linewidth=1, alpha=0.3))
        self.plotview.draw()
        self.shapes[-1].connect()    

    def accept(self):
        x, y = np.arange(self.mask.shape[1]), np.arange(self.mask.shape[0])
        for shape in self.shapes:
            if isinstance(shape, NXrectangle):
                rect = shape.rectangle
                x0, y0 = int(rect.get_x()), int(rect.get_y())
                x1, y1 = int(x0+rect.get_width()), int(y0+rect.get_height())               
                self.mask[y0:y1,x0:x1] = 1
            else:
                circle = shape.circle
                xc, yc = circle.center
                r = circle.radius
                inside = (x[None,:]-int(xc))**2+(y[:,None]-int(yc))**2 < r**2
                self.mask = self.mask | inside
        self.mask[np.where(self.counts<0)] = 1
        self.entry['instrument/detector/pixel_mask'] = self.mask        
        super(MaskDialog, self).accept()
        if 'Mask Editor' in plotviews:
            plotviews['Mask Editor'].close_view()

    def reject(self):
        super(MaskDialog, self).reject()
        if 'Mask Editor' in plotviews:
            plotviews['Mask Editor'].close_view()
Пример #19
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
Пример #20
0
class CalibrateDialog(NXDialog):

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    def reject(self):
        super().reject()
        self.close_plots()
Пример #21
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)
Пример #22
0
class MaskDialog(NXDialog):
    def __init__(self, parent=None):
        super().__init__(parent)

        self.plotview = None
        self.shapes = []
        self.parameters = {}
        self.select_entry(self.choose_entry)
        self.shape_box = self.select_box(['Rectangle', 'Circle'])
        self.shape_choice = self.select_box([], slot=self.choose_shape)
        self.set_layout(
            self.entry_layout,
            self.make_layout(
                self.action_buttons(('Add Shape', self.add_shape)),
                self.shape_box), self.shape_choice,
            self.close_buttons(save=True))
        self.shape_choice.setVisible(False)
        self.set_title('Mask Data')

    def choose_entry(self):
        if 'calibration' not in self.entry['instrument']:
            raise NeXusError('Please load calibration data to this entry')
        self.data = self.entry['instrument/calibration']
        self.counts = self.data.nxsignal.nxvalue
        self.mask = self.entry['instrument/detector/pixel_mask'].nxvalue
        self.xc = self.entry['instrument/detector/beam_center_x'].nxvalue
        self.yc = self.entry['instrument/detector/beam_center_y'].nxvalue
        self.plot_data()
        shape = self.data.nxsignal.shape

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

    def add_shape(self):
        if self.shape_box.currentText() == 'Rectangle':
            self.shapes.append(
                NXrectangle(self.xc - 50,
                            self.yc - 50,
                            100,
                            100,
                            border_tol=0.1,
                            plotview=self.plotview,
                            resize=True,
                            facecolor='r',
                            edgecolor='k',
                            linewidth=1,
                            alpha=0.3))
        else:
            self.shapes.append(
                NXcircle(self.xc,
                         self.yc,
                         50,
                         border_tol=0.1,
                         plotview=self.plotview,
                         resize=True,
                         facecolor='r',
                         edgecolor='k',
                         linewidth=1,
                         alpha=0.3))
        self.plotview.draw()
        self.shapes[-1].connect()
        self.shape_choice.addItem(repr(self.shapes[-1]))
        self.shape_choice.setVisible(True)
        self.insert_layout(self.shape_options(self.shapes[-1]))

    def shape_options(self, shape):
        p = self.parameters[shape] = GridParameters()
        if isinstance(shape, NXrectangle):
            x, y = shape.xy
            w, h = shape.width, shape.height
            p.add('x', x, 'Left Pixel')
            p.add('y', y, 'Bottom Pixel')
            p.add('w', w, 'Width')
            p.add('h', h, 'Height')
        else:
            x, y = shape.center
            r = abs(shape.width) / 2
            p.add('x', x, 'X-Center')
            p.add('y', y, 'Y-Center')
            p.add('r', r, 'Radius')
        return p.grid(header=False)

    def choose_shape(self):
        pass

    def accept(self):
        x, y = np.arange(self.mask.shape[1]), np.arange(self.mask.shape[0])
        for shape in self.shapes:
            if isinstance(shape, NXrectangle):
                x0, y0 = shape.xy
                x1, y1 = x0 + shape.width, y0 + shape.height
                self.mask[int(y0):int(y1), int(x0):int(x1)] = 1
            else:
                xc, yc = shape.center
                r = shape.radius
                inside = (x[None, :] - int(xc))**2 + (y[:, None] -
                                                      int(yc))**2 < r**2
                self.mask = self.mask | inside
        self.mask[np.where(self.counts < 0)] = 1
        try:
            self.entry['instrument/detector/pixel_mask'] = self.mask
        except NeXusError as error:
            report_error("Creating Mask", error)
            return
        super().accept()
        if 'Mask Editor' in plotviews:
            plotviews['Mask Editor'].close_view()

    def reject(self):
        super().reject()
        if 'Mask Editor' in plotviews:
            plotviews['Mask Editor'].close_view()
Пример #23
0
class CalibrateDialog(BaseDialog):
    def __init__(self, parent=None):
        super(CalibrateDialog, self).__init__(parent)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    def reject(self):
        super(CalibrateDialog, self).reject()
        if 'Powder Calibration' in plotviews:
            plotviews['Powder Calibration'].close_view()
        if 'Cake Plot' in plotviews:
            plotviews['Cake Plot'].close_view()
Пример #24
0
class PrepareDialog(NXDialog):
    def __init__(self, parent=None):
        super().__init__(parent)

        self.select_entry(self.choose_entry)

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

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

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

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

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

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

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

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

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

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

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

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

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

    def reject(self):
        self.stop()
        super().reject()
Пример #25
0
 def plot_mask(self):
     self.plotview = NXPlotView('3D Mask')
     self.plotview.plot(
         NXdata(self.mask,
                self.reduce.data.nxaxes,
                title=f"3D Mask: {self.reduce.name}"))
Пример #26
0
class OrientationDialog(BaseDialog):

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

        self.select_entry(self.choose_entry)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    def save_orientation(self):
        self.write_parameters()

    def write_parameters(self):
        try:
            self.refine.write_parameters()
        except NeXusError as error:
            report_error('Defining Orientation', error)
Пример #27
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()
Пример #28
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
Пример #29
0
class CalibrateDialog(BaseDialog):

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

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

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

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

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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    def reject(self):
        super(CalibrateDialog, self).reject()
        if 'Powder Calibration' in plotviews:
            plotviews['Powder Calibration'].close_view()
        if 'Cake Plot' in plotviews:
            plotviews['Cake Plot'].close_view()
Пример #30
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()