class SettingsDialog(NXDialog): def __init__(self, parent=None): super().__init__(parent) try: self.settings = NXSettings() default_directory = self.settings.directory except NeXusError: self.settings = None default_directory = "" self.set_layout( self.directorybox('Choose Settings Directory', suggestion=default_directory), self.close_layout(save=True)) if self.settings: self.define_parameters() self.set_title('New Settings') def choose_directory(self): super().choose_directory() directory = self.get_directory() self.settings = NXSettings(directory=directory) self.define_parameters() def define_parameters(self): self.refine_parameters = GridParameters() defaults = self.settings.settings['nxrefine'] for p in defaults: self.refine_parameters.add(p, defaults[p], p) self.reduce_parameters = GridParameters() defaults = self.settings.settings['nxreduce'] for p in defaults: self.reduce_parameters.add(p, defaults[p], p) if self.layout.count() == 2: self.layout.insertLayout( 1, self.refine_parameters.grid(header=False, title='NXRefine')) self.layout.insertLayout( 2, self.reduce_parameters.grid(header=False, title='NXReduce')) def accept(self): try: for p in self.refine_parameters: self.settings.set('nxrefine', p, self.refine_parameters[p].value) for p in self.reduce_parameters: self.settings.set('nxreduce', p, self.reduce_parameters[p].value) self.settings.save() super().accept() except Exception as error: report_error("Defining New Settings", error)
class SampleDialog(BaseDialog): def __init__(self, parent=None): super(SampleDialog, self).__init__(parent) self.sample = GridParameters() self.sample.add('sample', 'sample', 'Sample Name') self.sample.add('label', 'label', 'Sample Label') self.set_layout(self.directorybox('Choose Experiment Directory', default=False), self.sample.grid(header=False), self.close_buttons(save=True)) self.set_title('New Sample') def accept(self): home_directory = self.get_directory() self.mainwindow.default_directory = home_directory sample_directory = os.path.join(home_directory, self.sample['sample'].value, self.sample['label'].value) if not os.path.exists(sample_directory): os.makedirs(sample_directory) super(SampleDialog, self).accept()
class MaskDialog(BaseDialog): def __init__(self, parent=None): super(MaskDialog, self).__init__(parent) self.select_entry(self.choose_entry) self.parameters = GridParameters() self.parameters.add('mask', 'pilatus_mask/entry/mask', 'Mask Path') self.action_buttons(('Save Mask', self.save_mask)) self.set_layout(self.entry_layout, self.parameters.grid(), self.action_buttons(('Save Mask', self.save_mask)), self.close_buttons()) self.set_title('Mask Data') def save_mask(self): try: mask = self.treeview.tree[self.parameters['mask'].value] if mask.dtype != np.bool: raise NeXusError('Mask must be a Boolean array') elif len(mask.shape) == 1: raise NeXusError('Mask must be at least two-dimensional') elif len(mask.shape) > 2: mask = mask[0] self.entry['instrument/detector/pixel_mask'] = mask self.entry['instrument/detector/pixel_mask_applied'] = False except NeXusError as error: report_error('Applying Mask', error)
class EnergyDialog(BaseDialog): def __init__(self, parent=None): super(EnergyDialog, self).__init__(parent) layout = QtGui.QVBoxLayout() self.select_entry() self.parameters = GridParameters() self.parameters.add('m1', self.entry['monitor1/distance'], 'Monitor 1 Distance') self.parameters.add('m2', self.entry['monitor2/distance'], 'Monitor 2 Distance') self.parameters.add('Ei', self.entry['instrument/monochromator/energy'], 'Incident Energy') self.parameters.add('mod', self.entry['instrument/source/distance'], 'Moderator Distance') layout.addLayout(self.entry_layout) layout.addLayout(self.parameters.grid()) layout.addLayout(self.action_buttons(('Get Ei', self.get_ei))) layout.addWidget(self.close_buttons(save=True)) self.setLayout(layout) self.setWindowTitle('Get Incident Energy') self.m1 = self.entry['monitor1'] self.m2 = self.entry['monitor2'] @property def m1_distance(self): return self.parameters['m1'].value - self.moderator_distance @property def m2_distance(self): return self.parameters['m2'].value - self.moderator_distance @property def Ei(self): return self.parameters['Ei'].value @property def moderator_distance(self): return self.parameters['mod'].value def get_ei(self): t = 2286.26 * self.m1_distance / np.sqrt(self.Ei) m1_time = self.m1[t-200.0:t+200.0].moment() t = 2286.26 * self.m2_distance / np.sqrt(self.Ei) m2_time = self.m2[t-200.0:t+200.0].moment() self.parameters['Ei'].value = (2286.26 * (self.m2_distance - self.m1_distance) / (m2_time - m1_time))**2 def accept(self): try: self.parameters['Ei'].save() except NeXusError as error: report_error("Getting Incident Energy", error) super(EnergyDialog, self).accept()
class EnergyDialog(NXDialog): def __init__(self, parent=None): super().__init__(parent) self.select_entry() self.parameters = GridParameters() self.parameters.add('m1', self.entry['monitor1/distance'], 'Monitor 1 Distance') self.parameters.add('m2', self.entry['monitor2/distance'], 'Monitor 2 Distance') self.parameters.add('Ei', self.entry['instrument/monochromator/energy'], 'Incident Energy') self.parameters.add('mod', self.entry['instrument/source/distance'], 'Moderator Distance') action_buttons = self.action_buttons(('Get Ei', self.get_ei)) self.set_layout(self.entry_layout, self.parameters.grid(), action_buttons, self.close_buttons(save=True)) self.set_title('Get Incident Energy') self.m1 = self.entry['monitor1'] self.m2 = self.entry['monitor2'] @property def m1_distance(self): return self.parameters['m1'].value - self.moderator_distance @property def m2_distance(self): return self.parameters['m2'].value - self.moderator_distance @property def Ei(self): return self.parameters['Ei'].value @property def moderator_distance(self): return self.parameters['mod'].value def get_ei(self): t = 2286.26 * self.m1_distance / np.sqrt(self.Ei) m1_time = self.m1[t - 200.0:t + 200.0].moment() t = 2286.26 * self.m2_distance / np.sqrt(self.Ei) m2_time = self.m2[t - 200.0:t + 200.0].moment() self.parameters['Ei'].value = (2286.26 * (self.m2_distance - self.m1_distance) / (m2_time - m1_time))**2 def accept(self): try: self.parameters['Ei'].save() except NeXusError as error: report_error("Getting Incident Energy", error) super().accept()
class EnergyDialog(BaseDialog): def __init__(self, parent=None): super(EnergyDialog, self).__init__(parent) self.select_entry() self.parameters = GridParameters() self.parameters.add("m1", self.entry["monitor1/distance"], "Monitor 1 Distance") self.parameters.add("m2", self.entry["monitor2/distance"], "Monitor 2 Distance") self.parameters.add("Ei", self.entry["instrument/monochromator/energy"], "Incident Energy") self.parameters.add("mod", self.entry["instrument/source/distance"], "Moderator Distance") action_buttons = self.action_buttons(("Get Ei", self.get_ei)) self.set_layout(self.entry_layout, self.parameters.grid(), action_buttons, self.close_buttons(save=True)) self.set_title("Get Incident Energy") self.m1 = self.entry["monitor1"] self.m2 = self.entry["monitor2"] @property def m1_distance(self): return self.parameters["m1"].value - self.moderator_distance @property def m2_distance(self): return self.parameters["m2"].value - self.moderator_distance @property def Ei(self): return self.parameters["Ei"].value @property def moderator_distance(self): return self.parameters["mod"].value def get_ei(self): t = 2286.26 * self.m1_distance / np.sqrt(self.Ei) m1_time = self.m1[t - 200.0 : t + 200.0].moment() t = 2286.26 * self.m2_distance / np.sqrt(self.Ei) m2_time = self.m2[t - 200.0 : t + 200.0].moment() self.parameters["Ei"].value = (2286.26 * (self.m2_distance - self.m1_distance) / (m2_time - m1_time)) ** 2 def accept(self): try: self.parameters["Ei"].save() except NeXusError as error: report_error("Getting Incident Energy", error) super(EnergyDialog, self).accept()
class SampleDialog(BaseDialog): def __init__(self, parent=None): super(SampleDialog, self).__init__(parent) self.sample = GridParameters() self.sample.add('sample', 'sample', 'Sample Name') self.sample.add('label', 'label', 'Sample Label') self.set_layout( self.directorybox('Choose Experiment Directory', default=False), self.sample.grid(header=False), self.close_buttons(save=True)) self.set_title('New Sample') def accept(self): home_directory = self.get_directory() self.mainwindow.default_directory = home_directory sample_directory = os.path.join(home_directory, self.sample['sample'].value, self.sample['label'].value) if not os.path.exists(sample_directory): os.makedirs(sample_directory) super(SampleDialog, self).accept()
class ExperimentDialog(NXDialog): def __init__(self, parent=None): super().__init__(parent) self.parameters = GridParameters() self.parameters.add('experiment', 'experiment', 'Experiment') self.set_layout( self.directorybox('Choose Home Directory', default=False), self.parameters.grid(header=False), self.close_layout(save=True)) self.set_title('New Experiment') def accept(self): try: home_directory = self.get_directory() experiment_directory = os.path.join( home_directory, self.parameters['experiment'].value) if not os.path.exists(experiment_directory): os.makedirs(experiment_directory) self.mainwindow.default_directory = experiment_directory configuration_directory = os.path.join(experiment_directory, 'configurations') if not os.path.exists(configuration_directory): os.makedirs(configuration_directory) task_directory = os.path.join(experiment_directory, 'tasks') if not os.path.exists(task_directory): os.makedirs(task_directory) nxdb = NXDatabase(os.path.join(task_directory, 'nxdatabase.db')) calibration_directory = os.path.join(experiment_directory, 'calibrations') if not os.path.exists(calibration_directory): os.makedirs(calibration_directory) script_directory = os.path.join(experiment_directory, 'scripts') if not os.path.exists(script_directory): os.makedirs(script_directory) super().accept() except Exception as error: report_error("Defining New Experiment", error)
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()
class CalculateDialog(BaseDialog): def __init__(self, parent=None): super(CalculateDialog, self).__init__(parent) self.select_entry(self.choose_entry) self.refine = NXRefine(self.entry) self.refine.read_parameters() self.parameters = GridParameters() self.parameters.add('wavelength', self.refine.wavelength, 'Wavelength (Ang)') self.parameters.add('distance', self.refine.distance, 'Detector Distance (mm)') self.parameters.add('xc', self.refine.xc, 'Beam Center - x') self.parameters.add('yc', self.refine.yc, 'Beam Center - y') self.parameters.add('pixel', self.refine.pixel_size, 'Pixel Size (mm)') action_buttons = self.action_buttons(('Plot', self.plot_lattice), ('Save', self.write_parameters)) self.set_layout(self.entry_layout, self.parameters.grid(), action_buttons, self.close_buttons()) self.set_title('Calculate Angles') def choose_entry(self): self.refine = NXRefine(self.entry) self.update_parameters() def update_parameters(self): self.parameters['wavelength'].value = self.refine.wavelength self.parameters['distance'].value = self.refine.distance self.parameters['xc'].value = self.refine.xc self.parameters['yc'].value = self.refine.yc self.parameters['pixel'].value = self.refine.pixel_size def get_wavelength(self): return self.parameters['wavelength'].value def get_distance(self): return self.parameters['distance'].value def get_centers(self): return self.parameters['xc'].value, self.parameters['yc'].value def get_pixel_size(self): return self.parameters['pixel'].value def get_parameters(self): self.refine.wavelength = self.get_wavelength() self.refine.distance = self.get_distance() self.refine.xc, self.refine.yc = self.get_centers() self.refine.pixel_size = self.get_pixel_size() self.refine.yaw = self.refine.pitch = self.refine.roll = None def plot_lattice(self): try: self.get_parameters() self.plot_peaks(self.refine.xp, self.refine.yp) except NeXusError as error: report_error('Calculating Angles', error) def plot_peaks(self, x, y): try: polar_angles, azimuthal_angles = self.refine.calculate_angles(x, y) if polar_angles[0] > polar_angles[-1]: polar_angles = polar_angles[::-1] azimuthal_angles = azimuthal_angles[::-1] azimuthal_field = NXfield(azimuthal_angles, name='azimuthal_angle') azimuthal_field.long_name = 'Azimuthal Angle' polar_field = NXfield(polar_angles, name='polar_angle') polar_field.long_name = 'Polar Angle' plotview = get_plotview() plotview.plot(NXdata(azimuthal_field, polar_field, title='Peak Angles')) except NeXusError as error: report_error('Plotting Lattice', error) def write_parameters(self): try: self.get_parameters() polar_angles, azimuthal_angles = self.refine.calculate_angles( self.refine.xp, self.refine.yp) self.refine.write_angles(polar_angles, azimuthal_angles) self.refine.write_parameters() except NeXusError as error: report_error('Calculating Angles', error)
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)
class LatticeDialog(NXDialog): def __init__(self, parent=None): super().__init__(parent) self.select_root(self.choose_entry) self.refine = NXRefine() self.parameters = GridParameters() self.parameters.add('space_group', self.refine.space_group, 'Space Group', slot=self.set_groups) self.parameters.add('laue_group', self.refine.laue_groups, 'Laue Group') self.parameters.add('symmetry', self.refine.symmetries, 'Symmetry', slot=self.set_lattice_parameters) self.parameters.add('centring', self.refine.centrings, 'Cell Centring') self.parameters.add('a', self.refine.a, 'Unit Cell - a (Ang)', slot=self.set_lattice_parameters) self.parameters.add('b', self.refine.b, 'Unit Cell - b (Ang)', slot=self.set_lattice_parameters) self.parameters.add('c', self.refine.c, 'Unit Cell - c (Ang)', slot=self.set_lattice_parameters) self.parameters.add('alpha', self.refine.alpha, 'Unit Cell - alpha (deg)', slot=self.set_lattice_parameters) self.parameters.add('beta', self.refine.beta, 'Unit Cell - beta (deg)', slot=self.set_lattice_parameters) self.parameters.add('gamma', self.refine.gamma, 'Unit Cell - gamma (deg)', slot=self.set_lattice_parameters) self.parameters['laue_group'].value = self.refine.laue_group self.parameters['symmetry'].value = self.refine.symmetry self.parameters['centring'].value = self.refine.centring self.import_button = NXPushButton('Import CIF', self.import_cif) self.import_checkbox = NXCheckBox('Update Lattice Parameters') self.set_layout(self.root_layout, self.close_buttons(save=True)) self.set_title('Defining Lattice') def choose_entry(self): self.refine = NXRefine(self.root['entry']) if self.layout.count() == 2: self.insert_layout(1, self.parameters.grid(header=False)) if sgtbx: self.insert_layout( 2, self.make_layout(self.import_button, self.import_checkbox, align='center')) self.update_parameters() def import_cif(self): filename = getOpenFileName(self, 'Open CIF File') if os.path.exists(filename): cif_info = cif.reader(file_path=filename).model() for c in cif_info: s = cif_info[c] if '_cell_length_a' in s: break def value(text): if '(' in text: return float(text[:text.index('(')]) else: return float(text) if self.import_checkbox.isChecked(): self.refine.a = value(s['_cell_length_a']) self.refine.b = value(s['_cell_length_b']) self.refine.c = value(s['_cell_length_c']) self.refine.alpha = value(s['_cell_angle_alpha']) self.refine.beta = value(s['_cell_angle_beta']) self.refine.gamma = value(s['_cell_angle_gamma']) if '_space_group_IT_number' in s: sgi = sgtbx.space_group_info(s['_space_group_IT_number']) elif '_symmetry_Int_Tables_number' in s: sgi = sgtbx.space_group_info(s['_symmetry_Int_Tables_number']) elif '_space_group_name_H-M_alt' in s: sgi = sgtbx.space_group_info(s['_space_group_name_H-M_alt']) elif '_symmetry_space_group_name_H-M' in s: sgi = sgtbx.space_group_info( s['_symmetry_space_group_name_H-M']) elif '_space_group_name_Hall' in s: sgi = sgtbx.space_group_info('hall: ' + s['_space_group_name_Hall']) elif '_symmetry_space_group_name_Hall' in s: sgi = sgtbx.space_group_info( 'hall: ' + s['_symmetry_space_group_name_Hall']) else: sgi = None if sgi: self.refine.space_group = sgi.type().lookup_symbol() self.refine.symmetry = sgi.group().crystal_system().lower() self.refine.laue_group = sgi.group().laue_group_type() self.refine.centring = self.refine.space_group[0] self.update_parameters() def update_parameters(self): self.parameters['space_group'].value = self.refine.space_group self.parameters['laue_group'].value = self.refine.laue_group self.parameters['symmetry'].value = self.refine.symmetry self.parameters['centring'].value = self.refine.centring self.parameters['a'].value = self.refine.a self.parameters['b'].value = self.refine.b self.parameters['c'].value = self.refine.c self.parameters['alpha'].value = self.refine.alpha self.parameters['beta'].value = self.refine.beta self.parameters['gamma'].value = self.refine.gamma def set_groups(self): if self.space_group: try: if isinstance(self.space_group, float): sgi = sgtbx.space_group_info(int(self.space_group)) else: sgi = sgtbx.space_group_info(self.space_group) except RuntimeError as error: report_error("Defining Lattice", error) return try: self.refine.space_group = sgi.type().lookup_symbol() self.refine.symmetry = sgi.group().crystal_system().lower() self.refine.laue_group = sgi.group().laue_group_type() self.refine.centring = self.refine.space_group[0] self.update_parameters() except Exception: pass @property def space_group(self): return self.parameters['space_group'].value @property def laue_group(self): return self.parameters['laue_group'].value def get_symmetry(self): return self.parameters['symmetry'].value def get_centring(self): return self.parameters['centring'].value def get_lattice_parameters(self): return (self.parameters['a'].value, self.parameters['b'].value, self.parameters['c'].value, self.parameters['alpha'].value, self.parameters['beta'].value, self.parameters['gamma'].value) def set_lattice_parameters(self): symmetry = self.get_symmetry() if symmetry == 'cubic': self.parameters['b'].value = self.parameters['a'].value self.parameters['c'].value = self.parameters['a'].value self.parameters['alpha'].value = 90.0 self.parameters['beta'].value = 90.0 self.parameters['gamma'].value = 90.0 elif symmetry == 'tetragonal': self.parameters['b'].value = self.parameters['a'].value self.parameters['alpha'].value = 90.0 self.parameters['beta'].value = 90.0 self.parameters['gamma'].value = 90.0 elif symmetry == 'orthorhombic': self.parameters['alpha'].value = 90.0 self.parameters['beta'].value = 90.0 self.parameters['gamma'].value = 90.0 elif symmetry == 'hexagonal': self.parameters['b'].value = self.parameters['a'].value self.parameters['alpha'].value = 90.0 self.parameters['beta'].value = 90.0 self.parameters['gamma'].value = 120.0 elif symmetry == 'monoclinic': self.parameters['alpha'].value = 90.0 self.parameters['gamma'].value = 90.0 def get_parameters(self): (self.refine.a, self.refine.b, self.refine.c, self.refine.alpha, self.refine.beta, self.refine.gamma) = (self.get_lattice_parameters()) self.refine.space_group = self.space_group self.refine.laue_group = self.laue_group self.refine.symmetry = self.get_symmetry() self.refine.centring = self.get_centring() def write_parameters(self): self.get_parameters() self.refine.write_parameters(sample=True) def accept(self): try: self.write_parameters() super().accept() except NeXusError as error: report_error("Defining Lattice", error)
class LatticeDialog(BaseDialog): def __init__(self, parent=None): super(LatticeDialog, self).__init__(parent) self.select_entry(self.choose_entry) self.refine = NXRefine() self.parameters = GridParameters() self.parameters.add('symmetry', self.refine.symmetries, 'Symmetry', slot=self.set_lattice_parameters) self.parameters.add('centring', self.refine.centrings, 'Cell Centring') self.parameters.add('a', self.refine.a, 'Unit Cell - a (Ang)', slot=self.set_lattice_parameters) self.parameters.add('b', self.refine.b, 'Unit Cell - b (Ang)', slot=self.set_lattice_parameters) self.parameters.add('c', self.refine.c, 'Unit Cell - c (Ang)', slot=self.set_lattice_parameters) self.parameters.add('alpha', self.refine.alpha, 'Unit Cell - alpha (deg)', slot=self.set_lattice_parameters) self.parameters.add('beta', self.refine.beta, 'Unit Cell - beta (deg)', slot=self.set_lattice_parameters) self.parameters.add('gamma', self.refine.gamma, 'Unit Cell - gamma (deg)', slot=self.set_lattice_parameters) self.parameters['symmetry'].value = self.refine.symmetry self.parameters['centring'].value = self.refine.centring action_buttons = self.action_buttons(('Plot', self.plot_lattice), ('Save', self.write_parameters)) self.set_layout(self.entry_layout, self.parameters.grid(), action_buttons, self.close_buttons()) self.set_title('Defining Lattice') def choose_entry(self): self.refine = NXRefine(self.entry) self.update_parameters() def update_parameters(self): self.parameters['symmetry'].value = self.refine.symmetry self.parameters['centring'].value = self.refine.centring self.parameters['a'].value = self.refine.a self.parameters['b'].value = self.refine.b self.parameters['c'].value = self.refine.c self.parameters['alpha'].value = self.refine.alpha self.parameters['beta'].value = self.refine.beta self.parameters['gamma'].value = self.refine.gamma def get_symmetry(self): return self.parameters['symmetry'].value def get_centring(self): return self.parameters['centring'].value def get_lattice_parameters(self): return (self.parameters['a'].value, self.parameters['b'].value, self.parameters['c'].value, self.parameters['alpha'].value, self.parameters['beta'].value, self.parameters['gamma'].value) def set_lattice_parameters(self): symmetry = self.get_symmetry() if symmetry == 'cubic': self.parameters['b'].value = self.parameters['a'].value self.parameters['c'].value = self.parameters['a'].value self.parameters['alpha'].value = 90.0 self.parameters['beta'].value = 90.0 self.parameters['gamma'].value = 90.0 elif symmetry == 'tetragonal': self.parameters['b'].value = self.parameters['a'].value self.parameters['alpha'].value = 90.0 self.parameters['beta'].value = 90.0 self.parameters['gamma'].value = 90.0 elif symmetry == 'orthorhombic': self.parameters['alpha'].value = 90.0 self.parameters['beta'].value = 90.0 self.parameters['gamma'].value = 90.0 elif symmetry == 'hexagonal': self.parameters['b'].value = self.parameters['a'].value self.parameters['alpha'].value = 90.0 self.parameters['beta'].value = 90.0 self.parameters['gamma'].value = 120.0 elif symmetry == 'monoclinic': self.parameters['alpha'].value = 90.0 self.parameters['gamma'].value = 90.0 def get_parameters(self): (self.refine.a, self.refine.b, self.refine.c, self.refine.alpha, self.refine.beta, self.refine.gamma) = (self.get_lattice_parameters()) self.refine.symmetry = self.get_symmetry() self.refine.centring = self.get_centring() def plot_lattice(self): try: self.get_parameters() self.plot_peaks(self.refine.xp, self.refine.yp) polar_min, polar_max = plotview.xaxis.get_limits() self.plot_rings(polar_max) except NeXusError as error: report_error('Plotting Lattice', error) def write_parameters(self): try: self.get_parameters() self.refine.write_parameters() except NeXusError as error: report_error('Defining Lattice', error) def plot_peaks(self, x, y): try: polar_angles, azimuthal_angles = self.refine.calculate_angles(x, y) if polar_angles[0] > polar_angles[-1]: polar_angles = polar_angles[::-1] azimuthal_angles = azimuthal_angles[::-1] azimuthal_field = NXfield(azimuthal_angles, name='azimuthal_angle') azimuthal_field.long_name = 'Azimuthal Angle' polar_field = NXfield(polar_angles, name='polar_angle') polar_field.long_name = 'Polar Angle' plotview = get_plotview() plotview.plot( NXdata(azimuthal_field, polar_field, title='Peak Angles')) except NeXusError as error: report_error('Plotting Lattice', error) def plot_rings(self, polar_max=None): if polar_max is None: polar_max = self.refine.polar_max peaks = self.refine.calculate_rings(polar_max) plotview = get_plotview() plotview.vlines(peaks, colors='r', linestyles='dotted') plotview.draw()
class MaximumDialog(BaseDialog): def __init__(self, parent=None): super(MaximumDialog, self).__init__(parent) self.select_entry(self.choose_entry) self.parameters = GridParameters() self.parameters.add('first', '', 'First Frame') self.parameters.add('last', '', 'Last Frame') self.output = QtWidgets.QLabel('Maximum Value:') self.set_layout(self.entry_layout, self.output, self.parameters.grid(), self.action_buttons(('Find Maximum', self.find_maximum)), self.progress_layout(save=True)) self.progress_bar.setVisible(False) self.progress_bar.setValue(0) self.set_title('Find Maximum Value') self.reduce = None def choose_entry(self): self.reduce = NXReduce(self.entry) self.maximum = self.reduce.maximum if self.reduce.first: self.parameters['first'].value = self.reduce.first if self.reduce.last: self.parameters['last'].value = self.reduce.last @property def first(self): try: _first = np.int32(self.parameters['first'].value) if _first >= 0: return _first else: return None except Exception as error: return None @property def last(self): try: _last = np.int32(self.parameters['last'].value) if _last > 0: return _last else: return None except Exception as error: return None @property def maximum(self): return np.float(self.output.text().split()[-1]) @maximum.setter def maximum(self, value): self.output.setText('Maximum Value: %s' % value) def find_maximum(self): self.check_lock(self.reduce.data_file) self.start_thread() self.reduce = NXReduce(self.entry, first=self.first, last=self.last, maxcount=True, overwrite=True, gui=True) self.reduce.moveToThread(self.thread) self.reduce.start.connect(self.start_progress) self.reduce.update.connect(self.update_progress) self.reduce.result.connect(self.get_maximum) self.reduce.stop.connect(self.stop) self.thread.started.connect(self.reduce.nxmax) self.thread.finished.connect(self.stop) self.thread.start(QtCore.QThread.LowestPriority) def check_lock(self, file_name): try: with Lock(file_name, timeout=2): pass except LockException as error: if self.confirm_action('Clear lock?', str(error)): Lock(file_name).release() def get_maximum(self, maximum): self.maximum = maximum def stop(self): self.stop_progress() if self.thread and self.thread.isRunning(): self.reduce.stopped = True self.stop_thread() def accept(self): try: with Lock(self.reduce.wrapper_file): self.reduce.write_maximum(self.maximum) except LockException as error: if self.confirm_action('Clear lock?', str(error)): Lock(self.reduce.wrapper_file).release() self.stop() super(MaximumDialog, self).accept() def reject(self): self.stop() super(MaximumDialog, self).reject()
class ConvertDialog(BaseDialog): def __init__(self, parent=None): super(ConvertDialog, self).__init__(parent) layout = QtGui.QVBoxLayout() self.select_entry() self.parameters = GridParameters() self.parameters.add('Ei', self.entry['instrument/monochromator/energy'], 'Incident Energy') self.parameters.add('dQ', self.round(np.sqrt(self.Ei/2)/50), 'Q Step') self.parameters.add('dE', self.round(self.Ei/50), 'Energy Step') layout.addLayout(self.entry_layout) layout.addLayout(self.parameters.grid()) layout.addLayout(self.action_buttons(('Plot', self.plot_data), ('Save', self.save_data))) layout.addWidget(self.close_buttons()) self.setLayout(layout) self.setWindowTitle('Converting to (Q,E)') @property def Ei(self): return self.parameters['Ei'].value @property def dQ(self): return self.parameters['dQ'].value @property def dE(self): return self.parameters['dE'].value def read_parameters(self): self.L1 = - self.entry['sample/distance'] self.L2 = np.mean(self.entry['instrument/detector/distance']) self.m1 = self.entry['monitor1'] self.t_m1 = self.m1.moment() self.d_m1 = self.entry['monitor1/distance'] def convert_tof(self, tof): ki = np.sqrt(self.Ei / 2.0721) ts = self.t_m1 + 1588.254 * (self.L1 - self.d_m1) / ki kf = 1588.254 * self.L2 / (tof - ts) eps = self.Ei - 2.0721*kf**2 return eps def convert_QE(self): """Convert S(phi,eps) to S(Q,eps)""" self.read_parameters() Ei = self.Ei dQ = self.dQ dE = self.dE pol, tof = centers(self.entry['data'].nxsignal, self.entry['data'].nxaxes) en = self.convert_tof(tof) idx_max = min(np.where(np.abs(en-0.75*Ei)<0.1)[0]) en = en[:idx_max] data = self.entry['data'].nxsignal.nxdata[:,:idx_max] if self.entry['data'].nxerrors: errors = self.entry['data'].nxerrors.nxdata[:] Q = np.zeros((len(pol), len(en))) E = np.zeros((len(pol), len(en))) for i in range(0,len(pol)): p = pol[i] Q[i,:] = np.array(np.sqrt((2*Ei - en - 2*np.sqrt(Ei*(Ei-en)) * np.cos(p*np.pi/180.0))/2.0721)) E[i,:] = np.array(en) s = Q.shape Qin = Q.reshape(s[0]*s[1]) Ein = E.reshape(s[0]*s[1]) datain = data.reshape(s[0]*s[1]) if self.entry['data'].nxerrors: errorsin = errors.reshape(s[0]*s[1]) qmin = Q.min() qmax = Q.max() emin = E.min() emax = E.max() NQ = int((qmax-qmin)/dQ) + 1 NE = int((emax-emin)/dE) + 1 Qb = np.linspace(qmin, qmax, NQ) Eb = np.linspace(emin, emax, NE) #histogram and normalize norm, nbin = np.histogramdd((Ein,Qin), bins=(Eb,Qb)) hist, hbin = np.histogramdd((Ein,Qin), bins=(Eb,Qb), weights=datain) if self.entry['data'].nxerrors: histe, hbin = np.histogramdd((Ein,Qin), bins=(Eb,Qb), weights=errorsin*errorsin) histe = histe**0.5 err = histe/norm I = NXfield(hist/norm, name='S(Q,E)') Qb = NXfield(Qb[:-1]+dQ/2., name='Q') Eb = NXfield(Eb[:-1]+dE/2., name='E') result = NXdata(I, (Eb, Qb)) if self.entry.data.nxerrors: result.errors = NXfield(err) return result def round(self, x, prec=2, base=.05): return round(base * round(float(x)/base), prec) def plot_data(self): self.convert_QE().plot() def save_data(self): self.entry['sqe'] = self.convert_QE()
class MakeDialog(BaseDialog): def __init__(self, parent=None): super(MakeDialog, self).__init__(parent) self.scans = None self.set_layout( self.directorybox("Choose Sample Directory", self.choose_sample), self.textboxes(('Scan Command', 'Pil2Mscan')), self.action_buttons(('Select All', self.select_scans), ('Reverse All', self.reverse_scans), ('Clear All', self.clear_scans), ('Make Scan Macro', self.make_scans)), self.close_buttons(close=True)) self.set_title('Make Scans') def choose_sample(self): super(MakeDialog, self).choose_directory() self.sample_directory = self.get_directory() self.experiment_directory = os.path.dirname( os.path.dirname(self.sample_directory)) self.macro_directory = os.path.join(self.experiment_directory, 'macros') self.label = os.path.basename(self.sample_directory) self.sample = os.path.basename(os.path.dirname(self.sample_directory)) self.experiment = os.path.basename(self.experiment_directory) self.experiment_path = self.experiment self.scan_path = os.path.join(self.experiment, self.sample, self.label) self.setup_scans() def setup_scans(self): if self.scans: self.scans.delete_grid() self.scans = GridParameters() all_files = [ self.sample + '_' + d + '.nxs' for d in os.listdir(self.sample_directory) if os.path.isdir(os.path.join(self.sample_directory, d)) ] filenames = sorted([ f for f in all_files if os.path.exists(os.path.join(self.sample_directory, f)) ], key=natural_sort) for i, f in enumerate(filenames): scan = 'f%d' % i self.scans.add(scan, i + 1, f, True, self.update_scans) self.scans[scan].checkbox.stateChanged.connect(self.update_scans) self.insert_layout(2, self.scans.grid(header=False)) @property def scan_list(self): scan_list = [] for scan in self.scans.values(): if scan.checkbox.isChecked() and scan.value > 0: scan_list.append(scan) else: scan.value = 0 return sorted(scan_list, key=attrgetter('value')) def update_scans(self): scan_list = self.scan_list scan_number = 0 for scan in scan_list: scan_number += 1 scan.value = scan_number for scan in self.scans.values(): if scan.checkbox.isChecked() and scan.value == 0: scan.value = scan_number + 1 scan_number += 1 def select_scans(self): for i, scan in enumerate(self.scans): self.scans[scan].value = i + 1 self.scans[scan].checkbox.setChecked(True) def reverse_scans(self): for i, scan in enumerate(reversed(self.scan_list)): scan.value = i + 1 scan.checkbox.setChecked(True) def clear_scans(self): for scan in self.scans: self.scans[scan].value = 0 self.scans[scan].checkbox.setChecked(False) def make_scans(self): scans = [scan.label.text() for scan in self.scan_list] scan_command = self.textbox['Scan Command'].text() scan_parameters = [ '#command path filename temperature detx dety ' + 'phi_start phi_step phi_end chi omega frame_rate' ] for scan in self.scan_list: nexus_file = scan.label.text() root = nxload(os.path.join(self.sample_directory, nexus_file)) temperature = root.entry.sample.temperature base_name = os.path.basename(os.path.splitext(nexus_file)[0]) scan_dir = base_name.replace(self.sample + '_', '') for entry in [root[e] for e in root if e != 'entry']: if 'phi_set' in entry['instrument/goniometer']: phi_start = entry['instrument/goniometer/phi_set'] else: phi_start = entry['instrument/goniometer/phi'] phi_step = entry['instrument/goniometer/phi'].attrs['step'] phi_end = entry['instrument/goniometer/phi'].attrs['end'] if 'chi_set' in entry['instrument/goniometer']: chi = entry['instrument/goniometer/chi_set'] else: chi = entry['instrument/goniometer/chi'] if 'omega_set' in entry['instrument/goniometer']: omega = entry['instrument/goniometer/omega_set'] else: omega = entry['instrument/goniometer/omega'] dx = entry['instrument/detector/translation_x'] dy = entry['instrument/detector/translation_y'] if ('frame_time' in entry['instrument/detector'] and entry['instrument/detector/frame_time'] > 0.0): frame_rate = 1.0 / entry['instrument/detector/frame_time'] else: frame_rate = 10.0 scan_file = entry.nxname if scan_command == 'Pil2Mscan': scan_parameters.append( '%s %s %s %.6g %.6g %.6g %.6g %.6g %.6g %.6g %.6g %.6g' % (scan_command, os.path.join(self.scan_path, scan_dir), scan_file, temperature, dx, dy, phi_start, phi_step, phi_end, chi, omega, frame_rate)) if scan_command == 'Pil2Mstring': scan_parameters.append('Pil2Mstring("%s")' % scan_dir) elif scan_command != 'Pil2Mscan': scan_parameters.append('%s %s' % (scan_command, temperature)) if not os.path.exists(self.macro_directory): os.mkdir(os.path.join(self.experiment_directory, 'macros')) macro_filter = ';;'.join(("SPEC Macro (*.mac)", "Any Files (*.* *)")) macro = getSaveFileName(self, 'Open Macro', self.macro_directory, macro_filter) if macro: with open(macro, 'w') as f: f.write('\n'.join(scan_parameters))
class MaximumDialog(BaseDialog): def __init__(self, parent=None): super(MaximumDialog, self).__init__(parent) self.select_entry(self.choose_entry) self.parameters = GridParameters() self.parameters.add('first', '', 'First Frame') self.parameters.add('last', '', 'Last Frame') self.output = QtWidgets.QLabel('Maximum Value:') self.set_layout( self.entry_layout, self.output, self.parameters.grid(), self.action_buttons(('Find Maximum', self.find_maximum)), self.progress_layout(save=True)) self.progress_bar.setVisible(False) self.progress_bar.setValue(0) self.set_title('Find Maximum Value') self.reduce = None def choose_entry(self): self.reduce = NXReduce(self.entry) self.maximum = self.reduce.maximum if self.reduce.first: self.parameters['first'].value = self.reduce.first if self.reduce.last: self.parameters['last'].value = self.reduce.last @property def first(self): try: _first = np.int32(self.parameters['first'].value) if _first >= 0: return _first else: return None except Exception as error: return None @property def last(self): try: _last = np.int32(self.parameters['last'].value) if _last > 0: return _last else: return None except Exception as error: return None @property def maximum(self): return np.float(self.output.text().split()[-1]) @maximum.setter def maximum(self, value): self.output.setText('Maximum Value: %s' % value) def find_maximum(self): self.check_lock(self.reduce.data_file) self.start_thread() self.reduce = NXReduce(self.entry, first=self.first, last=self.last, maxcount=True, overwrite=True, gui=True) self.reduce.moveToThread(self.thread) self.reduce.start.connect(self.start_progress) self.reduce.update.connect(self.update_progress) self.reduce.result.connect(self.get_maximum) self.reduce.stop.connect(self.stop) self.thread.started.connect(self.reduce.nxmax) self.thread.finished.connect(self.stop) self.thread.start(QtCore.QThread.LowestPriority) def check_lock(self, file_name): try: with Lock(file_name, timeout=2): pass except LockException as error: if self.confirm_action('Clear lock?', str(error)): Lock(file_name).release() def get_maximum(self, maximum): self.maximum = maximum def stop(self): self.stop_progress() if self.thread and self.thread.isRunning(): self.reduce.stopped = True self.stop_thread() def accept(self): try: with Lock(self.reduce.wrapper_file): self.reduce.write_maximum(self.maximum) except LockException as error: if self.confirm_action('Clear lock?', str(error)): Lock(self.reduce.wrapper_file).release() self.stop() super(MaximumDialog, self).accept() def reject(self): self.stop() super(MaximumDialog, self).reject()
class ParametersDialog(NXDialog): def __init__(self, parent=None): super().__init__(parent) self.select_root(self.choose_root) default = NXSettings().settings['nxreduce'] self.parameters = GridParameters() self.parameters.add('threshold', default['threshold'], 'Peak Threshold') self.parameters.add('first', default['first'], 'First Frame') self.parameters.add('last', default['last'], 'Last Frame') self.parameters.add('monitor', ['monitor1', 'monitor2'], 'Normalization Monitor') self.parameters['monitor'].value = default['monitor'] self.parameters.add('norm', default['norm'], 'Normalization Value') self.parameters.add('radius', default['radius'], 'Punch Radius (Å)') self.parameters.add('qmax', default['qmax'], 'Maximum Taper Q (Å-1)') self.set_layout(self.root_layout, self.close_buttons(save=True)) self.set_title('Choose Parameters') def choose_root(self): self.entries = [self.root[entry] for entry in self.root if entry != 'entry'] if self.layout.count() == 2: self.layout.insertLayout(1, self.parameters.grid(header=False)) self.read_parameters() def read_parameters(self): if 'nxreduce' in self.root['entry']: reduce = self.root['entry/nxreduce'] if 'threshold' in reduce: self.parameters['threshold'].value = reduce['threshold'] if 'first_frame' in reduce: self.parameters['first'].value = reduce['first_frame'] if 'last_frame' in reduce: self.parameters['last'].value = reduce['last_frame'] if 'monitor' in reduce: self.parameters['monitor'].value = reduce['monitor'] if 'norm' in reduce: self.parameters['norm'].value = reduce['norm'] if 'radius' in reduce: self.parameters['radius'].value = reduce['radius'] if 'qmax' in reduce: self.parameters['qmax'].value = reduce['qmax'] else: try: reduce = NXReduce(self.entries[0]) if reduce.first: self.parameters['first'].value = reduce.first if reduce.last: self.parameters['last'].value = reduce.last if reduce.threshold: self.parameters['threshold'].value = reduce.threshold if reduce.monitor: self.parameters['monitor'].value = reduce.monitor if reduce.norm: self.parameters['norm'].value = reduce.norm if reduce.radius: self.parameters['radius'].value = reduce.radius if reduce.qmax: self.parameters['qmax'].value = reduce.qmax except Exception: pass def write_parameters(self): if 'nxreduce' not in self.root['entry']: self.root['entry/nxreduce'] = NXparameters() self.root['entry/nxreduce/threshold'] = self.threshold self.root['entry/nxreduce/first_frame'] = self.first self.root['entry/nxreduce/last_frame'] = self.last self.root['entry/nxreduce/monitor'] = self.monitor self.root['entry/nxreduce/norm'] = self.norm self.root['entry/nxreduce/radius'] = self.radius self.root['entry/nxreduce/qmax'] = self.qmax @property def threshold(self): return float(self.parameters['threshold'].value) @property def first(self): return int(self.parameters['first'].value) @property def last(self): return int(self.parameters['last'].value) @property def monitor(self): return self.parameters['monitor'].value @property def norm(self): return float(self.parameters['norm'].value) @property def radius(self): return float(self.parameters['radius'].value) @property def qmax(self): return float(self.parameters['qmax'].value) def accept(self): try: self.write_parameters() super().accept() except NeXusError as error: report_error(error)
class FindDialog(BaseDialog): def __init__(self, parent=None): super(FindDialog, self).__init__(parent) self.select_entry(self.choose_entry) self.parameters = GridParameters() self.parameters.add('threshold', '', 'Threshold') self.parameters.add('first', '', 'First Frame') self.parameters.add('last', '', 'Last Frame') find_layout = QtWidgets.QHBoxLayout() self.find_button = QtWidgets.QPushButton('Find Peaks') self.find_button.clicked.connect(self.find_peaks) self.peak_count = QtWidgets.QLabel() self.peak_count.setVisible(False) find_layout.addStretch() find_layout.addWidget(self.find_button) find_layout.addWidget(self.peak_count) find_layout.addStretch() self.set_layout(self.entry_layout, self.parameters.grid(), find_layout, self.progress_layout(save=True)) self.progress_bar.setVisible(False) self.progress_bar.setValue(0) self.set_title('Find Peaks') self.reduce = None def choose_entry(self): self.reduce = NXReduce(self.entry) if self.reduce.first: self.parameters['first'].value = self.reduce.first if self.reduce.last: self.parameters['last'].value = self.reduce.last else: try: self.parameters['last'].value = len(self.entry.data.nxaxes[0]) except Exception: pass if self.reduce.threshold: self.parameters['threshold'].value = self.reduce.threshold @property def threshold(self): try: _threshold = np.int32(self.parameters['threshold'].value) if _threshold > 0.0: return _threshold else: return None except Exception: return None @property def first(self): try: _first = np.int32(self.parameters['first'].value) if _first >= 0: return _first else: return None except Exception as error: return None @property def last(self): try: _last = np.int32(self.parameters['last'].value) if _last > 0: return _last else: return None except Exception as error: return None def find_peaks(self): self.check_lock(self.reduce.data_file) self.start_thread() self.reduce = NXReduce(self.entry, threshold=self.threshold, first=self.first, last=self.last, find=True, overwrite=True, gui=True) self.reduce.moveToThread(self.thread) self.reduce.start.connect(self.start_progress) self.reduce.update.connect(self.update_progress) self.reduce.result.connect(self.get_peaks) self.reduce.stop.connect(self.stop) self.thread.started.connect(self.reduce.nxfind) self.thread.start(QtCore.QThread.LowestPriority) def check_lock(self, file_name): try: with Lock(file_name, timeout=2): pass except LockException as error: if self.confirm_action('Clear lock?', str(error)): Lock(file_name).release() def get_peaks(self, peaks): self.peaks = peaks self.peak_count.setText('%s peaks found' % len(self.peaks)) self.peak_count.setVisible(True) def stop(self): self.stop_progress() if self.thread and self.thread.isRunning(): self.reduce.stopped = True self.stop_thread() def accept(self): try: with Lock(self.reduce.wrapper_file): self.reduce.write_peaks(self.peaks) except LockException as error: if self.confirm_action('Clear lock?', str(error)): Lock(self.reduce.wrapper_file).release() self.stop() super(FindDialog, self).accept() def reject(self): self.stop() super(FindDialog, self).reject()
class MaximumDialog(NXDialog): def __init__(self, parent=None): super().__init__(parent) self.select_entry(self.choose_entry) self.parameters = GridParameters() self.parameters.add('first', '', 'First Frame') self.parameters.add('last', '', 'Last Frame') self.output = NXLabel('Maximum Value:') self.set_layout( self.entry_layout, self.output, self.parameters.grid(), self.action_buttons(('Find Maximum', self.find_maximum)), self.progress_layout(save=True)) self.progress_bar.setVisible(False) self.progress_bar.setValue(0) self.set_title('Find Maximum Value') self.reduce = None def choose_entry(self): self.reduce = NXReduce(self.entry) self.maximum = self.reduce.maximum if self.reduce.first: self.parameters['first'].value = self.reduce.first if self.reduce.last: self.parameters['last'].value = self.reduce.last @property def first(self): try: _first = np.int32(self.parameters['first'].value) if _first >= 0: return _first else: return None except Exception as error: return None @property def last(self): try: _last = np.int32(self.parameters['last'].value) if _last > 0: return _last else: return None except Exception as error: return None @property def maximum(self): return np.float(self.output.text().split()[-1]) @maximum.setter def maximum(self, value): self.output.setText(f'Maximum Value: {value}') def find_maximum(self): if is_file_locked(self.reduce.data_file): return self.start_thread() self.reduce = NXReduce(self.entry, first=self.first, last=self.last, maxcount=True, overwrite=True, gui=True) self.reduce.moveToThread(self.thread) self.reduce.start.connect(self.start_progress) self.reduce.update.connect(self.update_progress) self.reduce.result.connect(self.get_maximum) self.reduce.stop.connect(self.stop) self.thread.started.connect(self.reduce.nxmax) self.thread.finished.connect(self.stop) self.thread.start(QtCore.QThread.LowestPriority) def get_maximum(self, maximum): self.maximum = maximum def stop(self): self.stop_progress() if self.thread and self.thread.isRunning(): self.reduce.stopped = True self.stop_thread() def accept(self): try: self.reduce.write_maximum(self.maximum) self.reduce.record('nxmax', maximum=self.maximum, first_frame=self.first, last_frame=self.last) self.reduce.record_end('nxmax') self.stop() super().accept() except Exception as error: report_error("Finding Maximum", error) def reject(self): self.stop() super().reject()
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()
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()
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
class CalculateDialog(NXDialog): def __init__(self, parent=None): super().__init__(parent) self.select_entry(self.choose_entry) self.refine = NXRefine() self.parameters = GridParameters() self.parameters.add('wavelength', self.refine.wavelength, 'Wavelength (Ang)') self.parameters.add('distance', self.refine.distance, 'Detector Distance (mm)') self.parameters.add('xc', self.refine.xc, 'Beam Center - x') self.parameters.add('yc', self.refine.yc, 'Beam Center - y') self.parameters.add('pixel', self.refine.pixel_size, 'Pixel Size (mm)') self.action_buttons = self.action_buttons( ('Plot', self.plot_lattice), ('Save', self.write_parameters)) self.set_layout(self.entry_layout, self.close_buttons()) self.set_title('Calculate Angles') def choose_entry(self): self.refine = NXRefine(self.entry) if 'peaks' in self.entry: if self.layout.count() == 2: self.insert_layout(1, self.parameters.grid(header=False)) self.insert_layout(2, self.action_buttons) self.update_parameters() else: self.display_message("Calculating Angles", "No peaks have been found in this entry") def update_parameters(self): self.parameters['wavelength'].value = self.refine.wavelength self.parameters['distance'].value = self.refine.distance self.parameters['xc'].value = self.refine.xc self.parameters['yc'].value = self.refine.yc self.parameters['pixel'].value = self.refine.pixel_size def get_wavelength(self): return self.parameters['wavelength'].value def get_distance(self): return self.parameters['distance'].value def get_centers(self): return self.parameters['xc'].value, self.parameters['yc'].value def get_pixel_size(self): return self.parameters['pixel'].value def get_parameters(self): self.refine.wavelength = self.get_wavelength() self.refine.distance = self.get_distance() self.refine.xc, self.refine.yc = self.get_centers() self.refine.pixel_size = self.get_pixel_size() self.refine.yaw = self.refine.pitch = self.refine.roll = None def plot_lattice(self): try: self.get_parameters() self.plot_peaks(self.refine.xp, self.refine.yp) except NeXusError as error: report_error("Calculating Angles", error) def plot_peaks(self, x, y): try: polar_angles, azimuthal_angles = self.refine.calculate_angles(x, y) if polar_angles[0] > polar_angles[-1]: polar_angles = polar_angles[::-1] azimuthal_angles = azimuthal_angles[::-1] azimuthal_field = NXfield(azimuthal_angles, name='azimuthal_angle') azimuthal_field.long_name = 'Azimuthal Angle' polar_field = NXfield(polar_angles, name='polar_angle') polar_field.long_name = 'Polar Angle' plotview = get_plotview() plotview.plot( NXdata(azimuthal_field, polar_field, title='Peak Angles')) except NeXusError as error: report_error("Plotting Lattice", error) def write_parameters(self): try: self.get_parameters() polar_angles, azimuthal_angles = self.refine.calculate_angles( self.refine.xp, self.refine.yp) self.refine.write_angles(polar_angles, azimuthal_angles) self.refine.write_parameters() except NeXusError as error: report_error("Calculating Angles", error)
class ParametersDialog(BaseDialog): def __init__(self, parent=None): super(ParametersDialog, self).__init__(parent) self.select_root(self.choose_root) self.parameters = GridParameters() self.parameters.add('threshold', '', 'Threshold') self.parameters.add('first', 25, 'First Frame') self.parameters.add('last', 3625, 'Last Frame') self.parameters.add('radius', 200, 'Radius') self.parameters.add('width', 3, 'Frame Width') self.parameters.add('norm', '', 'Normalization') self.set_layout(self.root_layout, self.parameters.grid(), self.close_buttons(save=True)) self.set_title('Choose Parameters') def choose_root(self): self.entries = [self.root[entry] for entry in self.root if entry != 'entry'] self.update_parameters() def update_parameters(self): reduce = NXReduce(self.entries[0]) if reduce.first: self.parameters['first'].value = reduce.first if reduce.last: self.parameters['last'].value = reduce.last if reduce.threshold: self.parameters['threshold'].value = reduce.threshold if reduce.radius: self.parameters['radius'].value = reduce.radius if reduce.width: self.parameters['width'].value = reduce.width if reduce.norm: self.parameters['norm'].value = reduce.norm def write_parameters(self, entry): if 'peaks' not in entry: entry['peaks'] = NXreflections() if self.first: entry['peaks'].attrs['first'] = np.int(self.first) elif 'first' in entry['peaks'].attrs: del entry['peaks'].attrs['first'] if self.last: entry['peaks'].attrs['last'] = np.int(self.last) elif 'last' in entry['peaks'].attrs: del entry['peaks'].attrs['last'] if self.threshold: entry['peaks'].attrs['threshold'] = self.threshold elif 'threshold' in entry['peaks'].attrs: del entry['peaks'].attrs['threshold'] if self.radius: entry['peaks'].attrs['radius'] = np.int(self.radius) elif 'radius' in entry['peaks'].attrs: del entry['peaks'].attrs['radius'] if self.width: entry['peaks'].attrs['width'] = np.int(self.width) elif 'width' in entry['peaks'].attrs: del entry['peaks'].attrs['width'] if self.norm: entry['peaks'].attrs['norm'] = self.norm elif 'norm' in entry['peaks'].attrs: del entry['peaks'].attrs['norm'] def get_value(self, key): value = self.parameters[key].value if isinstance(value, float) and value <= 0: return None elif isinstance(value, str): return None else: return value @property def threshold(self): return self.get_value('threshold') @property def first(self): return self.get_value('first') @property def last(self): return self.get_value('last') @property def radius(self): return self.get_value('radius') @property def width(self): return self.get_value('width') @property def norm(self): return self.get_value('norm') def accept(self): for entry in self.entries: self.write_parameters(entry) super(ParametersDialog, self).accept()
class Mask3DDialog(BaseDialog): def __init__(self, parent=None): super(Mask3DDialog, self).__init__(parent) self.select_entry(self.choose_entry) self.parameters = GridParameters() self.parameters.add('radius', 200, 'Radius') self.parameters.add('width', 3, 'Frame Width') self.set_layout( self.entry_layout, self.parameters.grid(), self.action_buttons(('Calculate 3D Mask', self.calculate_mask)), self.progress_layout(save=True)) self.progress_bar.setVisible(False) self.progress_bar.setValue(0) self.set_title('Calculate 3D Mask') self.reduce = None def choose_entry(self): self.reduce = NXReduce(self.entry) @property def radius(self): return self.parameters['radius'].value @property def width(self): return self.parameters['width'].value def calculate_mask(self): self.check_lock(self.reduce.wrapper_file) self.thread = QtCore.QThread() self.reduce = NXReduce(self.entry, radius=self.radius, width=self.width, mask=True, overwrite=True, gui=True) self.reduce.moveToThread(self.thread) self.reduce.start.connect(self.start_progress) self.reduce.update.connect(self.update_progress) self.reduce.result.connect(self.calculate_mask) self.reduce.stop.connect(self.stop) self.thread.started.connect(self.reduce.nxfind) self.thread.start(QtCore.QThread.LowestPriority) def check_lock(self, file_name): try: with Lock(file_name, timeout=2): pass except LockException as error: if self.confirm_action('Clear lock?', str(error)): Lock(file_name).release() def calculate_mask(self, mask): self.mask = mask def stop(self): self.stop_progress() if self.thread and self.thread.isRunning(): self.reduce.stopped = True self.thread.exit() def accept(self): try: with Lock(self.reduce.wrapper_file): self.reduce.write_peaks(self.peaks) except LockException as error: if self.confirm_action('Clear lock?', str(error)): Lock(self.reduce.wrapper_file).release() if self.thread: self.stop() super(Mask3DDialog, self).accept() def reject(self): if self.thread: self.stop() super(Mask3DDialog, self).reject()
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)
class Mask3DDialog(BaseDialog): def __init__(self, parent=None): super(Mask3DDialog, self).__init__(parent) self.select_entry(self.choose_entry) self.parameters = GridParameters() self.parameters.add('radius', 200, 'Radius') self.parameters.add('width', 3, 'Frame Width') self.set_layout(self.entry_layout, self.parameters.grid(), self.action_buttons(('Calculate 3D Mask', self.calculate_mask)), self.progress_layout(save=True)) self.progress_bar.setVisible(False) self.progress_bar.setValue(0) self.set_title('Calculate 3D Mask') self.reduce = None def choose_entry(self): self.reduce = NXReduce(self.entry) @property def radius(self): return self.parameters['radius'].value @property def width(self): return self.parameters['width'].value def calculate_mask(self): self.check_lock(self.reduce.wrapper_file) self.thread = QtCore.QThread() self.reduce = NXReduce(self.entry, radius=self.radius, width=self.width, mask=True, overwrite=True, gui=True) self.reduce.moveToThread(self.thread) self.reduce.start.connect(self.start_progress) self.reduce.update.connect(self.update_progress) self.reduce.result.connect(self.calculate_mask) self.reduce.stop.connect(self.stop) self.thread.started.connect(self.reduce.nxfind) self.thread.start(QtCore.QThread.LowestPriority) def check_lock(self, file_name): try: with Lock(file_name, timeout=2): pass except LockException as error: if self.confirm_action('Clear lock?', str(error)): Lock(file_name).release() def calculate_mask(self, mask): self.mask = mask def stop(self): self.stop_progress() if self.thread and self.thread.isRunning(): self.reduce.stopped = True self.thread.exit() def accept(self): try: with Lock(self.reduce.wrapper_file): self.reduce.write_peaks(self.peaks) except LockException as error: if self.confirm_action('Clear lock?', str(error)): Lock(self.reduce.wrapper_file).release() if self.thread: self.stop() super(Mask3DDialog, self).accept() def reject(self): if self.thread: self.stop() super(Mask3DDialog, self).reject()
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
class MakeDialog(BaseDialog): def __init__(self, parent=None): super(MakeDialog, self).__init__(parent) self.scans = None self.set_layout(self.directorybox("Choose Sample Directory", self.choose_sample), self.textboxes(('Scan Command', 'Pil2Mscan')), self.action_buttons(('Select All', self.select_scans), ('Reverse All', self.reverse_scans), ('Clear All', self.clear_scans), ('Make Scan Macro', self.make_scans)), self.close_buttons(close=True)) self.set_title('Make Scans') def choose_sample(self): super(MakeDialog, self).choose_directory() self.sample_directory = self.get_directory() self.experiment_directory = os.path.dirname(os.path.dirname(self.sample_directory)) self.macro_directory = os.path.join(self.experiment_directory, 'macros') self.label = os.path.basename(self.sample_directory) self.sample = os.path.basename(os.path.dirname(self.sample_directory)) self.experiment = os.path.basename(self.experiment_directory) self.experiment_path = self.experiment self.scan_path = os.path.join(self.experiment, self.sample, self.label) self.setup_scans() def setup_scans(self): if self.scans: self.scans.delete_grid() self.scans = GridParameters() all_files = [self.sample+'_'+d+'.nxs' for d in os.listdir(self.sample_directory) if os.path.isdir(os.path.join(self.sample_directory, d))] filenames = sorted([f for f in all_files if os.path.exists(os.path.join(self.sample_directory, f))], key=natural_sort) for i, f in enumerate(filenames): scan = 'f%d' % i self.scans.add(scan, i+1, f, True, self.update_scans) self.scans[scan].checkbox.stateChanged.connect(self.update_scans) self.insert_layout(2, self.scans.grid(header=False)) @property def scan_list(self): scan_list = [] for scan in self.scans.values(): if scan.checkbox.isChecked() and scan.value > 0: scan_list.append(scan) else: scan.value = 0 return sorted(scan_list, key=attrgetter('value')) def update_scans(self): scan_list = self.scan_list scan_number = 0 for scan in scan_list: scan_number += 1 scan.value = scan_number for scan in self.scans.values(): if scan.checkbox.isChecked() and scan.value == 0: scan.value = scan_number + 1 scan_number += 1 def select_scans(self): for i, scan in enumerate(self.scans): self.scans[scan].value = i+1 self.scans[scan].checkbox.setChecked(True) def reverse_scans(self): for i, scan in enumerate(reversed(self.scan_list)): scan.value = i+1 scan.checkbox.setChecked(True) def clear_scans(self): for scan in self.scans: self.scans[scan].value = 0 self.scans[scan].checkbox.setChecked(False) def make_scans(self): scans = [scan.label.text() for scan in self.scan_list] scan_command = self.textbox['Scan Command'].text() scan_parameters = ['#command path filename temperature detx dety ' + 'phi_start phi_step phi_end chi omega frame_rate'] for scan in self.scan_list: nexus_file = scan.label.text() root = nxload(os.path.join(self.sample_directory, nexus_file)) temperature = root.entry.sample.temperature base_name = os.path.basename(os.path.splitext(nexus_file)[0]) scan_dir = base_name.replace(self.sample+'_', '') for entry in [root[e] for e in root if e != 'entry']: if 'phi_set' in entry['instrument/goniometer']: phi_start = entry['instrument/goniometer/phi_set'] else: phi_start = entry['instrument/goniometer/phi'] phi_step = entry['instrument/goniometer/phi'].attrs['step'] phi_end = entry['instrument/goniometer/phi'].attrs['end'] if 'chi_set' in entry['instrument/goniometer']: chi = entry['instrument/goniometer/chi_set'] else: chi = entry['instrument/goniometer/chi'] if 'omega_set' in entry['instrument/goniometer']: omega = entry['instrument/goniometer/omega_set'] else: omega = entry['instrument/goniometer/omega'] dx = entry['instrument/detector/translation_x'] dy = entry['instrument/detector/translation_y'] if ('frame_time' in entry['instrument/detector'] and entry['instrument/detector/frame_time'] > 0.0): frame_rate = 1.0 / entry['instrument/detector/frame_time'] else: frame_rate = 10.0 scan_file = entry.nxname if scan_command == 'Pil2Mscan': scan_parameters.append( '%s %s %s %.6g %.6g %.6g %.6g %.6g %.6g %.6g %.6g %.6g' % (scan_command, os.path.join(self.scan_path, scan_dir), scan_file, temperature, dx, dy, phi_start, phi_step, phi_end, chi, omega, frame_rate)) if scan_command == 'Pil2Mstring': scan_parameters.append('Pil2Mstring("%s")' % scan_dir) elif scan_command != 'Pil2Mscan': scan_parameters.append('%s %s' % (scan_command, temperature)) if not os.path.exists(self.macro_directory): os.mkdir(os.path.join(self.experiment_directory, 'macros')) macro_filter = ';;'.join(("SPEC Macro (*.mac)", "Any Files (*.* *)")) macro = getSaveFileName(self, 'Open Macro', self.macro_directory, macro_filter) if macro: with open(macro, 'w') as f: f.write('\n'.join(scan_parameters))
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()
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()
class ConvertDialog(NXDialog): def __init__(self, parent=None): super().__init__(parent) self.select_entry() self.parameters = GridParameters() self.parameters.add('Ei', self.entry['instrument/monochromator/energy'], 'Incident Energy') self.parameters.add('dQ', self.round(np.sqrt(self.Ei / 2) / 50), 'Q Step') self.parameters.add('dE', self.round(self.Ei / 50), 'Energy Step') self.set_layout( self.entry_layout, self.parameters.grid(), self.action_buttons( ('Plot', self.plot_data), ('Save', self.save_data)), self.close_buttons()) self.setWindowTitle('Converting to (Q,E)') @property def Ei(self): return self.parameters['Ei'].value @property def dQ(self): return self.parameters['dQ'].value @property def dE(self): return self.parameters['dE'].value def read_parameters(self): self.L1 = -self.entry['sample/distance'] self.L2 = np.mean(self.entry['instrument/detector/distance']) self.m1 = self.entry['monitor1'] self.t_m1 = self.m1.moment() self.d_m1 = self.entry['monitor1/distance'] def convert_tof(self, tof): ki = np.sqrt(self.Ei / 2.0721) ts = self.t_m1 + 1588.254 * (self.L1 - self.d_m1) / ki kf = 1588.254 * self.L2 / (tof - ts) eps = self.Ei - 2.0721 * kf**2 return eps def convert_QE(self): """Convert S(phi,eps) to S(Q,eps)""" self.read_parameters() Ei = self.Ei dQ = self.dQ dE = self.dE signal = self.entry['data'].nxsignal pol = centers(self.entry['data/polar_angle'], signal.shape[0]) tof = centers(self.entry['data/time_of_flight'], signal.shape[1]) en = self.convert_tof(tof) idx_max = min(np.where(np.abs(en - 0.75 * Ei) < 0.1)[0]) en = en[:idx_max] data = signal.nxdata[:, :idx_max] if self.entry['data'].nxerrors: errors = self.entry['data'].nxerrors.nxdata[:] Q = np.zeros((len(pol), len(en))) E = np.zeros((len(pol), len(en))) for i in range(0, len(pol)): p = pol[i] Q[i, :] = np.array( np.sqrt( (2 * Ei - en - 2 * np.sqrt(Ei * (Ei - en)) * np.cos(p * np.pi / 180.0)) / 2.0721)) E[i, :] = np.array(en) s = Q.shape Qin = Q.reshape(s[0] * s[1]) Ein = E.reshape(s[0] * s[1]) datain = data.reshape(s[0] * s[1]) if self.entry['data'].nxerrors: errorsin = errors.reshape(s[0] * s[1]) qmin = Q.min() qmax = Q.max() emin = E.min() emax = E.max() NQ = int((qmax - qmin) / dQ) + 1 NE = int((emax - emin) / dE) + 1 Qb = np.linspace(qmin, qmax, NQ) Eb = np.linspace(emin, emax, NE) # histogram and normalize norm, nbin = np.histogramdd((Ein, Qin), bins=(Eb, Qb)) hist, hbin = np.histogramdd((Ein, Qin), bins=(Eb, Qb), weights=datain) if self.entry['data'].nxerrors: histe, hbin = np.histogramdd((Ein, Qin), bins=(Eb, Qb), weights=errorsin * errorsin) histe = histe**0.5 err = histe / norm Ib = NXfield(hist / norm, name='S(Q,E)') Qb = NXfield(Qb[:-1] + dQ / 2., name='Q') Eb = NXfield(Eb[:-1] + dE / 2., name='E') result = NXdata(Ib, (Eb, Qb)) if self.entry.data.nxerrors: result.errors = NXfield(err) return result def round(self, x, prec=2, base=.05): return round(base * round(float(x) / base), prec) def plot_data(self): self.convert_QE().plot() def save_data(self): self.entry['sqe'] = self.convert_QE()
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()
class LatticeDialog(BaseDialog): def __init__(self, parent=None): super(LatticeDialog, self).__init__(parent) self.select_entry(self.choose_entry) self.refine = NXRefine() self.parameters = GridParameters() self.parameters.add('symmetry', self.refine.symmetries, 'Symmetry', slot=self.set_lattice_parameters) self.parameters.add('centring', self.refine.centrings, 'Cell Centring') self.parameters.add('a', self.refine.a, 'Unit Cell - a (Ang)', slot=self.set_lattice_parameters) self.parameters.add('b', self.refine.b, 'Unit Cell - b (Ang)', slot=self.set_lattice_parameters) self.parameters.add('c', self.refine.c, 'Unit Cell - c (Ang)', slot=self.set_lattice_parameters) self.parameters.add('alpha', self.refine.alpha, 'Unit Cell - alpha (deg)', slot=self.set_lattice_parameters) self.parameters.add('beta', self.refine.beta, 'Unit Cell - beta (deg)', slot=self.set_lattice_parameters) self.parameters.add('gamma', self.refine.gamma, 'Unit Cell - gamma (deg)', slot=self.set_lattice_parameters) self.parameters['symmetry'].value = self.refine.symmetry self.parameters['centring'].value = self.refine.centring action_buttons = self.action_buttons(('Plot', self.plot_lattice), ('Save', self.write_parameters)) self.set_layout(self.entry_layout, self.parameters.grid(), action_buttons, self.close_buttons()) self.set_title('Defining Lattice') def choose_entry(self): self.refine = NXRefine(self.entry) self.update_parameters() def update_parameters(self): self.parameters['symmetry'].value = self.refine.symmetry self.parameters['centring'].value = self.refine.centring self.parameters['a'].value = self.refine.a self.parameters['b'].value = self.refine.b self.parameters['c'].value = self.refine.c self.parameters['alpha'].value = self.refine.alpha self.parameters['beta'].value = self.refine.beta self.parameters['gamma'].value = self.refine.gamma def get_symmetry(self): return self.parameters['symmetry'].value def get_centring(self): return self.parameters['centring'].value def get_lattice_parameters(self): return (self.parameters['a'].value, self.parameters['b'].value, self.parameters['c'].value, self.parameters['alpha'].value, self.parameters['beta'].value, self.parameters['gamma'].value) def set_lattice_parameters(self): symmetry = self.get_symmetry() if symmetry == 'cubic': self.parameters['b'].value = self.parameters['a'].value self.parameters['c'].value = self.parameters['a'].value self.parameters['alpha'].value = 90.0 self.parameters['beta'].value = 90.0 self.parameters['gamma'].value = 90.0 elif symmetry == 'tetragonal': self.parameters['b'].value = self.parameters['a'].value self.parameters['alpha'].value = 90.0 self.parameters['beta'].value = 90.0 self.parameters['gamma'].value = 90.0 elif symmetry == 'orthorhombic': self.parameters['alpha'].value = 90.0 self.parameters['beta'].value = 90.0 self.parameters['gamma'].value = 90.0 elif symmetry == 'hexagonal': self.parameters['b'].value = self.parameters['a'].value self.parameters['alpha'].value = 90.0 self.parameters['beta'].value = 90.0 self.parameters['gamma'].value = 120.0 elif symmetry == 'monoclinic': self.parameters['alpha'].value = 90.0 self.parameters['gamma'].value = 90.0 def get_parameters(self): (self.refine.a, self.refine.b, self.refine.c, self.refine.alpha, self.refine.beta, self.refine.gamma) = ( self.get_lattice_parameters()) self.refine.symmetry = self.get_symmetry() self.refine.centring = self.get_centring() def plot_lattice(self): try: self.get_parameters() self.plot_peaks(self.refine.xp, self.refine.yp) polar_min, polar_max = plotview.xaxis.get_limits() self.plot_rings(polar_max) except NeXusError as error: report_error('Plotting Lattice', error) def write_parameters(self): try: self.get_parameters() self.refine.write_parameters() except NeXusError as error: report_error('Defining Lattice', error) def plot_peaks(self, x, y): try: polar_angles, azimuthal_angles = self.refine.calculate_angles(x, y) if polar_angles[0] > polar_angles[-1]: polar_angles = polar_angles[::-1] azimuthal_angles = azimuthal_angles[::-1] azimuthal_field = NXfield(azimuthal_angles, name='azimuthal_angle') azimuthal_field.long_name = 'Azimuthal Angle' polar_field = NXfield(polar_angles, name='polar_angle') polar_field.long_name = 'Polar Angle' plotview = get_plotview() plotview.plot(NXdata(azimuthal_field, polar_field, title='Peak Angles')) except NeXusError as error: report_error('Plotting Lattice', error) def plot_rings(self, polar_max=None): if polar_max is None: polar_max = self.refine.polar_max peaks = self.refine.calculate_rings(polar_max) plotview = get_plotview() plotview.vlines(peaks, colors='r', linestyles='dotted') plotview.draw()
class FindDialog(BaseDialog): def __init__(self, parent=None): super(FindDialog, self).__init__(parent) self.select_entry(self.choose_entry) try: threshold = np.float32(self.entry.data.attrs["maximum"]) / 20 max_frame = np.int32(len(self.entry.data.nxaxes[0])) except Exception: threshold = 5000 max_frame = 0 self.parameters = GridParameters() self.parameters.add("threshold", threshold, "Threshold") self.parameters.add("min", 0, "First Frame") self.parameters.add("max", max_frame, "Last Frame") self.parameters.add("pixel_tolerance", 50, "Pixel Tolerance") self.parameters.add("frame_tolerance", 10, "Frame Tolerance") find_layout = QtGui.QHBoxLayout() self.find_button = QtGui.QPushButton("Find Peaks") self.find_button.clicked.connect(self.find_peaks) self.peak_count = QtGui.QLabel() self.peak_count.setVisible(False) find_layout.addStretch() find_layout.addWidget(self.find_button) find_layout.addWidget(self.peak_count) find_layout.addStretch() self.set_layout(self.entry_layout, self.parameters.grid(), find_layout) self.set_title("Find Peaks") self.npk = 0 try: self.parameters["max"].value = self.entry["data"].nxsignal.shape[0] self.parameters["threshold"].value = self.entry["data"].attrs["maximum"] / 20 except Exception: pass def choose_entry(self): try: self.parameters["threshold"].value = self.entry["data"].attrs["maximum"] / 20 self.parameters["max"].value = len(self.entry.data.nxaxes[0]) except Exception: pass def get_threshold(self): return self.parameters["threshold"].value def get_limits(self): return np.int32(self.parameters["min"].value), np.int32(self.parameters["max"].value) def get_tolerance(self): """ Return pixel and frame tolerances from the text boxes. Note that the pixel tolerance is squared to save square-root calculations in peak comparisons. """ return (self.parameters["pixel_tolerance"].value, self.parameters["frame_tolerance"].value) def find_peaks(self): field = self.entry["data"].nxsignal try: self.mask = self.entry["instrument/detector/pixel_mask"] except NeXusError: self.mask = None self.layout.removeWidget(self.find_button) self.find_button.setVisible(False) if len(field.shape) == 2: self.layout.addWidget(self.close_buttons(save=True)) elif len(field.shape) > 2: self.layout.addLayout(self.progress_layout(save=True)) threshold = self.get_threshold() self.blim = np.zeros(field.shape[-2:], np.int32) self.verbose = 0 lio = labelimage(field.shape[-2:], flipper=flip1) allpeaks = [] if len(field.shape) == 2: res = None else: chunk_size = field.nxfile[field.nxpath].chunks[0] z_min, z_max = self.get_limits() pixel_tolerance, frame_tolerance = self.get_tolerance() self.progress_bar.setRange(z_min, z_max) for i in range(0, field.shape[0], chunk_size): try: if i + chunk_size > z_min and i < z_max: self.progress_bar.setValue(i) self.update_progress() v = field[i : i + chunk_size, :, :].nxdata for j in range(chunk_size): if i + j >= z_min and i + j <= z_max: omega = np.float32(i + j) lio.peaksearch(v[j], threshold, omega) if lio.res is not None: blob_moments(lio.res) for k in range(lio.res.shape[0]): res = lio.res[k] peak = NXpeak( res[0], res[22], res[23], res[24], omega, res[27], res[26], res[29], threshold, pixel_tolerance, frame_tolerance, ) if peak.isvalid(self.mask): allpeaks.append(peak) except IndexError as error: pass if not allpeaks: self.reject() report_error("Finding peaks", "No peaks found") allpeaks = sorted(allpeaks) self.progress_bar.reset() self.progress_bar.setRange(z_min, z_max) merged_peaks = [] for z in range(z_min, z_max + 1): self.progress_bar.setValue(z) self.update_progress() frame = [peak for peak in allpeaks if peak.z == z] if not merged_peaks: merged_peaks.extend(frame) else: for peak1 in frame: combined = False for peak2 in last_frame: if peak1 == peak2: for idx in range(len(merged_peaks)): if peak1 == merged_peaks[idx]: break peak1.combine(merged_peaks[idx]) merged_peaks[idx] = peak1 combined = True break if not combined: reversed_peaks = [p for p in reversed(merged_peaks) if p.z >= peak1.z - frame_tolerance] for peak2 in reversed_peaks: if peak1 == peak2: for idx in range(len(merged_peaks)): if peak1 == merged_peaks[idx]: break peak1.combine(merged_peaks[idx]) merged_peaks[idx] = peak1 combined = True break if not combined: merged_peaks.append(peak1) if frame: last_frame = frame merged_peaks = sorted(merged_peaks) for peak in merged_peaks: peak.merge() merged_peaks = sorted(merged_peaks) self.peaks = merged_peaks self.progress_bar.setVisible(False) self.peak_count.setText("%s peaks found" % len(self.peaks)) self.peak_count.setVisible(True) def accept(self): try: if "peaks" in self.entry.entries: del self.entry["peaks"] self.entry.peaks = NXdata() shape = (len(self.peaks),) self.entry.peaks.npixels = NXfield([peak.np for peak in self.peaks], dtype=np.float32) self.entry.peaks.intensity = NXfield([peak.intensity for peak in self.peaks], dtype=np.float32) self.entry.peaks.x = NXfield([peak.x for peak in self.peaks], dtype=np.float32) self.entry.peaks.y = NXfield([peak.y for peak in self.peaks], dtype=np.float32) self.entry.peaks.z = NXfield([peak.z for peak in self.peaks], dtype=np.float32) self.entry.peaks.sigx = NXfield([peak.sigx for peak in self.peaks], dtype=np.float32) self.entry.peaks.sigy = NXfield([peak.sigy for peak in self.peaks], dtype=np.float32) self.entry.peaks.covxy = NXfield([peak.covxy for peak in self.peaks], dtype=np.float32) super(FindDialog, self).accept() except NeXusError as error: report_error("Finding peaks", error)