Actual source code: ex184.c

  1: static char help[] = "Example of inverting a block diagonal matrix.\n"
  2:                      "\n";

  4: #include <petscmat.h>

  6: int main(int argc, char **args)
  7: {
  8:   Mat          A, A_inv;
  9:   PetscMPIInt  rank, size;
 10:   PetscInt     M, m, bs, rstart, rend, j, x, y, pass, row;
 11:   PetscInt    *dnnz;
 12:   PetscScalar *v;
 13:   Vec          X, Y;
 14:   PetscReal    norm;

 16:   PetscFunctionBeginUser;
 17:   PetscCall(PetscInitialize(&argc, &args, NULL, help));
 18:   PetscCallMPI(MPI_Comm_size(PETSC_COMM_WORLD, &size));
 19:   PetscCallMPI(MPI_Comm_rank(PETSC_COMM_WORLD, &rank));

 21:   PetscOptionsBegin(PETSC_COMM_WORLD, NULL, "ex184", "Mat");
 22:   M = 8;
 23:   PetscCall(PetscOptionsGetInt(NULL, NULL, "-mat_size", &M, NULL));
 24:   bs = 3;
 25:   PetscCall(PetscOptionsGetInt(NULL, NULL, "-mat_block_size", &bs, NULL));
 26:   PetscOptionsEnd();

 28:   PetscCall(MatCreate(PETSC_COMM_WORLD, &A));
 29:   PetscCall(MatSetFromOptions(A));
 30:   PetscCall(MatSetSizes(A, PETSC_DECIDE, PETSC_DECIDE, M * bs, M * bs));
 31:   PetscCall(MatSetBlockSize(A, bs));
 32:   PetscCall(MatSetUp(A)); /* called so that MatGetLocalSize() will work */
 33:   PetscCall(MatGetLocalSize(A, &m, NULL));
 34:   PetscCall(PetscMalloc1(m / bs, &dnnz));
 35:   for (j = 0; j < m / bs; j++) dnnz[j] = 1;
 36:   PetscCall(MatXAIJSetPreallocation(A, bs, dnnz, NULL, NULL, NULL));
 37:   PetscCall(PetscFree(dnnz));

 39:   PetscCall(PetscMalloc1(bs * bs, &v));
 40:   PetscCall(MatGetOwnershipRange(A, &rstart, &rend));
 41:   /* pass 2 re-assembles new values into the nonzero pattern of pass 1 and pass 3 changes values
 42:      through MatZeroRows(); after each the check must run against an inverse that
 43:      MatInvertBlockDiagonal() recomputed rather than took from its cache */
 44:   for (pass = 1; pass <= 3; pass++) {
 45:     if (pass < 3) {
 46:       for (j = rstart / bs; j < rend / bs; j++) {
 47:         for (x = 0; x < bs; x++) {
 48:           for (y = 0; y < bs; y++) {
 49:             if (x == y) v[y + bs * x] = 2 * bs * pass;
 50:             else v[y + bs * x] = (-1 * (x < y) - 2 * (x > y)) * pass;
 51:           }
 52:         }
 53:         PetscCall(MatSetValuesBlocked(A, 1, &j, 1, &j, v, INSERT_VALUES));
 54:       }
 55:       PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
 56:       PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
 57:     } else {
 58:       row = rstart;
 59:       PetscCall(MatZeroRows(A, 1, &row, 2 * bs, NULL, NULL));
 60:     }

 62:     /* check that A  = inv(inv(A)) */
 63:     PetscCall(MatCreate(PETSC_COMM_WORLD, &A_inv));
 64:     PetscCall(MatSetFromOptions(A_inv));
 65:     PetscCall(MatInvertBlockDiagonalMat(A, A_inv));

 67:     /* Test A_inv * A on a random vector */
 68:     PetscCall(MatCreateVecs(A, &X, &Y));
 69:     PetscCall(VecSetRandom(X, NULL));
 70:     PetscCall(MatMult(A, X, Y));
 71:     PetscCall(VecScale(X, -1));
 72:     PetscCall(MatMultAdd(A_inv, Y, X, X));
 73:     PetscCall(VecNorm(X, NORM_MAX, &norm));
 74:     if (norm > PETSC_SMALL) {
 75:       PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Norm of error exceeds tolerance on pass %" PetscInt_FMT ".\nInverse of block diagonal A\n", pass));
 76:       PetscCall(MatView(A_inv, PETSC_VIEWER_STDOUT_WORLD));
 77:     }

 79:     PetscCall(MatDestroy(&A_inv));
 80:     PetscCall(VecDestroy(&X));
 81:     PetscCall(VecDestroy(&Y));
 82:   }
 83:   PetscCall(PetscFree(v));
 84:   PetscCall(MatDestroy(&A));

 86:   PetscCall(PetscFinalize());
 87:   return 0;
 88: }

 90: /*TEST
 91:   test:
 92:     suffix: seqaij
 93:     args: -mat_type seqaij -mat_size 12 -mat_block_size 3
 94:     nsize: 1
 95:     output_file: output/empty.out
 96:   test:
 97:     suffix: seqbaij
 98:     args: -mat_type seqbaij -mat_size 12 -mat_block_size 3
 99:     nsize: 1
100:     output_file: output/empty.out
101:   test:
102:     suffix: mpiaij
103:     args: -mat_type mpiaij -mat_size 12 -mat_block_size 3
104:     nsize: 2
105:     output_file: output/empty.out
106:   test:
107:     suffix: mpibaij
108:     args: -mat_type mpibaij -mat_size 12 -mat_block_size 3
109:     nsize: 2
110:     output_file: output/empty.out
111: TEST*/