Beispiel #1
0
    def flux(self):
        from hedge.flux import FluxVectorPlaceholder, make_normal

        dim = self.dimensions
        w = FluxVectorPlaceholder(1+dim)
        u = w[0]
        v = w[1:]
        normal = make_normal(dim)

        from hedge.tools import join_fields
        flux_weak = join_fields(
                np.dot(v.avg, normal),
                u.avg * normal)

        if self.flux_type == "central":
            pass
        elif self.flux_type == "upwind":
            # see doc/notes/hedge-notes.tm
            flux_weak -= self.sign*join_fields(
                    0.5*(u.int-u.ext),
                    0.5*(normal * np.dot(normal, v.int-v.ext)))
        else:
            raise ValueError("invalid flux type '%s'" % self.flux_type)

        flux_strong = join_fields(
                np.dot(v.int, normal),
                u.int * normal) - flux_weak

        return -self.c*flux_strong
    def flux_num(self, q, fluxes, bdry_tag_state_flux):
        n = self.len_q
        d = len(fluxes)
        fvph = FluxVectorPlaceholder(n*(d+1)+1)
        speed_ph = fvph[0]
        state_ph = fvph[1:n+1]
        fluxes_ph = [fvph[i*n+1:(i+1)*n+1] for i in range(1,d+1)]
        normal = make_normal(d)

        flux_strong = 0.5*sum(n_i*(f_i.ext-f_i.int) for n_i, f_i in zip(normal, fluxes_ph))

        if self.flux_type == "central":
            pass
        elif self.flux_type == "lf":
            penalty = flux_max(speed_ph.int,speed_ph.ext)*(state_ph.ext-state_ph.int)
            flux_strong = 0.5 * penalty + flux_strong
        else:
            raise ValueError("Invalid flux type '%s'" % self.flux_type)

        flux_op = get_flux_operator(flux_strong)
        int_operand = join_fields(self.wave_speed(q), q, *fluxes)

        return (flux_op(int_operand)
                +sum(flux_op(BoundaryPair(int_operand, join_fields(0, bdry_state, *bdry_fluxes), tag))
                     for tag, bdry_state, bdry_fluxes in bdry_tag_state_flux))
Beispiel #3
0
    def flux(self):
        from hedge.flux import FluxVectorPlaceholder, make_normal

        dim = self.dimensions
        w = FluxVectorPlaceholder(2+dim)
        c = w[0]
        u = w[1]
        v = w[2:]
        normal = make_normal(dim)

        from hedge.tools import join_fields
        flux = self.time_sign*1/2*join_fields(
                c.ext * np.dot(v.ext, normal)
                - c.int * np.dot(v.int, normal),
                normal*(c.ext*u.ext - c.int*u.int))

        if self.flux_type == "central":
            pass
        elif self.flux_type == "upwind":
            flux += join_fields(
                    c.ext*u.ext - c.int*u.int,
                    c.ext*normal*np.dot(normal, v.ext)
                    - c.int*normal*np.dot(normal, v.int)
                    )
        else:
            raise ValueError("invalid flux type '%s'" % self.flux_type)

        return flux
Beispiel #4
0
    def flux(self):
        from hedge.flux import (make_normal, FluxVectorPlaceholder, flux_max)
        from pymbolic.primitives import IfPositive

        d = self.dimensions

        w = FluxVectorPlaceholder((1 + d) + 1)
        u = w[0]
        v = w[1:d + 1]
        c = w[1 + d]

        normal = make_normal(self.dimensions)

        if self.flux_type == "central":
            return (u.int * numpy.dot(v.int, normal) +
                    u.ext * numpy.dot(v.ext, normal)) * 0.5
        elif self.flux_type == "lf":
            n_vint = numpy.dot(normal, v.int)
            n_vext = numpy.dot(normal, v.ext)
            return 0.5 * (n_vint * u.int + n_vext * u.ext) \
                   - 0.5 * (u.ext - u.int) \
                   * flux_max(c.int, c.ext)

        elif self.flux_type == "upwind":
            return (IfPositive(
                numpy.dot(normal, v.avg),
                numpy.dot(normal, v.int) * u.int,  # outflow
                numpy.dot(normal, v.ext) * u.ext,  # inflow
            ))
        else:
            raise ValueError, "invalid flux type"
Beispiel #5
0
    def flux(self):
        from hedge.flux import make_normal, FluxScalarPlaceholder

        u = FluxScalarPlaceholder(0)
        normal = make_normal(self.dimensions)

        return u.int * numpy.dot(normal, self.v) - self.weak_flux()
Beispiel #6
0
    def flux(self):
        from hedge.flux import (
                make_normal,
                FluxVectorPlaceholder,
                flux_max)
        from pymbolic.primitives import IfPositive

        d = self.dimensions

        w = FluxVectorPlaceholder((1+d)+1)
        u = w[0]
        v = w[1:d+1]
        c = w[1+d]

        normal = make_normal(self.dimensions)

        if self.flux_type == "central":
            return (u.int*numpy.dot(v.int, normal )
                    + u.ext*numpy.dot(v.ext, normal)) * 0.5
        elif self.flux_type == "lf":
            n_vint = numpy.dot(normal, v.int)
            n_vext = numpy.dot(normal, v.ext)
            return 0.5 * (n_vint * u.int + n_vext * u.ext) \
                   - 0.5 * (u.ext - u.int) \
                   * flux_max(c.int, c.ext)

        elif self.flux_type == "upwind":
            return (
                    IfPositive(numpy.dot(normal, v.avg),
                        numpy.dot(normal, v.int) * u.int, # outflow
                        numpy.dot(normal, v.ext) * u.ext, # inflow
                        ))
        else:
            raise ValueError, "invalid flux type"
Beispiel #7
0
    def flux(self):
        from hedge.flux import make_normal, FluxScalarPlaceholder

        u = FluxScalarPlaceholder(0)
        normal = make_normal(self.dimensions)

        return u.int * numpy.dot(normal, self.v) - self.weak_flux()
Beispiel #8
0
def make_lax_friedrichs_flux(wave_speed, state, fluxes, bdry_tags_states_and_fluxes,
        strong):
    from pytools.obj_array import join_fields
    from hedge.flux import make_normal, FluxVectorPlaceholder, flux_max

    n = len(state)
    d = len(fluxes)
    normal = make_normal(d)
    fvph = FluxVectorPlaceholder(len(state)*(1+d)+1)

    wave_speed_ph = fvph[0]
    state_ph = fvph[1:1+n]
    fluxes_ph = [fvph[1+i*n:1+(i+1)*n] for i in range(1, d+1)]

    penalty = flux_max(wave_speed_ph.int,wave_speed_ph.ext)*(state_ph.ext-state_ph.int)

    if not strong:
        num_flux = 0.5*(sum(n_i*(f_i.int+f_i.ext) for n_i, f_i in zip(normal, fluxes_ph))
                - penalty)
    else:
        num_flux = 0.5*(sum(n_i*(f_i.int-f_i.ext) for n_i, f_i in zip(normal, fluxes_ph))
                + penalty)

    from hedge.optemplate import get_flux_operator
    flux_op = get_flux_operator(num_flux)
    int_operand = join_fields(wave_speed, state, *fluxes)

    from hedge.optemplate import BoundaryPair
    return (flux_op(int_operand)
            + sum(
                flux_op(BoundaryPair(int_operand,
                    join_fields(0, bdry_state, *bdry_fluxes), tag))
                for tag, bdry_state, bdry_fluxes in bdry_tags_states_and_fluxes))
Beispiel #9
0
    def flux(self):
        from hedge.flux import FluxVectorPlaceholder, make_normal

        dim = self.dimensions
        w = FluxVectorPlaceholder(2 + dim)
        c = w[0]
        u = w[1]
        v = w[2:]
        normal = make_normal(dim)

        from hedge.tools import join_fields
        flux = self.time_sign * 1 / 2 * join_fields(
            c.ext * numpy.dot(v.ext, normal) - c.int * numpy.dot(
                v.int, normal), normal * (c.ext * u.ext - c.int * u.int))

        if self.flux_type == "central":
            pass
        elif self.flux_type == "upwind":
            flux += join_fields(
                c.ext * u.ext - c.int * u.int,
                c.ext * normal * numpy.dot(normal, v.ext) -
                c.int * normal * numpy.dot(normal, v.int))
        else:
            raise ValueError("invalid flux type '%s'" % self.flux_type)

        return flux
Beispiel #10
0
    def flux(self):
        from hedge.flux import FluxVectorPlaceholder, make_normal

        dim = self.dimensions
        w = FluxVectorPlaceholder(1 + dim)
        u = w[0]
        v = w[1:]
        normal = make_normal(dim)

        from hedge.tools import join_fields
        flux_weak = join_fields(numpy.dot(v.avg, normal), u.avg * normal)

        if self.flux_type == "central":
            pass
        elif self.flux_type == "upwind":
            # see doc/notes/hedge-notes.tm
            flux_weak -= self.sign * join_fields(
                0.5 * (u.int - u.ext), 0.5 *
                (normal * numpy.dot(normal, v.int - v.ext)))
        else:
            raise ValueError("invalid flux type '%s'" % self.flux_type)

        flux_strong = join_fields(numpy.dot(v.int, normal),
                                  u.int * normal) - flux_weak

        return -self.c * flux_strong
Beispiel #11
0
    def flux(self, beta, is_dirich):
        """The template for the numerical flux for variable coefficients.
            From Noels, Radovitzky 2007
        """
        from hedge.flux import (make_normal, FluxVectorPlaceholder,
                FluxConstantPlaceholder)
        from hedge.tools import join_fields
        
        dim = self.dimensions
        normal = make_normal(self.dimensions)
        w = FluxVectorPlaceholder(dim*2+9)

        # u is displacement field, v is its time derivative (velocity)
        u, v, F = self.split_grad_vars(w)
      
        P_int = self.material.stress(F.int, self.dimensions)
        C_int = self.material.tangent_moduli(F.int, self.dimensions, self.dimensions)

        # constitutive update for exterior face
        if is_dirich:
            P_ext = [0]*9  #[-3*p for p in P_int]
            C_ext = [0]*81 #C_int
        else:
            P_ext = self.material.stress(F.ext, self.dimensions)
            C_ext = self.material.tangent_moduli(F.ext, self.dimensions, self.dimensions)
        
        P_avg = [(P_int[i] + P_ext[i])/2 for i in range(dim*dim)]
        # 'force' flux
        v_flux = [0,]*self.dimensions
        for i in range(self.dimensions):
            for j in range(self.dimensions):
                v_flux[i] = v_flux[i] + P_avg[3*i+j]*normal[j]
        
        from hedge.flux import make_penalty_term
        stab_factor = beta * make_penalty_term()
        C_avg = [stab_factor * (C_int[i] + C_ext[i]) / 2 for i in range(dim*dim*dim*dim)]
        # stabilization term
        u_jump = u.ext - u.int
        for i in range(self.dimensions):
            for j in range(self.dimensions):
               for k in range(self.dimensions):
                    for l in range(self.dimensions):
                        v_flux[i] = v_flux[i] - normal[j]* \
                                                C_avg[27*i+9*j+3*k+l]* \
                                                u_jump[k]* \
                                                normal[l]

        return join_fields(
                # u needs no flux term
                0,0,0,
                # flux for v
                v_flux[0], v_flux[1], v_flux[2]
                )
Beispiel #12
0
    def op_template(self, w=None):
        """The full operator template - the high level description of
        the nonlinear mechanics operator.

        Combines the relevant operator templates for spatial
        derivatives, flux, boundary conditions etc.

        NOTE: Only boundary conditions allowed currently are homogenous
        dirichlet and neumann, and I'm not sure dirichlet is done 
        properly
        """
        from hedge.optemplate import InverseMassOperator, Field, \
                make_vector_field

        from hedge.tools import join_fields
        w = self.field_placeholder(w)
       
        u,v = self.split_vars(w)
        from hedge.optemplate import make_nabla

        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[j](u[i]) 
                if i == j:
                    F[ij] = F[ij] + 1
                ij = ij + 1
        
        w = join_fields(u,v,F)
        flux_w = w

        from hedge.optemplate import BoundaryPair, get_flux_operator

        flux_op = get_flux_operator(self.flux(self.beta, is_dirich=False))
        d_flux_op = get_flux_operator(self.flux(self.beta, is_dirich=True))
        
        from hedge.optemplate import make_normal, BoundarizeOperator

        dir_normal = make_normal(self.dirichlet_tag, self.dimensions)

        dir_bc = self.dirichlet_bc(w)

        return    self.local_derivatives(w) \
                - (flux_op(flux_w) + 
                   d_flux_op(BoundaryPair(flux_w, dir_bc, self.dirichlet_tag))
                  )
Beispiel #13
0
    def flux(self):
        from hedge.flux import make_normal, FluxVectorPlaceholder

        v = FluxVectorPlaceholder(self.arg_count)

        normal = make_normal(self.dimensions)

        flux = 0
        idx = 0

        for i, i_enabled in enumerate(self.subset):
            if i_enabled and i < self.dimensions:
                flux += (v.int - v.avg)[idx] * normal[i]
                idx += 1

        return flux
Beispiel #14
0
    def flux(self):
        from hedge.flux import make_normal, FluxVectorPlaceholder

        v = FluxVectorPlaceholder(self.arg_count)

        normal = make_normal(self.dimensions)

        flux = 0
        idx = 0

        for i, i_enabled in enumerate(self.subset):
            if i_enabled and i < self.dimensions:
                flux += (v.int-v.avg)[idx]*normal[i]
                idx += 1

        return flux
Beispiel #15
0
    def flux(self):
        from hedge.flux import make_normal, FluxVectorPlaceholder

        normal = make_normal(self.maxwell_op.dimensions)

        from hedge.tools import join_fields

        w = FluxVectorPlaceholder(self.component_count)
        e, h, phi = self.split_ehphi(w)

        # see hedge/doc/maxima/eclean.mac for derivation
        strong_flux = 0.5 * self.c * self.chi * join_fields(
            # flux e
            normal * (phi.int - phi.ext - numpy.dot(normal, e.int - e.ext)),
            # flux h
            len(h) * [0],
            # flux phi
            numpy.dot(e.int - e.ext, normal) - (phi.int - phi.ext))
        return strong_flux + join_fields(self.maxwell_op.flux(1), 0)
Beispiel #16
0
    def div(self, tgt, bc_getter, dirichlet_tags, neumann_tags):
        """
        :param bc_getter: a function (tag, volume_expr) -> boundary expr.
          *volume_expr* will be None to query the Neumann condition.
        """

        from hedge.tools.symbolic import make_common_subexpression as cse
        from hedge.flux import FluxVectorPlaceholder, make_normal, PenaltyTerm
        normal = make_normal(tgt.dimensions)

        n_times = tgt.normal_times_flux
        v_times = tgt.vec_times

        if tgt.strong_form:
            def adjust_flux(f):
                return n_times(flux_v.int) - f
        else:
            def adjust_flux(f):
                return f

        dim = tgt.dimensions

        flux_w = FluxVectorPlaceholder(2*tgt.dimensions)
        flux_v = flux_w[:dim]
        pure_diff_v = flux_w[dim:]
        flux_args = (
                list(tgt.int_flux_operand) 
                + list(IPDGDerivativeGenerator()(tgt.int_flux_operand)))

        stab_term_generator = StabilizationTermGenerator(flux_args)
        stab_term = (self.stab_coefficient * PenaltyTerm() 
                * stab_term_generator(tgt.int_flux_operand))
        flux = n_times(pure_diff_v.avg - stab_term)

        from pytools.obj_array import make_obj_array
        flux_arg_int = cse(make_obj_array(stab_term_generator.flux_args))

        tgt.add_derivative(cse(tgt.operand))
        tgt.add_inner_fluxes(adjust_flux(flux), flux_arg_int)

        self.add_div_bcs(tgt, bc_getter, dirichlet_tags, neumann_tags,
                stab_term, adjust_flux, flux_v, flux_arg_int, 2*tgt.dimensions)
Beispiel #17
0
    def weak_flux(self):
        from hedge.flux import make_normal, FluxScalarPlaceholder
        from pymbolic.primitives import IfPositive

        u = FluxScalarPlaceholder(0)
        normal = make_normal(self.dimensions)

        if self.flux_type == "central":
            return u.avg * numpy.dot(normal, self.v)
        elif self.flux_type == "lf":
            return u.avg*numpy.dot(normal, self.v) \
                    + 0.5*la.norm(self.v)*(u.int - u.ext)
        elif self.flux_type == "upwind":
            return (numpy.dot(normal, self.v) * IfPositive(
                numpy.dot(normal, self.v),
                u.int,  # outflow
                u.ext,  # inflow
            ))
        else:
            raise ValueError, "invalid flux type"
Beispiel #18
0
    def get_advection_flux(self, velocity):
        from hedge.flux import make_normal, FluxScalarPlaceholder
        from pymbolic.primitives import IfPositive

        u = FluxScalarPlaceholder(0)
        normal = make_normal(self.method.dimensions)

        if self.flux_type == "central":
            return u.avg * np.dot(normal, velocity)
        elif self.flux_type == "lf":
            return u.avg*np.dot(normal, velocity) \
                    + 0.5*la.norm(v)*(u.int - u.ext)
        elif self.flux_type == "upwind":
            return (np.dot(normal, velocity) * IfPositive(
                np.dot(normal, velocity),
                u.int,  # outflow
                u.ext,  # inflow
            ))
        else:
            raise ValueError, "invalid flux type"
Beispiel #19
0
    def get_advection_flux(self, velocity):
        from hedge.flux import make_normal, FluxScalarPlaceholder
        from pymbolic.primitives import IfPositive

        u = FluxScalarPlaceholder(0)
        normal = make_normal(self.method.dimensions)

        if self.flux_type == "central":
            return u.avg*np.dot(normal, velocity)
        elif self.flux_type == "lf":
            return u.avg*np.dot(normal, velocity) \
                    + 0.5*la.norm(v)*(u.int - u.ext)
        elif self.flux_type == "upwind":
            return (np.dot(normal, velocity)*
                    IfPositive(np.dot(normal, velocity),
                        u.int, # outflow
                        u.ext, # inflow
                        ))
        else:
            raise ValueError, "invalid flux type"
Beispiel #20
0
    def weak_flux(self):
        from hedge.flux import make_normal, FluxScalarPlaceholder
        from pymbolic.primitives import IfPositive

        u = FluxScalarPlaceholder(0)
        normal = make_normal(self.dimensions)

        if self.flux_type == "central":
            return u.avg*numpy.dot(normal, self.v)
        elif self.flux_type == "lf":
            return u.avg*numpy.dot(normal, self.v) \
                    + 0.5*la.norm(self.v)*(u.int - u.ext)
        elif self.flux_type == "upwind":
            return (numpy.dot(normal, self.v)*
                    IfPositive(numpy.dot(normal, self.v),
                        u.int, # outflow
                        u.ext, # inflow
                        ))
        else:
            raise ValueError, "invalid flux type"
Beispiel #21
0
    def flux(self):
        from hedge.flux import make_normal, FluxVectorPlaceholder

        normal = make_normal(self.maxwell_op.dimensions)

        from hedge.tools import join_fields

        w = FluxVectorPlaceholder(self.component_count)
        e, h, phi = self.split_ehphi(w)

        # see hedge/doc/maxima/eclean.mac for derivation
        strong_flux = 0.5*self.c*self.chi*join_fields(
                # flux e
                normal*(phi.int-phi.ext - numpy.dot(normal, e.int-e.ext)),
                # flux h
                len(h)*[0],
                # flux phi
                numpy.dot(e.int-e.ext, normal)-(phi.int-phi.ext)
                )
        return strong_flux + join_fields(self.maxwell_op.flux(1), 0)
Beispiel #22
0
    def absorbing_bc(self, w=None):
        """Construct part of the flux operator template for 1st order
        absorbing boundary conditions.
        """

        from hedge.optemplate import make_normal
        absorb_normal = make_normal(self.absorb_tag, self.dimensions)

        from hedge.optemplate import BoundarizeOperator, Field
        from hedge.tools import join_fields

        e, h = self.split_eh(self.field_placeholder(w))

        if self.fixed_material:
            epsilon = self.epsilon
            mu = self.mu
        else:
            epsilon = cse(
                    BoundarizeOperator(self.absorb_tag)(Field("epsilon")))
            mu = cse(
                    BoundarizeOperator(self.absorb_tag)(Field("mu")))

        absorb_Z = (mu/epsilon)**0.5
        absorb_Y = 1/absorb_Z

        absorb_e = BoundarizeOperator(self.absorb_tag)(e)
        absorb_h = BoundarizeOperator(self.absorb_tag)(h)

        bc = join_fields(
                absorb_e + 1/2*(self.space_cross_h(absorb_normal, self.space_cross_e(
                    absorb_normal, absorb_e))
                    - absorb_Z*self.space_cross_h(absorb_normal, absorb_h)),
                absorb_h + 1/2*(
                    self.space_cross_e(absorb_normal, self.space_cross_h(
                        absorb_normal, absorb_h))
                    + absorb_Y*self.space_cross_e(absorb_normal, absorb_e)))

        return bc
Beispiel #23
0
def make_lax_friedrichs_flux(wave_speed, state, fluxes,
                             bdry_tags_states_and_fluxes, strong):
    from pytools.obj_array import join_fields
    from hedge.flux import make_normal, FluxVectorPlaceholder, flux_max

    n = len(state)
    d = len(fluxes)
    normal = make_normal(d)
    fvph = FluxVectorPlaceholder(len(state) * (1 + d) + 1)

    wave_speed_ph = fvph[0]
    state_ph = fvph[1:1 + n]
    fluxes_ph = [fvph[1 + i * n:1 + (i + 1) * n] for i in range(1, d + 1)]

    penalty = flux_max(wave_speed_ph.int,
                       wave_speed_ph.ext) * (state_ph.ext - state_ph.int)

    if not strong:
        num_flux = 0.5 * (sum(n_i * (f_i.int + f_i.ext)
                              for n_i, f_i in zip(normal, fluxes_ph)) -
                          penalty)
    else:
        num_flux = 0.5 * (sum(n_i * (f_i.int - f_i.ext)
                              for n_i, f_i in zip(normal, fluxes_ph)) +
                          penalty)

    from hedge.optemplate import get_flux_operator
    flux_op = get_flux_operator(num_flux)
    int_operand = join_fields(wave_speed, state, *fluxes)

    from hedge.optemplate import BoundaryPair
    return (flux_op(int_operand) + sum(
        flux_op(
            BoundaryPair(int_operand, join_fields(0, bdry_state, *bdry_fluxes),
                         tag))
        for tag, bdry_state, bdry_fluxes in bdry_tags_states_and_fluxes))
def test_interior_fluxes_tri():
    """Check triangle surface integrals computed using interior fluxes
    against their known values.
    """

    from math import pi, sin, cos

    def round_trip_connect(start, end):
        for i in range(start, end):
            yield i, i + 1
        yield end, start

    a = -pi
    b = pi
    points = [(a, 0), (b, 0), (a, -1), (b, -1), (a, 1), (b, 1)]

    import meshpy.triangle as triangle

    mesh_info = triangle.MeshInfo()
    mesh_info.set_points(points)
    mesh_info.set_facets([(0, 1), (1, 3), (3, 2), (2, 0), (0, 4), (4, 5), (1, 5)])

    mesh_info.regions.resize(2)
    mesh_info.regions[0] = [0, -0.5, 1, 0.1]  # coordinate  # lower element tag  # max area
    mesh_info.regions[1] = [0, 0.5, 2, 0.01]  # coordinate  # upper element tag  # max area

    generated_mesh = triangle.build(mesh_info, attributes=True, volume_constraints=True)
    # triangle.write_gnuplot_mesh("mesh.dat", generated_mesh)

    def element_tagger(el):
        if generated_mesh.element_attributes[el.id] == 1:
            return ["upper"]
        else:
            return ["lower"]

    from hedge.mesh import make_conformal_mesh

    mesh = make_conformal_mesh(generated_mesh.points, generated_mesh.elements)

    from hedge.discretization.local import TriangleDiscretization
    from hedge.discretization import ones_on_volume

    discr = discr_class(mesh, TriangleDiscretization(4), debug=discr_class.noninteractive_debug_flags())

    def f_u(x, el):
        if generated_mesh.element_attributes[el.id] == 1:
            return cos(x[0] - x[1])
        else:
            return 0

    def f_l(x, el):
        if generated_mesh.element_attributes[el.id] == 0:
            return sin(x[0] - x[1])
        else:
            return 0

    u_l = discr.interpolate_volume_function(f_l)
    u_u = discr.interpolate_volume_function(f_u)
    u = u_u + u_u

    # discr.visualize_vtk("dual.vtk", [("u", u)])

    from hedge.flux import make_normal, FluxScalarPlaceholder
    from hedge.optemplate import Field, get_flux_operator

    fluxu = FluxScalarPlaceholder()
    res = discr.compile(get_flux_operator((fluxu.int - fluxu.ext) * make_normal(discr.dimensions)[1]) * Field("u"))(u=u)

    from hedge.discretization import ones_on_volume

    ones = ones_on_volume(discr)
    err = abs(numpy.dot(res, ones))
    # print err
    assert err < 5e-14
Beispiel #25
0
    def op_template(self):
        from hedge.optemplate import \
                make_vector_field, \
                BoundaryPair, \
                get_flux_operator, \
                make_nabla, \
                InverseMassOperator, \
                BoundarizeOperator

        d = self.dimensions

        w = make_vector_field("w", d + 1)
        u = w[0]
        v = w[1:]

        # boundary conditions -------------------------------------------------
        from hedge.tools import join_fields

        # dirichlet BCs -------------------------------------------------------
        from hedge.optemplate import make_normal, Field

        dir_normal = make_normal(self.dirichlet_tag, d)

        dir_u = BoundarizeOperator(self.dirichlet_tag) * u
        dir_v = BoundarizeOperator(self.dirichlet_tag) * v
        if self.dirichlet_bc_f:
            # FIXME
            from warnings import warn
            warn("Inhomogeneous Dirichlet conditions on the wave equation "
                 "are still having issues.")

            dir_g = Field("dir_bc_u")
            dir_bc = join_fields(2 * dir_g - dir_u, dir_v)
        else:
            dir_bc = join_fields(-dir_u, dir_v)

        # neumann BCs ---------------------------------------------------------
        neu_u = BoundarizeOperator(self.neumann_tag) * u
        neu_v = BoundarizeOperator(self.neumann_tag) * v
        neu_bc = join_fields(neu_u, -neu_v)

        # radiation BCs -------------------------------------------------------
        from hedge.optemplate import make_normal
        rad_normal = make_normal(self.radiation_tag, d)

        rad_u = BoundarizeOperator(self.radiation_tag) * u
        rad_v = BoundarizeOperator(self.radiation_tag) * v

        rad_bc = join_fields(
            0.5 * (rad_u - self.sign * numpy.dot(rad_normal, rad_v)), 0.5 *
            rad_normal * (numpy.dot(rad_normal, rad_v) - self.sign * rad_u))

        # entire operator -----------------------------------------------------
        nabla = make_nabla(d)
        flux_op = get_flux_operator(self.flux())

        from hedge.tools import join_fields
        result = (
            -join_fields(-self.c * numpy.dot(nabla, v), -self.c * (nabla * u))
            + InverseMassOperator() *
            (flux_op(w) + flux_op(BoundaryPair(w, dir_bc, self.dirichlet_tag))
             + flux_op(BoundaryPair(w, neu_bc, self.neumann_tag)) + flux_op(
                 BoundaryPair(w, rad_bc, self.radiation_tag))))

        if self.source_f is not None:
            result[0] += Field("source_u")

        return result
def test_interior_fluxes_tet():
    """Check tetrahedron surface integrals computed using interior fluxes
    against their known values.
    """

    import meshpy.tet as tet
    from math import pi, sin, cos

    mesh_info = tet.MeshInfo()

    # construct a two-box extrusion of this base
    base = [(-pi, -pi, 0), (pi, -pi, 0), (pi, pi, 0), (-pi, pi, 0)]

    # first, the nodes
    mesh_info.set_points(base + [(x, y, z + pi)
                                 for x, y, z in base] + [(x, y, z + pi + 1)
                                                         for x, y, z in base])

    # next, the facets

    # vertex indices for a box missing the -z face
    box_without_minus_z = [
        [4, 5, 6, 7],
        [0, 4, 5, 1],
        [1, 5, 6, 2],
        [2, 6, 7, 3],
        [3, 7, 4, 0],
    ]

    def add_to_all_vertex_indices(facets, increment):
        return [[pt + increment for pt in facet] for facet in facets]

    mesh_info.set_facets(
        [[0, 1, 2, 3]]  # base
        + box_without_minus_z  # first box
        + add_to_all_vertex_indices(box_without_minus_z, 4)  # second box
    )

    # set the volume properties -- this is where the tet size constraints are
    mesh_info.regions.resize(2)
    mesh_info.regions[0] = [
        0,
        0,
        pi / 2,  # point in volume -> first box
        0,  # region tag (user-defined number)
        0.5,  # max tet volume in region
    ]
    mesh_info.regions[1] = [
        0,
        0,
        pi + 0.5,  # point in volume -> second box
        1,  # region tag (user-defined number,  arbitrary)
        0.1,  # max tet volume in region
    ]

    generated_mesh = tet.build(mesh_info,
                               attributes=True,
                               volume_constraints=True)

    from hedge.mesh import make_conformal_mesh
    mesh = make_conformal_mesh(generated_mesh.points, generated_mesh.elements)

    from hedge.discretization.local import TetrahedronDiscretization
    from hedge.discretization import ones_on_volume
    discr = discr_class(mesh,
                        TetrahedronDiscretization(4),
                        debug=discr_class.noninteractive_debug_flags())

    def f_u(x, el):
        if generated_mesh.element_attributes[el.id] == 1:
            return cos(x[0] - x[1] + x[2])
        else:
            return 0

    def f_l(x, el):
        if generated_mesh.element_attributes[el.id] == 0:
            return sin(x[0] - x[1] + x[2])
        else:
            return 0

    u_l = discr.interpolate_volume_function(f_l)
    u_u = discr.interpolate_volume_function(f_u)
    u = u_l + u_u

    # visualize the produced field
    #from hedge.visualization import SiloVisualizer
    #vis = SiloVisualizer(discr)
    #visf = vis.make_file("sandwich")
    #vis.add_data(visf,
    #[("u_l", u_l), ("u_u", u_u)],
    #expressions=[("u", "u_l+u_u")])

    # make sure the surface integral of the difference
    # between top and bottom is zero
    from hedge.flux import make_normal, FluxScalarPlaceholder
    from hedge.optemplate import Field, get_flux_operator

    fluxu = FluxScalarPlaceholder()
    res = discr.compile(
        get_flux_operator(
            (fluxu.int - fluxu.ext) * make_normal(discr.dimensions)[1]) *
        Field("u"))(u=u)

    ones = ones_on_volume(discr)
    assert abs(numpy.dot(res, ones)) < 5e-14
Beispiel #27
0
    def flux(self):
        from hedge.flux import make_normal, FluxScalarPlaceholder
        u = FluxScalarPlaceholder()

        normal = make_normal(self.dimensions)
        return u.int * normal - u.avg * normal
Beispiel #28
0
    def flux(self, flux_type):
        """The template for the numerical flux for variable coefficients.

        :param flux_type: can be in [0,1] for anything between central and upwind,
          or "lf" for Lax-Friedrichs.

        As per Hesthaven and Warburton page 433.
        """
        from hedge.flux import (make_normal, FluxVectorPlaceholder,
                                FluxConstantPlaceholder)
        from hedge.tools import join_fields

        normal = make_normal(self.dimensions)

        if self.fixed_material:
            from hedge.tools import count_subset
            w = FluxVectorPlaceholder(count_subset(self.get_eh_subset()))

            e, h = self.split_eh(w)
            epsilon = FluxConstantPlaceholder(self.epsilon)
            mu = FluxConstantPlaceholder(self.mu)

        else:
            from hedge.tools import count_subset
            w = FluxVectorPlaceholder(count_subset(self.get_eh_subset()) + 2)

            epsilon, mu, e, h = self.split_eps_mu_eh(w)

        Z_int = (mu.int / epsilon.int)**0.5
        Y_int = 1 / Z_int
        Z_ext = (mu.ext / epsilon.ext)**0.5
        Y_ext = 1 / Z_ext

        if flux_type == "lf":
            if self.fixed_material:
                max_c = (self.epsilon * self.mu)**(-0.5)
            else:
                from hedge.flux import Max
                c_int = (epsilon.int * mu.int)**(-0.5)
                c_ext = (epsilon.ext * mu.ext)**(-0.5)
                max_c = Max(c_int, c_ext)  # noqa

            return join_fields(
                # flux e,
                1 / 2 * (
                    -self.space_cross_h(normal, h.int - h.ext)
                    # multiplication by epsilon undoes material divisor below
                    #-max_c*(epsilon.int*e.int - epsilon.ext*e.ext)
                ),
                # flux h
                1 / 2 * (
                    self.space_cross_e(normal, e.int - e.ext)
                    # multiplication by mu undoes material divisor below
                    #-max_c*(mu.int*h.int - mu.ext*h.ext)
                ))
        elif isinstance(flux_type, (int, float)):
            # see doc/maxima/maxwell.mac
            return join_fields(
                # flux e,
                (-1 / (Z_int + Z_ext) * self.space_cross_h(
                    normal,
                    Z_ext * (h.int - h.ext) -
                    flux_type * self.space_cross_e(normal, e.int - e.ext))),
                # flux h
                (1 / (Y_int + Y_ext) * self.space_cross_e(
                    normal,
                    Y_ext * (e.int - e.ext) +
                    flux_type * self.space_cross_h(normal, h.int - h.ext))),
            )
        else:
            raise ValueError("maxwell: invalid flux_type (%s)" %
                             self.flux_type)
Beispiel #29
0
    def flux(self, flux_type):
        """The template for the numerical flux for variable coefficients.

        :param flux_type: can be in [0,1] for anything between central and upwind,
          or "lf" for Lax-Friedrichs.

        As per Hesthaven and Warburton page 433.
        """
        from hedge.flux import (make_normal, FluxVectorPlaceholder,
                FluxConstantPlaceholder)
        from hedge.tools import join_fields

        normal = make_normal(self.dimensions)

        if self.fixed_material:
            from hedge.tools import count_subset
            w = FluxVectorPlaceholder(count_subset(self.get_eh_subset()))

            e, h = self.split_eh(w)
            epsilon = FluxConstantPlaceholder(self.epsilon)
            mu = FluxConstantPlaceholder(self.mu)

        else:
            from hedge.tools import count_subset
            w = FluxVectorPlaceholder(count_subset(self.get_eh_subset())+2)

            epsilon, mu, e, h = self.split_eps_mu_eh(w)

        Z_int = (mu.int/epsilon.int)**0.5
        Y_int = 1/Z_int
        Z_ext = (mu.ext/epsilon.ext)**0.5
        Y_ext = 1/Z_ext

        if flux_type == "lf":
            if self.fixed_material:
                max_c = (self.epsilon*self.mu)**(-0.5)
            else:
                from hedge.flux import Max
                c_int = (epsilon.int*mu.int)**(-0.5)
                c_ext = (epsilon.ext*mu.ext)**(-0.5)
                max_c = Max(c_int, c_ext)  # noqa

            return join_fields(
                    # flux e,
                    1/2*(
                        -self.space_cross_h(normal, h.int-h.ext)
                        # multiplication by epsilon undoes material divisor below
                        #-max_c*(epsilon.int*e.int - epsilon.ext*e.ext)
                    ),
                    # flux h
                    1/2*(
                        self.space_cross_e(normal, e.int-e.ext)
                        # multiplication by mu undoes material divisor below
                        #-max_c*(mu.int*h.int - mu.ext*h.ext)
                    ))
        elif isinstance(flux_type, (int, float)):
            # see doc/maxima/maxwell.mac
            return join_fields(
                    # flux e,
                    (
                        -1/(Z_int+Z_ext)*self.space_cross_h(normal,
                            Z_ext*(h.int-h.ext)
                            - flux_type*self.space_cross_e(normal, e.int-e.ext))
                        ),
                    # flux h
                    (
                        1/(Y_int + Y_ext)*self.space_cross_e(normal,
                            Y_ext*(e.int-e.ext)
                            + flux_type*self.space_cross_h(normal, h.int-h.ext))
                        ),
                    )
        else:
            raise ValueError("maxwell: invalid flux_type (%s)"
                    % self.flux_type)
Beispiel #30
0
    def flux(self):
        from hedge.flux import make_normal, FluxScalarPlaceholder
        u = FluxScalarPlaceholder()

        normal = make_normal(self.dimensions)
        return u.int*normal - u.avg*normal
Beispiel #31
0
    def op_template(self):
        from hedge.tools import join_fields
        from hedge.optemplate import Field, make_vector_field, BoundaryPair, \
                BoundarizeOperator, make_normal, get_flux_operator, \
                make_nabla, InverseMassOperator

        w = make_vector_field("w", self.component_count)
        e, h, phi = self.split_ehphi(w)
        rho = Field("rho")

        # local part ----------------------------------------------------------
        nabla = make_nabla(self.maxwell_op.dimensions)

        # in conservation form: u_t + A u_x = 0
        # we're describing the A u_x part, the sign gets reversed
        # below.
        max_local_op = join_fields(self.maxwell_op.local_derivatives(w), 0)

        c = self.maxwell_op.c
        chi = self.chi

        hyp_local_operator = max_local_op + join_fields(
            c * chi * (nabla * phi),
            0 * h,
            c * chi * numpy.dot(nabla, e) -
            c * chi * rho / self.maxwell_op.epsilon

            # sign gets reversed below, so this is actually
            # the decay it advertises to be.
            + self.phi_decay * phi)

        # BCs -----------------------------------------------------------------
        pec_tag = self.maxwell_op.pec_tag

        pec_e = BoundarizeOperator(pec_tag)(e)
        pec_h = BoundarizeOperator(pec_tag)(h)
        pec_phi = BoundarizeOperator(pec_tag)(phi)
        pec_n = make_normal(pec_tag, self.maxwell_op.dimensions)

        bc = "prev"
        print "HYP CLEAN BC", bc
        if bc == "char":
            # see hedge/doc/maxima/eclean.mac for derivation
            pec_bc = join_fields(
                -pec_e + 3 / 2 * pec_n * numpy.dot(pec_n, pec_e) +
                1 / 2 * pec_phi * pec_n, pec_h,
                1 / 2 * (pec_phi + numpy.dot(pec_n, pec_e)))
        elif bc == "invent":
            # see hedge/doc/maxima/eclean.mac for derivation
            pec_bc = join_fields(-pec_e + 2 * pec_n * numpy.dot(pec_n, pec_e),
                                 pec_h, pec_phi)
        elif bc == "munz":
            # Munz et al
            pec_bc = join_fields(-pec_e, pec_h,
                                 pec_phi - numpy.dot(pec_n, pec_e))
        elif bc == "prev":
            # previous condition
            pec_bc = join_fields(-pec_e + 2 * pec_n * numpy.dot(pec_n, pec_e),
                                 pec_h, -pec_phi)

        # assemble operator ---------------------------------------------------
        flux_op = get_flux_operator(self.flux())
        return -hyp_local_operator + InverseMassOperator()(
            flux_op(w) + flux_op(BoundaryPair(w, pec_bc, pec_tag)))
def test_interior_fluxes_tri():
    """Check triangle surface integrals computed using interior fluxes
    against their known values.
    """

    from math import pi, sin, cos

    def round_trip_connect(start, end):
        for i in range(start, end):
            yield i, i + 1
        yield end, start

    a = -pi
    b = pi
    points = [(a, 0), (b, 0), (a, -1), (b, -1), (a, 1), (b, 1)]

    import meshpy.triangle as triangle

    mesh_info = triangle.MeshInfo()
    mesh_info.set_points(points)
    mesh_info.set_facets([(0, 1), (1, 3), (3, 2), (2, 0), (0, 4), (4, 5),
                          (1, 5)])

    mesh_info.regions.resize(2)
    mesh_info.regions[0] = [
        0,
        -0.5,  # coordinate
        1,  # lower element tag
        0.1,  # max area
    ]
    mesh_info.regions[1] = [
        0,
        0.5,  # coordinate
        2,  # upper element tag
        0.01,  # max area
    ]

    generated_mesh = triangle.build(mesh_info,
                                    attributes=True,
                                    volume_constraints=True)

    #triangle.write_gnuplot_mesh("mesh.dat", generated_mesh)

    def element_tagger(el):
        if generated_mesh.element_attributes[el.id] == 1:
            return ["upper"]
        else:
            return ["lower"]

    from hedge.mesh import make_conformal_mesh
    mesh = make_conformal_mesh(generated_mesh.points, generated_mesh.elements)

    from hedge.discretization.local import TriangleDiscretization
    from hedge.discretization import ones_on_volume
    discr = discr_class(mesh,
                        TriangleDiscretization(4),
                        debug=discr_class.noninteractive_debug_flags())

    def f_u(x, el):
        if generated_mesh.element_attributes[el.id] == 1:
            return cos(x[0] - x[1])
        else:
            return 0

    def f_l(x, el):
        if generated_mesh.element_attributes[el.id] == 0:
            return sin(x[0] - x[1])
        else:
            return 0

    # u_l = discr.interpolate_volume_function(f_l)
    u_u = discr.interpolate_volume_function(f_u)
    u = u_u + u_u

    #discr.visualize_vtk("dual.vtk", [("u", u)])

    from hedge.flux import make_normal, FluxScalarPlaceholder
    from hedge.optemplate import Field, get_flux_operator
    fluxu = FluxScalarPlaceholder()
    res = discr.compile(
        get_flux_operator(
            (fluxu.int - fluxu.ext) * make_normal(discr.dimensions)[1]) *
        Field("u"))(u=u)

    ones = ones_on_volume(discr)
    err = abs(numpy.dot(res, ones))
    #print err
    assert err < 5e-14
Beispiel #33
0
    def op_template(self):
        from hedge.tools import join_fields
        from hedge.optemplate import Field, make_vector_field, BoundaryPair, \
                BoundarizeOperator, make_normal, get_flux_operator, \
                make_nabla, InverseMassOperator

        w = make_vector_field("w", self.component_count)
        e, h, phi = self.split_ehphi(w)
        rho = Field("rho")


        # local part ----------------------------------------------------------
        nabla = make_nabla(self.maxwell_op.dimensions)

        # in conservation form: u_t + A u_x = 0
        # we're describing the A u_x part, the sign gets reversed
        # below.
        max_local_op = join_fields(self.maxwell_op.local_derivatives(w), 0)

        c = self.maxwell_op.c
        chi = self.chi

        hyp_local_operator = max_local_op + join_fields(
                c*chi*(nabla*phi),
                0*h,
                c*chi*numpy.dot(nabla, e) 
                - c*chi*rho/self.maxwell_op.epsilon

                # sign gets reversed below, so this is actually 
                # the decay it advertises to be.
                + self.phi_decay*phi
                )

        # BCs -----------------------------------------------------------------
        pec_tag = self.maxwell_op.pec_tag

        pec_e = BoundarizeOperator(pec_tag)(e)
        pec_h = BoundarizeOperator(pec_tag)(h)
        pec_phi = BoundarizeOperator(pec_tag)(phi)
        pec_n = make_normal(pec_tag, self.maxwell_op.dimensions)

        bc = "prev"
        print "HYP CLEAN BC", bc
        if bc == "char":
            # see hedge/doc/maxima/eclean.mac for derivation
            pec_bc = join_fields(
                    -pec_e
                    + 3/2 * pec_n * numpy.dot(pec_n, pec_e)
                    + 1/2 * pec_phi * pec_n ,

                    pec_h,

                    1/2*(pec_phi+numpy.dot(pec_n, pec_e))
                    )
        elif bc == "invent":
            # see hedge/doc/maxima/eclean.mac for derivation
            pec_bc = join_fields(
                    -pec_e
                    + 2 * pec_n * numpy.dot(pec_n, pec_e),
                    pec_h, 
                    pec_phi)
        elif bc == "munz":
            # Munz et al
            pec_bc = join_fields(
                    -pec_e, 
                    pec_h, 
                    pec_phi-numpy.dot(pec_n, pec_e))
        elif bc == "prev":
            # previous condition
            pec_bc = join_fields(
                    -pec_e
                    +2*pec_n * numpy.dot(pec_n, pec_e),

                    pec_h,

                    -pec_phi)

        # assemble operator ---------------------------------------------------
        flux_op = get_flux_operator(self.flux())
        return -hyp_local_operator + InverseMassOperator()(
                    flux_op(w)
                    + flux_op(BoundaryPair(w, pec_bc, pec_tag)))
Beispiel #34
0
    def op_template(self, with_sensor=False):
        from hedge.optemplate import \
                Field, \
                make_vector_field, \
                BoundaryPair, \
                get_flux_operator, \
                make_nabla, \
                InverseMassOperator, \
                BoundarizeOperator

        d = self.dimensions

        w = make_vector_field("w", d + 1)
        u = w[0]
        v = w[1:]

        from hedge.tools import join_fields
        c = Field("c")
        flux_w = join_fields(c, w)

        # {{{ boundary conditions
        from hedge.flux import make_normal
        normal = make_normal(d)

        from hedge.tools import join_fields

        # Dirichlet
        dir_c = BoundarizeOperator(self.dirichlet_tag) * c
        dir_u = BoundarizeOperator(self.dirichlet_tag) * u
        dir_v = BoundarizeOperator(self.dirichlet_tag) * v

        dir_bc = join_fields(dir_c, -dir_u, dir_v)

        # Neumann
        neu_c = BoundarizeOperator(self.neumann_tag) * c
        neu_u = BoundarizeOperator(self.neumann_tag) * u
        neu_v = BoundarizeOperator(self.neumann_tag) * v

        neu_bc = join_fields(neu_c, neu_u, -neu_v)

        # Radiation
        from hedge.optemplate import make_normal
        rad_normal = make_normal(self.radiation_tag, d)

        rad_c = BoundarizeOperator(self.radiation_tag) * c
        rad_u = BoundarizeOperator(self.radiation_tag) * u
        rad_v = BoundarizeOperator(self.radiation_tag) * v

        rad_bc = join_fields(
            rad_c,
            0.5 * (rad_u - self.time_sign * numpy.dot(rad_normal, rad_v)),
            0.5 * rad_normal *
            (numpy.dot(rad_normal, rad_v) - self.time_sign * rad_u))

        # }}}

        # {{{ diffusion -------------------------------------------------------
        from pytools.obj_array import with_object_array_or_scalar

        def make_diffusion(arg):
            if with_sensor or (self.diffusion_coeff is not None
                               and self.diffusion_coeff != 0):
                if self.diffusion_coeff is None:
                    diffusion_coeff = 0
                else:
                    diffusion_coeff = self.diffusion_coeff

                if with_sensor:
                    diffusion_coeff += Field("sensor")

                from hedge.second_order import SecondDerivativeTarget

                # strong_form here allows the reuse the value of grad u.
                grad_tgt = SecondDerivativeTarget(
                    self.dimensions, strong_form=True, operand=arg)

                self.diffusion_scheme.grad(
                    grad_tgt,
                    bc_getter=None,
                    dirichlet_tags=[],
                    neumann_tags=[])

                div_tgt = SecondDerivativeTarget(
                    self.dimensions,
                    strong_form=False,
                    operand=diffusion_coeff * grad_tgt.minv_all)

                self.diffusion_scheme.div(
                    div_tgt,
                    bc_getter=None,
                    dirichlet_tags=[],
                    neumann_tags=[])

                return div_tgt.minv_all
            else:
                return 0

        # }}}

        # entire operator -----------------------------------------------------
        nabla = make_nabla(d)
        flux_op = get_flux_operator(self.flux())

        return (
            -join_fields(
                -self.time_sign * c * numpy.dot(nabla, v) - make_diffusion(u),
                -self.time_sign * c *
                (nabla * u) - with_object_array_or_scalar(make_diffusion, v)) +
            InverseMassOperator() * (flux_op(flux_w) + flux_op(
                BoundaryPair(flux_w, dir_bc, self.dirichlet_tag)) + flux_op(
                    BoundaryPair(flux_w, neu_bc, self.neumann_tag)) + flux_op(
                        BoundaryPair(flux_w, rad_bc, self.radiation_tag))))
Beispiel #35
0
 def normal_times_flux(self, flux):
     from hedge.flux import make_normal
     return self.vec_times(make_normal(self.dimensions), flux)
Beispiel #36
0
 def normal_times_flux(self, flux):
     from hedge.flux import make_normal
     return self.vec_times(make_normal(self.dimensions), flux)
def test_interior_fluxes_tet():
    """Check tetrahedron surface integrals computed using interior fluxes
    against their known values.
    """

    import meshpy.tet as tet
    from math import pi, sin, cos

    mesh_info = tet.MeshInfo()

    # construct a two-box extrusion of this base
    base = [(-pi, -pi, 0), (pi, -pi, 0), (pi, pi, 0), (-pi, pi, 0)]

    # first, the nodes
    mesh_info.set_points(base + [(x, y, z + pi) for x, y, z in base] + [(x, y, z + pi + 1) for x, y, z in base])

    # next, the facets

    # vertex indices for a box missing the -z face
    box_without_minus_z = [[4, 5, 6, 7], [0, 4, 5, 1], [1, 5, 6, 2], [2, 6, 7, 3], [3, 7, 4, 0]]

    def add_to_all_vertex_indices(facets, increment):
        return [[pt + increment for pt in facet] for facet in facets]

    mesh_info.set_facets(
        [[0, 1, 2, 3]]  # base
        + box_without_minus_z  # first box
        + add_to_all_vertex_indices(box_without_minus_z, 4)  # second box
    )

    # set the volume properties -- this is where the tet size constraints are
    mesh_info.regions.resize(2)
    mesh_info.regions[0] = [
        0,
        0,
        pi / 2,  # point in volume -> first box
        0,  # region tag (user-defined number)
        0.5,  # max tet volume in region
    ]
    mesh_info.regions[1] = [
        0,
        0,
        pi + 0.5,  # point in volume -> second box
        1,  # region tag (user-defined number, arbitrary)
        0.1,  # max tet volume in region
    ]

    generated_mesh = tet.build(mesh_info, attributes=True, volume_constraints=True)

    from hedge.mesh import make_conformal_mesh

    mesh = make_conformal_mesh(generated_mesh.points, generated_mesh.elements)

    from hedge.discretization.local import TetrahedronDiscretization
    from hedge.discretization import ones_on_volume

    discr = discr_class(mesh, TetrahedronDiscretization(4), debug=discr_class.noninteractive_debug_flags())

    def f_u(x, el):
        if generated_mesh.element_attributes[el.id] == 1:
            return cos(x[0] - x[1] + x[2])
        else:
            return 0

    def f_l(x, el):
        if generated_mesh.element_attributes[el.id] == 0:
            return sin(x[0] - x[1] + x[2])
        else:
            return 0

    u_l = discr.interpolate_volume_function(f_l)
    u_u = discr.interpolate_volume_function(f_u)
    u = u_l + u_u

    # visualize the produced field
    # from hedge.visualization import SiloVisualizer
    # vis = SiloVisualizer(discr)
    # visf = vis.make_file("sandwich")
    # vis.add_data(visf,
    # [("u_l", u_l), ("u_u", u_u)],
    # expressions=[("u", "u_l+u_u")])

    # make sure the surface integral of the difference
    # between top and bottom is zero
    from hedge.flux import make_normal, FluxScalarPlaceholder
    from hedge.optemplate import Field, get_flux_operator

    fluxu = FluxScalarPlaceholder()
    res = discr.compile(get_flux_operator((fluxu.int - fluxu.ext) * make_normal(discr.dimensions)[1]) * Field("u"))(u=u)

    from hedge.discretization import ones_on_volume

    ones = ones_on_volume(discr)
    assert abs(numpy.dot(res, ones)) < 5e-14
Beispiel #38
0
    def op_template(self, with_sensor=False):
        from hedge.optemplate import \
                Field, \
                make_sym_vector, \
                BoundaryPair, \
                get_flux_operator, \
                make_nabla, \
                InverseMassOperator, \
                BoundarizeOperator

        d = self.dimensions

        w = make_sym_vector("w", d+1)
        u = w[0]
        v = w[1:]

        from hedge.tools import join_fields
        flux_w = join_fields(self.c, w)

        # {{{ boundary conditions
        from hedge.tools import join_fields

        # Dirichlet
        dir_c = BoundarizeOperator(self.dirichlet_tag) * self.c
        dir_u = BoundarizeOperator(self.dirichlet_tag) * u
        dir_v = BoundarizeOperator(self.dirichlet_tag) * v

        dir_bc = join_fields(dir_c, -dir_u, dir_v)

        # Neumann
        neu_c = BoundarizeOperator(self.neumann_tag) * self.c
        neu_u = BoundarizeOperator(self.neumann_tag) * u
        neu_v = BoundarizeOperator(self.neumann_tag) * v

        neu_bc = join_fields(neu_c, neu_u, -neu_v)

        # Radiation
        from hedge.optemplate import make_normal
        rad_normal = make_normal(self.radiation_tag, d)

        rad_c = BoundarizeOperator(self.radiation_tag) * self.c
        rad_u = BoundarizeOperator(self.radiation_tag) * u
        rad_v = BoundarizeOperator(self.radiation_tag) * v

        rad_bc = join_fields(
                rad_c,
                0.5*(rad_u - self.time_sign*np.dot(rad_normal, rad_v)),
                0.5*rad_normal*(np.dot(rad_normal, rad_v) - self.time_sign*rad_u)
                )

        # }}}

        # {{{ diffusion -------------------------------------------------------
        from pytools.obj_array import with_object_array_or_scalar

        def make_diffusion(arg):
            if with_sensor or (
                    self.diffusion_coeff is not None and self.diffusion_coeff != 0):
                if self.diffusion_coeff is None:
                    diffusion_coeff = 0
                else:
                    diffusion_coeff = self.diffusion_coeff

                if with_sensor:
                    diffusion_coeff += Field("sensor")

                from hedge.second_order import SecondDerivativeTarget

                # strong_form here allows the reuse the value of grad u.
                grad_tgt = SecondDerivativeTarget(
                        self.dimensions, strong_form=True,
                        operand=arg)

                self.diffusion_scheme.grad(grad_tgt, bc_getter=None,
                        dirichlet_tags=[], neumann_tags=[])

                div_tgt = SecondDerivativeTarget(
                        self.dimensions, strong_form=False,
                        operand=diffusion_coeff*grad_tgt.minv_all)

                self.diffusion_scheme.div(div_tgt,
                        bc_getter=None,
                        dirichlet_tags=[], neumann_tags=[])

                return div_tgt.minv_all
            else:
                return 0

        # }}}

        # entire operator -----------------------------------------------------
        nabla = make_nabla(d)
        flux_op = get_flux_operator(self.flux())

        return (
                - join_fields(
                    - self.time_sign*self.c*np.dot(nabla, v) - make_diffusion(u)
                    + self.source,

                    -self.time_sign*self.c*(nabla*u) - with_object_array_or_scalar(
                        make_diffusion, v)
                    )
                +
                InverseMassOperator() * (
                    flux_op(flux_w)
                    + flux_op(BoundaryPair(flux_w, dir_bc, self.dirichlet_tag))
                    + flux_op(BoundaryPair(flux_w, neu_bc, self.neumann_tag))
                    + flux_op(BoundaryPair(flux_w, rad_bc, self.radiation_tag))
                    ))
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 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