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)
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
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