Ejemplo n.º 1
0
def metrology2phil(calib_dir, verbose):
  """XXX Should really review the SLAC progress since last time
  around!  XXX Note that this is all SLAC-specific (as is the whole
  thing, I guess).
  """
  # XXX Can this fail?  How?
  sections = calib2sections(calib_dir)
  if (sections is None):
    return (None)

  return sections2phil(sections, verbose)
Ejemplo n.º 2
0
def average(argv=None):
    if argv == None:
        argv = sys.argv[1:]

    try:
        from mpi4py import MPI
    except ImportError:
        raise Sorry("MPI not found")

    command_line = (libtbx.option_parser.option_parser(usage="""
%s [-p] -c config -x experiment -a address -r run -d detz_offset [-o outputdir] [-A averagepath] [-S stddevpath] [-M maxpath] [-n numevents] [-s skipnevents] [-v] [-m] [-b bin_size] [-X override_beam_x] [-Y override_beam_y] [-D xtc_dir] [-f] [-g gain_mask_value] [--min] [--minpath minpath]

To write image pickles use -p, otherwise the program writes CSPAD CBFs.
Writing CBFs requires the geometry to be already deployed.

Examples:
cxi.mpi_average -c cxi49812/average.cfg -x cxi49812 -a CxiDs1.0:Cspad.0 -r 25 -d 571

Use one process on the current node to process all the events from run 25 of
experiment cxi49812, using a detz_offset of 571.

mpirun -n 16 cxi.mpi_average -c cxi49812/average.cfg -x cxi49812 -a CxiDs1.0:Cspad.0 -r 25 -d 571

As above, using 16 cores on the current node.

bsub -a mympi -n 100 -o average.out -q psanaq cxi.mpi_average -c cxi49812/average.cfg -x cxi49812 -a CxiDs1.0:Cspad.0 -r 25 -d 571 -o cxi49812

As above, using the psanaq and 100 cores, putting the log in average.out and
the output images in the folder cxi49812.
""" % libtbx.env.dispatcher_name).option(
        None,
        "--as_pickle",
        "-p",
        action="store_true",
        default=False,
        dest="as_pickle",
        help="Write results as image pickle files instead of cbf files"
    ).option(
        None,
        "--raw_data",
        "-R",
        action="store_true",
        default=False,
        dest="raw_data",
        help=
        "Disable psana corrections such as dark pedestal subtraction or common mode (cbf only)"
    ).option(
        None,
        "--background_pickle",
        "-B",
        default=None,
        dest="background_pickle",
        help=""
    ).option(
        None,
        "--config",
        "-c",
        type="string",
        default=None,
        dest="config",
        metavar="PATH",
        help="psana config file"
    ).option(
        None,
        "--experiment",
        "-x",
        type="string",
        default=None,
        dest="experiment",
        help="experiment name (eg cxi84914)"
    ).option(
        None,
        "--run",
        "-r",
        type="int",
        default=None,
        dest="run",
        help="run number"
    ).option(
        None,
        "--address",
        "-a",
        type="string",
        default="CxiDs2.0:Cspad.0",
        dest="address",
        help="detector address name (eg CxiDs2.0:Cspad.0)"
    ).option(
        None,
        "--detz_offset",
        "-d",
        type="float",
        default=None,
        dest="detz_offset",
        help=
        "offset (in mm) from sample interaction region to back of CSPAD detector rail (CXI), or detector distance (XPP)"
    ).option(
        None,
        "--outputdir",
        "-o",
        type="string",
        default=".",
        dest="outputdir",
        metavar="PATH",
        help="Optional path to output directory for output files"
    ).option(
        None,
        "--averagebase",
        "-A",
        type="string",
        default="{experiment!l}_avg-r{run:04d}",
        dest="averagepath",
        metavar="PATH",
        help=
        "Path to output average image without extension. String substitution allowed"
    ).option(
        None,
        "--stddevbase",
        "-S",
        type="string",
        default="{experiment!l}_stddev-r{run:04d}",
        dest="stddevpath",
        metavar="PATH",
        help=
        "Path to output standard deviation image without extension. String substitution allowed"
    ).option(
        None,
        "--maxbase",
        "-M",
        type="string",
        default="{experiment!l}_max-r{run:04d}",
        dest="maxpath",
        metavar="PATH",
        help=
        "Path to output maximum projection image without extension. String substitution allowed"
    ).option(
        None,
        "--numevents",
        "-n",
        type="int",
        default=None,
        dest="numevents",
        help="Maximum number of events to process. Default: all"
    ).option(
        None,
        "--skipevents",
        "-s",
        type="int",
        default=0,
        dest="skipevents",
        help="Number of events in the beginning of the run to skip. Default: 0"
    ).option(
        None,
        "--verbose",
        "-v",
        action="store_true",
        default=False,
        dest="verbose",
        help="Print more information about progress"
    ).option(
        None,
        "--pickle-optical-metrology",
        "-m",
        action="store_true",
        default=False,
        dest="pickle_optical_metrology",
        help=
        "If writing pickle files, use the optical metrology in the experiment's calib directory"
    ).option(
        None,
        "--bin_size",
        "-b",
        type="int",
        default=None,
        dest="bin_size",
        help="Rayonix detector bin size"
    ).option(
        None,
        "--override_beam_x",
        "-X",
        type="float",
        default=None,
        dest="override_beam_x",
        help="Rayonix detector beam center x coordinate"
    ).option(
        None,
        "--override_beam_y",
        "-Y",
        type="float",
        default=None,
        dest="override_beam_y",
        help="Rayonix detector beam center y coordinate"
    ).option(
        None,
        "--calib_dir",
        "-C",
        type="string",
        default=None,
        dest="calib_dir",
        metavar="PATH",
        help="calibration directory"
    ).option(
        None,
        "--pickle_calib_dir",
        "-P",
        type="string",
        default=None,
        dest="pickle_calib_dir",
        metavar="PATH",
        help=
        "pickle calibration directory specification. Replaces --calib_dir functionality."
    ).option(
        None,
        "--xtc_dir",
        "-D",
        type="string",
        default=None,
        dest="xtc_dir",
        metavar="PATH",
        help="xtc stream directory"
    ).option(
        None,
        "--use_ffb",
        "-f",
        action="store_true",
        default=False,
        dest="use_ffb",
        help=
        "Use the fast feedback filesystem at LCLS. Only for the active experiment!"
    ).option(
        None,
        "--gain_mask_value",
        "-g",
        type="float",
        default=None,
        dest="gain_mask_value",
        help=
        "Ratio between low and high gain pixels, if CSPAD in mixed-gain mode. Only used in CBF averaging mode."
    ).option(
        None,
        "--min",
        None,
        action="store_true",
        default=False,
        dest="do_minimum_projection",
        help="Output a minimum projection"
    ).option(
        None,
        "--minpath",
        None,
        type="string",
        default="{experiment!l}_min-r{run:04d}",
        dest="minpath",
        metavar="PATH",
        help=
        "Path to output minimum image without extension. String substitution allowed"
    )).process(args=argv)


    if len(command_line.args) > 0 or \
        command_line.options.as_pickle is None or \
        command_line.options.experiment is None or \
        command_line.options.run is None or \
        command_line.options.address is None or \
        command_line.options.detz_offset is None or \
        command_line.options.averagepath is None or \
        command_line.options.stddevpath is None or \
        command_line.options.maxpath is None or \
        command_line.options.pickle_optical_metrology is None:
        command_line.parser.show_help()
        return

    # set this to sys.maxint to analyze all events
    if command_line.options.numevents is None:
        maxevents = sys.maxsize
    else:
        maxevents = command_line.options.numevents

    comm = MPI.COMM_WORLD
    rank = comm.Get_rank()
    size = comm.Get_size()

    if command_line.options.config is not None:
        psana.setConfigFile(command_line.options.config)
    dataset_name = "exp=%s:run=%d:smd" % (command_line.options.experiment,
                                          command_line.options.run)
    if command_line.options.xtc_dir is not None:
        if command_line.options.use_ffb:
            raise Sorry("Cannot specify the xtc_dir and use SLAC's ffb system")
        dataset_name += ":dir=%s" % command_line.options.xtc_dir
    elif command_line.options.use_ffb:
        # as ffb is only at SLAC, ok to hardcode /reg/d here
        dataset_name += ":dir=/reg/d/ffb/%s/%s/xtc" % (
            command_line.options.experiment[0:3],
            command_line.options.experiment)
    if command_line.options.calib_dir is not None:
        psana.setOption('psana.calib-dir', command_line.options.calib_dir)
    ds = psana.DataSource(dataset_name)
    address = command_line.options.address
    src = psana.Source('DetInfo(%s)' % address)
    nevent = np.array([0.])

    if command_line.options.background_pickle is not None:
        background = easy_pickle.load(
            command_line.options.background_pickle)['DATA'].as_numpy_array()

    for run in ds.runs():
        runnumber = run.run()

        if not command_line.options.as_pickle:
            psana_det = psana.Detector(address, ds.env())

        # list of all events
        if command_line.options.skipevents > 0:
            print("Skipping first %d events" % command_line.options.skipevents)
        elif "Rayonix" in command_line.options.address:
            print("Skipping first image in the Rayonix detector"
                  )  # Shuttering issue
            command_line.options.skipevents = 1

        for i, evt in enumerate(run.events()):
            if i % size != rank: continue
            if i < command_line.options.skipevents: continue
            if i >= maxevents: break
            if i % 10 == 0: print('Rank', rank, 'processing event', i)
            #print "Event #",rank*mylength+i," has id:",evt.get(EventId)
            if 'Rayonix' in command_line.options.address or 'FeeHxSpectrometer' in command_line.options.address or 'XrayTransportDiagnostic' in command_line.options.address:
                data = evt.get(psana.Camera.FrameV1, src)
                if data is None:
                    print("No data")
                    continue
                data = data.data16().astype(np.float64)
            elif command_line.options.as_pickle:
                data = evt.get(psana.ndarray_float64_3, src, 'image0')
            else:
                # get numpy array, 32x185x388
                from xfel.cftbx.detector.cspad_cbf_tbx import get_psana_corrected_data
                if command_line.options.raw_data:
                    data = get_psana_corrected_data(psana_det,
                                                    evt,
                                                    use_default=False,
                                                    dark=False,
                                                    common_mode=None,
                                                    apply_gain_mask=False,
                                                    per_pixel_gain=False)
                else:
                    if command_line.options.gain_mask_value is None:
                        data = get_psana_corrected_data(psana_det,
                                                        evt,
                                                        use_default=True)
                    else:
                        data = get_psana_corrected_data(
                            psana_det,
                            evt,
                            use_default=False,
                            dark=True,
                            common_mode=None,
                            apply_gain_mask=True,
                            gain_mask_value=command_line.options.
                            gain_mask_value,
                            per_pixel_gain=False)

            if data is None:
                print("No data")
                continue

            if command_line.options.background_pickle is not None:
                data -= background

            if 'FeeHxSpectrometer' in command_line.options.address or 'XrayTransportDiagnostic' in command_line.options.address:
                distance = np.array([0.0])
                wavelength = np.array([1.0])
            else:
                d = cspad_tbx.env_distance(address, run.env(),
                                           command_line.options.detz_offset)
                if d is None:
                    print("No distance, using distance",
                          command_line.options.detz_offset)
                    assert command_line.options.detz_offset is not None
                    if 'distance' not in locals():
                        distance = np.array([command_line.options.detz_offset])
                    else:
                        distance += command_line.options.detz_offset
                else:
                    if 'distance' in locals():
                        distance += d
                    else:
                        distance = np.array([float(d)])

                w = cspad_tbx.evt_wavelength(evt)
                if w is None:
                    print("No wavelength")
                    if 'wavelength' not in locals():
                        wavelength = np.array([1.0])
                else:
                    if 'wavelength' in locals():
                        wavelength += w
                    else:
                        wavelength = np.array([w])

            t = cspad_tbx.evt_time(evt)
            if t is None:
                print("No timestamp, skipping shot")
                continue
            if 'timestamp' in locals():
                timestamp += t[0] + (t[1] / 1000)
            else:
                timestamp = np.array([t[0] + (t[1] / 1000)])

            if 'sum' in locals():
                sum += data
            else:
                sum = np.array(data, copy=True)
            if 'sumsq' in locals():
                sumsq += data * data
            else:
                sumsq = data * data
            if 'maximum' in locals():
                maximum = np.maximum(maximum, data)
            else:
                maximum = np.array(data, copy=True)

            if command_line.options.do_minimum_projection:
                if 'minimum' in locals():
                    minimum = np.minimum(minimum, data)
                else:
                    minimum = np.array(data, copy=True)

            nevent += 1

    #sum the images across mpi cores
    if size > 1:
        print("Synchronizing rank", rank)
    totevent = np.zeros(nevent.shape)
    comm.Reduce(nevent, totevent)

    if rank == 0 and totevent[0] == 0:
        raise Sorry("No events found in the run")

    sumall = np.zeros(sum.shape).astype(sum.dtype)
    comm.Reduce(sum, sumall)

    sumsqall = np.zeros(sumsq.shape).astype(sumsq.dtype)
    comm.Reduce(sumsq, sumsqall)

    maxall = np.zeros(maximum.shape).astype(maximum.dtype)
    comm.Reduce(maximum, maxall, op=MPI.MAX)

    if command_line.options.do_minimum_projection:
        minall = np.zeros(maximum.shape).astype(minimum.dtype)
        comm.Reduce(minimum, minall, op=MPI.MIN)

    waveall = np.zeros(wavelength.shape).astype(wavelength.dtype)
    comm.Reduce(wavelength, waveall)

    distall = np.zeros(distance.shape).astype(distance.dtype)
    comm.Reduce(distance, distall)

    timeall = np.zeros(timestamp.shape).astype(timestamp.dtype)
    comm.Reduce(timestamp, timeall)

    if rank == 0:
        if size > 1:
            print("Synchronized")

        # Accumulating floating-point numbers introduces errors,
        # which may cause negative variances.  Since a two-pass
        # approach is unacceptable, the standard deviation is
        # clamped at zero.
        mean = sumall / float(totevent[0])
        variance = (sumsqall / float(totevent[0])) - (mean**2)
        variance[variance < 0] = 0
        stddev = np.sqrt(variance)

        wavelength = waveall[0] / totevent[0]
        distance = distall[0] / totevent[0]
        pixel_size = cspad_tbx.pixel_size
        saturated_value = cspad_tbx.cspad_saturated_value
        timestamp = timeall[0] / totevent[0]
        timestamp = (int(timestamp), timestamp % int(timestamp) * 1000)
        timestamp = cspad_tbx.evt_timestamp(timestamp)

        if command_line.options.as_pickle:
            extension = ".pickle"
        else:
            extension = ".cbf"

        dest_paths = [
            cspad_tbx.pathsubst(command_line.options.averagepath + extension,
                                evt, ds.env()),
            cspad_tbx.pathsubst(command_line.options.stddevpath + extension,
                                evt, ds.env()),
            cspad_tbx.pathsubst(command_line.options.maxpath + extension, evt,
                                ds.env())
        ]
        if command_line.options.do_minimum_projection:
            dest_paths.append(
                cspad_tbx.pathsubst(command_line.options.minpath + extension,
                                    evt, ds.env()))

        dest_paths = [
            os.path.join(command_line.options.outputdir, path)
            for path in dest_paths
        ]
        if 'Rayonix' in command_line.options.address:
            all_data = [mean, stddev, maxall]
            if command_line.options.do_minimum_projection:
                all_data.append(minall)
            from xfel.cxi.cspad_ana import rayonix_tbx
            pixel_size = rayonix_tbx.get_rayonix_pixel_size(
                command_line.options.bin_size)
            beam_center = [
                command_line.options.override_beam_x,
                command_line.options.override_beam_y
            ]
            active_areas = flex.int([0, 0, mean.shape[1], mean.shape[0]])
            split_address = cspad_tbx.address_split(address)
            old_style_address = split_address[0] + "-" + split_address[
                1] + "|" + split_address[2] + "-" + split_address[3]
            for data, path in zip(all_data, dest_paths):
                print("Saving", path)
                d = cspad_tbx.dpack(
                    active_areas=active_areas,
                    address=old_style_address,
                    beam_center_x=pixel_size * beam_center[0],
                    beam_center_y=pixel_size * beam_center[1],
                    data=flex.double(data),
                    distance=distance,
                    pixel_size=pixel_size,
                    saturated_value=rayonix_tbx.rayonix_saturated_value,
                    timestamp=timestamp,
                    wavelength=wavelength)
                easy_pickle.dump(path, d)
        elif 'FeeHxSpectrometer' in command_line.options.address or 'XrayTransportDiagnostic' in command_line.options.address:
            all_data = [mean, stddev, maxall]
            split_address = cspad_tbx.address_split(address)
            old_style_address = split_address[0] + "-" + split_address[
                1] + "|" + split_address[2] + "-" + split_address[3]
            if command_line.options.do_minimum_projection:
                all_data.append(minall)
            for data, path in zip(all_data, dest_paths):
                d = cspad_tbx.dpack(address=old_style_address,
                                    data=flex.double(data),
                                    distance=distance,
                                    pixel_size=0.1,
                                    timestamp=timestamp,
                                    wavelength=wavelength)
                print("Saving", path)
                easy_pickle.dump(path, d)
        elif command_line.options.as_pickle:
            split_address = cspad_tbx.address_split(address)
            old_style_address = split_address[0] + "-" + split_address[
                1] + "|" + split_address[2] + "-" + split_address[3]

            xpp = 'xpp' in address.lower()
            if xpp:
                evt_time = cspad_tbx.evt_time(
                    evt)  # tuple of seconds, milliseconds
                timestamp = cspad_tbx.evt_timestamp(
                    evt_time)  # human readable format
                from iotbx.detectors.cspad_detector_formats import detector_format_version, reverse_timestamp
                from xfel.cxi.cspad_ana.cspad_tbx import xpp_active_areas
                version_lookup = detector_format_version(
                    old_style_address,
                    reverse_timestamp(timestamp)[0])
                assert version_lookup is not None
                active_areas = xpp_active_areas[version_lookup]['active_areas']
                beam_center = [1765 // 2, 1765 // 2]
            else:
                if command_line.options.pickle_calib_dir is not None:
                    metro_path = command_line.options.pickle_calib_dir
                elif command_line.options.pickle_optical_metrology:
                    from xfel.cftbx.detector.cspad_cbf_tbx import get_calib_file_path
                    metro_path = get_calib_file_path(run.env(), address, run)
                else:
                    metro_path = libtbx.env.find_in_repositories(
                        "xfel/metrology/CSPad/run4/CxiDs1.0_Cspad.0")
                sections = parse_calib.calib2sections(metro_path)
                beam_center, active_areas = cspad_tbx.cbcaa(
                    cspad_tbx.getConfig(address, ds.env()), sections)

            class fake_quad(object):
                def __init__(self, q, d):
                    self.q = q
                    self.d = d

                def quad(self):
                    return self.q

                def data(self):
                    return self.d

            if xpp:
                quads = [
                    fake_quad(i, mean[i * 8:(i + 1) * 8, :, :])
                    for i in range(4)
                ]
                mean = cspad_tbx.image_xpp(old_style_address,
                                           None,
                                           ds.env(),
                                           active_areas,
                                           quads=quads)
                mean = flex.double(mean.astype(np.float64))

                quads = [
                    fake_quad(i, stddev[i * 8:(i + 1) * 8, :, :])
                    for i in range(4)
                ]
                stddev = cspad_tbx.image_xpp(old_style_address,
                                             None,
                                             ds.env(),
                                             active_areas,
                                             quads=quads)
                stddev = flex.double(stddev.astype(np.float64))

                quads = [
                    fake_quad(i, maxall[i * 8:(i + 1) * 8, :, :])
                    for i in range(4)
                ]
                maxall = cspad_tbx.image_xpp(old_style_address,
                                             None,
                                             ds.env(),
                                             active_areas,
                                             quads=quads)
                maxall = flex.double(maxall.astype(np.float64))

                if command_line.options.do_minimum_projection:
                    quads = [
                        fake_quad(i, minall[i * 8:(i + 1) * 8, :, :])
                        for i in range(4)
                    ]
                    minall = cspad_tbx.image_xpp(old_style_address,
                                                 None,
                                                 ds.env(),
                                                 active_areas,
                                                 quads=quads)
                    minall = flex.double(minall.astype(np.float64))
            else:
                quads = [
                    fake_quad(i, mean[i * 8:(i + 1) * 8, :, :])
                    for i in range(4)
                ]
                mean = cspad_tbx.CsPadDetector(address,
                                               evt,
                                               ds.env(),
                                               sections,
                                               quads=quads)
                mean = flex.double(mean.astype(np.float64))

                quads = [
                    fake_quad(i, stddev[i * 8:(i + 1) * 8, :, :])
                    for i in range(4)
                ]
                stddev = cspad_tbx.CsPadDetector(address,
                                                 evt,
                                                 ds.env(),
                                                 sections,
                                                 quads=quads)
                stddev = flex.double(stddev.astype(np.float64))

                quads = [
                    fake_quad(i, maxall[i * 8:(i + 1) * 8, :, :])
                    for i in range(4)
                ]
                maxall = cspad_tbx.CsPadDetector(address,
                                                 evt,
                                                 ds.env(),
                                                 sections,
                                                 quads=quads)
                maxall = flex.double(maxall.astype(np.float64))

                if command_line.options.do_minimum_projection:
                    quads = [
                        fake_quad(i, minall[i * 8:(i + 1) * 8, :, :])
                        for i in range(4)
                    ]
                    minall = cspad_tbx.CsPadDetector(address,
                                                     evt,
                                                     ds.env(),
                                                     sections,
                                                     quads=quads)
                    minall = flex.double(minall.astype(np.float64))

            all_data = [mean, stddev, maxall]
            if command_line.options.do_minimum_projection:
                all_data.append(minall)

            for data, path in zip(all_data, dest_paths):
                print("Saving", path)

                d = cspad_tbx.dpack(active_areas=active_areas,
                                    address=old_style_address,
                                    beam_center_x=pixel_size * beam_center[0],
                                    beam_center_y=pixel_size * beam_center[1],
                                    data=data,
                                    distance=distance,
                                    pixel_size=pixel_size,
                                    saturated_value=saturated_value,
                                    timestamp=timestamp,
                                    wavelength=wavelength)

                easy_pickle.dump(path, d)
        else:
            # load a header only cspad cbf from the slac metrology
            from xfel.cftbx.detector import cspad_cbf_tbx
            import pycbf
            base_dxtbx = cspad_cbf_tbx.env_dxtbx_from_slac_metrology(
                run, address)
            if base_dxtbx is None:
                raise Sorry("Couldn't load calibration file for run %d" %
                            run.run())

            all_data = [mean, stddev, maxall]
            if command_line.options.do_minimum_projection:
                all_data.append(minall)

            for data, path in zip(all_data, dest_paths):
                print("Saving", path)
                cspad_img = cspad_cbf_tbx.format_object_from_data(
                    base_dxtbx,
                    data,
                    distance,
                    wavelength,
                    timestamp,
                    address,
                    round_to_int=False)
                cspad_img._cbf_handle.write_widefile(path, pycbf.CBF,\
                  pycbf.MIME_HEADERS|pycbf.MSG_DIGEST|pycbf.PAD_4K, 0)
    active_areas = xpp_active_areas[params.metrology]['active_areas']

    for asic_number, (y1, x1, y2, x2) in enumerate([(active_areas[(i*4)+0]+1,
                                                     active_areas[(i*4)+1]+1,
                                                     active_areas[(i*4)+2]-1,
                                                     active_areas[(i*4)+3]-1) for i in xrange(len(active_areas)//4)]):
      ax.add_patch(Rectangle((x1,y1), x2-x1, y2-y1, color="grey"))
      ax.annotate(asic_number, (x1+(x2-x1)/2,y1+(y2-y1)/2))

    ax.set_xlim((0, 2000))
    ax.set_ylim((0, 2000))
    ax.set_ylim(ax.get_ylim()[::-1])
  else:
    # Read the metrology from an LCLS calibration directory
    from xfel.cxi.cspad_ana.parse_calib import calib2sections
    sections = calib2sections(params.metrology)
    for q_id, quad in enumerate(sections):
      for s_id, sensor in enumerate(quad):
        for a_id, asic in enumerate(sensor.corners_asic()):
          y1, x1, y2, x2 = asic
          p0 = col((x1,y1))
          p1 = col((x2,y1))
          p2 = col((x2,y2))
          p3 = col((x1,y2))
          v1 = p1-p0
          v2 = p3-p0
          vcen = ((v2/2) + (v1/2)) + p0

          ax.add_patch(Polygon((p0[0:2],p1[0:2],p2[0:2],p3[0:2]), closed=True, color='green', fill=False, hatch='/'))
          ax.annotate(q_id*16+s_id*2+a_id, vcen[0:2])
Ejemplo n.º 4
0
    params = master_phil.fetch(sources=user_phil).extract()
    assert params.pickle_file is not None
    if len(params.pickle_file) == 0:
        master_phil.show()
        raise Usage(
            "pickle_file must be defined (either pickle_file=XXX, or the file path(s) alone)."
        )
    assert params.detector is not None
    assert params.plot is not None

    if params.old_metrology is None:
        params.old_metrology = libtbx.env.find_in_repositories(
            "xfel/metrology/CSPad/run4/CxiDs1.0_Cspad.0")
    if os.path.isdir(params.old_metrology):
        sections = calib2sections(params.old_metrology)
    else:
        from xfel.cxi.cspad_ana.cspad_tbx import xpp_active_areas
        assert params.old_metrology in xpp_active_areas

    if params.new_metrology is None:
        params.new_metrology = libtbx.env.find_in_repositories(
            "xfel/metrology/CSPad/run4/CxiDs1.0_Cspad.0")
    assert os.path.isdir(params.new_metrology) or os.path.isfile(
        params.new_metrology)

    # Read the new metrology, either from a calibration directory or an optical metrology
    # flat file
    if os.path.isdir(params.new_metrology):
        metro_style = "calibdir"
    address, timestamp = address_and_timestamp_from_detector_format_version(
        params.detector_format_version)
    timestamp = evt_timestamp((timestamp, 0))

    raw_data = numpy.zeros((11840, 194))
    if params.detector_format_version is not None and "XPP" in params.detector_format_version:
        from xfel.cxi.cspad_ana.cspad_tbx import xpp_active_areas
        active_areas = xpp_active_areas[
            params.detector_format_version]['active_areas']
        data = flex.int(flex.grid((1765, 1765)))
        beam_center = (1765 // 2, 1765 // 2)
    else:
        if params.optical_metrology_path is None:
            calib_dir = libtbx.env.find_in_repositories(
                "xfel/metrology/CSPad/run4/CxiDs1.0_Cspad.0")
            sections = calib2sections(calib_dir)
        else:
            sections = calib2sections(params.optical_metrology_path)
        asic_start = 0
        data3d = []
        for i_quad in range(4):
            asic_size = 185 * 194
            section_size = asic_size * 4
            quad_start = i_quad * section_size * 4
            quad_asics = []
            for i_2x2 in range(4):
                for i_asic in range(2):
                    asic_end = asic_start + 185
                    a = raw_data[asic_start:asic_end, :]
                    asic_start = asic_end
Ejemplo n.º 6
0
def convert_detector(raw_data, detector_format_version, address, optical_metrology_path=None):
  # https://confluence.slac.stanford.edu/display/PCDS/CSPad+metrology+and+calibration+files%2C+links
  data3d = []
  if raw_data.shape == (5920,388):
    asic_start = 0
    if optical_metrology_path is None:
      calib_dir = libtbx.env.find_in_repositories("xfel/metrology/CSPad/run4/CxiDs1.0_Cspad.0")
      sections = parse_calib.calib2sections(calib_dir)
    else:
      sections = parse_calib.calib2sections(optical_metrology_path)
    for i_quad in range(4):
      asic_size = 185 * 388
      section_size = asic_size * 2
      quad_start = i_quad * section_size * 4
      quad_asics = []
      for i_2x2 in range(4):
        for i_asic in range(2):
          asic_end = asic_start + 185
          quad_asics.append(raw_data[asic_start:asic_end, :])
          asic_start = asic_end
      quad_data = numpy.dstack(quad_asics)
      quad_data = numpy.rollaxis(quad_data, 2,0)
      data3d.append(fake_cspad_ElementV2(quad_data, i_quad))
    env = fake_env(fake_config())
    evt = fake_evt(data3d)
    return flex.double(cspad_tbx.CsPadDetector(address, evt, env, sections).astype(numpy.float64)), None
  else:
    asic_start = 0
    if detector_format_version is not None and 'XPP' in detector_format_version:
      from xfel.cxi.cspad_ana.cspad_tbx import xpp_active_areas
      rotations = xpp_active_areas[detector_format_version]['rotations']
      active_areas = xpp_active_areas[detector_format_version]['active_areas']
      det = flex.double([0]*(1765*1765))
      det.reshape(flex.grid((1765,1765)))
      for i in xrange(64):
        row = active_areas[i*4]
        col = active_areas[i*4 + 1]
        block = flex.double(raw_data[i * 185:(i+1)*185, :])
        det.matrix_paste_block_in_place(block.matrix_rot90(rotations[i]), row, col)
      return det, active_areas

    else:
      if optical_metrology_path is None:
        calib_dir = libtbx.env.find_in_repositories("xfel/metrology/CSPad/run4/CxiDs1.0_Cspad.0")
        sections = parse_calib.calib2sections(calib_dir)
      else:
        sections = parse_calib.calib2sections(optical_metrology_path)
      for i_quad in range(4):
        asic_size = 185 * 194
        section_size = asic_size * 4
        quad_start = i_quad * section_size * 4
        quad_asics = []
        for i_2x2 in range(4):
          for i_asic in range(2):
            asic_end = asic_start + 185
            a = raw_data[asic_start:asic_end, :]
            asic_start = asic_end

            asic_end = asic_start + 185
            b = raw_data[asic_start:asic_end, :]
            asic_start = asic_end

            quad_asics.append(numpy.concatenate((a,b),axis=1))
        quad_data = numpy.dstack(quad_asics)
        quad_data = numpy.rollaxis(quad_data, 2,0)
        data3d.append(fake_cspad_ElementV2(quad_data, i_quad))

      env = fake_env(fake_config())
      evt = fake_evt(data3d)
      beam_center, active_areas = cspad_tbx.cbcaa(fake_config(),sections)
      return flex.double(cspad_tbx.CsPadDetector(address, evt, env, sections).astype(numpy.float64)), active_areas
Ejemplo n.º 7
0
def display_calib(dirname, right, verbose):
    """XXX Docstring, in fact revise all the documentation

  @param dirname Directory with calibration information
  @param right   @c True to restrict rotations to right angles
  @param verbose @c True to print ASIC coordinates
  """

    fig = plt.figure(figsize=(10, 10))
    ax = plt.axes([0, 0, 1, 1])
    plt.axis([0, 1765, 1765, 0])

    colours = []
    patches = []
    sections = calib2sections(dirname)
    for q in xrange(len(sections)):
        for s in xrange(len(sections[q])):

            # Get the vertices of the section s in quadrant q, and round
            # rotation angles to integer multiples of 90 degrees by default.
            # Change from matrix-coordinate system to screen coordinate
            # system, where origin is in the top left corner, the first
            # coordinate increases to the right, and the second coordinate
            # increases downwards.  Ensure that the eight sections within
            # the quadrants are coloured consistently.
            vertices = sections[q][s].corners(right)
            for i in xrange(len(vertices)):
                vertices[i] = [vertices[i][1], vertices[i][0]]

            art = mpatches.Circle(vertices[0], 10)
            patches.append(art)
            colours.append(s)

            polygon = mpatches.Polygon(vertices)
            patches.append(polygon)
            colours.append(s)

            plt.text(sections[q][s].center[1],
                     sections[q][s].center[0],
                     "(%1d, %1d)" % (q, s),
                     family="sans-serif",
                     size=14,
                     ha="center",
                     va="center")

            # Assuming that rotations are integer multiples of 90 degrees,
            # print the ASIC coordinates in "spotfinder" format, ordered by
            # quadrant, section, and ASIC.  XXX This only makes sense for
            # right = True.
            if (verbose):
                vertices = sections[q][s].corners_asic()
                print "(%4d, %4d, %4d, %4d)" % \
                    (vertices[0][0], vertices[0][1], vertices[0][2], vertices[0][3])
                print "(%4d, %4d, %4d, %4d)" % \
                    (vertices[1][0], vertices[1][1], vertices[1][2], vertices[1][3])

    collection = PatchCollection(patches, cmap=matplotlib.cm.jet, alpha=0.4)
    collection.set_array(numpy.array(colours))
    ax.add_collection(collection)
    ax.set_xticks([])
    ax.set_yticks([])
    plt.show()

    return (0)
Ejemplo n.º 8
0
def average(argv=None):
  if argv == None:
    argv = sys.argv[1:]

  try:
    from mpi4py import MPI
  except ImportError:
    raise Sorry("MPI not found")

  command_line = (libtbx.option_parser.option_parser(
    usage="""
%s [-p] -c config -x experiment -a address -r run -d detz_offset [-o outputdir] [-A averagepath] [-S stddevpath] [-M maxpath] [-n numevents] [-s skipnevents] [-v] [-m] [-b bin_size] [-X override_beam_x] [-Y override_beam_y] [-D xtc_dir] [-f]

To write image pickles use -p, otherwise the program writes CSPAD CBFs.
Writing CBFs requires the geometry to be already deployed.

Examples:
cxi.mpi_average -c cxi49812/average.cfg -x cxi49812 -a CxiDs1.0:Cspad.0 -r 25 -d 571

Use one process on the current node to process all the events from run 25 of
experiment cxi49812, using a detz_offset of 571.

mpirun -n 16 cxi.mpi_average -c cxi49812/average.cfg -x cxi49812 -a CxiDs1.0:Cspad.0 -r 25 -d 571

As above, using 16 cores on the current node.

bsub -a mympi -n 100 -o average.out -q psanaq cxi.mpi_average -c cxi49812/average.cfg -x cxi49812 -a CxiDs1.0:Cspad.0 -r 25 -d 571 -o cxi49812

As above, using the psanaq and 100 cores, putting the log in average.out and
the output images in the folder cxi49812.
""" % libtbx.env.dispatcher_name)
                .option(None, "--as_pickle", "-p",
                        action="store_true",
                        default=False,
                        dest="as_pickle",
                        help="Write results as image pickle files instead of cbf files")
                .option(None, "--config", "-c",
                        type="string",
                        default=None,
                        dest="config",
                        metavar="PATH",
                        help="psana config file")
                .option(None, "--experiment", "-x",
                        type="string",
                        default=None,
                        dest="experiment",
                        help="experiment name (eg cxi84914)")
                .option(None, "--run", "-r",
                        type="int",
                        default=None,
                        dest="run",
                        help="run number")
                .option(None, "--address", "-a",
                        type="string",
                        default="CxiDs2.0:Cspad.0",
                        dest="address",
                        help="detector address name (eg CxiDs2.0:Cspad.0)")
                .option(None, "--detz_offset", "-d",
                        type="float",
                        default=None,
                        dest="detz_offset",
                        help="offset (in mm) from sample interaction region to back of CSPAD detector rail (CXI), or detector distance (XPP)")
                .option(None, "--outputdir", "-o",
                        type="string",
                        default=".",
                        dest="outputdir",
                        metavar="PATH",
                        help="Optional path to output directory for output files")
                .option(None, "--averagebase", "-A",
                        type="string",
                        default="{experiment!l}_avg-r{run:04d}",
                        dest="averagepath",
                        metavar="PATH",
                        help="Path to output average image without extension. String substitution allowed")
                .option(None, "--stddevbase", "-S",
                        type="string",
                        default="{experiment!l}_stddev-r{run:04d}",
                        dest="stddevpath",
                        metavar="PATH",
                        help="Path to output standard deviation image without extension. String substitution allowed")
                .option(None, "--maxbase", "-M",
                        type="string",
                        default="{experiment!l}_max-r{run:04d}",
                        dest="maxpath",
                        metavar="PATH",
                        help="Path to output maximum projection image without extension. String substitution allowed")
                .option(None, "--numevents", "-n",
                        type="int",
                        default=None,
                        dest="numevents",
                        help="Maximum number of events to process. Default: all")
                .option(None, "--skipevents", "-s",
                        type="int",
                        default=0,
                        dest="skipevents",
                        help="Number of events in the beginning of the run to skip. Default: 0")
                .option(None, "--verbose", "-v",
                        action="store_true",
                        default=False,
                        dest="verbose",
                        help="Print more information about progress")
                .option(None, "--pickle-optical-metrology", "-m",
                        action="store_true",
                        default=False,
                        dest="pickle_optical_metrology",
                        help="If writing pickle files, use the optical metrology in the experiment's calib directory")
                .option(None, "--bin_size", "-b",
                        type="int",
                        default=None,
                        dest="bin_size",
                        help="Rayonix detector bin size")
                .option(None, "--override_beam_x", "-X",
                        type="float",
                        default=None,
                        dest="override_beam_x",
                        help="Rayonix detector beam center x coordinate")
                .option(None, "--override_beam_y", "-Y",
                        type="float",
                        default=None,
                        dest="override_beam_y",
                        help="Rayonix detector beam center y coordinate")
                .option(None, "--calib_dir", "-C",
                        type="string",
                        default=None,
                        dest="calib_dir",
                        metavar="PATH",
                        help="calibration directory")
                .option(None, "--xtc_dir", "-D",
                        type="string",
                        default=None,
                        dest="xtc_dir",
                        metavar="PATH",
                        help="xtc stream directory")
                .option(None, "--use_ffb", "-f",
                        action="store_true",
                        default=False,
                        dest="use_ffb",
                        help="Use the fast feedback filesystem at LCLS. Only for the active experiment!")
                ).process(args=argv)


  if len(command_line.args) > 0 or \
      command_line.options.as_pickle is None or \
      command_line.options.experiment is None or \
      command_line.options.run is None or \
      command_line.options.address is None or \
      command_line.options.detz_offset is None or \
      command_line.options.averagepath is None or \
      command_line.options.stddevpath is None or \
      command_line.options.maxpath is None or \
      command_line.options.pickle_optical_metrology is None:
    command_line.parser.show_help()
    return

  # set this to sys.maxint to analyze all events
  if command_line.options.numevents is None:
    maxevents = sys.maxint
  else:
    maxevents = command_line.options.numevents

  comm = MPI.COMM_WORLD
  rank = comm.Get_rank()
  size = comm.Get_size()

  if command_line.options.config is not None:
    psana.setConfigFile(command_line.options.config)
  dataset_name = "exp=%s:run=%d:idx"%(command_line.options.experiment, command_line.options.run)
  if command_line.options.xtc_dir is not None:
    if command_line.options.use_ffb:
      raise Sorry("Cannot specify the xtc_dir and use SLAC's ffb system")
    dataset_name += ":dir=%s"%command_line.options.xtc_dir
  elif command_line.options.use_ffb:
    # as ffb is only at SLAC, ok to hardcode /reg/d here
    dataset_name += ":dir=/reg/d/ffb/%s/%s/xtc"%(command_line.options.experiment[0:3],command_line.options.experiment)
  ds = psana.DataSource(dataset_name)
  address = command_line.options.address
  src = psana.Source('DetInfo(%s)'%address)
  if not command_line.options.as_pickle:
    psana_det = psana.Detector(address, ds.env())

  nevent = np.array([0.])

  for run in ds.runs():
    runnumber = run.run()
    # list of all events
    if command_line.options.skipevents > 0:
      print "Skipping first %d events"%command_line.options.skipevents

    times = run.times()[command_line.options.skipevents:]
    nevents = min(len(times),maxevents)
    # chop the list into pieces, depending on rank.  This assigns each process
    # events such that the get every Nth event where N is the number of processes
    mytimes = [times[i] for i in xrange(nevents) if (i+rank)%size == 0]
    for i in xrange(len(mytimes)):
      if i%10==0: print 'Rank',rank,'processing event',rank*len(mytimes)+i,', ',i,'of',len(mytimes)
      evt = run.event(mytimes[i])
      #print "Event #",rank*mylength+i," has id:",evt.get(EventId)
      if 'Rayonix' in command_line.options.address:
        data = evt.get(Camera.FrameV1,src)
        if data is None:
          print "No data"
          continue
        data=data.data16().astype(np.float64)
      elif command_line.options.as_pickle:
        data = evt.get(psana.ndarray_float64_3, src, 'image0')
      else:
        # get numpy array, 32x185x388
        data = psana_det.calib(evt) # applies psana's complex run-dependent calibrations
      if data is None:
        print "No data"
        continue

      d = cspad_tbx.env_distance(address, run.env(), command_line.options.detz_offset)
      if d is None:
        print "No distance, skipping shot"
        continue
      if 'distance' in locals():
        distance += d
      else:
        distance = np.array([float(d)])

      w = cspad_tbx.evt_wavelength(evt)
      if w is None:
        print "No wavelength, skipping shot"
        continue
      if 'wavelength' in locals():
        wavelength += w
      else:
        wavelength = np.array([w])

      t = cspad_tbx.evt_time(evt)
      if t is None:
        print "No timestamp, skipping shot"
        continue
      if 'timestamp' in locals():
        timestamp += t[0] + (t[1]/1000)
      else:
        timestamp = np.array([t[0] + (t[1]/1000)])

      if 'sum' in locals():
        sum+=data
      else:
        sum=np.array(data, copy=True)
      if 'sumsq' in locals():
        sumsq+=data*data
      else:
        sumsq=data*data
      if 'maximum' in locals():
        maximum=np.maximum(maximum,data)
      else:
        maximum=np.array(data, copy=True)

      nevent += 1

  #sum the images across mpi cores
  if size > 1:
    print "Synchronizing rank", rank
  totevent = np.zeros(nevent.shape)
  comm.Reduce(nevent,totevent)

  if rank == 0 and totevent[0] == 0:
    raise Sorry("No events found in the run")

  sumall = np.zeros(sum.shape).astype(sum.dtype)
  comm.Reduce(sum,sumall)

  sumsqall = np.zeros(sumsq.shape).astype(sumsq.dtype)
  comm.Reduce(sumsq,sumsqall)

  maxall = np.zeros(maximum.shape).astype(maximum.dtype)
  comm.Reduce(maximum,maxall, op=MPI.MAX)

  waveall = np.zeros(wavelength.shape).astype(wavelength.dtype)
  comm.Reduce(wavelength,waveall)

  distall = np.zeros(distance.shape).astype(distance.dtype)
  comm.Reduce(distance,distall)

  timeall = np.zeros(timestamp.shape).astype(timestamp.dtype)
  comm.Reduce(timestamp,timeall)

  if rank==0:
    if size > 1:
      print "Synchronized"

    # Accumulating floating-point numbers introduces errors,
    # which may cause negative variances.  Since a two-pass
    # approach is unacceptable, the standard deviation is
    # clamped at zero.
    mean = sumall / float(totevent[0])
    variance = (sumsqall / float(totevent[0])) - (mean**2)
    variance[variance < 0] = 0
    stddev = np.sqrt(variance)

    wavelength = waveall[0] / totevent[0]
    distance = distall[0] / totevent[0]
    pixel_size = cspad_tbx.pixel_size
    saturated_value = cspad_tbx.cspad_saturated_value
    timestamp = timeall[0] / totevent[0]
    timestamp = (int(timestamp), timestamp % int(timestamp) * 1000)
    timestamp = cspad_tbx.evt_timestamp(timestamp)


    if command_line.options.as_pickle:
      extension = ".pickle"
    else:
      extension = ".cbf"

    dest_paths = [cspad_tbx.pathsubst(command_line.options.averagepath + extension, evt, ds.env()),
                  cspad_tbx.pathsubst(command_line.options.stddevpath  + extension, evt, ds.env()),
                  cspad_tbx.pathsubst(command_line.options.maxpath     + extension, evt, ds.env())]
    dest_paths = [os.path.join(command_line.options.outputdir, path) for path in dest_paths]
    if 'Rayonix' in command_line.options.address:
      from xfel.cxi.cspad_ana import rayonix_tbx
      pixel_size = rayonix_tbx.get_rayonix_pixel_size(command_line.options.bin_size)
      beam_center = [command_line.options.override_beam_x,command_line.options.override_beam_y]
      detector_dimensions = rayonix_tbx.get_rayonix_detector_dimensions(command_line.options.bin_size)
      active_areas = flex.int([0,0,detector_dimensions[0],detector_dimensions[1]])
      split_address = cspad_tbx.address_split(address)
      old_style_address = split_address[0] + "-" + split_address[1] + "|" + split_address[2] + "-" + split_address[3]
      for data, path in zip([mean, stddev, maxall], dest_paths):
        print "Saving", path
        d = cspad_tbx.dpack(
            active_areas=active_areas,
            address=old_style_address,
            beam_center_x=pixel_size * beam_center[0],
            beam_center_y=pixel_size * beam_center[1],
            data=flex.double(data),
            distance=distance,
            pixel_size=pixel_size,
            saturated_value=rayonix_tbx.rayonix_saturated_value,
            timestamp=timestamp,
            wavelength=wavelength)
        easy_pickle.dump(path, d)
    elif command_line.options.as_pickle:
      split_address = cspad_tbx.address_split(address)
      old_style_address = split_address[0] + "-" + split_address[1] + "|" + split_address[2] + "-" + split_address[3]

      xpp = 'xpp' in address.lower()
      if xpp:
        evt_time = cspad_tbx.evt_time(evt) # tuple of seconds, milliseconds
        timestamp = cspad_tbx.evt_timestamp(evt_time) # human readable format
        from xfel.detector_formats import detector_format_version, reverse_timestamp
        from xfel.cxi.cspad_ana.cspad_tbx import xpp_active_areas
        version_lookup = detector_format_version(old_style_address, reverse_timestamp(timestamp)[0])
        assert version_lookup is not None
        active_areas = xpp_active_areas[version_lookup]['active_areas']
        beam_center = [1765 // 2, 1765 // 2]
      else:
        if command_line.options.calib_dir is not None:
          metro_path = command_line.options.calib_dir
        elif command_line.options.pickle_optical_metrology:
          from xfel.cftbx.detector.cspad_cbf_tbx import get_calib_file_path
          metro_path = get_calib_file_path(run.env(), address, run)
        else:
          metro_path = libtbx.env.find_in_repositories("xfel/metrology/CSPad/run4/CxiDs1.0_Cspad.0")
        sections = parse_calib.calib2sections(metro_path)
        beam_center, active_areas = cspad_tbx.cbcaa(
          cspad_tbx.getConfig(address, ds.env()), sections)

      class fake_quad(object):
        def __init__(self, q, d):
          self.q = q
          self.d = d

        def quad(self):
          return self.q

        def data(self):
          return self.d

      if xpp:
        quads = [fake_quad(i, mean[i*8:(i+1)*8,:,:]) for i in xrange(4)]
        mean = cspad_tbx.image_xpp(old_style_address, None, ds.env(), active_areas, quads = quads)
        mean = flex.double(mean.astype(np.float64))

        quads = [fake_quad(i, stddev[i*8:(i+1)*8,:,:]) for i in xrange(4)]
        stddev = cspad_tbx.image_xpp(old_style_address, None, ds.env(), active_areas, quads = quads)
        stddev = flex.double(stddev.astype(np.float64))

        quads = [fake_quad(i, maxall[i*8:(i+1)*8,:,:]) for i in xrange(4)]
        maxall = cspad_tbx.image_xpp(old_style_address, None, ds.env(), active_areas, quads = quads)
        maxall = flex.double(maxall.astype(np.float64))
      else:
        quads = [fake_quad(i, mean[i*8:(i+1)*8,:,:]) for i in xrange(4)]
        mean = cspad_tbx.CsPadDetector(
          address, evt, ds.env(), sections, quads=quads)
        mean = flex.double(mean.astype(np.float64))

        quads = [fake_quad(i, stddev[i*8:(i+1)*8,:,:]) for i in xrange(4)]
        stddev = cspad_tbx.CsPadDetector(
          address, evt, ds.env(), sections, quads=quads)
        stddev = flex.double(stddev.astype(np.float64))

        quads = [fake_quad(i, maxall[i*8:(i+1)*8,:,:]) for i in xrange(4)]
        maxall = cspad_tbx.CsPadDetector(
          address, evt, ds.env(), sections, quads=quads)
        maxall = flex.double(maxall.astype(np.float64))

      for data, path in zip([mean, stddev, maxall], dest_paths):
        print "Saving", path

        d = cspad_tbx.dpack(
          active_areas=active_areas,
          address=old_style_address,
          beam_center_x=pixel_size * beam_center[0],
          beam_center_y=pixel_size * beam_center[1],
          data=data,
          distance=distance,
          pixel_size=pixel_size,
          saturated_value=saturated_value,
          timestamp=timestamp,
          wavelength=wavelength)

        easy_pickle.dump(path, d)
    else:
      # load a header only cspad cbf from the slac metrology
      from xfel.cftbx.detector import cspad_cbf_tbx
      import pycbf
      base_dxtbx = cspad_cbf_tbx.env_dxtbx_from_slac_metrology(run, address)
      if base_dxtbx is None:
        raise Sorry("Couldn't load calibration file for run %d"%run.run())

      for data, path in zip([mean, stddev, maxall], dest_paths):
        print "Saving", path

        cspad_img = cspad_cbf_tbx.format_object_from_data(base_dxtbx, data, distance, wavelength, timestamp, address)
        cspad_img._cbf_handle.write_widefile(path, pycbf.CBF,\
          pycbf.MIME_HEADERS|pycbf.MSG_DIGEST|pycbf.PAD_4K, 0)
Ejemplo n.º 9
0
def display_calib(dirname, right, verbose):
    """XXX Docstring, in fact revise all the documentation

  @param dirname Directory with calibration information
  @param right   @c True to restrict rotations to right angles
  @param verbose @c True to print ASIC coordinates
  """

    fig = plt.figure(figsize=(10, 10))
    ax = plt.axes([0, 0, 1, 1])
    plt.axis([0, 1765, 1765, 0])

    colours = []
    patches = []
    sections = calib2sections(dirname)
    for q in xrange(len(sections)):
        for s in xrange(len(sections[q])):

            # Get the vertices of the section s in quadrant q, and round
            # rotation angles to integer multiples of 90 degrees by default.
            # Change from matrix-coordinate system to screen coordinate
            # system, where origin is in the top left corner, the first
            # coordinate increases to the right, and the second coordinate
            # increases downwards.  Ensure that the eight sections within
            # the quadrants are coloured consistently.
            vertices = sections[q][s].corners(right)
            for i in xrange(len(vertices)):
                vertices[i] = [vertices[i][1], vertices[i][0]]

            art = mpatches.Circle(vertices[0], 10)
            patches.append(art)
            colours.append(s)

            polygon = mpatches.Polygon(vertices)
            patches.append(polygon)
            colours.append(s)

            plt.text(
                sections[q][s].center[1],
                sections[q][s].center[0],
                "(%1d, %1d)" % (q, s),
                family="sans-serif",
                size=14,
                ha="center",
                va="center",
            )

            # Assuming that rotations are integer multiples of 90 degrees,
            # print the ASIC coordinates in "spotfinder" format, ordered by
            # quadrant, section, and ASIC.  XXX This only makes sense for
            # right = True.
            if verbose:
                vertices = sections[q][s].corners_asic()
                print "(%4d, %4d, %4d, %4d)" % (vertices[0][0], vertices[0][1], vertices[0][2], vertices[0][3])
                print "(%4d, %4d, %4d, %4d)" % (vertices[1][0], vertices[1][1], vertices[1][2], vertices[1][3])

    collection = PatchCollection(patches, cmap=matplotlib.cm.jet, alpha=0.4)
    collection.set_array(numpy.array(colours))
    ax.add_collection(collection)
    ax.set_xticks([])
    ax.set_yticks([])
    plt.show()

    return 0
Ejemplo n.º 10
0
def convert_detector(raw_data,
                     detector_format_version,
                     address,
                     optical_metrology_path=None):
    # https://confluence.slac.stanford.edu/display/PCDS/CSPad+metrology+and+calibration+files%2C+links
    data3d = []
    if raw_data.shape == (5920, 388):
        asic_start = 0
        if optical_metrology_path is None:
            calib_dir = libtbx.env.find_in_repositories(
                "xfel/metrology/CSPad/run4/CxiDs1.0_Cspad.0")
            sections = parse_calib.calib2sections(calib_dir)
        else:
            sections = parse_calib.calib2sections(optical_metrology_path)
        for i_quad in range(4):
            asic_size = 185 * 388
            section_size = asic_size * 2
            quad_start = i_quad * section_size * 4
            quad_asics = []
            for i_2x2 in range(4):
                for i_asic in range(2):
                    asic_end = asic_start + 185
                    quad_asics.append(raw_data[asic_start:asic_end, :])
                    asic_start = asic_end
            quad_data = numpy.dstack(quad_asics)
            quad_data = numpy.rollaxis(quad_data, 2, 0)
            data3d.append(fake_cspad_ElementV2(quad_data, i_quad))
        env = fake_env(fake_config())
        evt = fake_evt(data3d)
        return flex.double(
            cspad_tbx.CsPadDetector(address, evt, env,
                                    sections).astype(numpy.float64)), None
    else:
        asic_start = 0
        if detector_format_version is not None and 'XPP' in detector_format_version:
            from xfel.cxi.cspad_ana.cspad_tbx import xpp_active_areas
            rotations = xpp_active_areas[detector_format_version]['rotations']
            active_areas = xpp_active_areas[detector_format_version][
                'active_areas']
            det = flex.double([0] * (1765 * 1765))
            det.reshape(flex.grid((1765, 1765)))
            for i in range(64):
                row = active_areas[i * 4]
                col = active_areas[i * 4 + 1]
                block = flex.double(raw_data[i * 185:(i + 1) * 185, :])
                det.matrix_paste_block_in_place(
                    block.matrix_rot90(rotations[i]), row, col)
            return det, active_areas

        else:
            if optical_metrology_path is None:
                calib_dir = libtbx.env.find_in_repositories(
                    "xfel/metrology/CSPad/run4/CxiDs1.0_Cspad.0")
                sections = parse_calib.calib2sections(calib_dir)
            else:
                sections = parse_calib.calib2sections(optical_metrology_path)
            for i_quad in range(4):
                asic_size = 185 * 194
                section_size = asic_size * 4
                quad_start = i_quad * section_size * 4
                quad_asics = []
                for i_2x2 in range(4):
                    for i_asic in range(2):
                        asic_end = asic_start + 185
                        a = raw_data[asic_start:asic_end, :]
                        asic_start = asic_end

                        asic_end = asic_start + 185
                        b = raw_data[asic_start:asic_end, :]
                        asic_start = asic_end

                        quad_asics.append(numpy.concatenate((a, b), axis=1))
                quad_data = numpy.dstack(quad_asics)
                quad_data = numpy.rollaxis(quad_data, 2, 0)
                data3d.append(fake_cspad_ElementV2(quad_data, i_quad))

            env = fake_env(fake_config())
            evt = fake_evt(data3d)
            beam_center, active_areas = cspad_tbx.cbcaa(
                fake_config(), sections)
            return flex.double(
                cspad_tbx.CsPadDetector(address, evt, env, sections).astype(
                    numpy.float64)), active_areas
  from xfel.cxi.cspad_ana.cspad_tbx import dpack, evt_timestamp, cbcaa, pixel_size, CsPadDetector
  from iotbx.detectors.cspad_detector_formats import address_and_timestamp_from_detector_format_version
  from convert_gain_map import fake_env, fake_config, fake_evt, fake_cspad_ElementV2
  address, timestamp = address_and_timestamp_from_detector_format_version(params.detector_format_version)
  timestamp = evt_timestamp((timestamp,0))

  raw_data = numpy.zeros((11840,194))
  if params.detector_format_version is not None and "XPP" in params.detector_format_version:
    from xfel.cxi.cspad_ana.cspad_tbx import xpp_active_areas
    active_areas = xpp_active_areas[params.detector_format_version]['active_areas']
    data = flex.int(flex.grid((1765,1765)))
    beam_center = (1765 // 2, 1765 // 2)
  else:
    if params.optical_metrology_path is None:
      calib_dir = libtbx.env.find_in_repositories("xfel/metrology/CSPad/run4/CxiDs1.0_Cspad.0")
      sections = calib2sections(calib_dir)
    else:
      sections = calib2sections(params.optical_metrology_path)
    asic_start = 0
    data3d = []
    for i_quad in range(4):
      asic_size = 185 * 194
      section_size = asic_size * 4
      quad_start = i_quad * section_size * 4
      quad_asics = []
      for i_2x2 in range(4):
        for i_asic in range(2):
          asic_end = asic_start + 185
          a = raw_data[asic_start:asic_end, :]
          asic_start = asic_end
Ejemplo n.º 12
0
def metrology2phil(calib_dir, verbose):
  """XXX Should really review the SLAC progress since last time
  around!  XXX Note that this is all SLAC-specific (as is the whole
  thing, I guess).
  """

  from xfel.cftbx.detector.metrology import master_phil

  # XXX Can this fail?  How?
  sections = calib2sections(calib_dir)
  if (sections is None):
    return (None)

  # Properties of CSPad pixels (Philipp et al., 2007).  The counters
  # are 14 bits wide, and the pixels are square with a side length of
  # 110 um.  Because cspad_tbx depends on pyana, it may fail to import
  # in which case a hardcoded fallback is provided.
  try:
    from xfel.cxi.cspad_ana.cspad_tbx import cspad_saturated_value as sv
    from xfel.cxi.cspad_ana.cspad_tbx import pixel_size as ps
    saturated_value = sv
    pixel_size = ps * 1e-3
  except ImportError:
    saturated_value = 90000
    pixel_size = 110e-6

  # Build the Phil object.  XXX Should have det-z?  Probably not,
  # because then it aint't just metrology anymore.  In fact, under
  # orthographic projection the whole translation/orientation thing
  # can be scrapped for the detector.  XXX look up include,
  # include_scope for phil XXX Hardcoded address for now.
  address = "CxiDs1-0|Cspad-0"
  metrology_str = "detector { serial = %d\n" % 0
  metrology_str += "label = %s\n" % address

  # The center of the detector is defined as the average of all the
  # sections it contains.  The first coordinate of the matrix-oriented
  # coordinate system of the Section class maps to -y, the second to
  # x, and the third to z.  While the detector still sits on the
  # origin (zero translation), the mapping from the origin in Section
  # coordinates is still needed.
  t_d = [0, 0, 0]
  nmemb = 0
  for p in xrange(len(sections)):
    for s in xrange(len(sections[p])):
      t_d[0] += +sections[p][s].center[1]
      t_d[1] += -sections[p][s].center[0]
      t_d[2] += 0
      nmemb += 1
  if (nmemb > 0):
    for i in xrange(3):
      t_d[i] /= nmemb
  metrology_str += "translation = 0, 0, 0\n"

  o_d = matrix.col([0, 0, 1]).axis_and_angle_as_unit_quaternion(
    angle=0, deg=True)
  metrology_str += "orientation = %s, %s, %s, %s\n" % \
      tuple(repr(c) for c in o_d)

  for p in xrange(len(sections)):
    # Loop over quadrants (panels).  XXX Translation of panels is
    # wrongly set to to centre of sections in the quadrant
    # w.r.t. center of the detector.
    metrology_str += "panel { serial = %d\n" % p
    metrology_str += "translation = "
    t_p = [0, 0, 0]
    for s in xrange(len(sections[p])):
      t_p[0] += +sections[p][s].center[1] - t_d[0]
      t_p[1] += -sections[p][s].center[0] - t_d[1]
      t_p[2] +=  0                        - t_d[2]
    for i in xrange(3):
      t_p[i] /= len(sections[p])
      metrology_str += "%s" % repr(t_p[i] * pixel_size)
      if (i < 2):
        metrology_str += ", "
      else:
        metrology_str += "\n"

    # XXX Orientation wrongly set to zero.
    o_p = matrix.col([0, 0, 1]).axis_and_angle_as_unit_quaternion(
      angle=0, deg=True)
    metrology_str += "orientation = %s, %s, %s, %s\n" % \
        tuple(repr(c) for c in o_p)

    for s in xrange(len(sections[p])):
      # Loop over sensors (sections or two-by-one:s).  Note that
      # sensors are rotated by -90 degrees in the SLAC metrology
      # convention w.r.t. their appearance in the XTC stream.
      s_t = [0, 0, 0]
      s_t[0] = +sections[p][s].center[1] - t_p[0] - t_d[0]
      s_t[1] = -sections[p][s].center[0] - t_p[1] - t_d[1]
      s_t[2] =  0                        - t_p[2] - t_d[2]

      metrology_str += "sensor { serial = %d\n" % s
      metrology_str += "translation = "
      for i in xrange(3):
        metrology_str += "%s" % repr(s_t[i] * pixel_size)
        if (i < 2):
          metrology_str += ", "
        else:
          metrology_str += "\n"

      s_o = matrix.col([0, 0, 1]).axis_and_angle_as_unit_quaternion(
        angle=sections[p][s].angle - 90, deg=True)
      metrology_str += "orientation = %s, %s, %s, %s\n" % \
          tuple(repr(c) for c in s_o)

      for a in xrange(2):
        # The ASIC:s of the CSPad are 185 rows by 194 columns.  The
        # ASIC:s are horizontally aligned within a section, with a
        # three-column gap between them.
        metrology_str += "asic { serial = %d\n" % a

        if (a == 0):
          metrology_str += "translation = %s, %s, %s\n" % (
            repr(-(194 + 3) / 2 * pixel_size), "0", "0") # XXX hardcoded!
        else:
          metrology_str += "translation = %s, %s, %s\n" % (
            repr(+(194 + 3) / 2 * pixel_size), "0", "0") # XXX hardcoded!
        metrology_str += "orientation = 1, 0, 0, 0\n"
        metrology_str += "pixel_size = %s, %s\n" % (
          repr(pixel_size), repr(pixel_size))
        metrology_str += "dimension = %d, %d\n" % (194, 185) # XXX hardcoded!
        metrology_str += "saturation = %s\n" % repr(float(saturated_value))
        metrology_str += "}\n"
      metrology_str += "}\n"
    metrology_str += "}\n"
  metrology_str += "}\n"

  metrology_phil = master_phil.fetch(
    sources=[phil.parse(metrology_str)])
  return (metrology_phil)
Ejemplo n.º 13
0
    active_areas = xpp_active_areas[params.metrology]['active_areas']

    for asic_number, (y1, x1, y2, x2) in enumerate([(active_areas[(i*4)+0]+1,
                                                     active_areas[(i*4)+1]+1,
                                                     active_areas[(i*4)+2]-1,
                                                     active_areas[(i*4)+3]-1) for i in xrange(len(active_areas)//4)]):
      ax.add_patch(Rectangle((x1,y1), x2-x1, y2-y1, color="grey"))
      ax.annotate(asic_number, (x1+(x2-x1)/2,y1+(y2-y1)/2))

    ax.set_xlim((0, 2000))
    ax.set_ylim((0, 2000))
    ax.set_ylim(ax.get_ylim()[::-1])
  else:
    # Read the metrology from an LCLS calibration directory
    from xfel.cxi.cspad_ana.parse_calib import calib2sections
    sections = calib2sections(params.metrology)
    for q_id, quad in enumerate(sections):
      for s_id, sensor in enumerate(quad):
        for a_id, asic in enumerate(sensor.corners_asic()):
          y1, x1, y2, x2 = asic
          p0 = col((x1,y1))
          p1 = col((x2,y1))
          p2 = col((x2,y2))
          p3 = col((x1,y2))
          v1 = p1-p0
          v2 = p3-p0
          vcen = ((v2/2) + (v1/2)) + p0

          ax.add_patch(Polygon((p0[0:2],p1[0:2],p2[0:2],p3[0:2]), closed=True, color='green', fill=False, hatch='/'))
          ax.annotate(q_id*16+s_id*2+a_id, vcen[0:2])
Ejemplo n.º 14
0
      except RuntimeError, e :
        raise Sorry("Unrecognized argument '%s' (error: %s)" % (arg, str(e)))

  params = master_phil.fetch(sources=user_phil).extract()
  assert params.pickle_file is not None
  if len(params.pickle_file) == 0 :
    master_phil.show()
    raise Usage("pickle_file must be defined (either pickle_file=XXX, or the file path(s) alone).")
  assert params.detector is not None
  assert params.plot is not None

  if params.old_metrology is None:
    params.old_metrology=libtbx.env.find_in_repositories(
      "xfel/metrology/CSPad/run4/CxiDs1.0_Cspad.0")
  if os.path.isdir(params.old_metrology):
    sections = calib2sections(params.old_metrology)
  else:
    from xfel.cxi.cspad_ana.cspad_tbx import xpp_active_areas
    assert params.old_metrology in xpp_active_areas

  if params.new_metrology is None:
    params.new_metrology=libtbx.env.find_in_repositories(
      "xfel/metrology/CSPad/run4/CxiDs1.0_Cspad.0")
  assert os.path.isdir(params.new_metrology) or os.path.isfile(params.new_metrology)

  # Read the new metrology, either from a calibration directory or an optical metrology
  # flat file
  if os.path.isdir(params.new_metrology):
    metro_style = "calibdir"

    from xfel.cftbx.detector.metrology2phil import metrology2phil