def increase_order(V: function.FunctionSpace) -> function.FunctionSpace:
    """For a given function space, return the same space, but with
    polynomial degree increase by 1.

    """
    e = ufl.algorithms.elementtransformations.increase_order(V.ufl_element())
    return function.FunctionSpace(V.mesh, e)
def test_ghost_mesh_assembly(mode, dx, ds):
    mesh = UnitSquareMesh(MPI.comm_world, 12, 12, ghost_mode=mode)
    V = FunctionSpace(mesh, ("Lagrange", 1))
    u, v = ufl.TrialFunction(V), ufl.TestFunction(V)
    dx = dx(mesh)
    ds = ds(mesh)

    f = Function(V)
    with f.vector.localForm() as f_local:
        f_local.set(10.0)
    a = inner(f * u, v) * dx + inner(u, v) * ds
    L = inner(f, v) * dx + inner(2.0, v) * ds

    # Initial assembly
    A = fem.assemble_matrix(a)
    A.assemble()
    assert isinstance(A, PETSc.Mat)
    b = fem.assemble_vector(L)
    b.ghostUpdate(addv=PETSc.InsertMode.ADD, mode=PETSc.ScatterMode.REVERSE)
    assert isinstance(b, PETSc.Vec)

    # Check that the norms are the same for all three modes
    normA = A.norm()
    assert normA == pytest.approx(0.6713621455570528, rel=1.e-6, abs=1.e-12)

    normb = b.norm()
    assert normb == pytest.approx(1.582294032953906, rel=1.e-6, abs=1.e-12)
def change_regularity(V: function.FunctionSpace,
                      family: str) -> function.FunctionSpace:
    """For a given function space, return the corresponding space with
    the finite elements specified by 'family'. Possible families are
    the families supported by the form compiler

    """
    e = ufl.algorithms.elementtransformations.change_regularity(
        V.ufl_element(), family)
    return function.FunctionSpace(V.mesh, e)
def test_ghost_mesh_dS_assembly(mode, dS):
    mesh = UnitSquareMesh(MPI.comm_world, 12, 12, ghost_mode=mode)
    V = FunctionSpace(mesh, ("Lagrange", 1))
    u, v = ufl.TrialFunction(V), ufl.TestFunction(V)
    dS = dS(mesh)

    a = inner(avg(u), avg(v)) * dS

    # Initial assembly
    A = fem.assemble_matrix(a)
    A.assemble()
    assert isinstance(A, PETSc.Mat)

    # Check that the norms are the same for all three modes
    normA = A.norm()
    print(normA)

    assert normA == pytest.approx(2.1834054713561906, rel=1.e-6, abs=1.e-12)
Exemple #5
0
def ode_1st_nonlinear_odeint(a=1.0, b=1.0, c=1.0, nT=10, dt=0.1, **kwargs):
    """
    Create 1st order ODE problem and solve with `ODEInt` time integrator.

    First order nonlinear non-autonomous ODE:
    t * dot u - a * cos(c*t) * u^2 - 2 * u - a * b^2 * t^4 * cos(c*t) = 0 with initial condition u(t=1) = 0
    """

    mesh = UnitCubeMesh(MPI.COMM_WORLD, 1, 1, 1)
    U = FunctionSpace(mesh, ("DG", 0))

    u = Function(U, name="u")
    ut = Function(U, name="ut")

    u.vector.set(0.0)  # initial condition
    ut.vector.set(
        a * b**2 *
        numpy.cos(c))  # exact initial rate of this ODE for generalised alpha

    u.vector.ghostUpdate()
    ut.vector.ghostUpdate()

    δu = ufl.TestFunction(U)

    dx = ufl.Measure("dx", domain=mesh)

    # Global time
    t = dolfinx.Constant(mesh, 1.0)

    # Time step size
    dt = dolfinx.Constant(mesh, dt)

    # Time integrator
    odeint = dolfiny.odeint.ODEInt(t=t, dt=dt, x=u, xt=ut, **kwargs)

    # Weak form (as one-form)
    f = δu * (t * ut - a * ufl.cos(c * t) * u**2 - 2 * u -
              a * b**2 * t**4 * ufl.cos(c * t)) * dx

    # Overall form (as one-form)
    F = odeint.discretise_in_time(f)
    # Overall form (as list of forms)
    F = dolfiny.function.extract_blocks(F, [δu])

    # # Options for PETSc backend
    from petsc4py import PETSc
    opts = PETSc.Options()
    opts["snes_type"] = "newtonls"
    opts["snes_linesearch_type"] = "basic"
    opts["snes_atol"] = 1.0e-10
    opts["snes_rtol"] = 1.0e-12

    # Silence SNES monitoring during test
    dolfiny.snesblockproblem.SNESBlockProblem.print_norms = lambda self, it: 1

    # Create nonlinear problem
    problem = dolfiny.snesblockproblem.SNESBlockProblem(F, [u])

    # Book-keeping of results
    u_avg = numpy.zeros(nT + 1)
    u_avg[0] = u.vector.sum() / u.vector.getSize()

    dolfiny.utils.pprint(f"+++ Processing time steps = {nT}")

    # Process time steps
    for time_step in range(1, nT + 1):

        # Stage next time step
        odeint.stage()

        # Solve nonlinear problem
        u, = problem.solve()

        # Assert convergence of nonlinear solver
        assert problem.snes.getConvergedReason(
        ) > 0, "Nonlinear solver did not converge!"

        # Update solution states for time integration
        odeint.update()

        # Store result
        u_avg[time_step] = u.vector.sum() / u.vector.getSize()

    return u_avg
Exemple #6
0
def ode_1st_linear_odeint(a=1.0, b=0.5, u_0=1.0, nT=10, dt=0.1, **kwargs):
    """
    Create 1st order ODE problem and solve with `ODEInt` time integrator.

    First order linear ODE:
    dot u + a * u - b = 0 with initial condition u(t=0) = u_0
    """

    mesh = UnitCubeMesh(MPI.COMM_WORLD, 1, 1, 1)
    U = FunctionSpace(mesh, ("DG", 0))

    u = Function(U, name="u")
    ut = Function(U, name="ut")

    u.vector.set(u_0)  # initial condition
    ut.vector.set(
        b - a * u_0)  # exact initial rate of this ODE for generalised alpha

    u.vector.ghostUpdate()
    ut.vector.ghostUpdate()

    δu = ufl.TestFunction(U)

    dx = ufl.Measure("dx", domain=mesh)

    # Global time
    time = dolfinx.Constant(mesh, 0.0)

    # Time step size
    dt = dolfinx.Constant(mesh, dt)

    # Time integrator
    odeint = dolfiny.odeint.ODEInt(t=time, dt=dt, x=u, xt=ut, **kwargs)

    # Weak form (as one-form)
    f = δu * (ut + a * u - b) * dx

    # Overall form (as one-form)
    F = odeint.discretise_in_time(f)
    # Overall form (as list of forms)
    F = dolfiny.function.extract_blocks(F, [δu])

    # Silence SNES monitoring during test
    dolfiny.snesblockproblem.SNESBlockProblem.print_norms = lambda self, it: 1

    # Create problem (although having a linear ODE we use the dolfiny.snesblockproblem API)
    problem = dolfiny.snesblockproblem.SNESBlockProblem(F, [u])

    # Book-keeping of results
    u_avg = numpy.zeros(nT + 1)
    u_avg[0] = u.vector.sum() / u.vector.getSize()

    dolfiny.utils.pprint(f"+++ Processing time steps = {nT}")

    # Process time steps
    for time_step in range(1, nT + 1):

        # Stage next time step
        odeint.stage()

        # Solve (linear) problem
        u, = problem.solve()

        # Update solution states for time integration
        odeint.update()

        # Store result
        u_avg[time_step] = u.vector.sum() / u.vector.getSize()

    return u_avg
def test_neohooke():
    mesh = UnitCubeMesh(MPI.COMM_WORLD, 7, 7, 7)
    V = VectorFunctionSpace(mesh, ("P", 1))
    P = FunctionSpace(mesh, ("P", 1))

    L = FunctionSpace(mesh, ("R", 0))

    u = Function(V, name="u")
    v = ufl.TestFunction(V)

    p = Function(P, name="p")
    q = ufl.TestFunction(P)

    lmbda0 = Function(L)

    d = mesh.topology.dim
    Id = ufl.Identity(d)
    F = Id + ufl.grad(u)
    C = F.T * F
    J = ufl.det(F)

    E_, nu_ = 10.0, 0.3
    mu, lmbda = E_ / (2 * (1 + nu_)), E_ * nu_ / ((1 + nu_) * (1 - 2 * nu_))
    psi = (mu / 2) * (ufl.tr(C) -
                      3) - mu * ufl.ln(J) + lmbda / 2 * ufl.ln(J)**2 + (p -
                                                                        1.0)**2
    pi = psi * ufl.dx

    F0 = ufl.derivative(pi, u, v)
    F1 = ufl.derivative(pi, p, q)

    # Number of eigenvalues to find
    nev = 8

    opts = PETSc.Options("neohooke")
    opts["eps_smallest_magnitude"] = True
    opts["eps_nev"] = nev
    opts["eps_ncv"] = 50 * nev
    opts["eps_conv_abs"] = True

    # opts["eps_non_hermitian"] = True
    opts["eps_tol"] = 1.0e-14
    opts["eps_max_it"] = 1000
    opts["eps_error_relative"] = "::ascii_info_detail"
    opts["eps_monitor"] = "::ascii_info_detail"

    slepcp = dolfiny.slepcblockproblem.SLEPcBlockProblem([F0, F1], [u, p],
                                                         lmbda0,
                                                         prefix="neohooke")
    slepcp.solve()

    # mat = dolfiny.la.petsc_to_scipy(slepcp.eps.getOperators()[0])
    # eigvals, eigvecs = linalg.eigsh(mat, which="SM", k=nev)

    with XDMFFile(MPI.COMM_WORLD, "eigvec.xdmf", "w") as ofile:
        ofile.write_mesh(mesh)
        for i in range(nev):
            eigval, ur, ui = slepcp.getEigenpair(i)

            # Expect first 6 eignevalues 0, i.e. rigid body modes
            if i < 6:
                assert np.isclose(eigval, 0.0)

            for func in ur:
                name = func.name
                func.name = f"{name}_eigvec_{i}_real"
                ofile.write_function(func)

                func.name = name