class PicMethod(object): """ @arg debug: A set of strings telling what to debug. So far, the following debug flags are in use: - depositor: Debug the depositor. - verbose_vis: Generate E and B fields and force visualizations at particle locations. - ic: Check the initial condition when it's generated. - no_ic: Start with zero fields. - discretization: (See driver.py.) Turn on debug mode for the discretization. - shape_bw: Debug the finding of the optimal shape bandwidth. - interactive: Allow debug measures that require user interaction. - vis_files: Allow debug measures that write extra visualization files. """ def __init__(self, discr, units, depositor, pusher, dimensions_pos, dimensions_velocity, debug=set()): self.units = units self.discretization = discr self.debug = debug self.depositor = depositor self.pusher = pusher self.dimensions_mesh = discr.dimensions self.dimensions_pos = dimensions_pos self.dimensions_velocity = dimensions_velocity dims = (dimensions_pos, dimensions_velocity) self.mesh_data = _internal.MeshData(discr.dimensions) self.mesh_data.fill_from_hedge(discr) # subsystem init self.depositor.initialize(self) self.pusher.initialize(self) # instrumentation from pytools.log import IntervalTimer, EventCounter self.find_el_timer = IntervalTimer("t_find", "Time spent finding new elements") self.find_same_counter = EventCounter( "n_find_same", "#Particles found in same element") self.find_by_neighbor_counter = EventCounter( "n_find_neighbor", "#Particles found through neighbor") self.find_by_vertex_counter = EventCounter( "n_find_by_vertex", "#Particles found by vertex") self.find_global_counter = EventCounter( "n_find_global", "#Particles found by global search") def make_state(self): state = PicState(self) state.particle_number_shift_signaller.subscribe_with_state( self.depositor) state.particle_number_shift_signaller.subscribe_with_state(self.pusher) return state def get_dimensionality_suffix(self): return "%dd%dv" % (self.dimensions_pos, self.dimensions_velocity) def get_shape_function_class(self): from pyrticle.tools import \ PolynomialShapeFunction, \ CInfinityShapeFunction from pyrticle._internal import get_shape_function_name name = get_shape_function_name() if name == "c_infinity": return CInfinityShapeFunction elif name == "polynomial": return PolynomialShapeFunction else: raise ValueError, "unknown shape function class" def set_ignore_core_warnings(self, ignore): from pyrticle.tools import WarningForwarder, WarningIgnorer import pyrticle.tools del pyrticle.tools.warning_forwarder if ignore: pyrticle.tools.warning_forwarder = WarningIgnorer() else: pyrticle.tools.warning_forwarder = WarningForwarder() def add_instrumentation(self, mgr, observer): mgr.add_quantity(self.find_el_timer) mgr.add_quantity(self.find_same_counter) mgr.add_quantity(self.find_by_neighbor_counter) mgr.add_quantity(self.find_by_vertex_counter) mgr.add_quantity(self.find_global_counter) self.depositor.add_instrumentation(mgr, observer) self.pusher.add_instrumentation(mgr, observer) def velocities(self, state): try: return state.derived_quantity_cache["velocities"] except KeyError: result = _internal.get_velocities(state.particle_state, self.units.VACUUM_LIGHT_SPEED()) state.derived_quantity_cache["velocities"] = result return result def mean_beta(self, state): if len(state): return numpy.average(self.velocities(state), axis=0) \ / self.units.VACUUM_LIGHT_SPEED() else: return numpy.zeros((self.dimensions_velocity, )) def add_particles(self, state, iterable, maxcount=None): """Add the particles from C{iterable} to the cloud. C{iterable} is expected to yield tuples C{(position, velocity, charge, mass)}. If C{maxcount} is specified, maximally C{maxcount} particles are obtained from the iterable. """ pstate = state.particle_state if maxcount is not None: if pstate.particle_count + maxcount >= len( pstate.containing_elements): state.resize(pstate.particle_count + maxcount) for pos, vel, charge, mass in iterable: if maxcount is not None: if maxcount == 0: break maxcount -= 1 assert len(pos) == self.dimensions_pos assert len(vel) == self.dimensions_velocity pos = numpy.asarray(pos) vel = numpy.asarray(vel) mom = mass * self.units.gamma_from_v(vel) * vel cont_el = self.mesh_data.find_containing_element(pos) if cont_el == MeshData.INVALID_ELEMENT: print "not in valid element" continue if pstate.particle_count >= len(pstate.containing_elements): state.resize(max(128, 2 * pstate.particle_count)) pstate.containing_elements[pstate.particle_count] = cont_el pstate.positions[pstate.particle_count] = pos pstate.momenta[pstate.particle_count] = mom pstate.charges[pstate.particle_count] = charge pstate.masses[pstate.particle_count] = mass pstate.particle_count += 1 self.check_containment(state) state.particle_number_shift_signaller.note_change_size( pstate.particle_count) state.derived_quantity_cache.clear() def check_containment(self, state): """Check that a containing element is known for each particle. This is a new invariant as of 1/17/08, and violations of this end up segfaulting, which we should avoid. """ assert (state.particle_state.containing_elements[:len(state)] != MeshData.INVALID_ELEMENT).all() def upkeep(self, state): """Perform any operations must fall in between timesteps, such as resampling or deleting particles. """ self.depositor.upkeep(state) self.pusher.upkeep(state) state.vis_listener.clear() # deposition ---------------------------------------------------------- def deposit_densities(self, state): """Return a tuple (charge_density, current_densities), where current_densities is an d-by-n array, where d is the number of velocity dimensions, and n is the discretization nodes. """ def all_getter(): rho, j = self.depositor.deposit_densities(state, self.velocities()) j = numpy.asarray(j.T, order="C") return rho, j return state.get_derived_quantities_from_cache( ["rho", "j"], [self.deposit_rho, self.deposit_j], all_getter) def deposit_j(self, state): """Return a the current densities as an d-by-n array, where d is the number of velocity dimensions, and n is the number of discretization nodes. """ def j_getter(): return numpy.asarray(self.depositor.deposit_j( state, self.velocities(state)).T, order="C") return state.get_derived_quantity_from_cache("j", j_getter) def deposit_rho(self, state): """Return a the charge_density as a volume vector.""" def rho_getter(): return self.depositor.deposit_rho(state) return state.get_derived_quantity_from_cache("rho", rho_getter) # time advance ------------------------------------------------------------ def advance_state(self, state, dx, dp, ddep): pstate = state.particle_state cnt = pstate.particle_count positions = pstate.positions.copy() momenta = pstate.momenta.copy() positions[:cnt] += dx momenta[:cnt] += dp new_state = PicState( self, particle_count=cnt, containing_elements=pstate.containing_elements, positions=positions, momenta=momenta, charges=pstate.charges, masses=pstate.masses, depositor_state=self.depositor.advance_state(state, ddep), pusher_state=self.pusher.advance_state(state), pnss=state.particle_number_shift_signaller, vis_listener=state.vis_listener, ) from pyrticle._internal import FindEventCounters find_counters = FindEventCounters() class BHitListener(_internal.BoundaryHitListener): def note_boundary_hit(subself, pn): _internal.kill_particle( new_state.particle_state, pn, new_state.particle_number_shift_signaller) from pyrticle._internal import update_containing_elements sub_timer = self.find_el_timer.start_sub_timer() update_containing_elements(self.mesh_data, new_state.particle_state, BHitListener(), find_counters) sub_timer.stop().submit() self.find_same_counter.transfer(find_counters.find_same) self.find_by_neighbor_counter.transfer(find_counters.find_by_neighbor) self.find_by_vertex_counter.transfer(find_counters.find_by_vertex) self.find_global_counter.transfer(find_counters.find_global) return new_state # visualization ----------------------------------------------------------- def get_mesh_vis_vars(self): return self.vis_listener.mesh_vis_map.items() def add_to_vis(self, visualizer, vis_file, state, time=None, step=None, beamaxis=None, vis_listener=None): from hedge.visualization import VtkVisualizer, SiloVisualizer if isinstance(visualizer, VtkVisualizer): return self._add_to_vtk(visualizer, vis_file, state, time, step) elif isinstance(visualizer, SiloVisualizer): return self._add_to_silo(visualizer, vis_file, state, time, step, beamaxis, vis_listener) else: raise ValueError, "unknown visualizer type `%s'" % type(visualizer) def _add_to_silo(self, visualizer, db, state, time, step, beamaxis, vis_listener=None): from pylo import DBOPT_DTIME, DBOPT_CYCLE optlist = {} if time is not None: optlist[DBOPT_DTIME] = time if step is not None: optlist[DBOPT_CYCLE] = step pcount = len(state) if pcount: # real-space ------------------------------------------------------ db.put_pointmesh("particles", numpy.asarray(state.positions.T, order="C"), optlist) db.put_pointvar1("charge", "particles", state.charges) db.put_pointvar1("mass", "particles", state.masses) db.put_pointvar("momentum", "particles", numpy.asarray(state.momenta.T, order="C")) db.put_pointvar("velocity", "particles", numpy.asarray(self.velocities(state).T, order="C")) if vis_listener is not None: for name, value in self.vis_listener.particle_vis_map.iteritems( ): from pyrticle.tools import NumberShiftableVector value = NumberShiftableVector.unwrap(value) dim, remainder = divmod(len(value), pcount) assert remainder == 0, ( "particle vis value '%s' had invalid number of entries: " "%d (#particles=%d)" % (name, len(value), pcount)) if dim == 1: db.put_pointvar1(name, "particles", value) else: db.put_pointvar(name, "particles", [value[i::dim] for i in range(dim)]) # phase-space ----------------------------------------------------- axes_names = ["x", "y", "z"] if beamaxis is not None: for axis in range( min(self.dimensions_pos, self.dimensions_velocity)): if axis == beamaxis: continue axname = axes_names[axis] db.put_defvars("phasespace_%s" % axname, [ ("part_%s" % axname, "coord(particles)[%d]" % axis), ("part_%s_prime" % axname, "momentum[%d]/momentum[%d]" % (axis, beamaxis)), ("part_%s_momentum" % axname, "momentum[%d]" % (axis)), ])
class PicMethod(object): """ @arg debug: A set of strings telling what to debug. So far, the following debug flags are in use: - depositor: Debug the depositor. - verbose_vis: Generate E and B fields and force visualizations at particle locations. - ic: Check the initial condition when it's generated. - no_ic: Start with zero fields. - discretization: (See driver.py.) Turn on debug mode for the discretization. - shape_bw: Debug the finding of the optimal shape bandwidth. - interactive: Allow debug measures that require user interaction. - vis_files: Allow debug measures that write extra visualization files. """ def __init__(self, discr, units, depositor, pusher, dimensions_pos, dimensions_velocity, debug=set()): self.units = units self.discretization = discr self.debug = debug self.depositor = depositor self.pusher = pusher self.dimensions_mesh = discr.dimensions self.dimensions_pos = dimensions_pos self.dimensions_velocity = dimensions_velocity dims = (dimensions_pos, dimensions_velocity) self.mesh_data = _internal.MeshData(discr.dimensions) self.mesh_data.fill_from_hedge(discr) # subsystem init self.depositor.initialize(self) self.pusher.initialize(self) # instrumentation from pytools.log import IntervalTimer, EventCounter self.find_el_timer = IntervalTimer( "t_find", "Time spent finding new elements") self.find_same_counter = EventCounter( "n_find_same", "#Particles found in same element") self.find_by_neighbor_counter = EventCounter( "n_find_neighbor", "#Particles found through neighbor") self.find_by_vertex_counter = EventCounter( "n_find_by_vertex", "#Particles found by vertex") self.find_global_counter = EventCounter( "n_find_global", "#Particles found by global search") def make_state(self): state = PicState(self) state.particle_number_shift_signaller.subscribe_with_state(self.depositor) state.particle_number_shift_signaller.subscribe_with_state(self.pusher) return state def get_dimensionality_suffix(self): return "%dd%dv" % (self.dimensions_pos, self.dimensions_velocity) def get_shape_function_class(self): from pyrticle.tools import \ PolynomialShapeFunction, \ CInfinityShapeFunction from pyrticle._internal import get_shape_function_name name = get_shape_function_name() if name == "c_infinity": return CInfinityShapeFunction elif name == "polynomial": return PolynomialShapeFunction else: raise ValueError, "unknown shape function class" def set_ignore_core_warnings(self, ignore): from pyrticle.tools import WarningForwarder, WarningIgnorer import pyrticle.tools del pyrticle.tools.warning_forwarder if ignore: pyrticle.tools.warning_forwarder = WarningIgnorer() else: pyrticle.tools.warning_forwarder = WarningForwarder() def add_instrumentation(self, mgr, observer): mgr.add_quantity(self.find_el_timer) mgr.add_quantity(self.find_same_counter) mgr.add_quantity(self.find_by_neighbor_counter) mgr.add_quantity(self.find_by_vertex_counter) mgr.add_quantity(self.find_global_counter) self.depositor.add_instrumentation(mgr, observer) self.pusher.add_instrumentation(mgr, observer) def velocities(self, state): try: return state.derived_quantity_cache["velocities"] except KeyError: result = _internal.get_velocities( state.particle_state, self.units.VACUUM_LIGHT_SPEED()) state.derived_quantity_cache["velocities"] = result return result def mean_beta(self, state): if len(state): return numpy.average(self.velocities(state), axis=0) \ / self.units.VACUUM_LIGHT_SPEED() else: return numpy.zeros((self.dimensions_velocity,)) def add_particles(self, state, iterable, maxcount=None): """Add the particles from C{iterable} to the cloud. C{iterable} is expected to yield tuples C{(position, velocity, charge, mass)}. If C{maxcount} is specified, maximally C{maxcount} particles are obtained from the iterable. """ pstate = state.particle_state if maxcount is not None: if pstate.particle_count+maxcount >= len(pstate.containing_elements): state.resize(pstate.particle_count+maxcount) for pos, vel, charge, mass in iterable: if maxcount is not None: if maxcount == 0: break maxcount -= 1 assert len(pos) == self.dimensions_pos assert len(vel) == self.dimensions_velocity pos = numpy.asarray(pos) vel = numpy.asarray(vel) mom = mass*self.units.gamma_from_v(vel)*vel cont_el = self.mesh_data.find_containing_element(pos) if cont_el == MeshData.INVALID_ELEMENT: print "not in valid element" continue if pstate.particle_count >= len(pstate.containing_elements): state.resize(max(128, 2*pstate.particle_count)) pstate.containing_elements[pstate.particle_count] = cont_el pstate.positions[pstate.particle_count] = pos pstate.momenta[pstate.particle_count] = mom pstate.charges[pstate.particle_count] = charge pstate.masses[pstate.particle_count] = mass pstate.particle_count += 1 self.check_containment(state) state.particle_number_shift_signaller.note_change_size( pstate.particle_count) state.derived_quantity_cache.clear() def check_containment(self, state): """Check that a containing element is known for each particle. This is a new invariant as of 1/17/08, and violations of this end up segfaulting, which we should avoid. """ assert (state.particle_state.containing_elements[:len(state)] != MeshData.INVALID_ELEMENT).all() def upkeep(self, state): """Perform any operations must fall in between timesteps, such as resampling or deleting particles. """ self.depositor.upkeep(state) self.pusher.upkeep(state) state.vis_listener.clear() # deposition ---------------------------------------------------------- def deposit_densities(self, state): """Return a tuple (charge_density, current_densities), where current_densities is an d-by-n array, where d is the number of velocity dimensions, and n is the discretization nodes. """ def all_getter(): rho, j = self.depositor.deposit_densities(state, self.velocities()) j = numpy.asarray(j.T, order="C") return rho, j return state.get_derived_quantities_from_cache( ["rho", "j"], [self.deposit_rho, self.deposit_j], all_getter) def deposit_j(self, state): """Return a the current densities as an d-by-n array, where d is the number of velocity dimensions, and n is the number of discretization nodes. """ def j_getter(): return numpy.asarray( self.depositor.deposit_j( state, self.velocities(state)) .T, order="C") return state.get_derived_quantity_from_cache("j", j_getter) def deposit_rho(self, state): """Return a the charge_density as a volume vector.""" def rho_getter(): return self.depositor.deposit_rho(state) return state.get_derived_quantity_from_cache("rho", rho_getter) # time advance ------------------------------------------------------------ def advance_state(self, state, dx, dp, ddep): pstate = state.particle_state cnt = pstate.particle_count positions = pstate.positions.copy() momenta = pstate.momenta.copy() positions[:cnt] += dx momenta[:cnt] += dp new_state = PicState( self, particle_count=cnt, containing_elements=pstate.containing_elements, positions=positions, momenta=momenta, charges=pstate.charges, masses=pstate.masses, depositor_state=self.depositor.advance_state( state, ddep), pusher_state=self.pusher.advance_state(state), pnss=state.particle_number_shift_signaller, vis_listener=state.vis_listener, ) from pyrticle._internal import FindEventCounters find_counters = FindEventCounters() class BHitListener(_internal.BoundaryHitListener): def note_boundary_hit(subself, pn): _internal.kill_particle( new_state.particle_state, pn, new_state.particle_number_shift_signaller) from pyrticle._internal import update_containing_elements sub_timer = self.find_el_timer.start_sub_timer() update_containing_elements( self.mesh_data, new_state.particle_state, BHitListener(), find_counters) sub_timer.stop().submit() self.find_same_counter.transfer( find_counters.find_same) self.find_by_neighbor_counter.transfer( find_counters.find_by_neighbor) self.find_by_vertex_counter.transfer( find_counters.find_by_vertex) self.find_global_counter.transfer( find_counters.find_global) return new_state # visualization ----------------------------------------------------------- def get_mesh_vis_vars(self): return self.vis_listener.mesh_vis_map.items() def add_to_vis(self, visualizer, vis_file, state, time=None, step=None, beamaxis=None, vis_listener=None): from hedge.visualization import VtkVisualizer, SiloVisualizer if isinstance(visualizer, VtkVisualizer): return self._add_to_vtk(visualizer, vis_file, state, time, step) elif isinstance(visualizer, SiloVisualizer): return self._add_to_silo(visualizer, vis_file, state, time, step, beamaxis, vis_listener) else: raise ValueError, "unknown visualizer type `%s'" % type(visualizer) def _add_to_silo(self, visualizer, db, state, time, step, beamaxis, vis_listener=None): from pylo import DBOPT_DTIME, DBOPT_CYCLE optlist = {} if time is not None: optlist[DBOPT_DTIME] = time if step is not None: optlist[DBOPT_CYCLE] = step pcount = len(state) if pcount: # real-space ------------------------------------------------------ db.put_pointmesh("particles", numpy.asarray(state.positions.T, order="C"), optlist) db.put_pointvar1("charge", "particles", state.charges) db.put_pointvar1("mass", "particles", state.masses) db.put_pointvar("momentum", "particles", numpy.asarray(state.momenta.T, order="C")) db.put_pointvar("velocity", "particles", numpy.asarray(self.velocities(state).T, order="C")) if vis_listener is not None: for name, value in self.vis_listener.particle_vis_map.iteritems(): from pyrticle.tools import NumberShiftableVector value = NumberShiftableVector.unwrap(value) dim, remainder = divmod(len(value), pcount) assert remainder == 0, ( "particle vis value '%s' had invalid number of entries: " "%d (#particles=%d)" % (name, len(value), pcount)) if dim == 1: db.put_pointvar1(name, "particles", value) else: db.put_pointvar(name, "particles", [value[i::dim] for i in range(dim)]) # phase-space ----------------------------------------------------- axes_names = ["x", "y", "z"] if beamaxis is not None: for axis in range(min(self.dimensions_pos, self.dimensions_velocity)): if axis == beamaxis: continue axname = axes_names[axis] db.put_defvars("phasespace_%s" % axname, [ ("part_%s" % axname, "coord(particles)[%d]" % axis), ("part_%s_prime" % axname, "momentum[%d]/momentum[%d]" % (axis, beamaxis)), ("part_%s_momentum" % axname, "momentum[%d]" % (axis)), ])
class AdvectiveDepositor(Depositor): name = "Advective" def __init__( self, activation_threshold=1e-5, kill_threshold=1e-3, filter_amp=None, filter_order=None, upwind_alpha=1, ): Depositor.__init__(self) self.activation_threshold = activation_threshold self.kill_threshold = kill_threshold self.upwind_alpha = upwind_alpha self.shape_function = None self.filter_amp = filter_amp self.filter_order = filter_order if filter_amp is not None: from hedge.discretization import ExponentialFilterResponseFunction self.filter_response = ExponentialFilterResponseFunction( filter_amp, filter_order) else: self.filter_response = None def initialize(self, method): Depositor.initialize(self, method) discr = method.discretization eg, = discr.element_groups fg, = discr.face_groups ldis = eg.local_discretization from hedge.mesh import TAG_ALL bdry = discr.get_boundary(TAG_ALL) bdry_fg, = bdry.face_groups if self.filter_response: from hedge.discretization import Filter filter = Filter(discr, self.filter_response) filter_mat, = filter.filter_matrices else: filter_mat = numpy.zeros((0, 0)) backend_class = getattr( _internal, "AdvectiveDepositor" + method.get_dimensionality_suffix()) self.backend = backend_class(method.mesh_data, len(ldis.face_indices()), ldis.node_count(), ldis.mass_matrix(), ldis.inverse_mass_matrix(), filter_mat, ldis.face_mass_matrix(), fg, bdry_fg, self.activation_threshold, self.kill_threshold, self.upwind_alpha) for i, diffmat in enumerate(ldis.differentiation_matrices()): self.backend.add_local_diff_matrix(i, diffmat) def make_state(self, state): state = self.backend.DepositorState() from pyrticle.tools import NumberShiftMultiplexer state.rho_dof_shift_listener = NumberShiftMultiplexer( name="advective_rho_dofs") eg, = self.method.discretization.element_groups ldis = eg.local_discretization #state.resize_rho(eg.local_discretization.node_count() * 1024) return state def add_instrumentation(self, mgr, observer): Depositor.add_instrumentation(self, mgr, observer) # instrumentation from pytools.log import IntervalTimer, EventCounter self.element_activation_counter = EventCounter( "n_el_activations", "#Advective rec. elements activated this timestep") self.element_kill_counter = EventCounter( "n_el_kills", "#Advective rec. elements retired this timestep") self.advective_rhs_timer = IntervalTimer( "t_advective_rhs", "Time spent evaluating advective RHS") self.active_elements_log = ActiveAdvectiveElements(observer) mgr.add_quantity(self.element_activation_counter) mgr.add_quantity(self.element_kill_counter) mgr.add_quantity(self.advective_rhs_timer) mgr.add_quantity(self.active_elements_log) mgr.set_constant("el_activation_threshold", self.activation_threshold) mgr.set_constant("el_kill_threshold", self.kill_threshold) mgr.set_constant("adv_upwind_alpha", self.upwind_alpha) mgr.set_constant("filter_amp", self.filter_amp) mgr.set_constant("filter_amp", self.filter_order) def set_shape_function(self, state, sf): Depositor.set_shape_function(self, state, sf) state.depositor_state.clear() for pn in xrange(len(state)): self.backend.add_advective_particle(state.depositor_state, state.particle_state, sf, pn) def note_move(self, state, orig, dest, size): self.backend.note_move(state.depositor_state, orig, dest, size) def note_change_size(self, state, new_size): self.backend.note_change_size(state.depositor_state, new_size) if (self.shape_function is not None and new_size > state.depositor_state.count_advective_particles()): for pn in range(state.depositor_state.count_advective_particles(), new_size): self.backend.add_advective_particle(state.depositor_state, state.particle_state, self.shape_function, pn) def clear_particles(self): Depositor.clear_particles(self) self.cloud.pic_algorithm.clear_advective_particles() def upkeep(self, state): self.backend.perform_depositor_upkeep(state.depositor_state, state.particle_state) def rhs(self, state): from pyrticle.tools import NumberShiftableVector sub_timer = self.advective_rhs_timer.start_sub_timer() result = NumberShiftableVector( self.backend.get_advective_particle_rhs( state.depositor_state, state.particle_state, self.method.velocities(state)), signaller=state.depositor_state.rho_dof_shift_listener) sub_timer.stop() self.element_activation_counter.transfer( state.depositor_state.element_activation_counter) self.element_kill_counter.transfer( state.depositor_state.element_kill_counter) return result def advance_state(self, state, rhs): # depositor states tend to linger on for a bit--ours here are # big, so they need to go. from gc import collect collect() from pyrticle.tools import NumberShiftableVector return self.backend.apply_advective_particle_rhs( state.depositor_state, state.particle_state, NumberShiftableVector.unwrap(rhs), state.depositor_state.rho_dof_shift_listener)
class AdvectiveDepositor(Depositor): name = "Advective" def __init__(self, activation_threshold=1e-5, kill_threshold=1e-3, filter_amp=None, filter_order=None, upwind_alpha=1, ): Depositor.__init__(self) self.activation_threshold = activation_threshold self.kill_threshold = kill_threshold self.upwind_alpha = upwind_alpha self.shape_function = None self.filter_amp = filter_amp self.filter_order = filter_order if filter_amp is not None: from hedge.discretization import ExponentialFilterResponseFunction self.filter_response = ExponentialFilterResponseFunction( filter_amp, filter_order) else: self.filter_response = None def initialize(self, method): Depositor.initialize(self, method) discr = method.discretization eg, = discr.element_groups fg, = discr.face_groups ldis = eg.local_discretization from hedge.mesh import TAG_ALL bdry = discr.get_boundary(TAG_ALL) bdry_fg, = bdry.face_groups if self.filter_response: from hedge.discretization import Filter filter = Filter(discr, self.filter_response) filter_mat, = filter.filter_matrices else: filter_mat = numpy.zeros((0,0)) backend_class = getattr(_internal, "AdvectiveDepositor" + method.get_dimensionality_suffix()) self.backend = backend_class(method.mesh_data, len(ldis.face_indices()), ldis.node_count(), ldis.mass_matrix(), ldis.inverse_mass_matrix(), filter_mat, ldis.face_mass_matrix(), fg, bdry_fg, self.activation_threshold, self.kill_threshold, self.upwind_alpha) for i, diffmat in enumerate(ldis.differentiation_matrices()): self.backend.add_local_diff_matrix(i, diffmat) def make_state(self, state): state = self.backend.DepositorState() from pyrticle.tools import NumberShiftMultiplexer state.rho_dof_shift_listener = NumberShiftMultiplexer( name="advective_rho_dofs") eg, = self.method.discretization.element_groups ldis = eg.local_discretization #state.resize_rho(eg.local_discretization.node_count() * 1024) return state def add_instrumentation(self, mgr, observer): Depositor.add_instrumentation(self, mgr, observer) # instrumentation from pytools.log import IntervalTimer, EventCounter self.element_activation_counter = EventCounter( "n_el_activations", "#Advective rec. elements activated this timestep") self.element_kill_counter = EventCounter( "n_el_kills", "#Advective rec. elements retired this timestep") self.advective_rhs_timer = IntervalTimer( "t_advective_rhs", "Time spent evaluating advective RHS") self.active_elements_log = ActiveAdvectiveElements(observer) mgr.add_quantity(self.element_activation_counter) mgr.add_quantity(self.element_kill_counter) mgr.add_quantity(self.advective_rhs_timer) mgr.add_quantity(self.active_elements_log) mgr.set_constant("el_activation_threshold", self.activation_threshold) mgr.set_constant("el_kill_threshold", self.kill_threshold) mgr.set_constant("adv_upwind_alpha", self.upwind_alpha) mgr.set_constant("filter_amp", self.filter_amp) mgr.set_constant("filter_amp", self.filter_order) def set_shape_function(self, state, sf): Depositor.set_shape_function(self, state, sf) state.depositor_state.clear() for pn in xrange(len(state)): self.backend.add_advective_particle( state.depositor_state, state.particle_state, sf, pn) def note_move(self, state, orig, dest, size): self.backend.note_move(state.depositor_state, orig, dest, size) def note_change_size(self, state, new_size): self.backend.note_change_size(state.depositor_state, new_size) if (self.shape_function is not None and new_size > state.depositor_state.count_advective_particles()): for pn in range( state.depositor_state.count_advective_particles(), new_size): self.backend.add_advective_particle( state.depositor_state, state.particle_state, self.shape_function, pn) def clear_particles(self): Depositor.clear_particles(self) self.cloud.pic_algorithm.clear_advective_particles() def upkeep(self, state): self.backend.perform_depositor_upkeep( state.depositor_state, state.particle_state) def rhs(self, state): from pyrticle.tools import NumberShiftableVector sub_timer = self.advective_rhs_timer.start_sub_timer() result = NumberShiftableVector( self.backend.get_advective_particle_rhs( state.depositor_state, state.particle_state, self.method.velocities(state)), signaller=state.depositor_state.rho_dof_shift_listener ) sub_timer.stop() self.element_activation_counter.transfer( state.depositor_state.element_activation_counter) self.element_kill_counter.transfer( state.depositor_state.element_kill_counter) return result def advance_state(self, state, rhs): # depositor states tend to linger on for a bit--ours here are # big, so they need to go. from gc import collect collect() from pyrticle.tools import NumberShiftableVector return self.backend.apply_advective_particle_rhs( state.depositor_state, state.particle_state, NumberShiftableVector.unwrap(rhs), state.depositor_state.rho_dof_shift_listener)