Exemple #1
0
def get_bc_parts(mesh, lst):
    """
    Build a size_t function with boundary condition parts.

    Returns all Robin and Steklov conditions that need to be applied,
    the shift needed to get a nonnegative function,
    and the function itself.
    """
    if len(lst) > 0:
        shift = max(0, -min(e.value for e in lst))
    else:
        return [], [], 0, FacetFunction("size_t", mesh, 0)
    # values must be shifted by smallest Steklov value since size_t is unsigned
    fun = FacetFunction("size_t", mesh, shift)
    for bc in lst:
        sub = OnBoundary()
        # overwrite inside function with the one from bc
        sub.inside = bc.getTest()
        sub.mark(fun, bc.value + shift)
    # some conditions may cancel eachother
    exist = set(np.unique(fun.array()))
    lst = [e for e in lst if e.value + shift in exist]
    # separate Robin and Steklov, Dirichlet and Neumann are irrelevant
    Robin = [e for e in lst if e.value > 1 and e.parValue != 0]
    Steklov = [e for e in lst if e.value < 0 and e.parValue != 0]
    return Robin, Steklov, shift, fun
Exemple #2
0
def get_bc_parts(mesh, lst):
    """
    Build a size_t function with boundary condition parts.

    Returns all Robin and Steklov conditions that need to be applied,
    the shift needed to get a nonnegative function,
    and the function itself.
    """
    if len(lst) > 0:
        shift = max(0, -min(e.value for e in lst))
    else:
        return [], [], 0, FacetFunction("size_t", mesh, 0)
    # values must be shifted by smallest Steklov value since size_t is unsigned
    fun = FacetFunction("size_t", mesh, shift)
    for bc in lst:
        sub = OnBoundary()
        # overwrite inside function with the one from bc
        sub.inside = bc.getTest()
        sub.mark(fun, bc.value + shift)
    # some conditions may cancel eachother
    exist = set(np.unique(fun.array()))
    lst = [e for e in lst if e.value+shift in exist]
    # separate Robin and Steklov, Dirichlet and Neumann are irrelevant
    Robin = [e for e in lst if e.value > 1 and e.parValue != 0]
    Steklov = [e for e in lst if e.value < 0 and e.parValue != 0]
    return Robin, Steklov, shift, fun
Exemple #3
0
def mark_conditions(mesh, lst):
    """ Mark all boundary conditions from the list. """
    fun = FacetFunction("int", mesh, 0)
    for bc in lst:
        sub = OnBoundary()
        # overwrite inside function with the one from bc
        sub.inside = bc.getTest()
        sub.mark(fun, bc.value)
    return fun.array()
 def mesh_generator(n):
     mesh = RectangleMesh(1.0, 0.0, 2.0, 1.0, n, n, 'left/right')
     domains = CellFunction('uint', mesh)
     domains.set_all(0)
     dx = Measure('dx')[domains]
     boundaries = FacetFunction('uint', mesh)
     boundaries.set_all(0)
     ds = Measure('ds')[boundaries]
     return mesh, dx, ds
Exemple #5
0
def mark_conditions(mesh, lst):
    """ Mark all boundary conditions from the list. """
    fun = FacetFunction("int", mesh, 0)
    for bc in lst:
        sub = OnBoundary()
        # overwrite inside function with the one from bc
        sub.inside = bc.getTest()
        sub.mark(fun, bc.value)
    return fun.array()
Exemple #6
0
def square_with_obstacle():
    # Create classes for defining parts of the boundaries and the interior
    # of the domain
    class Left(SubDomain):
        def inside(self, x, on_boundary):
            return near(x[0], 0.0)

    class Right(SubDomain):
        def inside(self, x, on_boundary):
            return near(x[0], 1.0)

    class Bottom(SubDomain):
        def inside(self, x, on_boundary):
            return near(x[1], 0.0)

    class Top(SubDomain):
        def inside(self, x, on_boundary):
            return near(x[1], 1.0)

    class Obstacle(SubDomain):
        def inside(self, x, on_boundary):
            return (between(x[1], (0.5, 0.7)) and between(x[0], (0.2, 1.0)))

    # Initialize sub-domain instances
    left = Left()
    top = Top()
    right = Right()
    bottom = Bottom()
    obstacle = Obstacle()

    # Define mesh
    mesh = UnitSquareMesh(100, 100, 'crossed')

    # Initialize mesh function for interior domains
    domains = CellFunction('size_t', mesh)
    domains.set_all(0)
    obstacle.mark(domains, 1)

    # Initialize mesh function for boundary domains
    boundaries = FacetFunction('size_t', mesh)
    boundaries.set_all(0)
    left.mark(boundaries, 1)
    top.mark(boundaries, 2)
    right.mark(boundaries, 3)
    bottom.mark(boundaries, 4)

    boundary_indices = {'left': 1,
                        'top': 2,
                        'right': 3,
                        'bottom': 4}
    f = Constant(0.0)
    theta0 = Constant(293.0)
    return mesh, f, boundaries, boundary_indices, theta0
Exemple #7
0
def test_store_mesh(casedir):
    pp = PostProcessor(dict(casedir=casedir))

    from dolfin import (UnitSquareMesh, CellFunction, FacetFunction,
                        AutoSubDomain, Mesh, HDF5File, assemble, Expression,
                        ds, dx)

    # Store mesh
    mesh = UnitSquareMesh(6, 6)
    celldomains = CellFunction("size_t", mesh)
    celldomains.set_all(0)
    AutoSubDomain(lambda x: x[0] < 0.5).mark(celldomains, 1)

    facetdomains = FacetFunction("size_t", mesh)
    AutoSubDomain(lambda x, on_boundary: x[0] < 0.5 and on_boundary).mark(
        facetdomains, 1)

    pp.store_mesh(mesh, celldomains, facetdomains)

    # Read mesh back
    mesh2 = Mesh()
    f = HDF5File(mpi_comm_world(), os.path.join(pp.get_casedir(), "mesh.hdf5"),
                 'r')
    f.read(mesh2, "Mesh", False)

    celldomains2 = CellFunction("size_t", mesh2)
    f.read(celldomains2, "CellDomains")
    facetdomains2 = FacetFunction("size_t", mesh2)
    f.read(facetdomains2, "FacetDomains")

    e = Expression("1+x[1]", degree=1)

    dx1 = dx(1, domain=mesh, subdomain_data=celldomains)
    dx2 = dx(1, domain=mesh2, subdomain_data=celldomains2)
    C1 = assemble(e * dx1)
    C2 = assemble(e * dx2)
    assert abs(C1 - C2) < 1e-10

    ds1 = ds(1, domain=mesh, subdomain_data=facetdomains)
    ds2 = ds(1, domain=mesh2, subdomain_data=facetdomains2)
    F1 = assemble(e * ds1)
    F2 = assemble(e * ds2)
    assert abs(F1 - F2) < 1e-10
Exemple #8
0
def derived_bcs(V, original_bcs, u_):

    new_bcs = []

    # Check first if user has declared subdomains
    subdomain = original_bcs[0].user_sub_domain()
    if subdomain is None:
        mesh = V.mesh()
        ff = FacetFunction("size_t", mesh, 0)
        for i, bc in enumerate(original_bcs):
            bc.apply(u_[0].vector())  # Need to initialize bc
            m = bc.markers()  # Get facet indices of boundary
            ff.array()[m] = i + 1
            new_bcs.append(DirichletBC(V, Constant(0), ff, i + 1))

    else:
        for i, bc in enumerate(original_bcs):
            subdomain = bc.user_sub_domain()
            new_bcs.append(DirichletBC(V, Constant(0), subdomain))

    return new_bcs
Exemple #9
0
def derived_bcs(V, original_bcs, u_):

    new_bcs = []

    # Check first if user has declared subdomains
    subdomain = original_bcs[0].user_sub_domain()
    if subdomain is None:
        mesh = V.mesh()
        ff = FacetFunction("size_t", mesh, 0)
        for i, bc in enumerate(original_bcs):
            bc.apply(u_[0].vector())  # Need to initialize bc
            m = bc.markers()  # Get facet indices of boundary
            ff.array()[m] = i + 1
            new_bcs.append(DirichletBC(V, Constant(0), ff, i + 1))

    else:
        for i, bc in enumerate(original_bcs):
            subdomain = bc.user_sub_domain()
            new_bcs.append(DirichletBC(V, Constant(0), subdomain))

    return new_bcs
Exemple #10
0
def as_pvd(h5_file):
    '''Store facet and cell function for pvd'''
    root, ext = os.path.splitext(h5_file)

    mesh = Mesh()
    hdf = HDF5File(mesh.mpi_comm(), h5_file, 'r')
    hdf.read(mesh, '/mesh', False)

    facet_markers = FacetFunction('size_t', mesh)
    hdf.read(facet_markers, '/facet_markers')

    cell_markers = CellFunction('size_t', mesh)
    hdf.read(cell_markers, '/cell_markers')

    File(root + 'facets' + '.pvd') << facet_markers
    File(root + 'volumes' + '.pvd') << cell_markers

    return True
Exemple #11
0
def les_setup(u_, mesh, Wale, bcs, CG1Function, nut_krylov_solver, **NS_namespace):
    """Set up for solving Wale LES model
    """
    DG = FunctionSpace(mesh, "DG", 0)
    CG1 = FunctionSpace(mesh, "CG", 1)
    
    # Compute cell size and put in delta
    delta = Function(DG)
    delta.vector().zero()
    delta.vector().axpy(1.0, assemble(TestFunction(DG)*dx))
    
    # Set up Wale form
    Gij = grad(u_)
    Sij = sym(Gij)
    Skk = tr(Sij)
    dim = mesh.geometry().dim()
    Sd = sym(Gij*Gij) - 1./3.*Identity(mesh.geometry().dim())*Skk*Skk 
    nut_form = Wale['Cw']**2 * pow(delta, 2./dim) * pow(inner(Sd, Sd), 1.5) / (Max(pow(inner(Sij, Sij), 2.5) + pow(inner(Sd, Sd), 1.25), 1e-6))
    ff = FacetFunction("size_t", mesh, 0)
    bcs_nut = derived_bcs(CG1, bcs['u0'], u_)
    nut_ = CG1Function(nut_form, mesh, method=nut_krylov_solver, bcs=bcs_nut, name='nut', bounded=True)
    return dict(Sij=Sij, Sd=Sd, Skk=Skk, nut_=nut_, delta=delta, bcs_nut=bcs_nut)
Exemple #12
0
def marked_boundary(mesh):
    """ Return array of vertex values with 1 on boundary, 0 otherwise. """
    fun = FacetFunction("int", mesh, 0)
    on = OnBoundary()
    on.mark(fun, 1)
    return fun.array()
Exemple #13
0
def marked_boundary(mesh):
    """ Return array of vertex values with 1 on boundary, 0 otherwise. """
    fun = FacetFunction("int", mesh, 0)
    on = OnBoundary()
    on.mark(fun, 1)
    return fun.array()
Exemple #14
0
    def solve(self):
        """ Find eigenvalues for transformed mesh. """
        self.progress("Building mesh.")
        # build transformed mesh
        mesh = self.refineMesh()
        # dim = mesh.topology().dim()
        if self.bcLast:
            mesh = transform_mesh(mesh, self.transformList)
            Robin, Steklov, shift, bcs = get_bc_parts(mesh, self.bcList)
        else:
            Robin, Steklov, shift, bcs = get_bc_parts(mesh, self.bcList)
            mesh = transform_mesh(mesh, self.transformList)
            # boundary conditions computed on non-transformed mesh
            # copy the values to transformed mesh
            fun = FacetFunction("size_t", mesh, shift)
            fun.array()[:] = bcs.array()[:]
            bcs = fun
        ds = Measure('ds', domain=mesh, subdomain_data=bcs)
        V = FunctionSpace(mesh, self.method, self.deg)
        u = TrialFunction(V)
        v = TestFunction(V)
        self.progress("Assembling matrices.")
        wTop = Expression(self.wTop, degree=self.deg)
        wBottom = Expression(self.wBottom, degree=self.deg)

        #
        # build stiffness matrix form
        #
        s = dot(grad(u), grad(v))*wTop*dx
        # add Robin parts
        for bc in Robin:
            s += Constant(bc.parValue)*u*v*wTop*ds(bc.value+shift)

        #
        # build mass matrix form
        #
        if len(Steklov) > 0:
            m = 0
            for bc in Steklov:
                m += Constant(bc.parValue)*u*v*wBottom*ds(bc.value+shift)
        else:
            m = u*v*wBottom*dx

        # assemble
        # if USE_EIGEN:
        #     S, M = EigenMatrix(), EigenMatrix()
            # tempv = EigenVector()
        # else:
        S, M = PETScMatrix(), PETScMatrix()
        # tempv = PETScVector()

        if not np.any(bcs.array() == shift+1):
            # no Dirichlet parts
            assemble(s, tensor=S)
            assemble(m, tensor=M)
        else:
            #
            # with EIGEN we could
            #   apply Dirichlet condition symmetrically
            #   completely remove rows and columns
            #
            # Dirichlet parts are marked with shift+1
            #
            # temp = Constant(0)*v*dx
            bc = DirichletBC(V, Constant(0.0), bcs, shift+1)
            # assemble_system(s, temp, bc, A_tensor=S, b_tensor=tempv)
            # assemble_system(m, temp, bc, A_tensor=M, b_tensor=tempv)
            assemble(s, tensor=S)
            bc.apply(S)
            assemble(m, tensor=M)
            # bc.zero(M)

        # if USE_EIGEN:
        #    M = M.sparray()
        #    M.eliminate_zeros()
        #    print M.shape
        #    indices = M.indptr[:-1] - M.indptr[1:] < 0
        #    M = M[indices, :].tocsc()[:, indices]
        #    S = S.sparray()[indices, :].tocsc()[:, indices]
        #    print M.shape
        #
        # solve the eigenvalue problem
        #
        self.progress("Solving eigenvalue problem.")
        eigensolver = SLEPcEigenSolver(S, M)
        eigensolver.parameters["problem_type"] = "gen_hermitian"
        eigensolver.parameters["solver"] = "krylov-schur"
        if self.target is not None:
            eigensolver.parameters["spectrum"] = "target real"
            eigensolver.parameters["spectral_shift"] = self.target
        else:
            eigensolver.parameters["spectrum"] = "smallest magnitude"
            eigensolver.parameters["spectral_shift"] = -0.01
        eigensolver.parameters["spectral_transform"] = "shift-and-invert"
        eigensolver.solve(self.number)
        self.progress("Generating eigenfunctions.")
        if eigensolver.get_number_converged() == 0:
            return None
        eigf = []
        eigv = []
        if self.deg > 1:
            mesh = refine(mesh)
        W = FunctionSpace(mesh, 'CG', 1)
        for i in range(eigensolver.get_number_converged()):
            pair = eigensolver.get_eigenpair(i)[::2]
            eigv.append(pair[0])
            u = Function(V)
            u.vector()[:] = pair[1]
            eigf.append(interpolate(u, W))
        return eigv, eigf
Exemple #15
0
def les_setup(u_, mesh, assemble_matrix, CG1Function, nut_krylov_solver, bcs, **NS_namespace):
    """
    Set up for solving the Germano Dynamic LES model applying
    Lagrangian Averaging.
    """
    
    # Create function spaces
    CG1 = FunctionSpace(mesh, "CG", 1)
    p, q = TrialFunction(CG1), TestFunction(CG1)
    dim = mesh.geometry().dim()
    
    # Define delta and project delta**2 to CG1
    delta = pow(CellVolume(mesh), 1./dim)
    delta_CG1_sq = project(delta, CG1)
    delta_CG1_sq.vector().set_local(delta_CG1_sq.vector().array()**2)
    delta_CG1_sq.vector().apply("insert")

    # Define nut_
    Sij = sym(grad(u_))
    magS = sqrt(2*inner(Sij,Sij))
    Cs = Function(CG1)
    nut_form = Cs**2 * delta**2 * magS
    # Create nut_ BCs
    ff = FacetFunction("size_t", mesh, 0)
    bcs_nut = []
    for i, bc in enumerate(bcs['u0']):
        bc.apply(u_[0].vector()) # Need to initialize bc
        m = bc.markers() # Get facet indices of boundary
        ff.array()[m] = i+1
        bcs_nut.append(DirichletBC(CG1, Constant(0), ff, i+1))
    nut_ = CG1Function(nut_form, mesh, method=nut_krylov_solver, bcs=bcs_nut, bounded=True, name="nut")

    # Create functions for holding the different velocities
    u_CG1 = as_vector([Function(CG1) for i in range(dim)])
    u_filtered = as_vector([Function(CG1) for i in range(dim)])
    dummy = Function(CG1)
    ll = LagrangeInterpolator()

    # Assemble required filter matrices and functions
    G_under = Function(CG1, assemble(TestFunction(CG1)*dx))
    G_under.vector().set_local(1./G_under.vector().array())
    G_under.vector().apply("insert")
    G_matr = assemble(inner(p,q)*dx)

    # Set up functions for Lij and Mij
    Lij = [Function(CG1) for i in range(dim*dim)]
    Mij = [Function(CG1) for i in range(dim*dim)]
    # Check if case is 2D or 3D and set up uiuj product pairs and 
    # Sij forms, assemble required matrices
    Sijcomps = [Function(CG1) for i in range(dim*dim)]
    Sijfcomps = [Function(CG1) for i in range(dim*dim)]
    # Assemble some required matrices for solving for rate of strain terms
    Sijmats = [assemble_matrix(p.dx(i)*q*dx) for i in range(dim)]
    if dim == 3:
        tensdim = 6
        uiuj_pairs = ((0,0),(0,1),(0,2),(1,1),(1,2),(2,2))
    else:
        tensdim = 3
        uiuj_pairs = ((0,0),(0,1),(1,1))
    
    # Set up Lagrange functions
    JLM = Function(CG1)
    JLM.vector()[:] += 1E-32
    JMM = Function(CG1)
    JMM.vector()[:] += 1
    
    return dict(Sij=Sij, nut_form=nut_form, nut_=nut_, delta=delta, bcs_nut=bcs_nut,
                delta_CG1_sq=delta_CG1_sq, CG1=CG1, Cs=Cs, u_CG1=u_CG1, 
                u_filtered=u_filtered, ll=ll, Lij=Lij, Mij=Mij, Sijcomps=Sijcomps, 
                Sijfcomps=Sijfcomps, Sijmats=Sijmats, JLM=JLM, JMM=JMM, dim=dim, 
                tensdim=tensdim, G_matr=G_matr, G_under=G_under, dummy=dummy, 
                uiuj_pairs=uiuj_pairs) 
Exemple #16
0
    def solve(self):
        """ Find eigenvalues for transformed mesh. """
        self.progress("Building mesh.")
        # build transformed mesh
        mesh = self.refineMesh()
        # dim = mesh.topology().dim()
        if self.bcLast:
            mesh = transform_mesh(mesh, self.transformList)
            Robin, Steklov, shift, bcs = get_bc_parts(mesh, self.bcList)
        else:
            Robin, Steklov, shift, bcs = get_bc_parts(mesh, self.bcList)
            mesh = transform_mesh(mesh, self.transformList)
            # boundary conditions computed on non-transformed mesh
            # copy the values to transformed mesh
            fun = FacetFunction("size_t", mesh, shift)
            fun.array()[:] = bcs.array()[:]
            bcs = fun
        ds = Measure('ds', domain=mesh, subdomain_data=bcs)
        V = FunctionSpace(mesh, self.method, self.deg)
        u = TrialFunction(V)
        v = TestFunction(V)
        self.progress("Assembling matrices.")
        wTop = Expression(self.wTop)
        wBottom = Expression(self.wBottom)

        #
        # build stiffness matrix form
        #
        s = dot(grad(u), grad(v)) * wTop * dx
        # add Robin parts
        for bc in Robin:
            s += Constant(bc.parValue) * u * v * wTop * ds(bc.value + shift)

        #
        # build mass matrix form
        #
        if len(Steklov) > 0:
            m = 0
            for bc in Steklov:
                m += Constant(
                    bc.parValue) * u * v * wBottom * ds(bc.value + shift)
        else:
            m = u * v * wBottom * dx

        # assemble
        # if USE_EIGEN:
        #     S, M = EigenMatrix(), EigenMatrix()
        # tempv = EigenVector()
        # else:
        S, M = PETScMatrix(), PETScMatrix()
        # tempv = PETScVector()

        if not np.any(bcs.array() == shift + 1):
            # no Dirichlet parts
            assemble(s, tensor=S)
            assemble(m, tensor=M)
        else:
            #
            # with EIGEN we could
            #   apply Dirichlet condition symmetrically
            #   completely remove rows and columns
            #
            # Dirichlet parts are marked with shift+1
            #
            # temp = Constant(0)*v*dx
            bc = DirichletBC(V, Constant(0.0), bcs, shift + 1)
            # assemble_system(s, temp, bc, A_tensor=S, b_tensor=tempv)
            # assemble_system(m, temp, bc, A_tensor=M, b_tensor=tempv)
            assemble(s, tensor=S)
            bc.apply(S)
            assemble(m, tensor=M)
            # bc.zero(M)

        # if USE_EIGEN:
        #    M = M.sparray()
        #    M.eliminate_zeros()
        #    print M.shape
        #    indices = M.indptr[:-1] - M.indptr[1:] < 0
        #    M = M[indices, :].tocsc()[:, indices]
        #    S = S.sparray()[indices, :].tocsc()[:, indices]
        #    print M.shape
        #
        # solve the eigenvalue problem
        #
        self.progress("Solving eigenvalue problem.")
        eigensolver = SLEPcEigenSolver(S, M)
        eigensolver.parameters["problem_type"] = "gen_hermitian"
        eigensolver.parameters["solver"] = "krylov-schur"
        if self.target is not None:
            eigensolver.parameters["spectrum"] = "target real"
            eigensolver.parameters["spectral_shift"] = self.target
        else:
            eigensolver.parameters["spectrum"] = "smallest magnitude"
            eigensolver.parameters["spectral_shift"] = -0.01
        eigensolver.parameters["spectral_transform"] = "shift-and-invert"
        eigensolver.solve(self.number)
        self.progress("Generating eigenfunctions.")
        if eigensolver.get_number_converged() == 0:
            return None
        eigf = []
        eigv = []
        if self.deg > 1:
            mesh = refine(mesh)
        W = FunctionSpace(mesh, 'CG', 1)
        for i in range(eigensolver.get_number_converged()):
            pair = eigensolver.get_eigenpair(i)[::2]
            eigv.append(pair[0])
            u = Function(V)
            u.vector()[:] = pair[1]
            eigf.append(interpolate(u, W))
        return eigv, eigf
Exemple #17
0
class InflowBoundary(SubDomain):
    def inside(self, x, on_boundary):
        return on_boundary and near(x[0], x_min)


class NoslipBoundary(SubDomain):
    def inside(self, x, on_boundary):
        dx = x[0] - c_x
        dy = x[1] - c_y
        dr = sqrt(dx**2 + dy**2)
        return on_boundary and (near(x[1] *
                                     (y_max - x[1]), 0) or dr < r + 1E-3)


f_f = FacetFunction('size_t', mesh, 0)
InflowBoundary().mark(f_f, 13)
NoslipBoundary().mark(f_f, 12)


# Width of the L domain
def compute_width_L_cylinder(unit):
    return 4 * unit + 4 * unit * cos(pi / 4)


# Width of the O domain
def compute_width_O_cylinder(unit):
    return 4 * unit


class InflowProfileConstant(Expression):
Exemple #18
0
def peter():
    base = '../meshes/2d/peter'
    #base = '../meshes/2d/peter-fine'
    mesh = Mesh(base + '.xml')

    subdomains = MeshFunction('size_t', mesh, base+'_physical_region.xml')

    workpiece_index = 3
    subdomain_materials = {1: 'SiC',
                           2: 'carbon steel',
                           3: 'GaAs (liquid)'}

    submesh_workpiece = SubMesh(mesh, subdomains, workpiece_index)
    W = VectorFunctionSpace(submesh_workpiece, 'CG', 2)
    Q = FunctionSpace(submesh_workpiece, 'CG', 2)

    # Define melt boundaries.
    class LeftBoundary(SubDomain):
        def inside(self, x, on_boundary):
            # Be especially careful in the corners when defining the r=0 axis:
            # For the PPE to be consistent, we need to have n.u=0 *everywhere*
            # on the non-(r=0) boundaries.
            return on_boundary \
                and x[0] < GMSH_EPS \
                and 0.005+GMSH_EPS < x[1] and x[1] < 0.050-GMSH_EPS

    class SurfaceBoundary(SubDomain):
        def inside(self, x, on_boundary):
            return on_boundary \
                and 0.055-GMSH_EPS < x[1] \
                and 0.030-GMSH_EPS < x[0] and x[0] < 0.075+GMSH_EPS

    class StampBoundary(SubDomain):
        def inside(self, x, on_boundary):
            # Well well. If we don't include the endpoints here, the PPE turns
            # out inconsistent. This is weird since the endpoints should be
            # picked up by RightBoundary and StampBoundary.
            return on_boundary \
                and 0.050-GMSH_EPS < x[1] and x[1] < 0.055+GMSH_EPS \
                and x[0] < 0.030+GMSH_EPS

    class LowerBoundary(SubDomain):
        def inside(self, x, on_boundary):
            # Danger, danger.
            # If the rightmost point (0.075, 0.010) is excluded, the PPE will
            # end up inconsistent.
            # This is actually weird since it should be picked up by
            # RightBoundary.
            return on_boundary \
                and (x[1] < 0.005+GMSH_EPS
                     or (x[0] > 0.070-GMSH_EPS and x[1] < 0.010+GMSH_EPS)
                     )

    class RightBoundary(SubDomain):
        def inside(self, x, on_boundary):
            return on_boundary \
                and x[0] > 0.075-GMSH_EPS

    left_boundary = LeftBoundary()
    lower_boundary = LowerBoundary()
    right_boundary = RightBoundary()
    surface_boundary = SurfaceBoundary()
    stamp_boundary = StampBoundary()

    # Define workpiece boundaries.
    wp_boundaries = FacetFunction('size_t', submesh_workpiece)
    wp_boundaries.set_all(0)
    left_boundary.mark(wp_boundaries, 1)
    lower_boundary.mark(wp_boundaries, 2)
    right_boundary.mark(wp_boundaries, 3)
    surface_boundary.mark(wp_boundaries, 4)
    stamp_boundary.mark(wp_boundaries, 5)

    # For local use only:
    wp_boundary_indices = {'left': 1,
                           'lower': 2,
                           'right': 3,
                           'surface': 4,
                           'stamp': 5}

    # Boundary conditions for the velocity.
    u_bcs = [DirichletBC(W, (0.0, 0.0), stamp_boundary),
             DirichletBC(W, (0.0, 0.0), right_boundary),
             DirichletBC(W, (0.0, 0.0), lower_boundary),
             DirichletBC(W.sub(0), 0.0, left_boundary),
             DirichletBC(W.sub(1), 0.0, surface_boundary),
             ]
    p_bcs = []

    # Boundary conditions for the heat equation.
    # Dirichlet
    theta_bcs_d = []
    # Neumann
    theta_bcs_n = {}
    # Robin, i.e.,
    #
    #    -dtheta/dn = alpha (theta - theta0)
    #
    # (with alpha>0 to preserve coercivity of the scheme).
    #
    theta_bcs_r = {
        wp_boundary_indices['stamp']: (100.0, 1500.0),
        wp_boundary_indices['surface']: (100.0, 1550.0),
        wp_boundary_indices['right']: (300.0, Expression('200*x[0] + 1600', degree=1)),
        wp_boundary_indices['lower']: (300.0, Expression('-1200*x[1] + 1614', degree=1)),
        }
    return mesh, subdomains, subdomain_materials, workpiece_index, \
        wp_boundaries, W, u_bcs, p_bcs, \
        Q, theta_bcs_d, theta_bcs_n, theta_bcs_r
Exemple #19
0
def coil_in_box():
    mesh = Mesh('../meshes/2d/coil-in-box.xml')

    f = Constant(0.0)

    # Define mesh and boundaries.
    class LeftBoundary(SubDomain):
        def inside(self, x, on_boundary):
            return on_boundary and x[0] < GMSH_EPS
    left_boundary = LeftBoundary()

    class RightBoundary(SubDomain):
        def inside(self, x, on_boundary):
            return on_boundary and x[0] > 2.5 - GMSH_EPS
    right_boundary = RightBoundary()

    class LowerBoundary(SubDomain):
        def inside(self, x, on_boundary):
            return on_boundary and x[1] < GMSH_EPS
    lower_boundary = LowerBoundary()

    class UpperBoundary(SubDomain):
        def inside(self, x, on_boundary):
            return on_boundary and x[1] > 0.4-GMSH_EPS
    upper_boundary = UpperBoundary()

    class CoilBoundary(SubDomain):
        def inside(self, x, on_boundary):
            return on_boundary \
                and x[0] > GMSH_EPS and x[0] < 2.5-GMSH_EPS \
                and x[1] > GMSH_EPS and x[1] < 0.4-GMSH_EPS
    coil_boundary = CoilBoundary()

    #heater_temp = 380.0
    #room_temp = 293.0
    #bcs = [(coil_boundary, heater_temp),
    #       (left_boundary, room_temp),
    #       (right_boundary, room_temp),
    #       (upper_boundary, room_temp),
    #       (lower_boundary, room_temp)
    #       ]

    boundaries = {}
    boundaries['left'] = left_boundary
    boundaries['right'] = right_boundary
    boundaries['upper'] = upper_boundary
    boundaries['lower'] = lower_boundary
    boundaries['coil'] = coil_boundary

    boundaries = FacetFunction('size_t', mesh)
    boundaries.set_all(0)
    left_boundary.mark(boundaries, 1)
    right_boundary.mark(boundaries, 2)
    upper_boundary.mark(boundaries, 3)
    lower_boundary.mark(boundaries, 4)
    coil_boundary.mark(boundaries, 5)

    boundary_indices = {'left': 1,
                        'right': 2,
                        'top': 3,
                        'bottom': 4,
                        'coil': 5}
    theta0 = Constant(293.0)
    return mesh, f, boundaries, boundary_indices, theta0
Exemple #20
0
    if mpirank == 0: print 'Start assembling KV'
    MPI.barrier(mpicomm)
    t0 = time()
    KV = assemble(weak_V)
    MPI.barrier(mpicomm)
    t1 = time()
    if mpirank == 0: print 'Time to assemble KV = {}'.format(t1 - t0)
elif myrun == 2:

    class LeftRight(SubDomain):
        def inside(self, x, on_boundary):
            return (x[0] < 1e-16 or x[0] > 1.0 - 1e-16) \
            and on_boundary

    class_bc_abc = LeftRight()
    abc_boundaryparts = FacetFunction("size_t", mesh)
    class_bc_abc.mark(abc_boundaryparts, 1)
    ds = Measure("ds")[abc_boundaryparts]
    weak_1 = inner(sqrt(lam1 * rho1) * nabla_grad(trial),
                   nabla_grad(test)) * ds(1)
    weak_2 = inner(sqrt(lam2 * rho2) * nabla_grad(trial),
                   nabla_grad(test)) * ds(1)

    lam1.vector()[:] = 1.0
    rho1.vector()[:] = 1.0
    print 'Start assembling K2'
    t0 = time()
    K2 = assemble(weak_2)
    t1 = time()
    print 'Time to assemble K2 = {}'.format(t1 - t0)
Exemple #21
0
def construct_sleeve_geometry(
    t_wall=None,
    t_gap=None,
    t_sleeve=None,
    L_wall=None,
    L_sleeve=None,
    refinement_parameter=16,
):
    #
    # Define the domain as a polygon
    mesh = Mesh()
    domain = Polygon([
        dolfin.Point(0.0, 0.0),
        dolfin.Point(L_wall, 0.0),
        dolfin.Point(L_wall, t_wall),
        dolfin.Point((L_wall - L_sleeve), t_wall),
        dolfin.Point((L_wall - L_sleeve), (t_wall + t_gap)),
        dolfin.Point(L_wall, (t_wall + t_gap)),
        dolfin.Point(L_wall, (t_sleeve + t_wall + t_gap)),
        dolfin.Point((L_wall - L_sleeve), (t_sleeve + t_wall + t_gap)),
        dolfin.Point((L_wall - L_sleeve - t_sleeve - t_gap), t_wall),
        dolfin.Point(0.0, t_wall),
    ], )
    #
    # Define weld region
    weld_subdomain = Polygon([
        dolfin.Point((L_wall - L_sleeve - t_sleeve - t_gap), t_wall),
        dolfin.Point((L_wall - L_sleeve), t_wall),
        dolfin.Point((L_wall - L_sleeve), (t_wall + t_sleeve + t_gap)),
    ])
    domain.set_subdomain(1, weld_subdomain)
    #
    # Mesh
    mesh = generate_mesh(domain, refinement_parameter)
    #
    # Refine in the weld
    cell_markers = CellFunction("bool", mesh)
    cell_markers.set_all(False)
    c = is_in_weld_region(
        t_wall=t_wall,
        t_gap=t_gap,
        t_sleeve=t_sleeve,
        L_wall=L_wall,
        L_sleeve=L_sleeve,
    )

    class MyDomain(SubDomain):
        def inside(self, x, on_boundary):
            return c(x)

    my_domain = MyDomain()
    my_domain.mark(cell_markers, True)
    mesh = refine(mesh, cell_markers)

    #
    # Define the upper and lower boundaries
    class Upper(SubDomain):
        def inside(self, x, on_boundary):
            #
            # Define relevant points
            xb1 = (L_wall - L_sleeve - t_sleeve - t_gap)
            xb2 = (L_wall - L_sleeve)
            yb1 = t_wall
            yb2 = (t_wall + t_sleeve + t_gap)
            #
            # Define params for assessing if on a line between points
            dx_line = xb2 - xb1
            dy_line = yb2 - yb1
            dx = x[0] - xb1
            dy = x[1] - yb1
            zero = dx * dy_line - dx_line * dy
            #
            is_upper_region_one = x[0] <= xb1 and near(x[1], yb1)
            is_upper_region_two = x[0] >= xb1 and x[0] <= xb2 and near(zero, 0)
            is_upper_region_three = x[0] >= xb2 and near(x[1], yb2)
            #
            return is_upper_region_one or is_upper_region_two or is_upper_region_three

    class Lower(SubDomain):
        def inside(self, x, on_boundary):
            return near(x[1], 0)

    #
    # Set boundaries
    upper = Upper()
    lower = Lower()
    boundaries = FacetFunction("size_t", mesh)
    boundaries.set_all(0)
    upper.mark(boundaries, 1)
    lower.mark(boundaries, 2)
    #
    return (mesh, boundaries)
Exemple #22
0
def les_setup(u_, mesh, assemble_matrix, CG1Function, nut_krylov_solver, bcs,
              **NS_namespace):
    """
    Set up for solving the Germano Dynamic LES model applying
    Lagrangian Averaging.
    """

    # Create function spaces
    CG1 = FunctionSpace(mesh, "CG", 1)
    p, q = TrialFunction(CG1), TestFunction(CG1)
    dim = mesh.geometry().dim()

    # Define delta and project delta**2 to CG1
    delta = pow(CellVolume(mesh), 1. / dim)
    delta_CG1_sq = project(delta, CG1)
    delta_CG1_sq.vector().set_local(delta_CG1_sq.vector().array()**2)
    delta_CG1_sq.vector().apply("insert")

    # Define nut_
    Sij = sym(grad(u_))
    magS = sqrt(2 * inner(Sij, Sij))
    Cs = Function(CG1)
    nut_form = Cs**2 * delta**2 * magS
    # Create nut_ BCs
    ff = FacetFunction("size_t", mesh, 0)
    bcs_nut = []
    for i, bc in enumerate(bcs['u0']):
        bc.apply(u_[0].vector())  # Need to initialize bc
        m = bc.markers()  # Get facet indices of boundary
        ff.array()[m] = i + 1
        bcs_nut.append(DirichletBC(CG1, Constant(0), ff, i + 1))
    nut_ = CG1Function(nut_form,
                       mesh,
                       method=nut_krylov_solver,
                       bcs=bcs_nut,
                       bounded=True,
                       name="nut")

    # Create functions for holding the different velocities
    u_CG1 = as_vector([Function(CG1) for i in range(dim)])
    u_filtered = as_vector([Function(CG1) for i in range(dim)])
    dummy = Function(CG1)
    ll = LagrangeInterpolator()

    # Assemble required filter matrices and functions
    G_under = Function(CG1, assemble(TestFunction(CG1) * dx))
    G_under.vector().set_local(1. / G_under.vector().array())
    G_under.vector().apply("insert")
    G_matr = assemble(inner(p, q) * dx)

    # Set up functions for Lij and Mij
    Lij = [Function(CG1) for i in range(dim * dim)]
    Mij = [Function(CG1) for i in range(dim * dim)]
    # Check if case is 2D or 3D and set up uiuj product pairs and
    # Sij forms, assemble required matrices
    Sijcomps = [Function(CG1) for i in range(dim * dim)]
    Sijfcomps = [Function(CG1) for i in range(dim * dim)]
    # Assemble some required matrices for solving for rate of strain terms
    Sijmats = [assemble_matrix(p.dx(i) * q * dx) for i in range(dim)]
    if dim == 3:
        tensdim = 6
        uiuj_pairs = ((0, 0), (0, 1), (0, 2), (1, 1), (1, 2), (2, 2))
    else:
        tensdim = 3
        uiuj_pairs = ((0, 0), (0, 1), (1, 1))

    # Set up Lagrange functions
    JLM = Function(CG1)
    JLM.vector()[:] += 1E-32
    JMM = Function(CG1)
    JMM.vector()[:] += 1

    return dict(Sij=Sij,
                nut_form=nut_form,
                nut_=nut_,
                delta=delta,
                bcs_nut=bcs_nut,
                delta_CG1_sq=delta_CG1_sq,
                CG1=CG1,
                Cs=Cs,
                u_CG1=u_CG1,
                u_filtered=u_filtered,
                ll=ll,
                Lij=Lij,
                Mij=Mij,
                Sijcomps=Sijcomps,
                Sijfcomps=Sijfcomps,
                Sijmats=Sijmats,
                JLM=JLM,
                JMM=JMM,
                dim=dim,
                tensdim=tensdim,
                G_matr=G_matr,
                G_under=G_under,
                dummy=dummy,
                uiuj_pairs=uiuj_pairs)
Exemple #23
0
    def __init__(self):
        import os
        from dolfin import Mesh, MeshFunction, SubMesh, SubDomain, \
            FacetFunction, DirichletBC, dot, grad, FunctionSpace, \
            MixedFunctionSpace, Expression, FacetNormal, pi, Function, \
            Constant, TestFunction, MPI, mpi_comm_world, File
        import numpy
        import warnings

        from maelstrom import heat_cylindrical as cyl_heat
        from maelstrom import materials_database as md

        GMSH_EPS = 1.0e-15

        current_path = os.path.dirname(os.path.realpath(__file__))
        base = os.path.join(
            current_path,
            '../../meshes/2d/crucible-with-coils'
            )
        self.mesh = Mesh(base + '.xml')
        self.subdomains = MeshFunction('size_t',
                                       self.mesh,
                                       base + '_physical_region.xml'
                                       )

        self.subdomain_materials = {
            1: md.get_material('porcelain'),
            2: md.get_material('argon'),
            3: md.get_material('GaAs (solid)'),
            4: md.get_material('GaAs (liquid)'),
            27: md.get_material('air')
            }

        # coils
        for k in range(5, 27):
            self.subdomain_materials[k] = md.get_material('graphite EK90')

        # Define the subdomains which together form a single coil.
        self.coil_domains = [
            [5, 6, 7, 8, 9],
            [10, 11, 12, 13, 14],
            [15, 16, 17, 18, 19],
            [20, 21, 22, 23],
            [24, 25, 26]
            ]

        self.wpi = 4
        # http://fenicsproject.org/qa/2026/submesh-workaround-for-parallel-computation
        submesh_parallel_bug_fixed = False
        if submesh_parallel_bug_fixed:
            submesh_workpiece = SubMesh(self.mesh, self.subdomains, self.wpi)
        else:
            # To get the mesh in parallel, we need to read it in from a file.
            # Writing out can only happen in serial mode, though. :/
            base = os.path.join(current_path,
                                '../../meshes/2d/crucible-with-coils-submesh'
                                )
            filename = base + '.xml'
            if not os.path.isfile(filename):
                warnings.warn(
                    'Submesh file \'%s\' does not exist. Creating... '
                    % filename
                    )
                if MPI.size(mpi_comm_world()) > 1:
                    raise RuntimeError(
                        'Can only write submesh in serial mode.'
                        )
                submesh_workpiece = \
                    SubMesh(self.mesh, self.subdomains, self.wpi)
                output_stream = File(filename)
                output_stream << submesh_workpiece
            # Read the mesh
            submesh_workpiece = Mesh(base + '.xml')

        coords = submesh_workpiece.coordinates()
        ymin = min(coords[:, 1])
        ymax = max(coords[:, 1])

        # Find the top right point.
        k = numpy.argmax(numpy.sum(coords, 1))
        topright = coords[k, :]

        # Initialize mesh function for boundary domains
        class Left(SubDomain):
            def inside(self, x, on_boundary):
                # Explicitly exclude the lowest and the highest point of the
                # symmetry axis.
                # It is necessary for the consistency of the pressure-Poisson
                # system in the Navier-Stokes solver that the velocity is
                # exactly 0 at the boundary r>0. Hence, at the corner points
                # (r=0, melt-crucible, melt-crystal) we must enforce u=0
                # already and cannot have a component in z-direction.
                return on_boundary \
                    and x[0] < GMSH_EPS \
                    and x[1] < ymax - GMSH_EPS \
                    and x[1] > ymin + GMSH_EPS

        class Crucible(SubDomain):
            def inside(self, x, on_boundary):
                return on_boundary \
                    and ((x[0] > GMSH_EPS and x[1] < ymax - GMSH_EPS)
                         or (x[0] > topright[0] - GMSH_EPS
                             and x[1] > topright[1] - GMSH_EPS)
                         or (x[0] < GMSH_EPS and x[1] < ymin + GMSH_EPS)
                         )

        # At the top right part (boundary melt--gas), slip is allowed, so only
        # n.u=0 is enforced. Very weirdly, the PPE is consistent if and only if
        # the end points of UpperRight are in UpperRight. This contrasts
        # Left(), where the end points must NOT belong to Left().  Judging from
        # the experiments, these settings do the right thing.
        # TODO try to better understand the PPE system/dolfin's boundary
        # settings
        class Upper(SubDomain):
            def inside(self, x, on_boundary):
                return on_boundary \
                    and x[1] > ymax - GMSH_EPS

        class UpperRight(SubDomain):
            def inside(self, x, on_boundary):
                return on_boundary \
                    and x[1] > ymax - GMSH_EPS \
                    and x[0] > 0.038 - GMSH_EPS

        # The crystal boundary is taken to reach up to 0.038 where the
        # Dirichlet boundary data is about the melting point of the crystal,
        # 1511K. This setting gives pretty acceptable results when there is no
        # convection except the one induced by buoyancy. Is there is any more
        # stirring going on, though, the end point of the crystal with its
        # fixed temperature of 1511K might be the hottest point globally. This
        # looks rather unphysical.
        # TODO check out alternatives
        class UpperLeft(SubDomain):
            def inside(self, x, on_boundary):
                return on_boundary \
                    and x[1] > ymax - GMSH_EPS \
                    and x[0] < 0.038 + GMSH_EPS

        left = Left()
        crucible = Crucible()
        upper_left = UpperLeft()
        upper_right = UpperRight()

        self.wp_boundaries = FacetFunction('size_t', submesh_workpiece)
        self.wp_boundaries.set_all(0)
        left.mark(self.wp_boundaries, 1)
        crucible.mark(self.wp_boundaries, 2)
        upper_right.mark(self.wp_boundaries, 3)
        upper_left.mark(self.wp_boundaries, 4)

        if DEBUG:
            from dolfin import plot, interactive
            plot(self.wp_boundaries, title='Boundaries')
            interactive()

        submesh_boundary_indices = {
            'left': 1,
            'crucible': 2,
            'upper right': 3,
            'upper left': 4
            }

        # Boundary conditions for the velocity.
        #
        # [1] Incompressible flow and the finite element method; volume two;
        #     Isothermal Laminar Flow;
        #     P.M. Gresho, R.L. Sani;
        #
        # For the choice of function space, [1] says:
        #     "In 2D, the triangular elements P_2^+P_1 and P_2^+P_{-1} are very
        #      good [...]. [...] If you wish to avoid bubble functions on
        #      triangular elements, P_2P_1 is not bad, and P_2(P_1+P_0) is even
        #      better [...]."
        #
        # It turns out that adding the bubble space significantly hampers the
        # convergence of the Stokes solver and also considerably increases the
        # time it takes to construct the Jacobian matrix of the Navier--Stokes
        # problem if no optimization is applied.
        V = FunctionSpace(submesh_workpiece, 'CG', 2)
        with_bubbles = False
        if with_bubbles:
            V += FunctionSpace(submesh_workpiece, 'B', 3)
        self.W = MixedFunctionSpace([V, V, V])

        self.u_bcs = [
            DirichletBC(self.W,
                        Expression(
                            ('0.0', '0.0', '-2*pi*x[0] * 5.0/60.0'),
                            degree=1
                            ),
                        #(0.0, 0.0, 0.0),
                        crucible),
            DirichletBC(self.W.sub(0), 0.0, left),
            DirichletBC(self.W.sub(2), 0.0, left),
            # Make sure that u[2] is 0 at r=0.
            DirichletBC(self.W,
                        Expression(
                            ('0.0', '0.0', '2*pi*x[0] * 5.0/60.0'),
                            degree=1
                            ),
                        upper_left),
            DirichletBC(self.W.sub(1), 0.0, upper_right),
            ]
        self.p_bcs = []

        self.P = FunctionSpace(submesh_workpiece, 'CG', 1)

        # Boundary conditions for heat equation.
        self.Q = FunctionSpace(submesh_workpiece, 'CG', 2)
        # Dirichlet.
        # This is a bit of a tough call since the boundary conditions need to
        # be read from a Tecplot file here.
        import tecplot_reader
        filename = os.path.join(
            os.path.dirname(os.path.realpath(__file__)),
            'data/crucible-boundary.dat'
            )
        data = tecplot_reader.read(filename)
        RZ = numpy.c_[data['ZONE T']['node data']['r'],
                      data['ZONE T']['node data']['z']
                      ]
        T_vals = data['ZONE T']['node data']['temp. [K]']

        class TecplotDirichletBC(Expression):
            # TODO specify degree
            def eval(self, value, x):
                # Find on which edge x sits, and raise exception if it doesn't.
                edge_found = False
                for edge in data['ZONE T']['element data']:
                    # Given a point X and an edge X0--X1,
                    #
                    #     (1 - theta) X0 + theta X1,
                    #
                    # the minimum distance is assumed for
                    #
                    #    argmin_theta ||(1-theta) X0  + theta X1 - X||^2
                    #    = <X1 - X0, X - X0> / ||X1 - X0||^2.
                    #
                    # If the distance is 0 and 0<=theta<=1, we found the edge.
                    #
                    # Note that edges are 1-based in Tecplot.
                    X0 = RZ[edge[0] - 1]
                    X1 = RZ[edge[1] - 1]
                    theta = numpy.dot(X1-X0, x-X0) / numpy.dot(X1-X0, X1-X0)
                    diff = (1.0-theta)*X0 + theta*X1 - x
                    if numpy.dot(diff, diff) < 1.0e-10 and \
                            0.0 <= theta and theta <= 1.0:
                        # Linear interpolation of the temperature value.
                        value[0] = (1.0-theta) * T_vals[edge[0]-1] \
                                 + theta       * T_vals[edge[1]-1]
                        edge_found = True
                        break
                # This class is supposed to be used for Dirichlet boundary
                # conditions. For some reason, FEniCS also evaluates
                # DirichletBC objects at coordinates which do not sit on the
                # boundary, see
                # <http://fenicsproject.org/qa/1033/dirichletbc-expressions-evaluated-away-from-the-boundary>.
                # The assigned values have no meaning though, so not assigning
                # values[0] here is okay.
                #
                #from matplotlib import pyplot as pp
                #pp.plot(x[0], x[1], 'xg')
                if not edge_found:
                    value[0] = 0.0
                    warnings.warn('Coordinate (%e, %e) doesn\'t sit on edge.'
                                  % (x[0], x[1]))
                    #pp.plot(RZ[:, 0], RZ[:, 1], '.k')
                    #pp.plot(x[0], x[1], 'xr')
                    #pp.show()
                    #raise RuntimeError('Input coordinate '
                    #                   '%r is not on boundary.' % x)
                return

        tecplot_dbc = TecplotDirichletBC()
        self.theta_bcs_d = [
            DirichletBC(self.Q, tecplot_dbc, upper_left)
            ]
        theta_bcs_d_strict = [
            DirichletBC(self.Q, tecplot_dbc, upper_right),
            DirichletBC(self.Q, tecplot_dbc, crucible),
            DirichletBC(self.Q, tecplot_dbc, upper_left)
            ]

        # Neumann
        dTdr_vals = data['ZONE T']['node data']['dTempdx [K/m]']
        dTdz_vals = data['ZONE T']['node data']['dTempdz [K/m]']

        class TecplotNeumannBC(Expression):
            # TODO specify degree
            def eval(self, value, x):
                # Same problem as above: This expression is not only evaluated
                # at boundaries.
                for edge in data['ZONE T']['element data']:
                    X0 = RZ[edge[0] - 1]
                    X1 = RZ[edge[1] - 1]
                    theta = numpy.dot(X1-X0, x-X0) / numpy.dot(X1-X0, X1-X0)
                    dist = numpy.linalg.norm((1-theta)*X0 + theta*X1 - x)
                    if dist < 1.0e-5 and 0.0 <= theta and theta <= 1.0:
                        value[0] = (1-theta) * dTdr_vals[edge[0]-1] \
                            + theta * dTdr_vals[edge[1]-1]
                        value[1] = (1-theta) * dTdz_vals[edge[0]-1] \
                            + theta * dTdz_vals[edge[1]-1]
                        break
                return

            def value_shape(self):
                return (2,)

        tecplot_nbc = TecplotNeumannBC()
        n = FacetNormal(self.Q.mesh())
        self.theta_bcs_n = {
            submesh_boundary_indices['upper right']: dot(n, tecplot_nbc),
            submesh_boundary_indices['crucible']: dot(n, tecplot_nbc)
            }
        self.theta_bcs_r = {}

        # It seems that the boundary conditions from above are inconsistent in
        # that solving with Dirichlet overall and mixed Dirichlet-Neumann give
        # different results; the value *cannot* correspond to one solution.
        # From looking at the solutions, the pure Dirichlet setting appears
        # correct, so extract the Neumann values directly from that solution.
        zeta = TestFunction(self.Q)

        theta_reference = Function(self.Q, name='temperature (Dirichlet)')
        theta_reference.vector()[:] = 0.0

        # Solve the *quasilinear* PDE (coefficients may depend on theta).
        # This is to avoid setting a fixed temperature for the coefficients.

        # Get material parameters
        wp_material = self.subdomain_materials[self.wpi]
        if isinstance(wp_material.specific_heat_capacity, float):
            cp = wp_material.specific_heat_capacity
        else:
            cp = wp_material.specific_heat_capacity(theta_reference)
        if isinstance(wp_material.density, float):
            rho = wp_material.density
        else:
            rho = wp_material.density(theta_reference)
        if isinstance(wp_material.thermal_conductivity, float):
            k = wp_material.thermal_conductivity
        else:
            k = wp_material.thermal_conductivity(theta_reference)

        reference_problem = cyl_heat.HeatCylindrical(
            self.Q, theta_reference,
            zeta,
            b=Constant((0.0, 0.0, 0.0)),
            kappa=k,
            rho=rho,
            cp=cp,
            source=Constant(0.0),
            dirichlet_bcs=theta_bcs_d_strict
            )

        from dolfin import solve
        solve(reference_problem.F0 == 0,
              theta_reference,
              bcs=theta_bcs_d_strict
              )

        # Create equivalent boundary conditions from theta_reference. This
        # makes sure that the potentially expensive Expression evaluation in
        # theta_bcs_* is replaced by something reasonably cheap.
        for k, bc in enumerate(self.theta_bcs_d):
            self.theta_bcs_d[k] = DirichletBC(bc.function_space(),
                                              theta_reference,
                                              bc.domain_args[0]
                                              )
        # Adapt Neumann conditions.
        n = FacetNormal(self.Q.mesh())
        for k in self.theta_bcs_n:
            self.theta_bcs_n[k] = dot(n, grad(theta_reference))

        if DEBUG:
            # Solve the heat equation with the mixed Dirichlet-Neumann
            # boundary conditions and compare it to the Dirichlet-only
            # solution.
            theta_new = Function(
                self.Q,
                name='temperature (Neumann + Dirichlet)'
                )
            from dolfin import Measure
            ds_workpiece = Measure('ds')[self.wp_boundaries]
            problem_new = cyl_heat.HeatCylindrical(
                self.Q, theta_new,
                zeta,
                b=Constant((0.0, 0.0, 0.0)),
                kappa=k,
                rho=rho,
                cp=cp,
                source=Constant(0.0),
                dirichlet_bcs=self.theta_bcs_d,
                neumann_bcs=self.theta_bcs_n,
                ds=ds_workpiece
                )

            from dolfin import solve
            solve(problem_new.F0 == 0,
                  theta_new,
                  bcs=problem_new.dirichlet_bcs
                  )
            from dolfin import plot, interactive, errornorm
            print('||theta_new - theta_ref|| = %e'
                  % errornorm(theta_new, theta_reference)
                  )
            plot(theta_reference)
            plot(theta_new)
            plot(
                theta_reference - theta_new,
                title='theta_ref - theta_new'
                )
            interactive()

        #omega = 2 * pi * 10.0e3
        self.omega = 2 * pi * 300.0

        return