예제 #1
0
class Script(object):
  ''' A class to encapsulate the script. '''

  def __init__(self):
    ''' Initialise the script. '''
    from dials.util.options import OptionParser
    import libtbx.load_env

    # Create the parser
    usage = "usage: %s [options] reflections.pickle" % libtbx.env.dispatcher_name
    self.parser = OptionParser(
      usage=usage,
      phil=phil_scope,
      read_reflections=True,
      epilog=help_message)

    self.parser.add_option(
      '--xkcd',
      action='store_true',
      dest='xkcd',
      default=False,
      help='Special drawing mode')

  def run(self):
    ''' Run the script. '''
    from dials.util.command_line import Command
    from libtbx.utils import Sorry

    # Parse the command line arguments
    params, options = self.parser.parse_args(show_diff_phil=True)

    if options.xkcd:
      from matplotlib import pyplot
      pyplot.xkcd()

    # Shoe the help
    if len(params.input.reflections) != 1:
      self.parser.print_help()
      exit(0)

    # Analyse the reflections
    analyse = Analyser(
      params.output.directory, grid_size=params.grid_size,
      pixels_per_bin=params.pixels_per_bin,
      centroid_diff_max=params.centroid_diff_max)
    analyse(params.input.reflections[0].data)
예제 #2
0
def run():
    from dials.util.options import OptionParser

    # Create the parser
    usage = "usage: dials.analyse_output [options] observations.refl"
    parser = OptionParser(usage=usage,
                          phil=phil_scope,
                          read_reflections=True,
                          epilog=help_message)

    parser.add_option(
        "--xkcd",
        action="store_true",
        dest="xkcd",
        default=False,
        help="Special drawing mode",
    )

    # Parse the command line arguments
    params, options = parser.parse_args(show_diff_phil=True)

    if options.xkcd:
        pyplot.xkcd()

    # Show the help
    if len(params.input.reflections) != 1:
        parser.print_help()
        print("""
dials.analyse_output is deprecated and will be removed in a future release.
Its successor is dials.report, which generates interactive reports.
""")
        exit(0)

    # Analyse the reflections
    analyse(
        params.input.reflections[0].data,
        params.output.directory,
        grid_size=params.grid_size,
        pixels_per_bin=params.pixels_per_bin,
        centroid_diff_max=params.centroid_diff_max,
    )
    print("""
dials.analyse_output is deprecated and will be removed in a future release.
Its successor is dials.report, which generates interactive reports.
""")
예제 #3
0
class Script(object):
  '''A class for running the script.'''

  def __init__(self):
    # The script usage
    import libtbx.load_env
    self.usage = "usage: %s [options] [param.phil] " % libtbx.env.dispatcher_name
    self.parser = None

  def initialize(self):
    '''Initialise the script.'''
    from dials.util.options import OptionParser
    # Create the parser
    self.parser = OptionParser(
      usage=self.usage,
      phil=phil_scope,
      epilog=help_message)
    self.parser.add_option(
        '--plots',
        action='store_true',
        default=False,
        dest='show_plots',
        help='Show some plots.')

    # Parse the command line. quick_parse is required for MPI compatibility
    params, options = self.parser.parse_args(show_diff_phil=True,quick_parse=True)
    self.params = params
    self.options = options

  def validate(self):
    from xfel.merging.application.validation.application import application
    application(self.params)

  def modify(self, experiments, reflections):
    return experiments, reflections #nop

  def run(self):
    print('''Initializing and validating phil...''')

    self.initialize()
    self.validate()

    # do other stuff
    return
class Script(base_Script):
    def validate(self, comm):
        base_Script.validate(self)
        if (self.params.rescale_with_average_cell):
            raise Usage("""Rescaling_with_average_cell not supported with MPI
      (Would require a second round of scaling, inefficient).""")
        if (self.params.mpi.cs == True and comm.Get_size() <= 1):
            raise Usage(
                "Client-server algorithm requires a minimum size of 2 MPI ranks to process data. Currently size=%d"
                % comm.Get_size())

    def initialize(self):
        '''Initialise the script.'''
        from dials.util.options import OptionParser
        from iotbx.phil import parse
        from xfel.command_line.cxi_merge import master_phil
        help_message = '''
    MPI enabled script for merging xfel data
    '''
        phil_mpi = """
    mpi {
    logging = False
      .type = bool
      .help = logging Used to report timing information on the MPI operations. All strings are of the format '~<UNIQUE_STRING> START/END RANK=<MPI_RANK> TIME=<Unix time>;'
    cs = False
      .type = bool
      .help = cs This enables the client-server work distribution duing merging. A minimum of 2 ranks are needed for this processing method.
      .help = Default operation is set to false, which chunks the data evenly over all available ranks.
    }
    """
        phil_scope = parse(master_phil + phil_mpi)
        # Create the parser
        self.parser = OptionParser(usage=self.usage,
                                   phil=phil_scope,
                                   epilog=help_message)
        self.parser.add_option('--plots',
                               action='store_true',
                               default=False,
                               dest='show_plots',
                               help='Show some plots.')

        # Parse the command line. quick_parse is required for MPI compatibility
        params, options = self.parser.parse_args(show_diff_phil=True,
                                                 quick_parse=True)
        self.params = params
        self.options = options

    def run(self, comm, timing=False):
        rank = comm.Get_rank()
        size = comm.Get_size()
        from time import time as tt

        # set things up
        if rank == 0:
            self.initialize()
            self.validate(comm)
            self.read_models()

            timing = self.params.mpi.logging
            if timing: print "~SETUP START RANK=%d TIME=%f;" % (rank, tt())

            scaler_master = self.scaler_class(miller_set=self.miller_set,
                                              i_model=self.i_model,
                                              params=self.params,
                                              log=self.out)
            scaler_master.mpi_initialize(self.frame_files)

            transmitted_info = dict(file_names=self.frame_files,
                                    miller_set=self.miller_set,
                                    model=self.i_model,
                                    params=self.params)
            if timing: print "~SETUP END RANK=%d TIME=%f;" % (rank, tt())

        else:
            if timing: print "~SETUP START RANK=%d TIME=%f;" % (rank, tt())
            transmitted_info = None
            if timing: print "~SETUP END RANK=%d TIME=%f;" % (rank, tt())

        if timing: print "~BROADCAST START RANK=%d TIME=%f;" % (rank, tt())
        transmitted_info = comm.bcast(transmitted_info, root=0)
        if timing: print "~BROADCAST END RANK=%d TIME=%f;" % (rank, tt())

        # now actually do the work
        if timing:
            print "~SCALER_WORKER_SETUP START RANK=%d TIME=%f;" % (rank, tt())
        scaler_worker = self.scaler_class(transmitted_info["miller_set"],
                                          transmitted_info["model"],
                                          transmitted_info["params"],
                                          log=sys.stdout)
        if timing:
            print "~SCALER_WORKER_SETUP END RANK=%d TIME=%f;" % (rank, tt())
        assert scaler_worker.params.backend == 'FS'  # only option that makes sense
        from xfel.merging.database.merging_database_fs import manager2 as manager
        db_mgr = manager(scaler_worker.params)

        # Use client-server distribution of work to the available MPI ranks.
        # Each free rank requests a TAR ID and proceeds to process it.
        if scaler_worker.params.mpi.cs == True:
            tar_file_names = transmitted_info["file_names"]
            if timing:
                print "~SCALER_WORKERS START RANK=%d TIME=%f;" % (rank, tt())
            if rank == 0:
                for ix in range(len(tar_file_names)):
                    rankreq = comm.recv(source=MPI.ANY_SOURCE)
                    comm.send(ix, dest=rankreq)
                for rankreq in range(size - 1):
                    rankreq = comm.recv(source=MPI.ANY_SOURCE)
                    comm.send('endrun', dest=rankreq)
                scaler_worker.finished_db_mgr = db_mgr
            else:
                while True:
                    comm.send(rank, dest=0)
                    idx = comm.recv(source=0)
                    if idx == 'endrun':
                        scaler_worker.finished_db_mgr = db_mgr
                        break
                    if timing:
                        print "~SCALER_WORKER START=%d RANK=%d TIME=%f;" % (
                            idx, rank, tt())
                    scaler_worker._scale_all_serial([
                        tar_file_names[idx],
                    ], db_mgr)
                    if timing:
                        print "~SCALER_WORKER END=%d RANK=%d TIME=%f;" % (
                            idx, rank, tt())
            if timing:
                print "~SCALER_WORKERS END RANK=%d TIME=%f;" % (rank, tt())

        # Distribute chunks of TAR files to each MPI rank.
        # The files are equidistributed across all the available ranks.
        else:
            file_names = [
                transmitted_info["file_names"][i]
                for i in range(len(transmitted_info["file_names"]))
                if i % size == rank
            ]
            if timing:
                print "SCALER_WORKERS START RANK=%d TIME=%f" % (rank, tt())
            scaler_worker._scale_all_serial(file_names, db_mgr)
            if timing:
                print "SCALER_WORKERS END RANK=%d TIME=%f" % (rank, tt())
            scaler_worker.finished_db_mgr = db_mgr

        # might want to clean up a bit before returning
        del scaler_worker.log
        del scaler_worker.params
        del scaler_worker.miller_set
        del scaler_worker.i_model
        del scaler_worker.reverse_lookup

        # gather reports and all add together
        if timing: print "~GATHER START RANK=%d TIME=%f;" % (rank, tt())
        reports = comm.gather(scaler_worker, root=0)
        if timing: print "~GATHER END RANK=%d TIME=%f;" % (rank, tt())
        if rank == 0:
            print "Processing reports from %d ranks" % (len(reports))
            ireport = 0
            for item in reports:
                if timing:
                    print "~SCALER_MASTER_ADD START RANK=%d TIME=%f;" % (rank,
                                                                         tt())
                scaler_master._add_all_frames(item)

                if timing:
                    print "~SCALER_MASTER_ADD END RANK=%d TIME=%f;" % (rank,
                                                                       tt())
                print "processing %d calls from report %d" % (len(
                    item.finished_db_mgr.sequencer), ireport)
                ireport += 1

                for call_instance in item.finished_db_mgr.sequencer:
                    if call_instance["call"] == "insert_frame":
                        if timing:
                            print "~SCALER_MASTER_INSERT_FRAME START RANK=%d TIME=%f;" % (
                                rank, tt())
                        frame_id_zero_base = scaler_master.master_db_mgr.insert_frame(
                            **call_instance["data"])
                        if timing:
                            print "~SCALER_MASTER_INSERT_FRAME END RANK=%d TIME=%f;" % (
                                rank, tt())
                    elif call_instance["call"] == "insert_observation":
                        if timing:
                            print "~SCALER_MASTER_INSERT_OBS START RANK=%d TIME=%f;" % (
                                rank, tt())
                        call_instance["data"]['frame_id_0_base'] = [
                            frame_id_zero_base
                        ] * len(call_instance["data"]['frame_id_0_base'])
                        scaler_master.master_db_mgr.insert_observation(
                            **call_instance["data"])
                        if timing:
                            print "~SCALER_MASTER_INSERT_OBS END RANK=%d TIME=%f;" % (
                                rank, tt())

            if timing:
                print "~SCALER_MASTER_FINALISE START RANK=%d TIME=%f;" % (rank,
                                                                          tt())
            scaler_master.master_db_mgr.join(
            )  # database written, finalize the manager
            scaler_master.mpi_finalize()
            if timing:
                print "~SCALER_MASTER_FINALISE END RANK=%d TIME=%f;" % (rank,
                                                                        tt())

            return self.finalize(scaler_master)
예제 #5
0
class Script(object):
  '''A class for running the script.'''

  def __init__(self, scaler_class):
    # The script usage
    import libtbx.load_env
    self.usage = "usage: %s [options] [param.phil] " % libtbx.env.dispatcher_name
    self.parser = None
    self.scaler_class = scaler_class

  def initialize(self):
    '''Initialise the script.'''
    from dials.util.options import OptionParser
    from iotbx.phil import parse
    phil_scope = parse(master_phil)
    # Create the parser
    self.parser = OptionParser(
      usage=self.usage,
      phil=phil_scope,
      epilog=help_message)
    self.parser.add_option(
        '--plots',
        action='store_true',
        default=False,
        dest='show_plots',
        help='Show some plots.')

    # Parse the command line. quick_parse is required for MPI compatibility
    params, options = self.parser.parse_args(show_diff_phil=True,quick_parse=True)
    self.params = params
    self.options = options

  def validate(self):
    from xfel.merging.phil_validation import application
    application(self.params)
    if ((self.params.d_min is None) or
        (self.params.data is None) or
        ( (self.params.model is None) and self.params.scaling.algorithm != "mark1") ) :
      command_name = os.environ["LIBTBX_DISPATCHER_NAME"]
      raise Usage(command_name + " "
                  "d_min=4.0 "
                  "data=~/scratch/r0220/006/strong/ "
                  "model=3bz1_3bz2_core.pdb")
    if ((self.params.rescale_with_average_cell) and
        (not self.params.set_average_unit_cell)) :
      raise Usage("If rescale_with_average_cell=True, you must also specify "+
        "set_average_unit_cell=True.")
    if [self.params.raw_data.sdfac_auto, self.params.raw_data.sdfac_refine, self.params.raw_data.errors_from_sample_residuals].count(True) > 1:
      raise Usage("Specify only one of sdfac_auto, sdfac_refine or errors_from_sample_residuals.")

  def read_models(self):
    # Read Nat's reference model from an MTZ file.  XXX The observation
    # type is given as F, not I--should they be squared?  Check with Nat!
    log = open("%s.log" % self.params.output.prefix, "w")
    out = multi_out()
    out.register("log", log, atexit_send_to=None)
    out.register("stdout", sys.stdout)
    print >> out, "I model"
    if self.params.model is not None:
      from xfel.merging.general_fcalc import run as run_fmodel
      i_model = run_fmodel(self.params)
      self.params.target_unit_cell = i_model.unit_cell()
      self.params.target_space_group = i_model.space_group_info()
      i_model.show_summary()
    else:
      i_model = None

    print >> out, "Target unit cell and space group:"
    print >> out, "  ", self.params.target_unit_cell
    print >> out, "  ", self.params.target_space_group
    from xfel.command_line.cxi_merge import consistent_set_and_model
    self.miller_set, self.i_model = consistent_set_and_model(self.params,i_model)
    self.frame_files = get_observations(self.params)
    self.out = out

  def scale_all(self):
    scaler = self.scaler_class(
      miller_set=self.miller_set,
      i_model=self.i_model,
      params=self.params,
      log=self.out)
    scaler.scale_all(self.frame_files)
    return scaler

  def finalize(self, scaler):
    scaler.show_unit_cell_histograms()
    if (self.params.rescale_with_average_cell) :
      average_cell_abc = scaler.uc_values.get_average_cell_dimensions()
      average_cell = uctbx.unit_cell(list(average_cell_abc) +
        list(self.params.target_unit_cell.parameters()[3:]))
      self.params.target_unit_cell = average_cell
      print >> out, ""
      print >> out, "#" * 80
      print >> out, "RESCALING WITH NEW TARGET CELL"
      print >> out, "  average cell: %g %g %g %g %g %g" % \
        self.params.target_unit_cell.parameters()
      print >> out, ""
      scaler.reset()
      scaler.scale_all(frame_files)
      scaler.show_unit_cell_histograms()
    if False : #(self.params.output.show_plots) :
      try :
        plot_overall_completeness(completeness)
      except Exception as e :
        print "ERROR: can't show plots"
        print "  %s" % str(e)
    print >> self.out, "\n"

    sum_I, sum_I_SIGI = scaler.sum_intensities()

    miller_set_avg = self.miller_set.customized_copy(
      unit_cell=self.params.target_unit_cell)
    table1 = show_overall_observations(
      obs=miller_set_avg,
      redundancy=scaler.completeness,
      redundancy_to_edge=scaler.completeness_predictions,
      summed_wt_I=scaler.summed_wt_I,
      summed_weight=scaler.summed_weight,
      ISIGI=scaler.ISIGI,
      n_bins=self.params.output.n_bins,
      title="Statistics for all reflections",
      out=self.out,
      work_params=self.params)
    print >> self.out, ""
    if self.params.model is not None:
      n_refl, corr = scaler.get_overall_correlation(sum_I)
    else:
      n_refl, corr = ((scaler.completeness > 0).count(True), 0)
    print >> self.out, "\n"
    table2 = show_overall_observations(
      obs=miller_set_avg,
      redundancy=scaler.summed_N,
      redundancy_to_edge=scaler.completeness_predictions,
      summed_wt_I=scaler.summed_wt_I,
      summed_weight=scaler.summed_weight,
      ISIGI=scaler.ISIGI,
      n_bins=self.params.output.n_bins,
      title="Statistics for reflections where I > 0",
      out=self.out,
      work_params=self.params)
    #from libtbx import easy_pickle
    #easy_pickle.dump(file_name="stats.pickle", obj=stats)
    #stats.report(plot=self.params.plot)
    #miller_counts = miller_set_p1.array(data=stats.counts.as_double()).select(
    #  stats.counts != 0)
    #miller_counts.as_mtz_dataset(column_root_label="NOBS").mtz_object().write(
    #  file_name="nobs.mtz")
    if self.params.data_subsubsets.subsubset is not None and self.params.data_subsubsets.subsubset_total is not None:
      easy_pickle.dump("scaler_%d.pickle"%self.params.data_subsubsets.subsubset, scaler)
    explanation = """
  Explanation:
  Completeness       = # unique Miller indices present in data / # Miller indices theoretical in asymmetric unit
  Asu. Multiplicity  = # measurements / # Miller indices theoretical in asymmetric unit
  Obs. Multiplicity  = # measurements / # unique Miller indices present in data
  Pred. Multiplicity = # predictions on all accepted images / # Miller indices theoretical in asymmetric unit"""
    print >> self.out, explanation
    mtz_file, miller_array = scaler.finalize_and_save_data()
    #table_pickle_file = "%s_graphs.pkl" % self.params.output.prefix
    #easy_pickle.dump(table_pickle_file, [table1, table2])
    loggraph_file = os.path.abspath("%s_graphs.log" % self.params.output.prefix)
    f = open(loggraph_file, "w")
    f.write(table1.format_loggraph())
    f.write("\n")
    f.write(table2.format_loggraph())
    f.close()
    result = scaling_result(
      miller_array=miller_array,
      plots=scaler.get_plot_statistics(),
      mtz_file=mtz_file,
      loggraph_file=loggraph_file,
      obs_table=table1,
      all_obs_table=table2,
      n_reflections=n_refl,
      overall_correlation=corr)
    easy_pickle.dump("%s.pkl" % self.params.output.prefix, result)
    return result

  def show_plot(self,result):
    if result is not None:
      if (self.options.show_plots) :
        try :
          result.plots.show_all_pyplot()
          from wxtbx.command_line import loggraph
          loggraph.run([result.loggraph_file])
        except Exception as e :
          print "Can't display plots"
          print "You should be able to view them by running this command:"
          print "  wxtbx.loggraph %s" % result.loggraph_file
          raise e

  def run(self):
    '''Execute the script.'''
    self.initialize()
    self.validate()
    self.read_models()
    scaler = self.scale_all()
    result = self.finalize(scaler)
    return result
예제 #6
0
class Script(object):
  '''A class for running the script.'''

  def __init__(self):
    # The script usage
    import libtbx.load_env
    self.usage = "usage: %s [options] [param.phil] " % libtbx.env.dispatcher_name
    self.parser = None

  def initialize(self):
    '''Initialise the script.'''
    from dials.util.options import OptionParser
    from iotbx.phil import parse
    phil_scope = parse(master_phil)
    # Create the parser
    self.parser = OptionParser(
      usage=self.usage,
      phil=phil_scope,
      epilog=help_message)
    self.parser.add_option(
        '--plots',
        action='store_true',
        default=False,
        dest='show_plots',
        help='Show some plots.')

    # Parse the command line. quick_parse is required for MPI compatibility
    params, options = self.parser.parse_args(show_diff_phil=True,quick_parse=True)
    self.params = params
    self.options = options

  def load_data(self):
    from xfel.merging.application.input.file_loader import file_loader
    from dxtbx.model.experiment_list import ExperimentList
    from dials.array_family import flex
    all_experiments = ExperimentList()
    all_reflections = flex.reflection_table()

    # example showing what reading all the data into a single experiment list/
    # reflection table would look like
    loader = file_loader(self.params)
    for experiments_filename, reflections_filename in loader.filepair_generator():
      experiments, reflections = loader.load_data(experiments_filename, reflections_filename)
      for experiment_id, experiment in enumerate(experiments):
        all_experiments.append(experiment)
        refls = reflections.select(reflections['id'] == experiment_id)
        refls['id'] = flex.int(len(refls), len(all_experiments)-1)
        all_reflections.extend(refls)

    all_reflections.sort('miller_index_asymmetric')
    return all_experiments, all_reflections

  def validate(self):
    from xfel.merging.application.validation.application import application
    application(self.params)

  def run(self):
    print('''Mock run, merge some data.''')
    self.initialize()
    experiments, reflections = self.load_data()
    print ('Read %d experiments consisting of %d reflections'%(len(experiments), len(reflections)))
    self.validate()
    # do other stuff
    return