Ejemplo n.º 1
0
    def stokes(self):
        P2 = VectorElement("CG", self.mesh.ufl_cell(), 2)
        P1 = FiniteElement("CG", self.mesh.ufl_cell(), 1)
        TH = P2 * P1
        VQ = FunctionSpace(self.mesh, TH)
        mf = self.mf
        self.no_slip = Constant((0., 0))
        self.topflow = Expression(("-x[0] * (x[0] - 1.0) * 6.0 * m", "0.0"),
                                  m=self.U_m,
                                  degree=2)
        bc0 = DirichletBC(VQ.sub(0), self.topflow, mf, self.bc_dict["top"])
        bc1 = DirichletBC(VQ.sub(0), self.no_slip, mf, self.bc_dict["left"])
        bc2 = DirichletBC(VQ.sub(0), self.no_slip, mf, self.bc_dict["bottom"])
        bc3 = DirichletBC(VQ.sub(0), self.no_slip, mf, self.bc_dict["right"])
        # bc4 = DirichletBC(VQ.sub(1), Constant(0), mf, self.bc_dict["top"])
        bcs = [bc0, bc1, bc2, bc3]

        vup = TestFunction(VQ)
        up = TrialFunction(VQ)
        # the solution will be in here:
        up_ = Function(VQ)

        u, p = split(up)  # Trial
        vu, vp = split(vup)  # Test
        u_, p_ = split(up_)  # Function holding the solution
        F = self.mu*inner(grad(vu), grad(u))*dx - inner(div(vu), p)*dx \
            - inner(vp, div(u))*dx + dot(self.g*self.rho, vu)*dx
        solve(lhs(F) == rhs(F), up_, bcs=bcs)
        self.u_.assign(project(u_, self.V))
        self.p_.assign(project(p_, self.Q))
        return
Ejemplo n.º 2
0
def test_clear_sub_map_data_vector(mesh):
    mesh = UnitSquareMesh(8, 8)
    P1 = FiniteElement("Lagrange", mesh.ufl_cell(), 1)
    W = FunctionSpace(mesh, P1 * P1)

    # Check block size
    assert W.dofmap().index_map.block_size == 2

    W.dofmap().clear_sub_map_data()
    with pytest.raises(RuntimeError):
        W0 = W.sub(0)
        assert (W0)
    with pytest.raises(RuntimeError):
        W1 = W.sub(1)
        assert (W1)
Ejemplo n.º 3
0
def test_tabulate_dofs(mesh_factory):
    func, args = mesh_factory
    mesh = func(*args)
    W0 = FiniteElement("Lagrange", mesh.ufl_cell(), 1)
    W1 = VectorElement("Lagrange", mesh.ufl_cell(), 1)
    W = FunctionSpace(mesh, W0 * W1)

    L0 = W.sub(0)
    L1 = W.sub(1)
    L01 = L1.sub(0)
    L11 = L1.sub(1)

    for i, cell in enumerate(Cells(mesh)):
        dofs0 = L0.dofmap().cell_dofs(cell.index())
        dofs1 = L01.dofmap().cell_dofs(cell.index())
        dofs2 = L11.dofmap().cell_dofs(cell.index())
        dofs3 = L1.dofmap().cell_dofs(cell.index())

        assert np.array_equal(dofs0, L0.dofmap().cell_dofs(i))
        assert np.array_equal(dofs1, L01.dofmap().cell_dofs(i))
        assert np.array_equal(dofs2, L11.dofmap().cell_dofs(i))
        assert np.array_equal(dofs3, L1.dofmap().cell_dofs(i))

        assert len(np.intersect1d(dofs0, dofs1)) == 0
        assert len(np.intersect1d(dofs0, dofs2)) == 0
        assert len(np.intersect1d(dofs1, dofs2)) == 0
        assert np.array_equal(np.append(dofs1, dofs2), dofs3)
Ejemplo n.º 4
0
def compute_error(problem, mesh_size):
    mesh = problem.mesh_generator(mesh_size)

    u = problem.solution['u']
    u_sol = Expression((ccode(u['value'][0]), ccode(u['value'][1])),
                       degree=u['degree'])

    p = problem.solution['p']
    p_sol = Expression(ccode(p['value']), degree=p['degree'])

    f = Expression(
        (ccode(problem.f['value'][0]), ccode(problem.f['value'][1])),
        degree=problem.f['degree'])

    W = VectorElement('Lagrange', mesh.ufl_cell(), 2)
    P = FiniteElement('Lagrange', mesh.ufl_cell(), 1)
    WP = FunctionSpace(mesh, W * P)

    # Get Dirichlet boundary conditions
    u_bcs = DirichletBC(WP.sub(0), u_sol, 'on_boundary')
    p_bcs = DirichletBC(WP.sub(1), p_sol, 'on_boundary')

    u_approx, p_approx = flow.stokes.solve(WP,
                                           bcs=[u_bcs, p_bcs],
                                           mu=problem.mu,
                                           f=f,
                                           verbose=True,
                                           tol=1.0e-12)

    # compute errors
    u_error = errornorm(u_sol, u_approx)
    p_error = errornorm(p_sol, p_approx)
    return mesh.hmax(), u_error, p_error
Ejemplo n.º 5
0
def generate_collapsed_bilinear_form_space(mesh):
    element_0 = VectorElement("Lagrange", mesh.ufl_cell(), 2)
    element_1 = FiniteElement("Lagrange", mesh.ufl_cell(), 1)
    element = MixedElement(element_0, element_1)
    U = FunctionSpace(mesh, element)
    V = U.sub(0).collapse()
    return (V, U)
Ejemplo n.º 6
0
def CollapsedFunctionSpaces(mesh):
    element_0 = VectorElement("Lagrange", mesh.ufl_cell(), 2, dim=2)
    element_1 = FiniteElement("Lagrange", mesh.ufl_cell(), 1)
    element = MixedElement(element_0, element_1)
    U = FunctionSpace(mesh, element)
    V = U.sub(0).collapse()
    return (V, U)
Ejemplo n.º 7
0
def _test_eigen_solver_sparse(callback_type):
    from rbnics.backends.dolfin import EigenSolver

    # Define mesh
    mesh = UnitSquareMesh(10, 10)

    # Define function space
    V_element = VectorElement("Lagrange", mesh.ufl_cell(), 2)
    Q_element = FiniteElement("Lagrange", mesh.ufl_cell(), 1)
    W_element = MixedElement(V_element, Q_element)
    W = FunctionSpace(mesh, W_element)

    # Create boundaries
    class Wall(SubDomain):
        def inside(self, x, on_boundary):
            return on_boundary and (x[1] < 0 + DOLFIN_EPS
                                    or x[1] > 1 - DOLFIN_EPS)

    boundaries = MeshFunction("size_t", mesh, mesh.topology().dim() - 1)
    boundaries.set_all(0)
    wall = Wall()
    wall.mark(boundaries, 1)

    # Define variational problem
    vq = TestFunction(W)
    (v, q) = split(vq)
    up = TrialFunction(W)
    (u, p) = split(up)
    lhs = inner(grad(u), grad(v)) * dx - div(v) * p * dx - div(u) * q * dx
    rhs = -inner(p, q) * dx

    # Define boundary condition
    bc = [DirichletBC(W.sub(0), Constant((0., 0.)), boundaries, 1)]

    # Define eigensolver depending on callback type
    assert callback_type in ("form callbacks", "tensor callbacks")
    if callback_type == "form callbacks":
        solver = EigenSolver(W, lhs, rhs, bc)
    elif callback_type == "tensor callbacks":
        LHS = assemble(lhs)
        RHS = assemble(rhs)
        solver = EigenSolver(W, LHS, RHS, bc)

    # Solve the eigenproblem
    solver.set_parameters({
        "linear_solver": "mumps",
        "problem_type": "gen_non_hermitian",
        "spectrum": "target real",
        "spectral_transform": "shift-and-invert",
        "spectral_shift": 1.e-5
    })
    solver.solve(1)
    r, c = solver.get_eigenvalue(0)
    assert abs(c) < 1.e-10
    assert r > 0., "r = " + str(r) + " is not positive"
    print("Sparse inf-sup constant: ", sqrt(r))
    return (sqrt(r), solver.condensed_A, solver.condensed_B)
Ejemplo n.º 8
0
def get_function_subspace(function_space: FunctionSpace, component: list_of(str)):
    assert len(set([function_space.component_to_index(c) for c in component])) == 1
    output = function_space.sub(component[0]).collapse()
    output._component_to_index.clear()
    for c in component:
        output._component_to_index[c] = None
    output._index_to_components.clear()
    output._index_to_components[None] = component
    return output
Ejemplo n.º 9
0
def test_tabulate_dofs_periodic(mesh_factory):
    class PeriodicBoundary2(SubDomain):
        def inside(self, x, on_boundary):
            return x[0] < np.finfo(float).eps

        def map(self, x, y):
            y[0] = x[0] - 1.0
            y[1] = x[1]

    func, args = mesh_factory
    mesh = func(*args)

    # Create periodic boundary
    periodic_boundary = PeriodicBoundary2()

    V = FiniteElement("Lagrange", mesh.ufl_cell(), 2)
    Q = VectorElement("Lagrange", mesh.ufl_cell(), 2)
    W = V * Q

    V = FunctionSpace(mesh, V, constrained_domain=periodic_boundary)
    Q = FunctionSpace(mesh, Q, constrained_domain=periodic_boundary)
    W = FunctionSpace(mesh, W, constrained_domain=periodic_boundary)

    L0 = W.sub(0)
    L1 = W.sub(1)
    L01 = L1.sub(0)
    L11 = L1.sub(1)

    # Check dimensions
    assert V.dim == 110
    assert Q.dim == 220
    assert L0.dim == V.dim
    assert L1.dim == Q.dim
    assert L01.dim == V.dim
    assert L11.dim == V.dim

    for i, cell in enumerate(Cells(mesh)):
        dofs0 = L0.dofmap().cell_dofs(cell.index())
        dofs1 = L01.dofmap().cell_dofs(cell.index())
        dofs2 = L11.dofmap().cell_dofs(cell.index())
        dofs3 = L1.dofmap().cell_dofs(cell.index())

        assert np.array_equal(dofs0, L0.dofmap().cell_dofs(i))
        assert np.array_equal(dofs1, L01.dofmap().cell_dofs(i))
        assert np.array_equal(dofs2, L11.dofmap().cell_dofs(i))
        assert np.array_equal(dofs3, L1.dofmap().cell_dofs(i))

        assert len(np.intersect1d(dofs0, dofs1)) == 0
        assert len(np.intersect1d(dofs0, dofs2)) == 0
        assert len(np.intersect1d(dofs1, dofs2)) == 0
        assert np.array_equal(np.append(dofs1, dofs2), dofs3)
Ejemplo n.º 10
0
def test_tabulate_coord_periodic(mesh_factory):
    class PeriodicBoundary2(SubDomain):
        def inside(self, x, on_boundary):
            return x[0] < np.finfo(float).eps

        def map(self, x, y):
            y[0] = x[0] - 1.0
            y[1] = x[1]

    # Create periodic boundary condition
    periodic_boundary = PeriodicBoundary2()

    func, args = mesh_factory
    mesh = func(*args)

    V = FiniteElement("Lagrange", mesh.ufl_cell(), 1)
    Q = VectorElement("Lagrange", mesh.ufl_cell(), 1)
    W = V * Q

    V = FunctionSpace(mesh, V, constrained_domain=periodic_boundary)
    W = FunctionSpace(mesh, W, constrained_domain=periodic_boundary)

    L0 = W.sub(0)
    L1 = W.sub(1)
    L01 = L1.sub(0)
    L11 = L1.sub(1)

    sdim = V.element().space_dimension()
    coord0 = np.zeros((sdim, 2), dtype="d")
    coord1 = np.zeros((sdim, 2), dtype="d")
    coord2 = np.zeros((sdim, 2), dtype="d")
    coord3 = np.zeros((sdim, 2), dtype="d")

    for cell in Cells(mesh):
        coord0 = V.element().tabulate_dof_coordinates(cell)
        coord1 = L0.element().tabulate_dof_coordinates(cell)
        coord2 = L01.element().tabulate_dof_coordinates(cell)
        coord3 = L11.element().tabulate_dof_coordinates(cell)
        coord4 = L1.element().tabulate_dof_coordinates(cell)

        assert (coord0 == coord1).all()
        assert (coord0 == coord2).all()
        assert (coord0 == coord3).all()
        assert (coord4[:sdim] == coord0).all()
        assert (coord4[sdim:] == coord0).all()
Ejemplo n.º 11
0
def test_tabulate_coord_periodic(mesh_factory):
    def periodic_boundary(x):
        return x[0] < np.finfo(float).eps

    func, args = mesh_factory
    mesh = func(*args)

    V = FiniteElement("Lagrange", mesh.ufl_cell(), 1)
    Q = VectorElement("Lagrange", mesh.ufl_cell(), 1)
    W = V * Q

    V = FunctionSpace(mesh, V, constrained_domain=periodic_boundary)
    W = FunctionSpace(mesh, W, constrained_domain=periodic_boundary)

    L0 = W.sub(0)
    L1 = W.sub(1)
    L01 = L1.sub(0)
    L11 = L1.sub(1)

    sdim = V.element.space_dimension()
    coord0 = np.zeros((sdim, 2), dtype="d")
    coord1 = np.zeros((sdim, 2), dtype="d")
    coord2 = np.zeros((sdim, 2), dtype="d")
    coord3 = np.zeros((sdim, 2), dtype="d")

    for i in range(mesh.num_cells()):
        cell = MeshEntity(mesh, mesh.topology.dim, i)
        coord0 = V.element.tabulate_dof_coordinates(cell)
        coord1 = L0.element.tabulate_dof_coordinates(cell)
        coord2 = L01.element.tabulate_dof_coordinates(cell)
        coord3 = L11.element.tabulate_dof_coordinates(cell)
        coord4 = L1.element.tabulate_dof_coordinates(cell)

        assert (coord0 == coord1).all()
        assert (coord0 == coord2).all()
        assert (coord0 == coord3).all()
        assert (coord4[:sdim] == coord0).all()
        assert (coord4[sdim:] == coord0).all()
Ejemplo n.º 12
0
def test_clear_sub_map_data_scalar(mesh):
    V = FunctionSpace(mesh, ("CG", 2))
    with pytest.raises(ValueError):
        V.sub(1)

    V = VectorFunctionSpace(mesh, ("CG", 2))
    V1 = V.sub(1)
    assert (V1)

    # Clean sub-map data
    V.dofmap().clear_sub_map_data()

    # Can still get previously computed map
    V1 = V.sub(1)

    # New sub-map should throw an error
    with pytest.raises(RuntimeError):
        V.sub(0)
Ejemplo n.º 13
0
TH = P2 * P1
W = FunctionSpace(mesh, TH)

# The mixed finite element space is known as Taylor–Hood.
# It is a stable, standard element pair for the Stokes
# equations. Now we can define boundary conditions::


# Extract subdomain facet arrays
mf = sub_domains.values
mf0 = np.where(mf == 0)
mf1 = np.where(mf == 1)

# No-slip boundary condition for velocity
# x1 = 0, x1 = 1 and around the dolphin
noslip = Function(W.sub(0).collapse())
noslip.interpolate(lambda x: np.zeros((x.shape[0], 2)))

bc0 = DirichletBC(W.sub(0), noslip, mf0[0])

# Inflow boundary condition for velocity
# x0 = 1


def inflow_eval(x):
    values = np.zeros((x.shape[0], 2))
    values[:, 0] = - np.sin(x[:, 1] * np.pi)
    return values


inflow = Function(W.sub(0).collapse())
Ejemplo n.º 14
0
# x1 = 0, x1 = 1 and around the dolphin


@function.expression.numba_eval
def noslip_eval(values, x, cell):
    values[:, 0] = 0.0
    values[:, 1] = 0.0


# Extract subdomain facet arrays
mf = sub_domains.array()
mf0 = np.where(mf == 0)
mf1 = np.where(mf == 1)

noslip_expr = Expression(noslip_eval, shape=(2, ))
noslip = interpolate(noslip_expr, W.sub(0).collapse())
bc0 = DirichletBC(W.sub(0), noslip, mf0[0])

# Inflow boundary condition for velocity
# x0 = 1


@function.expression.numba_eval
def inflow_eval(values, x, cell):
    values[:, 0] = -np.sin(x[:, 1] * np.pi)
    values[:, 1] = 0.0


inflow_expr = Expression(inflow_eval, shape=(2, ))
inflow = interpolate(inflow_expr, W.sub(0).collapse())
bc1 = DirichletBC(W.sub(0), inflow, mf1[0])
Ejemplo n.º 15
0
def get_function_subspace(function_space: FunctionSpace,
                          component: (int, str)):
    return function_space.sub(component).collapse()
Ejemplo n.º 16
0
class Ball_in_tube(object):
    def __init__(self):
        # https://fenicsproject.org/qa/12891/initialize-mesh-from-vertices-connectivities-at-once
        points, cells, _, cell_data, _ = meshes.ball_in_tube_cyl.generate()
        # 2018.1
        # self.mesh = Mesh(
        #     dolfin.mpi_comm_world(), dolfin.cpp.mesh.CellType.Type_triangle,
        #     points[:, :2], cells['triangle']
        #     )
        with TemporaryDirectory() as temp_dir:
            tmp_filename = os.path.join(temp_dir, "test.xml")
            meshio.write_points_cells(
                tmp_filename,
                points,
                cells,
                cell_data=cell_data,
                file_format="dolfin-xml",
            )
            self.mesh = Mesh(tmp_filename)

        V0_element = FiniteElement("CG", self.mesh.ufl_cell(), 2)
        V1_element = FiniteElement("B", self.mesh.ufl_cell(), 3)
        self.W = FunctionSpace(self.mesh, V0_element * V1_element)

        self.P = FunctionSpace(self.mesh, "CG", 1)

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

        left_boundary = LeftBoundary()

        class RightBoundary(SubDomain):
            # pylint: disable=no-self-use
            def inside(self, x, on_boundary):
                return on_boundary and x[0] > 1.0 - GMSH_EPS

        right_boundary = RightBoundary()

        class LowerBoundary(SubDomain):
            # pylint: disable=no-self-use
            def inside(self, x, on_boundary):
                return on_boundary and x[1] < GMSH_EPS

        lower_boundary = LowerBoundary()

        # class UpperBoundary(SubDomain):
        #     # pylint: disable=no-self-use
        #     def inside(self, x, on_boundary):
        #         return on_boundary and x[1] > 5.0-GMSH_EPS

        class CoilBoundary(SubDomain):
            # pylint: disable=no-self-use
            def inside(self, x, on_boundary):
                # One has to pay a little bit of attention when defining the
                # coil boundary; it's easy to miss the edges closest to x[0]=0.
                return (on_boundary and x[1] > 1.0 - GMSH_EPS
                        and x[1] < 2.0 + GMSH_EPS and x[0] < 1.0 - GMSH_EPS)

        coil_boundary = CoilBoundary()

        self.u_bcs = [
            DirichletBC(self.W, (0.0, 0.0), right_boundary),
            DirichletBC(self.W.sub(0), 0.0, left_boundary),
            DirichletBC(self.W, (0.0, 0.0), lower_boundary),
            DirichletBC(self.W, (0.0, 0.0), coil_boundary),
        ]
        self.p_bcs = []
        # self.p_bcs = [DirichletBC(Q, 0.0, upper_boundary)]
        return
Ejemplo n.º 17
0
class Ball_in_tube(object):
    def __init__(self):
        # https://fenicsproject.org/qa/12891/initialize-mesh-from-vertices-connectivities-at-once
        points, cells, _, cell_data, _ = meshes.ball_in_tube_cyl.generate()
        # 2018.1
        # self.mesh = Mesh(
        #     dolfin.mpi_comm_world(), dolfin.cpp.mesh.CellType.Type_triangle,
        #     points[:, :2], cells['triangle']
        #     )
        with TemporaryDirectory() as temp_dir:
            tmp_filename = os.path.join(temp_dir, "test.xml")
            meshio.write_points_cells(
                tmp_filename,
                points,
                cells,
                cell_data=cell_data,
                file_format="dolfin-xml",
            )
            self.mesh = Mesh(tmp_filename)

        V0_element = FiniteElement("CG", self.mesh.ufl_cell(), 2)
        V1_element = FiniteElement("B", self.mesh.ufl_cell(), 3)
        self.W = FunctionSpace(self.mesh, V0_element * V1_element)

        self.P = FunctionSpace(self.mesh, "CG", 1)

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

        left_boundary = LeftBoundary()

        class RightBoundary(SubDomain):
            # pylint: disable=no-self-use
            def inside(self, x, on_boundary):
                return on_boundary and x[0] > 1.0 - GMSH_EPS

        right_boundary = RightBoundary()

        class LowerBoundary(SubDomain):
            # pylint: disable=no-self-use
            def inside(self, x, on_boundary):
                return on_boundary and x[1] < GMSH_EPS

        lower_boundary = LowerBoundary()

        # class UpperBoundary(SubDomain):
        #     # pylint: disable=no-self-use
        #     def inside(self, x, on_boundary):
        #         return on_boundary and x[1] > 5.0-GMSH_EPS

        class CoilBoundary(SubDomain):
            # pylint: disable=no-self-use
            def inside(self, x, on_boundary):
                # One has to pay a little bit of attention when defining the
                # coil boundary; it's easy to miss the edges closest to x[0]=0.
                return (
                    on_boundary
                    and x[1] > 1.0 - GMSH_EPS
                    and x[1] < 2.0 + GMSH_EPS
                    and x[0] < 1.0 - GMSH_EPS
                )

        coil_boundary = CoilBoundary()

        self.u_bcs = [
            DirichletBC(self.W, (0.0, 0.0), right_boundary),
            DirichletBC(self.W.sub(0), 0.0, left_boundary),
            DirichletBC(self.W, (0.0, 0.0), lower_boundary),
            DirichletBC(self.W, (0.0, 0.0), coil_boundary),
        ]
        self.p_bcs = []
        # self.p_bcs = [DirichletBC(Q, 0.0, upper_boundary)]
        return
def test_steady_stokes(k):
    # Polynomial order and mesh resolution
    nx_list = [4, 8, 16]

    nu = Constant(1)

    if comm.Get_rank() == 0:
        print('{:=^72}'.format('Computing for polynomial order ' + str(k)))

    # Error listst
    error_u, error_p, error_div = [], [], []

    for nx in nx_list:
        if comm.Get_rank() == 0:
            print('# Resolution ' + str(nx))

        mesh = UnitSquareMesh(nx, nx)

        # Get forcing from exact solutions
        u_exact, p_exact = exact_solution(mesh)
        f = div(p_exact * Identity(2) - 2 * nu * sym(grad(u_exact)))

        # Define FunctionSpaces and functions
        V = VectorElement("DG", mesh.ufl_cell(), k)
        Q = FiniteElement("DG", mesh.ufl_cell(), k - 1)
        Vbar = VectorElement("DGT", mesh.ufl_cell(), k)
        Qbar = FiniteElement("DGT", mesh.ufl_cell(), k)

        mixedL = FunctionSpace(mesh, MixedElement([V, Q]))
        mixedG = FunctionSpace(mesh, MixedElement([Vbar, Qbar]))

        Uh = Function(mixedL)
        Uhbar = Function(mixedG)

        # Set forms
        alpha = Constant(6 * k * k)
        forms_stokes = FormsStokes(mesh, mixedL, mixedG,
                                   alpha).forms_steady(nu, f)

        # No-slip boundary conditions, set pressure in one of the corners
        bc0 = DirichletBC(mixedG.sub(0), Constant((0, 0)), Gamma)
        bc1 = DirichletBC(mixedG.sub(1), Constant(0), Corner, "pointwise")
        bcs = [bc0, bc1]

        # Initialize static condensation class
        ssc = StokesStaticCondensation(mesh, forms_stokes['A_S'],
                                       forms_stokes['G_S'],
                                       forms_stokes['B_S'],
                                       forms_stokes['Q_S'],
                                       forms_stokes['S_S'], bcs)

        # Assemble global system and incorporates bcs
        ssc.assemble_global_system(True)
        # Solve using mumps
        ssc.solve_problem(Uhbar, Uh, "mumps", "default")

        # Compute velocity/pressure/local div error
        uh, ph = Uh.split()
        e_u = np.sqrt(np.abs(assemble(dot(uh - u_exact, uh - u_exact) * dx)))
        e_p = np.sqrt(np.abs(assemble((ph - p_exact) * (ph - p_exact) * dx)))
        e_d = np.sqrt(np.abs(assemble(div(uh) * div(uh) * dx)))

        if comm.rank == 0:
            error_u.append(e_u)
            error_p.append(e_p)
            error_div.append(e_d)
            print('Error in velocity ' + str(error_u[-1]))
            print('Error in pressure ' + str(error_p[-1]))
            print('Local mass error ' + str(error_div[-1]))

    if comm.rank == 0:
        iterator_list = [1. / float(nx) for nx in nx_list]
        conv_u = compute_convergence(iterator_list, error_u)
        conv_p = compute_convergence(iterator_list, error_p)

        assert any(conv > k + 0.75 for conv in conv_u)
        assert any(conv > (k - 1) + 0.75 for conv in conv_p)
a = (nu*inner(grad(u), grad(v)) - div(v)*p + q*div(u))*dx

# Body force - Linear form
f = Constant((0, 0))
Lf = inner(f, v)*dx

# Neumann boundary condition - Linear form
L_neumann = dot(-Constant(P_inlet)*n,v) * ds(mark["inlet"]) + \
            dot(-Constant(P_outlet)*n,v) * ds(mark["outlet"])


L= Lf + L_neumann

# Dirichlet boundary condition
noslip = Constant(zero_vec)
bc_wall = DirichletBC(W.sub(0), noslip, boundaries, mark["wall"])

bcs = [bc_wall]

# Compute solution
w = Function(W)
solve(a == L, w, bcs)

# Split the mixed solution using deepcopy
# (needed for further computation on coefficient vector)
(u, p) = w.split(True)

# # Split the mixed solution using a shallow copy
(u, p) = w.split()

Ejemplo n.º 20
0
class Lid_driven_cavity(object):
    def __init__(self):
        n = 40
        self.mesh = UnitSquareMesh(n, n, "crossed")

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

        class RightBoundary(SubDomain):
            def inside(self, x, on_boundary):
                return on_boundary and x[0] > 1.0 - DOLFIN_EPS

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

        class UpperBoundary(SubDomain):
            def inside(self, x, on_boundary):
                return on_boundary and x[1] > 1.0 - DOLFIN_EPS

        class RestrictedUpperBoundary(SubDomain):
            def inside(self, x, on_boundary):
                return (on_boundary and x[1] > 1.0 - DOLFIN_EPS
                        and DOLFIN_EPS < x[0] and x[0] < 0.5 - DOLFIN_EPS)

        left = LeftBoundary()
        right = RightBoundary()
        lower = LowerBoundary()
        upper = UpperBoundary()
        # restricted_upper = RestrictedUpperBoundary()

        # Be particularly careful with the boundary conditions.
        # The main problem here is that the PPE system is consistent if and
        # only if
        #
        #     \int_\Omega div(u) = \int_\Gamma n.u = 0.
        #
        # This is exactly and even pointwise fulfilled for the continuous
        # problem.  In the discrete case, we can have to make sure that n.u is
        # 0 all along the boundary.
        # In the lid-driven cavity problem, of particular interest are the
        # corner points at the lid. One has to assert that the z-component of u
        # is 0 all across the lid, and the x-component of u is 0 everywhere but
        # the lid.  Since u is L2-"continuous", the lid condition on u_x must
        # not be enforced in the corner points. The u_y component must be
        # enforced all over the lid, including the end points.
        V_element = FiniteElement("CG", self.mesh.ufl_cell(), 2)
        self.W = FunctionSpace(self.mesh, V_element * V_element)

        self.u_bcs = [
            DirichletBC(self.W, (0.0, 0.0), left),
            DirichletBC(self.W, (0.0, 0.0), right),
            # DirichletBC(self.W.sub(0), Expression('x[0]'), restricted_upper),
            DirichletBC(self.W, (0.0, 0.0), lower),
            DirichletBC(self.W.sub(0), Constant("1.0"), upper),
            DirichletBC(self.W.sub(1), 0.0, upper),
            # DirichletBC(self.W.sub(0), Constant('-1.0'), lower),
            # DirichletBC(self.W.sub(1), 0.0, lower),
            # DirichletBC(self.W.sub(1), Constant('1.0'), left),
            # DirichletBC(self.W.sub(0), 0.0, left),
            # DirichletBC(self.W.sub(1), Constant('-1.0'), right),
            # DirichletBC(self.W.sub(0), 0.0, right),
        ]
        self.P = FunctionSpace(self.mesh, "CG", 1)
        self.p_bcs = []
        return
Ejemplo n.º 21
0
def run_with_params(Tb, mu_value, k_s, path):
    run_time_init = clock()

    mesh = BoxMesh(Point(0.0, 0.0, 0.0),
                   Point(mesh_width, mesh_width, mesh_height), nx, ny, nz)

    pbc = PeriodicBoundary()

    WE = VectorElement('CG', mesh.ufl_cell(), 2)
    SE = FiniteElement('CG', mesh.ufl_cell(), 1)
    WSSS = FunctionSpace(mesh,
                         MixedElement(WE, SE, SE, SE),
                         constrained_domain=pbc)
    # W = FunctionSpace(mesh, WE, constrained_domain=pbc)
    # S = FunctionSpace(mesh, SE, constrained_domain=pbc)
    W = WSSS.sub(0).collapse()
    S = WSSS.sub(1).collapse()

    temperature_vals = [27.0 + 273, Tb + 273, 1300.0 + 273, 1305.0 + 273]
    temp_prof = TemperatureProfile(temperature_vals, element=S.ufl_element())

    mu_a = mu_value  # this was taken from the Blankenbach paper, can change

    Ep = b / temp_prof.delta

    mu_bot = exp(-Ep *
                 (temp_prof.bottom * temp_prof.delta - 1573.0) + cc) * mu_a

    # TODO: verify exponentiation
    Ra = rho_0 * alpha * g * temp_prof.delta * h**3 / (kappa_0 * mu_a)
    w0 = rho_0 * alpha * g * temp_prof.delta * h**2 / mu_a
    tau = h / w0
    p0 = mu_a * w0 / h

    log(mu_a, mu_bot, Ra, w0, p0)

    slip_vx = 1.6E-09 / w0  # Non-dimensional
    slip_velocity = Constant((slip_vx, 0.0, 0.0))
    zero_slip = Constant((0.0, 0.0, 0.0))

    time_step = 3.0E11 / tau * 2

    dt = Constant(time_step)
    t_end = 3.0E15 / tau / 5.0  # Non-dimensional times

    u = Function(WSSS)

    # Instead of TrialFunctions, we use split(u) for our non-linear problem
    v, p, T, Tf = split(u)
    v_t, p_t, T_t, Tf_t = TestFunctions(WSSS)

    T0 = interpolate(temp_prof, S)

    mu_exp = Expression(
        'exp(-Ep * (T_val * dTemp - 1573.0) + cc * x[2] / mesh_height)',
        Ep=Ep,
        dTemp=temp_prof.delta,
        cc=cc,
        mesh_height=mesh_height,
        T_val=T0,
        element=S.ufl_element())

    Tf0 = interpolate(temp_prof, S)

    mu = Function(S)
    v0 = Function(W)

    v_theta = (1.0 - theta) * v0 + theta * v

    T_theta = (1.0 - theta) * T0 + theta * T

    Tf_theta = (1.0 - theta) * Tf0 + theta * Tf

    # TODO: Verify forms

    r_v = (inner(sym(grad(v_t)), 2.0 * mu * sym(grad(v))) - div(v_t) * p -
           T * v_t[2]) * dx

    r_p = p_t * div(v) * dx

    heat_transfer = Constant(k_s) * (Tf_theta - T_theta) * dt

    r_T = (
        T_t *
        ((T - T0) + dt * inner(v_theta, grad(T_theta)))  # TODO: Inner vs dot
        +
        (dt / Ra) * inner(grad(T_t), grad(T_theta)) - T_t * heat_transfer) * dx

    v_melt = Function(W)
    z_hat = Constant((0.0, 0.0, 1.0))

    # TODO: inner -> dot, take out Tf_t
    r_Tf = (Tf_t * ((Tf - Tf0) + dt * inner(v_melt, grad(Tf_theta))) +
            Tf_t * heat_transfer) * dx

    r = r_v + r_p + r_T + r_Tf

    bcv0 = DirichletBC(WSSS.sub(0), zero_slip, top)
    bcv1 = DirichletBC(WSSS.sub(0), slip_velocity, bottom)
    bcv2 = DirichletBC(WSSS.sub(0).sub(1), Constant(0.0), back)
    bcv3 = DirichletBC(WSSS.sub(0).sub(1), Constant(0.0), front)

    bcp0 = DirichletBC(WSSS.sub(1), Constant(0.0), bottom)
    bct0 = DirichletBC(WSSS.sub(2), Constant(temp_prof.surface), top)
    bct1 = DirichletBC(WSSS.sub(2), Constant(temp_prof.bottom), bottom)
    bctf1 = DirichletBC(WSSS.sub(3), Constant(temp_prof.bottom), bottom)

    bcs = [bcv0, bcv1, bcv2, bcv3, bcp0, bct0, bct1, bctf1]

    t = 0
    count = 0
    files = DefaultDictByKey(partial(create_xdmf, path))

    while t < t_end:
        mu.interpolate(mu_exp)
        rhosolid = rho_0 * (1.0 - alpha * (T0 * temp_prof.delta - 1573.0))
        deltarho = rhosolid - rho_melt
        # TODO: project (accuracy) vs interpolate
        assign(
            v_melt,
            project(
                v0 - darcy * (grad(p) * p0 / h - deltarho * z_hat * g) / w0,
                W))
        # TODO: Written out one step later?
        # v_melt.assign(v0 - darcy * (grad(p) * p0 / h - deltarho * yvec * g) / w0)
        # TODO: use nP after to avoid projection?

        solve(r == 0, u, bcs)
        nV, nP, nT, nTf = u.split()  # TODO: write with Tf, ... etc

        if count % output_every == 0:
            time_left(count, t_end / time_step,
                      run_time_init)  # TODO: timestep vs dt

            # TODO: Make sure all writes are to the same function for each time step
            files['T_fluid'].write(nTf, t)
            files['p'].write(nP, t)
            files['v_solid'].write(nV, t)
            files['T_solid'].write(nT, t)
            files['mu'].write(mu, t)
            files['v_melt'].write(v_melt, t)
            files['gradp'].write(project(grad(nP), W), t)
            files['rho'].write(project(rhosolid, S), t)
            files['Tf_grad'].write(project(grad(Tf), W), t)
            files['advect'].write(project(dt * dot(v_melt, grad(nTf))), t)
            files['ht'].write(project(heat_transfer, S), t)

        assign(T0, nT)
        assign(v0, nV)
        assign(Tf0, nTf)

        t += time_step
        count += 1

    log('Case mu={}, Tb={}, k={} complete. Run time = {:.2f} minutes'.format(
        mu_a, Tb, k_s, (clock() - run_time_init) / 60.0))
Ejemplo n.º 22
0
    "0.1*t*exp(-((x[0]-0.7)*(x[0]-0.7) + (x[1]-0.5)*(x[1]-0.5))/0.01)",
    t=0,
    degree=1)

# Define the right hand side for each of the PDEs
F1 = (-inner(grad(U1), grad(q1)) + U2 * q1 + domainSource * q1) * dx
F2 = (-inner(grad(U2), grad(q2)) - U1 * q2) * dx


# Define Dirichlet boundary, zero on all edges.
def boundary(x):
    return x[0] < DOLFIN_EPS or x[0] > 1.0 - DOLFIN_EPS or x[
        1] < DOLFIN_EPS or x[1] > 1.0 - DOLFIN_EPS


bc_u = DirichletBC(ME.sub(0), 0.0, boundary)
bc_v = DirichletBC(ME.sub(1), 0.0, boundary)

# Define the time domain
T = [0, 10]

# Create the solver object and adjust tolerance
obj = backwardEuler(T, W, [F1, F2], tdf=[domainSource], bcs=[bc_u, bc_v])

# Turn on some output and save run time statistics
obj.parameters["verbose"] = True
obj.parameters["drawplot"] = False
obj.parameters["output"]["path"] = "CoupledHeatEquation_folder"
obj.parameters["output"]["statistics"] = True
obj.parameters["timestepping"]["dt"] = T[1] / 40.0
Ejemplo n.º 23
0
def run_with_params(Tb, mu_value, k_s, path):
    run_time_init = clock()

    mesh = BoxMesh(Point(0.0, 0.0, 0.0), Point(mesh_width, mesh_width, mesh_height), nx, ny, nz)

    pbc = PeriodicBoundary()

    WE = VectorElement('CG', mesh.ufl_cell(), 2)
    SE = FiniteElement('CG', mesh.ufl_cell(), 1)
    WSSS = FunctionSpace(mesh, MixedElement(WE, SE, SE, SE), constrained_domain=pbc)
    # W = FunctionSpace(mesh, WE, constrained_domain=pbc)
    # S = FunctionSpace(mesh, SE, constrained_domain=pbc)
    W = WSSS.sub(0).collapse()
    S = WSSS.sub(1).collapse()

    temperature_vals = [27.0 + 273, Tb + 273, 1300.0 + 273, 1305.0 + 273]
    temp_prof = TemperatureProfile(temperature_vals, element=S.ufl_element())

    mu_a = mu_value  # this was taken from the Blankenbach paper, can change

    Ep = b / temp_prof.delta

    mu_bot = exp(-Ep * (temp_prof.bottom * temp_prof.delta - 1573.0) + cc) * mu_a

    # TODO: verify exponentiation
    Ra = rho_0 * alpha * g * temp_prof.delta * h ** 3 / (kappa_0 * mu_a)
    w0 = rho_0 * alpha * g * temp_prof.delta * h ** 2 / mu_a
    tau = h / w0
    p0 = mu_a * w0 / h

    log(mu_a, mu_bot, Ra, w0, p0)

    slip_vx = 1.6E-09 / w0  # Non-dimensional
    slip_velocity = Constant((slip_vx, 0.0, 0.0))
    zero_slip = Constant((0.0, 0.0, 0.0))

    time_step = 3.0E11 / tau * 2

    dt = Constant(time_step)
    t_end = 3.0E15 / tau / 5.0  # Non-dimensional times

    u = Function(WSSS)

    # Instead of TrialFunctions, we use split(u) for our non-linear problem
    v, p, T, Tf = split(u)
    v_t, p_t, T_t, Tf_t = TestFunctions(WSSS)

    T0 = interpolate(temp_prof, S)

    mu_exp = Expression('exp(-Ep * (T_val * dTemp - 1573.0) + cc * x[2] / mesh_height)',
                       Ep=Ep, dTemp=temp_prof.delta, cc=cc, mesh_height=mesh_height, T_val=T0,
                       element=S.ufl_element())

    Tf0 = interpolate(temp_prof, S)

    mu = Function(S)
    v0 = Function(W)

    v_theta = (1.0 - theta) * v0 + theta * v

    T_theta = (1.0 - theta) * T0 + theta * T

    Tf_theta = (1.0 - theta) * Tf0 + theta * Tf

    # TODO: Verify forms

    r_v = (inner(sym(grad(v_t)), 2.0 * mu * sym(grad(v)))
           - div(v_t) * p
           - T * v_t[2]) * dx

    r_p = p_t * div(v) * dx

    heat_transfer = Constant(k_s) * (Tf_theta - T_theta) * dt

    r_T = (T_t * ((T - T0) + dt * inner(v_theta, grad(T_theta)))  # TODO: Inner vs dot
           + (dt / Ra) * inner(grad(T_t), grad(T_theta))
           - T_t * heat_transfer) * dx

    v_melt = Function(W)
    z_hat = Constant((0.0, 0.0, 1.0))

    # TODO: inner -> dot, take out Tf_t
    r_Tf = (Tf_t * ((Tf - Tf0) + dt * inner(v_melt, grad(Tf_theta)))
            + Tf_t * heat_transfer) * dx

    r = r_v + r_p + r_T + r_Tf

    bcv0 = DirichletBC(WSSS.sub(0), zero_slip, top)
    bcv1 = DirichletBC(WSSS.sub(0), slip_velocity, bottom)
    bcv2 = DirichletBC(WSSS.sub(0).sub(1), Constant(0.0), back)
    bcv3 = DirichletBC(WSSS.sub(0).sub(1), Constant(0.0), front)

    bcp0 = DirichletBC(WSSS.sub(1), Constant(0.0), bottom)
    bct0 = DirichletBC(WSSS.sub(2), Constant(temp_prof.surface), top)
    bct1 = DirichletBC(WSSS.sub(2), Constant(temp_prof.bottom), bottom)
    bctf1 = DirichletBC(WSSS.sub(3), Constant(temp_prof.bottom), bottom)

    bcs = [bcv0, bcv1, bcv2, bcv3, bcp0, bct0, bct1, bctf1]

    t = 0
    count = 0
    files = DefaultDictByKey(partial(create_xdmf, path))

    while t < t_end:
        mu.interpolate(mu_exp)
        rhosolid = rho_0 * (1.0 - alpha * (T0 * temp_prof.delta - 1573.0))
        deltarho = rhosolid - rho_melt
        # TODO: project (accuracy) vs interpolate
        assign(v_melt, project(v0 - darcy * (grad(p) * p0 / h - deltarho * z_hat * g) / w0, W))
        # TODO: Written out one step later?
        # v_melt.assign(v0 - darcy * (grad(p) * p0 / h - deltarho * yvec * g) / w0)
        # TODO: use nP after to avoid projection?

        solve(r == 0, u, bcs)
        nV, nP, nT, nTf = u.split()  # TODO: write with Tf, ... etc

        if count % output_every == 0:
            time_left(count, t_end / time_step, run_time_init)  # TODO: timestep vs dt

            # TODO: Make sure all writes are to the same function for each time step
            files['T_fluid'].write(nTf, t)
            files['p'].write(nP, t)
            files['v_solid'].write(nV, t)
            files['T_solid'].write(nT, t)
            files['mu'].write(mu, t)
            files['v_melt'].write(v_melt, t)
            files['gradp'].write(project(grad(nP), W), t)
            files['rho'].write(project(rhosolid, S), t)
            files['Tf_grad'].write(project(grad(Tf), W), t)
            files['advect'].write(project(dt * dot(v_melt, grad(nTf))), t)
            files['ht'].write(project(heat_transfer, S), t)

        assign(T0, nT)
        assign(v0, nV)
        assign(Tf0, nTf)

        t += time_step
        count += 1

    log('Case mu={}, Tb={}, k={} complete. Run time = {:.2f} minutes'.format(mu_a, Tb, k_s, (clock() - run_time_init) / 60.0))
Ejemplo n.º 24
0
class Lid_driven_cavity(object):
    def __init__(self):
        n = 40
        self.mesh = UnitSquareMesh(n, n, "crossed")

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

        class RightBoundary(SubDomain):
            def inside(self, x, on_boundary):
                return on_boundary and x[0] > 1.0 - DOLFIN_EPS

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

        class UpperBoundary(SubDomain):
            def inside(self, x, on_boundary):
                return on_boundary and x[1] > 1.0 - DOLFIN_EPS

        class RestrictedUpperBoundary(SubDomain):
            def inside(self, x, on_boundary):
                return (
                    on_boundary
                    and x[1] > 1.0 - DOLFIN_EPS
                    and DOLFIN_EPS < x[0]
                    and x[0] < 0.5 - DOLFIN_EPS
                )

        left = LeftBoundary()
        right = RightBoundary()
        lower = LowerBoundary()
        upper = UpperBoundary()
        # restricted_upper = RestrictedUpperBoundary()

        # Be particularly careful with the boundary conditions.
        # The main problem here is that the PPE system is consistent if and
        # only if
        #
        #     \int_\Omega div(u) = \int_\Gamma n.u = 0.
        #
        # This is exactly and even pointwise fulfilled for the continuous
        # problem.  In the discrete case, we can have to make sure that n.u is
        # 0 all along the boundary.
        # In the lid-driven cavity problem, of particular interest are the
        # corner points at the lid. One has to assert that the z-component of u
        # is 0 all across the lid, and the x-component of u is 0 everywhere but
        # the lid.  Since u is L2-"continuous", the lid condition on u_x must
        # not be enforced in the corner points. The u_y component must be
        # enforced all over the lid, including the end points.
        V_element = FiniteElement("CG", self.mesh.ufl_cell(), 2)
        self.W = FunctionSpace(self.mesh, V_element * V_element)

        self.u_bcs = [
            DirichletBC(self.W, (0.0, 0.0), left),
            DirichletBC(self.W, (0.0, 0.0), right),
            # DirichletBC(self.W.sub(0), Expression('x[0]'), restricted_upper),
            DirichletBC(self.W, (0.0, 0.0), lower),
            DirichletBC(self.W.sub(0), Constant("1.0"), upper),
            DirichletBC(self.W.sub(1), 0.0, upper),
            # DirichletBC(self.W.sub(0), Constant('-1.0'), lower),
            # DirichletBC(self.W.sub(1), 0.0, lower),
            # DirichletBC(self.W.sub(1), Constant('1.0'), left),
            # DirichletBC(self.W.sub(0), 0.0, left),
            # DirichletBC(self.W.sub(1), Constant('-1.0'), right),
            # DirichletBC(self.W.sub(0), 0.0, right),
        ]
        self.P = FunctionSpace(self.mesh, "CG", 1)
        self.p_bcs = []
        return
    forms_pde["R_a"],
    forms_pde["S_a"],
    phi_bcs,
    property_idx,
)

# Function spaces for Stokes
mixedL = FunctionSpace(mesh, MixedElement([W_e_2, Q_E]))
mixedG = FunctionSpace(mesh, MixedElement([Wbar_e_2_H12, Qbar_E]))

U0, Uh = Function(mixedL), Function(mixedL)
Uhbar = Function(mixedG)

# BCs
bcs = [
    DirichletBC(mixedG.sub(0), Constant((0, 0)),
                "near(x[1], 0.0) or near(x[1], 1.0)"),
    DirichletBC(
        mixedG.sub(0).sub(0),
        Constant(0),
        CompiledSubDomain("near(x[0], 0.0) or near(x[0], lmbda)", lmbda=lmbda),
    ),
]

# Forms Stokes
alpha = Constant(6 * k * k)
Rb = Constant(1.0)
eta_top = Constant(1.0)
eta_bottom = Constant(0.01)
eta = eta_bottom + phi * (eta_top - eta_bottom)
forms_stokes = FormsStokes(mesh, mixedL, mixedG,
Ejemplo n.º 26
0
                                       forms_pde['N_a'], forms_pde['G_a'], forms_pde['L_a'],
                                       forms_pde['H_a'],
                                       forms_pde['B_a'],
                                       forms_pde['Q_a'], forms_pde['R_a'], forms_pde['S_a'],
                                       phi_bcs,
                                       property_idx)

# Function spaces for Stokes
mixedL = FunctionSpace(mesh, MixedElement([W_e_2, Q_E]))
mixedG = FunctionSpace(mesh, MixedElement([Wbar_e_2_H12, Qbar_E]))

U0, Uh = Function(mixedL), Function(mixedL)
Uhbar = Function(mixedG)

# BCs
bcs = [DirichletBC(mixedG.sub(0), Constant((0, 0, 0.0)), "near(x[1], 0.0) or near(x[1], 1.0)"),
       DirichletBC(mixedG.sub(0).sub(0), Constant(0),
                   CompiledSubDomain("near(x[0], 0.0) or near(x[0], lmbda)", lmbda=lmbdax)),
       DirichletBC(mixedG.sub(0).sub(2), Constant(0),
                   CompiledSubDomain("near(x[2], 0.0) or near(x[2], lmbda)", lmbda=lmbdaz))]

# Forms Stokes
alpha = Constant(6*k*k)
Rb = Constant(1.0)
eta_top = Constant(1.0)
eta_bottom = Constant(0.01)
eta = eta_bottom + phi * (eta_top - eta_bottom)
forms_stokes = FormsStokes(mesh, mixedL, mixedG, alpha) \
    .forms_steady(eta, Rb * phi * Constant((0, -1, 0)))

ssc = StokesStaticCondensation(mesh,
Ejemplo n.º 27
0
def test_karman(num_steps=2, lcar=0.1, show=False):
    mesh = create_mesh(lcar)

    W_element = VectorElement('Lagrange', mesh.ufl_cell(), 2)
    P_element = FiniteElement('Lagrange', mesh.ufl_cell(), 1)
    WP = FunctionSpace(mesh, W_element * P_element)

    W = WP.sub(0)
    # P = WP.sub(1)

    mesh_eps = 1.0e-12

    # Define mesh and boundaries.
    # pylint: disable=no-self-use
    class LeftBoundary(SubDomain):
        def inside(self, x, on_boundary):
            return on_boundary and x[0] < x0 + mesh_eps

    left_boundary = LeftBoundary()

    class RightBoundary(SubDomain):
        def inside(self, x, on_boundary):
            return on_boundary and x[0] > x1 - mesh_eps

    right_boundary = RightBoundary()

    class LowerBoundary(SubDomain):
        def inside(self, x, on_boundary):
            return on_boundary and x[1] < y0 + mesh_eps

    lower_boundary = LowerBoundary()

    class UpperBoundary(SubDomain):
        def inside(self, x, on_boundary):
            return on_boundary and x[1] > y1 - mesh_eps

    upper_boundary = UpperBoundary()

    class ObstacleBoundary(SubDomain):
        def inside(self, x, on_boundary):
            return (on_boundary and x0 + mesh_eps < x[0] < x1 - mesh_eps
                    and y0 + mesh_eps < x[1] < y1 - mesh_eps)

    obstacle_boundary = ObstacleBoundary()

    # Boundary conditions for the velocity.
    # Proper inflow and outflow conditions are a matter of voodoo. See for
    # example Gresho/Sani, or
    #
    #     Boundary conditions for open boundaries for the incompressible
    #     Navier-Stokes equation;
    #     B.C.V. Johansson;
    #     J. Comp. Phys. 105, 233-251 (1993).
    #
    # The latter in particularly suggest for the inflow:
    #
    #     u = u0,
    #     d^r v / dx^r = v_r,
    #     div(u) = 0,
    #
    # where u and v are the velocities in normal and tangential directions,
    # respectively, and r\in{0,1,2}. The setting r=0 essentially means to set
    # (u,v) statically at the left boundary, r=1 means to set u and control
    # dv/dn, which is what we do here (namely implicitly by dv/dn=0).
    # At the outflow,
    #
    #     d^j u / dx^j = 0,
    #     d^q v / dx^q = 0,
    #     p = p0,
    #
    # is suggested with j=q+1. Choosing q=0, j=1 means setting the tangential
    # component of the outflow to 0, and letting the normal component du/dn=0
    # (again, this is achieved implicitly by the weak formulation).
    #
    inflow = Expression('%e * (%e - x[1]) * (x[1] - %e) / %e' %
                        (entrance_velocity, y1, y0, (0.5 * (y1 - y0))**2),
                        degree=2)
    outflow = Expression('%e * (%e - x[1]) * (x[1] - %e) / %e' %
                         (entrance_velocity, y1, y0, (0.5 * (y1 - y0))**2),
                         degree=2)
    u_bcs = [
        DirichletBC(W, (0.0, 0.0), upper_boundary),
        DirichletBC(W, (0.0, 0.0), lower_boundary),
        DirichletBC(W, (0.0, 0.0), obstacle_boundary),
        DirichletBC(W.sub(0), inflow, left_boundary),
        #
        DirichletBC(W.sub(0), outflow, right_boundary),
    ]
    # dudt_bcs = [
    #     DirichletBC(W, (0.0, 0.0), upper_boundary),
    #     DirichletBC(W, (0.0, 0.0), lower_boundary),
    #     DirichletBC(W, (0.0, 0.0), obstacle_boundary),
    #     DirichletBC(W.sub(0), 0.0, left_boundary),
    #     # DirichletBC(W.sub(1), 0.0, right_boundary),
    #     ]

    # If there is a penetration boundary (i.e., n.u!=0), then the pressure must
    # be set somewhere to make sure that the Navier-Stokes problem remains
    # consistent.
    # When solving Stokes with no Dirichlet conditions whatsoever, the pressure
    # tends to 0 at the outlet. This is natural since there, the liquid can
    # flow out at the rate it needs to be under no pressure at all.
    # Hence, at outlets, set the pressure to 0.
    p_bcs = [
        # DirichletBC(P, 0.0, right_boundary)
    ]

    # Getting vortices is not easy. If we take the actual viscosity of water,
    # they don't appear.
    mu = 0.002
    # mu = materials.water.dynamic_viscosity(T=293.0)

    # For starting off, solve the Stokes equation.
    u0, p0 = flow.stokes.solve(WP,
                               u_bcs + p_bcs,
                               mu,
                               f=Constant((0.0, 0.0)),
                               verbose=False,
                               tol=1.0e-13,
                               max_iter=10000)
    u0.rename('velocity', 'velocity')
    p0.rename('pressure', 'pressure')

    rho = materials.water.density(T=293.0)
    # stepper = flow.navier_stokes.Chorin()
    # stepper = flow.navier_stokes.IPCS()
    stepper = flow.navier_stokes.Rotational()

    W2 = u0.function_space()
    P2 = p0.function_space()
    u_bcs = [
        DirichletBC(W2, (0.0, 0.0), upper_boundary),
        DirichletBC(W2, (0.0, 0.0), lower_boundary),
        DirichletBC(W2, (0.0, 0.0), obstacle_boundary),
        DirichletBC(W2.sub(0), inflow, left_boundary),
        #
        DirichletBC(W2.sub(0), outflow, right_boundary),
    ]
    # TODO settting the outflow _and_ the pressure at the outlet is actually
    #      not necessary. Even without the pressure Dirichlet conditions, the
    #      pressure correction system should be consistent.
    p_bcs = [DirichletBC(P2, 0.0, right_boundary)]

    # Report Reynolds number.
    # https://en.wikipedia.org/wiki/Reynolds_number#Sphere_in_a_fluid
    reynolds = entrance_velocity * obstacle_diameter * rho / mu
    print('Reynolds number:  %e' % reynolds)

    dt = 1.0e-5
    dt_max = 1.0
    t = 0.0

    with XDMFFile(mpi_comm_world(), 'karman.xdmf') as xdmf_file:
        xdmf_file.parameters['flush_output'] = True
        xdmf_file.parameters['rewrite_function_mesh'] = False

        k = 0
        while k < num_steps:
            k += 1
            print()
            print('t = %f' % t)
            if show:
                plot(u0)
                plot(p0)
                xdmf_file.write(u0, t)
                xdmf_file.write(p0, t)

            u1, p1 = stepper.step(Constant(dt), {0: u0},
                                  p0,
                                  u_bcs,
                                  p_bcs,
                                  Constant(rho),
                                  Constant(mu),
                                  f={
                                      0: Constant((0.0, 0.0)),
                                      1: Constant((0.0, 0.0))
                                  },
                                  verbose=False,
                                  tol=1.0e-10)
            u0.assign(u1)
            p0.assign(p1)

            # Adaptive stepsize control based solely on the velocity field.
            # CFL-like condition for time step. This should be some sort of
            # average of the temperature in the current step and the target
            # step.
            #
            # More on step-size control for Navier--Stokes:
            #
            #     Adaptive time step control for the incompressible
            #     Navier-Stokes equations;
            #     Volker John, Joachim Rang;
            #     Comput. Methods Appl. Mech. Engrg. 199 (2010) 514-524;
            #     <http://www.wias-berlin.de/people/john/ELECTRONIC_PAPERS/JR10.CMAME.pdf>.
            #
            # Section 3.3 in that paper notes that time-adaptivity for theta-
            # schemes is too costly. They rather reside to DIRK- and
            # Rosenbrock-methods.
            #
            begin('Step size adaptation...')
            ux, uy = u0.split()
            unorm = project(sqrt(ux**2 + uy**2),
                            FunctionSpace(mesh, 'Lagrange', 2),
                            form_compiler_parameters={'quadrature_degree': 4})
            unorm = norm(unorm.vector(), 'linf')

            # print('||u||_inf = %e' % unorm)
            # Some smooth step-size adaption.
            target_dt = 1.0 * mesh.hmax() / unorm
            print('current dt: %e' % dt)
            print('target dt:  %e' % target_dt)
            # alpha is the aggressiveness factor. The distance between the
            # current step size and the target step size is reduced by
            # |1-alpha|. Hence, if alpha==1 then dt_next==target_dt. Otherwise
            # target_dt is approached more slowly.
            alpha = 0.5
            dt = min(
                dt_max,
                # At most double the step size from step to step.
                dt * min(2.0, 1.0 + alpha * (target_dt - dt) / dt))
            print('next dt:    %e' % dt)
            t += dt
            end()

    return
Ejemplo n.º 28
0
class Crucible:
    def __init__(self):

        GMSH_EPS = 1.0e-15

        # https://fenicsproject.org/qa/12891/initialize-mesh-from-vertices-connectivities-at-once
        points, cells, point_data, cell_data, _ = meshes.crucible_with_coils.generate(
        )

        # Convert the cell data to 'uint' so we can pick a size_t MeshFunction
        # below as usual.
        for k0 in cell_data:
            for k1 in cell_data[k0]:
                cell_data[k0][k1] = numpy.array(cell_data[k0][k1],
                                                dtype=numpy.dtype("uint"))

        with TemporaryDirectory() as temp_dir:
            tmp_filename = os.path.join(temp_dir, "test.xml")
            meshio.write_points_cells(
                tmp_filename,
                points,
                cells,
                cell_data=cell_data,
                file_format="dolfin-xml",
            )
            self.mesh = Mesh(tmp_filename)
            self.subdomains = MeshFunction(
                "size_t", self.mesh,
                os.path.join(temp_dir, "test_gmsh:physical.xml"))

        self.subdomain_materials = {
            1: my_materials.porcelain,
            2: materials.argon,
            3: materials.gallium_arsenide_solid,
            4: materials.gallium_arsenide_liquid,
            27: materials.air,
        }

        # coils
        for k in range(5, 27):
            self.subdomain_materials[k] = my_materials.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

        self.submesh_workpiece = SubMesh(self.mesh, self.subdomains, self.wpi)

        # 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 \'{}\' does not exist. Creating... '.format(
        #             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(filename)

        coords = self.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 = MeshFunction(
            "size_t",
            self.submesh_workpiece,
            self.submesh_workpiece.topology().dim() - 1,
        )
        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_element = FiniteElement("CG", self.submesh_workpiece.ufl_cell(), 2)
        with_bubbles = False
        if with_bubbles:
            V_element += FiniteElement("B", self.submesh_workpiece.ufl_cell(),
                                       2)
        self.W_element = MixedElement(3 * [V_element])
        self.W = FunctionSpace(self.submesh_workpiece, self.W_element)

        rot0 = Expression(("0.0", "0.0", "-2*pi*x[0] * 5.0/60.0"), degree=1)
        # rot0 = (0.0, 0.0, 0.0)
        rot1 = Expression(("0.0", "0.0", "2*pi*x[0] * 5.0/60.0"), degree=1)
        self.u_bcs = [
            DirichletBC(self.W, rot0, 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, rot1, upper_left),
            DirichletBC(self.W.sub(1), 0.0, upper_right),
        ]
        self.p_bcs = []

        self.P_element = FiniteElement("CG", self.submesh_workpiece.ufl_cell(),
                                       1)
        self.P = FunctionSpace(self.submesh_workpiece, self.P_element)

        self.Q_element = FiniteElement("CG", self.submesh_workpiece.ufl_cell(),
                                       2)
        self.Q = FunctionSpace(self.submesh_workpiece, self.Q_element)

        # Dirichlet.
        # This is a bit of a tough call since the boundary conditions need to
        # be read from a Tecplot file here.
        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):
            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
                    if False:
                        warnings.warn(
                            "Coordinate ({:e}, {:e}) doesn't sit on edge.".
                            format(x[0], x[1]))
                    # pp.plot(RZ[:, 0], RZ[:, 1], '.k')
                    # pp.plot(x[0], x[1], 'xr')
                    # pp.show()
                    # raise RuntimeError('Input coordinate '
                    #                    '{} is not on boundary.'.format(x))
                return

        tecplot_dbc = TecplotDirichletBC(degree=5)
        self.theta_bcs_d = [DirichletBC(self.Q, tecplot_dbc, upper_left)]
        self.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):
            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(degree=5)
        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.

        # Pick fixed coefficients roughly at the temperature that we expect.
        # This could be made less magic by having the coefficients depend on
        # theta and solving the quasilinear equation.
        temp_estimate = 1550.0

        # 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(temp_estimate)
        if isinstance(wp_material.density, float):
            rho = wp_material.density
        else:
            rho = wp_material.density(temp_estimate)
        if isinstance(wp_material.thermal_conductivity, float):
            k = wp_material.thermal_conductivity
        else:
            k = wp_material.thermal_conductivity(temp_estimate)

        reference_problem = cyl_heat.Heat(
            self.Q,
            convection=None,
            kappa=k,
            rho=rho,
            cp=cp,
            source=Constant(0.0),
            dirichlet_bcs=self.theta_bcs_d_strict,
        )
        theta_reference = reference_problem.solve_stationary()
        theta_reference.rename("theta", "temperature (Dirichlet)")

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

        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", subdomain_data=self.wp_boundaries)

            heat = cyl_heat.Heat(
                self.Q,
                convection=None,
                kappa=k,
                rho=rho,
                cp=cp,
                source=Constant(0.0),
                dirichlet_bcs=self.theta_bcs_d,
                neumann_bcs=self.theta_bcs_n,
                robin_bcs=self.theta_bcs_r,
                my_ds=ds_workpiece,
            )
            theta_new = heat.solve_stationary()
            theta_new.rename("theta", "temperature (Neumann + Dirichlet)")

            from dolfin import plot, interactive, errornorm

            print("||theta_new - theta_ref|| = {:e}".format(
                errornorm(theta_new, theta_reference)))
            plot(theta_reference)
            plot(theta_new)
            plot(theta_reference - theta_new, title="theta_ref - theta_new")
            interactive()

        self.background_temp = 1400.0

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

        return
fc_val = [0.0, fc]

help = np.asarray(subdomains.array(), dtype=np.int32)
fc_function.vector()[:] = np.choose(help, fc_val)
zeroth = plot(fc_function, title="Fixed charge density, $c^f$")
plt.colorbar(zeroth)
plot(fc_function)
plt.xlim(0.0, 0.015)
plt.xticks([0.0, 0.005, 0.01, 0.015])
plt.ylim(0.0, 0.015)
plt.yticks([0.0, 0.005, 0.01, 0.015])
plt.show()

Sol_c = Constant(1.0)
Poten = 50.0E-3
l_bc_an = DirichletBC(ME.sub(0), Sol_c, left_boundary)
r_bc_an = DirichletBC(ME.sub(0), Sol_c, right_boundary)
l_bc_ca = DirichletBC(ME.sub(1), Sol_c, left_boundary)
r_bc_ca = DirichletBC(ME.sub(1), Sol_c, right_boundary)
l_bc_psi = DirichletBC(ME.sub(2), Constant(-Poten), left_boundary)
r_bc_psi = DirichletBC(ME.sub(2), Constant(Poten), right_boundary)
bcs = [l_bc_an, r_bc_an, l_bc_ca, r_bc_ca, l_bc_psi, r_bc_psi]

u = Function(ME)

V = FunctionSpace(mesh, P1)
an_int = interpolate(
    Expression(
        '((pow((x[0] - 7.5E-3), 2) + pow((x[1] - 7.5E-3), 2)) <= pow(2.5E-3, 2)) ? 0.4142 : 1.0',
        degree=1), V)
ca_int = interpolate(
def test_unsteady_stokes():
    nx, ny = 15, 15
    k = 1
    nu = Constant(1.0e-0)
    dt = Constant(2.5e-2)
    num_steps = 20
    theta0 = 1.0  # Initial theta value
    theta1 = 0.5  # Theta after 1 step
    theta = Constant(theta0)

    mesh = UnitSquareMesh(nx, ny)

    # The 'unsteady version' of the benchmark in the 2012 paper by Labeur&Wells
    u_exact = Expression(
        (
            "sin(t) * x[0]*x[0]*(1.0 - x[0])*(1.0 - x[0])*(2.0*x[1] \
                           -6.0*x[1]*x[1] + 4.0*x[1]*x[1]*x[1])",
            "-sin(t)* x[1]*x[1]*(1.0 - x[1])*(1.0 - x[1])*(2.0*x[0] \
                           - 6.0*x[0]*x[0] + 4.0*x[0]*x[0]*x[0])",
        ),
        t=0,
        degree=7,
        domain=mesh,
    )
    p_exact = Expression("sin(t) * x[0]*(1.0 - x[0])",
                         t=0,
                         degree=7,
                         domain=mesh)
    du_exact = Expression(
        (
            "cos(t) * x[0]*x[0]*(1.0 - x[0])*(1.0 - x[0])*(2.0*x[1] \
                            - 6.0*x[1]*x[1] + 4.0*x[1]*x[1]*x[1])",
            "-cos(t)* x[1]*x[1]*(1.0 - x[1])*(1.0 - x[1])*(2.0*x[0] \
                            -6.0*x[0]*x[0] + 4.0*x[0]*x[0]*x[0])",
        ),
        t=0,
        degree=7,
        domain=mesh,
    )

    ux_exact = Expression(
        (
            "x[0]*x[0]*(1.0 - x[0])*(1.0 - x[0])*(2.0*x[1] \
                            - 6.0*x[1]*x[1] + 4.0*x[1]*x[1]*x[1])",
            "-x[1]*x[1]*(1.0 - x[1])*(1.0 - x[1])*(2.0*x[0] \
                            - 6.0*x[0]*x[0] + 4.0*x[0]*x[0]*x[0])",
        ),
        degree=7,
        domain=mesh,
    )

    px_exact = Expression("x[0]*(1.0 - x[0])", degree=7, domain=mesh)

    sin_ext = Expression("sin(t)", t=0, degree=7, domain=mesh)

    f = du_exact + sin_ext * div(px_exact * Identity(2) -
                                 2 * sym(grad(ux_exact)))

    Vhigh = VectorFunctionSpace(mesh, "DG", 7)
    Phigh = FunctionSpace(mesh, "DG", 7)

    # New syntax:
    V = VectorElement("DG", mesh.ufl_cell(), k)
    Q = FiniteElement("DG", mesh.ufl_cell(), k - 1)
    Vbar = VectorElement("DGT", mesh.ufl_cell(), k)
    Qbar = FiniteElement("DGT", mesh.ufl_cell(), k)

    mixedL = FunctionSpace(mesh, MixedElement([V, Q]))
    mixedG = FunctionSpace(mesh, MixedElement([Vbar, Qbar]))
    V2 = FunctionSpace(mesh, V)

    Uh = Function(mixedL)
    Uhbar = Function(mixedG)
    U0 = Function(mixedL)
    Uhbar0 = Function(mixedG)
    u0, p0 = split(U0)
    ubar0, pbar0 = split(Uhbar0)
    ustar = Function(V2)

    # Then the boundary conditions
    bc0 = DirichletBC(mixedG.sub(0), Constant((0, 0)), Gamma)
    bc1 = DirichletBC(mixedG.sub(1), Constant(0), Corner, "pointwise")
    bcs = [bc0, bc1]

    alpha = Constant(6 * k * k)
    forms_stokes = FormsStokes(mesh, mixedL, mixedG,
                               alpha).forms_unsteady(ustar, dt, nu, f)
    ssc = StokesStaticCondensation(
        mesh,
        forms_stokes["A_S"],
        forms_stokes["G_S"],
        forms_stokes["G_ST"],
        forms_stokes["B_S"],
        forms_stokes["Q_S"],
        forms_stokes["S_S"],
    )

    t = 0.0
    step = 0
    for step in range(num_steps):
        step += 1
        t += float(dt)
        if comm.Get_rank() == 0:
            print("Step " + str(step) + " Time " + str(t))

        # Set time level in exact solution
        u_exact.t = t
        p_exact.t = t

        du_exact.t = t - (1 - float(theta)) * float(dt)
        sin_ext.t = t - (1 - float(theta)) * float(dt)

        ssc.assemble_global_lhs()
        ssc.assemble_global_rhs()
        for bc in bcs:
            ssc.apply_boundary(bc)

        ssc.solve_problem(Uhbar, Uh, "none", "default")
        assign(U0, Uh)
        assign(ustar, U0.sub(0))
        assign(Uhbar0, Uhbar)
        if step == 1:
            theta.assign(theta1)

        udiv_e = sqrt(assemble(div(Uh.sub(0)) * div(Uh.sub(0)) * dx))

    u_ex_h = interpolate(u_exact, Vhigh)
    p_ex_h = interpolate(p_exact, Phigh)

    u_error = sqrt(assemble(dot(Uh.sub(0) - u_ex_h, Uh.sub(0) - u_ex_h) * dx))
    p_error = sqrt(assemble(dot(Uh.sub(1) - p_ex_h, Uh.sub(1) - p_ex_h) * dx))

    assert udiv_e < 1e-12
    assert u_error < 1.5e-4
    assert p_error < 1e-2
Ejemplo n.º 31
0
    def _prepare_solution_fcns(self):
        # Extract parameters needed to create finite elements
        N = self.parameters["N"]
        gdim = self._mesh.geometry().dim()

        # Group elements for phi, chi, v
        elements_ch = (N - 1) * [
            self._FE["phi"],
        ] + (N - 1) * [
            self._FE["chi"],
        ]
        # NOTE: Elements for phi and chi are grouped together to avoid special
        #       treatment of the case with N = 2. For example, if N == 2 and
        #       phi would be represented as a vector with a single component
        #       then a special treatment is needed to plot this single
        #       component (UFL/DOLFIN ban to plot 1D function on a 2D mesh).
        elements = []
        elements.append(MixedElement(elements_ch))
        elements.append(VectorElement(self._FE["v"], dim=gdim))

        # Append elements for p and th
        elements.append(self._FE["p"])
        if self._FE["th"] is not None:
            elements.append(self._FE["th"])

        # Build function spaces
        W = FunctionSpace(self._mesh,
                          MixedElement(elements),
                          constrained_domain=self._constrained_domain)
        self._ndofs["total"] = W.dim()
        self._subspace["phi"] = [W.sub(0).sub(i) for i in range(N - 1)]
        self._subspace["chi"] = [
            W.sub(0).sub(i) for i in range(N - 1, 2 * (N - 1))
        ]
        self._ndofs["phi"] = W.sub(0).sub(0).dim()
        self._ndofs["chi"] = W.sub(0).sub(N - 1).dim()
        if gdim == 1:
            self._subspace["v"] = [
                W.sub(1),
            ]
            self._ndofs["v"] = W.sub(1).dim()
        else:
            self._subspace["v"] = [W.sub(1).sub(i) for i in range(gdim)]
            self._ndofs["v"] = W.sub(1).sub(0).dim()
        self._subspace["p"] = W.sub(2)
        self._ndofs["p"] = W.sub(2).dim()
        self._ndofs["th"] = 0
        if W.num_sub_spaces() == 4:
            self._subspace["th"] = W.sub(3)
            self._ndofs["th"] = W.sub(3).dim()
        self._ndofs["CH"] = W.sub(0).dim()
        self._ndofs["NS"] = (gdim * self._ndofs["v"] + self._ndofs["p"] +
                             self._ndofs["th"])
        assert self._ndofs["total"] == self._ndofs["CH"] + self._ndofs["NS"]

        # Create solution variable at ctl
        w_ctl = (Function(W), )
        w_ctl[0].rename("mono_ctl", "solution_mono_ctl")

        # Create solution variables at ptl
        w_ptl = [(Function(W), ) for i in range(self.parameters["PTL"])]
        for (i, f) in enumerate(w_ptl):
            f[0].rename("mono_ptl%i" % i, "solution_mono_ptl%i" % i)

        return (w_ctl, w_ptl)
Ejemplo n.º 32
0
    # Set log level for parallel
    set_log_level(LogLevel.ERROR)
    if rank == 0:
        set_log_level(LogLevel.PROGRESS)

    ff = MeshFunction("size_t", mesh, mesh.geometry().dim() - 1)
    Dirichlet(Lx, Ly, Lpml).mark(ff, 1)

    # Create function spaces
    VE = VectorElement("CG", mesh.ufl_cell(), 1, dim=2)
    TE = TensorElement("DG", mesh.ufl_cell(), 0, shape=(2, 2), symmetry=True)

    W = FunctionSpace(mesh, MixedElement([VE, TE]))
    F = FunctionSpace(mesh, "CG", 2)
    V = W.sub(0).collapse()
    M = W.sub(1).collapse()

    alpha_0 = alpha_0(m, car_dim, R, Lpml)
    alpha_1 = alpha_1(alpha_0, Lx, Lpml, degree=2)
    alpha_2 = alpha_2(alpha_0, Ly, Lpml, degree=2)

    beta_0 = beta_0(m, V_r, R, Lpml)
    beta_1 = beta_1(beta_0, Lx, Lpml, degree=2)
    beta_2 = beta_2(beta_0, Ly, Lpml, degree=2)

    alpha_1 = interpolate(alpha_1, F)
    alpha_2 = interpolate(alpha_2, F)
    beta_1 = interpolate(beta_1, F)
    beta_2 = interpolate(beta_2, F)
Ejemplo n.º 33
0
    def _prepare_solution_fcns(self):
        # Extract parameters needed to create finite elements
        N = self.parameters["N"]
        gdim = self._mesh.geometry().dim()

        # Group elements for phi, chi, v
        elements_ch = (N - 1) * [
            self._FE["phi"],
        ] + (N - 1) * [
            self._FE["chi"],
        ]
        elements_ns = [
            VectorElement(self._FE["v"], dim=gdim),
        ]

        # Append elements for p and th
        elements_ns.append(self._FE["p"])
        if self._FE["th"] is not None:
            elements_ns.append(self._FE["th"])

        # Build function spaces
        W_ch = FunctionSpace(self._mesh,
                             MixedElement(elements_ch),
                             constrained_domain=self._constrained_domain)
        W_ns = FunctionSpace(self._mesh,
                             MixedElement(elements_ns),
                             constrained_domain=self._constrained_domain)
        self._ndofs["CH"] = W_ch.dim()
        self._ndofs["NS"] = W_ns.dim()
        self._ndofs["total"] = W_ch.dim() + W_ns.dim()
        self._subspace["phi"] = [W_ch.sub(i) for i in range(N - 1)]
        self._subspace["chi"] = [
            W_ch.sub(i) for i in range(N - 1, 2 * (N - 1))
        ]
        self._ndofs["phi"] = W_ch.sub(0).dim()
        self._ndofs["chi"] = W_ch.sub(N - 1).dim()
        if gdim == 1:
            self._subspace["v"] = [
                W_ns.sub(0),
            ]
            self._ndofs["v"] = W_ns.sub(0).dim()
        else:
            self._subspace["v"] = [W_ns.sub(0).sub(i) for i in range(gdim)]
            self._ndofs["v"] = W_ns.sub(0).sub(0).dim()
        self._subspace["p"] = W_ns.sub(1)
        self._ndofs["p"] = W_ns.sub(1).dim()
        self._ndofs["th"] = 0
        if W_ns.num_sub_spaces() == 3:
            self._subspace["th"] = W_ns.sub(2)
            self._ndofs["th"] = W_ns.sub(2).dim()
        # ndofs = (
        #       (N-1)*(self._ndofs["phi"] + self._ndofs["chi"])
        #     + gdim*self._ndofs["v"]
        #     + self._ndofs["p"]
        #     + self._ndofs["th"]
        # )
        # assert self._ndofs["total"] == ndofs

        # Create solution variables at ctl
        w_ctl = (Function(W_ch), Function(W_ns))
        w_ctl[0].rename("semi_ctl_ch", "solution_semi_ch_ctl")
        w_ctl[1].rename("semi_ctl_ns", "solution_semi_ns_ctl")

        # Create solution variables at ptl
        w_ptl = [(Function(W_ch), Function(W_ns)) \
                     for i in range(self.parameters["PTL"])]
        for i, f in enumerate(w_ptl):
            f[0].rename("semi_ptl%i_ch" % i, "solution_semi_ch_ptl%i" % i)
            f[1].rename("semi_ptl%i_ns" % i, "solution_semi_ns_ptl%i" % i)

        return (w_ctl, w_ptl)