Beispiel #1
0
def test_lauegroup_to_lattice_functions(ccp4):
    from xia2.lib.SymmetryLib import lauegroup_to_lattice

    assert lauegroup_to_lattice("I m m m") == "oI"
    assert lauegroup_to_lattice("C 1 2/m 1") == "mC"
    assert lauegroup_to_lattice("P -1") == "aP"
    assert lauegroup_to_lattice("P 4/mmm") == "tP"
Beispiel #2
0
    def _scale_setup(self):
        '''Set things up for scaling, in particular mediate pointgroup /
    lattice with the indexers.'''

        assert (self._scalr_integraters)

        epochs = sorted(self._scalr_integraters)
        integraters = [self._scalr_integraters[e] for e in epochs]

        pointgroups = [self._scale_setup_integrater(i) for i in integraters]
        lattices = [lauegroup_to_lattice(p) for p in pointgroups]

        unique_lattices = list(set(lattices))

        # consider the situation that they arrived at more than one conclusion

        if len(unique_lattices) > 1:
            consensus_lattice = sort_lattices(unique_lattices)[0]

            for integrater in integraters:
                refiner = integrater.get_integrater_refiner()
                state = refiner.set_refiner_asserted_lattice(consensus_lattice)

                assert (state != refiner.LATTICE_IMPOSSIBLE)

        # then decide on the consensus pointgroup

        pointgroups = set([])

        for integrater in integraters:
            pointgroups = self._scale_list_likely_pointgroups(integrater)
            lattices = [lauegroup_to_lattice(p) for p in pointgroups]
            poingroups.add(pointgroups[lattices.index(consensus_lattice)])

        # FIXME will need to handle twinned cases more gracefully sometime
        # FIXME also need to "mend" the integrater set spacegroup API

        assert (len(pointgroups) == 1)

        for integrater in integraters:
            integrater.set_integrater_spacegroup_number(pointgroup)

        # now reindex to the correct setting

        reference = integraters[0]

        for integrater in integraters[1:]:
            self._scale_reindex_to_reference(reference, integrater)

        return pointgroups[0]
Beispiel #3
0
  def _scale_setup(self):
    '''Set things up for scaling, in particular mediate pointgroup /
    lattice with the indexers.'''

    assert(self._scalr_integraters)

    epochs = sorted(self._scalr_integraters)
    integraters = [self._scalr_integraters[e] for e in epochs]

    pointgroups = [self._scale_setup_integrater(i) for i in integraters]
    lattices = [lauegroup_to_lattice(p) for p in pointgroups]

    unique_lattices = list(set(lattices))

    # consider the situation that they arrived at more than one conclusion

    if len(unique_lattices) > 1:
      consensus_lattice = sort_lattices(unique_lattices)[0]

      for integrater in integraters:
        refiner = integrater.get_integrater_refiner()
        state = refiner.set_refiner_asserted_lattice(consensus_lattice)

        assert(state != refiner.LATTICE_IMPOSSIBLE)

    # then decide on the consensus pointgroup

    pointgroups = set([])

    for integrater in integraters:
      pointgroups = self._scale_list_likely_pointgroups(integrater)
      lattices = [lauegroup_to_lattice(p) for p in pointgroups]
      poingroups.add(pointgroups[lattices.index(consensus_lattice)])

    # FIXME will need to handle twinned cases more gracefully sometime
    # FIXME also need to "mend" the integrater set spacegroup API

    assert(len(pointgroups) == 1)

    for integrater in integraters:
      integrater.set_integrater_spacegroup_number(pointgroup)

    # now reindex to the correct setting

    reference = integraters[0]

    for integrater in integraters[1:]:
      self._scale_reindex_to_reference(reference, integrater)

    return pointgroups[0]
Beispiel #4
0
    def _scale_setup_integrater(self, integrater):
        '''Check that the pointgroup for a data set is consistent with
    the lattice used for integration, then determine the pointgroup for
    the data.'''

        # FIXME will have to handle gracefully user provided pointgroup

        pointgroups = self._scale_list_likely_pointgroups(integrater)
        refiner = integrater.get_integrater_refiner()
        lattices = [lauegroup_to_lattice(p) for p in pointgroups]

        correct_lattice = None

        for lattice in lattices:
            state = refiner.set_refiner_asserted_lattice(lattice)

            if state == refiner.LATTICE_CORRECT:
                correct_lattice = lattice
                break

            elif state == refiner.LATTICE_IMPOSSIBLE:
                continue

            elif state == refiner.LATTICE_POSSIBLE:
                correct_lattice = lattice
                break

        assert (correct_lattice)

        # run this analysis again, which may respond in different conclusions
        # if it triggers the reprocessing of the data with a new lattice

        pointgroups = self._scale_list_likely_pointgroups(integrater)
        lattices = [lauegroup_to_lattice(p) for p in pointgroups]

        return pointgroups[lattices.index(correct_lattice)]
Beispiel #5
0
  def _scale_setup_integrater(self, integrater):
    '''Check that the pointgroup for a data set is consistent with
    the lattice used for integration, then determine the pointgroup for
    the data.'''

    # FIXME will have to handle gracefully user provided pointgroup

    pointgroups = self._scale_list_likely_pointgroups(integrater)
    refiner = integrater.get_integrater_refiner()
    lattices = [lauegroup_to_lattice(p) for p in pointgroups]

    correct_lattice = None

    for lattice in lattices:
      state = refiner.set_refiner_asserted_lattice(lattice)

      if state == refiner.LATTICE_CORRECT:
        correct_lattice = lattice
        break

      elif state == refiner.LATTICE_IMPOSSIBLE:
        continue

      elif state == refiner.LATTICE_POSSIBLE:
        correct_lattice = lattice
        break

    assert(correct_lattice)

    # run this analysis again, which may respond in different conclusions
    # if it triggers the reprocessing of the data with a new lattice

    pointgroups = self._scale_list_likely_pointgroups(integrater)
    lattices = [lauegroup_to_lattice(p) for p in pointgroups]

    return pointgroups[lattices.index(correct_lattice)]
Beispiel #6
0
              'LaueGroupName')[0].childNodes[0].data
          reindex = s.getElementsByTagName(
              'ReindexOperator')[0].childNodes[0].data
          netzc = float(s.getElementsByTagName(
              'NetZCC')[0].childNodes[0].data)
          likelihood = float(s.getElementsByTagName(
              'Likelihood')[0].childNodes[0].data)
          r_merge = float(s.getElementsByTagName(
              'R')[0].childNodes[0].data)
          delta = float(s.getElementsByTagName(
              'CellDelta')[0].childNodes[0].data)

          # record this as a possible lattice... if it's Z score
          # is positive, anyway

          lattice = lauegroup_to_lattice(lauegroup)
          if not lattice in self._possible_lattices:
            if netzc > 0.0:
              self._possible_lattices.append(lattice)

            # do we not always want to have access to the
            # solutions, even if they are unlikely - this will
            # only be invoked if they are known to
            # be right...

            self._lattice_to_laue[lattice] = lauegroup

      return 'ok'

    def decide_spacegroup(self):
      '''Given data indexed in the correct pointgroup, have a
Beispiel #7
0
    def generate(self):
      if not self._initial_cell:
        raise RuntimeError, 'must set the cell'
      if not self._initial_lattice_type:
        raise RuntimeError, 'must set the lattice'

      self.start()

      self.input('%f %f %f %f %f %f' % tuple(self._initial_cell))
      self.input('%s' % self._initial_lattice_type)
      self.input('')

      self.close_wait()

      # parse the output of the program...

      for o in self.get_all_output():

        if not '[' in o:
          continue
        if 'Reindex op' in o:
          continue
        if 'Same cell' in o:
          continue
        if 'Other cell' in o:
          continue
        if 'within angular tolerance' in o:
          continue

        lauegroup = o[:11].strip()
        if not lauegroup:
          continue

        if lauegroup[0] == '[':
          continue

        modded_lauegroup = ''
        for token in lauegroup.split():
          if token == '1':
            continue
          modded_lauegroup += token

        try:
          lattice = lauegroup_to_lattice(modded_lauegroup)
        except KeyError, e:
          # there was some kind of mess made of the othercell
          # output - this happens!
          continue

        cell = tuple(map(float, o[11:45].split()))
        distortion = float(o.split()[-2])
        operator = o.split()[-1][1:-1]

        if not lattice in self._lattices:
          self._lattices.append(lattice)
          self._distortions[lattice] = distortion
          self._cells[lattice] = cell
          self._reindex_ops[lattice] = operator
        else:
          if distortion > self._distortions[lattice]:
            continue
          self._distortions[lattice] = distortion
          self._cells[lattice] = cell
          self._reindex_ops[lattice] = operator
Beispiel #8
0
    def generate(self):
      if not self._cell:
        raise RuntimeError('no unit cell specified')

      if not self._spacegroup:
        raise RuntimeError('no spacegroup specified')

      self.add_command_line('--unit_cell=%f,%f,%f,%f,%f,%f' % \
                            tuple(self._cell))
      self.add_command_line('--space_group=%s' % self._spacegroup)

      self.start()
      self.close_wait()

      # now wade through all of the options and see which comes
      # out best for each lattice class... - as defined by the
      # minimum value of Maximal angular difference

      state = { }

      for o in self.get_all_output():
        # print o[:-1]
        if ':' in o:
          count = o.find(':')
          left = o[:count]
          right = o[count + 1:]
          state[left.strip()] = right.strip()

        if 'Maximal angular difference' in o:
          # transform & digest results

          distortion = float(state[
              'Maximal angular difference'].split()[0])

          # this appears to be getting the wrong cell - I want the
          # one which corresponds to the correct lattice, yes?!
          # cell = map(float, state[
          # 'Symmetry-adapted cell'].replace(
          # '(', ' ').replace(')', ' ').replace(',', ' ').split())

          cell = map(float, state[
              'Unit cell'].replace(
              '(', ' ').replace(')', ' ').replace(',', ' ').split())

          lauegroup = ''

          # FIXME for more recent versions of cctbx the conventional
          # setting I 1 2/m 1 has appeared -> look at the
          # 'Symmetry in minimum-lengths cell' instead (equivalent
          # to changing lkey here to 'Conventional setting'
          #
          # No, can't do this because this now reports the Hall
          # symmetry not the Laue group. Will have to cope with
          # the I setting instead :o(

          lkey = 'Symmetry in minimum-lengths cell'

          for token in state[lkey].split('(')[0].split():
            if token == '1':
              continue
            lauegroup += token

          # FIXME bug 3157 - there appears to be a bug in
          # recent versions of cctbx (cf. above) which means
          # a lauegroup of 'R-3m:R' is given -> correct this
          # in the string. Also :h as well :o(

          lauegroup = lauegroup.replace(':R', ':H')
          lauegroup = lauegroup.replace(':h', ':H')
          lattice = lauegroup_to_lattice(lauegroup)


          reindex_basis = state['Change of basis']
          reindex = state['Inverse']

          if not lattice in self._lattices:
            self._lattices.append(lattice)
            self._distortions[lattice] = distortion
            self._cells[lattice] = cell
            self._reindex_ops[lattice] = reindex
            self._reindex_ops_basis[lattice] = reindex_basis
          elif distortion < self._distortions[lattice]:
            self._distortions[lattice] = distortion
            self._cells[lattice] = cell
            self._reindex_ops[lattice] = reindex
            self._reindex_ops_basis[lattice] = reindex_basis

          state = { }

      return
        def decide_pointgroup(self, ignore_errors=False, batches=None):
            """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()

            if self._allow_out_of_sequence_files:
                self.input("allow outofsequencefiles")

            # https://github.com/xia2/xia2/issues/125 pass in run limits for this
            # HKLIN file - prevents automated RUN determination from causing errors
            if batches:
                self.input("run 1 batch %d to %d" % tuple(batches))

            self.input("systematicabsences off")
            self.input("setting symmetry-based")
            if self._hklref:
                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 PhilIndex.params.xia2.settings.small_molecule:
                if self._hklref:
                    self.input("tolerance 5.0")
            if PhilIndex.params.xia2.settings.symmetry.chirality is not None:
                self.input(
                    "chirality %s" % PhilIndex.params.xia2.settings.symmetry.chirality
                )

            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()

            fatal_error = False

            for j, record in enumerate(output):
                if "FATAL ERROR message:" in record:
                    if ignore_errors:
                        fatal_error = True
                    else:
                        raise RuntimeError(
                            "Pointless error: %s" % output[j + 1].strip()
                        )
                if (
                    "Resolution range of Reference data and observed data do not"
                    in record
                    and ignore_errors
                ):
                    fatal_error = True
                if "All reflection pairs rejected" in record and ignore_errors:
                    fatal_error = True
                if (
                    "Reference data and observed data do not overlap" in record
                    and ignore_errors
                ):
                    fatal_error = True

            hklin_spacegroup = ""

            # split loop - first seek hklin symmetry then later look for everything
            # else

            for o in self.get_all_output():
                if "Spacegroup from HKLIN file" in o:
                    hklin_spacegroup = spacegroup_name_xHM_to_old(
                        o.replace("Spacegroup from HKLIN file :", "").strip()
                    )
                if "Space group from HKLREF file" in o:
                    hklref_spacegroup = spacegroup_name_xHM_to_old(
                        o.replace("Space group from HKLREF file :", "").strip()
                    )

            # https://github.com/xia2/xia2/issues/115
            if fatal_error:
                assert hklref_spacegroup

                self._pointgroup = hklref_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"

            for o in self.get_all_output():
                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:
                    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()
                )

            else:

                # if we have provided a HKLREF input then the xml output
                # is changed...

                # FIXME in here, need to check if there is the legend
                # "No possible alternative indexing" in the standard
                # output, as this will mean that the index scores are
                # not there... c/f oppf1314, with latest pointless build
                # 1.2.14.

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

                try:
                    best = dom.getElementsByTagName("IndexScores")[0]
                except IndexError:
                    Debug.write("Reindex not found in xml output")

                    # check for this legend then
                    found = False
                    for record in self.get_all_output():
                        if "No possible alternative indexing" in record:
                            found = True

                    if not found:
                        raise RuntimeError("error finding solution")

                    best = None

                hklref_pointgroup = ""

                # FIXME need to get this from the reflection file HKLREF
                reflection_file_elements = dom.getElementsByTagName("ReflectionFile")

                for rf in reflection_file_elements:
                    stream = rf.getAttribute("stream")
                    if stream == "HKLREF":
                        hklref_pointgroup = (
                            rf.getElementsByTagName("SpacegroupName")[0]
                            .childNodes[0]
                            .data.strip()
                        )
                        # Chatter.write('HKLREF pointgroup is %s' % \
                        # hklref_pointgroup)

                if hklref_pointgroup == "":
                    raise RuntimeError("error finding HKLREF pointgroup")

                self._pointgroup = hklref_pointgroup

                self._confidence = 1.0
                self._totalprob = 1.0

                if best:

                    index = best.getElementsByTagName("Index")[0]

                    self._reindex_matrix = map(
                        float,
                        index.getElementsByTagName("ReindexMatrix")[0]
                        .childNodes[0]
                        .data.split(),
                    )
                    self._reindex_operator = clean_reindex_operator(
                        index.getElementsByTagName("ReindexOperator")[0]
                        .childNodes[0]
                        .data.strip()
                    )
                else:

                    # no alternative indexing is possible so just
                    # assume the default...

                    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"

            if not self._input_laue_group and not self._hklref:

                scorelist = dom.getElementsByTagName("LaueGroupScoreList")[0]
                scores = scorelist.getElementsByTagName("LaueGroupScore")

                for s in scores:
                    lauegroup = (
                        s.getElementsByTagName("LaueGroupName")[0].childNodes[0].data
                    )
                    netzc = float(
                        s.getElementsByTagName("NetZCC")[0].childNodes[0].data
                    )

                    # record this as a possible lattice if its Z score is positive

                    lattice = lauegroup_to_lattice(lauegroup)
                    if not lattice in self._possible_lattices:
                        if netzc > 0.0:
                            self._possible_lattices.append(lattice)

                        # do we not always want to have access to the
                        # solutions, even if they are unlikely - this will
                        # only be invoked if they are known to
                        # be right...

                        self._lattice_to_laue[lattice] = lauegroup

            return "ok"
Beispiel #10
0
    def generate(self):
      if not self._initial_cell:
        raise RuntimeError('must set the cell')
      if not self._initial_lattice_type:
        raise RuntimeError('must set the lattice')

      self.start()

      self.input('%f %f %f %f %f %f' % tuple(self._initial_cell))
      self.input('%s' % self._initial_lattice_type)
      self.input('')

      self.close_wait()

      # parse the output of the program...

      for o in self.get_all_output():

        if not '[' in o:
          continue
        if 'Reindex op' in o:
          continue
        if 'Same cell' in o:
          continue
        if 'Other cell' in o:
          continue
        if 'within angular tolerance' in o:
          continue

        lauegroup = o[:11].strip()
        if not lauegroup:
          continue

        if lauegroup[0] == '[':
          continue

        modded_lauegroup = ''
        for token in lauegroup.split():
          if token == '1':
            continue
          modded_lauegroup += token

        try:
          lattice = lauegroup_to_lattice(modded_lauegroup)
        except KeyError:
          # there was some kind of mess made of the othercell
          # output - this happens!
          continue

        cell = tuple(map(float, o[11:45].split()))
        distortion = float(o.split()[-2])
        operator = o.split()[-1][1:-1]

        if not lattice in self._lattices:
          self._lattices.append(lattice)
          self._distortions[lattice] = distortion
          self._cells[lattice] = cell
          self._reindex_ops[lattice] = operator
        else:
          if distortion > self._distortions[lattice]:
            continue
          self._distortions[lattice] = distortion
          self._cells[lattice] = cell
          self._reindex_ops[lattice] = operator
Beispiel #11
0
def test_lauegroup_to_lattice_functions(ccp4):
    from xia2.lib.SymmetryLib import lauegroup_to_lattice
    assert lauegroup_to_lattice('I m m m') == 'oI'
    assert lauegroup_to_lattice('C 1 2/m 1') == 'mC'
    assert lauegroup_to_lattice('P -1') == 'aP'
    assert lauegroup_to_lattice('P 4/mmm') == 'tP'
Beispiel #12
0
    def generate(self):
      if not self._cell:
        raise RuntimeError, 'no unit cell specified'

      if not self._spacegroup:
        raise RuntimeError, 'no spacegroup specified'

      self.add_command_line('--unit_cell=%f,%f,%f,%f,%f,%f' % \
                            tuple(self._cell))
      self.add_command_line('--space_group=%s' % self._spacegroup)

      self.start()
      self.close_wait()

      # now wade through all of the options and see which comes
      # out best for each lattice class... - as defined by the
      # minimum value of Maximal angular difference

      state = { }

      for o in self.get_all_output():
        # print o[:-1]
        if ':' in o:
          count = o.find(':')
          left = o[:count]
          right = o[count + 1:]
          state[left.strip()] = right.strip()

        if 'Maximal angular difference' in o:
          # transform & digest results

          distortion = float(state[
              'Maximal angular difference'].split()[0])

          # this appears to be getting the wrong cell - I want the
          # one which corresponds to the correct lattice, yes?!
          # cell = map(float, state[
          # 'Symmetry-adapted cell'].replace(
          # '(', ' ').replace(')', ' ').replace(',', ' ').split())

          cell = map(float, state[
              'Unit cell'].replace(
              '(', ' ').replace(')', ' ').replace(',', ' ').split())

          lauegroup = ''

          # FIXME for more recent versions of cctbx the conventional
          # setting I 1 2/m 1 has appeared -> look at the
          # 'Symmetry in minimum-lengths cell' instead (equivalent
          # to changing lkey here to 'Conventional setting'
          #
          # No, can't do this because this now reports the Hall
          # symmetry not the Laue group. Will have to cope with
          # the I setting instead :o(

          lkey = 'Symmetry in minimum-lengths cell'

          for token in state[lkey].split('(')[0].split():
            if token == '1':
              continue
            lauegroup += token

          # FIXME bug 3157 - there appears to be a bug in
          # recent versions of cctbx (cf. above) which means
          # a lauegroup of 'R-3m:R' is given -> correct this
          # in the string. Also :h as well :o(

          lauegroup = lauegroup.replace(':R', ':H')
          lauegroup = lauegroup.replace(':h', ':H')
          lattice = lauegroup_to_lattice(lauegroup)


          reindex_basis = state['Change of basis']
          reindex = state['Inverse']

          if not lattice in self._lattices:
            self._lattices.append(lattice)
            self._distortions[lattice] = distortion
            self._cells[lattice] = cell
            self._reindex_ops[lattice] = reindex
            self._reindex_ops_basis[lattice] = reindex_basis
          elif distortion < self._distortions[lattice]:
            self._distortions[lattice] = distortion
            self._cells[lattice] = cell
            self._reindex_ops[lattice] = reindex
            self._reindex_ops_basis[lattice] = reindex_basis

          state = { }

      return
Beispiel #13
0
    def decide_pointgroup(self, ignore_errors=False, batches=None):
      '''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()

      if self._allow_out_of_sequence_files:
        self.input('allow outofsequencefiles')

      # https://github.com/xia2/xia2/issues/125 pass in run limits for this
      # HKLIN file - prevents automated RUN determination from causing errors
      if batches:
        self.input('run 1 batch %d to %d' % tuple(batches))

      self.input('systematicabsences off')
      self.input('setting symmetry-based')
      if self._hklref:
        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 PhilIndex.params.xia2.settings.small_molecule == True:
        if self._hklref:
          self.input('tolerance 5.0')
      if PhilIndex.params.ccp4.pointless.chirality is not None:
        self.input('chirality %s' %PhilIndex.params.ccp4.pointless.chirality)

      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()

      fatal_error = False

      for j, record in enumerate(output):
        if 'FATAL ERROR message:' in record:
          if ignore_errors:
            fatal_error = True
          else:
            raise RuntimeError('Pointless error: %s' % output[j+1].strip())
        if 'Resolution range of Reference data and observed data do not' \
          in record and ignore_errors:
          fatal_error = True
        if 'All reflection pairs rejected' in record and ignore_errors:
          fatal_error = True
        if 'Reference data and observed data do not overlap' in record and \
          ignore_errors:
          fatal_error = True

      hklin_spacegroup = ''
      hklin_lattice = ''

      # split loop - first seek hklin symmetry then later look for everything
      # else

      for o in self.get_all_output():
        if 'Spacegroup from HKLIN file' in o:
          hklin_spacegroup = spacegroup_name_xHM_to_old(
              o.replace(
              'Spacegroup from HKLIN file :', '').strip())
          hklin_lattice = Syminfo.get_lattice(hklin_spacegroup)
        if 'Space group from HKLREF file' in o:
          hklref_spacegroup = spacegroup_name_xHM_to_old(
              o.replace(
              'Space group from HKLREF file :', '').strip())
          hklref_lattice = Syminfo.get_lattice(hklref_spacegroup)

      # https://github.com/xia2/xia2/issues/115
      if fatal_error:
        assert hklref_spacegroup

        self._pointgroup = hklref_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'

      for o in self.get_all_output():
        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:
          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())

      else:

        # if we have provided a HKLREF input then the xml output
        # is changed...

        # FIXME in here, need to check if there is the legend
        # "No possible alternative indexing" in the standard
        # output, as this will mean that the index scores are
        # not there... c/f oppf1314, with latest pointless build
        # 1.2.14.

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

        try:
          best = dom.getElementsByTagName('IndexScores')[0]
        except IndexError:
          Debug.write('Reindex not found in xml output')

          # check for this legend then
          found = False
          for record in self.get_all_output():
            if 'No possible alternative indexing' in record:
              found = True

          if not found:
            raise RuntimeError('error finding solution')

          best = None

        hklref_pointgroup = ''

        # FIXME need to get this from the reflection file HKLREF
        reflection_file_elements = dom.getElementsByTagName(
            'ReflectionFile')

        for rf in reflection_file_elements:
          stream = rf.getAttribute('stream')
          if stream == 'HKLREF':
            hklref_pointgroup = rf.getElementsByTagName(
                'SpacegroupName')[0].childNodes[0].data.strip()
            # Chatter.write('HKLREF pointgroup is %s' % \
            # hklref_pointgroup)

        if hklref_pointgroup == '':
          raise RuntimeError('error finding HKLREF pointgroup')

        self._pointgroup = hklref_pointgroup

        self._confidence = 1.0
        self._totalprob = 1.0

        if best:

          index = best.getElementsByTagName('Index')[0]

          self._reindex_matrix = map(float,
                                     index.getElementsByTagName(
              'ReindexMatrix')[0].childNodes[0].data.split())
          self._reindex_operator = clean_reindex_operator(
              index.getElementsByTagName(
              'ReindexOperator')[0].childNodes[0].data.strip())
        else:

          # no alternative indexing is possible so just
          # assume the default...

          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'

      if not self._input_laue_group and not self._hklref:

        scorelist = dom.getElementsByTagName('LaueGroupScoreList')[0]
        scores = scorelist.getElementsByTagName('LaueGroupScore')

        lauegroups = { }
        netzcs = { }
        likelihoods = { }

        for s in scores:
          number = int(s.getElementsByTagName(
              'number')[0].childNodes[0].data)
          lauegroup = s.getElementsByTagName(
              'LaueGroupName')[0].childNodes[0].data
          reindex = s.getElementsByTagName(
              'ReindexOperator')[0].childNodes[0].data
          netzc = float(s.getElementsByTagName(
              'NetZCC')[0].childNodes[0].data)
          likelihood = float(s.getElementsByTagName(
              'Likelihood')[0].childNodes[0].data)
          r_merge = float(s.getElementsByTagName(
              'R')[0].childNodes[0].data)
          delta = float(s.getElementsByTagName(
              'CellDelta')[0].childNodes[0].data)

          # record this as a possible lattice... if it's Z score
          # is positive, anyway

          lattice = lauegroup_to_lattice(lauegroup)
          if not lattice in self._possible_lattices:
            if netzc > 0.0:
              self._possible_lattices.append(lattice)

            # do we not always want to have access to the
            # solutions, even if they are unlikely - this will
            # only be invoked if they are known to
            # be right...

            self._lattice_to_laue[lattice] = lauegroup

      return 'ok'