def sort(self, recursive=False, key=None, reverse=False): self._set = OrderedSet( sorted(self._items.keys(), key=key, reverse=reverse) \ + sorted(self.loops.keys(), key=key, reverse=reverse)) if recursive: for l in self.loops.values(): l.sort(key=key, reverse=reverse)
def imagesets(self): ''' Get a list of the unique imagesets (includes None). This returns unique complete sets rather than partial. ''' return list( OrderedSet([e.imageset for e in self if e.imageset is not None]))
def goniometers(self): ''' Get a list of the unique goniometers (includes None). ''' return list(OrderedSet(e.goniometer for e in self))
def detectors(self): ''' Get a list of the unique detectors (includes None). ''' return list(OrderedSet(e.detector for e in self))
def beams(self): ''' Get a list of the unique beams (includes None). ''' return list(OrderedSet(e.beam for e in self))
def __init__(self): self._items = {} self.loops = {} self._set = OrderedSet() self.keys_lower = {}
def run(args): from dials.util.options import OptionParser from dials.util.options import flatten_experiments from dials.util.options import flatten_datablocks from dials.util.options import flatten_reflections import libtbx.load_env usage = "%s [options] datablock.json | experiments.json | image_*.cbf" %( libtbx.env.dispatcher_name) parser = OptionParser( usage=usage, phil=phil_scope, read_experiments=True, read_datablocks=True, read_datablocks_from_images=True, read_reflections=True, check_format=False, epilog=help_message) params, options = parser.parse_args(show_diff_phil=True) experiments = flatten_experiments(params.input.experiments) datablocks = flatten_datablocks(params.input.datablock) reflections = flatten_reflections(params.input.reflections) if len(datablocks) == 0 and len(experiments) == 0 and len(reflections) == 0: parser.print_help() exit() for i_expt, expt in enumerate(experiments): print "Experiment %i:" %i_expt print str(expt.detector) print 'Max resolution (at corners): %f' % ( expt.detector.get_max_resolution(expt.beam.get_s0())) print 'Max resolution (inscribed): %f' % ( expt.detector.get_max_inscribed_resolution(expt.beam.get_s0())) print '' panel_id, (x, y) = beam_centre(expt.detector, expt.beam) if panel_id >= 0 and x is not None and y is not None: if len(expt.detector) > 1: beam_centre_str = "Beam centre: panel %i, (%.2f,%.2f)" %(panel_id, x, y) else: beam_centre_str = "Beam centre: (%.2f,%.2f)" %(x, y) else: beam_centre_str = "" print str(expt.beam) + beam_centre_str + '\n' if expt.scan is not None: print expt.scan if expt.goniometer is not None: print expt.goniometer expt.crystal.show(show_scan_varying=params.show_scan_varying) if expt.crystal.num_scan_points: from scitbx.array_family import flex from cctbx import uctbx abc = flex.vec3_double() angles = flex.vec3_double() for n in range(expt.crystal.num_scan_points): a, b, c, alpha, beta, gamma = expt.crystal.get_unit_cell_at_scan_point(n).parameters() abc.append((a, b, c)) angles.append((alpha, beta, gamma)) a, b, c = abc.mean() alpha, beta, gamma = angles.mean() mean_unit_cell = uctbx.unit_cell((a, b, c, alpha, beta, gamma)) print " Average unit cell: %s" %mean_unit_cell print for datablock in datablocks: if datablock.format_class() is not None: print 'Format: %s' %datablock.format_class() imagesets = datablock.extract_imagesets() for imageset in imagesets: try: print imageset.get_template() except Exception: pass detector = imageset.get_detector() print str(detector) + 'Max resolution: %f\n' %( detector.get_max_resolution(imageset.get_beam().get_s0())) if params.show_panel_distance: for ipanel, panel in enumerate(detector): from scitbx import matrix fast = matrix.col(panel.get_fast_axis()) slow = matrix.col(panel.get_slow_axis()) normal = fast.cross(slow) origin = matrix.col(panel.get_origin()) distance = origin.dot(normal) fast_origin = - (origin - distance * normal).dot(fast) slow_origin = - (origin - distance * normal).dot(slow) print 'Panel %d: distance %.2f origin %.2f %.2f' % \ (ipanel, distance, fast_origin, slow_origin) print '' panel_id, (x, y) = beam_centre(detector, imageset.get_beam()) if panel_id >= 0 and x is not None and y is not None: if len(detector) > 1: beam_centre_str = "Beam centre: panel %i, (%.2f,%.2f)" %(panel_id, x, y) else: beam_centre_str = "Beam centre: (%.2f,%.2f)" %(x, y) else: beam_centre_str = "" print str(imageset.get_beam()) + beam_centre_str + '\n' if imageset.get_scan() is not None: print imageset.get_scan() if imageset.get_goniometer() is not None: print imageset.get_goniometer() from libtbx.containers import OrderedDict, OrderedSet formats = OrderedDict([ ('miller_index', '%i, %i, %i'), ('d','%.2f'), ('dqe','%.3f'), ('id','%i'), ('imageset_id','%i'), ('panel','%i'), ('flags', '%i'), ('background.mean', '%.1f'), ('background.dispersion','%.1f'), ('background.mse', '%.1f'), ('background.sum.value', '%.1f'), ('background.sum.variance', '%.1f'), ('intensity.prf.value','%.1f'), ('intensity.prf.variance','%.1f'), ('intensity.sum.value','%.1f'), ('intensity.sum.variance','%.1f'), ('intensity.cor.value','%.1f'), ('intensity.cor.variance','%.1f'), ('lp','%.3f'), ('num_pixels.background','%i'), ('num_pixels.background_used','%i'), ('num_pixels.foreground','%i'), ('num_pixels.valid','%i'), ('partial_id','%i'), ('partiality','%.4f'), ('profile.correlation','%.3f'), ('profile.rmsd','%.3f'), ('xyzcal.mm','%.2f, %.2f, %.2f'), ('xyzcal.px','%.2f, %.2f, %.2f'), ('delpsical.rad','%.3f'), ('delpsical2','%.3f'), ('xyzobs.mm.value','%.2f, %.2f, %.2f'), ('xyzobs.mm.variance','%.4e, %.4e, %.4e'), ('xyzobs.px.value','%.2f, %.2f, %.2f'), ('xyzobs.px.variance','%.4f, %.4f, %.4f'), ('s1','%.4f, %.4f, %.4f'), ('rlp','%.4f, %.4f, %.4f'), ('zeta','%.3f'), ('x_resid','%.3f'), ('x_resid2','%.3f'), ('y_resid','%.3f'), ('y_resid2','%.3f'), ]) for rlist in reflections: from cctbx.array_family import flex print print "Reflection list contains %i reflections" %(len(rlist)) rows = [["Column", "min", "max", "mean"]] for k, col in rlist.cols(): if type(col) in (flex.double, flex.int, flex.size_t): if type(col) in (flex.int, flex.size_t): col = col.as_double() rows.append([k, formats[k] %flex.min(col), formats[k] %flex.max(col), formats[k]%flex.mean(col)]) elif type(col) in (flex.vec3_double, flex.miller_index): if type(col) == flex.miller_index: col = col.as_vec3_double() rows.append([k, formats[k] %col.min(), formats[k] %col.max(), formats[k]%col.mean()]) from libtbx import table_utils print table_utils.format(rows, has_header=True, prefix="| ", postfix=" |") intensity_keys = ( 'miller_index', 'd', 'intensity.prf.value', 'intensity.prf.variance', 'intensity.sum.value', 'intensity.sum.variance', 'background.mean', 'profile.correlation', 'profile.rmsd' ) profile_fit_keys = ('miller_index', 'd',) centroid_keys = ( 'miller_index', 'd', 'xyzcal.mm', 'xyzcal.px', 'xyzobs.mm.value', 'xyzobs.mm.variance', 'xyzobs.px.value', 'xyzobs.px.variance' ) keys_to_print = OrderedSet() if params.show_intensities: for k in intensity_keys: keys_to_print.add(k) if params.show_profile_fit: for k in profile_fit_keys: keys_to_print.add(k) if params.show_centroids: for k in centroid_keys: keys_to_print.add(k) if params.show_all_reflection_data: for k in formats: keys_to_print.add(k) def format_column(key, data, format_strings=None): if isinstance(data, flex.vec3_double): c_strings = [c.as_string(format_strings[i].strip()) for i, c in enumerate(data.parts())] elif isinstance(data, flex.miller_index): c_strings = [c.as_string(format_strings[i].strip()) for i, c in enumerate(data.as_vec3_double().parts())] elif isinstance(data, flex.size_t): c_strings = [data.as_int().as_string(format_strings[0].strip())] else: c_strings = [data.as_string(format_strings[0].strip())] column = flex.std_string() max_element_lengths = [c.max_element_length() for c in c_strings] for i in range(len(c_strings[0])): column.append(('%%%is' %len(key)) %', '.join( ('%%%is' %max_element_lengths[j]) %c_strings[j][i] for j in range(len(c_strings)))) return column if keys_to_print: keys = [k for k in keys_to_print if k in rlist] rows = [keys] max_reflections = len(rlist) if params.max_reflections is not None: max_reflections = min(len(rlist), params.max_reflections) columns = [] for k in keys: columns.append(format_column(k, rlist[k], format_strings=formats[k].split(','))) print print "Printing %i of %i reflections:" %(max_reflections, len(rlist)) for j in range(len(columns)): key = keys[j] width = max(len(key), columns[j].max_element_length()) print ("%%%is" %width) %key, print for i in range(max_reflections): for j in range(len(columns)): print columns[j][i], print return
def scaling_models(self): ''' Get a list of the unique scaling models (includes None). ''' return list(OrderedSet(e.scaling_model for e in self))
def show_reflections(reflections, show_intensities=False, show_profile_fit=False, show_centroids=False, show_all_reflection_data=False, show_flags=False, max_reflections=None): text = [] import collections from libtbx.containers import OrderedSet formats = collections.OrderedDict(( ('miller_index', '%i, %i, %i'), ('d', '%.2f'), ('qe', '%.3f'), ('id', '%i'), ('imageset_id', '%i'), ('panel', '%i'), ('flags', '%i'), ('background.mean', '%.1f'), ('background.dispersion', '%.1f'), ('background.mse', '%.1f'), ('background.sum.value', '%.1f'), ('background.sum.variance', '%.1f'), ('intensity.prf.value', '%.1f'), ('intensity.prf.variance', '%.1f'), ('intensity.sum.value', '%.1f'), ('intensity.sum.variance', '%.1f'), ('intensity.cor.value', '%.1f'), ('intensity.cor.variance', '%.1f'), ('lp', '%.3f'), ('num_pixels.background', '%i'), ('num_pixels.background_used', '%i'), ('num_pixels.foreground', '%i'), ('num_pixels.valid', '%i'), ('partial_id', '%i'), ('partiality', '%.4f'), ('profile.correlation', '%.3f'), ('profile.rmsd', '%.3f'), ('xyzcal.mm', '%.2f, %.2f, %.2f'), ('xyzcal.px', '%.2f, %.2f, %.2f'), ('delpsical.rad', '%.3f'), ('delpsical2', '%.3f'), ('delpsical.weights', '%.3f'), ('xyzobs.mm.value', '%.2f, %.2f, %.2f'), ('xyzobs.mm.variance', '%.4e, %.4e, %.4e'), ('xyzobs.px.value', '%.2f, %.2f, %.2f'), ('xyzobs.px.variance', '%.4f, %.4f, %.4f'), ('s1', '%.4f, %.4f, %.4f'), ('shoebox', '%.1f'), ('rlp', '%.4f, %.4f, %.4f'), ('zeta', '%.3f'), ('x_resid', '%.3f'), ('x_resid2', '%.3f'), ('y_resid', '%.3f'), ('y_resid2', '%.3f'), ('kapton_absorption_correction', '%.3f'), ('kapton_absorption_correction_sigmas', '%.3f'), )) for rlist in reflections: from dials.array_family import flex from dials.algorithms.shoebox import MaskCode foreground_valid = MaskCode.Valid | MaskCode.Foreground text.append('') text.append('Reflection list contains %i reflections' % (len(rlist))) if len(rlist) == 0: continue rows = [["Column", "min", "max", "mean"]] for k, col in rlist.cols(): if k in formats and not "%" in formats[k]: # Allow blanking out of entries that wouldn't make sense rows.append([k, formats[k], formats[k], formats[k]]) elif type(col) in (flex.double, flex.int, flex.size_t): if type(col) in (flex.int, flex.size_t): col = col.as_double() rows.append([ k, formats[k] % flex.min(col), formats[k] % flex.max(col), formats[k] % flex.mean(col) ]) elif type(col) in (flex.vec3_double, flex.miller_index): if isinstance(col, flex.miller_index): col = col.as_vec3_double() rows.append([ k, formats[k] % col.min(), formats[k] % col.max(), formats[k] % col.mean() ]) elif isinstance(col, flex.shoebox): rows.append([k, "", "", ""]) si = col.summed_intensity().observed_value() rows.append([ " summed I", formats[k] % flex.min(si), formats[k] % flex.max(si), formats[k] % flex.mean(si) ]) x1, x2, y1, y2, z1, z2 = col.bounding_boxes().parts() bbox_sizes = ((z2 - z1) * (y2 - y1) * (x2 - x1)).as_double() rows.append([ " N pix", formats[k] % flex.min(bbox_sizes), formats[k] % flex.max(bbox_sizes), formats[k] % flex.mean(bbox_sizes) ]) fore_valid = col.count_mask_values( foreground_valid).as_double() rows.append([ " N valid foreground pix", formats[k] % flex.min(fore_valid), formats[k] % flex.max(fore_valid), formats[k] % flex.mean(fore_valid) ]) text.append( table_utils.format(rows, has_header=True, prefix="| ", postfix=" |")) if show_flags: text.append(_create_flag_count_table(rlist)) intensity_keys = ('miller_index', 'd', 'intensity.prf.value', 'intensity.prf.variance', 'intensity.sum.value', 'intensity.sum.variance', 'background.mean', 'profile.correlation', 'profile.rmsd') profile_fit_keys = ( 'miller_index', 'd', ) centroid_keys = ('miller_index', 'd', 'xyzcal.mm', 'xyzcal.px', 'xyzobs.mm.value', 'xyzobs.mm.variance', 'xyzobs.px.value', 'xyzobs.px.variance') keys_to_print = OrderedSet() if show_intensities: for k in intensity_keys: keys_to_print.add(k) if show_profile_fit: for k in profile_fit_keys: keys_to_print.add(k) if show_centroids: for k in centroid_keys: keys_to_print.add(k) if show_all_reflection_data: for k in formats: keys_to_print.add(k) def format_column(key, data, format_strings=None): if isinstance(data, flex.vec3_double): c_strings = [ c.as_string(format_strings[i].strip()) for i, c in enumerate(data.parts()) ] elif isinstance(data, flex.miller_index): c_strings = [ c.as_string(format_strings[i].strip()) for i, c in enumerate(data.as_vec3_double().parts()) ] elif isinstance(data, flex.size_t): c_strings = [data.as_int().as_string(format_strings[0].strip())] elif isinstance(data, flex.shoebox): x1, x2, y1, y2, z1, z2 = data.bounding_boxes().parts() bbox_sizes = ((z2 - z1) * (y2 - y1) * (x2 - x1)).as_double() c_strings = [bbox_sizes.as_string(format_strings[0].strip())] key += " (N pix)" else: c_strings = [data.as_string(format_strings[0].strip())] column = flex.std_string() max_element_lengths = [c.max_element_length() for c in c_strings] for i in range(len(c_strings[0])): column.append(('%%%is' % len(key)) % ', '.join( ('%%%is' % max_element_lengths[j]) % c_strings[j][i] for j in range(len(c_strings)))) return column if keys_to_print: keys = [k for k in keys_to_print if k in rlist] rows = [keys] if max_reflections is not None: max_reflections = min(len(rlist), max_reflections) columns = [] for k in keys: columns.append( format_column(k, rlist[k], format_strings=formats[k].split(','))) text.append('') text.append('Printing %i of %i reflections:' % (max_reflections, len(rlist))) line = [] for j in range(len(columns)): key = keys[j] if key == 'shoebox': key += " (N pix)" width = max(len(key), columns[j].max_element_length()) line.append('%%%is' % width % key) text.append(' '.join(line)) for i in range(max_reflections): line = [] for j in range(len(columns)): line.append(columns[j][i]) text.append(' '.join(line)) return '\n'.join(text)
def profiles(self): ''' Get a list of the unique profile models (includes None). ''' from libtbx.containers import OrderedSet return list(OrderedSet([e.profile for e in self]))
def crystals(self): ''' Get a list of the unique crystals (includes None). ''' from libtbx.containers import OrderedSet return list(OrderedSet([e.crystal for e in self]))
def goniometers(self): ''' Get a list of the unique goniometers (includes None). ''' from libtbx.containers import OrderedSet return list(OrderedSet([e.goniometer for e in self]))
def __init__(self, cif_block, base_array_info=None): crystal_symmetry_builder.__init__(self, cif_block) if base_array_info is not None: self.crystal_symmetry = self.crystal_symmetry.join_symmetry( other_symmetry=base_array_info.crystal_symmetry_from_file, force=True) self._arrays = OrderedDict() if base_array_info is None: base_array_info = miller.array_info(source_type="cif") refln_containing_loops = self.get_miller_indices_containing_loops() for self.indices, refln_loop in refln_containing_loops: self.wavelength_id_array = None self.crystal_id_array = None self.scale_group_array = None wavelength_ids = [None] crystal_ids = [None] scale_groups = [None] for key, value in refln_loop.iteritems(): # need to get these arrays first if (key.endswith('wavelength_id') or key.endswith('crystal_id') or key.endswith('scale_group_code')): data = as_int_or_none_if_all_question_marks( value, column_name=key) if data is None: continue counts = data.counts() if len(counts) == 1: continue array = miller.array( miller.set(self.crystal_symmetry, self.indices).auto_anomalous(), data) if key.endswith('wavelength_id'): self.wavelength_id_array = array wavelength_ids = counts.keys() elif key.endswith('crystal_id'): self.crystal_id_array = array crystal_ids = counts.keys() elif key.endswith('scale_group_code'): self.scale_group_array = array scale_groups = counts.keys() for label, value in sorted(refln_loop.items()): for w_id in wavelength_ids: for crys_id in crystal_ids: for scale_group in scale_groups: if 'index_' in label: continue key = label labels = [label] if (key.endswith('wavelength_id') or key.endswith('crystal_id') or key.endswith('scale_group_code')): w_id = None crys_id = None scale_group = None key_suffix = '' if w_id is not None: key_suffix += '_%i' % w_id labels.insert(0, "wavelength_id=%i" % w_id) if crys_id is not None: key_suffix += '_%i' % crys_id labels.insert(0, "crystal_id=%i" % crys_id) if scale_group is not None: key_suffix += '_%i' % scale_group labels.insert( 0, "scale_group_code=%i" % scale_group) key += key_suffix sigmas = None if key in self._arrays: continue array = self.flex_std_string_as_miller_array( value, wavelength_id=w_id, crystal_id=crys_id, scale_group_code=scale_group) if array is None: continue if '_sigma' in key: sigmas_label = label key = None for suffix in ('', '_meas', '_calc'): if sigmas_label.replace( '_sigma', suffix) in refln_loop: key = sigmas_label.replace( '_sigma', suffix) + key_suffix break if key is None: key = sigmas_label + key_suffix elif key in self._arrays and self._arrays[ key].sigmas() is None: sigmas = array array = self._arrays[key] check_array_sizes(array, sigmas, key, sigmas_label) sigmas = as_flex_double( sigmas, sigmas_label) array.set_sigmas(sigmas.data()) info = array.info() array.set_info( info.customized_copy( labels=info.labels + [sigmas_label])) continue elif 'PHWT' in key: phwt_label = label fwt_label = label.replace('PHWT', 'FWT') if fwt_label not in refln_loop: continue phwt_array = array if fwt_label in self._arrays: array = self._arrays[fwt_label] check_array_sizes(array, phwt_array, fwt_label, phwt_label) phases = as_flex_double( phwt_array, phwt_label) info = array.info() array = array.phase_transfer(phases, deg=True) array.set_info( info.customized_copy( labels=info.labels + [phwt_label])) self._arrays[fwt_label] = array continue elif 'HL_' in key: hl_letter = key[key.find('HL_') + 3] hl_key = 'HL_' + hl_letter key = key.replace(hl_key, 'HL_A') if key in self._arrays: continue # this array is already dealt with hl_labels = [ label.replace(hl_key, 'HL_' + letter) for letter in 'ABCD' ] hl_keys = [ key.replace(hl_key, 'HL_' + letter) for letter in 'ABCD' ] hl_values = [ cif_block.get(hl_key) for hl_key in hl_labels ] if hl_values.count(None) == 0: selection = self.get_selection( hl_values[0], wavelength_id=w_id, crystal_id=crys_id, scale_group_code=scale_group) hl_values = [ as_double_or_none_if_all_question_marks( hl.select(selection), column_name=lab) for hl, lab in zip( hl_values, hl_labels) ] array = miller.array( miller.set( self.crystal_symmetry, self.indices.select( selection)).auto_anomalous(), flex.hendrickson_lattman(*hl_values)) labels = labels[:-1] + hl_labels elif '.B_' in key or '_B_' in key: if '.B_' in key: key, key_b = key.replace('.B_', '.A_'), key label, label_b = label.replace( '.B_', '.A_'), label elif '_B_' in key: key, key_b = key.replace('_B', '_A'), key label, label_b = label.replace('_B', '_A'), label if key in refln_loop and key_b in refln_loop: b_part = array.data() if key in self._arrays: info = self._arrays[key].info() a_part = self._arrays[key].data() self._arrays[key] = self._arrays[ key].array( data=flex.complex_double( a_part, b_part)) self._arrays[key].set_info( info.customized_copy( labels=info.labels + [key_b])) continue elif ('phase_' in key and not key.endswith('_meas') and self.crystal_symmetry.space_group() is not None): alt_key1 = label.replace('phase_', 'F_') alt_key2 = alt_key1 + '_au' if alt_key1 in refln_loop: phase_key = label key = alt_key1 + key_suffix elif alt_key2 in refln_loop: phase_key = label key = alt_key2 + key_suffix else: phase_key = None if phase_key is not None: phases = array.data() if key in self._arrays: array = self._arrays[key] array = as_flex_double(array, key) check_array_sizes( array, phases, key, phase_key) info = self._arrays[key].info() self._arrays[ key] = array.phase_transfer( phases, deg=True) self._arrays[key].set_info( info.customized_copy( labels=info.labels + [phase_key])) else: array = self.flex_std_string_as_miller_array( refln_loop[label], wavelength_id=w_id, crystal_id=crys_id, scale_group_code=scale_group) check_array_sizes( array, phases, key, phase_key) array.phase_transfer(phases, deg=True) labels = labels + [label, phase_key] if base_array_info.labels is not None: labels = base_array_info.labels + labels def rstrip_substrings(string, substrings): for substr in substrings: if substr == '': continue if string.endswith(substr): string = string[:-len(substr)] return string # determine observation type stripped_key = rstrip_substrings( key, [ key_suffix, '_au', '_meas', '_calc', '_plus', '_minus' ]) if (stripped_key.endswith('F_squared') or stripped_key.endswith('intensity') or stripped_key.endswith('.I') or stripped_key.endswith('_I')) and ( array.is_real_array() or array.is_integer_array()): array.set_observation_type_xray_intensity() elif (stripped_key.endswith('F') and (array.is_real_array() or array.is_integer_array())): array.set_observation_type_xray_amplitude() if (array.is_xray_amplitude_array() or array.is_xray_amplitude_array()): # e.g. merge_equivalents treats integer arrays differently, so must # convert integer observation arrays here to be safe if isinstance(array.data(), flex.int): array = array.customized_copy( data=array.data().as_double()) array.set_info( base_array_info.customized_copy(labels=labels)) self._arrays.setdefault(key, array) for key, array in self._arrays.copy().iteritems(): if (key.endswith('_minus') or '_minus_' in key or key.endswith('_plus') or '_plus_' in key): if '_minus' in key: minus_key = key plus_key = key.replace('_minus', '_plus') elif '_plus' in key: plus_key = key minus_key = key.replace('_plus', '_minus') if plus_key in self._arrays and minus_key in self._arrays: plus_array = self._arrays.pop(plus_key) minus_array = self._arrays.pop(minus_key) minus_array = minus_array.customized_copy( indices=-minus_array.indices()).set_info( minus_array.info()) array = plus_array.concatenate( minus_array, assert_is_similar_symmetry=False) array = array.customized_copy(anomalous_flag=True) array.set_info( minus_array.info().customized_copy(labels=list( OrderedSet(plus_array.info().labels + minus_array.info().labels)))) array.set_observation_type(plus_array.observation_type()) self._arrays.setdefault(key, array) if len(self._arrays) == 0: raise CifBuilderError("No reflection data present in cif block")
def __init__(self, experiment, vectors, frame='reciprocal', mode='main'): from libtbx.utils import Sorry self.experiment = experiment self.vectors = vectors self.frame = frame self.mode = mode gonio = experiment.goniometer scan = experiment.scan self.s0 = matrix.col(self.experiment.beam.get_s0()) self.rotation_axis = matrix.col(gonio.get_rotation_axis()) from dxtbx.model import MultiAxisGoniometer if not isinstance(gonio, MultiAxisGoniometer): raise Sorry('Only MultiAxisGoniometer models supported') axes = gonio.get_axes() if len(axes) != 3: raise Sorry('Only 3-axis goniometers supported') e1, e2, e3 = (matrix.col(e) for e in reversed(axes)) fixed_rotation = matrix.sqr(gonio.get_fixed_rotation()) setting_rotation = matrix.sqr(gonio.get_setting_rotation()) rotation_axis = matrix.col(gonio.get_rotation_axis_datum()) rotation_matrix = rotation_axis.axis_and_angle_as_r3_rotation_matrix( experiment.scan.get_oscillation()[0], deg=True) from dials.algorithms.refinement import rotation_decomposition results = OrderedDict() # from https://github.com/legrandp/xdsme/blob/master/XOalign/XOalign.py#L427 # referential_permutations sign permutations for four permutations of # parallel/antiparallel (rotation axis & beam) # y1 // e1, y2 // beamVector; y1 anti// e1, y2 // beamVector # y1 // e1, y2 anti// beamVector; y1 anti// e1, y2 anti// beamVector ex = matrix.col((1, 0, 0)) ey = matrix.col((0, 1, 0)) ez = matrix.col((0, 0, 1)) referential_permutations = ([ ex, ey, ez], [-ex, -ey, ez], [ ex, -ey, -ez], [-ex, ey, -ez]) for (v1_, v2_) in self.vectors: results[(v1_, v2_)] = OrderedDict() space_group = self.experiment.crystal.get_space_group() for smx in list(space_group.smx())[:]: results[(v1_, v2_)][smx] = [] crystal = copy.deepcopy(self.experiment.crystal) cb_op = sgtbx.change_of_basis_op(smx) crystal = crystal.change_basis(cb_op) # Goniometer datum setting [D] at which the orientation was determined D = (setting_rotation * rotation_matrix * fixed_rotation).inverse() # The setting matrix [U] will vary with the datum setting according to # [U] = [D] [U0] U = matrix.sqr(crystal.get_U()) # XXX In DIALS recorded U is equivalent to U0 - D is applied to U inside # prediction U0 = U B = matrix.sqr(crystal.get_B()) if self.frame == 'direct': B = B.inverse().transpose() v1_0 = U0 * B * v1_ v2_0 = U0 * B * v2_ #c (b) The laboratory frame vectors l1 & l2 are normally specified with the #c MODE command: MODE MAIN (the default) sets l1 (along which v1 will be #c placed) along the principle goniostat axis e1 (Omega), and l2 along #c the beam s0. This allows rotation for instance around a principle axis. #c The other mode is MODE CUSP, which puts l1 (v1) perpendicular to the #c beam (s0) and the e1 (Omega) axis, and l2 (v2) in the plane containing #c l1 & e1 (ie l1 = e1 x s0, l2 = e1). if self.mode == 'cusp': l1 = self.rotation_axis.cross(self.s0) l2 = self.rotation_axis else: l1 = self.rotation_axis.normalize() l3 = l1.cross(self.s0).normalize() l2 = l1.cross(l3) for perm in referential_permutations: S = matrix.sqr(perm[0].elems + perm[1].elems + perm[2].elems) from rstbx.cftbx.coordinate_frame_helpers import align_reference_frame R = align_reference_frame(v1_0, S * l1, v2_0, S * l2) solutions = rotation_decomposition.solve_r3_rotation_for_angles_given_axes( R, e1, e2, e3, return_both_solutions=True, deg=True) if solutions is None: continue results[(v1_, v2_)][smx].extend(solutions) self.all_solutions = results self.unique_solutions = OrderedDict() for (v1, v2), result in results.iteritems(): for solutions in result.itervalues(): for solution in solutions: k = tuple(round(a, 3) for a in solution[1:]) self.unique_solutions.setdefault(k, OrderedSet()) self.unique_solutions[k].add((v1, v2))
def crystals(self): ''' Get a list of the unique crystals (includes None). ''' return list(OrderedSet(e.crystal for e in self))
def profiles(self): ''' Get a list of the unique profile models (includes None). ''' return list(OrderedSet(e.profile for e in self))
def scans(self): """ Get a list of the unique scans (includes None). """ return list(OrderedSet(e.scan for e in self))
def imagesets(self): """Get a list of the unique imagesets.""" return list( OrderedSet([e.imageset for e in self if e.imageset is not None]))
def __init__(self, cif_block, base_array_info=None, wavelengths=None): crystal_symmetry_builder.__init__(self, cif_block) self._arrays = OrderedDict() self._origarrays = OrderedDict( ) # used for presenting raw data tables in HKLviewer basearraylabels = [] if base_array_info is not None: self.crystal_symmetry = self.crystal_symmetry.join_symmetry( other_symmetry=base_array_info.crystal_symmetry_from_file, force=True) if base_array_info.labels: basearraylabels = base_array_info.labels if (wavelengths is None): wavelengths = {} if base_array_info is None: base_array_info = miller.array_info(source_type="cif") refln_containing_loops = self.get_miller_indices_containing_loops() for self.indices, refln_loop in refln_containing_loops: self.wavelength_id_array = None self.crystal_id_array = None self.scale_group_array = None wavelength_ids = [None] crystal_ids = [None] scale_groups = [None] for key, value in six.iteritems(refln_loop): # Get wavelength_ids, crystal_id, scale_group_code columns for selecting data of other # columns in self.get_selection() used by self.flex_std_string_as_miller_array() if (key.endswith('wavelength_id') or key.endswith('crystal_id') or key.endswith('scale_group_code')): data = as_int_or_none_if_all_question_marks( value, column_name=key) if data is None: continue counts = data.counts() if key.endswith('wavelength_id'): wavelength_ids = list(counts.keys()) if len(counts) == 1: continue array = miller.array( miller.set(self.crystal_symmetry, self.indices).auto_anomalous(), data) if key.endswith('wavelength_id'): self.wavelength_id_array = array wavelength_ids = list(counts.keys()) elif key.endswith('crystal_id'): self.crystal_id_array = array crystal_ids = list(counts.keys()) elif key.endswith('scale_group_code'): self.scale_group_array = array scale_groups = list(counts.keys()) labelsuffix = [] wavelbl = [] cryslbl = [] scalegrplbl = [] self._origarrays["HKLs"] = self.indices alllabels = list(sorted(refln_loop.keys())) remaininglabls = alllabels[:] # deep copy the list # Parse labels matching cif column conventions # https://mmcif.wwpdb.org/dictionaries/mmcif_pdbx_v50.dic/Categories/refln.html # and extract groups of labels or just single columns. # Groups corresponds to the map coefficients, phase and amplitudes, # amplitudes or intensities with sigmas and hendrickson-lattman columns. phaseamplabls, remaininglabls = self.get_phase_amplitude_labels( remaininglabls) mapcoefflabls, remaininglabls = self.get_mapcoefficient_labels( remaininglabls) HLcoefflabls, remaininglabls = self.get_HL_labels(remaininglabls) data_sig_obstype_labls, remaininglabls = self.get_FSigF_ISigI_labels( remaininglabls) for w_id in wavelength_ids: for crys_id in crystal_ids: for scale_group in scale_groups: # If reflection data files contain more than one crystal, wavelength or scalegroup # then add their id(s) as a suffix to data labels computed below. Needed for avoiding # ambuguity but avoid when not needed to make labels more human readable! if (len(wavelength_ids) > 1 or len(wavelengths) > 1) and w_id is not None: wavelbl = ["wavelength_id=%i" % w_id] if len(crystal_ids) > 1 and crys_id is not None: cryslbl = ["crystal_id=%i" % crys_id] if len(scale_groups) > 1 and scale_group is not None: scalegrplbl = ["scale_group_code=%i" % scale_group] labelsuffix = scalegrplbl + cryslbl + wavelbl jlablsufx = "" if len(labelsuffix): jlablsufx = "," + ",".join(labelsuffix) for mapcoefflabl in mapcoefflabls: A_array = refln_loop[mapcoefflabl[0]] B_array = refln_loop[mapcoefflabl[1]] # deselect any ? marks in the two arrays, assuming both A and B have the same ? marks selection = self.get_selection( A_array, wavelength_id=w_id, crystal_id=crys_id, scale_group_code=scale_group) A_array = A_array.select(selection) B_array = B_array.select(selection) # form the miller array with map coefficients data = flex.complex_double(flex.double(A_array), flex.double(B_array)) millarr = miller.array( miller.set(self.crystal_symmetry, self.indices.select( selection)).auto_anomalous(), data) # millarr will be None for column data not matching w_id,crys_id,scale_group values if millarr is None: continue labl = basearraylabels + mapcoefflabl + labelsuffix millarr.set_info( base_array_info.customized_copy( labels=labl, wavelength=wavelengths.get(w_id, None))) self._arrays[mapcoefflabl[0] + jlablsufx] = millarr for phaseamplabl in phaseamplabls: amplitudestrarray = refln_loop[phaseamplabl[0]] phasestrarray = refln_loop[phaseamplabl[1]] millarr = self.flex_std_string_as_miller_array( amplitudestrarray, wavelength_id=w_id, crystal_id=crys_id, scale_group_code=scale_group) phasesmillarr = self.flex_std_string_as_miller_array( phasestrarray, wavelength_id=w_id, crystal_id=crys_id, scale_group_code=scale_group) # millarr will be None for column data not matching w_id,crys_id,scale_group values if millarr is None or phasesmillarr is None: continue phases = as_flex_double(phasesmillarr, phaseamplabl[1]) millarr = millarr.phase_transfer(phases, deg=True) labl = basearraylabels + phaseamplabl + labelsuffix millarr.set_info( base_array_info.customized_copy( labels=labl, wavelength=wavelengths.get(w_id, None))) self._arrays[phaseamplabl[0] + jlablsufx] = millarr for datlabl, siglabl, otype in data_sig_obstype_labls: datastrarray = refln_loop[datlabl] millarr = self.flex_std_string_as_miller_array( datastrarray, wavelength_id=w_id, crystal_id=crys_id, scale_group_code=scale_group) # millarr will be None for column data not matching w_id,crys_id,scale_group values if millarr is None: continue millarr = as_flex_double(millarr, datlabl) datsiglabl = [datlabl] if siglabl: sigmasstrarray = refln_loop[siglabl] sigmas = self.flex_std_string_as_miller_array( sigmasstrarray, wavelength_id=w_id, crystal_id=crys_id, scale_group_code=scale_group) sigmas = as_flex_double(sigmas, siglabl) millarr.set_sigmas(sigmas.data()) datsiglabl = [datlabl, siglabl] datsiglabl = basearraylabels + datsiglabl + labelsuffix millarr.set_info( base_array_info.customized_copy( labels=datsiglabl, wavelength=wavelengths.get(w_id, None))) if otype is not None: millarr.set_observation_type(otype) self._arrays[datlabl + jlablsufx] = millarr for hl_labels in HLcoefflabls: hl_values = [ cif_block.get(hl_key) for hl_key in hl_labels ] if hl_values.count(None) == 0: selection = self.get_selection( hl_values[0], wavelength_id=w_id, crystal_id=crys_id, scale_group_code=scale_group) hl_values = [ as_double_or_none_if_all_question_marks( hl.select(selection), column_name=lab) for hl, lab in zip(hl_values, hl_labels) ] # hl_values will be None for column data not matching w_id,crys_id,scale_group values if hl_values == [None, None, None, None]: continue millarr = miller.array( miller.set( self.crystal_symmetry, self.indices.select( selection)).auto_anomalous(), flex.hendrickson_lattman(*hl_values)) hlabels = basearraylabels + hl_labels + labelsuffix millarr.set_info( base_array_info.customized_copy( labels=hlabels, wavelength=wavelengths.get(w_id, None))) self._arrays[hl_labels[0] + jlablsufx] = millarr # pick up remaining columns if any that weren't identified above for label in alllabels: if "index_" in label: continue datastrarray = refln_loop[label] if label in remaininglabls: labels = basearraylabels + [label ] + labelsuffix lablsufx = jlablsufx millarr = self.flex_std_string_as_miller_array( datastrarray, wavelength_id=w_id, crystal_id=crys_id, scale_group_code=scale_group) # millarr will be None for column data not matching w_id,crys_id,scale_group values if (label.endswith( 'wavelength_id' ) or label.endswith( 'crystal_id' ) or # get full array if any of these labels, not just subsets label.endswith('scale_group_code')): millarr = self.flex_std_string_as_miller_array( datastrarray, wavelength_id=None, crystal_id=None, scale_group_code=None) lablsufx = "" labels = basearraylabels + [label] if millarr is None: continue otype = self.guess_observationtype(label) if otype is not None: millarr.set_observation_type(otype) millarr.set_info( base_array_info.customized_copy( labels=labels, wavelength=wavelengths.get(w_id, None))) self._arrays[label + lablsufx] = millarr origarr = self.flex_std_string_as_miller_array( datastrarray, wavelength_id=w_id, crystal_id=crys_id, scale_group_code=scale_group) newlabel = label.replace("_refln.", "") newlabel2 = newlabel.replace("_refln_", "") if origarr: # want only genuine miller arrays self._origarrays[newlabel2 + jlablsufx] = origarr.data() # Convert any groups of I+,I-,SigI+,SigI- (or amplitudes) arrays into anomalous arrays # i.e. both friedel mates in the same array for key, array in six.iteritems(self._arrays.copy()): plus_key = "" if '_minus' in key: minus_key = key plus_key = key.replace('_minus', '_plus') elif '-' in key: minus_key = key plus_key = key.replace('-', '+') elif '_plus' in key: plus_key = key minus_key = key.replace('_plus', '_minus') elif '+' in key: plus_key = key minus_key = key.replace('+', '-') if plus_key in self._arrays and minus_key in self._arrays: plus_array = self._arrays.pop(plus_key) minus_array = self._arrays.pop(minus_key) minus_array = minus_array.customized_copy( indices=-minus_array.indices()).set_info( minus_array.info()) array = plus_array.concatenate( minus_array, assert_is_similar_symmetry=False) array = array.customized_copy(anomalous_flag=True) array.set_info(minus_array.info().customized_copy(labels=list( OrderedSet(plus_array.info().labels + minus_array.info().labels)))) array.set_observation_type(plus_array.observation_type()) self._arrays.setdefault(key, array) if len(self._arrays) == 0: raise CifBuilderError("No reflection data present in cif block") # Sort the ordered dictionary to resemble the order of columns in the cif file # This is to avoid any F_meas arrays accidentally being put adjacent to # pdbx_anom_difference arrays in the self._arrays OrderedDict. Otherwise these # arrays may unintentionally be combined into a reconstructed anomalous amplitude # array when saving as an mtz file due to a problem in the iotbx/mtz module. # See http://phenix-online.org/pipermail/cctbxbb/2021-March/002289.html arrlstord = [] arrlst = list(self._arrays) for arr in arrlst: for i, k in enumerate(refln_loop.keys()): if arr.split(",")[0] == k: arrlstord.append((arr, i)) # arrlstord must have the same keys as in the self._arrays dictionary assert sorted(arrlst) == sorted([e[0] for e in arrlstord]) sortarrlst = sorted(arrlstord, key=lambda arrord: arrord[1]) self._ordarrays = OrderedDict() for sortkey, i in sortarrlst: self._ordarrays.setdefault(sortkey, self._arrays[sortkey]) self._arrays = self._ordarrays