Exemplo n.º 1
0
    def plot_points(pts, img, name='', s=10, c='r', cmap=None,
                    vmin=None, vmax=None, cbar=False):
        global snapshot_num, imprefix
        fig, ax = plt.subplots(figsize=(8, 8))
        # dpi = 300 gives 2.675 pixels for each image pixel, or 112.14 real
        # pixels per inch. This may be unreliable, but assume that many image
        # pixels per inch, and use integer multiples of that for dpi
        # PPI = 112.14 if figsize (8, 6)
        PPI = 84.638  # if figsize (8, 8)
        dpi = 4*PPI
        axim = ax.imshow(img, cmap=cmap, vmin=vmin, vmax=vmax,
                         interpolation='nearest')
        if cbar:
            fig.tight_layout()
            cb_height = 4
            cax = fig.add_axes(np.array([10, 99-cb_height, 80, cb_height])/100)
            fig.colorbar(axim, cax=cax, orientation='horizontal')
        xl, yl = ax.get_xlim(), ax.get_ylim()
        s = abs(s)
        helpy.draw_circles(helpy.consecutive_fields_view(pts, 'xy')[:, ::-1], s,
                           ax, lw=max(s/10, .5), color=c, fill=False, zorder=2)
        if s > 3:
            ax.scatter(pts['y'], pts['x'], s, c, '+')
        ax.set_xlim(xl)
        ax.set_ylim(yl)
        ax.set_xticks([])
        ax.set_yticks([])

        if args.save:
            savename = '{}_{:02d}_{}.png'.format(imprefix, snapshot_num, name)
            fig.savefig(savename, dpi=dpi, bbox_inches='tight', pad_inches=0)
            snapshot_num += 1
            plt.close(fig)
Exemplo n.º 2
0
def vv_autocorr(vs, normalize=False):
    normalize = normalize and 1
    fields = helpy.vel_dtype.names
    vvs = [corr.autocorr(helpy.consecutive_fields_view(tv, fields),
                         norm=normalize, cumulant=True)
           for pvs in vs.itervalues() for tv in pvs.itervalues()]
    vvs, vv, dvv = helpy.avg_uneven(vvs, weight=True)
    return [np.array(a, order='C').astype('f4').view(helpy.vel_dtype).squeeze()
            for a in vvs, vv, dvv]
 def convol_track_config(self, pdata, odata, startframe):
     pfsets = helpy.load_framesets(pdata)
     pftrees = {f: KDTree(helpy.consecutive_fields_view(pfset, 'xy'),
                          leafsize=32) for f, pfset in pfsets.iteritems()}
     trackids = tracks.find_tracks(pdata, maxdist= self.max_dist, giveup = 10, n = 0, stub = 20, \
                                   pftrees = pftrees, pfsets = pfsets, startframe = startframe)
     trackids = tracks.remove_duplicates(trackids, data = pdata)
     return_data = helpy.initialize_tdata(pdata, trackids, odata)
     return_data = helpy.add_self_view(return_data, ('x','y'),'xy')
     return return_data
Exemplo n.º 4
0
def vv_autocorr(vs, normalize=False):
    normalize = normalize and 1
    fields = helpy.vel_dtype.names
    vvs = [
        corr.autocorr(helpy.consecutive_fields_view(tv, fields),
                      norm=normalize,
                      cumulant=True) for pvs in vs.itervalues()
        for tv in pvs.itervalues()
    ]
    vvs, vv, dvv = helpy.avg_uneven(vvs, weight=True)
    return [
        np.array(a, order='C').astype('f4').view(helpy.vel_dtype).squeeze()
        for a in vvs, vv, dvv
    ]
Exemplo n.º 5
0
    def plot_points(pts,
                    img,
                    name='',
                    s=10,
                    c='r',
                    cmap=None,
                    vmin=None,
                    vmax=None,
                    cbar=False):
        global snapshot_num, imprefix
        fig, ax = plt.subplots(figsize=(8, 8))
        # dpi = 300 gives 2.675 pixels for each image pixel, or 112.14 real
        # pixels per inch. This may be unreliable, but assume that many image
        # pixels per inch, and use integer multiples of that for dpi
        # PPI = 112.14 if figsize (8, 6)
        PPI = 84.638  # if figsize (8, 8)
        dpi = 4 * PPI
        axim = ax.imshow(img,
                         cmap=cmap,
                         vmin=vmin,
                         vmax=vmax,
                         interpolation='nearest')
        if cbar:
            fig.tight_layout()
            cb_height = 4
            cax = fig.add_axes(
                np.array([10, 99 - cb_height, 80, cb_height]) / 100)
            fig.colorbar(axim, cax=cax, orientation='horizontal')
        xl, yl = ax.get_xlim(), ax.get_ylim()
        s = abs(s)
        helpy.draw_circles(helpy.consecutive_fields_view(pts, 'xy')[:, ::-1],
                           s,
                           ax,
                           lw=max(s / 10, .5),
                           color=c,
                           fill=False,
                           zorder=2)
        if s > 3:
            ax.scatter(pts['y'], pts['x'], s, c, '+')
        ax.set_xlim(xl)
        ax.set_ylim(yl)
        ax.set_xticks([])
        ax.set_yticks([])

        if args.save:
            savename = '{}_{:02d}_{}.png'.format(imprefix, snapshot_num, name)
            fig.savefig(savename, dpi=dpi, bbox_inches='tight', pad_inches=0)
            snapshot_num += 1
            plt.close(fig)
Exemplo n.º 6
0
def trackmsd(trackset, dt0, dtau):
    """ finds the mean squared displacement as a function of tau,
        averaged over t0, for one track (particle)

        parameters
        ----------
        trackset : a subset of the data for a given track
        dt0 : spacing stepsize for values of t0, gives the number of starting
            points averaged over in `t0avg`
        dtau : spacing stepsize for values of tau, gives the spacing of the
            points in time at which the msd is evaluated

        For dt0, dtau:  Small values will take longer to calculate without
            adding to the statistics. Large values calculate faster but give
            worse statistics. For the special case dt0 = dtau = 1, a
            correlation is used for a signicant speedup

        returns
        -------
        a list of tuples (tau, msd(tau)) the value of tau and the mean squared
        displacement for a single track at that value of tau

    """
    if dt0 == dtau == 1:
        xy = helpy.consecutive_fields_view(trackset, 'xy')
        return corr.msd(xy, ret_taus=True)

    trackbegin, trackend = trackset['f'][[0,-1]]
    tracklen = trackend - trackbegin + 1
    if verbose:
        print "length {} from {} to {}".format(tracklen, trackbegin, trackend)
    if isinstance(dtau, float):
        taus = helpy.farange(dt0, tracklen, dtau)
    elif isinstance(dtau, int):
        taus = xrange(dtau, tracklen, dtau)

    tmsd = []
    for tau in taus:
        avg = t0avg(trackset, tracklen, tau)
        if avg > 0 and not np.isnan(avg):
            tmsd.append([tau,avg[0]])
    if verbose:
        print "\t...actually", len(tmsd)
    return tmsd
Exemplo n.º 7
0
def fill_gaps(tracksets, max_gap=5, interp=['xy','o'], inplace=True, verbose=False):
    if not inplace:
        tracksets = {t: s.copy() for t,s in tracksets.iteritems()}
    if verbose:
        print 'filling gaps with nans'
        if interp:
            print 'and interpolating nans in', ', '.join(interp)
    for t, tset in tracksets.items():
        if verbose: print "\ttrack {:4d}:".format(t),
        fs = tset['f']
        gaps = np.diff(fs) - 1
        mx = gaps.max()
        if not mx:
            if verbose: print "not any gaps"
            if 'o' in interp:
                interp_nans(tset['o'], tset['f'], inplace=True)
            continue
        elif mx > max_gap:
            if verbose:
                print "dropped, gap too big: {} > {}".format(mx, max_gap)
            tracksets.pop(t)
            continue
        gapi = gaps.nonzero()[0]
        gaps = gaps[gapi]
        gapi = np.repeat(gapi, gaps)
        missing = np.full(len(gapi), np.nan, tset.dtype)
        if verbose:
            print ("missing {:3} frames in {:2} gaps (biggest {})"
                    ).format(len(gapi), len(gaps), mx)
        missing['f'] = np.concatenate(map(range, gaps)) + fs[gapi] + 1
        missing['t'] = t
        tset = np.insert(tset, gapi+1, missing)
        if interp:
            for field in interp:
                view = helpy.consecutive_fields_view(tset, field, careful=False)
                interp_nans(view, inplace=True)
        tracksets[t] = tset
    return tracksets
Exemplo n.º 8
0
def animate_detection(imstack, fsets, fcsets, fosets=None, rc=0, side=15, verbose=False):

    from matplotlib.patches import Circle

    def advance(event):
        key = event.key
        if verbose:
            print 'pressed', key, 'next frame:',
        global f_display
        if key=='left':
            if f_display>=1:
                f_display -= 1
        elif key=='right':
            f_display += 1
        else:
            plt.close()
            f_display = -1
        if verbose:
            print f_display
            sys.stdout.flush()

    plt_text = np.vectorize(plt.text)

    def draw_circles(ax, centers, r, *args, **kwargs):
        patches = [Circle(cent, r, *args, **kwargs) for cent in centers]
        map(ax.add_patch, patches)
        ax.figure.canvas.draw()
        return patches

    if side==1:
        side = 15
    txtoff = max(rc, side, 10)

    fig = plt.figure(figsize=(12, 12))
    p = plt.imshow(imstack[0], cmap='gray')
    h, w = imstack[0].shape
    ax = p.axes
    global f_display
    f_display = repeat = f_old = 0
    lengths = map(len, [imstack, fsets, fcsets])
    f_max = min(lengths)
    assert f_max, 'Lengths imstack: {}, fsets: {}, fcsets: {}'.format(*lengths)
    while 0 <= f_display < f_max:
        if repeat > 5:
            if verbose:
                print 'stuck on frame', f_display
            break
        f_display %= f_max
        if f_display==f_old:
            repeat += 1
        else:
            repeat = 0
        f_old = f_display
        if verbose:
            print 'starting loop with f_display =', f_display
        xyo = helpy.consecutive_fields_view(fsets[f_display], 'xyo', False)
        xyc = helpy.consecutive_fields_view(fcsets[f_display], 'xy', False)
        x, y, o = xyo.T
        omask = np.isfinite(o)
        xo, yo, oo = xyo[omask].T

        p.set_data(imstack[f_display])
        remove = []
        if rc > 0:
            patches = draw_circles(ax, xyo[:, 1::-1], rc,
                                color='g', fill=False, zorder=.5)
            remove.extend(patches)
        q = plt.quiver(yo, xo, np.sin(oo), np.cos(oo), angles='xy',
                       units='xy', width=side/8, scale_units='xy', scale=1/side)
        ps = plt.scatter(y, x, c='r')#c=np.where(omask, 'r', 'b'))
        cs = plt.scatter(xyc[:,1], xyc[:,0], c='g', s=8)
        if fosets is not None:
            oc = helpy.quick_field_view(fosets[f_display], 'corner').reshape(-1, 2)
            ocs = plt.scatter(oc[:,1], oc[:,0], c='orange', s=8)
            remove.append(ocs)
        remove.extend([q, ps, cs])

        tstr = fsets[f_display]['t'].astype('S')
        txt = plt_text(y+txtoff, x+txtoff, tstr, color='r')
        remove.extend(txt)

        plt.xlim(0, w)
        plt.ylim(0, h)
        plt.title("frame {}\n{} orientations / {} particles detected".format(
                    f_display, np.count_nonzero(omask), len(o)))
        fig.canvas.draw()

        plt.waitforbuttonpress()
        fig.canvas.mpl_connect('key_press_event', advance)
        for rem in remove:
            rem.remove()
        if verbose:
            print 'ending frame', f_display
            sys.stdout.flush()
    if verbose:
        print 'loop broken'
    def phase_detection(self):
        self.solids = []
        self.detect = []
        self.liquid_density = list()
        self.solid_density = list()
        self.solid_fraction = list()
        self.liquid_fraction = list()
        self.solid_molecular_order = list()
        self.liquid_molecular_order = list()
        self.solid_local_bond4 = list()
        self.solid_local_bond6 = list()
        self.solid_local_mole4 = list()
        self.solid_polar = list()
        self.solid_polar_fraction = list()
        self.radi_polar = list()
        self.radi_polar_fraction = list()
        self.xys = dict()
        self.final_id = dict()
        self.vor_area = list()
        self.vornoi_history = list()
        self.inter_boundary_number = list()
        #self.liquid_vor_area = np.empty(0)
        plot_number = 0
        sorted_keys = sorted(self.config_vdata.keys())
        for startframe in sorted_keys:                
            #pids = v_data.keys()
            v_data = self.config_vdata[startframe]
            qualify_id, order_para_mean, vr_mean, vomega_list = self.single_config_detect(v_data)
            self.detect.append(len(qualify_id))
            qualify_id_set = set(qualify_id)            
            order_mask, vr_mask, vomega_mask = self.solid_criteria(order_para_mean, vr_mean, vomega_list)
            
            fdata = helpy.load_framesets(v_data)              
                
            
            # find the frame where contains all the qualified particles
            count = 0
            while (count < 49) & (not set(fdata[startframe+count]['t']).issuperset(qualify_id_set)):
                count+=1
                if count == 49:
                    break
            startframe += count
            # for the idtentified frame, make TRUE if t in qualified_id
            fdata_track = fdata[startframe]['t']
            track_mask = list()
            for t in fdata_track:
                track_mask.append(t in qualify_id)
            track_mask = np.asarray(track_mask)            
            #build KDTree to query the nearest neighbor
            xys = helpy.consecutive_fields_view(fdata[startframe][track_mask], 'xy')
            ors = helpy.consecutive_fields_view(fdata[startframe][track_mask], 'o')
            disp = xys - [self.x0, self.y0] # displacement to the center
            radial = np.hypot(*disp.T)
            criteria = self.R - 1.4*self.side_len
            radial_mask = radial >= criteria
            #switch x, y coordinate into the regular orientation
            xys = xys[:,::-1]
            xys[:,1] = 1024 - xys[:,1]
            self.xys[startframe] = xys
            
            ftree = KDTree(xys, leafsize = 16)
            #####################################################################
            # 1st iteration, 
            # find at least two particles within 1.5 particle size radius
            # 3 of your neighbor must satisfy vr_criteria.
            # need to meet vomega criteria 
            #####################################################################           
            final_mask = []       

            for pt_id in range(len(xys)):
                if not vr_mask[pt_id]:
                    final_mask.append(False)
                    continue
                dists, ids = ftree.query(xys[pt_id], self.nnn)
                #if np.all(dists < self.side_len * 2.0):
                if np.sum(dists < self.side_len*1.5) > 2:
                    final_mask.append(np.sum(vr_mask[ids]) > 3)
                else:
                    final_mask.append(False)
            temp_mask = np.array(final_mask) & np.array(vomega_mask)
            
                        
            ##############################################################################
            # if you neighbors qualified then you will be solid ,exclude detection error
            # 
            # qualified_id is a True or False mask
            ##############################################################################
            qualified_solid = list()
            for pt_id in range(len(xys)):
                dists, ids = ftree.query(xys[pt_id], self.nnn)
                qualified_solid.append(temp_mask[pt_id] or np.sum(temp_mask[ids[1:]]) >= 3)
            
            self.final_id[startframe] = qualified_solid    
            solid_number = np.sum(qualified_solid)
            self.solids.append(solid_number) 
            
            
                       
            plot_vor = startframe < 550
            voronoi = self.density_calculation(solid_number, len(qualify_id), xys, ors, disp,\
                                                             qualified_solid, plot_vor, radial_mask)
            #print(qualified_solid)
            self.liquid_density.append(voronoi.liquid_density)
            self.solid_density.append(voronoi.solid_density)
            self.solid_local_bond4.append(np.nanmean(voronoi.solid_local_bond4))
            self.solid_local_bond6.append(np.nanmean(voronoi.solid_local_bond6))
            self.solid_local_mole4.append(np.nanmean(voronoi.solid_local_mole4))
            self.solid_polar.append(np.nanmean(voronoi.solid_polar))
            self.solid_polar_fraction.append(voronoi.solid_polar_fraction)
            self.radi_polar.append(np.nanmean(voronoi.radius_polar))
            self.radi_polar_fraction.append(voronoi.R_polar_fraction)
            self.inter_boundary_number.append(voronoi.interface_number)
    
            
            self.vornoi_history.append(voronoi)
            if plot_number < self.plot_check:
                xs = helpy.consecutive_fields_view(fdata[startframe][track_mask],'x')
                ys = helpy.consecutive_fields_view(fdata[startframe][track_mask],'y')
                self.plot_check_solid(xs, ys, vr_mean, vr_mask, order_para_mean, \
                                      order_mask,vomega_list, vomega_mask, final_mask,\
                                      qualified_solid)
                plot_number += 1
        self.save_phase()
        return len(qualify_id)
Exemplo n.º 10
0
def get_angles_loop(pdata, cdata, pfsets, cfsets, cftrees, nc=3, rc=11, drc=0, do_average=True, verbose=False):
    """ get_angles(pdata, cdata, pfsets, cfsets, cftrees, nc=3, rc=11, drc=0, do_average=True)
        
        arguments:
            pdata   - data array with 'x' and 'y' fields for particle centers
            cdata   - data array wity 'x' and 'y' fields for corners
                (these arrays need not have the same length,
                    but both must have 'f' field for the image frame)
            pfsets  - slices into pdata, by frame
            cfsets  -    and for cdata
            cftrees - dict of KDTrees for corners, by frame
            nc      - number of corner dots
            rc      - distance between center and corner dot
            drc     - tolerance for rc
            do_average - whether to average the nc corners to one value for return
            
        returns:
            odata   - array with fields:
                'orient' for orientation of particles
                'corner' for particle corner (with 'x' and 'y' sub-fields)
            (odata has the same shape as data)
    """
    import helpy
    if do_average or nc == 1:
        dt = [('corner',float,(nc,2)),
              ('orient',float),
              ('cdisp',float,(nc,))]
    elif nc > 1:
        dt = [('corner',float,(nc,2,)),
              ('orient',float,(nc,)),
              ('cdisp',float,(nc,))]
    odata = np.full(len(pdata), np.nan, dtype=dt)
    odata_corner = odata['corner']
    odata_orient = odata['orient']
    odata_cdisp  = odata['cdisp']
    full_ids = pdata['id']
    id_ok = full_ids[0]==0 and np.all(np.diff(full_ids)==1)
    print_freq = len(pfsets)//(100 if verbose>1 else 5) + 1
    if verbose:
        print 'seeking orientations'
    for f in pfsets:
        if verbose and not f % print_freq:
            print f,
        fpdata = pfsets[f]
        fcdata = cfsets[f]
        tree = cftrees[f]
        positions = helpy.consecutive_fields_view(fpdata, 'xy')
        cpositions = helpy.consecutive_fields_view(fcdata, 'xy')
        frame_ids = helpy.quick_field_view(fpdata, 'id')
        for frame_id, posi in izip(frame_ids, positions):
            #TODO could probably be sped up by looping through the output of
            #     ptree.query_ball_tree(ctree)
            corner, orient, disp = \
                find_corner(posi, cpositions, tree=tree,
                            nc=nc, rc=rc, drc=drc, do_average=do_average)
            if orient is None: continue
            full_id = frame_id if id_ok else np.searchsorted(full_ids, frame_id)
            odata_corner[full_id] = corner
            odata_orient[full_id] = orient
            odata_cdisp[full_id] = disp

    if do_average or nc == 1:
        mask = np.isfinite(odata['orient'])
    elif nc > 1:
        mask = np.all(np.isfinite(odata['orient']), axis=1)

    return odata, mask
Exemplo n.º 11
0
def get_angles(pdata,
               cdata,
               pfsets,
               cfsets,
               cftrees,
               nc,
               rc,
               drc=None,
               ang=None,
               dang=None,
               do_average=True,
               verbose=False):
    """find the orientations of particles given center and corner positions

    Parameters
    ----------
    pdata:      data array with 'x' and 'y' fields for particle centers
    cdata:      data array wity 'x' and 'y' fields for corners
        pdata and cdata arrays need not have the same length,
        but both must have 'f' field for the image frame)
    pfsets:     slices into pdata, by frame
    cfsets:     slices into cdata, by frame
    cftrees:    dict of KDTrees for corners, by frame
        the following arguments are passed to find_corner:
    nc:         number of corner dots
    rc:         expected distance between center and corner dot
    drc:        tolerance for rc, defaults to sqrt(rc)
    ang:        angular separation between corners (if nc > 1)
    dang:       tolerance for ang (if None, ang is ignored if nfound == nc, but
                is uses to choose best nc of nfound if nfound > nc)
    do_average: whether to average the nc corners to one value for return

    Returns
    -------
    odata:  structured array, same shape as pdata, with fields:
            'corner' for particle corner (with 'x' and 'y' sub-fields)
            'orient' for orientation of particles
            'cdisp' for the corner - center displacement
    """
    dt = [('corner', float, (nc, 2)), ('orient', float),
          ('cdisp', float, (nc, ))]
    if nc > 1 and not do_average:
        dt[1] += ((nc, ), )  # give the 'orient' field a shape of (nc,)
    odata = np.full(len(pdata), np.nan, dtype=dt)
    if ang > pi:
        ang = np.radians(ang)
        if dang:
            dang = np.radians(dang)
    odata_corner = odata['corner']
    odata_orient = odata['orient']
    odata_cdisp = odata['cdisp']
    full_ids = pdata['id']
    id_ok = full_ids[0] == 0 and np.all(np.diff(full_ids) == 1)
    print_freq = len(pfsets) // (100 if verbose > 1 else 5) + 1
    print 'seeking orientations'
    for f in pfsets:
        if verbose and not f % print_freq:
            print f,
        fpdata = pfsets[f]
        fcdata = cfsets[f]
        cftree = cftrees[f]
        positions = helpy.consecutive_fields_view(fpdata, 'xy')
        cpositions = helpy.consecutive_fields_view(fcdata, 'xy')
        fp_ids = helpy.quick_field_view(fpdata, 'id')
        for fp_id, posi in it.izip(fp_ids, positions):
            # TODO could probably be sped up by looping through the output of
            # ptree.query_ball_tree(ctree)
            corner, orient, disp = \
                find_corner(posi, cpositions, nc=nc, rc=rc, drc=drc, ang=ang,
                            dang=dang, tree=cftree, do_average=do_average)
            if orient is None:
                continue
            full_id = fp_id if id_ok else np.searchsorted(full_ids, fp_id)
            odata_corner[full_id] = corner
            odata_orient[full_id] = orient
            odata_cdisp[full_id] = disp

    if do_average or nc == 1:
        mask = np.isfinite(odata['orient'])
    elif nc > 1:
        mask = np.all(np.isfinite(odata['orient']), axis=1)

    return odata, mask
Exemplo n.º 12
0
def get_angles(pdata, cdata, pfsets, cfsets, cftrees, nc, rc, drc=None,
               ang=None, dang=None, do_average=True, verbose=False):
    """find the orientations of particles given center and corner positions

    Parameters
    ----------
    pdata:      data array with 'x' and 'y' fields for particle centers
    cdata:      data array wity 'x' and 'y' fields for corners
        pdata and cdata arrays need not have the same length,
        but both must have 'f' field for the image frame)
    pfsets:     slices into pdata, by frame
    cfsets:     slices into cdata, by frame
    cftrees:    dict of KDTrees for corners, by frame
        the following arguments are passed to find_corner:
    nc:         number of corner dots
    rc:         expected distance between center and corner dot
    drc:        tolerance for rc, defaults to sqrt(rc)
    ang:        angular separation between corners (if nc > 1)
    dang:       tolerance for ang (if None, ang is ignored if nfound == nc, but
                is uses to choose best nc of nfound if nfound > nc)
    do_average: whether to average the nc corners to one value for return

    Returns
    -------
    odata:  structured array, same shape as pdata, with fields:
            'corner' for particle corner (with 'x' and 'y' sub-fields)
            'orient' for orientation of particles
            'cdisp' for the corner - center displacement
    """
    dt = [('corner', float, (nc, 2)),
          ('orient', float),
          ('cdisp', float, (nc,))]
    if nc > 1 and not do_average:
        dt[1] += ((nc,),)   # give the 'orient' field a shape of (nc,)
    odata = np.full(len(pdata), np.nan, dtype=dt)
    if ang > pi:
        ang = np.radians(ang)
        if dang:
            dang = np.radians(dang)
    odata_corner = odata['corner']
    odata_orient = odata['orient']
    odata_cdisp = odata['cdisp']
    full_ids = pdata['id']
    id_ok = full_ids[0] == 0 and np.all(np.diff(full_ids) == 1)
    print_freq = len(pfsets)//(100 if verbose > 1 else 5) + 1
    print 'seeking orientations'
    for f in pfsets:
        if verbose and not f % print_freq:
            print f,
        fpdata = pfsets[f]
        fcdata = cfsets[f]
        cftree = cftrees[f]
        positions = helpy.consecutive_fields_view(fpdata, 'xy')
        cpositions = helpy.consecutive_fields_view(fcdata, 'xy')
        fp_ids = helpy.quick_field_view(fpdata, 'id')
        for fp_id, posi in it.izip(fp_ids, positions):
            # TODO could probably be sped up by looping through the output of
            # ptree.query_ball_tree(ctree)
            corner, orient, disp = \
                find_corner(posi, cpositions, nc=nc, rc=rc, drc=drc, ang=ang,
                            dang=dang, tree=cftree, do_average=do_average)
            if orient is None:
                continue
            full_id = fp_id if id_ok else np.searchsorted(full_ids, fp_id)
            odata_corner[full_id] = corner
            odata_orient[full_id] = orient
            odata_cdisp[full_id] = disp

    if do_average or nc == 1:
        mask = np.isfinite(odata['orient'])
    elif nc > 1:
        mask = np.all(np.isfinite(odata['orient']), axis=1)

    return odata, mask
    def phase_detection(self):
        self.solids = []
        self.detect = []
        self.liquid_density = list()
        self.solid_fraction = list()
        self.xys = dict()
        self.final_id = dict()
        self.solid_vor_area = np.empty(0)
        self.liquid_vor_area = np.empty(0)
        plot_number = 0
        sorted_keys = sorted(self.config_vdata.keys())
        for startframe in sorted_keys:
            #pids = v_data.keys()
            v_data = self.config_vdata[startframe]
            qualify_id, order_para_mean, vr_mean, vomega_list = self.single_config_detect(
                v_data)
            self.detect.append(len(qualify_id))
            qualify_id_set = set(qualify_id)
            order_mask, vr_mask, vomega_mask = self.solid_criteria(
                order_para_mean, vr_mean, vomega_list)

            fdata = helpy.load_framesets(v_data)

            # find the frame where contains all the qualified particles
            count = 0
            while (count < 49) & (not set(fdata[startframe + count]
                                          ['t']).issuperset(qualify_id_set)):
                count += 1
                if count == 49:
                    break
            startframe += count
            # for the idtentified frame, make TRUE if t in qualified_id
            fdata_track = fdata[startframe]['t']
            track_mask = list()
            for t in fdata_track:
                track_mask.append(t in qualify_id)
            track_mask = np.asarray(track_mask)
            #build KDTree to query the nearest neighbor
            xys = helpy.consecutive_fields_view(fdata[startframe][track_mask],
                                                'xy')
            disp = xys - [self.x0, self.y0]
            radial = np.hypot(*disp.T)
            criteria = self.R - 1.4 * self.side_len
            radial_mask = radial >= criteria
            #switch x, y coordinate into the regular orientation
            xys = xys[:, ::-1]
            xys[:, 1] = 1024 - xys[:, 1]
            self.xys[startframe] = xys

            ftree = KDTree(xys, leafsize=16)

            final_mask = []

            for pt_id in range(len(xys)):
                if not vr_mask[pt_id]:
                    final_mask.append(False)
                    continue
                dists, ids = ftree.query(xys[pt_id], self.nnn)
                #if np.all(dists < self.side_len * 2.0):
                if np.sum(dists < self.side_len * 1.5) > 2:
                    final_mask.append(np.sum(vr_mask[ids]) > 3)
                else:
                    final_mask.append(False)
            temp_mask = np.array(final_mask) & np.array(vomega_mask)

            # if you neighbors qualified then you will be solid ,exclude detection error
            qualified_solid = list()
            for pt_id in range(len(xys)):
                dists, ids = ftree.query(xys[pt_id], self.nnn)
                qualified_solid.append(temp_mask[pt_id]
                                       or np.sum(temp_mask[ids[1:]]) >= 3)

            self.final_id[startframe] = qualified_solid
            solid_number = np.sum(qualified_solid)
            self.solids.append(solid_number)

            plot_vor = startframe < 550
            rho_liquid, rho_solid = self.density_calculation(
                solid_number, len(qualify_id), xys, qualified_solid, plot_vor,
                radial_mask)
            self.liquid_density.append(rho_liquid)
            self.solid_fraction.append(float(solid_number) / len(qualify_id))
            self.solid_density.append(rho_solid)

            if plot_number < self.plot_check:
                xs = helpy.consecutive_fields_view(
                    fdata[startframe][track_mask], 'x')
                ys = helpy.consecutive_fields_view(
                    fdata[startframe][track_mask], 'y')
                self.plot_check_solid(xs, ys, vr_mean, vr_mask, order_para_mean, \
                                      order_mask,vomega_list, vomega_mask, final_mask,\
                                      qualified_solid)
                plot_number += 1
        return len(qualify_id)