snes = PETSc.SNES().create(comm) snes.setFunction(form_function, F) snes.setJacobian(form_jacobian, J, P) # P is the preconditioner of J snes.setFromOptions() snes.solve(None, x) # `snes.solve(b, x)`: # b: The affine right-hand side or `None` to use zero. # x: The starting vector or `None` to use the vector stored internally.
import sys, petsc4py petsc4py.init(sys.argv) from petsc4py import PETSc import numpy as np SNES_REASONS = { v: k for k, v invars(PETSc.SNES.ConvergedReason).items() ifisinstance(v, int) } comm = PETSc.COMM_WORLD opt = PETSc.Options()
jac_type = opt.getString("jac_type", "analytic") nx = opt.getInt("nx", 50) ny = opt.getInt("ny", 50) N = nx * ny hx = 1.0 / (nx - 1) hy = 1.0 / (ny - 1)
defform_function(snes, X, F): # compute F = A*X - R ctx = snes.getApplicationContext() A, R = ctx["A"], ctx["R"] A.mult(X, F) # F = A * X F.axpy(-1.0, R) # F = F - R
defform_jacobian(snes, X, J, P): # compute J and P (P=J) ctx = snes.getApplicationContext() A = ctx["A"]
# copy A to P if P.handle != A.handle: A.copy(P, structure=PETSc.Mat.Structure.SAME_NONZERO_PATTERN) P.assemble() # copy A to J if J.handle != P.handle and J.handle != A.handle: if J.getType() != "mffd": # JFNK A.copy(J, structure=PETSc.Mat.Structure.SAME_NONZERO_PATTERN) J.assemble()
# create matrix A A = PETSc.Mat().createAIJ(size=(N, N), comm=comm) A.setFromOptions() A.setPreallocationNNZ(5) # 5-point stencil A.setUp()
rstart, rend = A.getOwnershipRange() cstart, cend = A.getOwnershipRangeColumn()
# solve F(X)=0 X = A.createVecRight() # F(X) = A*X - R X.set(0.0) snes.solve(None, X) # `None` stands for `0` in `F(X)=0`
if jac_type == "color": # output the coloring info func_calls = snes.getFunctionEvaluations() PETSc.Sys.Print(f"SNES form_function calls = {func_calls}") # or use `-mat_coloring_view` to see the coloring info
# compute exact solution U_ex = A.createVecRight() with U_ex as ue_arr: for col inrange(cstart, cend): i, j = get_coords(col, nx) ue_arr[col - cstart] = exact_u(i * hx, j * hy) U_ex.assemble()