def set_distance(self, distance): if distance is None: return from xia2.Wrappers.Mosflm.AutoindexHelpers import set_distance set_distance(self.get_detector(), distance) self._fp_distance_prov = "user"
def set_distance(self, distance): if distance is None: return from xia2.Wrappers.Mosflm.AutoindexHelpers import set_distance set_distance(self.get_detector(), distance) self._fp_distance_prov = 'user' return
def _index(self): '''Implement the indexer interface.''' Citations.cite('mosflm') indexer = MosflmIndex() indexer.set_working_directory(self.get_working_directory()) auto_logfiler(indexer) from xia2.lib.bits import unique_elements _images = unique_elements(self._indxr_images) indexer.set_images(_images) images_str = ', '.join(map(str, _images)) cell_str = None if self._indxr_input_cell: cell_str = '%.2f %.2f %.2f %.2f %.2f %.2f' % \ self._indxr_input_cell if self._indxr_sweep_name: #if len(self._fp_directory) <= 50: #dirname = self._fp_directory #else: #dirname = '...%s' % self._fp_directory[-46:] dirname = os.path.dirname(self.get_imageset().get_template()) Journal.block( 'autoindexing', self._indxr_sweep_name, 'mosflm', { 'images': images_str, 'target cell': self._indxr_input_cell, 'target lattice': self._indxr_input_lattice, 'template': self.get_imageset().get_template(), 'directory': dirname }) #task = 'Autoindex from images:' #for i in _images: #task += ' %s' % self.get_image_name(i) #self.set_task(task) indexer.set_template(os.path.basename(self.get_template())) indexer.set_directory(self.get_directory()) xsweep = self.get_indexer_sweep() if xsweep is not None: if xsweep.get_distance() is not None: indexer.set_distance(xsweep.get_distance()) #if self.get_wavelength_prov() == 'user': #index.set_wavelength(self.get_wavelength()) if xsweep.get_beam_centre() is not None: indexer.set_beam_centre(xsweep.get_beam_centre()) if self._indxr_input_cell: indexer.set_unit_cell(self._indxr_input_cell) if self._indxr_input_lattice is not None: spacegroup_number = lattice_to_spacegroup( self._indxr_input_lattice) indexer.set_space_group_number(spacegroup_number) if not self._mosflm_autoindex_thresh: try: min_peaks = 200 Debug.write('Aiming for at least %d spots...' % min_peaks) thresholds = [] for i in _images: p = Printpeaks() p.set_working_directory(self.get_working_directory()) auto_logfiler(p) p.set_image(self.get_image_name(i)) thresh = p.threshold(min_peaks) Debug.write('Autoindex threshold for image %d: %d' % \ (i, thresh)) thresholds.append(thresh) thresh = min(thresholds) self._mosflm_autoindex_thresh = thresh except Exception as e: print str(e) #XXX this should disappear! Debug.write('Error computing threshold: %s' % str(e)) Debug.write('Using default of 20.0') thresh = 20.0 else: thresh = self._mosflm_autoindex_thresh Debug.write('Using autoindex threshold: %d' % thresh) if self._mosflm_autoindex_sol: indexer.set_solution_number(self._mosflm_autoindex_sol) indexer.set_threshold(thresh) # now forget this to prevent weird things happening later on if self._mosflm_autoindex_sol: self._mosflm_autoindex_sol = 0 indexer.run() indxr_cell = indexer.get_refined_unit_cell() self._indxr_lattice = indexer.get_lattice() space_group_number = indexer.get_indexed_space_group_number() detector_distance = indexer.get_refined_distance() beam_centre = indexer.get_refined_beam_centre() mosaic_spreads = indexer.get_mosaic_spreads() if min(list(indxr_cell)) < 10.0 and \ indxr_cell[2] / indxr_cell[0] > 6: Debug.write('Unrealistic autoindexing solution: ' + '%.2f %.2f %.2f %.2f %.2f %.2f' % indxr_cell) # tweak some parameters and try again... self._mosflm_autoindex_thresh *= 1.5 self.set_indexer_done(False) return intgr_params = {} # look up other possible indexing solutions (not well - in # standard settings only!) This is moved earlier as it could # result in returning if Mosflm has selected the wrong # solution! try: self._indxr_other_lattice_cell = indexer.get_solutions() # Change 27/FEB/08 to support user assigned spacegroups if self._indxr_user_input_lattice: lattice_to_spacegroup_dict = { 'aP': 1, 'mP': 3, 'mC': 5, 'oP': 16, 'oC': 20, 'oF': 22, 'oI': 23, 'tP': 75, 'tI': 79, 'hP': 143, 'hR': 146, 'cP': 195, 'cF': 196, 'cI': 197 } for k in self._indxr_other_lattice_cell.keys(): if lattice_to_spacegroup_dict[k] > \ lattice_to_spacegroup_dict[ self._indxr_input_lattice]: del (self._indxr_other_lattice_cell[k]) # check that the selected unit cell matches - and if # not raise a "horrible" exception if self._indxr_input_cell: assert indxr_cell is not None for j in range(6): if math.fabs(self._indxr_input_cell[j] - indxr_cell[j]) > 2.0: Chatter.write('Mosflm autoindexing did not select ' + 'correct (target) unit cell') raise RuntimeError( 'something horrible happened in indexing') except RuntimeError as e: # check if mosflm rejected a solution we have it if 'horribl' in str(e): # ok it did - time to break out the big guns... if not self._indxr_input_cell: raise RuntimeError( 'error in solution selection when not preset') # XXX FIXME self._mosflm_autoindex_sol = _get_indexing_solution_number( indexer.get_all_output(), self._indxr_input_cell, self._indxr_input_lattice) # set the fact that we are not done... self.set_indexer_done(False) # and return - hopefully this will restart everything return else: raise e if len(mosaic_spreads) == 0: # then consider setting it do a default value... # equal to the oscillation width (a good guess) phi_width = self.get_phi_width() Chatter.write( 'Mosaic estimation failed, so guessing at %4.2f' % \ phi_width) # only consider this if we have thus far no idea on the # mosaic spread... mosaic_spreads.append(phi_width) intgr_params['raster'] = indexer.get_raster() intgr_params['separation'] = indexer.get_separation() self._indxr_resolution_estimate = indexer.get_resolution_estimate() # compute mosaic as mean(mosaic_spreads) self._indxr_mosaic = sum(mosaic_spreads) / len(mosaic_spreads) self._indxr_payload['mosflm_integration_parameters'] = intgr_params self._indxr_payload['mosflm_orientation_matrix'] = open( os.path.join(self.get_working_directory(), 'xiaindex.mat'), 'r').readlines() import copy from dxtbx.model.detector_helpers import set_mosflm_beam_centre from xia2.Wrappers.Mosflm.AutoindexHelpers import set_distance from xia2.Wrappers.Mosflm.AutoindexHelpers import crystal_model_from_mosflm_mat from cctbx import sgtbx, uctbx # update the beam centre (i.e. shift the origin of the detector) detector = copy.deepcopy(self.get_detector()) beam = copy.deepcopy(self.get_beam()) set_mosflm_beam_centre(detector, beam, beam_centre) if detector_distance is not None: set_distance(detector, detector_distance) # make a dxtbx crystal_model object from the mosflm matrix space_group = sgtbx.space_group_info(number=space_group_number).group() crystal_model = crystal_model_from_mosflm_mat( self._indxr_payload['mosflm_orientation_matrix'], unit_cell=uctbx.unit_cell(tuple(indxr_cell)), space_group=space_group) # construct an experiment_list from dxtbx.model import Experiment, ExperimentList experiment = Experiment(beam=beam, detector=detector, goniometer=self.get_goniometer(), scan=self.get_scan(), crystal=crystal_model) experiment_list = ExperimentList([experiment]) self.set_indexer_experiment_list(experiment_list)
def _mosflm_refine_cell(self, idxr, set_spacegroup=None): '''Perform the refinement of the unit cell. This will populate all of the information needed to perform the integration.''' # FIXME this will die after #1285 #if not self.get_integrater_indexer(): #Debug.write('Replacing indexer of %s with self at %d' % \ #(str(self.get_integrater_indexer()), __line__)) #self.set_integrater_indexer(self) #idxr = self.get_integrater_indexer() if not idxr.get_indexer_payload('mosflm_orientation_matrix'): raise RuntimeError('unexpected situation in indexing') lattice = idxr.get_indexer_lattice() mosaic = idxr.get_indexer_mosaic() cell = idxr.get_indexer_cell() beam_centre = idxr.get_indexer_beam_centre() # bug # 3174 - if mosaic is very small (here defined to be # 0.25 x osc_width) then set to this minimum value. phi_width = idxr.get_phi_width() if mosaic < 0.25 * phi_width: mosaic = 0.25 * phi_width if idxr.get_indexer_payload('mosflm_beam_centre'): beam_centre = idxr.get_indexer_payload('mosflm_beam_centre') distance = idxr.get_indexer_distance() matrix = idxr.get_indexer_payload('mosflm_orientation_matrix') integration_params = idxr.get_indexer_payload( 'mosflm_integration_parameters') if integration_params is None: integration_params = {} if integration_params: if 'separation' in integration_params: self.set_refiner_parameter( 'mosflm', 'separation', '%f %f' % tuple(integration_params['separation'])) if 'raster' in integration_params: self.set_refiner_parameter( 'mosflm', 'raster', '%d %d %d %d %d' % tuple(integration_params['raster'])) idxr.set_indexer_payload('mosflm_integration_parameters', None) spacegroup_number = lattice_to_spacegroup(lattice) # copy these into myself for later reference, if indexer # is not myself - everything else is copied via the # cell refinement process... from cctbx import sgtbx from dxtbx.model import Crystal from dxtbx.model.detector_helpers import set_mosflm_beam_centre experiment = idxr.get_indexer_experiment_list()[0] set_mosflm_beam_centre(experiment.detector, experiment.beam, beam_centre) space_group = sgtbx.space_group_info(number=spacegroup_number).group() a, b, c = experiment.crystal.get_real_space_vectors() experiment.crystal = Crystal(a, b, c, space_group=space_group) # FIXME surely these have been assigned further up?! if not self._mosflm_cell_ref_images: self._mosflm_cell_ref_images = self._refine_select_images(mosaic) f = open( os.path.join(self.get_working_directory(), 'xiaindex-%s.mat' % lattice), 'w') for m in matrix: f.write(m) f.close() # then start the cell refinement refiner = MosflmRefineCell() refiner.set_working_directory(self.get_working_directory()) auto_logfiler(refiner) if self._mosflm_gain: refiner.set_gain(self._mosflm_gain) refiner.set_template(os.path.basename(idxr.get_template())) refiner.set_directory(idxr.get_directory()) refiner.set_input_mat_file('xiaindex-%s.mat' % lattice) refiner.set_output_mat_file('xiarefine.mat') refiner.set_beam_centre(beam_centre) refiner.set_unit_cell(cell) refiner.set_distance(distance) if set_spacegroup: refiner.set_space_group_number(set_spacegroup) else: refiner.set_space_group_number(spacegroup_number) # FIXME 18/JUN/08 - it may help to have an overestimate # of the mosaic spread in here as it *may* refine down # better than up... - this is not a good idea as it may # also not refine at all! - 12972 # integration failed # Bug # 3103 if self._mosflm_cell_ref_double_mosaic: mosaic *= 2.0 refiner.set_mosaic(mosaic) # if set, use the resolution for cell refinement - see # bug # 2078... if self._mosflm_cell_ref_resolution: refiner.set_resolution(self._mosflm_cell_ref_resolution) refiner.set_fix_mosaic(self._mosflm_postref_fix_mosaic) # note well that the beam centre is coming from indexing so # should be already properly handled #if idxr.get_wavelength_prov() == 'user': #refiner.set_wavelength(idxr.get_wavelength()) # belt + braces mode - only to be used when considering failover, # will run an additional step of autoindexing prior to cell # refinement, to be used only after proving that not going it # will result in cell refinement failure - will use the first # wedge... N.B. this is only useful if the indexer is Labelit # not Mosflm... refiner.set_add_autoindex(self._mosflm_cell_ref_add_autoindex) # get all of the stored parameter values parameters = self.get_refiner_parameters('mosflm') refiner.update_parameters(parameters) detector = idxr.get_detector() detector_width, detector_height = detector[0].get_image_size_mm() lim_x = 0.5 * detector_width lim_y = 0.5 * detector_height Debug.write('Scanner limits: %.1f %.1f' % (lim_x, lim_y)) refiner.set_limits(lim_x, lim_y) refiner.set_images(self._mosflm_cell_ref_images) failover = PhilIndex.params.xia2.settings.failover if failover and not self._mosflm_cell_ref_add_autoindex: refiner.set_ignore_cell_refinement_failure(True) refiner.run() # then look to see if the cell refinement worked ok - if it # didn't then this may indicate that the lattice was wrongly # selected. cell_refinement_ok = refiner.cell_refinement_ok() if not cell_refinement_ok: Debug.write('Repeating cell refinement...') self.set_integrater_prepare_done(False) self._mosflm_cell_ref_add_autoindex = True return [0.0], [0.0] rms_values = refiner.get_rms_values() background_residual = refiner.get_background_residual() self._refinr_cell = refiner.get_refined_unit_cell() distance = refiner.get_refined_distance2() experiment = idxr.get_indexer_experiment_list()[0] from xia2.Wrappers.Mosflm.AutoindexHelpers import set_distance set_distance(experiment.detector, distance) self.set_refiner_parameter('mosflm', 'distortion yscale', refiner.get_refined_distortion_yscale()) self.set_refiner_parameter('mosflm', 'raster', refiner.get_raster()) #integration_params['distortion yscale'] \ #= refiner.get_refined_distortion_yscale() #integration_params['raster'] = refiner.get_raster() separation = refiner.get_separation() if separation is not None: self.set_refiner_parameter('mosflm', 'separation', '%s %s' % refiner.get_separation()) #integration_params['separation'] = refiner.get_separation() self.set_refiner_parameter('mosflm', 'beam', '%s %s' % refiner.get_refined_beam_centre()) self.set_refiner_parameter('mosflm', 'distance', refiner.get_refined_distance()) self.set_refiner_parameter('mosflm', 'distortion tilt', refiner.get_refined_distortion_tilt()) self.set_refiner_parameter('mosflm', 'distortion twist', refiner.get_refined_distortion_twist()) integration_params['beam'] = tuple( float(b) for b in refiner.get_refined_beam_centre()) integration_params['distance'] = refiner.get_refined_distance() integration_params[ 'distortion tilt'] = refiner.get_refined_distortion_tilt() integration_params[ 'distortion twist'] = refiner.get_refined_distortion_twist() idxr._indxr_mosaic = refiner.get_refined_mosaic() idxr.set_indexer_payload( 'mosflm_orientation_matrix', open(os.path.join(self.get_working_directory(), 'xiarefine.mat'), 'r').readlines()) self.set_refiner_payload( 'mosflm_orientation_matrix', idxr.get_indexer_payload('mosflm_orientation_matrix')) self.set_refiner_payload('mosaic', refiner.get_refined_mosaic()) self.set_refiner_payload('beam', integration_params['beam']) self.set_refiner_payload('distance', integration_params['distance']) from xia2.Wrappers.Mosflm.AutoindexHelpers import crystal_model_from_mosflm_mat # make a dxtbx crystal_model object from the mosflm matrix experiment = idxr.get_indexer_experiment_list()[0] crystal_model = crystal_model_from_mosflm_mat( idxr._indxr_payload['mosflm_orientation_matrix'], unit_cell=refiner.get_refined_unit_cell(), space_group=experiment.crystal.get_space_group()) experiment.crystal = crystal_model #self.set_refiner_payload( #'mosflm_integration_parameters', integration_params) self._refinr_refined_experiment_list = ExperimentList([experiment]) return rms_values, background_residual
def __init__( self, name, wavelength, sample, directory=None, image=None, beam=None, reversephi=False, distance=None, gain=0.0, dmin=0.0, dmax=0.0, polarization=0.0, frames_to_process=None, user_lattice=None, user_cell=None, epoch=0, ice=False, excluded_regions=None, ): """Create a new sweep named name, belonging to XWavelength object wavelength, representing the images in directory starting with image, with beam centre optionally defined.""" if excluded_regions is None: excluded_regions = [] # + check the wavelength is an XWavelength object # raise an exception if not... or not... if not wavelength.__class__.__name__ == "XWavelength": pass # FIXME bug 2221 if DIRECTORY starts with ~/ or ~graeme (say) need to # interpret this properly - e.g. map it to a full PATH. directory = expand_path(directory) self._name = name self._wavelength = wavelength self._sample = sample self._directory = directory self._image = image self._reversephi = reversephi self._epoch = epoch self._user_lattice = user_lattice self._user_cell = user_cell self._header = {} self._resolution_high = dmin self._resolution_low = dmax self._ice = ice self._excluded_regions = excluded_regions self._imageset = None # FIXME in here also need to be able to accumulate the total # dose from all experimental measurements (complex) and provide # a _epoch_to_dose dictionary or some such... may be fiddly as # this will need to parse across multiple templates. c/f Bug # 2798 self._epoch_to_image = {} self._image_to_epoch = {} # to allow first, last image for processing to be # set... c/f integrater interface self._frames_to_process = frames_to_process # + derive template, list of images params = PhilIndex.get_python_object() if directory and image: self._template, self._directory = image2template_directory( os.path.join(directory, image)) from xia2.Schema import load_imagesets imagesets = load_imagesets( self._template, self._directory, image_range=self._frames_to_process, reversephi=(params.xia2.settings.input.reverse_phi or self._reversephi), ) assert len( imagesets ) == 1, "one imageset expected, %d found" % len(imagesets) self._imageset = copy.deepcopy(imagesets[0]) start, end = self._imageset.get_array_range() self._images = list(range(start + 1, end + 1)) # FIXME in here check that (1) the list of images is continuous # and (2) that all of the images are readable. This should also # take into account frames_to_process if set. if self._frames_to_process is None: self._frames_to_process = min(self._images), max(self._images) start, end = self._frames_to_process error = False if params.general.check_image_files_readable: for j in range(start, end + 1): if not j in self._images: Debug.write("image %i missing for %s" % (j, self.get_imageset().get_template())) error = True continue image_name = self.get_imageset().get_path(j - start) if not os.access(image_name, os.R_OK): Debug.write("image %s unreadable" % image_name) error = True continue if error: raise RuntimeError("problem with sweep %s" % self._name) # + read the image header information into here? # or don't I need it? it would be useful for checking # against wavelength.getWavelength() I guess to make # sure that the plumbing is all sound. # check that they match by closer than 0.0001A, if wavelength # is not None beam_ = self._imageset.get_beam() scan = self._imageset.get_scan() if wavelength is not None: # If the wavelength value is 0.0 then first set it to the header # value - note that this assumes that the header value is correct # (a reasonable assumption) if wavelength.get_wavelength() == 0.0: wavelength.set_wavelength(beam_.get_wavelength()) # FIXME 08/DEC/06 in here need to allow for the fact # that the wavelength in the image header could be wrong and # in fact it should be replaced with the input value - # through the user will need to be warned of this and # also everything using the FrameProcessor interface # will also have to respect this! if (math.fabs(beam_.get_wavelength() - wavelength.get_wavelength()) > 0.0001): # format = 'wavelength for sweep %s does not ' + \ # 'match wavelength %s' # raise RuntimeError(format % \ # (name, wavelength.get_name())) format = ("Header wavelength for sweep %s different" + " to assigned value (%4.2f vs. %4.2f)") Chatter.write(format % (name, beam_.get_wavelength(), wavelength.get_wavelength())) # also in here look at the image headers to see if we can # construct a mapping between exposure epoch and image ... images = [] if self._frames_to_process: start, end = self._frames_to_process for j in self._images: if j >= start and j <= end: images.append(j) else: images = self._images for j in images: epoch = scan.get_image_epoch(j) if epoch == 0.0: epoch = float( os.stat(self._imageset.get_path(j - images[0])).st_mtime) self._epoch_to_image[epoch] = j self._image_to_epoch[j] = epoch epochs = self._epoch_to_image.keys() Debug.write("Exposure epoch for sweep %s: %d %d" % (self._template, min(epochs), max(epochs))) self._input_imageset = copy.deepcopy(self._imageset) # + get the lattice - can this be a pointer, so that when # this object updates lattice it is globally-for-this-crystal # updated? The lattice included directly in here includes an # exact unit cell for data reduction, the crystal lattice # contains an approximate unit cell which should be # from the unit cells from all sweeps contained in the # XCrystal. FIXME should I be using a LatticeInfo object # in here? See what the Indexer interface produces. ALT: # just provide an Indexer implementation "hook". # See Headnote 001 above. See also _get_indexer, # _get_integrater below. self._indexer = None self._refiner = None self._integrater = None # I don't need this - it is equivalent to self.getWavelength( # ).getCrystal().getLattice() # self._crystal_lattice = None # this means that this module will have to present largely the # same interface as Indexer and Integrater so that the calls # can be appropriately forwarded. # finally configure the beam if set if beam is not None: from dxtbx.model.detector_helpers import set_mosflm_beam_centre try: set_mosflm_beam_centre( self.get_imageset().get_detector(), self.get_imageset().get_beam(), beam, ) except AssertionError as e: Debug.write("Error setting mosflm beam centre: %s" % e) if distance is not None: from xia2.Wrappers.Mosflm.AutoindexHelpers import set_distance set_distance(self.get_imageset().get_detector(), distance) self._beam_centre = beam self._distance = distance self._gain = gain self._polarization = polarization self._add_detector_identification_to_cif()