def cmd_plot_waveform(ctx, config, waveforms, name): ''' Plot waveforms. ''' res = None ses = ctx.obj['session'] if ':' in waveforms: from pixsim.store import get_last_ids total_ids = get_last_ids(ses)['result'] first_id, last_id, we_got = pythonify(waveforms, total_ids) if we_got is None: return res = [get_result(ses, id=x) for x in range(first_id, last_id+1)] else: res = [get_result(ses, id=waveforms)] if name is None: waveforms = [arr.data for r in res for arr in r.data] else: waveforms = [arr.data for r in res for arr in r.data if name == arr.name.split('_')[-1]] import pixsim.plotting as plt click.echo("Plotting {} waveforms...".format(len(waveforms))) plt.plot_waveforms(waveforms, **ctx.obj['cfg'][config])
def cmd_step(ctx, velocity, geoconfig, config, name): """Step through velocity field. Also retrieves the linspace from parent raster results.""" ses = ctx.obj['session'] vres = get_result(ses, source=velocity) if vres is None: click.echo("No matching results for ".format(velocity)) return rasres = get_result(ses, id=vres.parent_id) if rasres is None: click.echo("No matching results for parent ID = {}".format(vres.parent_id)) return vfield = find_data(vres, ['vector']) linspace = find_data(rasres, ['linspace']) assert vfield is not None and 'Velocity field not found' assert linspace is not None and 'linspace not found' import pixsim.step as step import pixsim.geometry as geometry pixcoll = geometry.make_pixels_center(**ctx.obj['cfg'][geoconfig]) assert len(pixcoll) > 0 arrays = step.step(vfield, linspace, pixcoll, **ctx.obj['cfg'][config]) res = Result(name=name, typename='step', data=arrays, parent=vres) save_result(ctx, res)
def average_paths(ses, name, first_id, last_id): from pixsim.store import get_result # initialize path names result = get_result(ses, id=first_id) step_size = 0 # # This assumes each path started at the same time and # constant step in time # import numpy as np arrs_to_add = list() max_steps = -1 for resid in range(first_id, last_id + 1): result = get_result(ses, id=resid) # making no assumption, look for the correct path use_this_wvf = None for path, wvf in enumerate(result.data): use_this_wvf = np.asarray(wvf.data) # add waveform to arrs if len(use_this_wvf) > max_steps: max_steps = len(use_this_wvf) arrs_to_add.append(use_this_wvf) # assuming we used fixed step size in t, we can easily add them avgwvf = np.zeros(max_steps) for arr in arrs_to_add: step_size = arr[1, 0] - arr[0, 0] wvfarr = arr[:, 1] resized = np.zeros_like(avgwvf) resized[:wvfarr.shape[0]] = wvfarr avgwvf = np.add(avgwvf, resized) # normalize if do_norm(avgwvf): avgwvf /= abs(np.sum(avgwvf)) # for plotting new_wvf = list() time = 0 for tick in range(0, avgwvf.shape[0]): point = [time, avgwvf[tick]] new_wvf.append(np.asarray(point)) time += step_size callit = name + '_avg_waveform' return [Array(name=callit, typename='tuples', data=new_wvf)]
def cmd_gen_raster(ctx, config, name, boundary): ''' Generate raster. Used to generate the rasters for for a collection of weighting solutions. This is meant to run after a gen weight, so results can be passed using boundary option. ''' id_range = boundary ses = ctx.obj['session'] from pixsim.store import get_last_ids total_ids = get_last_ids(ses)['result'] first_id, last_id, we_got = pythonify(id_range, total_ids) if we_got is None: return sources = [x for x in range(first_id, last_id+1)] do_it = click.prompt("Do range {}-{}? (y/n)".format(first_id, last_id), default='y') if 'y' != do_it: return for src in sources: click.echo('Running for {}'.format(str(src))) bres = get_result(ses, id=src) if bres is None: click.echo("No matching results for name = {}".format(src)) continue # we are using a specific naming convention where the domain is the last string dom = bres.name.split('_')[-1] callit = name+'_weight_raster_domain_'+dom ctx.invoke(cmd_raster, config=config, boundary=src, name=callit)
def cmd_gen_vtx(ctx, source, geoconfig, name, dirname, dmap): ''' Generate step vertices for electrode array. This will create new step vertices in global coordinates based on electrode domain IDs and relative starting positions in the template step file. Will create a directory of step files to use for stepping in the corresponding weighting field. Template file should have something similar to:\n domains 8 9 10 11 \n 0.75 0 0 ''' import pixsim.geometry as geometry pixcoll = geometry.make_pixels_center(**ctx.obj['cfg'][geoconfig]) do_domains, do_pos = list(), list() with open(source) as tmpfile: domainline = tmpfile.readline().split() assert domainline[0] == 'domains' and 'Header assumed to be \'domains\'' do_domains = [int(dom) for dom in domainline[1:]] while True: linevec = tmpfile.readline().split() if len(linevec) < 1: break pos = [float(x) for x in linevec] assert len(pos) == 3 do_pos.append(pos) ses = ctx.obj['session'] gres = get_result(ses, name=dmap) if gres is None: click.echo("No matching results for name = {}".format(dmap)) return domap = gres.data[0].data # generate import os os.mkdir(dirname) arrs = list() for did in do_domains: # find the center position of this domain cent = None # dmap entries => (domainid, pid, center) for entry in domap: if entry[0] == did: cent = entry[2] break assert cent is not None filename = name+'genvtx_domain_'+str(did)+'.txt' path = os.path.join(dirname, filename) with open(path, 'w') as f: for count, rpos in enumerate(do_pos, 1): callit = name+'vtx'+str(count) gpos = [rpos[i]+cent[i] for i in range(0, 3)] out = [callit, str(gpos[0]), str(gpos[1]), str(gpos[2])] out = ' '.join(out) f.write(out+'\n')
def cmd_gen_response(ctx, config, name, waveforms, step): ''' Generate response. ''' ses = ctx.obj['session'] curres = get_result(ses, id=waveforms) if curres is None: click.echo("No matching results for id = {}".format(waveforms)) return stepres = get_result(ses, id=step) if stepres is None: click.echo("No matching results for id = {}".format(stepres)) return import pixsim.response as rsp arrays = rsp.response(stepres.data, curres.data, **ctx.obj['cfg'][config]) res = Result(name=name, typename='current', data=arrays, parent=curres) save_result(ctx, res)
def cmd_current(ctx, step, raster, config, name): """Calculate the current waveforms.""" ses = ctx.obj['session'] sres = get_result(ses, source=step) if sres is None: click.echo("No matching results for name = {}".format(step)) return rasres = get_result(ses, source=raster) if rasres is None: click.echo("No matching results for name = {}".format(raster)) return assert(sres.typename == 'step' and rasres.typename == 'raster') efield, linspaces = find_data(rasres, ['vector', 'linspace']) paths = [p.data for p in sres.data if 'tuples' in p.typename] pnames = [p.name for p in sres.data if 'tuples' in p.typename] import pixsim.current as current arrays = current.compute(efield, linspaces, paths, pnames) res = Result(name=name, typename='current', data=arrays, parent=rasres) save_result(ctx, res)
def cmd_ana(ctx, result): """Entry to drift sim.""" ses = ctx.obj['session'] click.echo("Loading data...") res = get_result(ses, source=result) if res is None: click.echo("No matching results for name = {}".format(result)) return import pixsim.analyze as ana ana.analyze(res.data)
def cmd_plot_efield(ctx, result_id, config): ''' Plot efield. ''' ses = ctx.obj['session'] res = get_result(ses, id=result_id) if res is None: click.echo("No matching results for id = {}".format(result_id)) return points, linspaces, pot, grad = find_data(res, ['points', 'linspace', 'scalar', 'vector']) import pixsim.plotting as plt plt.plot_efield(ctx.obj['mesh_filename'], grad, **ctx.obj['cfg'][config])
def cmd_gen_current(ctx, config, name, raster, step): ''' Generate current. ''' ses = ctx.obj['session'] from pixsim.store import get_last_ids total_ids = get_last_ids(ses)['result'] first_id, last_id, we_got = pythonify(raster, total_ids) if we_got is None: return rasres = {x:get_result(ses, id=x) for x in range(first_id, last_id+1)} first_id, last_id, we_got = pythonify(step, total_ids) if we_got is None: return stepres = {x:get_result(ses, id=x) for x in range(first_id, last_id+1)} # mapping raster results to step by matching domain_## for sid, sres in stepres.iteritems(): if sres is None: click.echo("No matching results for id = {}".format(sid)) continue matching_this = sres.name.split('_')[-1] usethisras = None for rid, rres in rasres.iteritems(): if rres is None: click.echo("No matching results for id = {}".format(rid)) continue domainid = rres.name.split('_')[-1] if domainid == matching_this: usethisras = rres break # make sure we found a match if usethisras is None: raise AssertionError('Could not find matching domain ID') click.echo('Running for weight {} and step {}'.format(usethisras.parent.name, sres.name)) callit = name+'_waveforms_for_domain_'+domainid ctx.invoke(cmd_current, step=sres.id, raster=usethisras.id, config=config, name=callit)
def cmd_sim(ctx, response, config): """Entry to drift sim.""" ses = ctx.obj['session'] rres = get_result(ses, source=response) if rres is None: click.echo("No matching results for name = {}".format(response)) return import pixsim.driftsim as dsim arrs = dsim.sim(rres, **ctx.obj['cfg'][config]) res = Result(name='simwaveforms', typename='current', data=arrs) save_result(ctx, res)
def cmd_velocity(ctx, raster, config, name): """Evaluating velocity on raster""" ses = ctx.obj['session'] rasres = get_result(ses, source=raster) if rasres is None: click.echo("No matching results for {}".format(raster)) return potential, linspace = find_data(rasres, ['scalar', 'linspace']) assert(potential is not None and linspace is not None) import pixsim.velocity as velocity arrays = velocity.drift(potential, linspace, **ctx.obj['cfg'][config]) res = Result(name=name, typename='velocity', data=arrays, parent=rasres) save_result(ctx, res)
def cmd_raster(ctx, boundary, config, name): """Evaluate solution on a raster of points""" ses = ctx.obj['session'] bres = None bres = get_result(ses, source=boundary) if bres is None: click.echo("No matching results for {}".format(boundary)) return sol = find_data(bres, ['scalar']) from pixsim.raster import linear arrays = linear(ctx.obj['mesh_filename'], sol, **ctx.obj['cfg'][config]) res = Result(name=name, typename='raster', data=arrays, parent=bres) save_result(ctx, res)
def cmd_play(ctx, result_id): """Used for editing or experimenting""" ses = ctx.obj['session'] if result_id is not None: result = get_result(ses, id=result_id) if result is None: click.echo("No matching result result_id = {}".format(result_id)) return vtx_1, vtx_108 = None, None for arr in result.data: if 'vtx1' in arr.name: vtx_1 = arr.data if 'vtx108' in arr.name: vtx_108 = arr.data assert vtx_1 is not None and vtx_108 is not None print vtx_108
def save_raster_vtk(ses, outname, res_id): ''' Save a drift result into a VTK file. ''' print 'Saving raster results...' #res_id = input('Enter the raster result ID: ') result = get_result(ses, id=res_id) if result is None: print 'No matching results for ID = {}'.format(res_id) return arrs = result.array_data_by_name() points = arrs['points'].T from tvtk.api import tvtk, write_data for thing in ['pfield','efield']: values = arrs[thing] npoints = len(points) ug = tvtk.UnstructuredGrid() point_type = tvtk.Vertex().cell_type cell_types = numpy.array([point_type]*npoints) cell_array = tvtk.CellArray() cells = numpy.array([npoints]+range(npoints)) cell_array.set_cells(point_type, cells) ug.set_cells(1, cell_array) if thing == 'pfield': ug.points = points ug.point_data.scalars = values.reshape(npoints) ug.point_data.scalars.name = thing else: ug.points = points field = numpy.asarray([[x,y,z] for x,y,z in zip(values[0,:,:,:].reshape(npoints),values[1,:,:,:].reshape(npoints),values[2,:,:,:].reshape(npoints))]) ug.point_data.vectors = field ug.point_data.vectors.name = thing fname = '%s-%s.vtk' % (outname, thing) write_data(ug, fname)
def cmd_rename(ctx, result_id, array_id, name): ''' Rename result in the store. ''' ses = ctx.obj['session'] if result_id is not None: result = get_result(ses, id=result_id) if result is None: click.echo("No matching result result_id = {}".format(result_id)) return click.echo("rename %d %s %s to %s" % (result.id, result.name, result.typename, name)) result.name = name ses.add(result) ses.commit() elif array_id is not None: array = get_array(ses, None, array_id) if array is None: click.echo("No matching array for array_id = {}".format(array_id)) return click.echo("rename %d %s %s to %s" % (array.id, array.name, array.typename, name)) array.name = name ses.add(array) ses.commit()
def cmd_gen_weight(ctx, config, name, dmap, domains): ''' Generate weights. Used to generate the weighting fields for a collection of electrodes (gen weight). Expecting a domain_map in the store. ''' ses = ctx.obj['session'] gres = get_result(ses, name=dmap, id=None) if gres is None: click.echo("No matching results for name = {}".format(dmap)) return domap = gres.data[0].data for entry in domap: dom, elect, pos = entry[0], entry[1], entry[2] if dom not in domains: continue par = ['weight:domain='+str(dom)] click.echo('Running boundary for electrode {} domain = {}'.format(elect, dom)) add_params(ctx, par) callit = name+'_weight_domain_'+str(dom) ctx.invoke(cmd_boundary, config=config, name=callit)
def save_boundary_vtk(ses, mshfile, outname, res_id): ''' Save a boundary result into a VTK file. ''' print 'Saving boundary results...' #res_id = input('Enter the boundary result ID: ') result = get_result(ses, id=res_id) if result is None: print 'No matching results for ID = {}'.format(res_id) return mesh = meshio.read(mshfile) barrs = result.array_data_by_name() from tvtk.api import tvtk, write_data pd = tvtk.PolyData() pd.points = mesh.points pd.polys = mesh.cells['triangle'] pd.cell_data.add_array(mesh.cell_data['triangle']['gmsh:physical']) pd.cell_data.get_array(0).name = 'domains' for count, name in enumerate(['dirichlet', 'neumann']): pd.cell_data.add_array(barrs[name]) pd.cell_data.get_array(count + 1).name = name outname = outname+'.vtk' write_data(pd, outname)
def average_identical_paths(ses, first_id, last_id): from pixsim.store import get_result # initialize path names result = get_result(ses, id=first_id) path_names = [str(w.name) for w in result.data] waveforms = list() step_size = 0 # # We will loop over each path name, store the data from # each result, fill an array which has length max(data) # # This assumes each path started at the same time and # constant step in time # import numpy as np for name in path_names: arrs_to_add = list() max_steps = -1 for resid in range(first_id, last_id + 1): result = get_result(ses, id=resid) # making no assumption, look for the correct path use_this_wvf = None for path, wvf in enumerate(result.data): if str(wvf.name) == name: use_this_wvf = np.asarray(wvf.data) break if use_this_wvf is None: click.echo( 'Skipping result {} - Could not find waveform named {}'. format(resid, nm)) continue # add waveform to arrs if len(use_this_wvf) > max_steps: max_steps = len(use_this_wvf) arrs_to_add.append(use_this_wvf) # assuming we used fixed step size in t, we can easily add them avgwvf = np.zeros(max_steps) for arr in arrs_to_add: step_size = arr[1, 0] - arr[0, 0] wvfarr = arr[:, 1] resized = np.zeros_like(avgwvf) resized[:wvfarr.shape[0]] = wvfarr avgwvf = np.add(avgwvf, resized) waveforms.append(avgwvf) # normalize for wvf in waveforms: wvf /= np.sum(wvf) # for plotting wvf_with_t = list() for wvf in waveforms: new_wvf = list() time = 0 for tick in range(0, wvf.shape[0]): point = [time, wvf[tick]] new_wvf.append(np.asarray(point)) time += step_size wvf_with_t.append(np.asarray(new_wvf)) arrs = list() for wvf, nm in zip(wvf_with_t, path_names): callit = 'avg_waveform_for_' + nm arrs.append(Array(name=callit, typename='tuples', data=wvf))
def save_step_vtk(ses, outname, res_id): ''' Save a step result into a VTK file. ''' print 'Saving stepping results...' #res_id = input('Enter the step result ID: ') step_res = get_result(ses, id=res_id) if step_res is None: print 'No matching results for ID = {}'.format(res_id) return # we need the raster data vel_res = get_result(ses, id=step_res.parent_id) if vel_res is None: print 'No matching results for ID = {}'.format(step_res.parent_id) return rast_res = get_result(ses, id=vel_res.parent_id) if rast_res is None: print 'No matching results for ID = {}'.format(vel_res.parent_id) return # get the field and linspaces field, linspaces = None, None for arr in rast_res.data: if arr.typename == 'scalar': field = arr.data if arr.typename == 'linspace': linspaces = arr.data assert(field is not None and linspaces is not None) field = Scalar(field, linspaces) # exporting initial position vtxs = [x for x in step_res.data if 'points' in x.typename] points = list() pot = list() for vtx in vtxs: for pt in vtx.data: points.append(pt) pot.append(field(pt)) points = numpy.asarray(points) pot = numpy.asarray(pot) from tvtk.api import tvtk, write_data if len(vtxs): ug = tvtk.UnstructuredGrid() point_type = tvtk.Vertex().cell_type npoints = len(points) cell_types = numpy.array([point_type]*npoints) cell_array = tvtk.CellArray() cells = numpy.array([npoints]+range(npoints)) cell_array.set_cells(point_type, cells) ug.set_cells(1, cell_array) ug.points = points ug.point_data.scalars = pot ug.point_data.scalars.name = 'potential' fname = '%s-%s.vtk' % (outname, 'vtxs') write_data(ug, fname) # exporting paths paths = [x for x in step_res.data if 'tuples' in x.typename] points = list() pot = list() vel = list() for path in paths: for pt in path.data: xyz = pt[0:3] uvw = pt[3:6] points.append(xyz) pot.append(field(xyz)) mag = numpy.sqrt(uvw.dot(uvw)) vel.append(mag) points = numpy.asarray(points) pot = numpy.asarray(pot) vel = numpy.asarray(vel) if len(paths): for flv,data in {'potential':pot, 'velocity':vel}.iteritems(): ug = tvtk.UnstructuredGrid() point_type = tvtk.Vertex().cell_type npoints = len(points) cell_types = numpy.array([point_type]*npoints) cell_array = tvtk.CellArray() cells = numpy.array([npoints]+range(npoints)) cell_array.set_cells(point_type, cells) ug.set_cells(1, cell_array) ug.points = points ug.point_data.scalars = data ug.point_data.scalars.name = flv fname = '%s-%s-%s.vtk' % (outname, 'paths', flv) write_data(ug, fname)