Пример #1
0
def _prepare_pointless_hklin(working_directory,
                             hklin,
                             phi_width):
  '''Prepare some data for pointless - this will take only 180 degrees
  of data if there is more than this (through a "rebatch" command) else
  will simply return hklin.'''

  # also remove blank images?

  if not Flags.get_microcrystal() and not Flags.get_small_molecule():

    Debug.write('Excluding blank images')

    hklout = os.path.join(
        working_directory,
        '%s_noblank.mtz' % (os.path.split(hklin)[-1][:-4]))

    FileHandler.record_temporary_file(hklout)

    hklin = remove_blank(hklin, hklout)

  # find the number of batches

  md = Mtzdump()
  md.set_working_directory(working_directory)
  auto_logfiler(md)
  md.set_hklin(hklin)
  md.dump()

  batches = max(md.get_batches()) - min(md.get_batches())

  phi_limit = 180

  if batches * phi_width < phi_limit or Flags.get_small_molecule():
    return hklin

  hklout = os.path.join(
      working_directory,
      '%s_prepointless.mtz' % (os.path.split(hklin)[-1][:-4]))

  rb = Rebatch()
  rb.set_working_directory(working_directory)
  auto_logfiler(rb)
  rb.set_hklin(hklin)
  rb.set_hklout(hklout)

  first = min(md.get_batches())
  last = first + int(phi_limit / phi_width)

  Debug.write('Preparing data for pointless - %d batches (%d degrees)' % \
              ((last - first), phi_limit))

  rb.limit_batches(first, last)

  # we will want to delete this one exit
  FileHandler.record_temporary_file(hklout)

  return hklout
Пример #2
0
  def _updated_aimless(self):
    '''Generate a correctly configured Aimless...'''

    aimless = None

    if not self._scalr_corrections:
      aimless = self._factory.Aimless()
    else:

      aimless = self._factory.Aimless(
          partiality_correction = self._scalr_correct_partiality,
          absorption_correction = self._scalr_correct_absorption,
          decay_correction = self._scalr_correct_decay)

    if Flags.get_microcrystal():

      # fiddly little data sets - allow more rapid scaling...

      aimless.set_scaling_parameters('rotation', 2.0)
      if self._scalr_correct_decay:
        aimless.set_bfactor(bfactor=True, brotation = 2.0)

    if Flags.get_small_molecule():
      aimless.set_scaling_parameters('rotation', 15.0)
      aimless.set_bfactor(bfactor=False)

    aimless.set_surface_tie(PhilIndex.params.ccp4.aimless.surface_tie)
    aimless.set_surface_link(PhilIndex.params.ccp4.aimless.surface_link)

    return aimless
Пример #3
0
    def merge(self):
      '''Actually merge the already scaled reflections.'''

      self.check_hklin()
      self.check_hklout()

      if not self._onlymerge:
        raise RuntimeError, 'for scaling use scale()'

      if not self._scalepack:
        self.set_task('Merging scaled reflections from %s => %s' % \
                     (os.path.split(self.get_hklin())[-1],
                      os.path.split(self.get_hklout())[-1]))
      else:
        self.set_task('Merging reflections from %s => scalepack %s' % \
                     (os.path.split(self.get_hklin())[-1],
                      os.path.split(self.get_hklout())[-1]))

      self._xmlout = os.path.join(self.get_working_directory(),
                                  '%d_aimless.xml' % self.get_xpid())

      self.start()
      self.input('xmlout %d_aimless.xml' % self.get_xpid())
      if not Flags.get_small_molecule():
        self.input('bins 20')
      self.input('run 1 all')
      self.input('scales constant')
      self.input('initial unity')
      self.input('sdcorrection both noadjust 1.0 0.0 0.0')

      if self._anomalous:
        self.input('anomalous on')
      else:
        self.input('anomalous off')

      if self._scalepack:
        self.input('output polish unmerged')
      self.input('output unmerged')

      self.close_wait()

      # check for errors

      try:
        self.check_for_errors()
        self.check_ccp4_errors()
        self.check_aimless_errors()

        status = self.get_ccp4_status()

        if 'Error' in status:
          raise RuntimeError, '[AIMLESS] %s' % status

      except RuntimeError, e:
        try:
          os.remove(self.get_hklout())
        except:
          pass

        raise e
Пример #4
0
    def reindex(self):
      '''Actually perform the reindexing.'''

      if PhilIndex.params.ccp4.reindex.program == 'reindex':
        return self.reindex_old()

      self.check_hklin()
      self.check_hklout()

      if not self._spacegroup and not self._operator:
        raise RuntimeError, 'reindex requires spacegroup or operator'

      if self._operator:
        self._operator = self._operator.replace('[', '').replace(']', '')

      Debug.write('Reindex... %s %s' % (self._spacegroup, self._operator))

      if self._spacegroup and Flags.get_small_molecule() and False:
        if not self._operator or self._operator.replace(' ', '') == 'h,k,l':
          return self.cctbx_reindex()

      self.start()

      if self._spacegroup:

        if type(self._spacegroup) == type(0):
          spacegroup = Syminfo.spacegroup_number_to_name(
              self._spacegroup)
        elif self._spacegroup[0] in '0123456789':
          spacegroup = Syminfo.spacegroup_number_to_name(
              int(self._spacegroup))
        else:
          spacegroup = self._spacegroup

        self.input('spacegroup \'%s\'' % spacegroup)

      if self._operator:
        # likewise
        self.input('reindex \'%s\'' % self._operator)
      else:
        self.input('reindex \'h,k,l\'')

      self.close_wait()

      # check for errors

      try:
        self.check_for_errors()

      except RuntimeError, e:
        try:
          os.remove(self.get_hklout())
        except:
          pass

        raise e
Пример #5
0
  def _estimate_resolution_limit(self, hklin, batch_range=None):
    params = PhilIndex.params.xia2.settings.resolution
    m = Merger()
    m.set_working_directory(self.get_working_directory())
    from xia2.lib.bits import auto_logfiler
    auto_logfiler(m)
    m.set_hklin(hklin)
    m.set_limit_rmerge(params.rmerge)
    m.set_limit_completeness(params.completeness)
    m.set_limit_cc_half(params.cc_half)
    m.set_limit_isigma(params.isigma)
    m.set_limit_misigma(params.misigma)
    if Flags.get_small_molecule():
      m.set_nbins(20)
    if batch_range is not None:
      start, end = batch_range
      m.set_batch_range(start, end)
    m.run()

    if params.completeness:
      r_comp = m.get_resolution_completeness()
    else:
      r_comp = 0.0

    if params.cc_half:
      r_cc_half = m.get_resolution_cc_half()
    else:
      r_cc_half = 0.0

    if params.rmerge:
      r_rm = m.get_resolution_rmerge()
    else:
      r_rm = 0.0

    if params.isigma:
      r_uis = m.get_resolution_isigma()
    else:
      r_uis = 0.0

    if params.misigma:
      r_mis = m.get_resolution_misigma()
    else:
      r_mis = 0.0

    resolution = max([r_comp, r_rm, r_uis, r_mis, r_cc_half])

    return resolution
Пример #6
0
  def _do_indexing(self, method=None):
    indexer = self.Index()
    for indxr in self._indxr_indexers:
      indexer.add_spot_filename(indxr._indxr_payload["spot_list"])
      indexer.add_sweep_filename(indxr._indxr_payload["datablock.json"])
    if PhilIndex.params.dials.index.phil_file is not None:
      indexer.set_phil_file(PhilIndex.params.dials.index.phil_file)
    if PhilIndex.params.dials.index.max_cell:
      indexer.set_max_cell(PhilIndex.params.dials.index.max_cell)
    if Flags.get_small_molecule():
      indexer.set_min_cell(3)
    if PhilIndex.params.dials.fix_geometry:
      indexer.set_detector_fix('all')
      indexer.set_beam_fix('all')

    if self._indxr_input_lattice:
      indexer.set_indexer_input_lattice(self._indxr_input_lattice)
      Debug.write('Set lattice: %s' % self._indxr_input_lattice)

    if self._indxr_input_cell:
      indexer.set_indexer_input_cell(self._indxr_input_cell)
      Debug.write('Set cell: %f %f %f %f %f %f' % \
                  self._indxr_input_cell)
      original_cell = self._indxr_input_cell

    if method is None:
      if PhilIndex.params.dials.index.method is None:
        method = 'fft3d'
        Debug.write('Choosing indexing method: %s' % method)
      else:
        method = PhilIndex.params.dials.index.method

    indexer.run(method)

    if not os.path.exists(indexer.get_experiments_filename()):
      raise RuntimeError("Indexing has failed: %s does not exist."
                         %indexer.get_experiments_filename())
    elif not os.path.exists(indexer.get_indexed_filename()):
      raise RuntimeError("Indexing has failed: %s does not exist."
                         %indexer.get_indexed_filename())

    return indexer
Пример #7
0
  def _index_select_images(self):
    '''Select correct images based on image headers.'''

    if Flags.get_small_molecule():
      return self._index_select_images_small_molecule()

    if Flags.get_microcrystal():
      return self._index_select_images_microcrystal()

    phi_width = self.get_phi_width()
    images = self.get_matching_images()

    if Flags.get_interactive():
      selected_images = index_select_images_user(phi_width, images,
                                                 Chatter)
    else:
      selected_images = index_select_images_lone(phi_width, images)

    for image in selected_images:
      Debug.write('Selected image %s' % image)
      self.add_indexer_image_wedge(image)

    return
Пример #8
0
    def run(self):
      '''Run colspot.'''

      #image_header = self.get_header()

      ## crank through the header dictionary and replace incorrect
      ## information with updated values through the indexer
      ## interface if available...

      ## need to add distance, wavelength - that should be enough...

      #if self.get_distance():
        #image_header['distance'] = self.get_distance()

      #if self.get_wavelength():
        #image_header['wavelength'] = self.get_wavelength()

      #if self.get_two_theta():
        #image_header['two_theta'] = self.get_two_theta()

      header = imageset_to_xds(self.get_imageset())

      xds_inp = open(os.path.join(self.get_working_directory(),
                                  'XDS.INP'), 'w')

      # what are we doing?
      xds_inp.write('JOB=COLSPOT\n')
      xds_inp.write('MAXIMUM_NUMBER_OF_PROCESSORS=%d\n' % \
                    self._parallel)

      #if image_header['detector'] in ('pilatus', 'dectris'):
      if self.get_imageset().get_detector()[0].get_type() == 'SENSOR_PAD':
        xds_inp.write('MINIMUM_NUMBER_OF_PIXELS_IN_A_SPOT=%d\n' %
                      self._params.minimum_pixels_per_spot)

      for record in header:
        xds_inp.write('%s\n' % record)

      name_template = os.path.join(self.get_directory(),
                                   self.get_template().replace('#', '?'))

      record = 'NAME_TEMPLATE_OF_DATA_FRAMES=%s\n' % \
               name_template

      xds_inp.write(record)

      xds_inp.write('DATA_RANGE=%d %d\n' % self._data_range)
      for spot_range in self._spot_range:
        xds_inp.write('SPOT_RANGE=%d %d\n' % spot_range)
      xds_inp.write('BACKGROUND_RANGE=%d %d\n' % \
                    self._background_range)

      # microcrystals have very mall spots, perhaps?

      if Flags.get_microcrystal():
        xds_inp.write('MINIMUM_NUMBER_OF_PIXELS_IN_A_SPOT=1\n')

      if Flags.get_small_molecule():
        xds_inp.write('STRONG_PIXEL=5\n')
        # FIXME should probably be moved to a phil parameter

      xds_inp.close()

      # copy the input file...
      shutil.copyfile(os.path.join(self.get_working_directory(),
                                   'XDS.INP'),
                      os.path.join(self.get_working_directory(),
                                   '%d_COLSPOT.INP' % self.get_xpid()))

      # write the input data files...

      for file_name in self._input_data_files_list:
        src = self._input_data_files[file_name]
        dst = os.path.join(
            self.get_working_directory(), file_name)
        if src != dst:
          shutil.copyfile(src, dst)

      self.start()
      self.close_wait()

      xds_check_version_supported(self.get_all_output())

      # copy the LP file
      shutil.copyfile(os.path.join(self.get_working_directory(),
                                   'COLSPOT.LP'),
                      os.path.join(self.get_working_directory(),
                                   '%d_COLSPOT.LP' % self.get_xpid()))

      # gather the output files

      for file in self._output_data_files_list:
        self._output_data_files[file] = os.path.join(
          self.get_working_directory(), file)

      return
Пример #9
0
    def decide_spacegroup(self):
      '''Given data indexed in the correct pointgroup, have a
      guess at the spacegroup.'''

      if not self._xdsin:

        self.check_hklin()
        self.set_task('Computing the correct spacegroup for %s' % \
                      self.get_hklin())

      else:
        Debug.write('Pointless using XDS input file %s' % \
                    self._xdsin)
        self.set_task('Computing the correct spacegroup for %s' % \
                      self.get_xdsin())


      # FIXME this should probably be a standard CCP4 keyword

      if self._xdsin:
        self.add_command_line('xdsin')
        self.add_command_line(self._xdsin)

      self.add_command_line('xmlout')
      self.add_command_line('%d_pointless.xml' % self.get_xpid())

      self.add_command_line('hklout')
      self.add_command_line('pointless.mtz')

      self.start()

      self.input('lauegroup hklin')
      self.input('setting symmetry-based')

      if Flags.get_small_molecule():
        self.input('chirality nonchiral')

      self.close_wait()

      # check for errors
      self.check_for_errors()

      hklin_spacegroup = ''

      xml_file = os.path.join(self.get_working_directory(),
                              '%d_pointless.xml' % self.get_xpid())
      mend_pointless_xml(xml_file)

      if not os.path.exists(xml_file) and \
         os.path.exists('%s.xml' % xml_file):
        xml_file = '%s.xml' % xml_file

      dom = xml.dom.minidom.parse(xml_file)

      sg_list = dom.getElementsByTagName('SpacegroupList')[0]
      sg_node = sg_list.getElementsByTagName('Spacegroup')[0]
      best_prob = float(sg_node.getElementsByTagName(
          'TotalProb')[0].childNodes[0].data.strip())

      # FIXME 21/NOV/06 in here record a list of valid spacegroups
      # (that is, those which are as likely as the most likely)
      # for later use...

      self._spacegroup = sg_node.getElementsByTagName(
          'SpacegroupName')[0].childNodes[0].data.strip()
      self._spacegroup_reindex_operator = sg_node.getElementsByTagName(
          'ReindexOperator')[0].childNodes[0].data.strip()
      self._spacegroup_reindex_matrix = tuple(
          map(float, sg_node.getElementsByTagName(
          'ReindexMatrix')[0].childNodes[0].data.split()))

      # get a list of "equally likely" spacegroups

      for node in sg_list.getElementsByTagName('Spacegroup'):
        prob = float(node.getElementsByTagName(
            'TotalProb')[0].childNodes[0].data.strip())
        name = node.getElementsByTagName(
            'SpacegroupName')[0].childNodes[0].data.strip()

        if math.fabs(prob - best_prob) < 0.01:
          # this is jolly likely!
          self._likely_spacegroups.append(name)

      # now parse the output looking for the unit cell information -
      # this should look familiar from mtzdump

      output = self.get_all_output()
      length = len(output)

      a = 0.0
      b = 0.0
      c = 0.0
      alpha = 0.0
      beta = 0.0
      gamma = 0.0

      self._cell_info['datasets'] = []
      self._cell_info['dataset_info'] = { }

      for i in range(length):

        line = output[i][:-1]

        if 'Dataset ID, ' in line:

          block = 0
          while output[block * 5 + i + 2].strip():
            dataset_number = int(
                output[5 * block + i + 2].split()[0])
            project = output[5 * block + i + 2][10:].strip()
            crystal = output[5 * block + i + 3][10:].strip()
            dataset = output[5 * block + i + 4][10:].strip()
            cell = map(float, output[5 * block + i + 5].strip(
                ).split())
            wavelength = float(output[5 * block + i + 6].strip())

            dataset_id = '%s/%s/%s' % \
                         (project, crystal, dataset)

            self._cell_info['datasets'].append(dataset_id)
            self._cell_info['dataset_info'][dataset_id] = { }
            self._cell_info['dataset_info'][
                dataset_id]['wavelength'] = wavelength
            self._cell_info['dataset_info'][
                dataset_id]['cell'] = cell
            self._cell_info['dataset_info'][
                dataset_id]['id'] = dataset_number
            block += 1

      for dataset in self._cell_info['datasets']:
        cell = self._cell_info['dataset_info'][dataset]['cell']
        a += cell[0]
        b += cell[1]
        c += cell[2]
        alpha += cell[3]
        beta += cell[4]
        gamma += cell[5]

      n = len(self._cell_info['datasets'])
      self._cell = (a / n, b / n, c / n, alpha / n, beta / n, gamma / n)

      return 'ok'
Пример #10
0
    def decide_pointgroup(self):
      '''Decide on the correct pointgroup for hklin.'''

      if not self._xdsin:
        self.check_hklin()
        self.set_task('Computing the correct pointgroup for %s' % \
                      self.get_hklin())

      else:
        Debug.write('Pointless using XDS input file %s' % \
                    self._xdsin)

        self.set_task('Computing the correct pointgroup for %s' % \
                      self.get_xdsin())

      # FIXME this should probably be a standard CCP4 keyword

      if self._xdsin:
        self.add_command_line('xdsin')
        self.add_command_line(self._xdsin)

      self.add_command_line('xmlout')
      self.add_command_line('%d_pointless.xml' % self.get_xpid())

      if self._hklref:
        self.add_command_line('hklref')
        self.add_command_line(self._hklref)

      self.start()

      self.input('systematicabsences off')
      self.input('setting symmetry-based')
      if self._hklref:
        from xia2.Handlers.Phil import PhilIndex
        dev = PhilIndex.params.xia2.settings.developmental
        if dev.pointless_tolerance > 0.0:
          self.input('tolerance %f' % dev.pointless_tolerance)

      # may expect more %age variation for small molecule data
      if Flags.get_small_molecule() and self._hklref:
        self.input('tolerance 5.0')

      if Flags.get_small_molecule():
        self.input('chirality nonchiral')

      if self._input_laue_group:
        self.input('lauegroup %s' % self._input_laue_group)

      self.close_wait()

      # check for errors
      self.check_for_errors()

      # check for fatal errors
      output = self.get_all_output()
      for j, record in enumerate(output):
        if 'FATAL ERROR message:' in record:
          raise RuntimeError, 'Pointless error: %s' % output[j+1].strip()

      hklin_spacegroup = ''
      hklin_lattice = ''

      for o in self.get_all_output():

        if 'Spacegroup from HKLIN file' in o:

          # hklin_spacegroup = o.split(':')[-1].strip()
          hklin_spacegroup = spacegroup_name_xHM_to_old(
              o.replace(
              'Spacegroup from HKLIN file :', '').strip())
          hklin_lattice = Syminfo.get_lattice(hklin_spacegroup)

        if 'No alternative indexing possible' in o:
          # then the XML file will be broken - no worries...

          self._pointgroup = hklin_spacegroup
          self._confidence = 1.0
          self._totalprob = 1.0
          self._reindex_matrix = [1.0, 0.0, 0.0,
                                  0.0, 1.0, 0.0,
                                  0.0, 0.0, 1.0]
          self._reindex_operator = 'h,k,l'

          return 'ok'

        if '**** Incompatible symmetries ****' in o:
          raise RuntimeError, \
                                                'reindexing against a reference with different symmetry'

        if '***** Stopping because cell discrepancy between files' in o:
                                        raise RuntimeError, 'incompatible unit cells between data sets'

        if 'L-test suggests that the data may be twinned' in o:
          self._probably_twinned = True

      # parse the XML file for the information I need...

      xml_file = os.path.join(self.get_working_directory(),
                              '%d_pointless.xml' % self.get_xpid())
      mend_pointless_xml(xml_file)
      # catch the case sometimes on ppc mac where pointless adds
      # an extra .xml on the end...

      if not os.path.exists(xml_file) and \
         os.path.exists('%s.xml' % xml_file):
        xml_file = '%s.xml' % xml_file

      if not self._hklref:

        dom = xml.dom.minidom.parse(xml_file)

        try:
          best = dom.getElementsByTagName('BestSolution')[0]
        except IndexError, e:
          raise RuntimeError, 'error getting solution from pointless'
        self._pointgroup = best.getElementsByTagName(
            'GroupName')[0].childNodes[0].data
        self._confidence = float(best.getElementsByTagName(
            'Confidence')[0].childNodes[0].data)
        self._totalprob = float(best.getElementsByTagName(
            'TotalProb')[0].childNodes[0].data)
        self._reindex_matrix = map(float, best.getElementsByTagName(
            'ReindexMatrix')[0].childNodes[0].data.split())
        self._reindex_operator = clean_reindex_operator(
            best.getElementsByTagName(
            'ReindexOperator')[0].childNodes[0].data.strip())
Пример #11
0
    def run(self):
      '''Run integrate.'''

      #image_header = self.get_header()

      ## crank through the header dictionary and replace incorrect
      ## information with updated values through the indexer
      ## interface if available...

      ## need to add distance, wavelength - that should be enough...

      #if self.get_distance():
        #image_header['distance'] = self.get_distance()

      #if self.get_wavelength():
        #image_header['wavelength'] = self.get_wavelength()

      #if self.get_two_theta():
        #image_header['two_theta'] = self.get_two_theta()

      header = imageset_to_xds(self.get_imageset())

      xds_inp = open(os.path.join(self.get_working_directory(),
                                  'XDS.INP'), 'w')

      # what are we doing?
      xds_inp.write('JOB=INTEGRATE\n')
      xds_inp.write('MAXIMUM_NUMBER_OF_PROCESSORS=%d\n' % \
                    self._parallel)

      from xia2.Handlers.Phil import PhilIndex
      xds_params = PhilIndex.params.xds
      if xds_params.profile_grid_size:
        ab, c = xds_params.profile_grid_size
        assert(ab > 0 and ab < 22 and (ab % 2) == 1)
        assert(c > 0 and c < 22 and (c % 2) == 1)
        xds_inp.write(
            'NUMBER_OF_PROFILE_GRID_POINTS_ALONG_ALPHA/BETA= %d\n' % ab)
        xds_inp.write(
            'NUMBER_OF_PROFILE_GRID_POINTS_ALONG_GAMMA= %d\n' % c)

      if Flags.get_xparallel() > 1:
        xds_inp.write('MAXIMUM_NUMBER_OF_JOBS=%d\n' % \
                      Flags.get_xparallel())

      elif Flags.get_xparallel() == -1:
        chunk_width = 30.0
        phi_width = self.get_phi_width()
        nchunks = int(
            (self._data_range[1] - self._data_range[0] + 1) * \
            phi_width / chunk_width)

        Debug.write('Xparallel: -1 using %d chunks' % nchunks)

        xds_inp.write('MAXIMUM_NUMBER_OF_JOBS=%d\n' % nchunks)

      profile_fitting = PhilIndex.params.xds.integrate.profile_fitting
      if not profile_fitting:
        xds_inp.write('PROFILE_FITTING=FALSE\n')

      # write out lots of output
      xds_inp.write('TEST=2\n')

      if self._params.delphi:
        xds_inp.write('DELPHI=%.1f\n' % self._params.delphi)
      elif Flags.get_small_molecule():
        xds_inp.write('DELPHI=%.1f\n' % \
                      xds_params.delphi_small)
      else:
        xds_inp.write('DELPHI=%.1f\n' % \
                      xds_params.delphi)

      if self._refined_xparm:
        xds_inp.write('REFINE(INTEGRATE)=%s\n' %
                      ' '.join(self._params.refine_final))
      else:
        xds_inp.write('REFINE(INTEGRATE)=%s\n' %
                      ' '.join(self._params.refine))

      if self._params.fix_scale:
        if _running_xds_version() >= 20130330:
          xds_inp.write('DATA_RANGE_FIXED_SCALE_FACTOR= %d %d 1\n' %
                        self._data_range)
        else:
          xds_inp.write('FIXED_SCALE_FACTOR=TRUE\n')

      # check for updated input parameters or ones from phil

      if self._updates.has_key('BEAM_DIVERGENCE') and \
             self._updates.has_key('BEAM_DIVERGENCE_E.S.D.'):
        xds_inp.write(
            'BEAM_DIVERGENCE=%f BEAM_DIVERGENCE_E.S.D.=%f\n' % \
            (self._updates['BEAM_DIVERGENCE'],
             self._updates['BEAM_DIVERGENCE_E.S.D.']))
      elif self._params.beam_divergence and self._params.beam_divergence_esd:
        xds_inp.write(
            'BEAM_DIVERGENCE=%f BEAM_DIVERGENCE_E.S.D.=%f\n' % \
            (self._params.beam_divergence,
             self._params.beam_divergence_esd))

      if self._updates.has_key('REFLECTING_RANGE') and \
             self._updates.has_key('REFLECTING_RANGE_E.S.D.'):
        xds_inp.write(
            'REFLECTING_RANGE=%f REFLECTING_RANGE_E.S.D.=%f\n' % \
            (self._updates['REFLECTING_RANGE'],
             self._updates['REFLECTING_RANGE_E.S.D.']))
      elif self._params.reflecting_range and self._params.reflecting_range_esd:
        xds_inp.write(
            'REFLECTING_RANGE=%f REFLECTING_RANGE_E.S.D.=%f\n' % \
            (self._params.reflecting_range,
             self._params.reflecting_range_esd))

      for record in header:
        xds_inp.write('%s\n' % record)

      name_template = os.path.join(self.get_directory(),
                                   self.get_template().replace('#', '?'))

      record = 'NAME_TEMPLATE_OF_DATA_FRAMES=%s\n' % \
               name_template

      xds_inp.write(record)

      xds_inp.write('DATA_RANGE=%d %d\n' % self._data_range)
      # xds_inp.write('MINIMUM_ZETA=0.1\n')

      xds_inp.close()

      # copy the input file...
      shutil.copyfile(os.path.join(self.get_working_directory(),
                                   'XDS.INP'),
                      os.path.join(self.get_working_directory(),
                                   '%d_INTEGRATE.INP' % self.get_xpid()))

      # write the input data files...

      for file_name in self._input_data_files_list:
        src = self._input_data_files[file_name]
        dst = os.path.join(
            self.get_working_directory(), file_name)
        if src != dst:
          shutil.copyfile(src, dst)

      self.start()
      self.close_wait()

      xds_check_version_supported(self.get_all_output())
      xds_check_error(self.get_all_output())

      # look for errors
      # like this perhaps - what the hell does this mean?
      #   !!! ERROR !!! "STRONGHKL": ASSERT VIOLATION

      # copy the LP file
      shutil.copyfile(os.path.join(self.get_working_directory(),
                                   'INTEGRATE.LP'),
                      os.path.join(self.get_working_directory(),
                                   '%d_INTEGRATE.LP' % self.get_xpid()))

      # gather the output files

      for file in self._output_data_files_list:
        self._output_data_files[file] = os.path.join(
          self.get_working_directory(), file)

      self._integrate_hkl = os.path.join(self.get_working_directory(),
                                         'INTEGRATE.HKL')

      # look through integrate.lp for some useful information
      # to help with the analysis

      space_group_number = 0

      mosaics = []

      for o in open(os.path.join(
          self.get_working_directory(),
          'INTEGRATE.LP')).readlines():
        if 'SPACE_GROUP_NUMBER' in o:
          space_group_number = int(o.split()[-1])
        if 'CRYSTAL MOSAICITY (DEGREES)' in o:
          mosaic = float(o.split()[-1])
          mosaics.append(mosaic)

      assert len(mosaics) > 0, "XDS refinement failed (no mosaic spread range reported)"
      self._min_mosaic = min(mosaics)
      self._max_mosaic = max(mosaics)
      self._mean_mosaic = sum(mosaics) / len(mosaics)

      Debug.write(
          'Mosaic spread range: %.3f %.3f %.3f' % \
          (self._min_mosaic, self._mean_mosaic, self._max_mosaic))

      stats = _parse_integrate_lp(os.path.join(
          self.get_working_directory(),
          'INTEGRATE.LP'))

      self._per_image_statistics = stats

      self._updates = _parse_integrate_lp_updates(os.path.join(
          self.get_working_directory(),
          'INTEGRATE.LP'))

      return
Пример #12
0
    def run(self, method):
      from xia2.Handlers.Streams import Debug
      Debug.write('Running dials.index')

      self.clear_command_line()
      for f in self._sweep_filenames:
        self.add_command_line(f)
      for f in self._spot_filenames:
        self.add_command_line(f)
      self.add_command_line('indexing.method=%s' % method)
      nproc = Flags.get_parallel()
      self.set_cpu_threads(nproc)
      self.add_command_line('indexing.nproc=%i' % nproc)
      if Flags.get_small_molecule():
        self.add_command_line('filter_ice=false')
      if self._reflections_per_degree is not None:
        self.add_command_line(
          'reflections_per_degree=%i' %self._reflections_per_degree)
      if self._fft3d_n_points is not None:
        self.add_command_line(
          'fft3d.reciprocal_space_grid.n_points=%i' %self._fft3d_n_points)
      if self._close_to_spindle_cutoff is not None:
        self.add_command_line(
          'close_to_spindle_cutoff=%f' %self._close_to_spindle_cutoff)
      if self._outlier_algorithm:
        self.add_command_line('outlier.algorithm=%s' % self._outlier_algorithm)
      if self._max_cell:
        self.add_command_line('max_cell=%d' % self._max_cell)
      if self._min_cell:
        self.add_command_line('min_cell=%d' % self._min_cell)
      if self._d_min_start:
        self.add_command_line('d_min_start=%f' % self._d_min_start)
      if self._indxr_input_lattice is not None:
        from xia2.Experts.SymmetryExpert import lattice_to_spacegroup_number
        self._symm = lattice_to_spacegroup_number(
            self._indxr_input_lattice)
        self.add_command_line('known_symmetry.space_group=%s' % self._symm)
      if self._indxr_input_cell is not None:
        self.add_command_line(
          'known_symmetry.unit_cell="%s,%s,%s,%s,%s,%s"' %self._indxr_input_cell)
      if self._maximum_spot_error:
        self.add_command_line('maximum_spot_error=%.f' %
                              self._maximum_spot_error)
      if self._detector_fix:
        self.add_command_line('detector.fix=%s' % self._detector_fix)
      if self._beam_fix:
        self.add_command_line('beam.fix=%s' % self._beam_fix)
      if self._phil_file is not None:
        self.add_command_line("%s" %self._phil_file)

      self._experiment_filename = os.path.join(
        self.get_working_directory(), '%d_experiments.json' %self.get_xpid())
      self._indexed_filename = os.path.join(
        self.get_working_directory(), '%d_indexed.pickle' %self.get_xpid())
      self.add_command_line("output.experiments=%s" %self._experiment_filename)
      self.add_command_line("output.reflections=%s" %self._indexed_filename)

      self.start()
      self.close_wait()
      self.check_for_errors()

      records = self.get_all_output()

      for i, record in enumerate(records):
        if 'Unit cell:' in record:
          self._p1_cell = map(float, record.replace('(', '').replace(
            ')', '').replace(',', '').split()[-6:])

        if 'Final RMSDs by experiment' in record:
          values = records[i+6].strip().strip('|').split('|')
          if len(values):
            values = [float(v) for v in values]
            if values[0] == 0:
              self._nref = int(values[1])
              self._rmsd_x = values[2]
              self._rmsd_y = values[3]
              self._rmsd_z = values[4]

      return
Пример #13
0
    def multi_merge(self):
      '''Merge data from multiple runs - this is very similar to
      the scaling subroutine...'''

      self.check_hklin()
      self.check_hklout()

      if not self._scalepack:
        self.set_task('Scaling reflections from %s => %s' % \
                     (os.path.split(self.get_hklin())[-1],
                      os.path.split(self.get_hklout())[-1]))
      else:
        self.set_task('Scaling reflections from %s => scalepack %s' % \
                     (os.path.split(self.get_hklin())[-1],
                      os.path.split(self.get_hklout())[-1]))

      self.start()

      self._xmlout = os.path.join(self.get_working_directory(),
                                  '%d_aimless.xml' % self.get_xpid())

      self.input('xmlout %d_aimless.xml' % self.get_xpid())
      if not Flags.get_small_molecule():
        self.input('bins 20')

      if self._new_scales_file:
        self.input('dump %s' % self._new_scales_file)

      if self._resolution:
        self.input('resolution %f' % self._resolution)

      run_number = 0
      for run in self._runs:
        run_number += 1

        if not run[5]:
          self.input('run %d batch %d to %d' % (run_number,
                                                run[0], run[1]))

        if run[6] != 0.0 and not run[5]:
          self.input('resolution run %d high %f' % \
                     (run_number, run[6]))

      # put in the pname, xname, dname stuff
      run_number = 0
      for run in self._runs:
        run_number += 1

        if run[7]:
          Debug.write('Run %d corresponds to sweep %s' % \
                      (run_number, run[7]))

        if run[5]:
          continue

      # we are only merging here so the scales command is
      # dead simple...

      self.input('scales constant')

      if self._anomalous:
        self.input('anomalous on')
      else:
        self.input('anomalous off')

      # FIXME this is probably not ready to be used yet...
      if self._scalepack:
        self.input('output polish unmerged')
      self.input('output unmerged')

      if self._scales_file:
        self.input('onlymerge')
        self.input('restore %s' % self._scales_file)

      self.close_wait()

      # check for errors

      try:
        self.check_for_errors()
        self.check_ccp4_errors()
        self.check_aimless_errors()

        status = 'OK'

        Debug.write('Aimless status: %s' % status)

        if 'Error' in status:
          raise RuntimeError, '[AIMLESS] %s' % status

      except RuntimeError, e:
        try:
          os.remove(self.get_hklout())
        except:
          pass

        raise e
Пример #14
0
    def scale(self):
      '''Actually perform the scaling.'''

      self.check_hklin()
      self.check_hklout()

      if self._chef_unmerged and self._scalepack:
        raise RuntimeError, 'CHEF and scalepack incompatible'

      if self._onlymerge:
        raise RuntimeError, 'use merge() method'

      if not self._scalepack:
        self.set_task('Scaling reflections from %s => %s' % \
                     (os.path.split(self.get_hklin())[-1],
                      os.path.split(self.get_hklout())[-1]))
      else:
        self.set_task('Scaling reflections from %s => scalepack %s' % \
                     (os.path.split(self.get_hklin())[-1],
                      os.path.split(self.get_hklout())[-1]))

      self._xmlout = os.path.join(self.get_working_directory(),
                                  '%d_aimless.xml' % self.get_xpid())

      self.start()

      nproc = Flags.get_parallel()
      if nproc > 1:
        self.set_working_environment('OMP_NUM_THREADS', '%d' %nproc)
        self.input('refine parallel')
      self.input('xmlout %d_aimless.xml' % self.get_xpid())
      if not Flags.get_small_molecule():
        self.input('bins 20')
      self.input('intensities %s' %self._intensities)

      if self._new_scales_file:
        self.input('dump %s' % self._new_scales_file)

      run_number = 0
      for run in self._runs:
        run_number += 1

        if not run[5]:
          self.input('run %d batch %d to %d' % (run_number,
                                                run[0], run[1]))

        if run[6] != 0.0 and not run[5]:
          self.input('resolution run %d high %f' % \
                     (run_number, run[6]))

      run_number = 0
      for run in self._runs:
        run_number += 1

        if run[7]:
          Debug.write('Run %d corresponds to sweep %s' % \
                      (run_number, run[7]))

        if run[5]:
          continue

      self.input('sdcorrection same')

      # FIXME this is a bit of a hack - should be better determined
      # than this...
      if Flags.get_small_molecule():
        #self.input('sdcorrection tie sdfac 0.707 0.3 tie sdadd 0.01 0.05')
        #self.input('reject all 30')
        self.input('sdcorrection fixsdb')

      if self._secondary and self._surface_tie:
        self.input('tie surface %.4f' % self._surface_tie)
        if not self._surface_link:
          self.input('unlink all')

      # assemble the scales command
      if self._mode == 'rotation':
        scale_command = 'scales rotation spacing %f' % self._spacing

        if self._secondary:
          nterm = int(self._secondary)
          if self._fixed_secondary_lmax:
            scale_command += ' secondary %d %d absorption %d %d' % \
              (nterm, nterm - 1, nterm, nterm - 1)
          else:
            scale_command += ' secondary %d absorption %d' % \
              (nterm, nterm)

        if self._bfactor:
          scale_command += ' bfactor on'

          if self._brotation:
            scale_command += ' brotation %f' % \
                             self._brotation

        else:
          scale_command += ' bfactor off'

        if self._tails:
          scale_command += ' tails'

        self.input(scale_command)

      else:

        scale_command = 'scales batch'

        if self._bfactor:
          scale_command += ' bfactor on'

          if self._brotation:
            scale_command += ' brotation %f' % \
                             self._brotation
          else:
            scale_command += ' brotation %f' % \
                             self._spacing

        else:
          scale_command += ' bfactor off'

        if self._tails:
          scale_command += ' tails'

        self.input(scale_command)

      # Debug.write('Scaling command: "%s"' % scale_command)

      # next any 'generic' parameters

      if self._resolution:
        self.input('resolution %f' % self._resolution)

      if self._resolution_by_run != { }:
        # FIXME 20/NOV/06 this needs implementing somehow...
        pass

      self.input('cycles %d' % self._cycles)

      if self._anomalous:
        self.input('anomalous on')
      else:
        self.input('anomalous off')

      if self._scalepack:
        self.input('output polish unmerged')
      elif self._chef_unmerged:
        self.input('output unmerged together')
      else:
        self.input('output unmerged')

      # run using previously determined scales

      if self._scales_file:
        self.input('onlymerge')
        self.input('restore %s' % self._scales_file)

      self.close_wait()

      # check for errors

      if True:
        # try:
        try:
          self.check_for_errors()
          self.check_ccp4_errors()
          self.check_aimless_error_negative_scale_run()
          self.check_aimless_errors()
        except Exception, e:
          Chatter.write(
            "Aimless failed, see log file for more details:\n  %s" %self.get_log_file())
          raise

        status = 'OK'

        Debug.write('Aimless status: %s' % status)

        if 'Error' in status:
          raise RuntimeError, '[AIMLESS] %s' % status
Пример #15
0
  def _sort_together_data_ccp4(self):
    '''Sort together in the right order (rebatching as we go) the sweeps
    we want to scale together.'''

    max_batches = 0

    for e in self._sweep_handler.get_epochs():
      if Flags.get_small_molecule():
        continue
      si = self._sweep_handler.get_sweep_information(e)

      pname, xname, dname = si.get_project_info()
      sname = si.get_sweep_name()



    for epoch in self._sweep_handler.get_epochs():

      si = self._sweep_handler.get_sweep_information(epoch)
      hklin = si.get_reflections()

      # limit the reflections - e.g. if we are re-running the scaling step
      # on just a subset of the integrated data

      hklin = si.get_reflections()
      limit_batch_range = None
      for sweep in PhilIndex.params.xia2.settings.sweep:
        if sweep.id == sname and sweep.range is not None:
          limit_batch_range = sweep.range
          break

      if limit_batch_range is not None:
        Debug.write('Limiting batch range for %s: %s' %(sname, limit_batch_range))
        start, end = limit_batch_range
        hklout = os.path.splitext(hklin)[0] + '_tmp.mtz'
        FileHandler.record_temporary_file(hklout)
        rb = self._factory.Pointless()
        rb.set_hklin(hklin)
        rb.set_hklout(hklout)
        rb.limit_batches(start, end)
        si.set_reflections(hklout)
        si.set_batches(limit_batch_range)

      # keep a count of the maximum number of batches in a block -
      # this will be used to make rebatch work below.

      hklin = si.get_reflections()
      md = self._factory.Mtzdump()
      md.set_hklin(hklin)
      md.dump()

      batches = md.get_batches()
      if 1 + max(batches) - min(batches) > max_batches:
        max_batches = max(batches) - min(batches) + 1

      datasets = md.get_datasets()

      Debug.write('In reflection file %s found:' % hklin)
      for d in datasets:
        Debug.write('... %s' % d)

      dataset_info = md.get_dataset_info(datasets[0])

    Debug.write('Biggest sweep has %d batches' % max_batches)
    max_batches = nifty_power_of_ten(max_batches)

    # then rebatch the files, to make sure that the batch numbers are
    # in the same order as the epochs of data collection.

    counter = 0

    for epoch in self._sweep_handler.get_epochs():

      si = self._sweep_handler.get_sweep_information(epoch)
      rb = self._factory.Rebatch()

      hklin = si.get_reflections()

      pname, xname, dname = si.get_project_info()
      sname = si.get_sweep_name()

      hklout = os.path.join(self.get_working_directory(),
                            '%s_%s_%s_%s_integrated.mtz' % \
                            (pname, xname, dname, sname))

      first_batch = min(si.get_batches())
      si.set_batch_offset(counter * max_batches - first_batch + 1)

      rb.set_hklin(hklin)
      rb.set_first_batch(counter * max_batches + 1)
      rb.set_project_info(pname, xname, dname)
      rb.set_hklout(hklout)

      new_batches = rb.rebatch()

      # update the "input information"

      si.set_reflections(hklout)
      si.set_batches(new_batches)

      # update the counter & recycle

      counter += 1

    s = self._factory.Sortmtz()

    hklout = os.path.join(self.get_working_directory(),
                          '%s_%s_sorted.mtz' % \
                          (self._scalr_pname, self._scalr_xname))

    s.set_hklout(hklout)

    for epoch in self._sweep_handler.get_epochs():
      s.add_hklin(self._sweep_handler.get_sweep_information(
          epoch).get_reflections())

    s.sort()

    # verify that the measurements are in the correct setting
    # choice for the spacegroup

    hklin = hklout
    hklout = hklin.replace('sorted.mtz', 'temp.mtz')

    if not self.get_scaler_reference_reflection_file():

      p = self._factory.Pointless()

      FileHandler.record_log_file('%s %s pointless' % \
                                  (self._scalr_pname,
                                   self._scalr_xname),
                                  p.get_log_file())

      if len(self._sweep_handler.get_epochs()) > 1:
        p.set_hklin(hklin)
      else:
        # permit the use of pointless preparation...
        epoch = self._sweep_handler.get_epochs()[0]
        p.set_hklin(self._prepare_pointless_hklin(
            hklin, self._sweep_handler.get_sweep_information(
            epoch).get_integrater().get_phi_width()))

      if self._scalr_input_spacegroup:
        Debug.write('Assigning user input spacegroup: %s' % \
                    self._scalr_input_spacegroup)

        p.decide_spacegroup()
        spacegroup = p.get_spacegroup()
        reindex_operator = p.get_spacegroup_reindex_operator()

        Debug.write('Pointless thought %s (reindex as %s)' % \
                    (spacegroup, reindex_operator))

        spacegroup = self._scalr_input_spacegroup
        reindex_operator = 'h,k,l'

      elif Flags.get_small_molecule() and False:
        p.decide_pointgroup()
        spacegroup = p.get_pointgroup()
        reindex_operator = p.get_reindex_operator()

        Debug.write('Pointless thought %s (reindex as %s)' % \
                    (spacegroup, reindex_operator))
        self._scalr_likely_spacegroups = [spacegroup]

      else:
        p.decide_spacegroup()
        spacegroup = p.get_spacegroup()
        reindex_operator = p.get_spacegroup_reindex_operator()

        Debug.write('Pointless thought %s (reindex as %s)' % \
                    (spacegroup, reindex_operator))

      if self._scalr_input_spacegroup:
        self._scalr_likely_spacegroups = [self._scalr_input_spacegroup]
      else:
        self._scalr_likely_spacegroups = p.get_likely_spacegroups()

      Chatter.write('Likely spacegroups:')
      for spag in self._scalr_likely_spacegroups:
        Chatter.write('%s' % spag)

      Chatter.write(
          'Reindexing to first spacegroup setting: %s (%s)' % \
          (spacegroup, clean_reindex_operator(reindex_operator)))

    else:

      md = self._factory.Mtzdump()
      md.set_hklin(self.get_scaler_reference_reflection_file())
      md.dump()

      spacegroup = md.get_spacegroup()
      reindex_operator = 'h,k,l'

      self._scalr_likely_spacegroups = [spacegroup]

      Debug.write('Assigning spacegroup %s from reference' % \
                  spacegroup)

    # then run reindex to set the correct spacegroup

    ri = self._factory.Reindex()
    ri.set_hklin(hklin)
    ri.set_hklout(hklout)
    ri.set_spacegroup(spacegroup)
    ri.set_operator(reindex_operator)
    ri.reindex()

    FileHandler.record_temporary_file(hklout)

    # then resort the reflections (one last time!)

    s = self._factory.Sortmtz()

    temp = hklin
    hklin = hklout
    hklout = temp

    s.add_hklin(hklin)
    s.set_hklout(hklout)

    s.sort()

    # done preparing!

    self._prepared_reflections = s.get_hklout()

    return
Пример #16
0
  def _scale(self):
    '''Actually scale all of the data together.'''

    from xia2.Handlers.Environment import debug_memory_usage
    debug_memory_usage()

    Journal.block(
        'scaling', self.get_scaler_xcrystal().get_name(), 'XSCALE',
        {'scaling model':'default (all)'})

    epochs = self._sweep_information.keys()
    epochs.sort()

    xscale = self.XScale()

    xscale.set_spacegroup_number(self._xds_spacegroup)
    xscale.set_cell(self._scalr_cell)

    Debug.write('Set CELL: %.2f %.2f %.2f %.2f %.2f %.2f' % \
                tuple(self._scalr_cell))
    Debug.write('Set SPACEGROUP_NUMBER: %d' % \
                self._xds_spacegroup)

    Debug.write('Gathering measurements for scaling')

    for epoch in epochs:

      # get the prepared reflections
      reflections = self._sweep_information[epoch][
          'prepared_reflections']

      # and the get wavelength that this belongs to
      dname = self._sweep_information[epoch]['dname']
      sname = self._sweep_information[epoch]['sname']

      # and the resolution range for the reflections
      intgr = self._sweep_information[epoch]['integrater']
      Debug.write('Epoch: %d' % epoch)
      Debug.write('HKL: %s (%s/%s)' % (reflections, dname, sname))

      resolution_low = intgr.get_integrater_low_resolution()
      resolution_high = self._scalr_resolution_limits.get((dname, sname), 0.0)

      resolution = (resolution_high, resolution_low)

      xscale.add_reflection_file(reflections, dname, resolution)

    # set the global properties of the sample
    xscale.set_crystal(self._scalr_xname)
    xscale.set_anomalous(self._scalr_anomalous)

    if Flags.get_zero_dose():
      Debug.write('Switching on zero-dose extrapolation')
      xscale.set_zero_dose()

    debug_memory_usage()
    xscale.run()

    scale_factor = xscale.get_scale_factor()

    Debug.write('XSCALE scale factor found to be: %e' % scale_factor)

    # record the log file

    pname = self._scalr_pname
    xname = self._scalr_xname

    FileHandler.record_log_file('%s %s XSCALE' % \
                                (pname, xname),
                                os.path.join(self.get_working_directory(),
                                             'XSCALE.LP'))

    # check for outlier reflections and if a number are found
    # then iterate (that is, rerun XSCALE, rejecting these outliers)

    if not Flags.get_quick() and Flags.get_remove():
      if len(xscale.get_remove()) > 0:

        xscale_remove = xscale.get_remove()
        current_remove = []
        final_remove = []

        # first ensure that there are no duplicate entries...
        if os.path.exists(os.path.join(
            self.get_working_directory(),
            'REMOVE.HKL')):
          for line in open(os.path.join(
              self.get_working_directory(),
              'REMOVE.HKL'), 'r').readlines():
            h, k, l = map(int, line.split()[:3])
            z = float(line.split()[3])

            if not (h, k, l, z) in current_remove:
              current_remove.append((h, k, l, z))

          for c in xscale_remove:
            if c in current_remove:
              continue
            final_remove.append(c)

          Debug.write(
              '%d alien reflections are already removed' % \
              (len(xscale_remove) - len(final_remove)))

        else:
          # we want to remove all of the new dodgy reflections
          final_remove = xscale_remove

        remove_hkl = open(os.path.join(
            self.get_working_directory(),
            'REMOVE.HKL'), 'w')

        z_min = Flags.get_z_min()
        rejected = 0

        # write in the old reflections
        for remove in current_remove:
          z = remove[3]
          if z >= z_min:
            remove_hkl.write('%d %d %d %f\n' % remove)
          else:
            rejected += 1
        Debug.write('Wrote %d old reflections to REMOVE.HKL' % \
                    (len(current_remove) - rejected))
        Debug.write('Rejected %d as z < %f' % \
                    (rejected, z_min))

        # and the new reflections
        rejected = 0
        used = 0
        for remove in final_remove:
          z = remove[3]
          if z >= z_min:
            used += 1
            remove_hkl.write('%d %d %d %f\n' % remove)
          else:
            rejected += 1
        Debug.write('Wrote %d new reflections to REMOVE.HKL' % \
                    (len(final_remove) - rejected))
        Debug.write('Rejected %d as z < %f' % \
                    (rejected, z_min))

        remove_hkl.close()

        # we want to rerun the finishing step so...
        # unless we have added no new reflections
        if used:
          self.set_scaler_done(False)

    if not self.get_scaler_done():
      Chatter.write('Excluding outlier reflections Z > %.2f' %
                    Flags.get_z_min())

      if Flags.get_egg():
        for record in ttt():
          Chatter.write(record)
      return

    debug_memory_usage()

    # now get the reflection files out and merge them with aimless

    output_files = xscale.get_output_reflection_files()
    wavelength_names = output_files.keys()

    # these are per wavelength - also allow for user defined resolution
    # limits a la bug # 3183. No longer...

    for epoch in self._sweep_information.keys():

      input = self._sweep_information[epoch]

      intgr = input['integrater']

      rkey = input['dname'], input['sname']

      if intgr.get_integrater_user_resolution():
        dmin = intgr.get_integrater_high_resolution()

        if not self._user_resolution_limits.has_key(rkey):
          self._scalr_resolution_limits[rkey] = dmin
          self._user_resolution_limits[rkey] = dmin
        elif dmin < self._user_resolution_limits[rkey]:
          self._scalr_resolution_limits[rkey] = dmin
          self._user_resolution_limits[rkey] = dmin

    self._scalr_scaled_refl_files = { }

    self._scalr_statistics = { }

    max_batches = 0
    mtz_dict = { }

    project_info = { }
    for epoch in self._sweep_information.keys():
      pname = self._scalr_pname
      xname = self._scalr_xname
      dname = self._sweep_information[epoch]['dname']
      reflections = os.path.split(
          self._sweep_information[epoch]['prepared_reflections'])[-1]
      project_info[reflections] = (pname, xname, dname)

    for epoch in self._sweep_information.keys():
      self._sweep_information[epoch]['scaled_reflections'] = None

    debug_memory_usage()

    for wavelength in wavelength_names:
      hklin = output_files[wavelength]

      xsh = XDSScalerHelper()
      xsh.set_working_directory(self.get_working_directory())

      ref = xsh.split_and_convert_xscale_output(
          hklin, 'SCALED_', project_info, 1.0 / scale_factor)

      for hklout in ref.keys():
        for epoch in self._sweep_information.keys():
          if os.path.split(self._sweep_information[epoch][
              'prepared_reflections'])[-1] == \
              os.path.split(hklout)[-1]:
            if self._sweep_information[epoch][
                'scaled_reflections'] != None:
              raise RuntimeError, 'duplicate entries'
            self._sweep_information[epoch][
                'scaled_reflections'] = ref[hklout]

      del(xsh)

    debug_memory_usage()

    for epoch in self._sweep_information.keys():
      hklin = self._sweep_information[epoch]['scaled_reflections']
      dname = self._sweep_information[epoch]['dname']
      sname = self._sweep_information[epoch]['sname']

      hkl_copy = os.path.join(self.get_working_directory(),
                              'R_%s' % os.path.split(hklin)[-1])

      if not os.path.exists(hkl_copy):
        shutil.copyfile(hklin, hkl_copy)

      # let's properly listen to the user's resolution limit needs...

      if self._user_resolution_limits.get((dname, sname), False):
        resolution = self._user_resolution_limits[(dname, sname)]

      else:
        resolution = self._estimate_resolution_limit(hklin)

      Chatter.write('Resolution for sweep %s/%s: %.2f' % \
                    (dname, sname, resolution))

      if not (dname, sname) in self._scalr_resolution_limits:
        self._scalr_resolution_limits[(dname, sname)] = resolution
        self.set_scaler_done(False)
      else:
        if resolution < self._scalr_resolution_limits[(dname, sname)]:
          self._scalr_resolution_limits[(dname, sname)] = resolution
          self.set_scaler_done(False)

    debug_memory_usage()

    if not self.get_scaler_done():
      Debug.write('Returning as scaling not finished...')
      return

    self._sort_together_data_xds()

    highest_resolution = min(self._scalr_resolution_limits.values())

    self._scalr_highest_resolution = highest_resolution

    Debug.write('Scaler highest resolution set to %5.2f' % \
                highest_resolution)

    if not self.get_scaler_done():
      Debug.write('Returning as scaling not finished...')
      return

    sdadd_full = 0.0
    sdb_full = 0.0

    # ---------- FINAL MERGING ----------

    sc = self._factory.Aimless()

    FileHandler.record_log_file('%s %s aimless' % (self._scalr_pname,
                                                   self._scalr_xname),
                                sc.get_log_file())

    sc.set_resolution(highest_resolution)
    sc.set_hklin(self._prepared_reflections)
    sc.set_new_scales_file('%s_final.scales' % self._scalr_xname)

    if sdadd_full == 0.0 and sdb_full == 0.0:
      pass
    else:
      sc.add_sd_correction('both', 1.0, sdadd_full, sdb_full)

    for epoch in epochs:
      input = self._sweep_information[epoch]
      start, end = (min(input['batches']), max(input['batches']))

      rkey = input['dname'], input['sname']
      run_resolution_limit = self._scalr_resolution_limits[rkey]

      sc.add_run(start, end, exclude = False,
                 resolution = run_resolution_limit,
                 name = input['sname'])

    sc.set_hklout(os.path.join(self.get_working_directory(),
                               '%s_%s_scaled.mtz' % \
                               (self._scalr_pname, self._scalr_xname)))

    if self.get_scaler_anomalous():
      sc.set_anomalous()

    sc.multi_merge()

    FileHandler.record_xml_file('%s %s aimless xml' % (self._scalr_pname,
                                                       self._scalr_xname),
                                sc.get_xmlout())
    data = sc.get_summary()

    loggraph = sc.parse_ccp4_loggraph()

    standard_deviation_info = { }

    for key in loggraph.keys():
      if 'standard deviation v. Intensity' in key:
        dataset = key.split(',')[-1].strip()
        standard_deviation_info[dataset] = transpose_loggraph(
            loggraph[key])

    resolution_info = { }

    for key in loggraph.keys():
      if 'Analysis against resolution' in key:
        dataset = key.split(',')[-1].strip()
        resolution_info[dataset] = transpose_loggraph(
            loggraph[key])

    # and also radiation damage stuff...

    batch_info = { }

    for key in loggraph.keys():
      if 'Analysis against Batch' in key:
        dataset = key.split(',')[-1].strip()
        batch_info[dataset] = transpose_loggraph(
            loggraph[key])


    # finally put all of the results "somewhere useful"

    self._scalr_statistics = data

    self._scalr_scaled_refl_files = copy.deepcopy(
        sc.get_scaled_reflection_files())

    self._scalr_scaled_reflection_files = { }

    # also output the unmerged scalepack format files...

    sc = self._factory.Aimless()
    sc.set_resolution(highest_resolution)
    sc.set_hklin(self._prepared_reflections)
    sc.set_scalepack()

    for epoch in epochs:
      input = self._sweep_information[epoch]
      start, end = (min(input['batches']), max(input['batches']))

      rkey = input['dname'], input['sname']
      run_resolution_limit = self._scalr_resolution_limits[rkey]

      sc.add_run(start, end, exclude = False,
                 resolution = run_resolution_limit,
                 name = input['sname'])

    sc.set_hklout(os.path.join(self.get_working_directory(),
                               '%s_%s_scaled.mtz' % \
                               (self._scalr_pname,
                                self._scalr_xname)))

    if self.get_scaler_anomalous():
      sc.set_anomalous()

    sc.multi_merge()

    self._scalr_scaled_reflection_files['sca_unmerged'] = { }
    self._scalr_scaled_reflection_files['mtz_unmerged'] = { }

    for dataset in sc.get_scaled_reflection_files().keys():
      hklout = sc.get_scaled_reflection_files()[dataset]

      # then mark the scalepack files for copying...

      scalepack = os.path.join(os.path.split(hklout)[0],
                               os.path.split(hklout)[1].replace(
          '_scaled', '_scaled_unmerged').replace('.mtz', '.sca'))
      self._scalr_scaled_reflection_files['sca_unmerged'][
          dataset] = scalepack
      FileHandler.record_data_file(scalepack)
      mtz_unmerged = os.path.splitext(scalepack)[0] + '.mtz'
      self._scalr_scaled_reflection_files['mtz_unmerged'][dataset] = mtz_unmerged
      FileHandler.record_data_file(mtz_unmerged)

    if PhilIndex.params.xia2.settings.merging_statistics.source == 'cctbx':
      for key in self._scalr_scaled_refl_files:
        stats = self._compute_scaler_statistics(
          self._scalr_scaled_reflection_files['mtz_unmerged'][key])
        self._scalr_statistics[
          (self._scalr_pname, self._scalr_xname, key)] = stats

    # convert reflection files to .sca format - use mtz2various for this

    self._scalr_scaled_reflection_files['sca'] = { }
    self._scalr_scaled_reflection_files['hkl'] = { }

    for key in self._scalr_scaled_refl_files:

      f = self._scalr_scaled_refl_files[key]
      scaout = '%s.sca' % f[:-4]

      m2v = self._factory.Mtz2various()
      m2v.set_hklin(f)
      m2v.set_hklout(scaout)
      m2v.convert()

      self._scalr_scaled_reflection_files['sca'][key] = scaout
      FileHandler.record_data_file(scaout)

      if Flags.get_small_molecule():
        hklout = '%s.hkl' % f[:-4]

        m2v = self._factory.Mtz2various()
        m2v.set_hklin(f)
        m2v.set_hklout(hklout)
        m2v.convert_shelx()

        self._scalr_scaled_reflection_files['hkl'][key] = hklout
        FileHandler.record_data_file(hklout)

    return