def main(n): '''Solves grad-div problem in 2d with HypreAMS preconditioning''' # Exact solution x, y = sp.symbols('x[0] x[1]') sigma = sp.Matrix([sp.cos(pi * y**2), sp.sin(pi * x**2)]) sp_div = lambda f: f[0].diff(x, 1) + f[1].diff(y, 1) sp_grad = lambda f: sp.Matrix([f.diff(x, 1), f.diff(y, 1)]) f = -sp_grad(sp_div(sigma)) + sigma sigma_expr, f_expr = map(as_expression, (sigma, f)) # The discrete problem mesh = UnitSquareMesh(n, n) V = FunctionSpace(mesh, 'RT', 1) u, v = TrialFunction(V), TestFunction(V) a = inner(div(u), div(v)) * dx + inner(u, v) * dx L = inner(f_expr, v) * dx A, b = assemble_system(a, L) # Solve Q = FunctionSpace(mesh, 'CG', 1) G = DiscreteOperators.build_gradient(V, Q) ksp = PETSc.KSP().create(PETSc.COMM_WORLD) ksp.setType('cg') ksp.setTolerances(rtol=1E-8, atol=1E-12, divtol=1.0E10, max_it=300) opts = PETSc.Options() opts.setValue("ksp_monitor_true_residual", None) ksp.setFromOptions() # AMS preconditioner pc = ksp.getPC() pc.setType('hypre') pc.setHYPREType('ams') vec = lambda x: as_backend_type(x).vec() mat = lambda A: as_backend_type(A).mat() # Attach gradient pc.setHYPREDiscreteGradient(mat(G)) # Constant nullspace (in case not mass and bcs) constants = [ vec(interpolate(c, V).vector()) for c in (Constant((1, 0)), Constant((0, 1))) ] pc.setHYPRESetEdgeConstantVectors(*constants) # NOTE: term mass term is accounted for automatically by Hypre # unless pc.setPoissonBetaMatrix(None) # Set operator for the linear solver ksp.setOperators(mat(A)) uh = Function(V) ksp.solve(vec(b), vec(uh.vector())) niters = ksp.getIterationNumber() error = errornorm(sigma_expr, uh, 'Hdiv', degree_rise=1) hmin = mesh.mpi_comm().tompi4py().allreduce(mesh.hmin(), pyMPI.MIN) return hmin, V.dim(), niters, error
uu = Function(W) tic() AA, bb = assemble_system(a, L1 - RHSform, bcs) A, b = CP.Assemble(AA, bb) print toc() print A # b = b.getSubVector(t_is) PP = assemble(prec) bcc.apply(PP) P = CP.Assemble(PP) b = bb.array() zeros = 0 * b bb = IO.arrayToVec(b) x = IO.arrayToVec(zeros) ksp = PETSc.KSP() ksp.create(comm=PETSc.COMM_WORLD) # ksp.setTolerances(1e-5) ksp.setType('preonly') pc = ksp.getPC() pc.setType(PETSc.PC.Type.LU) # if Solver == "LSC": # pc.setPythonContext(NSprecond.LSCnew(W,A,L,Bd,dBt)) # elif Solver == "PCD": # F = assemble(fp) # F = CP.Assemble(F) # pc.setPythonContext(NSprecond.PCD(W, A, Mass, F, L)) ksp.setOperators(A) OptDB = PETSc.Options()
def solve_GenEO_eigmin(self, V0s, tauGenEO_eigmin): """ Solves the local GenEO eigenvalue problem related to the smallest eigenvalue eigmin. Parameters ========== V0s : list of local PETSc .vecs V0s may already contain some local coarse vectors. This routine will possibly add more vectors to the list. tauGenEO_eigmin: Real. Threshold for selecting eigenvectors for the coarse space. """ if tauGenEO_eigmin > 0: #to compute the smallest eigenvalues of the preconditioned matrix, Ms must be factorized tempksp = PETSc.KSP().create(comm=PETSc.COMM_SELF) tempksp.setOperators(self.Ms) tempksp.setType('preonly') temppc = tempksp.getPC() temppc.setType('cholesky') temppc.setFactorSolverType('mumps') temppc.setFactorSetUpSolverType() tempF = temppc.getFactorMatrix() tempF.setMumpsIcntl(7, 2) tempF.setMumpsIcntl(24, 1) tempF.setMumpsCntl(3, self.mumpsCntl3) temppc.setUp() tempnrb = tempF.getMumpsInfog(28) for i in range(tempnrb): tempF.setMumpsIcntl(25, i + 1) self.works.set(0.) tempksp.solve(self.works, self.works) V0s.append(self.works.copy()) tempF.setMumpsIcntl(25, 0) if self.verbose: PETSc.Sys.Print( 'Subdomain number {} contributes {} coarse vectors as zero energy modes of the scaled local operator (in GenEO for eigmin)' .format(mpi.COMM_WORLD.rank, tempnrb), comm=self.comm) #Eigenvalue Problem for smallest eigenvalues eps = SLEPc.EPS().create(comm=PETSc.COMM_SELF) eps.setDimensions(nev=self.nev) eps.setProblemType(SLEPc.EPS.ProblemType.GHIEP) eps.setOperators(self.Ms, self.Atildes) eps.setWhichEigenpairs(SLEPc.EPS.Which.TARGET_REAL) eps.setTarget(0.) ST = eps.getST() ST.setType("sinvert") ST.setKSP(tempksp) if len(V0s) > 0: eps.setDeflationSpace(V0s) eps.solve() if eps.getConverged() < self.nev: PETSc.Sys.Print( 'WARNING: Only {} eigenvalues converged for GenEO_eigmin in subdomain {} whereas {} were requested' .format(eps.getConverged(), mpi.COMM_WORLD.rank, self.nev), comm=self.comm) for i in range(min(eps.getConverged(), self.maxev)): if (abs(eps.getEigenvalue(i)) < tauGenEO_eigmin ): #TODO tell slepc that the eigenvalues are real V0s.append(self.works.duplicate()) eps.getEigenvector(i, V0s[-1]) if self.verbose: PETSc.Sys.Print( 'GenEO eigenvalue number {} for lambdamin in subdomain {}: {}' .format(i, mpi.COMM_WORLD.rank, eps.getEigenvalue(i)), comm=self.comm) else: if self.verbose: PETSc.Sys.Print( 'GenEO eigenvalue number {} for lambdamin in subdomain {}: {} <-- not selected (> {})' .format(i, mpi.COMM_WORLD.rank, eps.getEigenvalue(i), tauGenEO_eigmin), comm=self.comm) self.eps_eigmin = eps #the only reason for this line is to make sure self.ksp_Atildes and hence PCBNN.ksp is not destroyed
def __init__(self, cfgfile): ''' Constructor ''' # load run config file cfg = Config(cfgfile) # timestep setup self.ht = cfg['grid']['ht'] # timestep size self.nt = cfg['grid']['nt'] # number of timesteps self.nsave = cfg['io']['nsave'] # save only every nsave'th timestep # grid setup nx = cfg['grid']['nx'] # number of points in x ny = cfg['grid']['ny'] # number of points in y Lx = cfg['grid']['Lx'] # spatial domain in x x1 = cfg['grid']['x1'] # x2 = cfg['grid']['x2'] # Ly = cfg['grid']['Ly'] # spatial domain in y y1 = cfg['grid']['y1'] # y2 = cfg['grid']['y2'] # if x1 != x2: Lx = x2 - x1 else: x1 = 0.0 x2 = Lx if y1 != y2: Ly = y2 - y1 else: y1 = 0.0 y2 = Ly self.hx = Lx / nx # gridstep size in x self.hy = Ly / ny # gridstep size in y self.time = PETSc.Vec().createMPI(1, PETSc.DECIDE, comm=PETSc.COMM_WORLD) self.time.setName('t') if PETSc.COMM_WORLD.getRank() == 0: self.time.setValue(0, 0.0) # set some PETSc options OptDB = PETSc.Options() OptDB.setValue('ksp_rtol', cfg['solver']['petsc_residual']) # OptDB.setValue('ksp_max_it', 100) OptDB.setValue('ksp_max_it', 200) # OptDB.setValue('ksp_max_it', 1000) # OptDB.setValue('ksp_max_it', 2000) # OptDB.setValue('ksp_monitor', '') # OptDB.setValue('log_info', '') # OptDB.setValue('log_summary', '') # create DA with single dof self.da1 = PETSc.DA().create(dim=2, dof=1, sizes=[nx, ny], proc_sizes=[PETSc.DECIDE, PETSc.DECIDE], boundary_type=('periodic', 'periodic'), stencil_width=1, stencil_type='box') # create DA (dof = 5 for Bx, By, Vx, Vy, P) self.da4 = PETSc.DA().create(dim=2, dof=5, sizes=[nx, ny], proc_sizes=[PETSc.DECIDE, PETSc.DECIDE], boundary_type=('periodic', 'periodic'), stencil_width=1, stencil_type='box') # create DA for x grid self.dax = PETSc.DA().create(dim=1, dof=1, sizes=[nx], proc_sizes=[PETSc.DECIDE], boundary_type=('periodic')) # create DA for y grid self.day = PETSc.DA().create(dim=1, dof=1, sizes=[ny], proc_sizes=[PETSc.DECIDE], boundary_type=('periodic')) # initialise grid self.da1.setUniformCoordinates(xmin=x1, xmax=x2, ymin=y1, ymax=y2) self.da4.setUniformCoordinates(xmin=x1, xmax=x2, ymin=y1, ymax=y2) self.dax.setUniformCoordinates(xmin=x1, xmax=x2) self.day.setUniformCoordinates(xmin=y1, xmax=y2) # create solution and RHS vector self.dx = self.da4.createGlobalVec() self.x = self.da4.createGlobalVec() self.b = self.da4.createGlobalVec() self.Pb = self.da1.createGlobalVec() self.localX = self.da4.createLocalVec() # create global RK4 vectors self.X1 = self.da4.createGlobalVec() self.X2 = self.da4.createGlobalVec() self.X3 = self.da4.createGlobalVec() self.X4 = self.da4.createGlobalVec() # create local RK4 vectors self.localX1 = self.da4.createLocalVec() self.localX2 = self.da4.createLocalVec() self.localX3 = self.da4.createLocalVec() self.localX4 = self.da4.createLocalVec() # create vectors for magnetic and velocity field self.Bx = self.da1.createGlobalVec() self.By = self.da1.createGlobalVec() self.Vx = self.da1.createGlobalVec() self.Vy = self.da1.createGlobalVec() self.P = self.da1.createGlobalVec() # set variable names self.x.setName('solver_x') self.b.setName('solver_b') self.Bx.setName('Bx') self.By.setName('By') self.Vx.setName('Vx') self.Vy.setName('Vy') self.P.setName('P') # create Matrix object self.petsc_matrix = PETScSolver(self.da1, self.da4, nx, ny, self.ht, self.hx, self.hy) self.petsc_function = PETScFunction(self.da1, self.da4, nx, ny, self.ht, self.hx, self.hy) self.petsc_jacobian = PETScJacobian(self.da1, self.da4, nx, ny, self.ht, self.hx, self.hy) # create sparse matrix self.J = PETSc.Mat().createPython( [self.dx.getSizes(), self.b.getSizes()], comm=PETSc.COMM_WORLD) self.J.setPythonContext(self.petsc_jacobian) self.J.setUp() # create linear solver and preconditioner self.ksp = PETSc.KSP().create() self.ksp.setFromOptions() self.ksp.setOperators(self.J) self.ksp.setType(cfg['solver']['petsc_ksp_type']) self.ksp.setInitialGuessNonzero(True) self.pc = self.ksp.getPC() self.pc.setType(cfg['solver']['petsc_pc_type']) # create Preconditioner matrix and solver self.pc_mat = PETScPreconditioner(self.da1, self.da4, self.P, nx, ny, self.ht, self.hx, self.hy) # create sparse matrix self.pc_A = PETSc.Mat().createPython( [self.x.getSizes(), self.b.getSizes()], comm=PETSc.COMM_WORLD) self.pc_A.setPythonContext(self.pc_mat) self.pc_A.setUp() # create linear solver and preconditioner self.pc_ksp = PETSc.KSP().create() self.pc_ksp.setFromOptions() self.pc_ksp.setOperators(self.pc_A) self.pc_ksp.setType(cfg['solver']['petsc_ksp_type']) self.pc_ksp.setInitialGuessNonzero(True) self.pc_pc = self.pc_ksp.getPC() self.pc_pc.setType('none') # create Poisson matrix and solver self.poisson_mat = PETScPoissonSolver(self.da1, self.da4, self.x, nx, ny, self.ht, self.hx, self.hy) self.poisson_A = PETSc.Mat().createPython( [self.P.getSizes(), self.Pb.getSizes()], comm=PETSc.COMM_WORLD) self.poisson_A.setPythonContext(self.poisson_mat) self.poisson_A.setUp() self.poisson_ksp = PETSc.KSP().create() self.poisson_ksp.setFromOptions() self.poisson_ksp.setOperators(self.poisson_A) self.poisson_ksp.setType(cfg['solver']['petsc_ksp_type']) # self.poisson_ksp.setInitialGuessNonzero(True) self.poisson_pc = self.poisson_ksp.getPC() self.poisson_pc.setType('none') # create Arakawa solver object # self.mhd_rk4 = PETScRK4(self.da4, nx, ny, self.ht, self.hx, self.hy) # set initial data (xs, xe), (ys, ye) = self.da1.getRanges() coords = self.da1.getCoordinateDA().getVecArray( self.da1.getCoordinates()) # print # print(self.hx) # print(coords[1,0][0] - coords[0,0][0]) # print # print(self.hy) # print(coords[0,1][1] - coords[0,0][1]) # print # print(Lx) # print(coords[-1,0][0]+self.hx) # print # print(Ly) # print(coords[0,-1][1]+self.hy) # print x_arr = self.da4.getVecArray(self.x) Bx_arr = self.da1.getVecArray(self.Bx) By_arr = self.da1.getVecArray(self.By) Vx_arr = self.da1.getVecArray(self.Vx) Vy_arr = self.da1.getVecArray(self.Vy) # P_arr = self.da1.getVecArray(self.P) if cfg['initial_data']['magnetic_python'] != None: init_data = __import__( "runs." + cfg['initial_data']['magnetic_python'], globals(), locals(), ['magnetic_x', 'magnetic_y'], 0) for i in range(xs, xe): for j in range(ys, ye): Bx_arr[i, j] = init_data.magnetic_x(coords[i, j][0], coords[i, j][1], Lx, Ly) By_arr[i, j] = init_data.magnetic_y(coords[i, j][0], coords[i, j][1], Lx, Ly) else: Bx_arr[xs:xe, ys:ye] = cfg['initial_data']['magnetic'] By_arr[xs:xe, ys:ye] = cfg['initial_data']['magnetic'] if cfg['initial_data']['velocity_python'] != None: init_data = __import__( "runs." + cfg['initial_data']['velocity_python'], globals(), locals(), ['velocity_x', 'velocity_y'], 0) for i in range(xs, xe): for j in range(ys, ye): Vx_arr[i, j] = init_data.velocity_x(coords[i, j][0], coords[i, j][1], Lx, Ly) Vy_arr[i, j] = init_data.velocity_y(coords[i, j][0], coords[i, j][1], Lx, Ly) else: Vx_arr[xs:xe, ys:ye] = cfg['initial_data']['velocity'] Vy_arr[xs:xe, ys:ye] = cfg['initial_data']['velocity'] # if cfg['initial_data']['pressure_python'] != None: # init_data = __import__("runs." + cfg['initial_data']['pressure_python'], globals(), locals(), ['pressure', ''], 0) # # for i in range(xs, xe): # for j in range(ys, ye): # P_arr[i,j] = init_data.pressure(coords[i,j][0], coords[i,j][1], Lx, Ly) #+ 0.5 * (Bx_arr[i,j]**2 + By_arr[i,j]**2) # copy distribution function to solution vector x_arr[xs:xe, ys:ye, 0] = Bx_arr[xs:xe, ys:ye] x_arr[xs:xe, ys:ye, 1] = By_arr[xs:xe, ys:ye] x_arr[xs:xe, ys:ye, 2] = Vx_arr[xs:xe, ys:ye] x_arr[xs:xe, ys:ye, 3] = Vy_arr[xs:xe, ys:ye] self.petsc_matrix.formRHSPoisson(self.Pb, self.x) self.poisson_ksp.solve(self.Pb, self.P) x_arr = self.da4.getVecArray(self.x) P_arr = self.da1.getVecArray(self.P) x_arr[xs:xe, ys:ye, 4] = P_arr[xs:xe, ys:ye] # update solution history self.petsc_matrix.update_history(self.x) self.petsc_function.update_history(self.x) self.petsc_jacobian.update_history(self.x) # create HDF5 output file self.hdf5_viewer = PETSc.Viewer().createHDF5( cfg['io']['hdf5_output'], mode=PETSc.Viewer.Mode.WRITE, comm=PETSc.COMM_WORLD) self.hdf5_viewer.HDF5PushGroup("/") # write grid data to hdf5 file coords_x = self.dax.getCoordinates() coords_y = self.day.getCoordinates() coords_x.setName('x') coords_y.setName('y') self.hdf5_viewer(coords_x) self.hdf5_viewer(coords_y) # write initial data to hdf5 file self.hdf5_viewer.HDF5SetTimestep(0) self.hdf5_viewer(self.time) # self.hdf5_viewer(self.x) # self.hdf5_viewer(self.b) self.hdf5_viewer(self.Bx) self.hdf5_viewer(self.By) self.hdf5_viewer(self.Vx) self.hdf5_viewer(self.Vy) self.hdf5_viewer(self.P)
def adjoint(self, tao, x, G): dx, dy, dz = self.dx, self.dy, self.dz nx, ny, nz = self.nx, self.ny, self.nz (minX, maxX), (minY, maxY), (minZ, maxZ) = self.mesh.dm.getLocalBoundingBox() k_list, H_list, a_list = np.array_split(x.array[:-1], 3) q0 = x.array[-1] # Unpack vectors onto mesh k0, H, a = self.map(k_list, H_list, a_list) self.mesh.update_properties(k0, H) self.mesh.boundary_condition('maxZ', 298.0, flux=False) self.mesh.boundary_condition('minZ', q0, flux=True) b = self.mesh.construct_rhs() k = [k0] T = [None] error_local = np.array([True]) error_global = np.ones(comm.size, dtype=bool) i = 0 while error_global.any(): self.mesh.update_properties(k[i], H) A = self.mesh.construct_matrix() self.ksp.solve(b._gdata, self.temperature) self.mesh.dm.globalToLocal(self.temperature, self.mesh.lvec) T.append(self.mesh.lvec.array.copy()) k.append(k0*(298.0/T[-1])**a) error_local[0] = np.absolute(k[-1] - k[-2]).max() > 1e-6 comm.Allgather([error_local, MPI.BOOL], [error_global, MPI.BOOL]) i += 1 dT_ad = np.zeros_like(k0) dk_ad = np.zeros_like(k0) dH_ad = np.zeros_like(k0) da_ad = np.zeros_like(k0) dq0_ad = np.array(0.0) dk_list_ad = np.zeros_like(k_list) dH_list_ad = np.zeros_like(H_list) da_list_ad = np.zeros_like(a_list) dq0_list_ad = np.array(0.0) cost = np.array(0.0) sum_cost = np.array(0.0) # Cost observations if self.observation.has_key('q'): obs = self.observation['q'] # Compute heat flux gradTz, gradTy, gradTx = np.gradient(T[-1].reshape(self.mesh.n), *self.mesh.grid_coords[::-1]) heatflux = -k[-1].reshape(self.mesh.n)*(gradTz + gradTy + gradTx) q_interp = heatflux.ravel() if obs[2] is not None: self.interp.values = heatflux q_interp = self.interp(obs[2], method='nearest') cost += self.objective_function(q_interp, obs[0], obs[1], obs[-1]) ## AD ## dcdq = self.objective_function_ad(q_interp, obs[0], obs[1]) dq_ad = dcdq*1.0 if obs[2] is not None: dq_interp_ad = dcdq*1.0 dq_ad = self.interp.adjoint(obs[2], dq_interp_ad, method='nearest').ravel() # print "ad\n", dq_interp_ad self.mesh.lvec.setArray(dq_ad) self.mesh.dm.localToGlobal(self.mesh.lvec, self.mesh.gvec) self.mesh.dm.globalToLocal(self.mesh.gvec, self.mesh.lvec) dq_ad = self.mesh.lvec.array.copy() #/self.ghost_weights # print "dq_interp_ad", dq_ad_interp # print obs[-1] # print "dq_ad\n", dq_ad.min(), dq_ad.mean(), dq_ad.max() # print "dq_ad\n", np.hstack([dq_ad[dq_ad>0].reshape(-1,1), self.mesh.coords[dq_ad>0]]) # print "np.nan", np.where(dq_ad==np.nan) dqdTz = -k[-1]/(nz*dz) dqdTy = -k[-1]/(ny*dy) dqdTx = -k[-1]/(nx*dz) dqdk = -(gradTz + gradTy + gradTx).ravel() dk_ad += dqdk*dq_ad dT_ad += dqdTx*dq_ad + dqdTy*dq_ad + dqdTz*dq_ad # print dT_ad.min(), dT_ad.max() if self.observation.has_key('T'): obs = self.observation['T'] T_interp = T[-1] if obs[2] is not None: self.interp.values = T[-1].reshape(self.mesh.n) T_interp = self.interp(obs[2], method='nearest') cost += self.objective_function(T_interp, obs[0], obs[1], obs[-1]) ## AD ## dcdT = self.objective_function_ad(T_interp, obs[0], obs[1]) dT_ad2 = dcdT*1.0 if obs[2] is not None: dT_interp_ad = dcdT*1.0 dT_ad2 = self.interp.adjoint(obs[2], dq_interp_ad, method='nearest').ravel() self.mesh.lvec.setArray(dT_ad2) self.mesh.dm.localToGlobal(self.mesh.lvec, self.mesh.gvec) self.mesh.dm.globalToLocal(self.mesh.gvec, self.mesh.lvec) dT_ad2 = self.mesh.lvec.array.copy() # print "dT_ad\n", dT_ad2.min(), dT_ad2.mean(), dT_ad2.max() dT_ad += dT_ad2 comm.Allreduce([cost, MPI.DOUBLE], [sum_cost, MPI.DOUBLE], op=MPI.SUM) # Cost priors for key, array, array_ad in [('k', k_list, dk_list_ad), ('H', H_list, dH_list_ad), ('a', a_list, da_list_ad), ('q0', q0, dq0_list_ad)]: if self.prior.has_key(key): prior = self.prior[key] sum_cost += self.objective_function(array, prior[0], prior[1]) ## AD ## dcdp = self.objective_function_ad(array, prior[0], prior[1]) # array_ad += dcdp*1.0 # print "dT", comm.rank, dT_ad # print "dK", comm.rank, dk_ad dk0_ad = np.zeros_like(k0) idx_local = np.array([True]) idx_global = np.ones(comm.size, dtype=bool) idx_lowerBC = self.mesh.bc['minZ']['mask'] idx_upperBC = self.mesh.bc['maxZ']['mask'] kspT = PETSc.KSP().create(comm) kspT.setType('bcgs') kspT.setTolerances(1e-12, 1e-12) kspT.setFromOptions() # kspT.setDM(self.mesh.dm) # pc = kspT.getPC() # pc.setType('gamg') dAdklT = self.mesh.gvec.duplicate() for j in range(i): dkda = np.log(298.0/T[-1-j])*k0*(298.0/T[-1-j])**a dkdk0 = (298.0/T[-1-j])**a dkdT = -a*k0/T[-1-j]*(298.0/T[-1-j])**a dk0_ad += dkdk0*dk_ad dT_ad += dkdT*dk_ad da_ad += dkda*dk_ad dk_ad.fill(0.0) self.mesh.update_properties(k[-1-j], H) self.mesh.boundary_condition('maxZ', 298.0, flux=False) self.mesh.boundary_condition('minZ', q0, flux=True) A = self.mesh.construct_matrix() AT = self.mesh._initialise_matrix() A.transpose(AT) self.mesh.lvec.setArray(dT_ad) self.mesh.dm.localToGlobal(self.mesh.lvec, b._gdata) kspT.setOperators(AT) kspT.solve(b._gdata, self.mesh.gvec) self.mesh.dm.globalToLocal(self.mesh.gvec, self.mesh.lvec) db_ad = self.mesh.lvec.array dH_ad += -db_ad dH_ad[idx_lowerBC] += db_ad[idx_lowerBC]/dy dq0_ad += np.sum(-db_ad[idx_lowerBC]/dy/self.ghost_weights[idx_lowerBC]) A.scale(-1.0) # self.mesh.boundary_condition('maxZ', 0.0, flux=False) # self.mesh.diffusivity.fill(1.0) # dAdkl = self.mesh.construct_matrix(in_place=False, derivative=True) # self.mesh.lvec.setArray(T[-1-j]) # self.mesh.dm.localToGlobal(self.mesh.lvec, self._temperature) # dAdkl.mult(self._temperature, dAdklT) # self.ksp.solve(dAdklT, self.mesh.gvec) # dk_ad += dT_ad.dot(self.mesh.lvec.array) self.mesh.lvec.setArray(T[-1-j]) self.mesh.dm.localToGlobal(self.mesh.lvec, self._temperature) kappa = np.zeros_like(H) for l, lith in enumerate(self.lithology_index): idx = self.lithology == lith idx_dT = dT_ad != 0.0 idx_n = np.logical_and(idx, idx_dT) idx_local[0] = idx_n.any() comm.Allgather([idx_local, MPI.BOOL], [idx_global, MPI.BOOL]) if idx_global.any(): self.mesh.boundary_condition('maxZ', 0.0, flux=False) kappa.fill(0.0) kappa[idx] = 1.0 self.mesh.diffusivity[:] = kappa dAdkl = self.mesh.construct_matrix(in_place=False, derivative=True) # diag = dAdkl.getDiagonal() # diag.array[idx_upperBC] = 0.0 # dAdkl.setDiagonal(diag) dAdkl.mult(self._temperature, dAdklT) self.ksp.setOperators(A) self.ksp.solve(dAdklT, self.mesh.gvec) self.mesh.dm.globalToLocal(self.mesh.gvec, self.mesh.lvec) if idx_local[0]: dk_ad[idx_n] += dT_ad.dot(self.mesh.lvec.array)/idx_n.sum() # print self.mesh.lvec.array.mean(), dk_ad.mean(), dk0_ad.mean(), idx_n.any(), idx_n.sum() dT_ad.fill(0.0) dk0_ad += dk_ad kspT.destroy() dk0_ad /= self.ghost_weights dH_ad /= self.ghost_weights da_ad /= self.ghost_weights for i, index in enumerate(self.lithology_index): idx = self.lithology == index dk_list_ad[i] += dk0_ad[idx].sum() dH_list_ad[i] += dH_ad[idx].sum() da_list_ad[i] += da_ad[idx].sum() sum_dk_list_ad = np.zeros_like(dk_list_ad) sum_dH_list_ad = np.zeros_like(dk_list_ad) sum_da_list_ad = np.zeros_like(dk_list_ad) sum_dq0_ad = np.array(0.0) comm.Allreduce([dk_list_ad, MPI.DOUBLE], [sum_dk_list_ad, MPI.DOUBLE], op=MPI.SUM) comm.Allreduce([dH_list_ad, MPI.DOUBLE], [sum_dH_list_ad, MPI.DOUBLE], op=MPI.SUM) comm.Allreduce([da_list_ad, MPI.DOUBLE], [sum_da_list_ad, MPI.DOUBLE], op=MPI.SUM) comm.Allreduce([dq0_ad, MPI.DOUBLE], [sum_dq0_ad, MPI.DOUBLE], op=MPI.SUM) dq0_list_ad += sum_dq0_ad # Procs have unique lithololgy, need to communicate the gradients after vectors are all been packed up # I think these fellows ought to have their prior sensitivities added at the end since these are global. # for i, index in enumerate(self.lithology_index): # idx = self.lithology == index # dk_list_ad[i] += sum_dk0_ad[idx].sum() # dH_list_ad[i] += sum_dH_ad[idx].sum() # da_list_ad[i] += sum_da_ad[idx].sum() # procs should have their part of the sensitivities summed. Even if this doesn't result in any difference, # performance should be improved by communicating smaller arrays for key, array, array_ad in [('k', k_list, sum_dk_list_ad), ('H', H_list, sum_dH_list_ad), ('a', a_list, sum_da_list_ad), ('q0', q0, sum_dq0_ad)]: if key in self.prior: prior = self.prior[key] array_ad += self.objective_function_ad(array, prior[0], prior[1]) G.setArray(np.concatenate([sum_dk_list_ad, sum_dH_list_ad, sum_da_list_ad, [sum_dq0_ad]])) print("cost = {}".format(sum_cost)) return sum_cost
metric=Metric) PDE.assembly() PDE.solve() # getting scipy matrix A_scipy = PDE.system.get() PDE.system.save("sys.mtx") b = np.ones(PDE.size) A = PETSc.Mat().createAIJ(size=A_scipy.shape, csr=(A_scipy.indptr, A_scipy.indices, A_scipy.data)) # ... # Initialize ksp solver. ksp = PETSc.KSP().create() ksp.setOperators(A) pc = ksp.getPC() # Allow for solver choice to be set from command line with -ksp_type <solver>. # Recommended option: -ksp_type preonly -pc_type lu ksp.setFromOptions() ksptype = PETSc.KSP.Type.CG pctype = None #ksptype = PETSc.KSP.Type.GMRES ; pctype = None #ksptype = PETSc.KSP.Type.BICG ; pctype = None #ksptype = PETSc.KSP.Type.BCGS ; pctype = None #ksptype = PETSc.KSP.Type.BCGSL ; pctype = None #ksptype = PETSc.KSP.Type.CGS ; pctype = None #ksptype = PETSc.KSP.Type.STCG ; pctype = None
def solve(A, b, u, IS, Fspace, IterType, OuterTol, InnerTol, HiptmairMatrices, KSPlinearfluids, kspF, Fp, MatrixLinearFluids, kspFp): if IterType == "Full": ksp = PETSc.KSP().create() ksp.setTolerances(OuterTol) ksp.setType('fgmres') u_is = PETSc.IS().createGeneral(range(Fspace[0].dim())) p_is = PETSc.IS().createGeneral( range(Fspace[0].dim(), Fspace[0].dim() + Fspace[1].dim())) b_is = PETSc.IS().createGeneral( range(Fspace[0].dim() + Fspace[1].dim(), Fspace[0].dim() + Fspace[1].dim() + Fspace[2].dim())) Bt = A.getSubMatrix(u_is, p_is) C = A.getSubMatrix(u_is, b_is) reshist = {} def monitor(ksp, its, fgnorm): reshist[its] = fgnorm # print "------------------------->>>> ", ksp.buildResidual().array print "OUTER:", fgnorm return ksp.buildResidual().array ksp.setMonitor(monitor) pc = ksp.getPC() pc.setType(PETSc.PC.Type.KSP) ksp.setOperators(A) reshist1 = {} def monitor(ksp, its, fgnorm): reshist1[its] = fgnorm print "INNER:", fgnorm # ksp.setMonitor(monitor) pc = ksp.getPC() pc.setType(PETSc.PC.Type.PYTHON) pc.setPythonContext( MHDstabPrecond.Test(Fspace, kspF, KSPlinearfluids[0], KSPlinearfluids[1], Fp, HiptmairMatrices[3], HiptmairMatrices[4], HiptmairMatrices[2], HiptmairMatrices[0], HiptmairMatrices[1], HiptmairMatrices[6], 1e-3, Bt, C)) # PP = PETSc.Mat().createPython([A.size[0], A.size[0]]) # PP.setType('python') # p = PrecondMulti.MultiApply(Fspace,A,HiptmairMatrices[6],MatrixLinearFluids[1],MatrixLinearFluids[0],kspFp, HiptmairMatrices[3]) tic() scale = b.norm() b = b / scale print b.norm() ksp.solve(b, u) u = u * scale print toc() # print s.getvalue() NSits = ksp.its del ksp # print u.array return u, NSits, 1 NS_is = IS[0] M_is = IS[1] kspNS = PETSc.KSP().create() kspM = PETSc.KSP().create() kspNS.setTolerances(OuterTol) kspNS.setOperators(A.getSubMatrix(NS_is, NS_is)) kspM.setOperators(A.getSubMatrix(M_is, M_is)) del A uNS = u.getSubVector(NS_is) bNS = b.getSubVector(NS_is) kspNS.setType('gmres') pcNS = kspNS.getPC() kspNS.setTolerances(OuterTol) pcNS.setType(PETSc.PC.Type.PYTHON) if IterType == "MD": pcNS.setPythonContext( NSpreconditioner.NSPCD(MixedFunctionSpace([Fspace[0], Fspace[1]]), kspF, KSPlinearfluids[0], KSPlinearfluids[1], Fp)) else: pcNS.setPythonContext( StokesPrecond.MHDApprox(MixedFunctionSpace([Fspace[0], Fspace[1]]), kspF, KSPlinearfluids[1])) scale = bNS.norm() bNS = bNS / scale start_time = time.time() kspNS.solve(bNS, uNS) print("{:25}").format("NS, time: "), " ==> ", ( "{:4f}").format(time.time() - start_time), ( "{:9}").format(" Its: "), ("{:4}").format( kspNS.its), ("{:9}").format(" time: "), ("{:4}").format( time.strftime('%X %x %Z')[0:5]) uNS = scale * uNS NSits = kspNS.its # kspNS.destroy() # for line in reshist.values(): # print line kspM.setFromOptions() kspM.setType(kspM.Type.MINRES) kspM.setTolerances(InnerTol) pcM = kspM.getPC() pcM.setType(PETSc.PC.Type.PYTHON) pcM.setPythonContext( MP.Hiptmair(MixedFunctionSpace([Fspace[2], Fspace[3]]), HiptmairMatrices[3], HiptmairMatrices[4], HiptmairMatrices[2], HiptmairMatrices[0], HiptmairMatrices[1], HiptmairMatrices[6], 1e-6)) # x = x*scale uM = u.getSubVector(M_is) bM = b.getSubVector(M_is) scale = bM.norm() bM = bM / scale start_time = time.time() kspM.solve(bM, uM) print("{:25}").format("Maxwell solve, time: "), " ==> ", ( "{:4f}").format(time.time() - start_time), ( "{:9}").format(" Its: "), ("{:4}").format( kspM.its), ("{:9}").format(" time: "), ("{:4}").format( time.strftime('%X %x %Z')[0:5]) uM = uM * scale Mits = kspM.its kspM.destroy() u = IO.arrayToVec(np.concatenate([uNS.array, uM.array])) return u, NSits, Mits
def xtest_assembly_solve_block(): """Solve a two-field mass-matrix like problem with block matrix approaches and test that solution is the same. """ mesh = dolfin.generation.UnitSquareMesh(dolfin.MPI.comm_world, 32, 31) p0, p1 = 1, 1 P0 = ufl.FiniteElement("Lagrange", mesh.ufl_cell(), p0) P1 = ufl.FiniteElement("Lagrange", mesh.ufl_cell(), p1) V0 = dolfin.function.functionspace.FunctionSpace(mesh, P0) V1 = dolfin.function.functionspace.FunctionSpace(mesh, P1) def boundary(x): return numpy.logical_or(x[:, 0] < 1.0e-6, x[:, 0] > 1.0 - 1.0e-6) u_bc0 = dolfin.function.constant.Constant(50.0) u_bc1 = dolfin.function.constant.Constant(20.0) bc0 = dolfin.fem.dirichletbc.DirichletBC(V0, u_bc0, boundary) bc1 = dolfin.fem.dirichletbc.DirichletBC(V1, u_bc1, boundary) # Variational problem u, p = dolfin.function.argument.TrialFunction( V0), dolfin.function.argument.TrialFunction(V1) v, q = dolfin.function.argument.TestFunction( V0), dolfin.function.argument.TestFunction(V1) f = dolfin.function.constant.Constant(1.0) g = dolfin.function.constant.Constant(-3.0) zero = dolfin.function.constant.Constant(0.0) a00 = inner(u, v) * dx a01 = zero * inner(p, v) * dx a10 = zero * inner(u, q) * dx a11 = inner(p, q) * dx L0 = inner(f, v) * dx L1 = inner(g, q) * dx def monitor(ksp, its, rnorm): pass # print("Norm:", its, rnorm) # Create assembler assembler = dolfin.fem.assembling.Assembler([[a00, a01], [a10, a11]], [L0, L1], [bc0, bc1]) # Monolithic blocked A0, b0 = assembler.assemble( mat_type=dolfin.cpp.fem.Assembler.BlockType.monolithic) A0norm = A0.mat().norm() b0norm = b0.vec().norm() x0 = A0.mat().createVecLeft() ksp = PETSc.KSP() ksp.create(mesh.mpi_comm()) ksp.setOperators(A0.mat()) ksp.setTolerances(rtol=1.0e-12) ksp.setMonitor(monitor) ksp.setType('cg') ksp.setFromOptions() # ksp.view() ksp.solve(b0.vec(), x0) x0norm = x0.norm() # Nested (MatNest) A1, b1 = assembler.assemble( mat_type=dolfin.cpp.fem.Assembler.BlockType.nested) b1norm = b1.vec().norm() assert b1norm == pytest.approx(b0norm, 1.0e-12) x1 = dolfin.la.PETScVector(b1) ksp = PETSc.KSP() ksp.create(mesh.mpi_comm()) ksp.setMonitor(monitor) ksp.setTolerances(rtol=1.0e-12) ksp.setOperators(A1.mat()) ksp.setType('cg') ksp.setFromOptions() # ksp.view() ksp.solve(b1.vec(), x1.vec()) x1norm = x1.vec().norm() assert x1norm == pytest.approx(x0norm, rel=1.0e-10) # Monolithic version E = P0 * P1 W = dolfin.function.functionspace.FunctionSpace(mesh, E) u0, u1 = dolfin.function.argument.TrialFunctions(W) v0, v1 = dolfin.function.argument.TestFunctions(W) a = inner(u0, v0) * dx + inner(u1, v1) * dx L = inner(f, v0) * ufl.dx + inner(g, v1) * dx u_bc = dolfin.function.constant.Constant((50.0, 20.0)) bc = dolfin.fem.dirichletbc.DirichletBC(W, u_bc, boundary) assembler = dolfin.fem.assembling.Assembler([[a]], [L], [bc]) A2, b2 = assembler.assemble( mat_type=dolfin.cpp.fem.Assembler.BlockType.monolithic) A2norm = A2.mat().norm() b2norm = b2.vec().norm() assert A2norm == pytest.approx(A0norm, 1.0e-12) assert b2norm == pytest.approx(b0norm, 1.0e-12) x2 = dolfin.cpp.la.PETScVector(b2) ksp = PETSc.KSP() ksp.create(mesh.mpi_comm()) ksp.setMonitor(monitor) ksp.setOperators(A2.mat()) ksp.setType('cg') ksp.setTolerances(rtol=1.0e-9) ksp.setFromOptions() # ksp.view() ksp.solve(b2.vec(), x2.vec()) x2norm = x2.vec().norm() assert x2norm == pytest.approx(x0norm, 1.0e-10) # Old assembler (reference) A3, b3 = dolfin.fem.assembling.assemble_system(a, L, [bc]) x3 = dolfin.cpp.la.PETScVector(b3) ksp = PETSc.KSP() ksp.create(mesh.mpi_comm()) ksp.setMonitor(monitor) ksp.setOperators(A3.mat()) ksp.setType('cg') ksp.setTolerances(rtol=1.0e-9) ksp.setFromOptions() # ksp.view() ksp.solve(b3.vec(), x3.vec()) x3norm = x3.vec().norm() assert x3norm == pytest.approx(x0norm, 1.0e-10)
def __init__(self, da, grid, bdy_type, sparam, verbose=0, solver='gmres', pc=None): ''' Setup the PV inversion solver Parameters ---------- da : petsc DMDA holds the petsc grid grid : qgsolver grid object grid data holder bdy_type : dict prescribe vertical and lateral boundary conditions. Examples bdy_type = {'bottom': 'D', 'top': 'D'} for Dirichlet bdy conditions bdy_type = {'bottom': 'N_RHO', 'top': 'N_RHO'} for Neumann bdy conditions with RHO bdy_type = {'bottom': 'N_PSI', 'top': 'N_PSI'} for Neumann bdy conditions using PSI instead of RHO bdy_type = {'periodic': None} for horizontal periodicity sparam : ndarray numpy array containing f^2/N^2 verbose : int, optional degree of verbosity, 0 means no outputs solver : str, optional petsc solver: 'gmres' (default), 'bicg', 'cg' pc : str, optional what is default? preconditionner: 'icc', 'bjacobi', 'asm', 'mg', 'none' ''' self._verbose = verbose # self.bdy_type = bdy_type if ('periodic' in self.bdy_type) and (self.bdy_type['periodic']): self.petscBoundaryType = 'periodic' else: self.petscBoundaryType = None # create the operator self.L = da.createMat() # if self._verbose>0: print('A PV inversion object is being created') print(' Operator L declared') # Fill in operator values if grid._flag_hgrid_uniform and grid._flag_vgrid_uniform: self._set_L(self.L, da, grid, sparam) else: self._set_L_curv(self.L, da, grid, sparam) # if self._verbose>0: print(' Operator L filled') # global vector for PV inversion self._RHS = da.createGlobalVec() # create solver self.ksp = PETSc.KSP() self.ksp.create(PETSc.COMM_WORLD) self.ksp.setOperators(self.L) self.ksp.setType(solver) self.ksp.setInitialGuessNonzero(True) if pc is not None: self.ksp.getPC().setType(pc) # set tolerances self.ksp.setTolerances(rtol=1e-4) self.ksp.setTolerances(max_it=100) # tests: #self.ksp.setPCSide(PETSc.PC.Side.R) #self.ksp.setInitialGuessNonzero(False) #self.ksp.setTolerances(atol=1e-1) #self.ksp.setTolerances(max_it=100) # for opt in sys.argv[1:]: PETSc.Options().setValue(opt, None) self.ksp.setFromOptions() if self._verbose>0: print(' PV inversion is set up')
def setUp(self, pc): A, P = pc.getOperators() print A.size self.Ct = A.getSubMatrix(self.u_is, self.b_is) self.C = A.getSubMatrix(self.b_is, self.u_is) self.D = A.getSubMatrix(self.r_is, self.b_is) self.Bt = A.getSubMatrix(self.u_is, self.p_is) self.B = A.getSubMatrix(self.p_is, self.u_is) self.Dt = A.getSubMatrix(self.b_is, self.r_is) # print self.Ct.view() #CFC = sp.csr_matrix( (data,(row,column)), shape=(self.W[1].dim(),self.W[1].dim()) ) #print CFC.shape #CFC = PETSc.Mat().createAIJ(size=CFC.shape,csr=(CFC.indptr, CFC.indices, CFC.data)) #print CFC.size, self.AA.size #MX = self.AA+self.F MX = self.F # MO.StoreMatrix(B,"A") # print FC.todense() self.kspF.setType('preonly') self.kspF.getPC().setType('lu') self.kspF.setFromOptions() self.kspF.setPCSide(0) self.kspA.setType('preonly') self.kspA.getPC().setType('lu') self.kspA.setFromOptions() self.kspA.setPCSide(0) self.kspQ.setType('preonly') self.kspQ.getPC().setType('lu') self.kspQ.setFromOptions() self.kspQ.setPCSide(0) self.kspScalar.setType('preonly') self.kspScalar.getPC().setType('lu') self.kspScalar.setFromOptions() self.kspScalar.setPCSide(0) kspMX = PETSc.KSP() kspMX.create(comm=PETSc.COMM_WORLD) pcMX = kspMX.getPC() kspMX.setType('preonly') pcMX.setType('lu') kspMX.setOperators(MX, MX) OptDB = PETSc.Options() #OptDB["pc_factor_mat_ordering_type"] = "rcm" #OptDB["pc_factor_mat_solver_package"] = "mumps" kspMX.setFromOptions() self.kspMX = kspMX # self.kspCGScalar.setType('preonly') # self.kspCGScalar.getPC().setType('lu') # self.kspCGScalar.setFromOptions() # self.kspCGScalar.setPCSide(0) self.kspVector.setType('preonly') self.kspVector.getPC().setType('lu') self.kspVector.setFromOptions() self.kspVector.setPCSide(0) print "setup"
def test_lifting(get_assemblers): # noqa: F811 """ Test MPC lifting operation on a single cell """ assemble_matrix, assemble_vector = get_assemblers # Create mesh and function space mesh = create_unit_square(MPI.COMM_WORLD, 1, 1, CellType.quadrilateral) V = fem.FunctionSpace(mesh, ("Lagrange", 1)) # Solve Problem without MPC for reference u = ufl.TrialFunction(V) v = ufl.TestFunction(V) x = ufl.SpatialCoordinate(mesh) f = x[1] * ufl.sin(2 * ufl.pi * x[0]) a = ufl.inner(ufl.grad(u), ufl.grad(v)) * ufl.dx rhs = ufl.inner(f, v) * ufl.dx bilinear_form = fem.form(a) linear_form = fem.form(rhs) # Create Dirichlet boundary condition u_bc = fem.Function(V) with u_bc.vector.localForm() as u_local: u_local.set(2.3) def dirichletboundary(x): return np.isclose(x[0], 1) mesh.topology.create_connectivity(2, 1) geometrical_dofs = fem.locate_dofs_geometrical(V, dirichletboundary) bc = fem.dirichletbc(u_bc, geometrical_dofs) bcs = [bc] # Generate reference matrices A_org = fem.petsc.assemble_matrix(bilinear_form, bcs=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) # Create multipoint constraint def l2b(li): return np.array(li, dtype=np.float64).tobytes() s_m_c = {l2b([0, 0]): {l2b([0, 1]): 1}} mpc = dolfinx_mpc.MultiPointConstraint(V) mpc.create_general_constraint(s_m_c) mpc.finalize() A = assemble_matrix(bilinear_form, mpc, bcs=bcs) b = assemble_vector(linear_form, mpc) dolfinx_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) solver = PETSc.KSP().create(MPI.COMM_WORLD) solver.setType(PETSc.KSP.Type.PREONLY) solver.getPC().setType(PETSc.PC.Type.LU) solver.setOperators(A) # Solve uh = b.copy() uh.set(0) solver.solve(b, uh) uh.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD) mpc.backsubstitution(uh) V_mpc = mpc.function_space u_out = fem.Function(V_mpc) u_out.vector.array[:] = uh.array root = 0 comm = mesh.comm with Timer("~TEST: Compare"): dolfinx_mpc.utils.compare_mpc_lhs(A_org, A, mpc, root=root) dolfinx_mpc.utils.compare_mpc_rhs(L_org, b, mpc, root=root) # Gather LHS, RHS and solution on one process A_csr = dolfinx_mpc.utils.gather_PETScMatrix(A_org, root=root) K = dolfinx_mpc.utils.gather_transformation_matrix(mpc, root=root) L_np = dolfinx_mpc.utils.gather_PETScVector(L_org, root=root) u_mpc = dolfinx_mpc.utils.gather_PETScVector(uh, root=root) # constants = dolfinx_mpc.utils.gather_contants(mpc, root=root) if MPI.COMM_WORLD.rank == root: KTAK = K.T * A_csr * K reduced_L = K.T @ (L_np) # - constants) # Solve linear system d = scipy.sparse.linalg.spsolve(KTAK, reduced_L) # Back substitution to full solution vecto uh_numpy = K @ (d) # + constants) assert np.allclose(uh_numpy, u_mpc) list_timings(comm, [TimingType.wall])
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])
cnt = 0 for kt in range(2, 3): #ktv=2 # Build A and B for eigen-analysis A, B = build_AB(kt, r, z, Lap, Pr_b, Qr_b, parms) #returns first eigenvector, used as a guess for timestepping sn = solve_eigensystem(A, B, nEV, cnt, Nz, N2, guess) # Time Stepping A = -1j * A dt = 1e4 dto2 = dt / 2 tol = 1e-7 ksp = PETSc.KSP().create(PETSc.COMM_WORLD) ksp.setOperators(B - dto2 * A) #Abot ksp.setTolerances(1e-9) pc = ksp.getPC() pc.setType('none') # ksp.setFromOptions() Atop = B + dto2 * A Atop.assemble() sntemp = PETSc.Vec().createMPI(sn.getSize()) sntemp.setUp() count = 1 error = 1 max_it = 8e5
def test_cell_domains(get_assemblers): # noqa: F811 """ Periodic MPC conditions over integral with different cell subdomains """ assemble_matrix, assemble_vector = get_assemblers N = 5 # Create mesh and function space mesh = create_unit_square(MPI.COMM_WORLD, 15, N) V = fem.FunctionSpace(mesh, ("Lagrange", 1)) def left_side(x): return x[0] < 0.5 tdim = mesh.topology.dim num_cells = mesh.topology.index_map(tdim).size_local cell_midpoints = compute_midpoints(mesh, tdim, range(num_cells)) values = np.ones(num_cells, dtype=np.intc) # All cells on right side marked one, all other with 1 values += left_side(cell_midpoints.T) ct = meshtags(mesh, mesh.topology.dim, np.arange(num_cells, dtype=np.int32), values) # Solve Problem without MPC for reference u = ufl.TrialFunction(V) v = ufl.TestFunction(V) x = ufl.SpatialCoordinate(mesh) c1 = fem.Constant(mesh, PETSc.ScalarType(2)) c2 = fem.Constant(mesh, PETSc.ScalarType(10)) dx = ufl.Measure("dx", domain=mesh, subdomain_data=ct) a = c1 * ufl.inner(ufl.grad(u), ufl.grad(v)) * dx(1) +\ c2 * ufl.inner(ufl.grad(u), ufl.grad(v)) * dx(2)\ + 0.01 * ufl.inner(u, v) * dx(1) rhs = ufl.inner(x[1], v) * dx(1) + \ ufl.inner(fem.Constant(mesh, PETSc.ScalarType(1)), v) * dx(2) bilinear_form = fem.form(a) linear_form = fem.form(rhs) # Generate reference matrices A_org = fem.petsc.assemble_matrix(bilinear_form) A_org.assemble() L_org = fem.petsc.assemble_vector(linear_form) L_org.ghostUpdate(addv=PETSc.InsertMode.ADD_VALUES, mode=PETSc.ScatterMode.REVERSE) def l2b(li): return np.array(li, dtype=np.float64).tobytes() s_m_c = {} for i in range(0, N + 1): s_m_c[l2b([1, i / N])] = {l2b([0, i / N]): 1} mpc = dolfinx_mpc.MultiPointConstraint(V) mpc.create_general_constraint(s_m_c) mpc.finalize() # Setup MPC system with Timer("~TEST: Assemble matrix old"): A = assemble_matrix(bilinear_form, mpc) with Timer("~TEST: Assemble vector"): b = assemble_vector(linear_form, mpc) b.ghostUpdate(addv=PETSc.InsertMode.ADD_VALUES, mode=PETSc.ScatterMode.REVERSE) solver = PETSc.KSP().create(MPI.COMM_WORLD) solver.setType(PETSc.KSP.Type.PREONLY) solver.getPC().setType(PETSc.PC.Type.LU) solver.setOperators(A) # Solve uh = b.copy() uh.set(0) solver.solve(b, uh) uh.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD) mpc.backsubstitution(uh) root = 0 comm = mesh.comm with Timer("~TEST: Compare"): dolfinx_mpc.utils.compare_mpc_lhs(A_org, A, mpc, root=root) dolfinx_mpc.utils.compare_mpc_rhs(L_org, b, mpc, root=root) # Gather LHS, RHS and solution on one process A_csr = dolfinx_mpc.utils.gather_PETScMatrix(A_org, root=root) K = dolfinx_mpc.utils.gather_transformation_matrix(mpc, root=root) L_np = dolfinx_mpc.utils.gather_PETScVector(L_org, root=root) u_mpc = dolfinx_mpc.utils.gather_PETScVector(uh, 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(comm, [TimingType.wall])
def run_dg_test(mesh, V, degree): """ Manufactured Poisson problem, solving u = x[component]**n, where n is the degree of the Lagrange function space. """ u, v = TrialFunction(V), TestFunction(V) # Exact solution x = SpatialCoordinate(mesh) u_exact = x[1]**degree # Coefficient k = Function(V) k.vector.set(2.0) k.vector.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD) # Source term f = -div(k * grad(u_exact)) # Mesh normals and element size n = FacetNormal(mesh) h = CellDiameter(mesh) h_avg = (h("+") + h("-")) / 2.0 # Penalty parameter alpha = 32 dx_ = dx(metadata={"quadrature_degree": -1}) ds_ = ds(metadata={"quadrature_degree": -1}) dS_ = dS(metadata={"quadrature_degree": -1}) with common.Timer("Compile forms"): a = inner(k * grad(u), grad(v)) * dx_ \ - k("+") * inner(avg(grad(u)), jump(v, n)) * dS_ \ - k("+") * inner(jump(u, n), avg(grad(v))) * dS_ \ + k("+") * (alpha / h_avg) * inner(jump(u, n), jump(v, n)) * dS_ \ - inner(k * grad(u), v * n) * ds_ \ - inner(u * n, k * grad(v)) * ds_ \ + (alpha / h) * inner(k * u, v) * ds_ L = inner(f, v) * dx_ - inner(k * u_exact * n, grad(v)) * ds_ \ + (alpha / h) * inner(k * u_exact, v) * ds_ for integral in a.integrals(): integral.metadata( )["quadrature_degree"] = ufl.algorithms.estimate_total_polynomial_degree( a) for integral in L.integrals(): integral.metadata( )["quadrature_degree"] = ufl.algorithms.estimate_total_polynomial_degree( L) with common.Timer("Assemble vector"): b = assemble_vector(L) b.ghostUpdate(addv=PETSc.InsertMode.ADD, mode=PETSc.ScatterMode.REVERSE) with common.Timer("Assemble matrix"): A = assemble_matrix(a, []) A.assemble() with common.Timer("Solve"): # Create LU linear solver solver = PETSc.KSP().create(MPI.COMM_WORLD) solver.setType(PETSc.KSP.Type.PREONLY) solver.getPC().setType(PETSc.PC.Type.LU) solver.setOperators(A) # Solve uh = Function(V) solver.solve(b, uh.vector) uh.vector.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD) with common.Timer("Error functional compile"): # Calculate error M = (u_exact - uh)**2 * dx M = fem.Form(M) with common.Timer("Error assembly"): error = mesh.mpi_comm().allreduce(assemble_scalar(M), op=MPI.SUM) common.list_timings(MPI.COMM_WORLD, [common.TimingType.wall]) assert np.absolute(error) < 1.0e-14
def solve(self, ksp, b, x): """ Solve of the AMPCG Krylov Subspace Solver. Parameters ========== ksp : FIX b : PETSc Vec The right hand side for which to solve. x : PETSc Vec To store the solution. """ self.mpc.proj.project(x) xtild = self.mpc.proj.coarse_init(b) x += xtild A, B = ksp.getOperators() r, z, p, Ap = self.work comm = ksp.comm A.mult(x, r) r.aypx(-1, b) self.mpc.mult(r, z) natural_norm = sqrt(r.dot(z)) self.natural_norm.append(natural_norm) its = ksp.getIterationNumber() if self.MPinitit or self.fullMP : if self.verbose : PETSc.Sys.Print('multipreconditioning initial iteration', comm=comm) self.ti.append(0) self.mpc.MP_mult(r, p[-1]) else: if self.verbose : PETSc.Sys.Print('not multipreconditioning initial iteration', comm=comm) self.ti.append(inf) p[-1] = z.copy() alpha = self.gamma.duplicate() beta = self.gamma.duplicate() phi = self.gamma.duplicate() if self.callback: self.callback(locals()) while not self.loop(ksp, r, z): if isinstance(p[-1], list): for i in range(self.ndom): self.gamma[i] = p[-1][i].dot(r) Ap[-1][i] = A*p[-1][i] for j in range(i + 1): tmp = Ap[-1][i].dot(p[-1][j]) self.Delta[i, j] = tmp self.Delta[j, i] = tmp self.Delta.assemble() self.ksp_Delta.append(PETSc.KSP().create(comm=PETSc.COMM_SELF)) self.ksp_Delta[-1].setOperators(self.Delta.copy()) self.ksp_Delta[-1].setType(ksp.Type.PREONLY) pc = self.ksp_Delta[-1].getPC() pc.setType(pc.Type.CHOLESKY) self.ksp_Delta[-1].solve(self.gamma, alpha) for i in range(self.ndom): x.axpy(alpha[i], p[-1][i]) r.axpy(-alpha[i], Ap[-1][i]) ti = self.gamma.dot(alpha) else: gamma0 = p[-1].dot(r) Ap[-1] = A*p[-1] delta = Ap[-1].dot(p[-1]) self.ksp_Delta.append(delta) alpha0 = gamma0/delta x.axpy(alpha0, p[-1]) r.axpy(-alpha0, Ap[-1]) ti = gamma0*alpha0 self.mpc.mult(r, z) natural_norm = r.dot(z) ti /= natural_norm natural_norm = sqrt(natural_norm) self.natural_norm.append(natural_norm) self.ti.append(ti) if ti < self.tau or self.fullMP: if self.verbose : PETSc.Sys.Print('multipreconditioning this iteration', comm=comm) p.append(self.add_vectors()) Ap.append(self.add_vectors()) self.mpc.MP_mult(r, p[-1]) else: p.append(z.copy()) Ap.append(z.duplicate()) if self.callback: self.callback(locals()) its = ksp.getIterationNumber() for it in range(its): if isinstance(p[-1], list): for i in range(self.ndom): if isinstance(p[it], list): for j in range(self.ndom): phi[j] = Ap[it][j].dot(p[-1][i]) self.ksp_Delta[it].solve(phi, beta) for j in range(self.ndom): p[-1][i].axpy(-beta[j], p[it][j]) else: phi0 = Ap[it].dot(p[-1][i]) beta0 = phi0/self.ksp_Delta[it] p[-1][i].axpy(-beta0, p[it]) else: if isinstance(p[it], list): for j in range(self.ndom): phi[j] = Ap[it][j].dot(p[-1]) self.ksp_Delta[it].solve(phi, beta) for j in range(self.ndom): p[-1].axpy(-beta[j], p[it][j]) else: phi0 = Ap[it].dot(p[-1]) beta0 = phi0/self.ksp_Delta[it] p[-1].axpy(-beta0, p[it]) if isinstance(p[-1], list): for i in range(self.ndom): self.mpc.proj.project(p[-1][i]) else: self.mpc.proj.project(p[-1])
def run_scalar_test(mesh, V, degree): """ Manufactured Poisson problem, solving u = x[1]**p, where p is the degree of the Lagrange function space. """ u, v = TrialFunction(V), TestFunction(V) a = inner(grad(u), grad(v)) * dx # Get quadrature degree for bilinear form integrand (ignores effect of non-affine map) a = inner(grad(u), grad(v)) * dx(metadata={"quadrature_degree": -1}) a.integrals()[0].metadata( )["quadrature_degree"] = ufl.algorithms.estimate_total_polynomial_degree(a) # Source term x = SpatialCoordinate(mesh) u_exact = x[1]**degree f = -div(grad(u_exact)) # Set quadrature degree for linear form integrand (ignores effect of non-affine map) L = inner(f, v) * dx(metadata={"quadrature_degree": -1}) L.integrals()[0].metadata( )["quadrature_degree"] = ufl.algorithms.estimate_total_polynomial_degree(L) with common.Timer("Linear form compile"): L = fem.Form(L) with common.Timer("Function interpolation"): u_bc = Function(V) u_bc.interpolate(lambda x: x[1]**degree) # Create Dirichlet boundary condition mesh.topology.create_connectivity_all() facetdim = mesh.topology.dim - 1 bndry_facets = np.where( np.array(cpp.mesh.compute_boundary_facets(mesh.topology)) == 1)[0] bdofs = locate_dofs_topological(V, facetdim, bndry_facets) assert (len(bdofs) < V.dim) bc = DirichletBC(u_bc, bdofs) with common.Timer("Vector assembly"): b = assemble_vector(L) apply_lifting(b, [a], [[bc]]) b.ghostUpdate(addv=PETSc.InsertMode.ADD, mode=PETSc.ScatterMode.REVERSE) set_bc(b, [bc]) with common.Timer("Bilinear form compile"): a = fem.Form(a) with common.Timer("Matrix assembly"): A = assemble_matrix(a, [bc]) A.assemble() # Create LU linear solver solver = PETSc.KSP().create(MPI.COMM_WORLD) solver.setType(PETSc.KSP.Type.PREONLY) solver.getPC().setType(PETSc.PC.Type.LU) solver.setOperators(A) with common.Timer("Solve"): uh = Function(V) solver.solve(b, uh.vector) uh.vector.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD) with common.Timer("Error functional compile"): M = (u_exact - uh)**2 * dx M = fem.Form(M) with common.Timer("Error assembly"): error = mesh.mpi_comm().allreduce(assemble_scalar(M), op=MPI.SUM) common.list_timings(MPI.COMM_WORLD, [common.TimingType.wall]) assert np.absolute(error) < 1.0e-14
v = TestFunction(V) F = inner(grad(u), grad(v)) * dx - k0**2 * inner(u, v) * dx - \ k_absorb * inner(u, v) * dx \ + inner(dot(grad(ui), n), v) * ds(1) a = lhs(F) L = rhs(F) ''' 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 = 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,
def reference_periodic(tetra: bool, r_lvl: int = 0, out_hdf5: h5py.File = None, xdmf: bool = False, boomeramg: bool = False, kspview: bool = False, degree: int = 1): # Create mesh and finite element if tetra: # Tet setup N = 3 mesh = create_unit_cube(MPI.COMM_WORLD, N, N, N) for i in range(r_lvl): mesh.topology.create_entities(mesh.topology.dim - 2) mesh = refine(mesh, redistribute=True) N *= 2 else: # Hex setup N = 3 for i in range(r_lvl): N *= 2 mesh = create_unit_cube(MPI.COMM_WORLD, N, N, N, CellType.hexahedron) V = FunctionSpace(mesh, ("CG", degree)) # Create Dirichlet boundary condition def dirichletboundary(x): return np.logical_or( np.logical_or(np.isclose(x[1], 0), np.isclose(x[1], 1)), np.logical_or(np.isclose(x[2], 0), np.isclose(x[2], 1))) mesh.topology.create_connectivity(2, 1) geometrical_dofs = locate_dofs_geometrical(V, dirichletboundary) bc = dirichletbc(PETSc.ScalarType(0), geometrical_dofs, V) bcs = [bc] # Define variational problem u = TrialFunction(V) v = TestFunction(V) a = inner(grad(u), grad(v)) * dx x = SpatialCoordinate(mesh) dx_ = x[0] - 0.9 dy_ = x[1] - 0.5 dz_ = x[2] - 0.1 f = x[0] * sin(5.0 * pi * x[1]) + 1.0 * exp( -(dx_ * dx_ + dy_ * dy_ + dz_ * dz_) / 0.02) rhs = inner(f, v) * dx # Assemble rhs, RHS and apply lifting bilinear_form = form(a) linear_form = form(rhs) A_org = assemble_matrix(bilinear_form, bcs) A_org.assemble() L_org = assemble_vector(linear_form) apply_lifting(L_org, [bilinear_form], [bcs]) L_org.ghostUpdate(addv=PETSc.InsertMode.ADD_VALUES, mode=PETSc.ScatterMode.REVERSE) set_bc(L_org, bcs) # Create PETSc nullspace nullspace = PETSc.NullSpace().create(constant=True) PETSc.Mat.setNearNullSpace(A_org, nullspace) # Set PETSc options opts = PETSc.Options() if boomeramg: opts["ksp_type"] = "cg" opts["ksp_rtol"] = 1.0e-5 opts["pc_type"] = "hypre" opts['pc_hypre_type'] = 'boomeramg' opts["pc_hypre_boomeramg_max_iter"] = 1 opts["pc_hypre_boomeramg_cycle_type"] = "v" # opts["pc_hypre_boomeramg_print_statistics"] = 1 else: opts["ksp_type"] = "cg" opts["ksp_rtol"] = 1.0e-12 opts["pc_type"] = "gamg" opts["pc_gamg_type"] = "agg" opts["pc_gamg_sym_graph"] = True # Use Chebyshev smoothing for multigrid opts["mg_levels_ksp_type"] = "richardson" opts["mg_levels_pc_type"] = "sor" # opts["help"] = None # List all available options # opts["ksp_view"] = None # List progress of solver # Initialize PETSc solver, set options and operator solver = PETSc.KSP().create(MPI.COMM_WORLD) solver.setFromOptions() solver.setOperators(A_org) # Solve linear problem u_ = Function(V) start = perf_counter() with Timer("Solve"): solver.solve(L_org, u_.vector) end = perf_counter() u_.vector.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD) if kspview: solver.view() it = solver.getIterationNumber() num_dofs = V.dofmap.index_map.size_global * V.dofmap.index_map_bs if out_hdf5 is not None: d_set = out_hdf5.get("its") d_set[r_lvl] = it d_set = out_hdf5.get("num_dofs") d_set[r_lvl] = num_dofs d_set = out_hdf5.get("solve_time") d_set[r_lvl, MPI.COMM_WORLD.rank] = end - start if MPI.COMM_WORLD.rank == 0: print("Rlvl {0:d}, Iterations {1:d}".format(r_lvl, it)) # Output solution to XDMF if xdmf: ext = "tet" if tetra else "hex" fname = "results/reference_periodic_{0:d}_{1:s}.xdmf".format( r_lvl, ext) u_.name = "u_" + ext + "_unconstrained" with XDMFFile(MPI.COMM_WORLD, fname, "w") as out_periodic: out_periodic.write_mesh(mesh) out_periodic.write_function( u_, 0.0, "Xdmf/Domain/" + "Grid[@Name='{0:s}'][1]".format(mesh.name))
Aa.eliminate_zeros() plt.spy(Aa) plt.show() A,b = CP.Assemble(AA,bb) del AA F = assemble(fp) F = CP.Assemble(F) P = S.ExactPrecond(PP,Q,L,F,FSpaces) Mass = CP.Assemble(Q) u = b.duplicate() NS_is = PETSc.IS().createGeneral(range(Velocity.dim()+Pressure.dim())) M_is = PETSc.IS().createGeneral(range(Velocity.dim()+Pressure.dim(),W.dim())) kspNS = PETSc.KSP().create() kspM = PETSc.KSP().create() kspNS.setTolerances(1e-5) kspNS.setOperators(A.getSubMatrix(NS_is,NS_is),P.getSubMatrix(NS_is,NS_is)) kspM.setOperators(A.getSubMatrix(M_is,M_is),P.getSubMatrix(M_is,M_is)) A.destroy() P.destroy() OptDB = PETSc.Options() OptDB['pc_factor_shift_amount'] = "0.1" # OptDB['pc_factor_shift_type'] = 'POSITIVE_DEFINITE' OptDB['pc_factor_mat_ordering_type'] = 'amd' OptDB['pc_factor_mat_solver_package'] = 'mumps' # kspLAMG.max_it = 1 kspNS.setFromOptions() kspNS.setType('gmres') pcNS = kspNS.getPC()
def solve_linear(self, d_outputs, d_residuals, mode): linear_solver_ = self.options['linear_solver_'] pde_problem = self.options['pde_problem'] state_name = self.options['state_name'] state_function = pde_problem.states_dict[state_name]['function'] for argument_name, argument_function in iteritems(self.argument_functions_dict): density_func = argument_function mesh = state_function.function_space().mesh() sub_domains = df.MeshFunction('size_t', mesh, mesh.topology().dim() - 1) upper_edge = TractionBoundary() upper_edge.mark(sub_domains, 6) dss = df.Measure('ds')(subdomain_data=sub_domains) tractionBC = dss(6) residual_form = get_residual_form( state_function, df.TestFunction(state_function.function_space()), density_func, density_func.function_space(), tractionBC, # df.Constant((0.0, -9.e-1)) df.Constant((0.0, -9.e-1)), int(self.itr) ) A, _ = df.assemble_system(self.derivative_form, - residual_form, pde_problem.bcs_list) if linear_solver_=='fenics_direct': rhs_ = df.Function(state_function.function_space()) dR = df.Function(state_function.function_space()) rhs_.vector().set_local(d_outputs[state_name]) for bc in pde_problem.bcs_list: bc.apply(A) Am = df.as_backend_type(A).mat() ATm = Am.transpose() AT = df.PETScMatrix(ATm) df.solve(AT,dR.vector(),rhs_.vector()) d_residuals[state_name] = dR.vector().get_local() elif linear_solver_=='scipy_splu': for bc in pde_problem.bcs_list: bc.apply(A) Am = df.as_backend_type(A).mat() ATm = Am.transpose() ATm_csr = csr_matrix(ATm.getValuesCSR()[::-1], shape=Am.size) lu = splu(ATm_csr.tocsc()) d_residuals[state_name] = lu.solve(d_outputs[state_name],trans='T') elif linear_solver_=='fenics_Krylov': rhs_ = df.Function(state_function.function_space()) dR = df.Function(state_function.function_space()) rhs_.vector().set_local(d_outputs[state_name]) for bc in pde_problem.bcs_list: bc.apply(A) Am = df.as_backend_type(A).mat() ATm = Am.transpose() AT = df.PETScMatrix(ATm) solver = df.KrylovSolver('gmres', 'ilu') prm = solver.parameters prm["maximum_iterations"]=1000000 prm["divergence_limit"] = 1e2 solver.solve(AT,dR.vector(),rhs_.vector()) d_residuals[state_name] = dR.vector().get_local() elif linear_solver_=='petsc_gmres_ilu': ksp = PETSc.KSP().create() ksp.setType(PETSc.KSP.Type.GMRES) ksp.setTolerances(rtol=5e-11) for bc in pde_problem.bcs_list: bc.apply(A) Am = df.as_backend_type(A).mat() ksp.setOperators(Am) ksp.setFromOptions() pc = ksp.getPC() pc.setType("ilu") size = state_function.function_space().dim() dR = PETSc.Vec().create() dR.setSizes(size) dR.setType('seq') dR.setValues(range(size), d_residuals[state_name]) dR.setUp() du = PETSc.Vec().create() du.setSizes(size) du.setType('seq') du.setValues(range(size), d_outputs[state_name]) du.setUp() if mode == 'fwd': ksp.solve(dR,du) d_outputs[state_name] = du.getValues(range(size)) else: ksp.solveTranspose(du,dR) d_residuals[state_name] = dR.getValues(range(size))
def test_assembly_solve_block(mode): """Solve a two-field mass-matrix like problem with block matrix approaches and test that solution is the same. """ mesh = UnitSquareMesh(MPI.COMM_WORLD, 32, 31, ghost_mode=mode) P = ufl.FiniteElement("Lagrange", mesh.ufl_cell(), 1) V0 = dolfinx.fem.FunctionSpace(mesh, P) V1 = V0.clone() def boundary(x): return numpy.logical_or(x[0] < 1.0e-6, x[0] > 1.0 - 1.0e-6) # Locate facets on boundary facetdim = mesh.topology.dim - 1 bndry_facets = dolfinx.mesh.locate_entities_boundary(mesh, facetdim, boundary) bdofsV0 = dolfinx.fem.locate_dofs_topological(V0, facetdim, bndry_facets) bdofsV1 = dolfinx.fem.locate_dofs_topological(V1, facetdim, bndry_facets) u_bc0 = dolfinx.fem.Function(V0) u_bc0.vector.set(50.0) u_bc0.vector.ghostUpdate( addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD) u_bc1 = dolfinx.fem.Function(V1) u_bc1.vector.set(20.0) u_bc1.vector.ghostUpdate( addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD) bcs = [ dolfinx.fem.dirichletbc.DirichletBC(u_bc0, bdofsV0), dolfinx.fem.dirichletbc.DirichletBC(u_bc1, bdofsV1) ] # Variational problem u, p = ufl.TrialFunction(V0), ufl.TrialFunction(V1) v, q = ufl.TestFunction(V0), ufl.TestFunction(V1) f = 1.0 g = -3.0 zero = dolfinx.Function(V0) a00 = inner(u, v) * dx a01 = zero * inner(p, v) * dx a10 = zero * inner(u, q) * dx a11 = inner(p, q) * dx L0 = inner(f, v) * dx L1 = inner(g, q) * dx def monitor(ksp, its, rnorm): pass # print("Norm:", its, rnorm) A0 = dolfinx.fem.assemble_matrix_block([[a00, a01], [a10, a11]], bcs) b0 = dolfinx.fem.assemble_vector_block([L0, L1], [[a00, a01], [a10, a11]], bcs) A0.assemble() A0norm = A0.norm() b0norm = b0.norm() x0 = A0.createVecLeft() ksp = PETSc.KSP() ksp.create(mesh.mpi_comm()) ksp.setOperators(A0) ksp.setMonitor(monitor) ksp.setType('cg') ksp.setTolerances(rtol=1.0e-14) ksp.setFromOptions() ksp.solve(b0, x0) x0norm = x0.norm() # Nested (MatNest) A1 = dolfinx.fem.assemble_matrix_nest([[a00, a01], [a10, a11]], bcs, diagonal=1.0) A1.assemble() b1 = dolfinx.fem.assemble_vector_nest([L0, L1]) dolfinx.fem.apply_lifting_nest(b1, [[a00, a01], [a10, a11]], bcs) for b_sub in b1.getNestSubVecs(): b_sub.ghostUpdate(addv=PETSc.InsertMode.ADD, mode=PETSc.ScatterMode.REVERSE) bcs0 = dolfinx.cpp.fem.bcs_rows(dolfinx.fem.assemble._create_cpp_form([L0, L1]), bcs) dolfinx.fem.set_bc_nest(b1, bcs0) b1.assemble() b1norm = b1.norm() assert b1norm == pytest.approx(b0norm, 1.0e-12) A1norm = nest_matrix_norm(A1) assert A0norm == pytest.approx(A1norm, 1.0e-12) x1 = b1.copy() ksp = PETSc.KSP() ksp.create(mesh.mpi_comm()) ksp.setMonitor(monitor) ksp.setOperators(A1) ksp.setType('cg') ksp.setTolerances(rtol=1.0e-12) ksp.setFromOptions() ksp.solve(b1, x1) x1norm = x1.norm() assert x1norm == pytest.approx(x0norm, rel=1.0e-12) # Monolithic version E = P * P W = dolfinx.fem.FunctionSpace(mesh, E) u0, u1 = ufl.TrialFunctions(W) v0, v1 = ufl.TestFunctions(W) a = inner(u0, v0) * dx + inner(u1, v1) * dx L = inner(f, v0) * ufl.dx + inner(g, v1) * dx u0_bc = dolfinx.fem.Function(V0) u0_bc.vector.set(50.0) u0_bc.vector.ghostUpdate( addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD) u1_bc = dolfinx.fem.Function(V1) u1_bc.vector.set(20.0) u1_bc.vector.ghostUpdate( addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD) bdofsW0_V0 = dolfinx.fem.locate_dofs_topological((W.sub(0), V0), facetdim, bndry_facets) bdofsW1_V1 = dolfinx.fem.locate_dofs_topological((W.sub(1), V1), facetdim, bndry_facets) bcs = [ dolfinx.fem.dirichletbc.DirichletBC(u0_bc, bdofsW0_V0, W.sub(0)), dolfinx.fem.dirichletbc.DirichletBC(u1_bc, bdofsW1_V1, W.sub(1)) ] A2 = dolfinx.fem.assemble_matrix(a, bcs) A2.assemble() b2 = dolfinx.fem.assemble_vector(L) dolfinx.fem.apply_lifting(b2, [a], [bcs]) b2.ghostUpdate(addv=PETSc.InsertMode.ADD, mode=PETSc.ScatterMode.REVERSE) dolfinx.fem.set_bc(b2, bcs) A2norm = A2.norm() b2norm = b2.norm() assert A2norm == pytest.approx(A0norm, 1.0e-12) assert b2norm == pytest.approx(b0norm, 1.0e-12) x2 = b2.copy() ksp = PETSc.KSP() ksp.create(mesh.mpi_comm()) ksp.setMonitor(monitor) ksp.setOperators(A2) ksp.setType('cg') ksp.getPC().setType('jacobi') ksp.setTolerances(rtol=1.0e-12) ksp.setFromOptions() ksp.solve(b2, x2) x2norm = x2.norm() assert x2norm == pytest.approx(x0norm, 1.0e-10)
def __init__(self, a: ufl.Form, L: ufl.Form, bcs: typing.List[fem.DirichletBC] = [], u: fem.Function = None, petsc_options={}, form_compiler_parameters={}, jit_parameters={}): """Initialize solver for a linear variational problem. Parameters ---------- a A bilinear UFL form, the left hand side of the variational problem. L A linear UFL form, the right hand side of the variational problem. bcs A list of Dirichlet boundary conditions. u The solution function. It will be created if not provided. petsc_options Parameters that is passed to the linear algebra backend PETSc. For available choices for the 'petsc_options' kwarg, see the `PETSc-documentation <https://www.mcs.anl.gov/petsc/documentation/index.html>`. form_compiler_parameters Parameters used in FFCX compilation of this form. Run `ffcx --help` at the commandline to see all available options. Takes priority over all other parameter values, except for `scalar_type` which is determined by DOLFINX. jit_parameters Parameters used in CFFI JIT compilation of C code generated by FFCX. See `python/dolfinx/jit.py` for all available parameters. Takes priority over all other parameter values. .. code-block:: python problem = LinearProblem(a, L, [bc0, bc1], petsc_options={"ksp_type": "preonly", "pc_type": "lu"}) """ self._a = fem.Form(a, form_compiler_parameters=form_compiler_parameters, jit_parameters=jit_parameters) self._A = fem.create_matrix(self._a) self._L = fem.Form(L, form_compiler_parameters=form_compiler_parameters, jit_parameters=jit_parameters) self._b = fem.create_vector(self._L) if u is None: # Extract function space from TrialFunction (which is at the # end of the argument list as it is numbered as 1, while the # Test function is numbered as 0) self.u = fem.Function(a.arguments()[-1].ufl_function_space()) else: self.u = u self.bcs = bcs self._solver = PETSc.KSP().create( self.u.function_space.mesh.mpi_comm()) self._solver.setOperators(self._A) # Give PETSc solver options a unique prefix solver_prefix = "dolfinx_solve_{}".format(id(self)) self._solver.setOptionsPrefix(solver_prefix) # Set PETSc options opts = PETSc.Options() opts.prefixPush(solver_prefix) for k, v in petsc_options.items(): opts[k] = v opts.prefixPop() self._solver.setFromOptions()
def test_assembly_solve_block(): """Solve a two-field mass-matrix like problem with block matrix approaches and test that solution is the same. """ mesh = dolfin.generation.UnitSquareMesh(dolfin.MPI.comm_world, 32, 31) p0, p1 = 1, 1 P0 = ufl.FiniteElement("Lagrange", mesh.ufl_cell(), p0) P1 = ufl.FiniteElement("Lagrange", mesh.ufl_cell(), p1) V0 = dolfin.function.functionspace.FunctionSpace(mesh, P0) V1 = dolfin.function.functionspace.FunctionSpace(mesh, P1) def boundary(x): return numpy.logical_or(x[:, 0] < 1.0e-6, x[:, 0] > 1.0 - 1.0e-6) u_bc0 = dolfin.function.Function(V0) u_bc0.vector.set(50.0) u_bc0.vector.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD) u_bc1 = dolfin.function.Function(V1) u_bc1.vector.set(20.0) u_bc1.vector.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD) bcs = [ dolfin.fem.dirichletbc.DirichletBC(V0, u_bc0, boundary), dolfin.fem.dirichletbc.DirichletBC(V1, u_bc1, boundary) ] # Variational problem u, p = dolfin.function.TrialFunction(V0), dolfin.function.TrialFunction(V1) v, q = dolfin.function.TestFunction(V0), dolfin.function.TestFunction(V1) f = 1.0 g = -3.0 zero = dolfin.Function(V0) a00 = inner(u, v) * dx a01 = zero * inner(p, v) * dx a10 = zero * inner(u, q) * dx a11 = inner(p, q) * dx L0 = inner(f, v) * dx L1 = inner(g, q) * dx def monitor(ksp, its, rnorm): pass # print("Norm:", its, rnorm) A0 = dolfin.fem.assemble_matrix_block([[a00, a01], [a10, a11]], bcs) b0 = dolfin.fem.assemble_vector_block([L0, L1], [[a00, a01], [a10, a11]], bcs) A0norm = A0.norm() b0norm = b0.norm() x0 = A0.createVecLeft() ksp = PETSc.KSP() ksp.create(mesh.mpi_comm()) ksp.setOperators(A0) ksp.setMonitor(monitor) ksp.setType('cg') ksp.setTolerances(rtol=1.0e-14) ksp.setFromOptions() ksp.solve(b0, x0) x0norm = x0.norm() # Nested (MatNest) A1 = dolfin.fem.assemble_matrix_nest([[a00, a01], [a10, a11]], bcs) b1 = dolfin.fem.assemble_vector_nest([L0, L1], [[a00, a01], [a10, a11]], bcs) b1norm = b1.norm() assert b1norm == pytest.approx(b0norm, 1.0e-12) A1norm = nest_matrix_norm(A1) assert A0norm == pytest.approx(A1norm, 1.0e-12) x1 = b1.copy() ksp = PETSc.KSP() ksp.create(mesh.mpi_comm()) ksp.setMonitor(monitor) ksp.setOperators(A1) ksp.setType('cg') ksp.setTolerances(rtol=1.0e-12) ksp.setFromOptions() ksp.solve(b1, x1) x1norm = x1.norm() assert x1norm == pytest.approx(x0norm, rel=1.0e-12) # Monolithic version E = P0 * P1 W = dolfin.function.functionspace.FunctionSpace(mesh, E) u0, u1 = dolfin.function.TrialFunctions(W) v0, v1 = dolfin.function.TestFunctions(W) a = inner(u0, v0) * dx + inner(u1, v1) * dx L = inner(f, v0) * ufl.dx + inner(g, v1) * dx V0 = dolfin.function.functionspace.FunctionSpace(mesh, P0) V1 = dolfin.function.functionspace.FunctionSpace(mesh, P1) u0_bc = dolfin.function.Function(V0) u0_bc.vector.set(50.0) u0_bc.vector.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD) u1_bc = dolfin.function.Function(V1) u1_bc.vector.set(20.0) u1_bc.vector.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD) bcs = [ dolfin.fem.dirichletbc.DirichletBC(W.sub(0), u0_bc, boundary), dolfin.fem.dirichletbc.DirichletBC(W.sub(1), u1_bc, boundary) ] A2 = dolfin.fem.assemble_matrix(a, bcs) A2.assemble() b2 = dolfin.fem.assemble_vector(L) dolfin.fem.apply_lifting(b2, [a], [bcs]) b2.ghostUpdate(addv=PETSc.InsertMode.ADD, mode=PETSc.ScatterMode.REVERSE) dolfin.fem.set_bc(b2, bcs) A2norm = A2.norm() b2norm = b2.norm() assert A2norm == pytest.approx(A0norm, 1.0e-12) assert b2norm == pytest.approx(b0norm, 1.0e-12) x2 = b2.copy() ksp = PETSc.KSP() ksp.create(mesh.mpi_comm()) ksp.setMonitor(monitor) ksp.setOperators(A2) ksp.setType('cg') ksp.getPC().setType('jacobi') ksp.setTolerances(rtol=1.0e-12) ksp.setFromOptions() ksp.solve(b2, x2) x2norm = x2.norm() assert x2norm == pytest.approx(x0norm, 1.0e-10)
boundary_facets = dolfinx.mesh.locate_entities_boundary( mesh, mesh.topology.dim - 1, lambda x: np.full(x.shape[1], True, dtype=bool)) boundary_dofs = dolfinx.fem.locate_dofs_topological( (V.sub(1), V_1), mesh.topology.dim - 1, boundary_facets) bcs = [dirichletbc(zero_u, boundary_dofs, V.sub(1))] A = assemble_matrix(a, bcs=bcs) A.assemble() b = assemble_vector(L) apply_lifting(b, [a], bcs=[bcs]) b.ghostUpdate(addv=PETSc.InsertMode.ADD, mode=PETSc.ScatterMode.REVERSE) set_bc(b, bcs) # Solve solver = PETSc.KSP().create(MPI.COMM_WORLD) PETSc.Options()["ksp_type"] = "preonly" PETSc.Options()["pc_type"] = "lu" PETSc.Options()["pc_factor_mat_solver_type"] = "mumps" solver.setFromOptions() solver.setOperators(A) x_h = Function(V) solver.solve(b, x_h.vector) x_h.x.scatter_forward() sigma_h = S(ufl.as_tensor([[x_h[0], x_h[1]], [x_h[2], x_h[3]]])) # Viz xvfb.start_xvfb(wait=0.05)
def test_assembly_solve_taylor_hood(mesh): """Assemble Stokes problem with Taylor-Hood elements and solve.""" P2 = functionspace.VectorFunctionSpace(mesh, ("Lagrange", 2)) P1 = functionspace.FunctionSpace(mesh, ("Lagrange", 1)) def boundary0(x): """Define boundary x = 0""" return x[:, 0] < 10 * numpy.finfo(float).eps def boundary1(x): """Define boundary x = 1""" return x[:, 0] > (1.0 - 10 * numpy.finfo(float).eps) u0 = dolfin.Function(P2) u0.vector.set(1.0) u0.vector.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD) bc0 = dolfin.DirichletBC(P2, u0, boundary0) bc1 = dolfin.DirichletBC(P2, u0, boundary1) u, p = dolfin.TrialFunction(P2), dolfin.TrialFunction(P1) v, q = dolfin.TestFunction(P2), dolfin.TestFunction(P1) a00 = inner(ufl.grad(u), ufl.grad(v)) * dx a01 = ufl.inner(p, ufl.div(v)) * dx a10 = ufl.inner(ufl.div(u), q) * dx a11 = None p00 = a00 p01, p10 = None, None p11 = inner(p, q) * dx # FIXME # We need zero function for the 'zero' part of L p_zero = dolfin.Function(P1) f = dolfin.Function(P2) L0 = ufl.inner(f, v) * dx L1 = ufl.inner(p_zero, q) * dx # -- Blocked and nested A0 = dolfin.fem.assemble_matrix_nest([[a00, a01], [a10, a11]], [bc0, bc1]) A0norm = nest_matrix_norm(A0) P0 = dolfin.fem.assemble_matrix_nest([[p00, p01], [p10, p11]], [bc0, bc1]) P0norm = nest_matrix_norm(P0) b0 = dolfin.fem.assemble_vector_nest([L0, L1], [[a00, a01], [a10, a11]], [bc0, bc1]) b0norm = b0.norm() ksp = PETSc.KSP() ksp.create(mesh.mpi_comm()) ksp.setOperators(A0, P0) nested_IS = P0.getNestISs() ksp.setType("minres") pc = ksp.getPC() pc.setType("fieldsplit") pc.setFieldSplitIS(["u", nested_IS[0][0]], ["p", nested_IS[1][1]]) ksp_u, ksp_p = pc.getFieldSplitSubKSP() ksp_u.setType("preonly") ksp_u.getPC().setType('lu') ksp_u.getPC().setFactorSolverType('mumps') ksp_p.setType("preonly") def monitor(ksp, its, rnorm): # print("Num it, rnorm:", its, rnorm) pass ksp.setTolerances(rtol=1.0e-8, max_it=50) ksp.setMonitor(monitor) ksp.setFromOptions() x0 = b0.copy() ksp.solve(b0, x0) assert ksp.getConvergedReason() > 0 # -- Blocked and monolithic A1 = dolfin.fem.assemble_matrix_block([[a00, a01], [a10, a11]], [bc0, bc1]) assert A1.norm() == pytest.approx(A0norm, 1.0e-12) P1 = dolfin.fem.assemble_matrix_block([[p00, p01], [p10, p11]], [bc0, bc1]) assert P1.norm() == pytest.approx(P0norm, 1.0e-12) b1 = dolfin.fem.assemble_vector_block([L0, L1], [[a00, a01], [a10, a11]], [bc0, bc1]) assert b1.norm() == pytest.approx(b0norm, 1.0e-12) ksp = PETSc.KSP() ksp.create(mesh.mpi_comm()) ksp.setOperators(A1, P1) ksp.setType("minres") pc = ksp.getPC() pc.setType('lu') pc.setFactorSolverType('mumps') ksp.setTolerances(rtol=1.0e-8, max_it=50) ksp.setFromOptions() x1 = A1.createVecRight() ksp.solve(b1, x1) assert ksp.getConvergedReason() > 0 assert x1.norm() == pytest.approx(x0.norm(), 1e-8) # -- Monolithic P2 = ufl.VectorElement("Lagrange", mesh.ufl_cell(), 2) P1 = ufl.FiniteElement("Lagrange", mesh.ufl_cell(), 1) TH = P2 * P1 W = dolfin.FunctionSpace(mesh, TH) (u, p) = dolfin.TrialFunctions(W) (v, q) = dolfin.TestFunctions(W) a00 = ufl.inner(ufl.grad(u), ufl.grad(v)) * dx a01 = ufl.inner(p, ufl.div(v)) * dx a10 = ufl.inner(ufl.div(u), q) * dx a = a00 + a01 + a10 p00 = ufl.inner(ufl.grad(u), ufl.grad(v)) * dx p11 = ufl.inner(p, q) * dx p_form = p00 + p11 f = dolfin.Function(W.sub(0).collapse()) p_zero = dolfin.Function(W.sub(1).collapse()) L0 = inner(f, v) * dx L1 = inner(p_zero, q) * dx L = L0 + L1 bc0 = dolfin.DirichletBC(W.sub(0), u0, boundary0) bc1 = dolfin.DirichletBC(W.sub(0), u0, boundary1) A2 = dolfin.fem.assemble_matrix(a, [bc0, bc1]) A2.assemble() assert A2.norm() == pytest.approx(A0norm, 1.0e-12) P2 = dolfin.fem.assemble_matrix(p_form, [bc0, bc1]) P2.assemble() assert P2.norm() == pytest.approx(P0norm, 1.0e-12) b2 = dolfin.fem.assemble_vector(L) dolfin.fem.apply_lifting(b2, [a], [[bc0, bc1]]) b2.ghostUpdate(addv=PETSc.InsertMode.ADD, mode=PETSc.ScatterMode.REVERSE) dolfin.fem.set_bc(b2, [bc0, bc1]) b2norm = b2.norm() assert b2norm == pytest.approx(b0norm, 1.0e-12) ksp = PETSc.KSP() ksp.create(mesh.mpi_comm()) ksp.setOperators(A2, P2) ksp.setType("minres") pc = ksp.getPC() pc.setType('lu') pc.setFactorSolverType('mumps') def monitor(ksp, its, rnorm): # print("Num it, rnorm:", its, rnorm) pass ksp.setTolerances(rtol=1.0e-8, max_it=50) ksp.setMonitor(monitor) ksp.setFromOptions() x2 = A2.createVecRight() ksp.solve(b2, x2) assert ksp.getConvergedReason() > 0 assert x0.norm() == pytest.approx(x2.norm(), 1e-8)
def assemble_coarse_operators(self, V0s): """ Assembles the coarse operators from a list of local contributions to the coarse space. Parameters ========== V0s : list of local PETSc .vecs list of the coarse vectors contributed by the subdomain. Returns ========== V0 : list of local vectors or None ? FIX list of the local contributions to the coarse space numbered globally: V0[i] is either a scaled local vector from V0s or None if coarse vector number i belongs to another subdomain. The scaling that is applied to the coarse vectors ensures that their A-norm is 1. AV0 : list of global PETSc.Vecs list of the A*V0[i]. These are global vectors so not in the same format as the vectors in V0. Delta : PETSc.Mat (local) matrix of the coarse problem. As a result of the scaling of the coarse vectors, its diagonal is 1. This matrix is duplicated over all subdomains This matrix is duplicated over all subdomains ksp_Delta : PETSc.ksp Krylov subspace solver for the coarse problem matrix Delta. """ if self.verbose: if self.V0_is_global == False: PETSc.Sys.Print( 'Subdomain number {} contributes {} coarse vectors in total' .format(mpi.COMM_WORLD.rank, len(V0s)), comm=self.comm) if mpi.COMM_WORLD.rank == 0: self.gathered_dimV0s = [ ] #only for view save dims of V0s from each s self.work2 = self.work.duplicate() if (self.V0_is_global == False): V0 = [] for i in range(mpi.COMM_WORLD.size): nrbl = len(V0s) if i == mpi.COMM_WORLD.rank else None nrbl = mpi.COMM_WORLD.bcast(nrbl, root=i) if mpi.COMM_WORLD.rank == 0: self.gathered_dimV0s.append( nrbl) #only for view save dims of V0s from each s for irbm in range(nrbl): V0.append(V0s[irbm].copy() if i == mpi.COMM_WORLD.rank else None) else: V0 = V0s.copy() AV0 = [] for vec in V0: if (self.V0_is_global == False): if vec: self.works = vec.copy() else: self.works.set(0.) self.work.set(0) self.scatter_l2g(self.works, self.work, PETSc.InsertMode.ADD_VALUES) else: self.work = vec.copy() #debug1 = np.sqrt(self.work.dot(self.work)) #debug4 = self.work.norm() #debug3 = np.sqrt(self.works.dot(self.works)) #debug5 = self.works.norm() #print(f'normworks {debug3} = {debug5} normwork {debug1} = {debug4}') self.A.mult(self.work, self.work2) AV0.append(self.work2.copy()) tmp = np.sqrt(self.work.dot(self.work2)) if (self.V0_is_global == False): self.scatter_l2g(AV0[-1], self.works, PETSc.InsertMode.INSERT_VALUES, PETSc.ScatterMode.SCATTER_REVERSE) if vec: vec.scale(1. / tmp) self.works = vec.copy() else: self.works.set(0) self.work.set(0) self.scatter_l2g(self.works, self.work, PETSc.InsertMode.ADD_VALUES) #self.scatter_l2g(self.works, self.work, PETSc.InsertMode.ADD_VALUES) #self.A.mult(self.work,self.work2) self.A.mult(self.work, AV0[-1]) else: vec.scale(1. / tmp) self.A.mult(vec, AV0[-1]) #self.A.mult(self.work,AV0[-1]) # AV0[-1] = self.work2.copy() # AV0[-1] = xtmp.copy() #debug6 = np.sqrt(self.work2.dot(self.work2)) #debug7 = self.work2.norm() #debug2 = np.sqrt(AV0[-1].dot(AV0[-1])) #debug5 = AV0[-1].norm() # debug6 = np.sqrt(self.work2.dot(self.work2)) # debug7 = self.work2.norm() # debug2 = np.sqrt(AV0[-1].dot(AV0[-1])) # debug5 = AV0[-1].norm() # if mpi.COMM_WORLD.rank == 0: # print(f'norm Acoarsevec {debug2} = {debug5}') # print(f'norm Acoarsevec {debug2} = {debug5} = {debug6} = {debug7}') self.dim = len(V0) PETSc.Sys.Print('There are {} vectors in the coarse space.'.format( self.dim), comm=mpi.COMM_WORLD) #Define, fill and factorize coarse problem matrix Delta = PETSc.Mat().create(comm=PETSc.COMM_SELF) Delta.setType(PETSc.Mat.Type.SEQDENSE) Delta.setSizes([len(V0), len(V0)]) Delta.setOption(PETSc.Mat.Option.SYMMETRIC, True) Delta.setPreallocationDense(None) for i, vec in enumerate(V0): if (self.V0_is_global == False): if vec: self.works = vec.copy() else: self.works.set(0) self.work.set(0) self.scatter_l2g(self.works, self.work, PETSc.InsertMode.ADD_VALUES) else: self.work = vec.copy() for j in range(i + 1): tmp = AV0[j].dot(self.work) Delta[i, j] = tmp Delta[j, i] = tmp Delta.assemble() ksp_Delta = PETSc.KSP().create(comm=PETSc.COMM_SELF) ksp_Delta.setOperators(Delta) ksp_Delta.setType('preonly') pc = ksp_Delta.getPC() pc.setType('cholesky') return V0, AV0, Delta, ksp_Delta
def test_cube_contact(generate_hex_boxes, nonslip, get_assemblers): # noqa: F811 assemble_matrix, assemble_vector = get_assemblers comm = MPI.COMM_WORLD root = 0 # Generate mesh mesh_data = generate_hex_boxes mesh, mt = mesh_data fdim = mesh.topology.dim - 1 # Create functionspaces V = fem.VectorFunctionSpace(mesh, ("Lagrange", 1)) # Helper for orienting traction # Bottom boundary is fixed in all directions u_bc = fem.Function(V) with u_bc.vector.localForm() as u_local: u_local.set(0.0) bottom_dofs = fem.locate_dofs_topological(V, fdim, mt.find(5)) bc_bottom = fem.dirichletbc(u_bc, bottom_dofs) g_vec = [0, 0, -4.25e-1] if not nonslip: # Helper for orienting traction r_matrix = dolfinx_mpc.utils.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, [0, 0, -4.25e-1]) # Top boundary has a given deformation normal to the interface def top_v(x): values = np.empty((3, x.shape[1])) values[0] = g_vec[0] values[1] = g_vec[1] values[2] = g_vec[2] return values u_top = fem.Function(V) u_top.interpolate(top_v) top_dofs = fem.locate_dofs_topological(V, fdim, mt.find(3)) bc_top = fem.dirichletbc(u_top, top_dofs) 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 * ufl.sym(ufl.grad(v)) + lmbda * ufl.tr(ufl.sym(ufl.grad(v))) * ufl.Identity(len(v))) # Define variational problem u = ufl.TrialFunction(V) v = ufl.TestFunction(V) a = ufl.inner(sigma(u), ufl.grad(v)) * ufl.dx rhs = ufl.inner(fem.Constant(mesh, PETSc.ScalarType( (0, 0, 0))), v) * ufl.dx bilinear_form = fem.form(a) linear_form = fem.form(rhs) # Create LU solver solver = PETSc.KSP().create(comm) solver.setType("preonly") solver.setTolerances(rtol=1.0e-14) solver.getPC().setType("lu") # Create MPC contact condition and assemble matrices mpc = dolfinx_mpc.MultiPointConstraint(V) if nonslip: with Timer("~Contact: Create non-elastic constraint"): mpc.create_contact_inelastic_condition(mt, 4, 9) else: with Timer("~Contact: Create contact constraint"): nh = dolfinx_mpc.utils.create_normal_approximation(V, mt, 4) mpc.create_contact_slip_condition(mt, 4, 9, nh) mpc.finalize() with Timer("~TEST: Assemble bilinear form"): A = assemble_matrix(bilinear_form, mpc, bcs=bcs) with Timer("~TEST: Assemble vector"): b = assemble_vector(linear_form, mpc) dolfinx_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) with Timer("~MPC: Solve"): solver.setOperators(A) uh = b.copy() uh.set(0) solver.solve(b, uh) uh.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD) mpc.backsubstitution(uh) # Write solution to file # u_h = fem.Function(mpc.function_space) # u_h.vector.setArray(uh.array) # u_h.x.scatter_forward() # u_h.name = "u_{0:.2f}".format(theta) # import dolfinx.io as io # with io.XDMFFile(comm, "output/rotated_cube3D.xdmf", "w") as outfile: # 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 dolfinx_mpc.utils.log_info( "Solving reference problem with global matrix (using numpy)") with Timer("~TEST: Assemble bilinear form (unconstrained)"): 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) with Timer("~TEST: Compare"): dolfinx_mpc.utils.compare_mpc_lhs(A_org, A, mpc, root=root) dolfinx_mpc.utils.compare_mpc_rhs(L_org, b, mpc, root=root) # Gather LHS, RHS and solution on one process A_csr = dolfinx_mpc.utils.gather_PETScMatrix(A_org, root=root) K = dolfinx_mpc.utils.gather_transformation_matrix(mpc, root=root) L_np = dolfinx_mpc.utils.gather_PETScVector(L_org, root=root) u_mpc = dolfinx_mpc.utils.gather_PETScVector(uh, 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(comm, [TimingType.wall])
def assemble_coarse_operators(self, V0s): """ Assembles the coarse operators from a list of local contributions to the coarse space. Parameters ========== V0s : list of local PETSc .vecs list of the coarse vectors contributed by the subdomain. Returns ========== V0 : list of local vectors or None ? FIX list of the local contributions to the coarse space numbered globally: V0[i] is either a scaled local vector from V0s or None if coarse vector number i belongs to another subdomain. The scaling that is applied to the coarse vectors ensures that their A-norm is 1. AV0 : list of global PETSc.Vecs list of the A*V0[i]. These are global vectors so not in the same format as the vectors in V0. Delta : PETSc.Mat (local) matrix of the coarse problem. As a result of the scaling of the coarse vectors, its diagonal is 1. This matrix is duplicated over all subdomains This matrix is duplicated over all subdomains ksp_Delta : PETSc.ksp Krylov subspace solver for the coarse problem matrix Delta. """ if self.verbose: PETSc.Sys.Print( 'Subdomain number {} contributes {} coarse vectors in total'. format(mpi.COMM_WORLD.rank, len(V0s)), comm=self.comm) V0 = [] for i in range(mpi.COMM_WORLD.size): nrbl = len(V0s) if i == mpi.COMM_WORLD.rank else None nrbl = mpi.COMM_WORLD.bcast(nrbl, root=i) for irbm in range(nrbl): V0.append(V0s[irbm] if i == mpi.COMM_WORLD.rank else None) AV0 = [] work, _ = self.work for vec in V0: if vec: self.works = vec.copy() else: self.works.set(0.) work.set(0) self.scatter_l2g(self.works, work, PETSc.InsertMode.ADD_VALUES) AV0.append(self.A * work) self.scatter_l2g(AV0[-1], self.works, PETSc.InsertMode.INSERT_VALUES, PETSc.ScatterMode.SCATTER_REVERSE) if vec: vec.scale(1. / np.sqrt(vec.dot(self.works))) self.works = vec.copy() else: self.works.set(0) work.set(0) self.scatter_l2g(self.works, work, PETSc.InsertMode.ADD_VALUES) AV0[-1] = self.A * work PETSc.Sys.Print('There are {} vectors in the coarse space.'.format( len(V0)), comm=mpi.COMM_WORLD) #Define, fill and factorize coarse problem matrix Delta = PETSc.Mat().create(comm=PETSc.COMM_SELF) Delta.setType(PETSc.Mat.Type.SEQDENSE) Delta.setSizes([len(V0), len(V0)]) Delta.setOption(PETSc.Mat.Option.SYMMETRIC, True) Delta.setPreallocationDense(None) for i, vec in enumerate(V0): if vec: self.works = vec.copy() else: self.works.set(0) work.set(0) self.scatter_l2g(self.works, work, PETSc.InsertMode.ADD_VALUES) for j in range(i + 1): tmp = AV0[j].dot(work) Delta[i, j] = tmp Delta[j, i] = tmp Delta.assemble() ksp_Delta = PETSc.KSP().create(comm=PETSc.COMM_SELF) ksp_Delta.setOperators(Delta) ksp_Delta.setType('preonly') pc = ksp_Delta.getPC() pc.setType('cholesky') return V0, AV0, Delta, ksp_Delta
def monolithic_solve(): """Monolithic (interleaved) solver""" P2_el = ufl.VectorElement("Lagrange", mesh.ufl_cell(), 2) P1_el = ufl.FiniteElement("Lagrange", mesh.ufl_cell(), 1) TH = P2_el * P1_el W = FunctionSpace(mesh, TH) (u, p) = ufl.TrialFunctions(W) (v, q) = ufl.TestFunctions(W) a00 = ufl.inner(ufl.grad(u), ufl.grad(v)) * dx a01 = ufl.inner(p, ufl.div(v)) * dx a10 = ufl.inner(ufl.div(u), q) * dx a = a00 + a01 + a10 p00 = ufl.inner(ufl.grad(u), ufl.grad(v)) * dx p11 = ufl.inner(p, q) * dx p_form = p00 + p11 f = Function(W.sub(0).collapse()[0]) p_zero = Function(W.sub(1).collapse()[0]) L0 = inner(f, v) * dx L1 = inner(p_zero, q) * dx L = L0 + L1 a, p_form, L = form(a), form(p_form), form(L) bdofsW0_P2_0 = locate_dofs_topological(W.sub(0), facetdim, bndry_facets0) bdofsW0_P2_1 = locate_dofs_topological(W.sub(0), facetdim, bndry_facets1) bc0 = dirichletbc(bc_value, bdofsW0_P2_0, W.sub(0)) bc1 = dirichletbc(bc_value, bdofsW0_P2_1, W.sub(0)) A = assemble_matrix(a, bcs=[bc0, bc1]) A.assemble() P = assemble_matrix(p_form, bcs=[bc0, bc1]) P.assemble() b = assemble_vector(L) apply_lifting(b, [a], bcs=[[bc0, bc1]]) b.ghostUpdate(addv=PETSc.InsertMode.ADD, mode=PETSc.ScatterMode.REVERSE) set_bc(b, [bc0, bc1]) ksp = PETSc.KSP() ksp.create(mesh.comm) ksp.setOperators(A, P) ksp.setType("minres") pc = ksp.getPC() pc.setType('lu') def monitor(ksp, its, rnorm): # print("Num it, rnorm:", its, rnorm) pass ksp.setTolerances(rtol=1.0e-8, max_it=50) ksp.setMonitor(monitor) ksp.setFromOptions() x = A.createVecRight() ksp.solve(b, x) assert ksp.getConvergedReason() > 0 return b.norm(), x.norm(), A.norm(), P.norm()