file.write_mesh(mesh) # Step in time t = 0.0 # Check if we are running on CI server and reduce run time if "CI" in os.environ.keys() or "GITHUB_ACTIONS" in os.environ.keys(): T = 3 * dt else: T = 50 * dt u.vector.copy(result=u0.vector) u0.vector.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD) while (t < T): t += dt r = solver.solve(problem, u.vector) print("Step, num iterations:", int(t / dt), r[0]) u.vector.copy(result=u0.vector) file.write_function(u.sub(0), t) file.close() # Within the time stepping loop, the nonlinear problem is solved by # calling :py:func:`solver.solve(problem,u.vector)<dolfinx.cpp.NewtonSolver.solve>`, # with the new solution vector returned in :py:func:`u.vector<dolfinx.cpp.Function.vector>`. # The solution vector associated with ``u`` is copied to ``u0`` at the # end of each time step, and the ``c`` component of the solution # (the first component of ``u``) is then written to file.
set_output_file("viscoTrialrunW.log") num_its, converged = solver.solve( u) # already scatters `u` to ghost processes u.x.scatter_forward() dl_interp(CC, C) k_terms(dt, C, Cn, Cvn, C_quart, C_half, C_thr_quart, CCv, k_cache) with del_Cv.vector.localForm() as loc: loc.set(0.0) del_Cv.vector.axpy(1.0, CCv.vector - Cv_iter.vector) norm_delCv = del_Cv.x.norm() print(f"Staggered Iteration: {itr+1}, norm_deCv: {norm_delCv:.5e}") print(f"Newton iterations: {num_its}, Converged: {converged}") itr += 1 C.vector.copy(result=Cn.vector) # assign Cn <-- C CCv.vector.copy(result=Cvn.vector) # assign Cvn <-- Cv (converged) norm_Cv = calculate_norm_tensor_function(CCv) print(f"Cv norm is: {norm_Cv:.8e}") svals[i] = fem.assemble_scalar(fem.form(S[0, 0] * dx)) # average stress print(f"stress: {svals[i]:.6e}") with open("sfiles.txt", "a") as fil: fil.write(f"{t:.8f}, {svals[i]:.8f}\n") dl_interp(u, uplot) wfil.write_function(uplot, t=t) plt.plot(stretchVals, svals) plt.savefig("stresses.png") plt.close()
def solve(f0, f1, u, v, dt, num_steps): """Solve problem using the Runge Kutta method""" # Create solution vectors at RK intermediate stages un, vn = u.vector.copy(), v.vector.copy() # Solution at start of time step u0, v0 = u.vector.copy(), v.vector.copy() # Get Runge-Kutta timestepping data n_RK, a_runge, b_runge, c_runge = butcher(4) # Create lists to hold intermediate vectors ku, kv = n_RK * [None], n_RK * [None] file = XDMFFile(MPI.COMM_WORLD, "u.xdmf", "w") file.write_mesh(u.function_space.mesh) file.write_function(u, t=0.0) # print("Num dofs:", u.vector.size) t = 0.0 # loop_start = time.time() for step in range(num_steps): # print("Time step:", step, t, dt) # Store solution at start of time step as u0 and v0 u0 = u.vector.copy(result=u0) v0 = v.vector.copy(result=v0) # Runge Kutta steps, # https://en.wikipedia.org/wiki/Runge%E2%80%93Kutta_methods#Explicit_Runge%E2%80%93Kutta_methods for i in range(n_RK): un = u0.copy(result=un) vn = v0.copy(result=vn) for j in range(i): a = dt * a_runge[i, j] un.axpy(a, ku[j]) vn.axpy(a, kv[j]) # RK evaluation time tn = t + c_runge[i] * dt # Compute RHS vector ku[i] = f0(tn, un, vn, result=ku[i]) kv[i] = f1(tn, un, vn, result=kv[i]) # Update solution u.vector.axpy(dt * b_runge[i], ku[i]) v.vector.axpy(dt * b_runge[i], kv[i]) # Update time t += dt if step % 10 == 0: file.write_function(u, t=t) # print("Norm to file (u):", u.vector.norm()) # end = time.time() # print("RK time:", end - loop_start) # print("RK time per step:", (end - loop_start) / num_steps) return u
grid.point_data["c"] = u.x.array[dofs].real grid.set_active_scalars("c") p = pvqt.BackgroundPlotter(title="concentration", auto_update=True) p.add_mesh(grid, clim=[0, 1]) p.view_xy(True) p.add_text(f"time: {t}", font_size=12, name="timelabel") c = u.sub(0) u0.x.array[:] = u.x.array while (t < T): t += dt r = solver.solve(u) print(f"Step {int(t/dt)}: num iterations: {r[0]}") u0.x.array[:] = u.x.array file.write_function(c, t) # Update the plot window if have_pyvista: p.add_text(f"time: {t:.2e}", font_size=12, name="timelabel") grid.point_data["c"] = u.x.array[dofs].real p.app.processEvents() file.close() # Update ghost entries and plot if have_pyvista: u.x.scatter_forward() grid.point_data["c"] = u.x.array[dofs].real screenshot = None if pv.OFF_SCREEN:
def demo_stacked_cubes(outfile: XDMFFile, theta: float, gmsh: bool = True, quad: bool = False, compare: bool = False, res: float = 0.1): log_info( f"Run theta:{theta:.2f}, Quad: {quad}, Gmsh {gmsh}, Res {res:.2e}") celltype = "quadrilateral" if quad else "triangle" if gmsh: mesh, mt = gmsh_2D_stacked(celltype, theta) mesh.name = f"mesh_{celltype}_{theta:.2f}_gmsh" else: mesh_name = "mesh" filename = f"meshes/mesh_{celltype}_{theta:.2f}.xdmf" mesh_2D_dolfin(celltype, theta) with XDMFFile(MPI.COMM_WORLD, filename, "r") as xdmf: mesh = xdmf.read_mesh(name=mesh_name) mesh.name = f"mesh_{celltype}_{theta:.2f}" tdim = mesh.topology.dim fdim = tdim - 1 mesh.topology.create_connectivity(tdim, tdim) mesh.topology.create_connectivity(fdim, tdim) mt = xdmf.read_meshtags(mesh, name="facet_tags") # Helper until meshtags can be read in from xdmf V = VectorFunctionSpace(mesh, ("Lagrange", 1)) r_matrix = rotation_matrix([0, 0, 1], theta) g_vec = np.dot(r_matrix, [0, -1.25e2, 0]) g = Constant(mesh, PETSc.ScalarType(g_vec[:2])) def bottom_corner(x): return np.isclose(x, [[0], [0], [0]]).all(axis=0) # Fix bottom corner bc_value = np.array((0, ) * mesh.geometry.dim, dtype=PETSc.ScalarType) bottom_dofs = locate_dofs_geometrical(V, bottom_corner) bc_bottom = dirichletbc(bc_value, bottom_dofs, V) bcs = [bc_bottom] # Elasticity parameters E = PETSc.ScalarType(1.0e3) nu = 0 mu = Constant(mesh, E / (2.0 * (1.0 + nu))) lmbda = Constant(mesh, E * nu / ((1.0 + nu) * (1.0 - 2.0 * nu))) # Stress computation def sigma(v): return (2.0 * mu * sym(grad(v)) + lmbda * tr(sym(grad(v))) * Identity(len(v))) # Define variational problem u = TrialFunction(V) v = TestFunction(V) a = inner(sigma(u), grad(v)) * dx ds = Measure("ds", domain=mesh, subdomain_data=mt, subdomain_id=3) rhs = inner(Constant(mesh, PETSc.ScalarType( (0, 0))), v) * dx + inner(g, v) * ds def left_corner(x): return np.isclose(x.T, np.dot(r_matrix, [0, 2, 0])).all(axis=1) # Create multi point constraint mpc = MultiPointConstraint(V) with Timer("~Contact: Create contact constraint"): nh = create_normal_approximation(V, mt, 4) mpc.create_contact_slip_condition(mt, 4, 9, nh) with Timer("~Contact: Add non-slip condition at bottom interface"): bottom_normal = facet_normal_approximation(V, mt, 5) mpc.create_slip_constraint(V, (mt, 5), bottom_normal, bcs=bcs) with Timer("~Contact: Add tangential constraint at one point"): vertex = locate_entities_boundary(mesh, 0, left_corner) tangent = facet_normal_approximation(V, mt, 3, tangent=True) mtv = meshtags(mesh, 0, vertex, np.full(len(vertex), 6, dtype=np.int32)) mpc.create_slip_constraint(V, (mtv, 6), tangent, bcs=bcs) mpc.finalize() rtol = 1e-9 petsc_options = { "ksp_rtol": 1e-9, "pc_type": "gamg", "pc_gamg_type": "agg", "pc_gamg_square_graph": 2, "pc_gamg_threshold": 0.02, "pc_gamg_coarse_eq_limit": 1000, "pc_gamg_sym_graph": True, "mg_levels_ksp_type": "chebyshev", "mg_levels_pc_type": "jacobi", "mg_levels_esteig_ksp_type": "cg" # , "help": None, "ksp_view": None } # Solve Linear problem problem = LinearProblem(a, rhs, mpc, bcs=bcs, petsc_options=petsc_options) # Build near nullspace null_space = rigid_motions_nullspace(mpc.function_space) problem.A.setNearNullSpace(null_space) u_h = problem.solve() it = problem.solver.getIterationNumber() if MPI.COMM_WORLD.rank == 0: print("Number of iterations: {0:d}".format(it)) unorm = u_h.vector.norm() if MPI.COMM_WORLD.rank == 0: print(f"Norm of u: {unorm}") # Write solution to file ext = "_gmsh" if gmsh else "" u_h.name = "u_mpc_{0:s}_{1:.2f}{2:s}".format(celltype, theta, ext) outfile.write_mesh(mesh) outfile.write_function(u_h, 0.0, f"Xdmf/Domain/Grid[@Name='{mesh.name}'][1]") # Solve the MPC problem using a global transformation matrix # and numpy solvers to get reference values if not compare: return log_info("Solving reference problem with global matrix (using numpy)") with Timer("~MPC: Reference problem"): # Generate reference matrices and unconstrained solution A_org = assemble_matrix(form(a), bcs) A_org.assemble() L_org = assemble_vector(form(rhs)) apply_lifting(L_org, [form(a)], [bcs]) L_org.ghostUpdate(addv=PETSc.InsertMode.ADD_VALUES, mode=PETSc.ScatterMode.REVERSE) set_bc(L_org, bcs) root = 0 with Timer("~MPC: Verification"): compare_mpc_lhs(A_org, problem.A, mpc, root=root) compare_mpc_rhs(L_org, problem.b, mpc, root=root) # Gather LHS, RHS and solution on one process A_csr = gather_PETScMatrix(A_org, root=root) K = gather_transformation_matrix(mpc, root=root) L_np = gather_PETScVector(L_org, root=root) u_mpc = gather_PETScVector(u_h.vector, root=root) if MPI.COMM_WORLD.rank == root: KTAK = K.T * A_csr * K reduced_L = K.T @ L_np # Solve linear system d = scipy.sparse.linalg.spsolve(KTAK, reduced_L) # Back substitution to full solution vector uh_numpy = K @ d assert np.allclose(uh_numpy, u_mpc, rtol=rtol)
def demo_stacked_cubes(outfile: XDMFFile, theta: float, gmsh: bool = False, ct: CellType = CellType.tetrahedron, compare: bool = True, res: float = 0.1, noslip: bool = False): celltype = "hexahedron" if ct == CellType.hexahedron else "tetrahedron" type_ext = "no_slip" if noslip else "slip" mesh_ext = "_gmsh_" if gmsh else "_" log_info(f"Run theta:{theta:.2f}, Cell: {celltype}, GMSH {gmsh}, Noslip: {noslip}") # Read in mesh if gmsh: mesh, mt = gmsh_3D_stacked(celltype, theta, res) tdim = mesh.topology.dim fdim = tdim - 1 mesh.topology.create_connectivity(tdim, tdim) mesh.topology.create_connectivity(fdim, tdim) else: mesh_3D_dolfin(theta, ct, celltype, res) MPI.COMM_WORLD.barrier() with XDMFFile(MPI.COMM_WORLD, f"meshes/mesh_{celltype}_{theta:.2f}.xdmf", "r") as xdmf: mesh = xdmf.read_mesh(name="mesh") tdim = mesh.topology.dim fdim = tdim - 1 mesh.topology.create_connectivity(tdim, tdim) mesh.topology.create_connectivity(fdim, tdim) mt = xdmf.read_meshtags(mesh, "facet_tags") mesh.name = f"mesh_{celltype}_{theta:.2f}{type_ext}{mesh_ext}" # Create functionspaces V = fem.VectorFunctionSpace(mesh, ("Lagrange", 1)) # Define boundary conditions # Bottom boundary is fixed in all directions bottom_dofs = fem.locate_dofs_topological(V, fdim, mt.find(5)) # type: ignore u_bc = np.array((0, ) * mesh.geometry.dim, dtype=PETSc.ScalarType) bc_bottom = fem.dirichletbc(u_bc, bottom_dofs, V) g_vec = np.array([0, 0, -4.25e-1], dtype=PETSc.ScalarType) if not noslip: # Helper for orienting traction r_matrix = rotation_matrix([1 / np.sqrt(2), 1 / np.sqrt(2), 0], -theta) # Top boundary has a given deformation normal to the interface g_vec = np.dot(r_matrix, g_vec) top_dofs = fem.locate_dofs_topological(V, fdim, mt.find(3)) # type: ignore bc_top = fem.dirichletbc(g_vec, top_dofs, V) bcs = [bc_bottom, bc_top] # Elasticity parameters E = PETSc.ScalarType(1.0e3) nu = 0 mu = fem.Constant(mesh, E / (2.0 * (1.0 + nu))) lmbda = fem.Constant(mesh, E * nu / ((1.0 + nu) * (1.0 - 2.0 * nu))) # Stress computation def sigma(v): return (2.0 * mu * sym(grad(v)) + lmbda * tr(sym(grad(v))) * Identity(len(v))) # Define variational problem u = TrialFunction(V) v = TestFunction(V) a = inner(sigma(u), grad(v)) * dx # NOTE: Traction deactivated until we have a way of fixing nullspace # g = fem.Constant(mesh, PETSc.ScalarType(g_vec)) # ds = Measure("ds", domain=mesh, subdomain_data=mt, subdomain_id=3) rhs = inner(fem.Constant(mesh, PETSc.ScalarType((0, 0, 0))), v) * dx # + inner(g, v) * ds bilinear_form = fem.form(a) linear_form = fem.form(rhs) mpc = MultiPointConstraint(V) if noslip: with Timer("~~Contact: Create non-elastic constraint"): mpc.create_contact_inelastic_condition(mt, 4, 9) else: with Timer("~Contact: Create contact constraint"): nh = create_normal_approximation(V, mt, 4) mpc.create_contact_slip_condition(mt, 4, 9, nh) with Timer("~~Contact: Add data and finialize MPC"): mpc.finalize() # Create null-space null_space = rigid_motions_nullspace(mpc.function_space) num_dofs = V.dofmap.index_map.size_global * V.dofmap.index_map_bs with Timer(f"~~Contact: Assemble matrix ({num_dofs})"): A = assemble_matrix(bilinear_form, mpc, bcs=bcs) with Timer(f"~~Contact: Assemble vector ({num_dofs})"): b = assemble_vector(linear_form, mpc) apply_lifting(b, [bilinear_form], [bcs], mpc) b.ghostUpdate(addv=PETSc.InsertMode.ADD_VALUES, mode=PETSc.ScatterMode.REVERSE) fem.petsc.set_bc(b, bcs) # Solve Linear problem opts = PETSc.Options() opts["ksp_rtol"] = 1.0e-8 opts["pc_type"] = "gamg" opts["pc_gamg_type"] = "agg" opts["pc_gamg_coarse_eq_limit"] = 1000 opts["pc_gamg_sym_graph"] = True opts["mg_levels_ksp_type"] = "chebyshev" opts["mg_levels_pc_type"] = "jacobi" opts["mg_levels_esteig_ksp_type"] = "cg" opts["matptap_via"] = "scalable" # opts["pc_gamg_square_graph"] = 2 # opts["pc_gamg_threshold"] = 1e-2 # opts["help"] = None # List all available options # opts["ksp_view"] = None # List progress of solver # Create functionspace and build near nullspace A.setNearNullSpace(null_space) solver = PETSc.KSP().create(mesh.comm) solver.setOperators(A) solver.setFromOptions() u_h = fem.Function(mpc.function_space) with Timer("~~Contact: Solve"): solver.solve(b, u_h.vector) u_h.x.scatter_forward() with Timer("~~Contact: Backsubstitution"): mpc.backsubstitution(u_h.vector) it = solver.getIterationNumber() unorm = u_h.vector.norm() num_slaves = MPI.COMM_WORLD.allreduce(mpc.num_local_slaves, op=MPI.SUM) if mesh.comm.rank == 0: num_dofs = V.dofmap.index_map.size_global * V.dofmap.index_map_bs print(f"Number of dofs: {num_dofs}") print(f"Number of slaves: {num_slaves}") print(f"Number of iterations: {it}") print(f"Norm of u {unorm:.5e}") # Write solution to file u_h.name = f"u_{celltype}_{theta:.2f}{mesh_ext}{type_ext}".format(celltype, theta, type_ext, mesh_ext) outfile.write_mesh(mesh) outfile.write_function(u_h, 0.0, f"Xdmf/Domain/Grid[@Name='{mesh.name}'][1]") # Solve the MPC problem using a global transformation matrix # and numpy solvers to get reference values if not compare: return log_info("Solving reference problem with global matrix (using scipy)") with Timer("~~Contact: Reference problem"): A_org = fem.petsc.assemble_matrix(bilinear_form, bcs) A_org.assemble() L_org = fem.petsc.assemble_vector(linear_form) fem.petsc.apply_lifting(L_org, [bilinear_form], [bcs]) L_org.ghostUpdate(addv=PETSc.InsertMode.ADD_VALUES, mode=PETSc.ScatterMode.REVERSE) fem.petsc.set_bc(L_org, bcs) root = 0 with Timer("~~Contact: Compare LHS, RHS and solution"): compare_mpc_lhs(A_org, A, mpc, root=root) compare_mpc_rhs(L_org, b, mpc, root=root) # Gather LHS, RHS and solution on one process A_csr = gather_PETScMatrix(A_org, root=root) K = gather_transformation_matrix(mpc, root=root) L_np = gather_PETScVector(L_org, root=root) u_mpc = gather_PETScVector(u_h.vector, root=root) if MPI.COMM_WORLD.rank == root: KTAK = K.T * A_csr * K reduced_L = K.T @ L_np # Solve linear system d = scipy.sparse.linalg.spsolve(KTAK, reduced_L) # Back substitution to full solution vector uh_numpy = K @ d assert np.allclose(uh_numpy, u_mpc) list_timings(mesh.comm, [TimingType.wall])
opts[k] = v opts.prefixPop() solver.setFromOptions() with Timer("~PERIODIC: Assemble and solve MPC problem"): uh = problem.solve() # solver.view() it = solver.getIterationNumber() print("Constrained solver iterations {0:d}".format(it)) # Write solution to file uh.name = "u_mpc" outfile = XDMFFile(MPI.COMM_WORLD, "results/demo_periodic_geometrical.xdmf", "w") outfile.write_mesh(mesh) outfile.write_function(uh) print("----Verification----") # --------------------VERIFICATION------------------------- bilinear_form = fem.form(a) A_org = fem.petsc.assemble_matrix(bilinear_form, bcs) A_org.assemble() linear_form = fem.form(rhs) L_org = fem.petsc.assemble_vector(linear_form) fem.petsc.apply_lifting(L_org, [bilinear_form], [bcs]) L_org.ghostUpdate(addv=PETSc.InsertMode.ADD_VALUES, mode=PETSc.ScatterMode.REVERSE) fem.petsc.set_bc(L_org, bcs) solver.setOperators(A_org) u_ = fem.Function(V)