def test_b_mesh_mapping(celltype): """ Creates a boundary mesh and checks that the geometrical entities are mapped to the correct cells. """ mesh = dolfinx.UnitCubeMesh(MPI.COMM_WORLD, 2, 2, 2, cell_type=celltype) b_mesh, bndry_to_mesh = dolfinx.plotting.create_boundary_mesh( mesh, MPI.COMM_SELF) # Compute map from boundary mesh topology to boundary mesh geometry b_mesh.topology.create_connectivity(b_mesh.topology.dim, b_mesh.topology.dim) b_imap = b_mesh.topology.index_map(b_mesh.topology.dim) tdim_entities = np.arange(b_imap.size_local, dtype=np.int32) boundary_geometry = cmesh.entities_to_geometry(b_mesh, b_mesh.topology.dim, tdim_entities, False) # Compare geometry maps for i in range(boundary_geometry.shape[0]): assert (np.allclose(b_mesh.geometry.x[boundary_geometry[i]], mesh.geometry.x[bndry_to_mesh[i]])) # Check that boundary mesh integrated has the correct area b_volume = mesh.mpi_comm().allreduce(dolfinx.fem.assemble_scalar( dolfinx.Constant(b_mesh, 1) * ufl.dx), op=MPI.SUM) mesh_surface = mesh.mpi_comm().allreduce(dolfinx.fem.assemble_scalar( dolfinx.Constant(mesh, 1) * ufl.ds), op=MPI.SUM) assert (np.isclose(b_volume, mesh_surface))
def xtest_assembly_dS_domains(mode): N = 10 mesh = dolfinx.UnitSquareMesh(MPI.COMM_WORLD, N, N, ghost_mode=mode) one = dolfinx.Constant(mesh, 1) val = dolfinx.fem.assemble_scalar(one * ufl.dS) val = mesh.mpi_comm().allreduce(val, op=MPI.SUM) assert val == pytest.approx(2 * (N - 1) + N * numpy.sqrt(2), 1.0e-7)
def xtest_assembly_dS_domains(mode): N = 10 mesh = dolfinx.UnitSquareMesh(dolfinx.MPI.comm_world, N, N, ghost_mode=mode) one = dolfinx.Constant(mesh, 1) val = dolfinx.fem.assemble_scalar(one * ufl.dS) val = dolfinx.MPI.sum(mesh.mpi_comm(), val) assert val == pytest.approx(2 * (N - 1) + N * numpy.sqrt(2), 1.0e-7)
def solve(self, f, filename): # redifine constans for specific frequency self.f = f self.omega = 2 * np.pi * f self.lmda = self.c / f self.k0 = self.omega / self.c # Load mesh mesh, cell_tags, facet_tags = read_from_msh(filename, cell_data=True, facet_data=True, gdim=2) # Define function space V = dolfinx.FunctionSpace(mesh, ("Lagrange", self.degree)) # Interpolate wavenumber k onto V k = dolfinx.Constant(V, self.k0) # Interpolate absorbing layer piece of wavenumber k_absorb onto V k_absorb = dolfinx.Function(V) adiabatic_layer = AdiabaticLayer(self.deg_absorber, self.k0, self.lmda) k_absorb.interpolate(adiabatic_layer.eval) # Interpolate incident wave field onto V ui = dolfinx.Function(V) ui_expr = IncidentWave(self.k0) ui.interpolate(ui_expr.eval) # Define variational problem u = ufl.TrialFunction(V) v = ufl.TestFunction(V) ds_exited = ufl.Measure("ds", domain=mesh, subdomain_data=facet_tags, subdomain_id=1) a = ufl.inner(ufl.grad(u), ufl.grad(v)) * ufl.dx \ - k ** 2 * ufl.inner(u, v) * ufl.dx \ - k_absorb * ufl.inner(u, v) * ufl.dx L = -1j * self.omega * self.rho_0 * ufl.inner(ui, v) * ufl.dx # Assemble matrix and vector and set up direct solver A = dolfinx.fem.assemble_matrix(a) A.assemble() b = dolfinx.fem.assemble_vector(L) b.ghostUpdate(addv=PETSc.InsertMode.ADD, mode=PETSc.ScatterMode.REVERSE) solver = PETSc.KSP().create(mesh.mpi_comm()) opts = PETSc.Options() opts["ksp_type"] = "preonly" opts["pc_type"] = "lu" opts["pc_factor_mat_solver_type"] = "mumps" solver.setFromOptions() solver.setOperators(A) # Solve linear system u = dolfinx.Function(V) start = time.time() solver.solve(b, u.vector) end = time.time() time_elapsed = end - start print('Solve time: ', time_elapsed) u.vector.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD) save(mesh, u, f"../Solution/sol_{f}Hz.xdmf")
lid_velocity = Function(V) lid_velocity.interpolate(lid_velocity_expression) facets = locate_entities_boundary(mesh, 1, lid) bc1 = DirichletBC(lid_velocity, locate_dofs_topological(V, 1, facets)) # Collect Dirichlet boundary conditions bcs = [bc0, bc1] # We now define the bilinear and linear forms corresponding to the weak # mixed formulation of the Stokes equations in a blocked structure:: # Define variational problem (u, p) = ufl.TrialFunction(V), ufl.TrialFunction(Q) (v, q) = ufl.TestFunction(V), ufl.TestFunction(Q) f = dolfinx.Constant(mesh, (0, 0)) a = [[inner(grad(u), grad(v)) * dx, inner(p, div(v)) * dx], [inner(div(u), q) * dx, None]] L = [inner(f, v) * dx, inner(dolfinx.Constant(mesh, 0), q) * dx] # We will use a block-diagonal preconditioner to solve this problem:: a_p11 = inner(p, q) * dx a_p = [[a[0][0], None], [None, a_p11]] # Nested matrix solver # ^^^^^^^^^^^^^^^^^^^^ # # We now assemble the bilinear form into a nested matrix `A`, and call
def test_assembly_into_quadrature_function(): """Test assembly into a Quadrature function. This test evaluates a UFL Expression into a Quadrature function space by evaluating the Expression on all cells of the mesh, and then inserting the evaluated values into a PETSc Vector constructed from a matching Quadrature function space. Concretely, we consider the evaluation of: e = B*(K(T)))**2 * grad(T) where K = 1/(A + B*T) where A and B are Constants and T is a Coefficient on a P2 finite element space with T = x + 2*y. The result is compared with interpolating the analytical expression of e directly into the Quadrature space. In parallel, each process evaluates the Expression on both local cells and ghost cells so that no parallel communication is required after insertion into the vector. """ mesh = dolfinx.UnitSquareMesh(MPI.COMM_WORLD, 3, 6) quadrature_degree = 2 quadrature_points = basix.make_quadrature(basix.CellType.triangle, quadrature_degree) Q_element = ufl.VectorElement("Quadrature", ufl.triangle, quadrature_degree, quad_scheme="default") Q = dolfinx.FunctionSpace(mesh, Q_element) def T_exact(x): return x[0] + 2.0 * x[1] P2 = dolfinx.FunctionSpace(mesh, ("P", 2)) T = dolfinx.Function(P2) T.interpolate(T_exact) A = dolfinx.Constant(mesh, 1.0) B = dolfinx.Constant(mesh, 2.0) K = 1.0 / (A + B * T) e = B * K**2 * ufl.grad(T) e_expr = dolfinx.Expression(e, quadrature_points) map_c = mesh.topology.index_map(mesh.topology.dim) num_cells = map_c.size_local + map_c.num_ghosts cells = np.arange(0, num_cells, dtype=np.int32) e_eval = e_expr.eval(cells) # Assemble into Function e_Q = dolfinx.Function(Q) with e_Q.vector.localForm() as e_Q_local: e_Q_local.setBlockSize(e_Q.function_space.dofmap.bs) e_Q_local.setValuesBlocked(Q.dofmap.list.array, e_eval, addv=PETSc.InsertMode.INSERT) def e_exact(x): T = x[0] + 2.0 * x[1] K = 1.0 / (A.value + B.value * T) grad_T = np.zeros((2, x.shape[1])) grad_T[0, :] = 1.0 grad_T[1, :] = 2.0 e = B.value * K**2 * grad_T return e e_exact_Q = dolfinx.Function(Q) e_exact_Q.interpolate(e_exact) assert np.isclose((e_exact_Q.vector - e_Q.vector).norm(), 0.0)
def test_simple_evaluation(): """Test evaluation of UFL Expression. This test evaluates a UFL Expression on cells of the mesh and compares the result with an analytical expression. For a function f(x, y) = 3*(x^2 + 2*y^2) the result is compared with the exact gradient: grad f(x, y) = 3*[2*x, 4*y]. (x^2 + 2*y^2) is first interpolated into a P2 finite element space. The scaling by a constant factor of 3 and the gradient is calculated using code generated by FFCX. The analytical solution is found by evaluating the spatial coordinates as an Expression using UFL/FFCX and passing the result to a numpy function that calculates the exact gradient. """ mesh = dolfinx.generation.UnitSquareMesh(MPI.COMM_WORLD, 3, 3) P2 = dolfinx.FunctionSpace(mesh, ("P", 2)) # NOTE: The scaling by a constant factor of 3.0 to get f(x, y) is # implemented within the UFL Expression. This is to check that the # Constants are being set up correctly. def exact_expr(x): return x[0] ** 2 + 2.0 * x[1] ** 2 # Unused, but remains for clarity. def f(x): return 3 * (x[0] ** 2 + 2.0 * x[1] ** 2) def exact_grad_f(x): values = np.zeros_like(x) values[:, 0::2] = 2 * x[:, 0::2] values[:, 1::2] = 4 * x[:, 1::2] values *= 3.0 return values expr = dolfinx.Function(P2) expr.interpolate(exact_expr) ufl_grad_f = dolfinx.Constant(mesh, 3.0) * ufl.grad(expr) points = np.array([[0.0, 0.0], [1.0, 0.0], [0.0, 1.0]]) grad_f_expr = dolfinx.Expression(ufl_grad_f, points) assert grad_f_expr.num_points == points.shape[0] assert grad_f_expr.value_size == 2 # NOTE: Cell numbering is process local. map_c = mesh.topology.index_map(mesh.topology.dim) num_cells = map_c.size_local + map_c.num_ghosts cells = np.arange(0, num_cells, dtype=np.int32) grad_f_evaluated = grad_f_expr.eval(cells) assert grad_f_evaluated.shape[0] == cells.shape[0] assert grad_f_evaluated.shape[1] == grad_f_expr.value_size * grad_f_expr.num_points # Evaluate points in global space ufl_x = ufl.SpatialCoordinate(mesh) x_expr = dolfinx.Expression(ufl_x, points) assert x_expr.num_points == points.shape[0] assert x_expr.value_size == 2 x_evaluated = x_expr.eval(cells) assert x_evaluated.shape[0] == cells.shape[0] assert x_evaluated.shape[1] == x_expr.num_points * x_expr.value_size # Evaluate exact gradient using global points grad_f_exact = exact_grad_f(x_evaluated) assert np.allclose(grad_f_evaluated, grad_f_exact)
# Structure: shear correction factor, see Cowper (1966) sc_fac = 10 * (1 + n) / (12 + 11 * n) def s(e): """ Stress as function of strain from strain energy function """ e = ufl.variable(e) W = lamé_μ * e * e + lamé_λ / 2 * e**2 # Saint-Venant Kirchhoff s = ufl.diff(W, e) return s # Structure: load parameters μ = dolfinx.Constant(mesh, 1.0) # load factor p_x = μ * dolfinx.Constant(mesh, 1.0 * 0) p_z = μ * dolfinx.Constant(mesh, 1.0 * 0) m_y = μ * dolfinx.Constant(mesh, 1.0 * 0) F_x = μ * dolfinx.Constant( mesh, (2.0 * np.pi / L)**2 * E * I * 0) # prescribed F_x: 2, 4 F_z = μ * dolfinx.Constant( mesh, (0.5 * np.pi / L)**2 * E * I * 0) # prescribed F_z: 4, 8 M_y = μ * dolfinx.Constant( mesh, (2.0 * np.pi / L)**1 * E * I * 1) # prescribed M_y: 1, 2 # Define integration measures dx = ufl.Measure("dx", domain=mesh, subdomain_data=subdomains) ds = ufl.Measure("ds", domain=mesh, subdomain_data=interfaces)
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 __init__(self, t, dt, x, xt, **kwargs): """Initialises the ODE integrator (single-step-method). Uses underneath the generalised alpha method and its limits: Euler forward: alpha_f = 0, alpha_m = 1/2, gamma = 1/2 Euler backward: alpha_f = 1, alpha_m = 1/2, gamma = 1/2 Crank-Nicolson: alpha_f = 1/2, alpha_m = 1/2, gamma = 1/2 Theta: alpha_f = theta, alpha_m = 1/2, gamma = 1/2 Generalised alpha: The value of rho can be used to determine the values alpha_f = 1 / (1 + rho), alpha_m = 1 / 2 * (3 - rho) / (1 + rho), gamma = 1 / 2 + alpha_m - alpha_f Parameters ---------- t: Stage time. dt: Time step size. x: Pointer to function describing the state. xt: Pointer to function describing the rate of the state. rho: Spectral radius rho_infinity for generalised alpha. alpha_f: Specific value for alpha_f. alpha_m: Specific value for alpha_m. gamma: Specific value for gamma. """ # Set stage time and time step self.t = t self.dt = dt if not isinstance(self.t, dolfinx.Constant): raise RuntimeError("No stage time t as dolfinx.Constant provied.") if not isinstance(self.dt, dolfinx.Constant): raise RuntimeError("No time step dt as dolfinx.Constant provied.") # Pointers to state x and rate xt (as function or list of functions) self.x = x self.xt = xt if isinstance(self.x, list): self.x0 = [] for x, xt in zip(self.x, self.xt): if x.function_space is not xt.function_space: raise RuntimeError( "Incompatible function spaces for state and rate.") else: if self.x.function_space is not self.xt.function_space: raise RuntimeError( "Incompatible function spaces for state and rate.") # Set state x0 if isinstance(self.x, list): self.x0 = [] for xi in self.x: self.x0.append(dolfinx.function.Function(xi.function_space)) else: self.x0 = dolfinx.function.Function(self.x.function_space) # Set rate of state x0t if isinstance(self.xt, list): self.x0t = [] for xti in self.xt: self.x0t.append(dolfinx.function.Function(xti.function_space)) else: self.x0t = dolfinx.function.Function(self.xt.function_space) # Expression: derivative in time self.derivative_dt = lambda x, x0, x0t: \ 1.0 / (self.gamma * self.dt) * (x - x0) + (self.gamma - 1.0) / self.gamma * x0t # Expression: integral in time self.integral_dt = lambda x, xt, x0, x0t: \ self.dt / 2 * (x0 + x) + self.dt**2 / 12 * (x0t - xt) # Expression: state at collocation point in time interval self.state = lambda x0, x1: \ self.alpha_f * x1 + (1.0 - self.alpha_f) * x0 # Expression: rate of state at collocation point in time interval self.rate = lambda x0t, x1t: \ self.alpha_m * x1t + (1.0 - self.alpha_m) * x0t # Default values: Backward Euler self.alpha_f = dolfinx.Constant(self.t.ufl_domain(), 1.0) self.alpha_m = dolfinx.Constant(self.t.ufl_domain(), 0.5) self.gamma = dolfinx.Constant(self.t.ufl_domain(), 0.5) # Parameters from given rho if "rho" in kwargs: self.alpha_f.value = 1.0 / (1.0 + kwargs["rho"]) self.alpha_m.value = 0.5 * (3.0 - kwargs["rho"]) * self.alpha_f.value self.gamma.value = 0.5 + self.alpha_m.value - self.alpha_f.value # Parameters directly if "alpha_f" in kwargs and "alpha_m" in kwargs and "gamma" in kwargs: self.alpha_f.value = kwargs["alpha_f"] self.alpha_m.value = kwargs["alpha_m"] self.gamma.value = kwargs["gamma"]
# # Read mesh and meshtags from file # with dolfiny.io.XDMFFile(comm, f"{name}.xdmf", "r") as ifile: # mesh, mts = ifile.read_mesh_meshtags() # Get merged MeshTags for each codimension subdomains, subdomains_keys = dolfiny.mesh.merge_meshtags(mts, tdim - 0) interfaces, interfaces_keys = dolfiny.mesh.merge_meshtags(mts, tdim - 1) # Define shorthands for labelled tags ring_inner = interfaces_keys["ring_inner"] ring_outer = interfaces_keys["ring_outer"] domain = subdomains_keys["domain"] # Fluid material parameters rho = dolfinx.Constant(mesh, 2.0) # [kg/m^3] mu = dolfinx.Constant(mesh, 1.0) # [kg/m/s] tau_zero = dolfinx.Constant(mesh, 0.2) # [kg/m/s^2] tau_zero_regularisation = dolfinx.Constant(mesh, 1.e-3) # [-] # Max inner ring velocity v_inner_max = 0.1 # [m/s] # Normal and tangential velocity at inner ring v_n = dolfinx.Constant(mesh, 0.0) # [m/s] v_t = dolfinx.Constant(mesh, 0.0) # [m/s] -- value set/updated in analysis # Global time time = dolfinx.Constant(mesh, 0.0) # [s] # Time step size dt = dolfinx.Constant(mesh, 0.05) # [s] # Number of time steps
def test_assembly_into_quadrature_function(): """Test assembly into a Quadrature function. This test evaluates a UFL Expression into a Quadrature function space by evaluating the Expression on all cells of the mesh, and then inserting the evaluated values into a PETSc Vector constructed from a matching Quadrature function space. Concretely, we consider the evaluation of: e = B*(K(T)))**2 * grad(T) where K = 1/(A + B*T) where A and B are Constants and T is a Coefficient on a P2 finite element space with T = x + 2*y. The result is compared with interpolating the analytical expression of e directly into the Quadrature space. In parallel, each process evaluates the Expression on both local cells and ghost cells so that no parallel communication is required after insertion into the vector. """ mesh = dolfinx.UnitSquareMesh(MPI.COMM_WORLD, 3, 6) quadrature_degree = 2 quadrature_points, wts = basix.make_quadrature("default", basix.CellType.triangle, quadrature_degree) Q_element = ufl.VectorElement("Quadrature", ufl.triangle, quadrature_degree, quad_scheme="default") Q = dolfinx.FunctionSpace(mesh, Q_element) def T_exact(x): return x[0] + 2.0 * x[1] P2 = dolfinx.FunctionSpace(mesh, ("P", 2)) T = dolfinx.Function(P2) T.interpolate(T_exact) A = dolfinx.Constant(mesh, 1.0) B = dolfinx.Constant(mesh, 2.0) K = 1.0 / (A + B * T) e = B * K**2 * ufl.grad(T) e_expr = dolfinx.Expression(e, quadrature_points) map_c = mesh.topology.index_map(mesh.topology.dim) num_cells = map_c.size_local + map_c.num_ghosts cells = np.arange(0, num_cells, dtype=np.int32) e_eval = e_expr.eval(cells) # Assemble into Function e_Q = dolfinx.Function(Q) with e_Q.vector.localForm() as e_Q_local: e_Q_local.setBlockSize(e_Q.function_space.dofmap.bs) e_Q_local.setValuesBlocked(Q.dofmap.list.array, e_eval, addv=PETSc.InsertMode.INSERT) def e_exact(x): T = x[0] + 2.0 * x[1] K = 1.0 / (A.value + B.value * T) grad_T = np.zeros((2, x.shape[1])) grad_T[0, :] = 1.0 grad_T[1, :] = 2.0 e = B.value * K**2 * grad_T return e # FIXME: Below is only for testing purposes, # never to be used in user code! # # Replace when interpolation into Quadrature element works. coord_dofs = mesh.geometry.dofmap x_g = mesh.geometry.x tdim = mesh.topology.dim Q_dofs = Q.dofmap.list.array.reshape(num_cells, quadrature_points.shape[0]) bs = Q.dofmap.bs Q_dofs_unrolled = bs * np.repeat(Q_dofs, bs).reshape(-1, bs) + np.arange(bs) Q_dofs_unrolled = Q_dofs_unrolled.reshape( -1, bs * quadrature_points.shape[0]).astype(Q_dofs.dtype) with e_Q.vector.localForm() as local: e_exact_eval = np.zeros_like(local.array) for cell in range(num_cells): xg = x_g[coord_dofs.links(cell), :tdim] x = mesh.geometry.cmap.push_forward(quadrature_points, xg) e_exact_eval[Q_dofs_unrolled[cell]] = e_exact(x.T).T.flatten() assert np.allclose(local.array, e_exact_eval)
boundary_facets_fine = np.where( np.array(dolfinx.cpp.mesh.compute_boundary_facets(mesh_fine.topology)) == 1)[0] boundary_facets_coarse = np.where( np.array(dolfinx.cpp.mesh.compute_boundary_facets(mesh_coarse.topology)) == 1)[0] boundary_dofs_fine = dolfinx.fem.locate_dofs_topological( V_fine, fdim_fine, boundary_facets_fine) boundary_dofs_coarse = dolfinx.fem.locate_dofs_topological( V_coarse, fdim_coarse, boundary_facets_coarse) bc_fine = dolfinx.DirichletBC(u_fine, boundary_dofs_fine) u_D_fine = ufl.TrialFunction(V_fine) v_D_fine = ufl.TestFunction(V_fine) f_fine = dolfinx.Constant(mesh_fine, -6) a_fine = ufl.dot(ufl.grad(u_D_fine), ufl.grad(v_D_fine)) * ufl.dx #A_fine = dolfinx.fem.assemble_matrix(a_fine, bcs=[bc_fine]) # A_fine.assemble() bc_coarse = dolfinx.DirichletBC(u_coarse, boundary_dofs_coarse) u_D_coarse = ufl.TrialFunction(V_coarse) v_D_coarse = ufl.TestFunction(V_coarse) f_coarse = dolfinx.Constant(mesh_coarse, -6) a_coarse = ufl.dot(ufl.grad(u_D_coarse), ufl.grad(v_D_coarse)) * ufl.dx #A_coarse = dolfinx.fem.assemble_matrix(a_coarse, bcs=[bc_coarse]) # A_coarse.assemble() """ai1, aj1, av1 = A_fine.getValuesCSR() A_sp_fine = scp.sparse.csr_matrix((av1, aj1, ai1)) ai2, aj2, av2 = A_coarse.getValuesCSR()
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
# Driving velocity condition u = (1, 0) on top boundary (y = 1) lid_velocity = Function(V) lid_velocity.interpolate(lid_velocity_expression) facets = locate_entities_boundary(mesh, 1, lid) bc1 = DirichletBC(lid_velocity, locate_dofs_topological(V, 1, facets)) # Collect Dirichlet boundary conditions bcs = [bc0, bc1] # We now define the bilinear and linear forms corresponding to the weak # mixed formulation of the Stokes equations in a blocked structure:: # Define variational problem (u, p) = ufl.TrialFunction(V), ufl.TrialFunction(Q) (v, q) = ufl.TestFunction(V), ufl.TestFunction(Q) f = dolfinx.Constant(mesh, (0, 0)) a = [[inner(grad(u), grad(v)) * dx, inner(p, div(v)) * dx], [inner(div(u), q) * dx, None]] L = [inner(f, v) * dx, inner(dolfinx.Constant(mesh, 0), q) * dx] # We will use a block-diagonal preconditioner to solve this problem:: a_p11 = inner(p, q) * dx a_p = [[a[0][0], None], [None, a_p11]] # Nested matrix solver # ^^^^^^^^^^^^^^^^^^^^
# ofile.write_mesh_meshtags(mesh, mts) # # Read mesh and meshtags from file # with dolfiny.io.XDMFFile(comm, f"{name}.xdmf", "r") as ifile: # mesh, mts = ifile.read_mesh_meshtags() # Get merged MeshTags for each codimension subdomains, subdomains_keys = dolfiny.mesh.merge_meshtags(mts, tdim - 0) interfaces, interfaces_keys = dolfiny.mesh.merge_meshtags(mts, tdim - 1) # Define shorthands for labelled tags ring_inner = interfaces_keys["ring_inner"] ring_outer = interfaces_keys["ring_outer"] # Fluid material parameters rho = dolfinx.Constant(mesh, 2.0) # [kg/m^3] mu = dolfinx.Constant(mesh, 1.0) # [kg/m/s] tau_zero = dolfinx.Constant(mesh, 0.2) # [kg/m/s^2] tau_zero_regularisation = dolfinx.Constant(mesh, 1.e-3) # [-] # Max inner ring velocity v_inner_max = 0.1 # [m/s] # Global time time = dolfinx.Constant(mesh, 0.0) # [s] # Time step size dt = dolfinx.Constant(mesh, 0.05) # [s] # Number of time steps nT = 80 # Define integration measures
uD_i = dolfinx.Function(V_i) uD_i.interpolate(lambda x: 1 + x[0]**2 + 2 * x[1]**2) uD_i.vector.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD) fdim_i = mesh_i.topology.dim - 1 mesh_i.topology.create_connectivity(fdim_i, mesh_i.topology.dim) boundary_facets_i = np.where( np.array(dolfinx.cpp.mesh.compute_boundary_facets(mesh_i.topology)) == 1)[0] boundary_dofs_i = dolfinx.fem.locate_dofs_topological( V_i, fdim_i, boundary_facets_i) bc_i = dolfinx.DirichletBC(uD_i, boundary_dofs_i) u_i = ufl.TrialFunction(V_i) v_i = ufl.TestFunction(V_i) f_i = dolfinx.Constant(mesh_i, -6) a_i = ufl.dot(ufl.grad(u_i), ufl.grad(v_i)) * ufl.dx A_i = dolfinx.fem.assemble_matrix(a_i, bcs=[bc_i]) A_i.assemble() assert isinstance(A_i, PETSc.Mat) ai, aj, av = A_i.getValuesCSR() A_sp_i = scp.sparse.csr_matrix((av, aj, ai)) del A_i, av, ai, aj # Stores the Sparse version of the Stiffness Matrices A_sp_dict[i] = (A_sp_i, i) L_i = f_i * v_i * ufl.dx b_i = dolfinx.fem.create_vector(L_i) with b_i.localForm() as loc_b: loc_b.set(0) dolfinx.fem.assemble_vector(b_i, L_i) dolfinx.fem.apply_lifting(b_i, [a_i], [[bc_i]])