├── README.md ├── da_serial.py ├── ksp_serial.py ├── mat_serial.py └── vec_serial.py /README.md: -------------------------------------------------------------------------------- 1 | Purpose 2 | ======= 3 | 4 | A set of walk-throughs to gradually learn how to use PETSc via the petsc4py 5 | package. 6 | 7 | 8 | Contents 9 | ======== 10 | 11 | 1. vec_serial.py - work with vectors on a single process. 12 | 1. mat_serial.py - work with matrices on a single process. 13 | 1. ksp_serial.py - solve a linear system on a single process. 14 | 1. da_serial.py - work with distributed arrays on a single process. 15 | 1. da_maxwell_serial.py - solving maxwell's equations. 16 | 17 | 18 | Current Issues 19 | ============== 20 | 21 | 1. Implement a 2D E&M solver (that will work well with both modes). 22 | 23 | 24 | Issues for Later 25 | ================ 26 | 27 | 1. Remove "long way" comments in serial codes. 28 | 1. Do something with the maxwell 3D code. 29 | 30 | -------------------------------------------------------------------------------- /da_serial.py: -------------------------------------------------------------------------------- 1 | # Summary 2 | # Basic use of distributed arrays communication data structures in PETSc. 3 | # 4 | # Examples 5 | # Direct solve: 6 | # $ python da_serial.py -ksp_monitor -ksp_type preonly -pc_type lu 7 | # 8 | # Iterative solve: 9 | # $ python da_serial.py -ksp_monitor -ksp_type bcgs 10 | # 11 | # Description 12 | # DAs are extremely useful when working simulations that are discretized 13 | # on a structured grid. DAs don't actually hold data; instead, they are 14 | # templates for distributing and communicating information (matrices and 15 | # vectors) across a parallel system. 16 | # 17 | # In this example, we set up a simple 2D wave equation with mirror 18 | # boundary conditions. The solution, given a source at the center of the 19 | # grid, is solved using a ksp object. 20 | # 21 | # Note that this example is uniprocessor only, so there is nothing 22 | # "distributed" about the DA. Use this as a stepping stone to working with 23 | # DAs in a parallel setting. 24 | # 25 | # For more information, consult the PETSc user manual. 26 | # Also, look at the petsc4py/src/PETSc/DA.pyx file. 27 | 28 | import petsc4py 29 | import sys 30 | petsc4py.init(sys.argv) 31 | from petsc4py import PETSc 32 | from matplotlib import pylab 33 | 34 | # Dimensions of the 2D grid. 35 | nx = 101 36 | ny = 101 37 | 38 | w = 2./10. # Angular frequency of wave (2*pi / period). 39 | 40 | # Create the DA. 41 | da = PETSc.DA().create([nx, ny], \ 42 | stencil_width=1, \ 43 | boundary_type=('ghosted', 'ghosted')) 44 | 45 | # Create the rhs vector based on the DA. 46 | b = da.createGlobalVec() 47 | b_val = da.getVecArray(b) # Obtain access to elements of b. 48 | b_val[50, 50] = 1; # Set central value to 1. 49 | 50 | # Create (a vector to store) the solution vector. 51 | x = da.createGlobalVec() 52 | 53 | # Create the matrix. 54 | A = da.getMatrix('aij') 55 | 56 | # Stencil objects make it easy to set the values of the matrix elements. 57 | row = PETSc.Mat.Stencil() 58 | col = PETSc.Mat.Stencil() 59 | 60 | # Set matrix elements to correct values. 61 | (i0, i1), (j0, j1) = da.getRanges() 62 | for j in range(j0, j1): 63 | for i in range(i0, i1): 64 | row.index = (i, j) 65 | for index, value in [((i, j), -4 + w**2), 66 | ((i-1, j), 1), 67 | ((i+1, j), 1), 68 | ((i, j-1), 1), 69 | ((i, j+1), 1)]: 70 | col.index = index 71 | A.setValueStencil(row, col, value) # Sets a single matrix element. 72 | 73 | A.assemblyBegin() # Make matrices useable. 74 | A.assemblyEnd() 75 | 76 | # Initialize ksp solver. 77 | ksp = PETSc.KSP().create() 78 | ksp.setOperators(A) 79 | 80 | # Allow for solver choice to be set from command line with -ksp_type . 81 | # Recommended option: -ksp_type preonly -pc_type lu 82 | ksp.setFromOptions() 83 | print 'Solving with:', ksp.getType() 84 | 85 | # Solve! 86 | ksp.solve(b, x) 87 | 88 | # Plot solution, which is wave-like, although boundaries cause reflections. 89 | pylab.contourf(da.getVecArray(x)[:]) 90 | pylab.show() 91 | -------------------------------------------------------------------------------- /ksp_serial.py: -------------------------------------------------------------------------------- 1 | # Summary 2 | # Solving a linear system with the KSP package in PETSc. 3 | # 4 | # Description 5 | # We create the sparse linear system Ax = b and solve for x. Different solvers can be 6 | # used by including the option -ksp_type . Also, include the -ksp_monitor option 7 | # to monitor progress. 8 | # 9 | # In particular, compare results from the following solvers: 10 | # python ksp_serial.py -ksp_monitor -ksp_type chebychev 11 | # python ksp_serial.py -ksp_monitor -ksp_type cg 12 | # 13 | # For more information, consult the PETSc user manual. 14 | 15 | import petsc4py 16 | import sys 17 | from matplotlib import pylab 18 | petsc4py.init(sys.argv) 19 | from petsc4py import PETSc 20 | 21 | n = 100 # Size of grid. 22 | w = 6./10. # Angular frequency of wave (2*pi / period). 23 | 24 | # Create the rhs vector b. 25 | b = PETSc.Vec().createSeq(n) 26 | b.setValue(0, 1) # Set value of first element to 1. 27 | 28 | # Create solution vector x. 29 | x = PETSc.Vec().createSeq(n) 30 | 31 | # Create the wave equation matrix. 32 | A = PETSc.Mat().createAIJ([n, n], nnz=3) # nnz=3 since the matrix will be tridiagonal. 33 | 34 | # Insert values (the matrix is tridiagonal). 35 | A.setValue(0, 0, 2. - w**2) 36 | for k in range(1, n): 37 | A.setValue(k, k, 2. - w**2) # Diagonal. 38 | A.setValue(k-1, k, -1.) # Off-diagonal. 39 | A.setValue(k, k-1, -1.) # Off-diagonal. 40 | 41 | A.assemblyBegin() # Make matrices useable. 42 | A.assemblyEnd() 43 | 44 | # Initialize ksp solver. 45 | ksp = PETSc.KSP().create() 46 | ksp.setOperators(A) 47 | 48 | # Allow for solver choice to be set from command line with -ksp_type . 49 | ksp.setFromOptions() 50 | print 'Solving with:', ksp.getType() 51 | 52 | # Solve! 53 | ksp.solve(b, x) 54 | 55 | # Print results. 56 | print 'Converged in', ksp.getIterationNumber(), 'iterations.' 57 | 58 | # # Use this to plot the solution (should look like a sinusoid). 59 | # pylab.plot(x.getArray()) 60 | # pylab.show() 61 | -------------------------------------------------------------------------------- /mat_serial.py: -------------------------------------------------------------------------------- 1 | # Summary 2 | # Basic use of matrices in PETSc. 3 | # 4 | # Description 5 | # We create both a dense and sparse matrix. 6 | # 7 | # For more information, consult the PETSc user manual. 8 | # Also, look at the petsc4py/src/PETSc/Mat.pyx file, especially for a complete listing of 9 | # matrix types. 10 | 11 | import petsc4py 12 | petsc4py.init() 13 | from petsc4py import PETSc 14 | 15 | # Create vector to multiply matrices by. 16 | e = PETSc.Vec().createSeq(4) 17 | e.set(1) 18 | y = PETSc.Vec().createSeq(2) # Put answer here. 19 | 20 | # First, we'll create a dense matrix. 21 | # A = PETSc.Mat().create() 22 | # 23 | # A.setType('dense') # For a list of types, see petsc4py/src/PETSc/Mat.pyx 24 | # A.setSizes([2, 4]) 25 | A = PETSc.Mat().createDense([2, 4]) 26 | 27 | A.setValue(0, 0, 3) # Insert a single value into matrix. 28 | A.setValues([0, 1], [2, 3], [1, 1, 1, 1]) # Insert a 2x2 block of values into the matrix. 29 | 30 | A.assemblyBegin() # Assembling the matrix makes it "useable". 31 | A.assemblyEnd() 32 | 33 | print 'Values of dense matrix:' 34 | print A.getValues(range(2), range(4)) 35 | 36 | A.mult(e, y) 37 | print 'A * 1 =', y.getArray() 38 | 39 | 40 | # Next, we'll create a sparse matrix. 41 | # A = PETSc.Mat().create() 42 | # 43 | # A.setType('aij') # AIJ is PETSc's default sparse matrix format. 44 | # A.setSizes([2, 4]) 45 | A = PETSc.Mat().createAIJ([2, 4]) 46 | 47 | A.setValue(1, 2, -1) 48 | A.setValue(0, 0, -2) 49 | 50 | A.assemblyBegin() # Assembling the matrix makes it "useable". 51 | A.assemblyEnd() 52 | 53 | print 'Values of sparse matrix:' 54 | print A.getValues(range(2), range(4)) 55 | 56 | A.mult(e, y) 57 | print 'A * 1 =', y.getArray() 58 | -------------------------------------------------------------------------------- /vec_serial.py: -------------------------------------------------------------------------------- 1 | # Summary 2 | # Creating and using vectors and basic vector operations in PETSc. 3 | # 4 | # Description 5 | # Vectors are a basic mathematical building block. 6 | # 7 | # For a complete list of vector operations, consult the PETSc user manual. 8 | # Also look at the petsc4py/src/PETSc/Vec.pyx file for petsc4py implementation 9 | # details. 10 | 11 | import sys 12 | import petsc4py 13 | petsc4py.init(sys.argv) 14 | from petsc4py import PETSc 15 | 16 | n = 10 # Size of vector. 17 | 18 | # x = PETSc.Vec().create() # Create vector the long way. 19 | # x.setSizes(n) 20 | # x.setType('seq') # 'seq' means sequential vector. 21 | # 22 | # x.assemblyBegin() # Needed in order to work on vector. 23 | # x.assemblyEnd() 24 | 25 | x = PETSc.Vec().createSeq(n) # Faster way to create a sequential vector. 26 | 27 | x.setValues(range(n), range(n)) # x = [0 1 ... 9] 28 | x.shift(1) # x = x + 1 (add 1 to all elements in x) 29 | 30 | print 'Performing various vector operations on x =', x.getArray() 31 | 32 | print 'Sum of elements of x =', x.sum() 33 | print 'Dot product with itself =', x.dot(x) 34 | print '1-norm =', x.norm(PETSc.NormType.NORM_1) 35 | print '2-norm =', x.norm() 36 | print 'Infinity-norm =', x.norm(PETSc.NormType.NORM_INFINITY) 37 | print 'Minimum element in x (index, value) =', x.min() 38 | print 'Maximum element in x (index, value) =', x.max() 39 | --------------------------------------------------------------------------------