Пример #1
0
def simulate_diffractions(grain_params, experiment, controller):
    """actual forward simulation of the diffraction"""

    # use a packed array for the image_stack
    array_dims = (experiment.nframes, experiment.ncols,
                  ((experiment.nrows - 1) // 8) + 1)
    image_stack = np.zeros(array_dims, dtype=np.uint8)

    count = len(grain_params)
    subprocess = 'simulate diffractions'

    _project = xrdutil._project_on_detector_plane
    rD = experiment.rMat_d
    chi = experiment.chi
    tD = experiment.tVec_d
    tS = experiment.tVec_s
    distortion = experiment.distortion

    eta_range = [
        (-np.pi, np.pi),
    ]
    ome_range = experiment.ome_range
    ome_period = (-np.pi, np.pi)

    full_hkls = xrdutil._fetch_hkls_from_planedata(experiment.plane_data)
    bMat = experiment.plane_data.latVecOps['B']
    wlen = experiment.plane_data.wavelength

    controller.start(subprocess, count)
    for i in range(count):
        rC = xfcapi.makeRotMatOfExpMap(grain_params[i][0:3])
        tC = np.ascontiguousarray(grain_params[i][3:6])
        vInv_s = np.ascontiguousarray(grain_params[i][6:12])
        ang_list = np.vstack(
            xfcapi.oscillAnglesOfHKLs(full_hkls[:, 1:],
                                      chi,
                                      rC,
                                      bMat,
                                      wlen,
                                      vInv=vInv_s))
        # hkls not needed here
        all_angs, _ = xrdutil._filter_hkls_eta_ome(full_hkls, ang_list,
                                                   eta_range, ome_range)
        all_angs[:, 2] = xfcapi.mapAngle(all_angs[:, 2], ome_period)

        det_xy, _ = _project(all_angs, rD, rC, chi, tD, tC, tS, distortion)

        _write_pixels(det_xy, all_angs[:, 2], image_stack, experiment.base,
                      experiment.inv_deltas, experiment.clip_vals)

        controller.update(i + 1)

    controller.finish(subprocess)
    return image_stack
Пример #2
0
def simulate_diffractions(grain_params, experiment, controller):
    """actual forward simulation of the diffraction"""

    # use a packed array for the image_stack
    array_dims = (experiment.nframes,
                  experiment.ncols,
                  ((experiment.nrows - 1)//8) + 1)
    image_stack = np.zeros(array_dims, dtype=np.uint8)

    count = len(grain_params)
    subprocess = 'simulate diffractions'

    _project = xrdutil._project_on_detector_plane
    rD = experiment.rMat_d
    chi = experiment.chi
    tD = experiment.tVec_d
    tS = experiment.tVec_s
    distortion = experiment.distortion

    eta_range = [(-np.pi, np.pi), ]
    ome_range = experiment.ome_range
    ome_period = (-np.pi, np.pi)

    full_hkls = xrdutil._fetch_hkls_from_planedata(experiment.plane_data)
    bMat = experiment.plane_data.latVecOps['B']
    wlen = experiment.plane_data.wavelength

    controller.start(subprocess, count)
    for i in range(count):
        rC = xfcapi.makeRotMatOfExpMap(grain_params[i][0:3])
        tC = np.ascontiguousarray(grain_params[i][3:6])
        vInv_s = np.ascontiguousarray(grain_params[i][6:12])
        ang_list = np.vstack(xfcapi.oscillAnglesOfHKLs(full_hkls[:, 1:], chi,
                                                       rC, bMat, wlen,
                                                       vInv=vInv_s))
        # hkls not needed here
        all_angs, _ = xrdutil._filter_hkls_eta_ome(full_hkls, ang_list,
                                                   eta_range, ome_range)
        all_angs[:, 2] = xfcapi.mapAngle(all_angs[:, 2], ome_period)

        det_xy, _ = _project(all_angs, rD, rC, chi, tD,
                             tC, tS, distortion)

        _write_pixels(det_xy, all_angs[:, 2], image_stack, experiment.base,
                      experiment.inv_deltas, experiment.clip_vals)

        controller.update(i+1)

    controller.finish(subprocess)
    return image_stack
Пример #3
0
    def __init__(self, grain, image_series_dict, instrument, plane_data,
                 eta_step=0.25, threshold=None,
                 ome_period=(0, 360)):
        """
        image_series must be OmegaImageSeries class
        instrument_params must be a dict (loaded from yaml spec)
        active_hkls must be a list (required for now)
        """
        grain_params = np.squeeze(load_data_zero[grain,:])

        analysis_id = id_analysisname + '-grain-%d' % grain + '-%s' % initial_or_final

        self._planeData = plane_data

        # ???: change name of iHKLList?
        # ???: can we change the behavior of iHKLList?
        active_hkls = [0,1,2,3,4]

        if active_hkls is None:
            n_rings = len(plane_data.getTTh())
            self._iHKLList = range(n_rings)
        else:
            self._iHKLList = active_hkls
            n_rings = len(active_hkls)

        # ???: need to pass a threshold?
        eta_mapping, etas = instrument.extract_polar_maps_grain(
            plane_data, image_series_dict, grain_params,
            active_hkls=active_hkls, threshold=threshold,
            tth_tol=None, eta_tol=eta_step)


        # grab a det key
        # WARNING: this process assumes that the imageseries for all panels
        # have the same length and omegas
        det_key = eta_mapping.keys()[0]
        data_store = []
        for i_ring in range(n_rings):
            full_map = np.zeros_like(eta_mapping[det_key][i_ring])
            nan_mask_full = np.zeros(
                (len(eta_mapping), full_map.shape[0], full_map.shape[1])
            )
            i_p = 0
            for det_key, eta_map in eta_mapping.iteritems():
                nan_mask = ~np.isnan(eta_map[i_ring])
                nan_mask_full[i_p] = nan_mask
                full_map[nan_mask] += eta_map[i_ring][nan_mask]
                i_p += 1
            re_nan_these = np.sum(nan_mask_full, axis=0) == 0
            full_map[re_nan_these] = np.nan
            data_store.append(full_map)
        self._dataStore = data_store

        # handle omegas
        omegas_array = image_series_dict[det_key].metadata['omega']
        self._omegas = mapAngle(
            np.radians(np.average(omegas_array, axis=1)),
            np.radians(ome_period)
        )
        self._omeEdges = mapAngle(
            np.radians(np.r_[omegas_array[:, 0], omegas_array[-1, 1]]),
            np.radians(ome_period)
        )

        # !!! must avoid the case where omeEdges[0] = omeEdges[-1] for the
        # indexer to work properly
        if abs(self._omeEdges[0] - self._omeEdges[-1]) <= ct.sqrt_epsf:
            # !!! SIGNED delta ome
            del_ome = np.radians(omegas_array[0, 1] - omegas_array[0, 0])
            self._omeEdges[-1] = self._omeEdges[-2] + del_ome

        # handle etas
        # WARNING: unlinke the omegas in imageseries metadata,
        # these are in RADIANS and represent bin centers
        self._etas = etas
        self._etaEdges = np.r_[
            etas - 0.5*np.radians(eta_step),
            etas[-1] + 0.5*np.radians(eta_step)]

        self.save(npz_save_dir + analysis_id + "_maps.npz")
Пример #4
0
    def simulate_rotation_series(self,
                                 plane_data,
                                 grain_param_list,
                                 eta_ranges=[
                                     (-np.pi, np.pi),
                                 ],
                                 ome_ranges=[
                                     (-np.pi, np.pi),
                                 ],
                                 ome_period=(-np.pi, np.pi),
                                 chi=0.,
                                 tVec_s=ct.zeros_3,
                                 wavelength=None):
        """
        """

        # grab B-matrix from plane data
        bMat = plane_data.latVecOps['B']

        # reconcile wavelength
        #   * added sanity check on exclusions here; possible to
        #   * make some reflections invalid (NaN)
        if wavelength is None:
            wavelength = plane_data.wavelength
        else:
            if plane_data.wavelength != wavelength:
                plane_data.wavelength = ct.keVToAngstrom(wavelength)
        assert not np.any(np.isnan(plane_data.getTTh())),\
            "plane data exclusions incompatible with wavelength"

        # vstacked G-vector id, h, k, l
        full_hkls = xrdutil._fetch_hkls_from_planedata(plane_data)
        """ LOOP OVER GRAINS """
        valid_ids = []
        valid_hkls = []
        valid_angs = []
        valid_xys = []
        ang_pixel_size = []
        for gparm in grain_param_list:

            # make useful parameters
            rMat_c = makeRotMatOfExpMap(gparm[:3])
            tVec_c = gparm[3:6]
            vInv_s = gparm[6:]

            # All possible bragg conditions as vstacked [tth, eta, ome]
            # for each omega solution
            angList = np.vstack(
                oscillAnglesOfHKLs(
                    full_hkls[:, 1:],
                    chi,
                    rMat_c,
                    bMat,
                    wavelength,
                    vInv=vInv_s,
                ))

            # filter by eta and omega ranges
            # ??? get eta range from detector?
            allAngs, allHKLs = xrdutil._filter_hkls_eta_ome(
                full_hkls, angList, eta_ranges, ome_ranges)
            allAngs[:, 2] = mapAngle(allAngs[:, 2], ome_period)

            # find points that fall on the panel
            det_xy, rMat_s = xrdutil._project_on_detector_plane(
                allAngs, self.rmat, rMat_c, chi, self.tvec, tVec_c, tVec_s,
                self.distortion)
            xys_p, on_panel = self.clip_to_panel(det_xy)
            valid_xys.append(xys_p)

            # grab hkls and gvec ids for this panel
            valid_hkls.append(allHKLs[on_panel, 1:])
            valid_ids.append(allHKLs[on_panel, 0])

            # reflection angles (voxel centers) and pixel size in (tth, eta)
            valid_angs.append(allAngs[on_panel, :])
            ang_pixel_size.append(self.angularPixelSize(xys_p))
        return valid_ids, valid_hkls, valid_angs, valid_xys, ang_pixel_size
Пример #5
0
    def make_powder_rings(self,
                          pd,
                          merge_hkls=False,
                          delta_tth=None,
                          delta_eta=10.,
                          eta_period=None,
                          rmat_s=ct.identity_3x3,
                          tvec_s=ct.zeros_3,
                          tvec_c=ct.zeros_3,
                          full_output=False):
        """
        """
        # in case you want to give it tth angles directly
        if hasattr(pd, '__len__'):
            tth = np.array(pd).flatten()
            if delta_tth is None:
                raise RuntimeError(
                    "If supplying a 2theta list as first arg, " +
                    "must supply a delta_tth")
            sector_vertices = np.tile(
                0.5 * np.radians([
                    -delta_tth, -delta_eta, -delta_tth, delta_eta, delta_tth,
                    delta_eta, delta_tth, -delta_eta, 0.0, 0.0
                ]), (len(tth), 1))
        else:
            # Okay, we have a PlaneData object
            pd = PlaneData.makeNew(pd)  # make a copy to munge
            if delta_tth is not None:
                pd.tThWidth = np.radians(delta_tth)
            else:
                delta_tth = np.degrees(pd.tThWidth)

            # conversions, meh...
            del_eta = np.radians(delta_eta)

            # do merging if asked
            if merge_hkls:
                _, tth_ranges = pd.getMergedRanges()
                tth = np.array([0.5 * sum(i) for i in tth_ranges])
            else:
                tth_ranges = pd.getTThRanges()
                tth = pd.getTTh()
            tth_pm = tth_ranges - np.tile(tth, (2, 1)).T
            sector_vertices = np.vstack([[
                i[0], -del_eta, i[0], del_eta, i[1], del_eta, i[1], -del_eta,
                0.0, 0.0
            ] for i in tth_pm])

        # for generating rings
        if eta_period is None:
            eta_period = (-np.pi, np.pi)

        neta = int(360. / float(delta_eta))
        eta = mapAngle(
            np.radians(delta_eta *
                       (np.linspace(0, neta - 1, num=neta) + 0.5)) +
            eta_period[0], eta_period)

        angs = [
            np.vstack([i * np.ones(neta), eta,
                       np.zeros(neta)]) for i in tth
        ]

        # need xy coords and pixel sizes
        valid_ang = []
        valid_xy = []
        map_indices = []
        npp = 5  # [ll, ul, ur, lr, center]
        for i_ring in range(len(angs)):
            # expand angles to patch vertices
            these_angs = angs[i_ring].T
            patch_vertices = (np.tile(these_angs[:, :2], (1, npp)) +
                              np.tile(sector_vertices[i_ring],
                                      (neta, 1))).reshape(npp * neta, 2)

            # duplicate ome array
            ome_dupl = np.tile(these_angs[:, 2],
                               (npp, 1)).T.reshape(npp * neta, 1)

            # find vertices that all fall on the panel
            gVec_ring_l = anglesToGVec(np.hstack([patch_vertices, ome_dupl]),
                                       bHat_l=self.bvec)
            all_xy = gvecToDetectorXY(gVec_ring_l,
                                      self.rmat,
                                      rmat_s,
                                      ct.identity_3x3,
                                      self.tvec,
                                      tvec_s,
                                      tvec_c,
                                      beamVec=self.bvec)
            _, on_panel = self.clip_to_panel(all_xy)

            # all vertices must be on...
            patch_is_on = np.all(on_panel.reshape(neta, npp), axis=1)
            patch_xys = all_xy.reshape(neta, 5, 2)[patch_is_on]

            idx = np.where(patch_is_on)[0]

            valid_ang.append(these_angs[patch_is_on, :2])
            valid_xy.append(patch_xys[:, -1, :].squeeze())
            map_indices.append(idx)
            pass
        # ??? is this option necessary?
        if full_output:
            return valid_ang, valid_xy, map_indices, eta
        else:
            return valid_ang, valid_xy
def calibrate_instrument_from_sx(instr,
                                 grain_params,
                                 bmat,
                                 xyo_det,
                                 hkls_idx,
                                 param_flags=None,
                                 dparam_flags=None,
                                 ome_period=None,
                                 xtol=cnst.sqrt_epsf,
                                 ftol=cnst.sqrt_epsf,
                                 factor=10.,
                                 sim_only=False,
                                 use_robust_lsq=False):
    """
    arguments xyo_det, hkls_idx are DICTs over panels

    !!!
        distortion is still hosed...
        Currently a dict of detector keys with
        distortion[key] = [d_func, d_params, d_flags]
    """
    pnames = [
        '{:>24s}'.format('wavelength'),
        '{:>24s}'.format('chi'),
        '{:>24s}'.format('tvec_s[0]'),
        '{:>24s}'.format('tvec_s[1]'),
        '{:>24s}'.format('tvec_s[2]'),
        '{:>24s}'.format('expmap_c[0]'),
        '{:>24s}'.format('expmap_c[0]'),
        '{:>24s}'.format('expmap_c[0]'),
        '{:>24s}'.format('tvec_c[0]'),
        '{:>24s}'.format('tvec_c[1]'),
        '{:>24s}'.format('tvec_c[2]'),
    ]

    for det_key, panel in instr.detectors.iteritems():
        pnames += [
            '{:>24s}'.format('%s tilt[0]' % det_key),
            '{:>24s}'.format('%s tilt[1]' % det_key),
            '{:>24s}'.format('%s tilt[2]' % det_key),
            '{:>24s}'.format('%s tvec[0]' % det_key),
            '{:>24s}'.format('%s tvec[1]' % det_key),
            '{:>24s}'.format('%s tvec[2]' % det_key),
        ]

    # now add distortion if
    for det_key, panel in instr.detectors.iteritems():
        if panel.distortion is not None:
            for j in range(len(panel.distortion[1])):
                pnames.append('{:>24s}'.format('%s dparam[%d]' % (det_key, j)))

    # reset parameter flags for instrument as specified
    if param_flags is None:
        param_flags = instr.param_flags
    else:
        # will throw an AssertionError if wrong length
        instr.param_flags = param_flags

    det_keys = instr.detectors.keys()

    # re-map omegas if need be
    if ome_period is not None:
        for det_key in det_keys:
            xyo_det[det_key][:, 2] = xfcapi.mapAngle(xyo_det[det_key][:, 2],
                                                     ome_period)
    # grain parameters
    expmap_c = grain_params[:3]
    tvec_c = grain_params[3:6]
    vinv_s = grain_params[6:]

    plist_full = instr.calibration_params(expmap_c, tvec_c)

    dfuncs = {}
    ndparams = {}
    dparam_flags = []
    for det_key, panel in instr.detectors.iteritems():
        if panel.distortion is not None:
            dfuncs[det_key] = panel.distortion[0]
            # ititialize to all False...
            ndparams[det_key] = len(panel.distortion[1])
        else:
            dfuncs[det_key] = None
            ndparams[det_key] = 0
        dparam_flags.append(np.zeros(ndparams[det_key], dtype=bool))
    dparam_flags = np.hstack(dparam_flags)
    refine_flags = np.hstack([param_flags, dparam_flags])
    plist_fit = plist_full[refine_flags]
    fit_args = (plist_full, param_flags, dfuncs, dparam_flags, ndparams, instr,
                xyo_det, hkls_idx, bmat, vinv_s, ome_period, instr.beam_vector,
                instr.eta_vector)
    if sim_only:
        return sxcal_obj_func(plist_fit,
                              plist_full,
                              param_flags,
                              dfuncs,
                              dparam_flags,
                              ndparams,
                              instr,
                              xyo_det,
                              hkls_idx,
                              bmat,
                              vinv_s,
                              ome_period,
                              instr.beam_vector,
                              instr.eta_vector,
                              sim_only=True)
    else:
        print("Set up to refine:")
        for i in np.where(refine_flags)[0]:
            print("\t%s = %1.7e" % (pnames[i], plist_full[i]))

        # run optimization
        if use_robust_lsq:
            result = least_squares(sxcal_obj_func,
                                   plist_fit,
                                   args=fit_args,
                                   xtol=xtol,
                                   ftol=ftol,
                                   loss='soft_l1',
                                   method='trf')
            x = result.x
            resd = result.fun
            mesg = result.message
            ierr = result.status
        else:
            # do least squares problem
            x, cov_x, infodict, mesg, ierr = leastsq(sxcal_obj_func,
                                                     plist_fit,
                                                     args=fit_args,
                                                     factor=factor,
                                                     xtol=xtol,
                                                     ftol=ftol,
                                                     full_output=1)
            resd = infodict['fvec']
        if ierr not in [1, 2, 3, 4]:
            raise RuntimeError("solution not found: ierr = %d" % ierr)
        else:
            print("INFO: optimization fininshed successfully with ierr=%d" %
                  ierr)
            print("INFO: %s" % mesg)

        # ??? output message handling?
        fit_params = plist_full
        fit_params[refine_flags] = x

        # run simulation with optimized results
        sim_final = sxcal_obj_func(x,
                                   plist_full,
                                   param_flags,
                                   dfuncs,
                                   dparam_flags,
                                   ndparams,
                                   instr,
                                   xyo_det,
                                   hkls_idx,
                                   bmat,
                                   vinv_s,
                                   ome_period,
                                   instr.beam_vector,
                                   instr.eta_vector,
                                   sim_only=True)

        # ??? reset instrument here?
        instr.beam_energy = cnst.keVToAngstrom(fit_params[0])
        instr.chi = fit_params[1]
        instr.tvec = fit_params[2:5]
        ii = 11
        for det_key, panel in instr.detectors.iteritems():
            panel.tilt = fit_params[ii:ii + 3]
            panel.tvec = fit_params[ii + 3:ii + 6]
            ii += 6
            # !!! use jj to do distortion...
            if panel.distortion is not None:
                pass
            pass

        return fit_params, resd, sim_final
Пример #7
0
    def pull_spots(self, plane_data, grain_params,
                   imgser_dict,
                   tth_tol=0.25, eta_tol=1., ome_tol=1.,
                   npdiv=2, threshold=10,
                   eta_ranges=[(-np.pi, np.pi), ],
                   ome_period=(-np.pi, np.pi),
                   dirname='results', filename=None, output_format='text',
                   save_spot_list=False,
                   quiet=True, check_only=False,
                   interp='nearest'):
        """
        Exctract reflection info from a rotation series encoded as an
        OmegaImageseries object
        """

        # grain parameters
        rMat_c = makeRotMatOfExpMap(grain_params[:3])
        tVec_c = grain_params[3:6]

        # grab omega ranges from first imageseries
        #
        # WARNING: all imageseries AND all wedges within are assumed to have
        # the same omega values; put in a check that they are all the same???
        oims0 = imgser_dict[imgser_dict.keys()[0]]
        ome_ranges = [np.radians([i['ostart'], i['ostop']])
                      for i in oims0.omegawedges.wedges]

        # delta omega in DEGREES grabbed from first imageseries in the dict
        delta_ome = oims0.omega[0, 1] - oims0.omega[0, 0]

        # make omega grid for frame expansion around reference frame
        # in DEGREES
        ndiv_ome, ome_del = make_tolerance_grid(
            delta_ome, ome_tol, 1, adjust_window=True,
        )

        # generate structuring element for connected component labeling
        if ndiv_ome == 1:
            label_struct = ndimage.generate_binary_structure(2, 2)
        else:
            label_struct = ndimage.generate_binary_structure(3, 3)

        # simulate rotation series
        sim_results = self.simulate_rotation_series(
            plane_data, [grain_params, ],
            eta_ranges=eta_ranges,
            ome_ranges=ome_ranges,
            ome_period=ome_period)

        # patch vertex generator (global for instrument)
        tol_vec = 0.5*np.radians(
            [-tth_tol, -eta_tol,
             -tth_tol,  eta_tol,
             tth_tol,  eta_tol,
             tth_tol, -eta_tol])

        # prepare output if requested
        if filename is not None and output_format.lower() == 'hdf5':
            this_filename = os.path.join(dirname, filename)
            writer = io.GrainDataWriter_h5(
                os.path.join(dirname, filename),
                self.write_config(), grain_params)

        # =====================================================================
        # LOOP OVER PANELS
        # =====================================================================
        iRefl = 0
        compl = []
        output = dict.fromkeys(self.detectors)
        for detector_id in self.detectors:
            # initialize text-based output writer
            if filename is not None and output_format.lower() == 'text':
                output_dir = os.path.join(
                    dirname, detector_id
                    )
                if not os.path.exists(output_dir):
                    os.makedirs(output_dir)
                this_filename = os.path.join(
                    output_dir, filename
                )
                writer = io.PatchDataWriter(this_filename)

            # grab panel
            panel = self.detectors[detector_id]
            instr_cfg = panel.config_dict(self.chi, self.tvec)
            native_area = panel.pixel_area  # pixel ref area

            # pull out the OmegaImageSeries for this panel from input dict
            ome_imgser = imgser_dict[detector_id]

            # extract simulation results
            sim_results_p = sim_results[detector_id]
            hkl_ids = sim_results_p[0][0]
            hkls_p = sim_results_p[1][0]
            ang_centers = sim_results_p[2][0]
            xy_centers = sim_results_p[3][0]
            ang_pixel_size = sim_results_p[4][0]

            # now verify that full patch falls on detector...
            # ???: strictly necessary?
            #
            # patch vertex array from sim
            nangs = len(ang_centers)
            patch_vertices = (
                np.tile(ang_centers[:, :2], (1, 4)) +
                np.tile(tol_vec, (nangs, 1))
            ).reshape(4*nangs, 2)
            ome_dupl = np.tile(
                ang_centers[:, 2], (4, 1)
            ).T.reshape(len(patch_vertices), 1)

            # find vertices that all fall on the panel
            det_xy, _ = xrdutil._project_on_detector_plane(
                np.hstack([patch_vertices, ome_dupl]),
                panel.rmat, rMat_c, self.chi,
                panel.tvec, tVec_c, self.tvec,
                panel.distortion)
            _, on_panel = panel.clip_to_panel(det_xy, buffer_edges=True)

            # all vertices must be on...
            patch_is_on = np.all(on_panel.reshape(nangs, 4), axis=1)
            patch_xys = det_xy.reshape(nangs, 4, 2)[patch_is_on]

            # re-filter...
            hkl_ids = hkl_ids[patch_is_on]
            hkls_p = hkls_p[patch_is_on, :]
            ang_centers = ang_centers[patch_is_on, :]
            xy_centers = xy_centers[patch_is_on, :]
            ang_pixel_size = ang_pixel_size[patch_is_on, :]

            # TODO: add polygon testing right here!
            # done <JVB 06/21/16>
            if check_only:
                patch_output = []
                for i_pt, angs in enumerate(ang_centers):
                    # the evaluation omegas;
                    # expand about the central value using tol vector
                    ome_eval = np.degrees(angs[2]) + ome_del

                    # ...vectorize the omega_to_frame function to avoid loop?
                    frame_indices = [
                        ome_imgser.omega_to_frame(ome)[0] for ome in ome_eval
                    ]
                    if -1 in frame_indices:
                        if not quiet:
                            msg = """
                            window for (%d%d%d) falls outside omega range
                            """ % tuple(hkls_p[i_pt, :])
                            print(msg)
                        continue
                    else:
                        these_vertices = patch_xys[i_pt]
                        ijs = panel.cartToPixel(these_vertices)
                        ii, jj = polygon(ijs[:, 0], ijs[:, 1])
                        contains_signal = False
                        for i_frame in frame_indices:
                            contains_signal = contains_signal or np.any(
                                ome_imgser[i_frame][ii, jj] > threshold
                            )
                        compl.append(contains_signal)
                        patch_output.append((ii, jj, frame_indices))
            else:
                # make the tth,eta patches for interpolation
                patches = xrdutil.make_reflection_patches(
                    instr_cfg, ang_centers[:, :2], ang_pixel_size,
                    omega=ang_centers[:, 2],
                    tth_tol=tth_tol, eta_tol=eta_tol,
                    rMat_c=rMat_c, tVec_c=tVec_c,
                    distortion=panel.distortion,
                    npdiv=npdiv, quiet=True,
                    beamVec=self.beam_vector)

                # GRAND LOOP over reflections for this panel
                patch_output = []
                for i_pt, patch in enumerate(patches):

                    # strip relevant objects out of current patch
                    vtx_angs, vtx_xy, conn, areas, xy_eval, ijs = patch

                    prows, pcols = areas.shape
                    nrm_fac = areas/float(native_area)
                    nrm_fac = nrm_fac / np.min(nrm_fac)

                    # grab hkl info
                    hkl = hkls_p[i_pt, :]
                    hkl_id = hkl_ids[i_pt]

                    # edge arrays
                    tth_edges = vtx_angs[0][0, :]
                    delta_tth = tth_edges[1] - tth_edges[0]
                    eta_edges = vtx_angs[1][:, 0]
                    delta_eta = eta_edges[1] - eta_edges[0]

                    # need to reshape eval pts for interpolation
                    xy_eval = np.vstack([xy_eval[0].flatten(),
                                         xy_eval[1].flatten()]).T

                    # the evaluation omegas;
                    # expand about the central value using tol vector
                    ome_eval = np.degrees(ang_centers[i_pt, 2]) + ome_del

                    # ???: vectorize the omega_to_frame function to avoid loop?
                    frame_indices = [
                        ome_imgser.omega_to_frame(ome)[0] for ome in ome_eval
                    ]

                    if -1 in frame_indices:
                        if not quiet:
                            msg = """
                            window for (%d%d%d) falls outside omega range
                            """ % tuple(hkl)
                            print(msg)
                        continue
                    else:
                        # initialize spot data parameters
                        # !!! maybe change these to nan to not f**k up writer
                        peak_id = -999
                        sum_int = None
                        max_int = None
                        meas_angs = None
                        meas_xy = None

                        # quick check for intensity
                        contains_signal = False
                        patch_data_raw = []
                        for i_frame in frame_indices:
                            tmp = ome_imgser[i_frame][ijs[0], ijs[1]]
                            contains_signal = contains_signal or np.any(
                                tmp > threshold
                            )
                            patch_data_raw.append(tmp)
                            pass
                        patch_data_raw = np.stack(patch_data_raw, axis=0)
                        compl.append(contains_signal)

                        if contains_signal:
                            # initialize patch data array for intensities
                            if interp.lower() == 'bilinear':
                                patch_data = np.zeros(
                                    (len(frame_indices), prows, pcols))
                                for i, i_frame in enumerate(frame_indices):
                                    patch_data[i] = \
                                        panel.interpolate_bilinear(
                                            xy_eval,
                                            ome_imgser[i_frame],
                                            pad_with_nans=False
                                        ).reshape(prows, pcols)  # * nrm_fac
                            elif interp.lower() == 'nearest':
                                patch_data = patch_data_raw  # * nrm_fac
                            else:
                                msg = "interpolation option " + \
                                    "'%s' not understood"
                                raise(RuntimeError, msg % interp)

                            # now have interpolated patch data...
                            labels, num_peaks = ndimage.label(
                                patch_data > threshold, structure=label_struct
                            )
                            slabels = np.arange(1, num_peaks + 1)

                            if num_peaks > 0:
                                peak_id = iRefl
                                coms = np.array(
                                    ndimage.center_of_mass(
                                        patch_data,
                                        labels=labels,
                                        index=slabels
                                    )
                                )
                                if num_peaks > 1:
                                    center = np.r_[patch_data.shape]*0.5
                                    center_t = np.tile(center, (num_peaks, 1))
                                    com_diff = coms - center_t
                                    closest_peak_idx = np.argmin(
                                        np.sum(com_diff**2, axis=1)
                                    )
                                else:
                                    closest_peak_idx = 0
                                    pass  # end multipeak conditional
                                coms = coms[closest_peak_idx]
                                # meas_omes = \
                                #     ome_edges[0] + (0.5 + coms[0])*delta_ome
                                meas_omes = \
                                    ome_eval[0] + coms[0]*delta_ome
                                meas_angs = np.hstack(
                                    [tth_edges[0] + (0.5 + coms[2])*delta_tth,
                                     eta_edges[0] + (0.5 + coms[1])*delta_eta,
                                     mapAngle(
                                         np.radians(meas_omes), ome_period
                                         )
                                     ]
                                )

                                # intensities
                                #   - summed is 'integrated' over interpolated
                                #     data
                                #   - max is max of raw input data
                                sum_int = np.sum(
                                    patch_data[
                                        labels == slabels[closest_peak_idx]
                                    ]
                                )
                                max_int = np.max(
                                    patch_data_raw[
                                        labels == slabels[closest_peak_idx]
                                    ]
                                )
                                # ???: Should this only use labeled pixels?
                                # Those are segmented from interpolated data,
                                # not raw; likely ok in most cases.

                                # need MEASURED xy coords
                                gvec_c = anglesToGVec(
                                    meas_angs,
                                    chi=self.chi,
                                    rMat_c=rMat_c,
                                    bHat_l=self.beam_vector)
                                rMat_s = makeOscillRotMat(
                                    [self.chi, meas_angs[2]]
                                )
                                meas_xy = gvecToDetectorXY(
                                    gvec_c,
                                    panel.rmat, rMat_s, rMat_c,
                                    panel.tvec, self.tvec, tVec_c,
                                    beamVec=self.beam_vector)
                                if panel.distortion is not None:
                                    # FIXME: distortion handling
                                    meas_xy = panel.distortion[0](
                                        np.atleast_2d(meas_xy),
                                        panel.distortion[1],
                                        invert=True).flatten()
                                    pass
                                # FIXME: why is this suddenly necessary???
                                meas_xy = meas_xy.squeeze()
                                pass  # end num_peaks > 0
                        else:
                            patch_data = patch_data_raw
                            pass  # end contains_signal
                        # write output
                        if filename is not None:
                            if output_format.lower() == 'text':
                                writer.dump_patch(
                                    peak_id, hkl_id, hkl, sum_int, max_int,
                                    ang_centers[i_pt], meas_angs,
                                    xy_centers[i_pt], meas_xy)
                            elif output_format.lower() == 'hdf5':
                                xyc_arr = xy_eval.reshape(
                                    prows, pcols, 2
                                ).transpose(2, 0, 1)
                                writer.dump_patch(
                                    detector_id, iRefl, peak_id, hkl_id, hkl,
                                    tth_edges, eta_edges, np.radians(ome_eval),
                                    xyc_arr, ijs, frame_indices, patch_data,
                                    ang_centers[i_pt], xy_centers[i_pt],
                                    meas_angs, meas_xy)
                            pass  # end conditional on write output
                        pass  # end conditional on check only
                        patch_output.append([
                                peak_id, hkl_id, hkl, sum_int, max_int,
                                ang_centers[i_pt], meas_angs, meas_xy,
                                ])
                        iRefl += 1
                    pass  # end patch conditional
                pass  # end patch loop
            output[detector_id] = patch_output
            if filename is not None and output_format.lower() == 'text':
                writer.close()
            pass  # end detector loop
        if filename is not None and output_format.lower() == 'hdf5':
            writer.close()
        return compl, output
Пример #8
0
    def simulate_rotation_series(self, plane_data, grain_param_list,
                                 eta_ranges=[(-np.pi, np.pi), ],
                                 ome_ranges=[(-np.pi, np.pi), ],
                                 ome_period=(-np.pi, np.pi),
                                 chi=0., tVec_s=ct.zeros_3,
                                 wavelength=None):
        """
        """

        # grab B-matrix from plane data
        bMat = plane_data.latVecOps['B']

        # reconcile wavelength
        #   * added sanity check on exclusions here; possible to
        #   * make some reflections invalid (NaN)
        if wavelength is None:
            wavelength = plane_data.wavelength
        else:
            if plane_data.wavelength != wavelength:
                plane_data.wavelength = ct.keVToAngstrom(wavelength)
        assert not np.any(np.isnan(plane_data.getTTh())),\
            "plane data exclusions incompatible with wavelength"

        # vstacked G-vector id, h, k, l
        full_hkls = xrdutil._fetch_hkls_from_planedata(plane_data)

        """ LOOP OVER GRAINS """
        valid_ids = []
        valid_hkls = []
        valid_angs = []
        valid_xys = []
        ang_pixel_size = []
        for gparm in grain_param_list:

            # make useful parameters
            rMat_c = makeRotMatOfExpMap(gparm[:3])
            tVec_c = gparm[3:6]
            vInv_s = gparm[6:]

            # All possible bragg conditions as vstacked [tth, eta, ome]
            # for each omega solution
            angList = np.vstack(
                oscillAnglesOfHKLs(
                    full_hkls[:, 1:], chi,
                    rMat_c, bMat, wavelength,
                    vInv=vInv_s,
                    )
                )

            # filter by eta and omega ranges
            # ??? get eta range from detector?
            allAngs, allHKLs = xrdutil._filter_hkls_eta_ome(
                full_hkls, angList, eta_ranges, ome_ranges
                )
            allAngs[:, 2] = mapAngle(allAngs[:, 2], ome_period)

            # find points that fall on the panel
            det_xy, rMat_s = xrdutil._project_on_detector_plane(
                allAngs,
                self.rmat, rMat_c, chi,
                self.tvec, tVec_c, tVec_s,
                self.distortion)
            xys_p, on_panel = self.clip_to_panel(det_xy)
            valid_xys.append(xys_p)

            # grab hkls and gvec ids for this panel
            valid_hkls.append(allHKLs[on_panel, 1:])
            valid_ids.append(allHKLs[on_panel, 0])

            # reflection angles (voxel centers) and pixel size in (tth, eta)
            valid_angs.append(allAngs[on_panel, :])
            ang_pixel_size.append(self.angularPixelSize(xys_p))
        return valid_ids, valid_hkls, valid_angs, valid_xys, ang_pixel_size
Пример #9
0
    def make_powder_rings(
            self, pd, merge_hkls=False, delta_tth=None,
            delta_eta=10., eta_period=None,
            rmat_s=ct.identity_3x3,  tvec_s=ct.zeros_3,
            tvec_c=ct.zeros_3, full_output=False):
        """
        """
        # in case you want to give it tth angles directly
        if hasattr(pd, '__len__'):
            tth = np.array(pd).flatten()
            if delta_tth is None:
                raise RuntimeError(
                    "If supplying a 2theta list as first arg, "
                    + "must supply a delta_tth")
            sector_vertices = np.tile(
                0.5*np.radians([-delta_tth, -delta_eta,
                                -delta_tth, delta_eta,
                                delta_tth, delta_eta,
                                delta_tth, -delta_eta,
                                0.0, 0.0]), (len(tth), 1)
                )
        else:
            # Okay, we have a PlaneData object
            pd = PlaneData.makeNew(pd)    # make a copy to munge
            if delta_tth is not None:
                pd.tThWidth = np.radians(delta_tth)
            else:
                delta_tth = np.degrees(pd.tThWidth)

            # conversions, meh...
            del_eta = np.radians(delta_eta)

            # do merging if asked
            if merge_hkls:
                _, tth_ranges = pd.getMergedRanges()
                tth = np.array([0.5*sum(i) for i in tth_ranges])
            else:
                tth_ranges = pd.getTThRanges()
                tth = pd.getTTh()
            tth_pm = tth_ranges - np.tile(tth, (2, 1)).T
            sector_vertices = np.vstack(
                [[i[0], -del_eta,
                  i[0], del_eta,
                  i[1], del_eta,
                  i[1], -del_eta,
                  0.0, 0.0]
                 for i in tth_pm])

        # for generating rings
        if eta_period is None:
            eta_period = (-np.pi, np.pi)

        neta = int(360./float(delta_eta))
        eta = mapAngle(
            np.radians(delta_eta*(np.linspace(0, neta - 1, num=neta) + 0.5)) +
            eta_period[0], eta_period
        )

        angs = [np.vstack([i*np.ones(neta), eta, np.zeros(neta)]) for i in tth]

        # need xy coords and pixel sizes
        valid_ang = []
        valid_xy = []
        map_indices = []
        npp = 5  # [ll, ul, ur, lr, center]
        for i_ring in range(len(angs)):
            # expand angles to patch vertices
            these_angs = angs[i_ring].T
            patch_vertices = (
                np.tile(these_angs[:, :2], (1, npp))
                + np.tile(sector_vertices[i_ring], (neta, 1))
            ).reshape(npp*neta, 2)

            # duplicate ome array
            ome_dupl = np.tile(
                these_angs[:, 2], (npp, 1)
            ).T.reshape(npp*neta, 1)

            # find vertices that all fall on the panel
            gVec_ring_l = anglesToGVec(
                np.hstack([patch_vertices, ome_dupl]),
                bHat_l=self.bvec)
            all_xy = gvecToDetectorXY(
                gVec_ring_l,
                self.rmat, rmat_s, ct.identity_3x3,
                self.tvec, tvec_s, tvec_c,
                beamVec=self.bvec)
            _, on_panel = self.clip_to_panel(all_xy)

            # all vertices must be on...
            patch_is_on = np.all(on_panel.reshape(neta, npp), axis=1)
            patch_xys = all_xy.reshape(neta, 5, 2)[patch_is_on]

            idx = np.where(patch_is_on)[0]

            valid_ang.append(these_angs[patch_is_on, :2])
            valid_xy.append(patch_xys[:, -1, :].squeeze())
            map_indices.append(idx)
            pass
        # ??? is this option necessary?
        if full_output:
            return valid_ang, valid_xy, map_indices, eta
        else:
            return valid_ang, valid_xy
Пример #10
0
    def pull_spots(self,
                   plane_data,
                   grain_params,
                   imgser_dict,
                   tth_tol=0.25,
                   eta_tol=1.,
                   ome_tol=1.,
                   npdiv=2,
                   threshold=10,
                   eta_ranges=[
                       (-np.pi, np.pi),
                   ],
                   ome_period=(-np.pi, np.pi),
                   dirname='results',
                   filename=None,
                   output_format='text',
                   save_spot_list=False,
                   quiet=True,
                   check_only=False,
                   interp='nearest'):
        """
        Exctract reflection info from a rotation series encoded as an
        OmegaImageseries object
        """

        # grain parameters
        rMat_c = makeRotMatOfExpMap(grain_params[:3])
        tVec_c = grain_params[3:6]

        # grab omega ranges from first imageseries
        #
        # WARNING: all imageseries AND all wedges within are assumed to have
        # the same omega values; put in a check that they are all the same???
        oims0 = imgser_dict[imgser_dict.keys()[0]]
        ome_ranges = [
            np.radians([i['ostart'], i['ostop']])
            for i in oims0.omegawedges.wedges
        ]

        # delta omega in DEGREES grabbed from first imageseries in the dict
        delta_ome = oims0.omega[0, 1] - oims0.omega[0, 0]

        # make omega grid for frame expansion around reference frame
        # in DEGREES
        ndiv_ome, ome_del = make_tolerance_grid(
            delta_ome,
            ome_tol,
            1,
            adjust_window=True,
        )

        # generate structuring element for connected component labeling
        if ndiv_ome == 1:
            label_struct = ndimage.generate_binary_structure(2, 2)
        else:
            label_struct = ndimage.generate_binary_structure(3, 3)

        # simulate rotation series
        sim_results = self.simulate_rotation_series(plane_data, [
            grain_params,
        ],
                                                    eta_ranges=eta_ranges,
                                                    ome_ranges=ome_ranges,
                                                    ome_period=ome_period)

        # patch vertex generator (global for instrument)
        tol_vec = 0.5 * np.radians([
            -tth_tol, -eta_tol, -tth_tol, eta_tol, tth_tol, eta_tol, tth_tol,
            -eta_tol
        ])

        # prepare output if requested
        if filename is not None and output_format.lower() == 'hdf5':
            this_filename = os.path.join(dirname, filename)
            writer = io.GrainDataWriter_h5(os.path.join(dirname, filename),
                                           self.write_config(), grain_params)

        # =====================================================================
        # LOOP OVER PANELS
        # =====================================================================
        iRefl = 0
        compl = []
        output = dict.fromkeys(self.detectors)
        for detector_id in self.detectors:
            # initialize text-based output writer
            if filename is not None and output_format.lower() == 'text':
                output_dir = os.path.join(dirname, detector_id)
                if not os.path.exists(output_dir):
                    os.makedirs(output_dir)
                this_filename = os.path.join(output_dir, filename)
                writer = io.PatchDataWriter(this_filename)

            # grab panel
            panel = self.detectors[detector_id]
            instr_cfg = panel.config_dict(self.chi, self.tvec)
            native_area = panel.pixel_area  # pixel ref area

            # pull out the OmegaImageSeries for this panel from input dict
            ome_imgser = imgser_dict[detector_id]

            # extract simulation results
            sim_results_p = sim_results[detector_id]
            hkl_ids = sim_results_p[0][0]
            hkls_p = sim_results_p[1][0]
            ang_centers = sim_results_p[2][0]
            xy_centers = sim_results_p[3][0]
            ang_pixel_size = sim_results_p[4][0]

            # now verify that full patch falls on detector...
            # ???: strictly necessary?
            #
            # patch vertex array from sim
            nangs = len(ang_centers)
            patch_vertices = (np.tile(ang_centers[:, :2],
                                      (1, 4)) + np.tile(tol_vec,
                                                        (nangs, 1))).reshape(
                                                            4 * nangs, 2)
            ome_dupl = np.tile(ang_centers[:, 2],
                               (4, 1)).T.reshape(len(patch_vertices), 1)

            # find vertices that all fall on the panel
            det_xy, _ = xrdutil._project_on_detector_plane(
                np.hstack([patch_vertices, ome_dupl]), panel.rmat, rMat_c,
                self.chi, panel.tvec, tVec_c, self.tvec, panel.distortion)
            _, on_panel = panel.clip_to_panel(det_xy, buffer_edges=True)

            # all vertices must be on...
            patch_is_on = np.all(on_panel.reshape(nangs, 4), axis=1)
            patch_xys = det_xy.reshape(nangs, 4, 2)[patch_is_on]

            # re-filter...
            hkl_ids = hkl_ids[patch_is_on]
            hkls_p = hkls_p[patch_is_on, :]
            ang_centers = ang_centers[patch_is_on, :]
            xy_centers = xy_centers[patch_is_on, :]
            ang_pixel_size = ang_pixel_size[patch_is_on, :]

            # TODO: add polygon testing right here!
            # done <JVB 06/21/16>
            if check_only:
                patch_output = []
                for i_pt, angs in enumerate(ang_centers):
                    # the evaluation omegas;
                    # expand about the central value using tol vector
                    ome_eval = np.degrees(angs[2]) + ome_del

                    # ...vectorize the omega_to_frame function to avoid loop?
                    frame_indices = [
                        ome_imgser.omega_to_frame(ome)[0] for ome in ome_eval
                    ]
                    if -1 in frame_indices:
                        if not quiet:
                            msg = """
                            window for (%d%d%d) falls outside omega range
                            """ % tuple(hkls_p[i_pt, :])
                            print(msg)
                        continue
                    else:
                        these_vertices = patch_xys[i_pt]
                        ijs = panel.cartToPixel(these_vertices)
                        ii, jj = polygon(ijs[:, 0], ijs[:, 1])
                        contains_signal = False
                        for i_frame in frame_indices:
                            contains_signal = contains_signal or np.any(
                                ome_imgser[i_frame][ii, jj] > threshold)
                        compl.append(contains_signal)
                        patch_output.append((ii, jj, frame_indices))
            else:
                # make the tth,eta patches for interpolation
                patches = xrdutil.make_reflection_patches(
                    instr_cfg,
                    ang_centers[:, :2],
                    ang_pixel_size,
                    omega=ang_centers[:, 2],
                    tth_tol=tth_tol,
                    eta_tol=eta_tol,
                    rMat_c=rMat_c,
                    tVec_c=tVec_c,
                    distortion=panel.distortion,
                    npdiv=npdiv,
                    quiet=True,
                    beamVec=self.beam_vector)

                # GRAND LOOP over reflections for this panel
                patch_output = []
                for i_pt, patch in enumerate(patches):

                    # strip relevant objects out of current patch
                    vtx_angs, vtx_xy, conn, areas, xy_eval, ijs = patch

                    prows, pcols = areas.shape
                    nrm_fac = areas / float(native_area)
                    nrm_fac = nrm_fac / np.min(nrm_fac)

                    # grab hkl info
                    hkl = hkls_p[i_pt, :]
                    hkl_id = hkl_ids[i_pt]

                    # edge arrays
                    tth_edges = vtx_angs[0][0, :]
                    delta_tth = tth_edges[1] - tth_edges[0]
                    eta_edges = vtx_angs[1][:, 0]
                    delta_eta = eta_edges[1] - eta_edges[0]

                    # need to reshape eval pts for interpolation
                    xy_eval = np.vstack(
                        [xy_eval[0].flatten(), xy_eval[1].flatten()]).T

                    # the evaluation omegas;
                    # expand about the central value using tol vector
                    ome_eval = np.degrees(ang_centers[i_pt, 2]) + ome_del

                    # ???: vectorize the omega_to_frame function to avoid loop?
                    frame_indices = [
                        ome_imgser.omega_to_frame(ome)[0] for ome in ome_eval
                    ]

                    if -1 in frame_indices:
                        if not quiet:
                            msg = """
                            window for (%d%d%d) falls outside omega range
                            """ % tuple(hkl)
                            print(msg)
                        continue
                    else:
                        # initialize spot data parameters
                        # !!! maybe change these to nan to not f**k up writer
                        peak_id = -999
                        sum_int = None
                        max_int = None
                        meas_angs = None
                        meas_xy = None

                        # quick check for intensity
                        contains_signal = False
                        patch_data_raw = []
                        for i_frame in frame_indices:
                            tmp = ome_imgser[i_frame][ijs[0], ijs[1]]
                            contains_signal = contains_signal or np.any(
                                tmp > threshold)
                            patch_data_raw.append(tmp)
                            pass
                        patch_data_raw = np.stack(patch_data_raw, axis=0)
                        compl.append(contains_signal)

                        if contains_signal:
                            # initialize patch data array for intensities
                            if interp.lower() == 'bilinear':
                                patch_data = np.zeros(
                                    (len(frame_indices), prows, pcols))
                                for i, i_frame in enumerate(frame_indices):
                                    patch_data[i] = \
                                        panel.interpolate_bilinear(
                                            xy_eval,
                                            ome_imgser[i_frame],
                                            pad_with_nans=False
                                        ).reshape(prows, pcols)  # * nrm_fac
                            elif interp.lower() == 'nearest':
                                patch_data = patch_data_raw  # * nrm_fac
                            else:
                                msg = "interpolation option " + \
                                    "'%s' not understood"
                                raise (RuntimeError, msg % interp)

                            # now have interpolated patch data...
                            labels, num_peaks = ndimage.label(
                                patch_data > threshold, structure=label_struct)
                            slabels = np.arange(1, num_peaks + 1)

                            if num_peaks > 0:
                                peak_id = iRefl
                                coms = np.array(
                                    ndimage.center_of_mass(patch_data,
                                                           labels=labels,
                                                           index=slabels))
                                if num_peaks > 1:
                                    center = np.r_[patch_data.shape] * 0.5
                                    center_t = np.tile(center, (num_peaks, 1))
                                    com_diff = coms - center_t
                                    closest_peak_idx = np.argmin(
                                        np.sum(com_diff**2, axis=1))
                                else:
                                    closest_peak_idx = 0
                                    pass  # end multipeak conditional
                                coms = coms[closest_peak_idx]
                                # meas_omes = \
                                #     ome_edges[0] + (0.5 + coms[0])*delta_ome
                                meas_omes = \
                                    ome_eval[0] + coms[0]*delta_ome
                                meas_angs = np.hstack([
                                    tth_edges[0] + (0.5 + coms[2]) * delta_tth,
                                    eta_edges[0] + (0.5 + coms[1]) * delta_eta,
                                    mapAngle(np.radians(meas_omes), ome_period)
                                ])

                                # intensities
                                #   - summed is 'integrated' over interpolated
                                #     data
                                #   - max is max of raw input data
                                sum_int = np.sum(patch_data[
                                    labels == slabels[closest_peak_idx]])
                                max_int = np.max(patch_data_raw[
                                    labels == slabels[closest_peak_idx]])
                                # ???: Should this only use labeled pixels?
                                # Those are segmented from interpolated data,
                                # not raw; likely ok in most cases.

                                # need MEASURED xy coords
                                gvec_c = anglesToGVec(meas_angs,
                                                      chi=self.chi,
                                                      rMat_c=rMat_c,
                                                      bHat_l=self.beam_vector)
                                rMat_s = makeOscillRotMat(
                                    [self.chi, meas_angs[2]])
                                meas_xy = gvecToDetectorXY(
                                    gvec_c,
                                    panel.rmat,
                                    rMat_s,
                                    rMat_c,
                                    panel.tvec,
                                    self.tvec,
                                    tVec_c,
                                    beamVec=self.beam_vector)
                                if panel.distortion is not None:
                                    # FIXME: distortion handling
                                    meas_xy = panel.distortion[0](
                                        np.atleast_2d(meas_xy),
                                        panel.distortion[1],
                                        invert=True).flatten()
                                    pass
                                # FIXME: why is this suddenly necessary???
                                meas_xy = meas_xy.squeeze()
                                pass  # end num_peaks > 0
                        else:
                            patch_data = patch_data_raw
                            pass  # end contains_signal
                        # write output
                        if filename is not None:
                            if output_format.lower() == 'text':
                                writer.dump_patch(peak_id, hkl_id, hkl,
                                                  sum_int, max_int,
                                                  ang_centers[i_pt], meas_angs,
                                                  xy_centers[i_pt], meas_xy)
                            elif output_format.lower() == 'hdf5':
                                xyc_arr = xy_eval.reshape(prows, pcols,
                                                          2).transpose(
                                                              2, 0, 1)
                                writer.dump_patch(
                                    detector_id, iRefl, peak_id, hkl_id,
                                    hkl, tth_edges, eta_edges,
                                    np.radians(ome_eval), xyc_arr, ijs,
                                    frame_indices, patch_data,
                                    ang_centers[i_pt], xy_centers[i_pt],
                                    meas_angs, meas_xy)
                            pass  # end conditional on write output
                        pass  # end conditional on check only
                        patch_output.append([
                            peak_id,
                            hkl_id,
                            hkl,
                            sum_int,
                            max_int,
                            ang_centers[i_pt],
                            meas_angs,
                            meas_xy,
                        ])
                        iRefl += 1
                    pass  # end patch conditional
                pass  # end patch loop
            output[detector_id] = patch_output
            if filename is not None and output_format.lower() == 'text':
                writer.close()
            pass  # end detector loop
        if filename is not None and output_format.lower() == 'hdf5':
            writer.close()
        return compl, output