xref: /petsc/src/mat/tutorials/ex3.c (revision b122ec5aa1bd4469eb4e0673542fb7de3f411254)
1 static char help[] = "Illustration of MatIS using a 1D Laplacian assembly\n\n";
2 
3 /*
4   MatIS means that the matrix is not assembled. The easiest way to think of this (for me) is that processes do not have
5   to hold full matrix rows. One process can hold part of row i, and another processes can hold another part. However, there
6   are still the same number of global rows. The local size here is not the size of the local IS block, which we call the
7   overlap size, since that is a property only of MatIS. It is the size of the local piece of the vector you multiply in
8   MatMult(). This allows PETSc to understand the parallel layout of the Vec, and how it matches the Mat. If you only know
9   the overlap size when assembling, it is best to use PETSC_DECIDE for the local size in the creation routine, so that PETSc
10   automatically partitions the unknowns.
11 
12   Each P_1 element matrix for a cell will be
13 
14     /  1 -1 \
15     \ -1  1 /
16 
17   so that the assembled matrix has a tridiagonal [-1, 2, -1] pattern. We will use 1 cell per process for illustration,
18   and allow PETSc to decide the ownership.
19 */
20 
21 #include <petscmat.h>
22 
23 int main(int argc, char **argv) {
24   MPI_Comm               comm;
25   Mat                    A;
26   Vec                    x, y;
27   ISLocalToGlobalMapping map;
28   PetscScalar            elemMat[4] = {1.0, -1.0, -1.0, 1.0};
29   PetscReal              error;
30   PetscInt               overlapSize = 2, globalIdx[2];
31   PetscMPIInt            rank, size;
32 
33   CHKERRQ(PetscInitialize(&argc, &argv, NULL, help));
34   comm = PETSC_COMM_WORLD;
35   CHKERRMPI(MPI_Comm_rank(comm, &rank));
36   CHKERRMPI(MPI_Comm_size(comm, &size));
37   /* Create local-to-global map */
38   globalIdx[0] = rank;
39   globalIdx[1] = rank+1;
40   CHKERRQ(ISLocalToGlobalMappingCreate(comm, 1, overlapSize, globalIdx, PETSC_COPY_VALUES, &map));
41   /* Create matrix */
42   CHKERRQ(MatCreateIS(comm, 1, PETSC_DECIDE, PETSC_DECIDE, size+1, size+1, map, map, &A));
43   CHKERRQ(PetscObjectSetName((PetscObject) A, "A"));
44   CHKERRQ(ISLocalToGlobalMappingDestroy(&map));
45   CHKERRQ(MatISSetPreallocation(A, overlapSize, NULL, overlapSize, NULL));
46   CHKERRQ(MatSetValues(A, 2, globalIdx, 2, globalIdx, elemMat, ADD_VALUES));
47   CHKERRQ(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
48   CHKERRQ(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
49   /* Check that the constant vector is in the nullspace */
50   CHKERRQ(MatCreateVecs(A, &x, &y));
51   CHKERRQ(VecSet(x, 1.0));
52   CHKERRQ(PetscObjectSetName((PetscObject) x, "x"));
53   CHKERRQ(VecViewFromOptions(x, NULL, "-x_view"));
54   CHKERRQ(MatMult(A, x, y));
55   CHKERRQ(PetscObjectSetName((PetscObject) y, "y"));
56   CHKERRQ(VecViewFromOptions(y, NULL, "-y_view"));
57   CHKERRQ(VecNorm(y, NORM_2, &error));
58   PetscCheckFalse(error > PETSC_SMALL,comm, PETSC_ERR_ARG_WRONG, "Invalid output, x should be in the nullspace of A");
59   /* Check that an interior unit vector gets mapped to something of 1-norm 4 */
60   if (size > 1) {
61     CHKERRQ(VecSet(x, 0.0));
62     CHKERRQ(VecSetValue(x, 1, 1.0, INSERT_VALUES));
63     CHKERRQ(VecAssemblyBegin(x));
64     CHKERRQ(VecAssemblyEnd(x));
65     CHKERRQ(MatMult(A, x, y));
66     CHKERRQ(VecNorm(y, NORM_1, &error));
67     PetscCheckFalse(PetscAbsReal(error - 4) > PETSC_SMALL,comm, PETSC_ERR_ARG_WRONG, "Invalid output for matrix multiply");
68   }
69   /* Cleanup */
70   CHKERRQ(MatDestroy(&A));
71   CHKERRQ(VecDestroy(&x));
72   CHKERRQ(VecDestroy(&y));
73   CHKERRQ(PetscFinalize());
74   return 0;
75 }
76 
77 /*TEST
78 
79   test:
80     suffix: 0
81     requires:
82     args:
83 
84   test:
85     suffix: 1
86     nsize: 3
87     args:
88 
89   test:
90     suffix: 2
91     nsize: 7
92     args:
93 
94 TEST*/
95