Actual source code: ex87.c

  1: #include <petscksp.h>
  2: #include <petsc/private/petscimpl.h>

  4: static char help[] = "Solves a saddle-point linear system using PCHPDDM.\n\n";

  6: static PetscErrorCode MatAndISLoad(const char *prefix, const char *identifier, Mat A, IS is, Mat N, PetscMPIInt rank, PetscMPIInt size);

  8: int main(int argc, char **args)
  9: {
 10:   Vec               b, x;            /* computed solution and RHS */
 11:   Mat               A[4], aux[2], S; /* linear system matrix */
 12:   KSP               ksp, *subksp;    /* linear solver context */
 13:   PC                pc;
 14:   IS                is[2];
 15:   PetscMPIInt       rank, size;
 16:   PetscInt          m, M, n, N, id = 0;
 17:   PetscViewer       viewer;
 18:   const char *const system[] = {"elasticity", "stokes"};
 19:   /* "elasticity":
 20:    *    2D linear elasticity with rubber-like and steel-like material coefficients, i.e., Poisson's ratio \in {0.4999, 0.35} and Young's modulus \in {0.01 GPa, 200.0 GPa}
 21:    *      discretized by order 2 (resp. 0) Lagrange finite elements in displacements (resp. pressure) on a triangle mesh
 22:    * "stokes":
 23:    *    2D lid-driven cavity with constant viscosity
 24:    *      discretized by order 2 (resp. 1) Lagrange finite elements, i.e., lowest-order Taylor--Hood finite elements, in velocities (resp. pressure) on a triangle mesh
 25:    *      if the option -empty_A11 is not set (or set to false), a pressure with a zero mean-value is computed
 26:    */
 27:   char      dir[PETSC_MAX_PATH_LEN], prefix[PETSC_MAX_PATH_LEN];
 28:   PetscBool flg[4] = {PETSC_FALSE, PETSC_FALSE, PETSC_FALSE, PETSC_FALSE};

 30:   PetscFunctionBeginUser;
 31:   PetscCall(PetscInitialize(&argc, &args, NULL, help));
 32:   PetscCallMPI(MPI_Comm_size(PETSC_COMM_WORLD, &size));
 33:   PetscCheck(size == 4, PETSC_COMM_WORLD, PETSC_ERR_USER, "This example requires 4 processes");
 34:   PetscCall(PetscOptionsGetEList(NULL, NULL, "-system", system, PETSC_STATIC_ARRAY_LENGTH(system), &id, NULL));
 35:   if (id == 1) PetscCall(PetscOptionsGetBool(NULL, NULL, "-empty_A11", flg, NULL));
 36:   PetscCallMPI(MPI_Comm_rank(PETSC_COMM_WORLD, &rank));
 37:   for (PetscInt i = 0; i < 2; ++i) {
 38:     PetscCall(MatCreate(PETSC_COMM_WORLD, A + (i ? 3 : 0)));
 39:     PetscCall(ISCreate(PETSC_COMM_SELF, is + i));
 40:     PetscCall(MatCreate(PETSC_COMM_SELF, aux + i));
 41:   }
 42:   PetscCall(PetscStrncpy(dir, ".", sizeof(dir)));
 43:   PetscCall(PetscOptionsGetString(NULL, NULL, "-load_dir", dir, sizeof(dir), NULL));
 44:   /* loading matrices and auxiliary data for the diagonal blocks */
 45:   PetscCall(PetscSNPrintf(prefix, sizeof(prefix), "%s/%s", dir, id == 1 ? "B" : "A"));
 46:   PetscCall(MatAndISLoad(prefix, "00", A[0], is[0], aux[0], rank, size));
 47:   PetscCall(MatAndISLoad(prefix, "11", A[3], is[1], aux[1], rank, size));
 48:   /* loading the off-diagonal block with a coherent row/column layout */
 49:   PetscCall(MatCreate(PETSC_COMM_WORLD, A + 2));
 50:   PetscCall(MatGetLocalSize(A[0], &n, NULL));
 51:   PetscCall(MatGetSize(A[0], &N, NULL));
 52:   PetscCall(MatGetLocalSize(A[3], &m, NULL));
 53:   PetscCall(MatGetSize(A[3], &M, NULL));
 54:   PetscCall(MatSetSizes(A[2], m, n, M, N));
 55:   PetscCall(MatSetUp(A[2]));
 56:   PetscCall(PetscSNPrintf(prefix, sizeof(prefix), "%s/%s10.dat", dir, id == 1 ? "B" : "A"));
 57:   PetscCall(PetscViewerBinaryOpen(PETSC_COMM_WORLD, prefix, FILE_MODE_READ, &viewer));
 58:   PetscCall(MatLoad(A[2], viewer));
 59:   PetscCall(PetscViewerDestroy(&viewer));
 60:   /* transposing the off-diagonal block */
 61:   PetscCall(PetscOptionsGetBool(NULL, NULL, "-transpose", flg + 1, NULL));
 62:   PetscCall(PetscOptionsGetBool(NULL, NULL, "-permute", flg + 2, NULL));
 63:   PetscCall(PetscOptionsGetBool(NULL, NULL, "-explicit", flg + 3, NULL));
 64:   if (flg[1]) {
 65:     if (flg[2]) {
 66:       PetscCall(MatTranspose(A[2], MAT_INITIAL_MATRIX, A + 1));
 67:       PetscCall(MatDestroy(A + 2));
 68:     }
 69:     if (!flg[3]) PetscCall(MatCreateTranspose(A[2 - flg[2]], A + 1 + flg[2]));
 70:     else PetscCall(MatTranspose(A[2 - flg[2]], MAT_INITIAL_MATRIX, A + 1 + flg[2]));
 71:   } else {
 72:     if (flg[2]) {
 73:       PetscCall(MatHermitianTranspose(A[2], MAT_INITIAL_MATRIX, A + 1));
 74:       PetscCall(MatDestroy(A + 2));
 75:     }
 76:     if (!flg[3]) PetscCall(MatCreateHermitianTranspose(A[2 - flg[2]], A + 1 + flg[2]));
 77:     else PetscCall(MatHermitianTranspose(A[2 - flg[2]], MAT_INITIAL_MATRIX, A + 1 + flg[2]));
 78:   }
 79:   if (flg[0]) PetscCall(MatDestroy(A + 3));
 80:   else {
 81:     PetscCall(PetscOptionsGetBool(NULL, NULL, "-diagonal_A11", flg, NULL));
 82:     if (flg[0]) {
 83:       PetscCall(MatDestroy(A + 3));
 84:       PetscCall(MatCreateConstantDiagonal(PETSC_COMM_WORLD, m, m, M, M, PETSC_SMALL, A + 3));
 85:     }
 86:   }
 87:   /* global coefficient matrix */
 88:   PetscCall(MatCreateNest(PETSC_COMM_WORLD, 2, NULL, 2, NULL, A, &S));
 89:   PetscCall(KSPCreate(PETSC_COMM_WORLD, &ksp));
 90:   PetscCall(KSPSetOperators(ksp, S, S));
 91:   PetscCall(KSPGetPC(ksp, &pc));
 92:   /* outer preconditioner */
 93:   PetscCall(PCSetType(pc, PCFIELDSPLIT));
 94:   PetscCall(PCFieldSplitSetType(pc, PC_COMPOSITE_SCHUR));
 95:   PetscCall(PCFieldSplitSetSchurPre(pc, PC_FIELDSPLIT_SCHUR_PRE_SELF, NULL));
 96:   PetscCall(PCSetFromOptions(pc));
 97:   PetscCall(PCSetUp(pc));
 98:   PetscCall(PCFieldSplitGetSubKSP(pc, &n, &subksp));
 99:   PetscCall(KSPGetPC(subksp[0], &pc));
100:   /* inner preconditioner associated to top-left block */
101: #if defined(PETSC_HAVE_HPDDM) && defined(PETSC_HAVE_DYNAMIC_LIBRARIES) && defined(PETSC_USE_SHARED_LIBRARIES)
102:   PetscCall(PCSetType(pc, PCHPDDM));
103:   PetscCall(PCHPDDMSetAuxiliaryMat(pc, is[0], aux[0], NULL, NULL));
104: #endif
105:   PetscCall(PCSetFromOptions(pc));
106:   PetscCall(KSPGetPC(subksp[1], &pc));
107:   /* inner preconditioner associated to Schur complement, which will be set internally to a PCKSP */
108: #if defined(PETSC_HAVE_HPDDM) && defined(PETSC_HAVE_DYNAMIC_LIBRARIES) && defined(PETSC_USE_SHARED_LIBRARIES)
109:   PetscCall(PCSetType(pc, PCHPDDM));
110:   if (!flg[0]) PetscCall(PCHPDDMSetAuxiliaryMat(pc, is[1], aux[1], NULL, NULL));
111: #endif
112:   PetscCall(PCSetFromOptions(pc));
113:   PetscCall(PetscFree(subksp));
114:   PetscCall(KSPSetFromOptions(ksp));
115:   PetscCall(MatCreateVecs(S, &b, &x));
116:   PetscCall(PetscSNPrintf(prefix, sizeof(prefix), "%s/rhs_%s.dat", dir, id == 1 ? "B" : "A"));
117:   PetscCall(PetscViewerBinaryOpen(PETSC_COMM_WORLD, prefix, FILE_MODE_READ, &viewer));
118:   PetscCall(VecLoad(b, viewer));
119:   PetscCall(PetscViewerDestroy(&viewer));
120:   PetscCall(KSPSolve(ksp, b, x));
121:   flg[1] = PETSC_FALSE;
122:   PetscCall(PetscOptionsGetBool(NULL, NULL, "-viewer", flg + 1, NULL));
123:   if (flg[1]) PetscCall(PCView(pc, PETSC_VIEWER_STDOUT_WORLD));
124:   flg[1] = PETSC_FALSE;
125:   PetscCall(PetscOptionsGetBool(NULL, NULL, "-successive_solves", flg + 1, NULL));
126:   if (flg[1]) {
127:     KSPConvergedReason reason[2];
128:     PetscInt           iterations[2];
129:     PetscCall(KSPGetConvergedReason(ksp, reason));
130:     PetscCall(KSPGetTotalIterations(ksp, iterations));
131:     PetscCall(KSPMonitorCancel(ksp));
132:     PetscCall(PetscOptionsClearValue(NULL, "-ksp_monitor"));
133:     PetscCall(PetscObjectStateIncrease((PetscObject)S));
134:     PetscCall(KSPSetUp(ksp));
135:     PetscCall(KSPGetPC(ksp, &pc));
136:     PetscCall(PCFieldSplitGetSubKSP(pc, &n, &subksp));
137:     PetscCall(KSPGetPC(subksp[0], &pc));
138: #if defined(PETSC_HAVE_HPDDM) && defined(PETSC_HAVE_DYNAMIC_LIBRARIES) && defined(PETSC_USE_SHARED_LIBRARIES)
139:     PetscCall(PCHPDDMSetAuxiliaryMat(pc, is[0], aux[0], NULL, NULL));
140: #endif
141:     PetscCall(PCSetFromOptions(pc));
142:     PetscCall(KSPGetPC(subksp[1], &pc));
143: #if defined(PETSC_HAVE_HPDDM) && defined(PETSC_HAVE_DYNAMIC_LIBRARIES) && defined(PETSC_USE_SHARED_LIBRARIES)
144:     if (!flg[0]) PetscCall(PCHPDDMSetAuxiliaryMat(pc, is[1], aux[1], NULL, NULL));
145: #endif
146:     PetscCall(PCSetFromOptions(pc));
147:     PetscCall(PetscFree(subksp));
148:     PetscCall(KSPSolve(ksp, b, x));
149:     PetscCall(KSPGetConvergedReason(ksp, reason + 1));
150:     PetscCall(KSPGetTotalIterations(ksp, iterations + 1));
151:     iterations[1] -= iterations[0];
152:     PetscCheck(reason[0] == reason[1] && PetscAbs(iterations[0] - iterations[1]) <= 3, PetscObjectComm((PetscObject)ksp), PETSC_ERR_PLIB, "Successive calls to KSPSolve() did not converge for the same reason (%s v. %s) or with the same number of iterations (+/- 3, %" PetscInt_FMT " v. %" PetscInt_FMT ")", KSPConvergedReasons[reason[0]], KSPConvergedReasons[reason[1]], iterations[0], iterations[1]);
153:   }
154:   PetscCall(VecDestroy(&x));
155:   PetscCall(VecDestroy(&b));
156:   PetscCall(KSPDestroy(&ksp));
157:   PetscCall(MatDestroy(&S));
158:   PetscCall(MatDestroy(A + 1));
159:   PetscCall(MatDestroy(A + 2));
160:   for (PetscInt i = 0; i < 2; ++i) {
161:     PetscCall(MatDestroy(A + (i ? 3 : 0)));
162:     PetscCall(MatDestroy(aux + i));
163:     PetscCall(ISDestroy(is + i));
164:   }
165:   PetscCall(PetscFinalize());
166:   return 0;
167: }

169: PetscErrorCode MatAndISLoad(const char *prefix, const char *identifier, Mat A, IS is, Mat aux, PetscMPIInt rank, PetscMPIInt size)
170: {
171:   IS              sizes;
172:   const PetscInt *idx;
173:   PetscViewer     viewer;
174:   char            name[PETSC_MAX_PATH_LEN];

176:   PetscFunctionBeginUser;
177:   PetscCall(PetscSNPrintf(name, sizeof(name), "%s%s_sizes_%d_%d.dat", prefix, identifier, rank, size));
178:   PetscCall(PetscViewerBinaryOpen(PETSC_COMM_SELF, name, FILE_MODE_READ, &viewer));
179:   PetscCall(ISCreate(PETSC_COMM_SELF, &sizes));
180:   PetscCall(ISLoad(sizes, viewer));
181:   PetscCall(ISGetIndices(sizes, &idx));
182:   PetscCall(MatSetSizes(A, idx[0], idx[1], idx[2], idx[3]));
183:   PetscCall(MatSetUp(A));
184:   PetscCall(ISRestoreIndices(sizes, &idx));
185:   PetscCall(ISDestroy(&sizes));
186:   PetscCall(PetscViewerDestroy(&viewer));
187:   PetscCall(PetscSNPrintf(name, sizeof(name), "%s%s.dat", prefix, identifier));
188:   PetscCall(PetscViewerBinaryOpen(PETSC_COMM_WORLD, name, FILE_MODE_READ, &viewer));
189:   PetscCall(MatLoad(A, viewer));
190:   PetscCall(PetscViewerDestroy(&viewer));
191:   PetscCall(PetscSNPrintf(name, sizeof(name), "%s%s_is_%d_%d.dat", prefix, identifier, rank, size));
192:   PetscCall(PetscViewerBinaryOpen(PETSC_COMM_SELF, name, FILE_MODE_READ, &viewer));
193:   PetscCall(ISLoad(is, viewer));
194:   PetscCall(PetscViewerDestroy(&viewer));
195:   PetscCall(PetscSNPrintf(name, sizeof(name), "%s%s_aux_%d_%d.dat", prefix, identifier, rank, size));
196:   PetscCall(PetscViewerBinaryOpen(PETSC_COMM_SELF, name, FILE_MODE_READ, &viewer));
197:   PetscCall(MatLoad(aux, viewer));
198:   PetscCall(PetscViewerDestroy(&viewer));
199:   PetscFunctionReturn(PETSC_SUCCESS);
200: }

202: /*TEST

204:    testset:
205:       requires: datafilespath hpddm slepc double !complex !defined(PETSC_USE_64BIT_INDICES) defined(PETSC_HAVE_DYNAMIC_LIBRARIES) defined(PETSC_USE_SHARED_LIBRARIES)
206:       nsize: 4
207:       args: -load_dir ${DATAFILESPATH}/matrices/hpddm/GENEO -ksp_monitor -ksp_rtol 1e-4 -fieldsplit_ksp_max_it 100 -fieldsplit_pc_hpddm_levels_1_eps_nev 10 -fieldsplit_pc_hpddm_levels_1_st_share_sub_ksp -fieldsplit_pc_hpddm_has_neumann -fieldsplit_pc_hpddm_define_subdomains -fieldsplit_1_pc_hpddm_schur_precondition geneo -fieldsplit_pc_hpddm_coarse_pc_type redundant -fieldsplit_pc_hpddm_coarse_redundant_pc_type cholesky -fieldsplit_pc_hpddm_levels_1_sub_pc_type lu -fieldsplit_ksp_type fgmres -ksp_type fgmres -ksp_max_it 10 -fieldsplit_1_pc_hpddm_coarse_correction balanced -fieldsplit_1_pc_hpddm_levels_1_eps_gen_non_hermitian -fieldsplit_1_pc_hpddm_coarse_p 2
208:       test:
209:         requires: mumps
210:         suffix: 1
211:         args: -viewer -system {{elasticity stokes}separate output} -fieldsplit_1_pc_hpddm_ksp_pc_side left -fieldsplit_1_pc_hpddm_levels_1_sub_mat_mumps_icntl_26 1
212:         filter: grep -v -e "action of " -e "                            " -e "block size" -e "total: nonzeros=" -e "using I-node" -e "aij" -e "transpose" -e "diagonal" -e "total number of" -e "                rows="
213:       test:
214:         requires: mumps
215:         suffix: 2
216:         output_file: output/ex87_1_system-stokes.out
217:         args: -viewer -system stokes -empty_A11 -transpose {{false true}shared output} -permute {{false true}shared output} -fieldsplit_1_pc_hpddm_ksp_pc_side right -fieldsplit_1_pc_hpddm_coarse_mat_type baij -fieldsplit_1_pc_hpddm_levels_1_sub_mat_mumps_icntl_26 1 -explicit {{false true}shared output}
218:         filter: grep -v -e "action of " -e "                            " -e "block size" -e "total: nonzeros=" -e "using I-node" -e "aij" -e "transpose" -e "diagonal" -e "total number of" -e "                rows=" | sed -e "s/      right preconditioning/      left preconditioning/g" -e "s/      using UNPRECONDITIONED/      using PRECONDITIONED/g"
219:       test:
220:         suffix: 1_petsc
221:         args: -system {{elasticity stokes}separate output} -fieldsplit_1_pc_hpddm_ksp_pc_side left -fieldsplit_1_pc_hpddm_levels_1_sub_pc_factor_mat_solver_type petsc -fieldsplit_1_pc_hpddm_levels_1_eps_threshold 0.3 -permute
222:       test:
223:         suffix: 2_petsc
224:         output_file: output/ex87_1_petsc_system-stokes.out
225:         args: -system stokes -empty_A11 -transpose -fieldsplit_1_pc_hpddm_ksp_pc_side right -fieldsplit_1_pc_hpddm_levels_1_sub_pc_factor_mat_solver_type petsc -fieldsplit_1_pc_hpddm_coarse_mat_type baij -fieldsplit_1_pc_hpddm_levels_1_eps_threshold 0.3 -fieldsplit_1_pc_hpddm_levels_1_sub_pc_factor_shift_type inblocks -successive_solves
226:         filter: sed -e "s/type: transpose/type: hermitiantranspose/g"
227:       test:
228:         suffix: threshold
229:         output_file: output/ex87_1_petsc_system-elasticity.out
230:         args: -fieldsplit_1_pc_hpddm_ksp_pc_side left -fieldsplit_1_pc_hpddm_levels_1_eps_threshold 0.2 -fieldsplit_1_pc_hpddm_coarse_mat_type {{baij sbaij}shared output} -successive_solves
231:    testset:
232:       requires: datafilespath hpddm slepc double !complex !defined(PETSC_USE_64BIT_INDICES) defined(PETSC_HAVE_DYNAMIC_LIBRARIES) defined(PETSC_USE_SHARED_LIBRARIES)
233:       nsize: 4
234:       args: -load_dir ${DATAFILESPATH}/matrices/hpddm/GENEO -ksp_monitor -ksp_rtol 1e-4 -fieldsplit_ksp_max_it 100 -fieldsplit_pc_hpddm_levels_1_st_share_sub_ksp -fieldsplit_pc_hpddm_define_subdomains -fieldsplit_1_pc_hpddm_schur_precondition geneo -fieldsplit_pc_hpddm_coarse_pc_type redundant -fieldsplit_pc_hpddm_coarse_redundant_pc_type cholesky -fieldsplit_pc_hpddm_levels_1_sub_pc_type lu -fieldsplit_ksp_type fgmres -ksp_type fgmres -ksp_max_it 10 -fieldsplit_1_pc_hpddm_coarse_correction balanced -fieldsplit_1_pc_hpddm_levels_1_eps_gen_non_hermitian -fieldsplit_1_pc_hpddm_coarse_p 2 -system stokes -fieldsplit_1_pc_hpddm_ksp_pc_side left -fieldsplit_1_pc_hpddm_levels_1_sub_pc_factor_mat_solver_type petsc -fieldsplit_1_pc_hpddm_levels_1_eps_threshold 0.3
235:       test:
236:         suffix: diagonal
237:         output_file: output/ex87_1_petsc_system-stokes.out
238:         args: -fieldsplit_pc_hpddm_levels_1_eps_nev 10 -fieldsplit_0_pc_hpddm_has_neumann -diagonal_A11 {{false true}shared output}
239:       test:
240:         suffix: harmonic_overlap_2
241:         output_file: output/ex87_1_petsc_system-stokes.out
242:         args: -fieldsplit_0_pc_hpddm_harmonic_overlap 2 -fieldsplit_0_pc_hpddm_levels_1_svd_nsv 20 -diagonal_A11

244:    test:
245:       requires: datafilespath double !complex !defined(PETSC_USE_64BIT_INDICES) !hpddm !memkind
246:       nsize: 4
247:       suffix: selfp
248:       output_file: output/ex41_1.out
249:       filter: grep -v "CONVERGED_RTOL iterations"
250:       args: -load_dir ${DATAFILESPATH}/matrices/hpddm/GENEO -system stokes -ksp_rtol 1e-4 -ksp_converged_reason -ksp_max_it 30 -pc_type fieldsplit -pc_fieldsplit_type schur -fieldsplit_ksp_type preonly -pc_fieldsplit_schur_precondition selfp -fieldsplit_pc_type bjacobi -fieldsplit_sub_pc_type lu -transpose {{false true}shared output} -fieldsplit_1_mat_schur_complement_ainv_type lump

252: TEST*/