def split_eh(self, w): "Splits an array into E and H components" e_idx, h_idx = self.partial_to_eh_subsets() e, h = w[e_idx], w[h_idx] from hedge.flux import FluxVectorPlaceholder as FVP if isinstance(w, FVP): return FVP(scalars=e), FVP(scalars=h) else: return make_obj_array(e), make_obj_array(h)
def split_vars(self, w): "Splits an array into U and V components" dim = self.dimensions u, v = w[:dim], w[dim:] from hedge.flux import FluxVectorPlaceholder as FVP if isinstance(w, FVP): return FVP(scalars=u), FVP(scalars=v) else: return make_obj_array(u), make_obj_array(v)
def split_eps_mu_eh(self, w): """Splits an array into epsilon, mu, E and H components. Only used for fluxes. """ e_idx, h_idx = self.partial_to_eh_subsets() epsilon, mu, e, h = w[[0]], w[[1]], w[e_idx+2], w[h_idx+2] from hedge.flux import FluxVectorPlaceholder as FVP if isinstance(w, FVP): return FVP(scalars=epsilon), FVP(scalars=mu), FVP(scalars=e), FVP(scalars=h) else: return epsilon, mu, make_obj_array(e), make_obj_array(h)
def split_eps_mu_eh(self, w): """Splits an array into epsilon, mu, E and H components. Only used for fluxes. """ e_idx, h_idx = self.partial_to_eh_subsets() epsilon, mu, e, h = w[[0]], w[[1]], w[e_idx + 2], w[h_idx + 2] from hedge.flux import FluxVectorPlaceholder as FVP if isinstance(w, FVP): return (FVP(scalars=epsilon), FVP(scalars=mu), FVP(scalars=e), FVP(scalars=h)) else: return epsilon, mu, make_obj_array(e), make_obj_array(h)
def coefficients_from_boxes(self, discr, inner_bbox, outer_bbox=None, magnitude=None, tau_magnitude=None, exponent=None, dtype=None): if outer_bbox is None: outer_bbox = discr.mesh.bounding_box() if exponent is None: exponent = 2 if magnitude is None: magnitude = 20 if tau_magnitude is None: tau_magnitude = 0.4 # scale by free space conductivity from math import sqrt magnitude = magnitude * sqrt(self.epsilon / self.mu) tau_magnitude = tau_magnitude * sqrt(self.epsilon / self.mu) i_min, i_max = inner_bbox o_min, o_max = outer_bbox from hedge.tools import make_obj_array nodes = discr.nodes if dtype is not None: nodes = nodes.astype(dtype) sigma, sigma_prime, tau = zip(*[ self._construct_scalar_coefficients( discr, nodes[:, i], i_min[i], i_max[i], o_min[i], o_max[i], exponent) for i in range(discr.dimensions) ]) def conv(f): return discr.convert_volume(f, kind=discr.compute_kind, dtype=discr.default_scalar_type) return self.PMLCoefficients( sigma=conv(magnitude * make_obj_array(sigma)), sigma_prime=conv(magnitude * make_obj_array(sigma_prime)), tau=conv(tau_magnitude * make_obj_array(tau)))
def get_volume_nodes(self, discr): from hedge.tools import make_obj_array return discr.convert_volume(make_obj_array([ numpy.array(discr.nodes[:, i], dtype=discr.default_scalar_type) for i in range(discr.dimensions) ]), kind=discr.compute_kind)
def volume_interpolant(self, t, discr): from hedge.tools import make_obj_array return make_obj_array([ self.vol_0, self.vol_0, sph_dipole.source_modulation(t)*self.num_sf ])
def get_volume_nodes(self, discr): from hedge.tools import make_obj_array return discr.convert_volume( make_obj_array([ numpy.array(discr.nodes[:, i], dtype=discr.default_scalar_type) for i in range(discr.dimensions)]), kind=discr.compute_kind)
def __call__(self, ys, t, rhss): """ :param rhss: Matrix of right-hand sides, stored in row-major order, i.e. *[f2f, s2f, f2s, s2s]*. """ from hedge.tools import make_obj_array def finish_startup(): # we're done starting up, pack data into split histories for i, hn in enumerate(HIST_NAMES): hist = self.startup_history if not self.hist_is_fast[hn]: hist = hist[::self.substep_count] hist = hist[:self.orders[hn]] self.histories[hn] = [hist_entry[i] for hist_entry in hist] assert len(self.histories[hn]) == self.orders[hn] # here's some memory we won't need any more self.startup_stepper = None del self.startup_history def combined_rhs(t, y): y_fast, y_slow = y return make_obj_array( [rhs(t, lambda: y_fast, lambda: y_slow) for rhs in rhss]) def combined_summed_rhs(t, y): return numpy.sum(combined_rhs(t, y).reshape((2, 2), order="C"), axis=1) if self.startup_stepper is not None: ys = make_obj_array(ys) if self.max_order == 1: # we're running forward Euler, no need for the startup stepper assert not self.startup_history self.startup_history.append(combined_rhs(t, ys)) finish_startup() return self.run_ab(ys, t, rhss) for i in range(self.substep_count): ys = self.startup_stepper(ys, t + i * self.small_dt, self.small_dt, combined_summed_rhs) self.startup_history.insert( 0, combined_rhs(t + (i + 1) * self.small_dt, ys)) if len(self.startup_history ) == self.max_order * self.substep_count: finish_startup() return ys else: return self.run_ab(ys, t, rhss)
def coefficients_from_boxes(self, discr, inner_bbox, outer_bbox=None, magnitude=None, tau_magnitude=None, exponent=None, dtype=None): if outer_bbox is None: outer_bbox = discr.mesh.bounding_box() if exponent is None: exponent = 2 if magnitude is None: magnitude = 20 if tau_magnitude is None: tau_magnitude = 0.4 # scale by free space conductivity from math import sqrt magnitude = magnitude*sqrt(self.epsilon/self.mu) tau_magnitude = tau_magnitude*sqrt(self.epsilon/self.mu) i_min, i_max = inner_bbox o_min, o_max = outer_bbox from hedge.tools import make_obj_array nodes = discr.nodes if dtype is not None: nodes = nodes.astype(dtype) sigma, sigma_prime, tau = zip(*[self._construct_scalar_coefficients( discr, nodes[:,i], i_min[i], i_max[i], o_min[i], o_max[i], exponent) for i in range(discr.dimensions)]) def conv(f): return discr.convert_volume(f, kind=discr.compute_kind, dtype=discr.default_scalar_type) return self.PMLCoefficients( sigma=conv(magnitude*make_obj_array(sigma)), sigma_prime=conv(magnitude*make_obj_array(sigma_prime)), tau=conv(tau_magnitude*make_obj_array(tau)))
def get_boundary_nodes(self, discr, tag): from hedge.tools import make_obj_array bnodes = discr.get_boundary(tag).nodes nodes = discr.convert_boundary(make_obj_array([ numpy.array(bnodes[:, i], dtype=discr.default_scalar_type) for i in range(discr.dimensions) ]), tag, kind=discr.compute_kind) return nodes
def get_boundary_nodes(self, discr, tag): from hedge.tools import make_obj_array bnodes = discr.get_boundary(tag).nodes nodes = discr.convert_boundary( make_obj_array([ numpy.array(bnodes[:, i], dtype=discr.default_scalar_type) for i in range(discr.dimensions)]), tag, kind=discr.compute_kind) return nodes
def volume_interpolant(self, t, discr): from hedge.tools import make_obj_array result = discr.volume_zeros(kind="numpy", dtype=numpy.float64) omega = 6*c if omega*t > 2*pi: return make_obj_array([result, result, result]) x = make_obj_array(discr.nodes.T) r = numpy.sqrt(numpy.dot(x, x)) idx = r<0.3 result[idx] = (1+numpy.cos(pi*r/0.3))[idx] \ *numpy.sin(omega*t)**3 result = discr.convert_volume(result, kind=discr.compute_kind, dtype=discr.default_scalar_type) return make_obj_array([-result, result, result])
def rhs(t, fields_and_state): fields, ts_state = fields_and_state state_f = lambda: ts_state.state fields_f = lambda: fields fields_rhs = (self.f_rhs_calculator(t, fields_f, state_f) + self.p2f_rhs_calculator(t, fields_f, state_f)) state_rhs = (self.p_rhs_calculator(t, fields_f, state_f) + self.f2p_rhs_calculator(t, fields_f, state_f)) return make_obj_array([fields_rhs, state_rhs])
def volume_interpolant(self, t, discr): from hedge.tools import make_obj_array result = discr.volume_zeros(kind="numpy", dtype=np.float64) omega = 6 * c if omega * t > 2 * pi: return make_obj_array([result, result, result]) x = make_obj_array(discr.nodes.T) r = np.sqrt(np.dot(x, x)) idx = r < 0.3 result[idx] = (1+np.cos(pi*r/0.3))[idx] \ *np.sin(omega*t)**3 result = discr.convert_volume(result, kind=discr.compute_kind, dtype=discr.default_scalar_type) return make_obj_array([-result, result, result])
def __call__(self, ys, t, rhss): """ :param rhss: Matrix of right-hand sides, stored in row-major order, i.e. *[f2f, s2f, f2s, s2s]*. """ from hedge.tools import make_obj_array def finish_startup(): # we're done starting up, pack data into split histories for i, hn in enumerate(HIST_NAMES): hist = self.startup_history if not self.hist_is_fast[hn]: hist = hist[:: self.substep_count] hist = hist[: self.orders[hn]] self.histories[hn] = [hist_entry[i] for hist_entry in hist] assert len(self.histories[hn]) == self.orders[hn] # here's some memory we won't need any more self.startup_stepper = None del self.startup_history def combined_rhs(t, y): y_fast, y_slow = y return make_obj_array([rhs(t, lambda: y_fast, lambda: y_slow) for rhs in rhss]) def combined_summed_rhs(t, y): return numpy.sum(combined_rhs(t, y).reshape((2, 2), order="C"), axis=1) if self.startup_stepper is not None: ys = make_obj_array(ys) if self.max_order == 1: # we're running forward Euler, no need for the startup stepper assert not self.startup_history self.startup_history.append(combined_rhs(t, ys)) finish_startup() return self.run_ab(ys, t, rhss) for i in range(self.substep_count): ys = self.startup_stepper(ys, t + i * self.small_dt, self.small_dt, combined_summed_rhs) self.startup_history.insert(0, combined_rhs(t + (i + 1) * self.small_dt, ys)) if len(self.startup_history) == self.max_order * self.substep_count: finish_startup() return ys else: return self.run_ab(ys, t, rhss)
def rhs(t, fields_and_state): fields, ts_state = fields_and_state state_f = lambda: ts_state.state fields_f = lambda: fields fields_rhs = ( self.f_rhs_calculator(t, fields_f, state_f) + self.p2f_rhs_calculator(t, fields_f, state_f)) state_rhs = ( self.p_rhs_calculator(t, fields_f, state_f) + self.f2p_rhs_calculator(t, fields_f, state_f)) return make_obj_array([fields_rhs, state_rhs])
def initial_val(discr): # the initial solution for the TE_10-like mode def initial_Hz(x, el): from math import cos, sin if el in material_elements["vacuum"]: return h*cos(h*x[0]) else: return -l*sin(h*d)/sin(l*(a-d))*cos(l*(a-x[0])) from hedge.tools import make_obj_array result_zero = discr.volume_zeros(kind="numpy", dtype=numpy.float64) H_z = make_tdep_given(initial_Hz).volume_interpolant(0, discr) return make_obj_array([result_zero, result_zero, H_z])
def __call__(self, t, fields_f, state_f): state = state_f() velocities = self.method.velocities(state) from pyrticle.tools import NumberShiftableVector from hedge.tools import make_obj_array result = make_obj_array([ NumberShiftableVector( velocities, signaller=state.particle_number_shift_signaller), 0, self.method.depositor.rhs(state) ]) return result
def __call__(self, t, fields_f, state_f): state = state_f() velocities = self.method.velocities(state) from pyrticle.tools import NumberShiftableVector from hedge.tools import make_obj_array result = make_obj_array([ NumberShiftableVector(velocities, signaller=state.particle_number_shift_signaller), 0, self.method.depositor.rhs(state) ]) return result
def dirichlet_bc(self, w=None): """ Flux term for dirichlet (displacement) boundary conditions """ u, v = self.split_vars(self.field_placeholder(w)) if self.dirichlet_bc_data is not None: from hedge.optemplate import make_vector_field dir_field = cse( -make_vector_field("dirichlet_bc", 3)) else: dir_field = make_obj_array([0,]*3) from hedge.tools import join_fields return join_fields(dir_field, [0]*3, [0,]*9)
def __call__(self, t, fields_f, state_f): from pyrticle._internal import ZeroVector fields = fields_f() state = state_f() e, h = self.maxwell_op.split_eh(fields) # assemble field_args of the form [ex,ey,ez] and [bx,by,bz], # inserting ZeroVectors where necessary. idx = 0 e_arg = [] for use_component in self.maxwell_op.get_eh_subset()[0:3]: if use_component: e_arg.append(e[idx]) idx += 1 else: e_arg.append(ZeroVector()) idx = 0 b_arg = [] for use_component in self.maxwell_op.get_eh_subset()[3:6]: if use_component: b_arg.append(self.maxwell_op.mu * h[idx]) idx += 1 else: b_arg.append(ZeroVector()) field_args = tuple(e_arg) + tuple(b_arg) velocities = self.method.velocities(state) # compute forces forces = self.method.pusher.forces( state, velocities, *field_args) from pyrticle.tools import NumberShiftableVector from hedge.tools import make_obj_array result = make_obj_array([ 0, NumberShiftableVector(forces, signaller=state.particle_number_shift_signaller), 0]) return result
def calculate_piola(self,u=None): from hedge.optemplate import make_nabla from hedge.optemplate import make_vector_field u = make_vector_field('u', 3) nabla = make_nabla(self.dimensions) ij = 0 F = [0,]*9 for i in range(self.dimensions): for j in range(self.dimensions): F[ij] = nabla[i](u[j]) if i == j: F[ij] = F[ij] + 1 ij = ij + 1 return make_obj_array(self.material.stress(F, self.dimensions))
def __call__(self, t, x_vec): ones = numpy.ones_like(x_vec[0]) rho_field = ones*self.rho if self.gaussian_pulse_at is not None: rel_to_pulse = [x_vec[i] - self.gaussian_pulse_at[i] for i in range(len(x_vec))] rho_field += self.pulse_magnitude * self.rho * numpy.exp( - sum(rtp_i**2 for rtp_i in rel_to_pulse)/2) direction = self.direction_vector(x_vec.shape[0]) from hedge.tools import make_obj_array u_field = make_obj_array([ones*self.velocity*dir_i for dir_i in direction]) from hedge.tools import join_fields return join_fields(rho_field, self.e*ones, self.rho*u_field)
def __call__(self, t, x_vec): ones = numpy.ones_like(x_vec[0]) rho_field = ones * self.rho if self.gaussian_pulse_at is not None: rel_to_pulse = [ x_vec[i] - self.gaussian_pulse_at[i] for i in range(len(x_vec)) ] rho_field += self.pulse_magnitude * self.rho * numpy.exp( -sum(rtp_i**2 for rtp_i in rel_to_pulse) / 2) direction = self.direction_vector(x_vec.shape[0]) from hedge.tools import make_obj_array u_field = make_obj_array( [ones * self.velocity * dir_i for dir_i in direction]) from hedge.tools import join_fields return join_fields(rho_field, self.e * ones, self.rho * u_field)
def __call__(self, t, fields_f, state_f): from pyrticle._internal import ZeroVector fields = fields_f() state = state_f() e, h = self.maxwell_op.split_eh(fields) # assemble field_args of the form [ex,ey,ez] and [bx,by,bz], # inserting ZeroVectors where necessary. idx = 0 e_arg = [] for use_component in self.maxwell_op.get_eh_subset()[0:3]: if use_component: e_arg.append(e[idx]) idx += 1 else: e_arg.append(ZeroVector()) idx = 0 b_arg = [] for use_component in self.maxwell_op.get_eh_subset()[3:6]: if use_component: b_arg.append(self.maxwell_op.mu * h[idx]) idx += 1 else: b_arg.append(ZeroVector()) field_args = tuple(e_arg) + tuple(b_arg) velocities = self.method.velocities(state) # compute forces forces = self.method.pusher.forces(state, velocities, *field_args) from pyrticle.tools import NumberShiftableVector from hedge.tools import make_obj_array result = make_obj_array([ 0, NumberShiftableVector( forces, signaller=state.particle_number_shift_signaller), 0 ]) return result
def incident_bc(self, w=None): "Flux terms for incident boundary conditions" # NOTE: Untested for inhomogeneous materials, but would usually be # physically meaningless anyway (are there exceptions to this?) e, h = self.split_eh(self.field_placeholder(w)) if not self.fixed_material: from warnings import warn if self.incident_tag != hedge.mesh.TAG_NONE: warn("Incident boundary conditions assume homogeneous" " background material, results may be unphysical") from hedge.tools import count_subset fld_cnt = count_subset(self.get_eh_subset()) from hedge.tools import is_zero incident_bc_data = self.incident_bc_data(self, e, h) if is_zero(incident_bc_data): return make_obj_array([0]*fld_cnt) else: return cse(-incident_bc_data)
def incident_bc(self, w=None): "Flux terms for incident boundary conditions" # NOTE: Untested for inhomogeneous materials, but would usually be # physically meaningless anyway (are there exceptions to this?) e, h = self.split_eh(self.field_placeholder(w)) if not self.fixed_material: from warnings import warn if self.incident_tag != hedge.mesh.TAG_NONE: warn("Incident boundary conditions assume homogeneous" " background material, results may be unphysical") from hedge.tools import count_subset fld_cnt = count_subset(self.get_eh_subset()) from hedge.tools import is_zero incident_bc_data = self.incident_bc_data(self, e, h) if is_zero(incident_bc_data): return make_obj_array([0] * fld_cnt) else: return cse(-incident_bc_data)
def incident_bc(self, w=None): "Flux terms for incident boundary conditions" # NOTE: Untested for inhomogeneous materials, but would usually be # physically meaningless anyway (are there exceptions to this?) e, h = self.split_eh(self.field_placeholder(w)) if not self.fixed_material: from warnings import warn if self.incident_tag != hedge.mesh.TAG_NONE: warn("Incident boundary conditions assume homogeneous"+ " background material, results may be unphysical") from hedge.tools import count_subset from hedge.tools import join_fields fld_cnt = count_subset(self.get_eh_subset()) if self.incident_bc_data is not None: from hedge.optemplate import make_vector_field inc_field = cse( -make_vector_field("incident_bc", fld_cnt)) else: inc_field = make_obj_array([0]*fld_cnt) return inc_field
def inner_run(self): t = 0 setup = self.setup setup.hook_startup(self) vis_order = setup.vis_order if vis_order is None: vis_order = setup.element_order if vis_order != setup.element_order: vis_discr = self.rcon.make_discretization(self.discr.mesh, order=vis_order, debug=setup.dg_debug) from hedge.discretization import Projector vis_proj = Projector(self.discr, vis_discr) else: vis_discr = self.discr def vis_proj(f): return f from hedge.visualization import SiloVisualizer vis = SiloVisualizer(vis_discr) fields = self.fields self.observer.set_fields_and_state(fields, self.state) from hedge.tools import make_obj_array from pyrticle.cloud import TimesteppablePicState def visualize(observer): sub_timer = self.vis_timer.start_sub_timer() import os.path visf = vis.make_file( os.path.join(setup.output_path, setup.vis_pattern % step)) self.method.add_to_vis(vis, visf, observer.state, time=t, step=step) vis.add_data( visf, [(name, vis_proj(fld)) for name, fld in setup.hook_vis_quantities(observer)], time=t, step=step) setup.hook_visualize(self, vis, visf, observer) visf.close() sub_timer.stop().submit() from hedge.timestep.multirate_ab import TwoRateAdamsBashforthTimeStepper if not isinstance(self.stepper, TwoRateAdamsBashforthTimeStepper): def rhs(t, fields_and_state): fields, ts_state = fields_and_state state_f = lambda: ts_state.state fields_f = lambda: fields fields_rhs = (self.f_rhs_calculator(t, fields_f, state_f) + self.p2f_rhs_calculator(t, fields_f, state_f)) state_rhs = (self.p_rhs_calculator(t, fields_f, state_f) + self.f2p_rhs_calculator(t, fields_f, state_f)) return make_obj_array([fields_rhs, state_rhs]) step_args = (self.dt, rhs) else: def add_unwrap(rhs): def unwrapping_rhs(t, fields, ts_state): return rhs(t, fields, lambda: ts_state().state) return unwrapping_rhs step_args = (( add_unwrap(self.f_rhs_calculator), add_unwrap(self.p2f_rhs_calculator), add_unwrap(self.f2p_rhs_calculator), add_unwrap(self.p_rhs_calculator), ), ) y = make_obj_array( [fields, TimesteppablePicState(self.method, self.state)]) del self.state try: from hedge.timestep import times_and_steps step_it = times_and_steps(max_steps=self.nsteps, logmgr=self.logmgr, max_dt_getter=lambda t: self.dt) for step, t, dt in step_it: self.method.upkeep(y[1].state) if step % setup.vis_interval == 0: visualize(self.observer) y = self.stepper(y, t, *step_args) fields, ts_state = y self.observer.set_fields_and_state(fields, ts_state.state) setup.hook_after_step(self, self.observer) finally: vis.close() self.discr.close() self.logmgr.save() setup.hook_when_done(self)
def combined_rhs(t, y): y_fast, y_slow = y return make_obj_array( [rhs(t, lambda: y_fast, lambda: y_slow) for rhs in rhss])
def volume_interpolant(self, t, discr): from hedge.tools import make_obj_array return make_obj_array([ self.vol_0, self.vol_0, sph_dipole.source_modulation(t) * self.num_sf ])
def make_nabla(dim): from hedge.tools import make_obj_array from hedge.optemplate import DifferentiationOperator return make_obj_array( [DifferentiationOperator(i) for i in range(dim)])
def inner_run(self): t = 0 setup = self.setup setup.hook_startup(self) vis_order = setup.vis_order if vis_order is None: vis_order = setup.element_order if vis_order != setup.element_order: vis_discr = self.rcon.make_discretization(self.discr.mesh, order=vis_order, debug=setup.dg_debug) from hedge.discretization import Projector vis_proj = Projector(self.discr, vis_discr) else: vis_discr = self.discr def vis_proj(f): return f from hedge.visualization import SiloVisualizer vis = SiloVisualizer(vis_discr) fields = self.fields self.observer.set_fields_and_state(fields, self.state) from hedge.tools import make_obj_array from pyrticle.cloud import TimesteppablePicState def visualize(observer): sub_timer = self.vis_timer.start_sub_timer() import os.path visf = vis.make_file(os.path.join( setup.output_path, setup.vis_pattern % step)) self.method.add_to_vis(vis, visf, observer.state, time=t, step=step) vis.add_data(visf, [(name, vis_proj(fld)) for name, fld in setup.hook_vis_quantities(observer)], time=t, step=step) setup.hook_visualize(self, vis, visf, observer) visf.close() sub_timer.stop().submit() from hedge.timestep.multirate_ab import TwoRateAdamsBashforthTimeStepper if not isinstance(self.stepper, TwoRateAdamsBashforthTimeStepper): def rhs(t, fields_and_state): fields, ts_state = fields_and_state state_f = lambda: ts_state.state fields_f = lambda: fields fields_rhs = ( self.f_rhs_calculator(t, fields_f, state_f) + self.p2f_rhs_calculator(t, fields_f, state_f)) state_rhs = ( self.p_rhs_calculator(t, fields_f, state_f) + self.f2p_rhs_calculator(t, fields_f, state_f)) return make_obj_array([fields_rhs, state_rhs]) step_args = (self.dt, rhs) else: def add_unwrap(rhs): def unwrapping_rhs(t, fields, ts_state): return rhs(t, fields, lambda: ts_state().state) return unwrapping_rhs step_args = (( add_unwrap(self.f_rhs_calculator), add_unwrap(self.p2f_rhs_calculator), add_unwrap(self.f2p_rhs_calculator), add_unwrap(self.p_rhs_calculator), ),) y = make_obj_array([ fields, TimesteppablePicState(self.method, self.state) ]) del self.state try: from hedge.timestep import times_and_steps step_it = times_and_steps( max_steps=self.nsteps, logmgr=self.logmgr, max_dt_getter=lambda t: self.dt) for step, t, dt in step_it: self.method.upkeep(y[1].state) if step % setup.vis_interval == 0: visualize(self.observer) y = self.stepper(y, t, *step_args) fields, ts_state = y self.observer.set_fields_and_state(fields, ts_state.state) setup.hook_after_step(self, self.observer) finally: vis.close() self.discr.close() self.logmgr.save() setup.hook_when_done(self)
def map_operator_binding(self, expr): from hedge.optemplate.operators import FluxOperatorBase from hedge.optemplate.primitives import BoundaryPair from hedge.flux import FluxSubstitutionMapper, FieldComponent if not (isinstance(expr.op, FluxOperatorBase) and isinstance(expr.field, BoundaryPair)): return IdentityMapper.map_operator_binding(self, expr) bpair = expr.field vol_field = bpair.field bdry_field = bpair.bfield flux = expr.op.flux bdry_dependencies = DependencyMapper( include_calls="descend_args", include_operator_bindings=True)(bdry_field) vol_dependencies = DependencyMapper( include_operator_bindings=True)(vol_field) vol_bdry_intersection = bdry_dependencies & vol_dependencies if vol_bdry_intersection: raise RuntimeError("Variables are being used as both " "boundary and volume quantities: %s" % ", ".join(str(v) for v in vol_bdry_intersection)) # Step 1: Find maximal flux-evaluable subexpression of boundary field # in given BoundaryPair. class MaxBoundaryFluxEvaluableExpressionFinder( IdentityMapper, OperatorReducerMixin): def __init__(self, vol_expr_list, expensive_bdry_op_detector): self.vol_expr_list = vol_expr_list self.vol_expr_to_idx = dict((vol_expr, idx) for idx, vol_expr in enumerate(vol_expr_list)) self.bdry_expr_list = [] self.bdry_expr_to_idx = {} self.expensive_bdry_op_detector = expensive_bdry_op_detector # {{{ expression registration def register_boundary_expr(self, expr): try: return self.bdry_expr_to_idx[expr] except KeyError: idx = len(self.bdry_expr_to_idx) self.bdry_expr_to_idx[expr] = idx self.bdry_expr_list.append(expr) return idx def register_volume_expr(self, expr): try: return self.vol_expr_to_idx[expr] except KeyError: idx = len(self.vol_expr_to_idx) self.vol_expr_to_idx[expr] = idx self.vol_expr_list.append(expr) return idx # }}} # {{{ map_xxx routines @memoize_method def map_common_subexpression(self, expr): # Here we need to decide whether this CSE should be turned into # a flux CSE or not. This is a good idea if the transformed # expression only contains "bare" volume or boundary # expressions. However, as soon as an operator is applied # somewhere in the subexpression, the CSE should not be touched # in order to avoid redundant evaluation of that operator. # # Observe that at the time of this writing (Feb 2010), the only # operators that may occur in boundary expressions are # quadrature-related. has_expensive_operators = \ self.expensive_bdry_op_detector(expr.child) if has_expensive_operators: return FieldComponent( self.register_boundary_expr(expr), is_interior=False) else: return IdentityMapper.map_common_subexpression(self, expr) def map_normal(self, expr): raise RuntimeError("Your operator template contains a flux normal. " "You may find this confusing, but you can't do that. " "It turns out that you need to use " "hedge.optemplate.make_normal() for normals in boundary " "terms of operator templates.") def map_normal_component(self, expr): if expr.boundary_tag != bpair.tag: raise RuntimeError("BoundaryNormalComponent and BoundaryPair " "do not agree about boundary tag: %s vs %s" % (expr.boundary_tag, bpair.tag)) from hedge.flux import Normal return Normal(expr.axis) def map_variable(self, expr): return FieldComponent( self.register_boundary_expr(expr), is_interior=False) map_subscript = map_variable def map_operator_binding(self, expr): from hedge.optemplate import (BoundarizeOperator, FluxExchangeOperator, QuadratureGridUpsampler, QuadratureBoundaryGridUpsampler) if isinstance(expr.op, BoundarizeOperator): if expr.op.tag != bpair.tag: raise RuntimeError("BoundarizeOperator and BoundaryPair " "do not agree about boundary tag: %s vs %s" % (expr.op.tag, bpair.tag)) return FieldComponent( self.register_volume_expr(expr.field), is_interior=True) elif isinstance(expr.op, FluxExchangeOperator): from hedge.mesh import TAG_RANK_BOUNDARY op_tag = TAG_RANK_BOUNDARY(expr.op.rank) if bpair.tag != op_tag: raise RuntimeError("BoundarizeOperator and FluxExchangeOperator " "do not agree about boundary tag: %s vs %s" % (op_tag, bpair.tag)) return FieldComponent( self.register_boundary_expr(expr), is_interior=False) elif isinstance(expr.op, QuadratureBoundaryGridUpsampler): if bpair.tag != expr.op.boundary_tag: raise RuntimeError("BoundarizeOperator " "and QuadratureBoundaryGridUpsampler " "do not agree about boundary tag: %s vs %s" % (expr.op.boundary_tag, bpair.tag)) return FieldComponent( self.register_boundary_expr(expr), is_interior=False) elif isinstance(expr.op, QuadratureGridUpsampler): # We're invoked before operator specialization, so we may # see these instead of QuadratureBoundaryGridUpsampler. return FieldComponent( self.register_boundary_expr(expr), is_interior=False) else: raise RuntimeError("Found '%s' in a boundary term. " "To the best of my knowledge, no hedge operator applies " "directly to boundary data, so this is likely in error." % expr.op) def map_flux_exchange(self, expr): return FieldComponent( self.register_boundary_expr(expr), is_interior=False) # }}} from hedge.tools import is_obj_array if not is_obj_array(vol_field): vol_field = [vol_field] mbfeef = MaxBoundaryFluxEvaluableExpressionFinder(list(vol_field), self.expensive_bdry_op_detector) #from hedge.optemplate.tools import pretty_print_optemplate #print pretty_print_optemplate(bdry_field) #raw_input("YO") new_bdry_field = mbfeef(bdry_field) # Step II: Substitute the new_bdry_field into the flux. def sub_bdry_into_flux(expr): if isinstance(expr, FieldComponent) and not expr.is_interior: if expr.index == 0 and not is_obj_array(bdry_field): return new_bdry_field else: return new_bdry_field[expr.index] else: return None new_flux = FluxSubstitutionMapper(sub_bdry_into_flux)(flux) from hedge.tools import is_zero, make_obj_array if is_zero(new_flux): return 0 else: return type(expr.op)(new_flux, *expr.op.__getinitargs__()[1:])( BoundaryPair( make_obj_array([self.rec(e) for e in mbfeef.vol_expr_list]), make_obj_array([self.rec(e) for e in mbfeef.bdry_expr_list]), bpair.tag))
def make_vec(basename): from hedge.tools import make_obj_array return make_obj_array( [var("%s%d" % (basename, i)) for i in range(self.dimensions)])
def combined_rhs(t, y): y_fast, y_slow = y return make_obj_array([rhs(t, lambda: y_fast, lambda: y_slow) for rhs in rhss])
def test_2d_gauss_theorem(): """Verify Gauss's theorem explicitly on a mesh""" from hedge.mesh.generator import make_disk_mesh from math import sin, cos from numpy import dot mesh = make_disk_mesh() order = 2 discr = discr_class(mesh, order=order, debug=discr_class.noninteractive_debug_flags()) ref_discr = discr_class(mesh, order=order) from hedge.flux import make_normal, FluxScalarPlaceholder normal = make_normal(discr.dimensions) flux_f_ph = FluxScalarPlaceholder(0) one_sided_x = flux_f_ph.int * normal[0] one_sided_y = flux_f_ph.int * normal[1] def f1(x, el): return sin(3 * x[0]) + cos(3 * x[1]) def f2(x, el): return sin(2 * x[0]) + cos(x[1]) from hedge.discretization import ones_on_volume ones = ones_on_volume(discr) f1_v = discr.interpolate_volume_function(f1) f2_v = discr.interpolate_volume_function(f2) from hedge.optemplate import BoundaryPair, Field, make_nabla, \ get_flux_operator nabla = make_nabla(discr.dimensions) divergence = nabla[0].apply(discr, f1_v) + nabla[1].apply(discr, f2_v) int_div = discr.integral(divergence) flux_optp = ( get_flux_operator(one_sided_x)(BoundaryPair(Field("f1"), Field("fz"))) + get_flux_operator(one_sided_y)(BoundaryPair(Field("f2"), Field("fz")))) from hedge.mesh import TAG_ALL bdry_val = discr.compile(flux_optp)(f1=f1_v, f2=f2_v, fz=discr.boundary_zeros(TAG_ALL)) ref_bdry_val = ref_discr.compile(flux_optp)( f1=f1_v, f2=f2_v, fz=discr.boundary_zeros(TAG_ALL)) boundary_int = dot(bdry_val, ones) if False: from hedge.visualization import SiloVisualizer vis = SiloVisualizer(discr) visf = vis.make_file("test") from hedge.tools import make_obj_array from hedge.mesh import TAG_ALL vis.add_data(visf, [ ("bdry", bdry_val), ("ref_bdry", ref_bdry_val), ("div", divergence), ("f", make_obj_array([f1_v, f2_v])), ("n", discr.volumize_boundary_field(discr.boundary_normals(TAG_ALL), TAG_ALL)), ], expressions=[("bdiff", "bdry-ref_bdry")]) #print abs(boundary_int-int_div) assert abs(boundary_int - int_div) < 5e-15
def map_operator_binding(self, expr): from hedge.optemplate.operators import FluxOperatorBase from hedge.optemplate.primitives import BoundaryPair from hedge.flux import FluxSubstitutionMapper, FieldComponent if not (isinstance(expr.op, FluxOperatorBase) and isinstance(expr.field, BoundaryPair)): return IdentityMapper.map_operator_binding(self, expr) bpair = expr.field vol_field = bpair.field bdry_field = bpair.bfield flux = expr.op.flux bdry_dependencies = DependencyMapper( include_calls="descend_args", include_operator_bindings=True)(bdry_field) vol_dependencies = DependencyMapper( include_operator_bindings=True)(vol_field) vol_bdry_intersection = bdry_dependencies & vol_dependencies if vol_bdry_intersection: raise RuntimeError( "Variables are being used as both " "boundary and volume quantities: %s" % ", ".join(str(v) for v in vol_bdry_intersection)) # Step 1: Find maximal flux-evaluable subexpression of boundary field # in given BoundaryPair. class MaxBoundaryFluxEvaluableExpressionFinder(IdentityMapper, OperatorReducerMixin): def __init__(self, vol_expr_list, expensive_bdry_op_detector): self.vol_expr_list = vol_expr_list self.vol_expr_to_idx = dict( (vol_expr, idx) for idx, vol_expr in enumerate(vol_expr_list)) self.bdry_expr_list = [] self.bdry_expr_to_idx = {} self.expensive_bdry_op_detector = expensive_bdry_op_detector # {{{ expression registration def register_boundary_expr(self, expr): try: return self.bdry_expr_to_idx[expr] except KeyError: idx = len(self.bdry_expr_to_idx) self.bdry_expr_to_idx[expr] = idx self.bdry_expr_list.append(expr) return idx def register_volume_expr(self, expr): try: return self.vol_expr_to_idx[expr] except KeyError: idx = len(self.vol_expr_to_idx) self.vol_expr_to_idx[expr] = idx self.vol_expr_list.append(expr) return idx # }}} # {{{ map_xxx routines @memoize_method def map_common_subexpression(self, expr): # Here we need to decide whether this CSE should be turned into # a flux CSE or not. This is a good idea if the transformed # expression only contains "bare" volume or boundary # expressions. However, as soon as an operator is applied # somewhere in the subexpression, the CSE should not be touched # in order to avoid redundant evaluation of that operator. # # Observe that at the time of this writing (Feb 2010), the only # operators that may occur in boundary expressions are # quadrature-related. has_expensive_operators = \ self.expensive_bdry_op_detector(expr.child) if has_expensive_operators: return FieldComponent(self.register_boundary_expr(expr), is_interior=False) else: return IdentityMapper.map_common_subexpression(self, expr) def map_normal(self, expr): raise RuntimeError( "Your operator template contains a flux normal. " "You may find this confusing, but you can't do that. " "It turns out that you need to use " "hedge.optemplate.make_normal() for normals in boundary " "terms of operator templates.") def map_normal_component(self, expr): if expr.boundary_tag != bpair.tag: raise RuntimeError( "BoundaryNormalComponent and BoundaryPair " "do not agree about boundary tag: %s vs %s" % (expr.boundary_tag, bpair.tag)) from hedge.flux import Normal return Normal(expr.axis) def map_variable(self, expr): return FieldComponent(self.register_boundary_expr(expr), is_interior=False) map_subscript = map_variable def map_operator_binding(self, expr): from hedge.optemplate import (BoundarizeOperator, FluxExchangeOperator, QuadratureGridUpsampler, QuadratureBoundaryGridUpsampler) if isinstance(expr.op, BoundarizeOperator): if expr.op.tag != bpair.tag: raise RuntimeError( "BoundarizeOperator and BoundaryPair " "do not agree about boundary tag: %s vs %s" % (expr.op.tag, bpair.tag)) return FieldComponent(self.register_volume_expr( expr.field), is_interior=True) elif isinstance(expr.op, FluxExchangeOperator): from hedge.mesh import TAG_RANK_BOUNDARY op_tag = TAG_RANK_BOUNDARY(expr.op.rank) if bpair.tag != op_tag: raise RuntimeError( "BoundarizeOperator and " "FluxExchangeOperator do not agree about " "boundary tag: %s vs %s" % (op_tag, bpair.tag)) return FieldComponent(self.register_boundary_expr(expr), is_interior=False) elif isinstance(expr.op, QuadratureBoundaryGridUpsampler): if bpair.tag != expr.op.boundary_tag: raise RuntimeError( "BoundarizeOperator " "and QuadratureBoundaryGridUpsampler " "do not agree about boundary tag: %s vs %s" % (expr.op.boundary_tag, bpair.tag)) return FieldComponent(self.register_boundary_expr(expr), is_interior=False) elif isinstance(expr.op, QuadratureGridUpsampler): # We're invoked before operator specialization, so we may # see these instead of QuadratureBoundaryGridUpsampler. return FieldComponent(self.register_boundary_expr(expr), is_interior=False) else: raise RuntimeError( "Found '%s' in a boundary term. " "To the best of my knowledge, no hedge operator applies " "directly to boundary data, so this is likely in error." % expr.op) def map_flux_exchange(self, expr): return FieldComponent(self.register_boundary_expr(expr), is_interior=False) # }}} from hedge.tools import is_obj_array if not is_obj_array(vol_field): vol_field = [vol_field] mbfeef = MaxBoundaryFluxEvaluableExpressionFinder( list(vol_field), self.expensive_bdry_op_detector) #from hedge.optemplate.tools import pretty #print pretty(bdry_field) #raw_input("YO") new_bdry_field = mbfeef(bdry_field) # Step II: Substitute the new_bdry_field into the flux. def sub_bdry_into_flux(expr): if isinstance(expr, FieldComponent) and not expr.is_interior: if expr.index == 0 and not is_obj_array(bdry_field): return new_bdry_field else: return new_bdry_field[expr.index] else: return None new_flux = FluxSubstitutionMapper(sub_bdry_into_flux)(flux) from hedge.tools import is_zero, make_obj_array if is_zero(new_flux): return 0 else: return type(expr.op)(new_flux, *expr.op.__getinitargs__()[1:])( BoundaryPair( make_obj_array([self.rec(e) for e in mbfeef.vol_expr_list]), make_obj_array( [self.rec(e) for e in mbfeef.bdry_expr_list]), bpair.tag))
def make_stiffness_t(dim): from hedge.tools import make_obj_array from hedge.optemplate import StiffnessTOperator return make_obj_array([StiffnessTOperator(i) for i in range(dim)])
def test_2d_gauss_theorem(): """Verify Gauss's theorem explicitly on a mesh""" from hedge.mesh.generator import make_disk_mesh from math import sin, cos, sqrt, exp, pi from numpy import dot mesh = make_disk_mesh() order = 2 discr = discr_class(mesh, order=order, debug=discr_class.noninteractive_debug_flags()) ref_discr = discr_class(mesh, order=order) from hedge.flux import make_normal, FluxScalarPlaceholder normal = make_normal(discr.dimensions) flux_f_ph = FluxScalarPlaceholder(0) one_sided_x = flux_f_ph.int * normal[0] one_sided_y = flux_f_ph.int * normal[1] def f1(x, el): return sin(3 * x[0]) + cos(3 * x[1]) def f2(x, el): return sin(2 * x[0]) + cos(x[1]) from hedge.discretization import ones_on_volume ones = ones_on_volume(discr) f1_v = discr.interpolate_volume_function(f1) f2_v = discr.interpolate_volume_function(f2) from hedge.optemplate import BoundaryPair, Field, make_nabla, get_flux_operator nabla = make_nabla(discr.dimensions) diff_optp = nabla[0] * Field("f1") + nabla[1] * Field("f2") divergence = nabla[0].apply(discr, f1_v) + nabla[1].apply(discr, f2_v) int_div = discr.integral(divergence) flux_optp = get_flux_operator(one_sided_x)(BoundaryPair(Field("f1"), Field("fz"))) + get_flux_operator(one_sided_y)( BoundaryPair(Field("f2"), Field("fz")) ) from hedge.mesh import TAG_ALL bdry_val = discr.compile(flux_optp)(f1=f1_v, f2=f2_v, fz=discr.boundary_zeros(TAG_ALL)) ref_bdry_val = ref_discr.compile(flux_optp)(f1=f1_v, f2=f2_v, fz=discr.boundary_zeros(TAG_ALL)) boundary_int = dot(bdry_val, ones) if False: from hedge.visualization import SiloVisualizer vis = SiloVisualizer(discr) visf = vis.make_file("test") from hedge.tools import make_obj_array from hedge.mesh import TAG_ALL vis.add_data( visf, [ ("bdry", bdry_val), ("ref_bdry", ref_bdry_val), ("div", divergence), ("f", make_obj_array([f1_v, f2_v])), ("n", discr.volumize_boundary_field(discr.boundary_normals(TAG_ALL), TAG_ALL)), ], expressions=[("bdiff", "bdry-ref_bdry")], ) # print abs(boundary_int-int_div) assert abs(boundary_int - int_div) < 5e-15
def make_stiffness_t(dim): from hedge.tools import make_obj_array from hedge.optemplate import StiffnessTOperator return make_obj_array( [StiffnessTOperator(i) for i in range(dim)])
def make_nabla(dim): from hedge.tools import make_obj_array from hedge.optemplate import DifferentiationOperator return make_obj_array([DifferentiationOperator(i) for i in range(dim)])