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