Actual source code: ex23.c
1: static char help[] = "Tests the use of interface functions for MATIS matrices and conversion routines.\n";
3: #include <petscmat.h>
5: PetscErrorCode TestMatZeroRows(Mat, Mat, PetscBool, IS, PetscScalar);
6: PetscErrorCode CheckMat(Mat, Mat, PetscBool, const char *);
8: int main(int argc, char **args)
9: {
10: Mat A, B, A2, B2, T;
11: Mat Aee, Aeo, Aoe, Aoo;
12: Mat *mats, *Asub, *Bsub;
13: Vec x, y;
14: MatInfo info;
15: ISLocalToGlobalMapping cmap, rmap;
16: IS is, is2, reven, rodd, ceven, codd;
17: IS *rows, *cols;
18: IS irow[2], icol[2];
19: PetscLayout rlayout, clayout;
20: const PetscInt *rrange, *crange;
21: MatType lmtype;
22: PetscScalar diag = 2.;
23: PetscInt n, m, i, lm, ln;
24: PetscInt rst, ren, cst, cen, nr, nc;
25: PetscMPIInt rank, size, lrank, rrank;
26: PetscBool testT, squaretest, isaij;
27: PetscBool permute = PETSC_FALSE, negmap = PETSC_FALSE, repmap = PETSC_FALSE, allow_repeated = PETSC_TRUE;
28: PetscBool diffmap = PETSC_TRUE, symmetric = PETSC_FALSE, issymmetric, test_matlab = PETSC_FALSE;
30: PetscFunctionBeginUser;
31: PetscCall(PetscInitialize(&argc, &args, (char *)0, help));
32: PetscCallMPI(MPI_Comm_rank(PETSC_COMM_WORLD, &rank));
33: PetscCallMPI(MPI_Comm_size(PETSC_COMM_WORLD, &size));
34: m = n = 2 * size;
35: PetscCall(PetscOptionsGetBool(NULL, NULL, "-symmetric", &symmetric, NULL));
36: PetscCall(PetscOptionsGetInt(NULL, NULL, "-m", &m, NULL));
37: PetscCall(PetscOptionsGetInt(NULL, NULL, "-n", &n, NULL));
38: PetscCall(PetscOptionsGetBool(NULL, NULL, "-negmap", &negmap, NULL));
39: PetscCall(PetscOptionsGetBool(NULL, NULL, "-repmap", &repmap, NULL));
40: PetscCall(PetscOptionsGetBool(NULL, NULL, "-permmap", &permute, NULL));
41: PetscCall(PetscOptionsGetBool(NULL, NULL, "-diffmap", &diffmap, NULL));
42: PetscCall(PetscOptionsGetBool(NULL, NULL, "-allow_repeated", &allow_repeated, NULL));
43: PetscCall(PetscOptionsGetBool(NULL, NULL, "-test_matlab", &test_matlab, NULL));
44: PetscCheck(size == 1 || m >= 4, PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONG, "Number of rows should be larger or equal 4 for parallel runs");
45: PetscCheck(size != 1 || m >= 2, PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONG, "Number of rows should be larger or equal 2 for uniprocessor runs");
46: PetscCheck(n >= 2, PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONG, "Number of cols should be larger or equal 2");
48: /* create a MATIS matrix */
49: PetscCall(MatCreate(PETSC_COMM_WORLD, &A));
50: PetscCall(MatSetSizes(A, PETSC_DECIDE, PETSC_DECIDE, m, n));
51: PetscCall(MatSetType(A, MATIS));
52: PetscCall(MatSetFromOptions(A));
53: if (!negmap && !repmap) {
54: /* This is not the proper setting for MATIS for finite elements, it is just used to test the routines
55: Here we use a one-to-one correspondence between local row/column spaces and global row/column spaces
56: Equivalent to passing NULL for the mapping */
57: PetscCall(ISCreateStride(PETSC_COMM_WORLD, n, 0, 1, &is));
58: } else if (negmap && !repmap) { /* non repeated but with negative indices */
59: PetscCall(ISCreateStride(PETSC_COMM_WORLD, n + 2, -2, 1, &is));
60: } else if (!negmap && repmap) { /* non negative but repeated indices */
61: IS isl[2];
63: PetscCall(ISCreateStride(PETSC_COMM_WORLD, n, 0, 1, &isl[0]));
64: PetscCall(ISCreateStride(PETSC_COMM_WORLD, n, n - 1, -1, &isl[1]));
65: PetscCall(ISConcatenate(PETSC_COMM_WORLD, 2, isl, &is));
66: PetscCall(ISDestroy(&isl[0]));
67: PetscCall(ISDestroy(&isl[1]));
68: } else { /* negative and repeated indices */
69: IS isl[2];
71: PetscCall(ISCreateStride(PETSC_COMM_WORLD, n + 1, -1, 1, &isl[0]));
72: PetscCall(ISCreateStride(PETSC_COMM_WORLD, n + 1, n - 1, -1, &isl[1]));
73: PetscCall(ISConcatenate(PETSC_COMM_WORLD, 2, isl, &is));
74: PetscCall(ISDestroy(&isl[0]));
75: PetscCall(ISDestroy(&isl[1]));
76: }
77: PetscCall(ISLocalToGlobalMappingCreateIS(is, &cmap));
78: PetscCall(ISDestroy(&is));
80: if (m != n || diffmap) {
81: PetscCall(ISCreateStride(PETSC_COMM_WORLD, m, permute ? m - 1 : 0, permute ? -1 : 1, &is));
82: PetscCall(ISLocalToGlobalMappingCreateIS(is, &rmap));
83: PetscCall(ISDestroy(&is));
84: } else {
85: PetscCall(PetscObjectReference((PetscObject)cmap));
86: rmap = cmap;
87: }
89: PetscCall(MatISSetAllowRepeated(A, allow_repeated));
90: PetscCall(MatSetLocalToGlobalMapping(A, rmap, cmap));
91: PetscCall(MatISStoreL2L(A, PETSC_FALSE));
92: PetscCall(MatISSetPreallocation(A, 3, NULL, 3, NULL));
93: PetscCall(MatSetOption(A, MAT_NEW_NONZERO_ALLOCATION_ERR, (PetscBool) !(repmap || negmap))); /* I do not want to precompute the pattern */
94: PetscCall(ISLocalToGlobalMappingGetSize(rmap, &lm));
95: PetscCall(ISLocalToGlobalMappingGetSize(cmap, &ln));
96: for (i = 0; i < lm; i++) {
97: PetscScalar v[3];
98: PetscInt cols[3];
100: cols[0] = (i - 1 + n) % n;
101: cols[1] = i % n;
102: cols[2] = (i + 1) % n;
103: v[0] = -1. * (symmetric ? PetscMin(i + 1, cols[0] + 1) : i + 1);
104: v[1] = 2. * (symmetric ? PetscMin(i + 1, cols[1] + 1) : i + 1);
105: v[2] = -1. * (symmetric ? PetscMin(i + 1, cols[2] + 1) : i + 1);
106: PetscCall(ISGlobalToLocalMappingApply(cmap, IS_GTOLM_MASK, 3, cols, NULL, cols));
107: PetscCall(MatSetValuesLocal(A, 1, &i, 3, cols, v, ADD_VALUES));
108: }
109: PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
110: PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
112: /* activate tests for square matrices with same maps only */
113: PetscCall(MatHasCongruentLayouts(A, &squaretest));
114: if (squaretest && rmap != cmap) {
115: PetscInt nr, nc;
117: PetscCall(ISLocalToGlobalMappingGetSize(rmap, &nr));
118: PetscCall(ISLocalToGlobalMappingGetSize(cmap, &nc));
119: if (nr != nc) squaretest = PETSC_FALSE;
120: else {
121: const PetscInt *idxs1, *idxs2;
123: PetscCall(ISLocalToGlobalMappingGetIndices(rmap, &idxs1));
124: PetscCall(ISLocalToGlobalMappingGetIndices(cmap, &idxs2));
125: PetscCall(PetscArraycmp(idxs1, idxs2, nr, &squaretest));
126: PetscCall(ISLocalToGlobalMappingRestoreIndices(rmap, &idxs1));
127: PetscCall(ISLocalToGlobalMappingRestoreIndices(cmap, &idxs2));
128: }
129: PetscCall(MPIU_Allreduce(MPI_IN_PLACE, &squaretest, 1, MPIU_BOOL, MPI_LAND, PetscObjectComm((PetscObject)A)));
130: }
131: if (negmap && repmap) squaretest = PETSC_FALSE;
133: /* test MatISGetLocalMat */
134: PetscCall(MatISGetLocalMat(A, &B));
135: PetscCall(MatGetType(B, &lmtype));
137: /* test MatGetInfo */
138: PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Test MatGetInfo\n"));
139: PetscCall(MatGetInfo(A, MAT_LOCAL, &info));
140: PetscCall(PetscViewerASCIIPushSynchronized(PETSC_VIEWER_STDOUT_WORLD));
141: PetscCall(PetscViewerASCIISynchronizedPrintf(PETSC_VIEWER_STDOUT_WORLD, "Process %2d: %" PetscInt_FMT " %" PetscInt_FMT " %" PetscInt_FMT " %" PetscInt_FMT " %" PetscInt_FMT "\n", PetscGlobalRank, (PetscInt)info.nz_used, (PetscInt)info.nz_allocated,
142: (PetscInt)info.nz_unneeded, (PetscInt)info.assemblies, (PetscInt)info.mallocs));
143: PetscCall(PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD));
144: PetscCall(MatGetInfo(A, MAT_GLOBAL_MAX, &info));
145: PetscCall(PetscViewerASCIIPrintf(PETSC_VIEWER_STDOUT_WORLD, "GlobalMax : %" PetscInt_FMT " %" PetscInt_FMT " %" PetscInt_FMT " %" PetscInt_FMT " %" PetscInt_FMT "\n", (PetscInt)info.nz_used, (PetscInt)info.nz_allocated, (PetscInt)info.nz_unneeded,
146: (PetscInt)info.assemblies, (PetscInt)info.mallocs));
147: PetscCall(MatGetInfo(A, MAT_GLOBAL_SUM, &info));
148: PetscCall(PetscViewerASCIIPrintf(PETSC_VIEWER_STDOUT_WORLD, "GlobalSum : %" PetscInt_FMT " %" PetscInt_FMT " %" PetscInt_FMT " %" PetscInt_FMT " %" PetscInt_FMT "\n", (PetscInt)info.nz_used, (PetscInt)info.nz_allocated, (PetscInt)info.nz_unneeded,
149: (PetscInt)info.assemblies, (PetscInt)info.mallocs));
151: /* test MatIsSymmetric */
152: PetscCall(MatIsSymmetric(A, 0.0, &issymmetric));
153: PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Test MatIsSymmetric: %d\n", issymmetric));
155: /* Create a MPIAIJ matrix, same as A */
156: PetscCall(MatCreate(PETSC_COMM_WORLD, &B));
157: PetscCall(MatSetSizes(B, PETSC_DECIDE, PETSC_DECIDE, m, n));
158: PetscCall(MatSetType(B, MATAIJ));
159: PetscCall(MatSetFromOptions(B));
160: PetscCall(MatSetLocalToGlobalMapping(B, rmap, cmap));
161: PetscCall(MatMPIAIJSetPreallocation(B, 3, NULL, 3, NULL));
162: PetscCall(MatMPIBAIJSetPreallocation(B, 1, 3, NULL, 3, NULL));
163: #if defined(PETSC_HAVE_HYPRE)
164: PetscCall(MatHYPRESetPreallocation(B, 3, NULL, 3, NULL));
165: #endif
166: PetscCall(MatISSetPreallocation(B, 3, NULL, 3, NULL));
167: PetscCall(MatSetOption(B, MAT_NEW_NONZERO_ALLOCATION_ERR, (PetscBool) !(repmap || negmap))); /* I do not want to precompute the pattern */
168: for (i = 0; i < lm; i++) {
169: PetscScalar v[3];
170: PetscInt cols[3];
172: cols[0] = (i - 1 + n) % n;
173: cols[1] = i % n;
174: cols[2] = (i + 1) % n;
175: v[0] = -1. * (symmetric ? PetscMin(i + 1, cols[0] + 1) : i + 1);
176: v[1] = 2. * (symmetric ? PetscMin(i + 1, cols[1] + 1) : i + 1);
177: v[2] = -1. * (symmetric ? PetscMin(i + 1, cols[2] + 1) : i + 1);
178: PetscCall(ISGlobalToLocalMappingApply(cmap, IS_GTOLM_MASK, 3, cols, NULL, cols));
179: PetscCall(MatSetValuesLocal(B, 1, &i, 3, cols, v, ADD_VALUES));
180: }
181: PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY));
182: PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY));
184: /* test MatView */
185: PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Test MatView\n"));
186: PetscCall(MatView(A, NULL));
187: PetscCall(MatView(B, NULL));
189: /* test MATLAB ASCII view */
190: if (test_matlab) { /* output is different when using real or complex numbers */
191: PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Test MatView ASCII MATLAB\n"));
192: PetscCall(PetscViewerPushFormat(PETSC_VIEWER_STDOUT_WORLD, PETSC_VIEWER_ASCII_MATLAB));
193: PetscCall(MatView(A, PETSC_VIEWER_STDOUT_WORLD));
194: PetscCall(PetscViewerPopFormat(PETSC_VIEWER_STDOUT_WORLD));
195: }
197: /* test CheckMat */
198: PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Test CheckMat\n"));
199: PetscCall(CheckMat(A, B, PETSC_FALSE, "CheckMat"));
201: /* test binary MatView/MatLoad */
202: {
203: PetscMPIInt color = rank % 2;
204: MPI_Comm comm;
205: char name[PETSC_MAX_PATH_LEN];
206: PetscViewer wview, cview, sview, view;
207: Mat A2;
209: PetscCallMPI(MPI_Comm_split(PETSC_COMM_WORLD, color, rank, &comm));
211: PetscCall(PetscSNPrintf(name, PETSC_STATIC_ARRAY_LENGTH(name), "world_is"));
212: PetscCall(PetscViewerBinaryOpen(PETSC_COMM_WORLD, name, FILE_MODE_WRITE, &wview));
213: PetscCall(PetscSNPrintf(name, PETSC_STATIC_ARRAY_LENGTH(name), "seq_is_%d", rank));
214: PetscCall(PetscViewerBinaryOpen(PETSC_COMM_SELF, name, FILE_MODE_WRITE, &sview));
215: PetscCall(PetscSNPrintf(name, PETSC_STATIC_ARRAY_LENGTH(name), "color_is_%d", color));
216: PetscCall(PetscViewerBinaryOpen(comm, name, FILE_MODE_WRITE, &cview));
217: PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Test MatView on binary world\n"));
218: PetscCall(MatView(A, wview));
219: PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Test MatView on binary self\n"));
220: PetscCall(MatView(A, sview));
221: PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Test MatView on binary subcomm\n"));
222: PetscCall(MatView(A, cview));
223: PetscCall(PetscViewerDestroy(&wview));
224: PetscCall(PetscViewerDestroy(&cview));
225: PetscCall(PetscViewerDestroy(&sview));
227: /* Load a world matrix */
228: PetscCall(MatCreate(PETSC_COMM_WORLD, &A2));
229: PetscCall(MatSetType(A2, MATIS));
230: PetscCall(PetscViewerPushFormat(PETSC_VIEWER_STDOUT_WORLD, PETSC_VIEWER_ASCII_INFO_DETAIL));
232: /* Read back the same matrix and check */
233: PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Test MatLoad from world\n"));
234: PetscCall(PetscViewerBinaryOpen(PETSC_COMM_WORLD, "world_is", FILE_MODE_READ, &view));
235: PetscCall(MatLoad(A2, view));
236: PetscCall(CheckMat(A, A2, PETSC_TRUE, "Load"));
237: PetscCall(MatView(A2, PETSC_VIEWER_STDOUT_WORLD));
238: PetscCall(PetscViewerDestroy(&view));
240: /* Read the matrix from rank 0 only */
241: PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Test MatLoad from self\n"));
242: PetscCall(PetscViewerBinaryOpen(PETSC_COMM_WORLD, "seq_is_0", FILE_MODE_READ, &view));
243: PetscCall(MatLoad(A2, view));
244: PetscCall(MatView(A2, PETSC_VIEWER_STDOUT_WORLD));
245: PetscCall(PetscViewerDestroy(&view));
247: /* Read the matrix from subcomm */
248: PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Test MatLoad from subcomm\n"));
249: PetscCall(PetscViewerBinaryOpen(PETSC_COMM_WORLD, "color_is_0", FILE_MODE_READ, &view));
250: PetscCall(MatLoad(A2, view));
251: PetscCall(MatView(A2, PETSC_VIEWER_STDOUT_WORLD));
252: PetscCall(PetscViewerDestroy(&view));
254: PetscCall(PetscViewerPopFormat(PETSC_VIEWER_STDOUT_WORLD));
255: PetscCall(MatDestroy(&A2));
257: /* now load the original matrix from color 0 only processes */
258: if (!color) {
259: PetscCall(PetscPrintf(comm, "Test subcomm MatLoad from world\n"));
260: PetscCall(MatCreate(comm, &A2));
261: PetscCall(MatSetType(A2, MATIS));
262: PetscCall(PetscViewerPushFormat(PETSC_VIEWER_STDOUT_(comm), PETSC_VIEWER_ASCII_INFO_DETAIL));
263: PetscCall(PetscViewerBinaryOpen(comm, "world_is", FILE_MODE_READ, &view));
264: PetscCall(MatLoad(A2, view));
265: PetscCall(MatView(A2, PETSC_VIEWER_STDOUT_(comm)));
266: PetscCall(PetscViewerDestroy(&view));
267: PetscCall(PetscViewerPopFormat(PETSC_VIEWER_STDOUT_(comm)));
268: PetscCall(MatDestroy(&A2));
269: }
271: PetscCallMPI(MPI_Comm_free(&comm));
272: }
274: /* test MatDuplicate and MatAXPY */
275: PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Test MatDuplicate and MatAXPY\n"));
276: PetscCall(MatDuplicate(A, MAT_COPY_VALUES, &A2));
277: PetscCall(CheckMat(A, A2, PETSC_FALSE, "MatDuplicate and MatAXPY"));
279: /* test MatConvert */
280: PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Test MatConvert_IS_XAIJ\n"));
281: PetscCall(MatConvert(A2, MATAIJ, MAT_INITIAL_MATRIX, &B2));
282: PetscCall(CheckMat(B, B2, PETSC_TRUE, "MatConvert_IS_XAIJ MAT_INITIAL_MATRIX"));
283: PetscCall(MatConvert(A2, MATAIJ, MAT_REUSE_MATRIX, &B2));
284: PetscCall(CheckMat(B, B2, PETSC_TRUE, "MatConvert_IS_XAIJ MAT_REUSE_MATRIX"));
285: PetscCall(MatConvert(A2, MATAIJ, MAT_INPLACE_MATRIX, &A2));
286: PetscCall(CheckMat(B, A2, PETSC_TRUE, "MatConvert_IS_XAIJ MAT_INPLACE_MATRIX"));
287: PetscCall(MatDestroy(&A2));
288: PetscCall(MatDestroy(&B2));
289: PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Test MatConvert_XAIJ_IS\n"));
290: PetscCall(MatDuplicate(B, MAT_COPY_VALUES, &B2));
291: PetscCall(MatConvert(B2, MATIS, MAT_INITIAL_MATRIX, &A2));
292: PetscCall(CheckMat(A, A2, PETSC_TRUE, "MatConvert_XAIJ_IS MAT_INITIAL_MATRIX"));
293: PetscCall(MatConvert(B2, MATIS, MAT_REUSE_MATRIX, &A2));
294: PetscCall(CheckMat(A, A2, PETSC_TRUE, "MatConvert_XAIJ_IS MAT_REUSE_MATRIX"));
295: PetscCall(MatConvert(B2, MATIS, MAT_INPLACE_MATRIX, &B2));
296: PetscCall(CheckMat(A, B2, PETSC_TRUE, "MatConvert_XAIJ_IS MAT_INPLACE_MATRIX"));
297: PetscCall(MatDestroy(&A2));
298: PetscCall(MatDestroy(&B2));
299: PetscCall(PetscStrcmp(lmtype, MATSEQAIJ, &isaij));
300: if (size == 1 && isaij) { /* tests special code paths in MatConvert_IS_XAIJ */
301: PetscInt ri, ci, rr[3] = {0, 1, 0}, cr[4] = {1, 2, 0, 1}, rk[3] = {0, 2, 1}, ck[4] = {1, 0, 3, 2};
302: ISLocalToGlobalMapping tcmap, trmap;
304: for (ri = 0; ri < 2; ri++) {
305: PetscInt *r;
307: r = (PetscInt *)(ri == 0 ? rr : rk);
308: for (ci = 0; ci < 2; ci++) {
309: PetscInt *c, rb, cb;
311: c = (PetscInt *)(ci == 0 ? cr : ck);
312: for (rb = 1; rb < 4; rb++) {
313: PetscCall(ISCreateBlock(PETSC_COMM_SELF, rb, 3, r, PETSC_COPY_VALUES, &is));
314: PetscCall(ISLocalToGlobalMappingCreateIS(is, &trmap));
315: PetscCall(ISDestroy(&is));
316: for (cb = 1; cb < 4; cb++) {
317: Mat T, lT, T2;
318: char testname[256];
320: PetscCall(PetscSNPrintf(testname, sizeof(testname), "MatConvert_IS_XAIJ special case (%" PetscInt_FMT " %" PetscInt_FMT ", bs %" PetscInt_FMT " %" PetscInt_FMT ")", ri, ci, rb, cb));
321: PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Test %s\n", testname));
323: PetscCall(ISCreateBlock(PETSC_COMM_SELF, cb, 4, c, PETSC_COPY_VALUES, &is));
324: PetscCall(ISLocalToGlobalMappingCreateIS(is, &tcmap));
325: PetscCall(ISDestroy(&is));
327: PetscCall(MatCreate(PETSC_COMM_SELF, &T));
328: PetscCall(MatSetSizes(T, PETSC_DECIDE, PETSC_DECIDE, rb * 3, cb * 4));
329: PetscCall(MatSetType(T, MATIS));
330: PetscCall(MatSetLocalToGlobalMapping(T, trmap, tcmap));
331: PetscCall(ISLocalToGlobalMappingDestroy(&tcmap));
332: PetscCall(MatISGetLocalMat(T, &lT));
333: PetscCall(MatSetType(lT, MATSEQAIJ));
334: PetscCall(MatSeqAIJSetPreallocation(lT, cb * 4, NULL));
335: PetscCall(MatSetRandom(lT, NULL));
336: PetscCall(MatConvert(lT, lmtype, MAT_INPLACE_MATRIX, &lT));
337: PetscCall(MatISRestoreLocalMat(T, &lT));
338: PetscCall(MatAssemblyBegin(T, MAT_FINAL_ASSEMBLY));
339: PetscCall(MatAssemblyEnd(T, MAT_FINAL_ASSEMBLY));
341: PetscCall(MatConvert(T, MATAIJ, MAT_INITIAL_MATRIX, &T2));
342: PetscCall(CheckMat(T, T2, PETSC_TRUE, "MAT_INITIAL_MATRIX"));
343: PetscCall(MatConvert(T, MATAIJ, MAT_REUSE_MATRIX, &T2));
344: PetscCall(CheckMat(T, T2, PETSC_TRUE, "MAT_REUSE_MATRIX"));
345: PetscCall(MatDestroy(&T2));
346: PetscCall(MatDuplicate(T, MAT_COPY_VALUES, &T2));
347: PetscCall(MatConvert(T2, MATAIJ, MAT_INPLACE_MATRIX, &T2));
348: PetscCall(CheckMat(T, T2, PETSC_TRUE, "MAT_INPLACE_MATRIX"));
349: PetscCall(MatDestroy(&T));
350: PetscCall(MatDestroy(&T2));
351: }
352: PetscCall(ISLocalToGlobalMappingDestroy(&trmap));
353: }
354: }
355: }
356: }
358: /* test MatDiagonalScale */
359: PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Test MatDiagonalScale\n"));
360: PetscCall(MatDuplicate(A, MAT_COPY_VALUES, &A2));
361: PetscCall(MatDuplicate(B, MAT_COPY_VALUES, &B2));
362: PetscCall(MatCreateVecs(A, &x, &y));
363: PetscCall(VecSetRandom(x, NULL));
364: if (issymmetric) {
365: PetscCall(VecCopy(x, y));
366: } else {
367: PetscCall(VecSetRandom(y, NULL));
368: PetscCall(VecScale(y, 8.));
369: }
370: PetscCall(MatDiagonalScale(A2, y, x));
371: PetscCall(MatDiagonalScale(B2, y, x));
372: PetscCall(CheckMat(A2, B2, PETSC_FALSE, "MatDiagonalScale"));
373: PetscCall(MatDestroy(&A2));
374: PetscCall(MatDestroy(&B2));
375: PetscCall(VecDestroy(&x));
376: PetscCall(VecDestroy(&y));
378: /* test MatPtAP (A IS and B AIJ) */
379: if (isaij && m == n) {
380: PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Test MatPtAP\n"));
381: /* There's a bug in MatCreateSubMatrices_MPIAIJ I cannot figure out */
382: if (!allow_repeated || !repmap || size == 1) {
383: PetscCall(MatISStoreL2L(A, PETSC_TRUE));
384: PetscCall(MatPtAP(A, B, MAT_INITIAL_MATRIX, PETSC_DEFAULT, &A2));
385: PetscCall(MatPtAP(B, B, MAT_INITIAL_MATRIX, PETSC_DEFAULT, &B2));
386: PetscCall(CheckMat(A2, B2, PETSC_FALSE, "MatPtAP MAT_INITIAL_MATRIX"));
387: PetscCall(MatPtAP(A, B, MAT_REUSE_MATRIX, PETSC_DEFAULT, &A2));
388: PetscCall(CheckMat(A2, B2, PETSC_FALSE, "MatPtAP MAT_REUSE_MATRIX"));
389: PetscCall(MatDestroy(&A2));
390: PetscCall(MatDestroy(&B2));
391: }
392: }
394: /* test MatGetLocalSubMatrix */
395: PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Test MatGetLocalSubMatrix\n"));
396: PetscCall(MatDuplicate(A, MAT_DO_NOT_COPY_VALUES, &A2));
397: PetscCall(ISCreateStride(PETSC_COMM_SELF, lm / 2 + lm % 2, 0, 2, &reven));
398: PetscCall(ISComplement(reven, 0, lm, &rodd));
399: PetscCall(ISCreateStride(PETSC_COMM_SELF, ln / 2 + ln % 2, 0, 2, &ceven));
400: PetscCall(ISComplement(ceven, 0, ln, &codd));
401: PetscCall(MatGetLocalSubMatrix(A2, reven, ceven, &Aee));
402: PetscCall(MatGetLocalSubMatrix(A2, reven, codd, &Aeo));
403: PetscCall(MatGetLocalSubMatrix(A2, rodd, ceven, &Aoe));
404: PetscCall(MatGetLocalSubMatrix(A2, rodd, codd, &Aoo));
405: for (i = 0; i < lm; i++) {
406: PetscInt j, je, jo, colse[3], colso[3];
407: PetscScalar ve[3], vo[3];
408: PetscScalar v[3];
409: PetscInt cols[3];
410: PetscInt row = i / 2;
412: cols[0] = (i - 1 + n) % n;
413: cols[1] = i % n;
414: cols[2] = (i + 1) % n;
415: v[0] = -1. * (symmetric ? PetscMin(i + 1, cols[0] + 1) : i + 1);
416: v[1] = 2. * (symmetric ? PetscMin(i + 1, cols[1] + 1) : i + 1);
417: v[2] = -1. * (symmetric ? PetscMin(i + 1, cols[2] + 1) : i + 1);
418: PetscCall(ISGlobalToLocalMappingApply(cmap, IS_GTOLM_MASK, 3, cols, NULL, cols));
419: for (j = 0, je = 0, jo = 0; j < 3; j++) {
420: if (cols[j] % 2) {
421: vo[jo] = v[j];
422: colso[jo++] = cols[j] / 2;
423: } else {
424: ve[je] = v[j];
425: colse[je++] = cols[j] / 2;
426: }
427: }
428: if (i % 2) {
429: PetscCall(MatSetValuesLocal(Aoe, 1, &row, je, colse, ve, ADD_VALUES));
430: PetscCall(MatSetValuesLocal(Aoo, 1, &row, jo, colso, vo, ADD_VALUES));
431: } else {
432: PetscCall(MatSetValuesLocal(Aee, 1, &row, je, colse, ve, ADD_VALUES));
433: PetscCall(MatSetValuesLocal(Aeo, 1, &row, jo, colso, vo, ADD_VALUES));
434: }
435: }
436: PetscCall(MatRestoreLocalSubMatrix(A2, reven, ceven, &Aee));
437: PetscCall(MatRestoreLocalSubMatrix(A2, reven, codd, &Aeo));
438: PetscCall(MatRestoreLocalSubMatrix(A2, rodd, ceven, &Aoe));
439: PetscCall(MatRestoreLocalSubMatrix(A2, rodd, codd, &Aoo));
440: PetscCall(ISDestroy(&reven));
441: PetscCall(ISDestroy(&ceven));
442: PetscCall(ISDestroy(&rodd));
443: PetscCall(ISDestroy(&codd));
444: PetscCall(MatAssemblyBegin(A2, MAT_FINAL_ASSEMBLY));
445: PetscCall(MatAssemblyEnd(A2, MAT_FINAL_ASSEMBLY));
446: PetscCall(MatAXPY(A2, -1., A, SAME_NONZERO_PATTERN));
447: PetscCall(CheckMat(A2, NULL, PETSC_FALSE, "MatGetLocalSubMatrix"));
448: PetscCall(MatDestroy(&A2));
450: /* test MatConvert_Nest_IS */
451: testT = PETSC_FALSE;
452: PetscCall(PetscOptionsGetBool(NULL, NULL, "-test_trans", &testT, NULL));
454: PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Test MatConvert_Nest_IS\n"));
455: nr = 2;
456: nc = 2;
457: PetscCall(PetscOptionsGetInt(NULL, NULL, "-nr", &nr, NULL));
458: PetscCall(PetscOptionsGetInt(NULL, NULL, "-nc", &nc, NULL));
459: if (testT) {
460: PetscCall(MatGetOwnershipRange(A, &cst, &cen));
461: PetscCall(MatGetOwnershipRangeColumn(A, &rst, &ren));
462: } else {
463: PetscCall(MatGetOwnershipRange(A, &rst, &ren));
464: PetscCall(MatGetOwnershipRangeColumn(A, &cst, &cen));
465: }
466: PetscCall(PetscMalloc3(nr, &rows, nc, &cols, 2 * nr * nc, &mats));
467: for (i = 0; i < nr * nc; i++) {
468: if (testT) {
469: PetscCall(MatCreateTranspose(A, &mats[i]));
470: PetscCall(MatTranspose(B, MAT_INITIAL_MATRIX, &mats[i + nr * nc]));
471: } else {
472: PetscCall(MatDuplicate(A, MAT_COPY_VALUES, &mats[i]));
473: PetscCall(MatDuplicate(B, MAT_COPY_VALUES, &mats[i + nr * nc]));
474: }
475: }
476: for (i = 0; i < nr; i++) PetscCall(ISCreateStride(PETSC_COMM_WORLD, ren - rst, i + rst, nr, &rows[i]));
477: for (i = 0; i < nc; i++) PetscCall(ISCreateStride(PETSC_COMM_WORLD, cen - cst, i + cst, nc, &cols[i]));
478: PetscCall(MatCreateNest(PETSC_COMM_WORLD, nr, rows, nc, cols, mats, &A2));
479: PetscCall(MatCreateNest(PETSC_COMM_WORLD, nr, rows, nc, cols, mats + nr * nc, &B2));
480: for (i = 0; i < nr; i++) PetscCall(ISDestroy(&rows[i]));
481: for (i = 0; i < nc; i++) PetscCall(ISDestroy(&cols[i]));
482: for (i = 0; i < 2 * nr * nc; i++) PetscCall(MatDestroy(&mats[i]));
483: PetscCall(PetscFree3(rows, cols, mats));
484: PetscCall(MatConvert(B2, MATAIJ, MAT_INITIAL_MATRIX, &T));
485: PetscCall(MatDestroy(&B2));
486: PetscCall(MatConvert(A2, MATIS, MAT_INITIAL_MATRIX, &B2));
487: PetscCall(CheckMat(B2, T, PETSC_TRUE, "MatConvert_Nest_IS MAT_INITIAL_MATRIX"));
488: PetscCall(MatConvert(A2, MATIS, MAT_REUSE_MATRIX, &B2));
489: PetscCall(CheckMat(B2, T, PETSC_TRUE, "MatConvert_Nest_IS MAT_REUSE_MATRIX"));
490: PetscCall(MatDestroy(&B2));
491: PetscCall(MatConvert(A2, MATIS, MAT_INPLACE_MATRIX, &A2));
492: PetscCall(CheckMat(A2, T, PETSC_TRUE, "MatConvert_Nest_IS MAT_INPLACE_MATRIX"));
493: PetscCall(MatDestroy(&T));
494: PetscCall(MatDestroy(&A2));
496: /* test MatCreateSubMatrix */
497: PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Test MatCreateSubMatrix\n"));
498: if (rank == 0) {
499: PetscCall(ISCreateStride(PETSC_COMM_WORLD, 1, 1, 1, &is));
500: PetscCall(ISCreateStride(PETSC_COMM_WORLD, 2, 0, 1, &is2));
501: } else if (rank == 1) {
502: PetscCall(ISCreateStride(PETSC_COMM_WORLD, 1, 0, 1, &is));
503: if (n > 3) {
504: PetscCall(ISCreateStride(PETSC_COMM_WORLD, 1, 3, 1, &is2));
505: } else {
506: PetscCall(ISCreateStride(PETSC_COMM_WORLD, 0, 0, 1, &is2));
507: }
508: } else if (rank == 2 && n > 4) {
509: PetscCall(ISCreateStride(PETSC_COMM_WORLD, 0, 0, 1, &is));
510: PetscCall(ISCreateStride(PETSC_COMM_WORLD, n - 4, 4, 1, &is2));
511: } else {
512: PetscCall(ISCreateStride(PETSC_COMM_WORLD, 0, 0, 1, &is));
513: PetscCall(ISCreateStride(PETSC_COMM_WORLD, 0, 0, 1, &is2));
514: }
515: PetscCall(MatCreateSubMatrix(A, is, is, MAT_INITIAL_MATRIX, &A2));
516: PetscCall(MatCreateSubMatrix(B, is, is, MAT_INITIAL_MATRIX, &B2));
517: PetscCall(CheckMat(A2, B2, PETSC_TRUE, "first MatCreateSubMatrix"));
519: PetscCall(MatCreateSubMatrix(A, is, is, MAT_REUSE_MATRIX, &A2));
520: PetscCall(MatCreateSubMatrix(B, is, is, MAT_REUSE_MATRIX, &B2));
521: PetscCall(CheckMat(A2, B2, PETSC_FALSE, "reuse MatCreateSubMatrix"));
522: PetscCall(MatDestroy(&A2));
523: PetscCall(MatDestroy(&B2));
525: if (!issymmetric) {
526: PetscCall(MatCreateSubMatrix(A, is, is2, MAT_INITIAL_MATRIX, &A2));
527: PetscCall(MatCreateSubMatrix(B, is, is2, MAT_INITIAL_MATRIX, &B2));
528: PetscCall(MatCreateSubMatrix(A, is, is2, MAT_REUSE_MATRIX, &A2));
529: PetscCall(MatCreateSubMatrix(B, is, is2, MAT_REUSE_MATRIX, &B2));
530: PetscCall(CheckMat(A2, B2, PETSC_FALSE, "second MatCreateSubMatrix"));
531: }
533: PetscCall(MatDestroy(&A2));
534: PetscCall(MatDestroy(&B2));
535: PetscCall(ISDestroy(&is));
536: PetscCall(ISDestroy(&is2));
538: /* test MatCreateSubMatrices */
539: PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Test MatCreateSubMatrices\n"));
540: PetscCall(MatGetLayouts(A, &rlayout, &clayout));
541: PetscCall(PetscLayoutGetRanges(rlayout, &rrange));
542: PetscCall(PetscLayoutGetRanges(clayout, &crange));
543: lrank = (size + rank - 1) % size;
544: rrank = (rank + 1) % size;
545: PetscCall(ISCreateStride(PETSC_COMM_SELF, (rrange[lrank + 1] - rrange[lrank]), rrange[lrank], 1, &irow[0]));
546: PetscCall(ISCreateStride(PETSC_COMM_SELF, (crange[rrank + 1] - crange[rrank]), crange[rrank], 1, &icol[0]));
547: PetscCall(ISCreateStride(PETSC_COMM_SELF, (rrange[rrank + 1] - rrange[rrank]), rrange[rrank], 1, &irow[1]));
548: PetscCall(ISCreateStride(PETSC_COMM_SELF, (crange[lrank + 1] - crange[lrank]), crange[lrank], 1, &icol[1]));
549: PetscCall(MatCreateSubMatrices(A, 2, irow, icol, MAT_INITIAL_MATRIX, &Asub));
550: PetscCall(MatCreateSubMatrices(B, 2, irow, icol, MAT_INITIAL_MATRIX, &Bsub));
551: PetscCall(CheckMat(Asub[0], Bsub[0], PETSC_FALSE, "MatCreateSubMatrices[0]"));
552: PetscCall(CheckMat(Asub[1], Bsub[1], PETSC_FALSE, "MatCreateSubMatrices[1]"));
553: PetscCall(MatCreateSubMatrices(A, 2, irow, icol, MAT_REUSE_MATRIX, &Asub));
554: PetscCall(MatCreateSubMatrices(B, 2, irow, icol, MAT_REUSE_MATRIX, &Bsub));
555: PetscCall(CheckMat(Asub[0], Bsub[0], PETSC_FALSE, "MatCreateSubMatrices[0]"));
556: PetscCall(CheckMat(Asub[1], Bsub[1], PETSC_FALSE, "MatCreateSubMatrices[1]"));
557: PetscCall(MatDestroySubMatrices(2, &Asub));
558: PetscCall(MatDestroySubMatrices(2, &Bsub));
559: PetscCall(ISDestroy(&irow[0]));
560: PetscCall(ISDestroy(&irow[1]));
561: PetscCall(ISDestroy(&icol[0]));
562: PetscCall(ISDestroy(&icol[1]));
564: /* Create an IS required by MatZeroRows(): just rank zero provides the rows to be eliminated */
565: if (size > 1) {
566: if (rank == 0) {
567: PetscInt st, len;
569: st = (m + 1) / 2;
570: len = PetscMin(m / 2, PetscMax(m - (m + 1) / 2 - 1, 0));
571: PetscCall(ISCreateStride(PETSC_COMM_WORLD, len, st, 1, &is));
572: } else {
573: PetscCall(ISCreateStride(PETSC_COMM_WORLD, 0, 0, 1, &is));
574: }
575: } else {
576: PetscCall(ISCreateStride(PETSC_COMM_WORLD, 1, 0, 1, &is));
577: }
579: if (squaretest) { /* tests for square matrices only, with same maps for rows and columns */
580: PetscInt *idx0, *idx1, n0, n1;
581: IS Ais[2], Bis[2];
583: /* test MatDiagonalSet */
584: PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Test MatDiagonalSet\n"));
585: PetscCall(MatDuplicate(A, MAT_COPY_VALUES, &A2));
586: PetscCall(MatDuplicate(B, MAT_COPY_VALUES, &B2));
587: PetscCall(MatCreateVecs(A, NULL, &x));
588: PetscCall(VecSetRandom(x, NULL));
589: PetscCall(MatDiagonalSet(A2, x, allow_repeated ? ADD_VALUES : INSERT_VALUES));
590: PetscCall(MatDiagonalSet(B2, x, allow_repeated ? ADD_VALUES : INSERT_VALUES));
591: PetscCall(CheckMat(A2, B2, PETSC_FALSE, "MatDiagonalSet"));
592: PetscCall(VecDestroy(&x));
593: PetscCall(MatDestroy(&A2));
594: PetscCall(MatDestroy(&B2));
596: /* test MatShift (MatShift_IS internally uses MatDiagonalSet_IS with ADD_VALUES) */
597: PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Test MatShift\n"));
598: PetscCall(MatDuplicate(A, MAT_COPY_VALUES, &A2));
599: PetscCall(MatDuplicate(B, MAT_COPY_VALUES, &B2));
600: PetscCall(MatShift(A2, 2.0));
601: PetscCall(MatShift(B2, 2.0));
602: PetscCall(CheckMat(A2, B2, PETSC_FALSE, "MatShift"));
603: PetscCall(MatDestroy(&A2));
604: PetscCall(MatDestroy(&B2));
606: /* nonzero diag value is supported for square matrices only */
607: PetscCall(TestMatZeroRows(A, B, PETSC_TRUE, is, diag));
609: /* test MatIncreaseOverlap */
610: PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Test MatIncreaseOverlap\n"));
611: PetscCall(MatGetOwnershipRange(A, &rst, &ren));
612: n0 = (ren - rst) / 2;
613: n1 = (ren - rst) / 3;
614: PetscCall(PetscMalloc1(n0, &idx0));
615: PetscCall(PetscMalloc1(n1, &idx1));
616: for (i = 0; i < n0; i++) idx0[i] = ren - i - 1;
617: for (i = 0; i < n1; i++) idx1[i] = rst + i;
618: PetscCall(ISCreateGeneral(PETSC_COMM_WORLD, n0, idx0, PETSC_OWN_POINTER, &Ais[0]));
619: PetscCall(ISCreateGeneral(PETSC_COMM_WORLD, n1, idx1, PETSC_OWN_POINTER, &Ais[1]));
620: PetscCall(ISCreateGeneral(PETSC_COMM_WORLD, n0, idx0, PETSC_COPY_VALUES, &Bis[0]));
621: PetscCall(ISCreateGeneral(PETSC_COMM_WORLD, n1, idx1, PETSC_COPY_VALUES, &Bis[1]));
622: PetscCall(MatIncreaseOverlap(A, 2, Ais, 3));
623: PetscCall(MatIncreaseOverlap(B, 2, Bis, 3));
624: /* Non deterministic output! */
625: PetscCall(ISSort(Ais[0]));
626: PetscCall(ISSort(Ais[1]));
627: PetscCall(ISSort(Bis[0]));
628: PetscCall(ISSort(Bis[1]));
629: PetscCall(ISView(Ais[0], NULL));
630: PetscCall(ISView(Bis[0], NULL));
631: PetscCall(ISView(Ais[1], NULL));
632: PetscCall(ISView(Bis[1], NULL));
633: PetscCall(MatCreateSubMatrices(A, 2, Ais, Ais, MAT_INITIAL_MATRIX, &Asub));
634: PetscCall(MatCreateSubMatrices(B, 2, Bis, Ais, MAT_INITIAL_MATRIX, &Bsub));
635: PetscCall(CheckMat(Asub[0], Bsub[0], PETSC_FALSE, "MatIncreaseOverlap[0]"));
636: PetscCall(CheckMat(Asub[1], Bsub[1], PETSC_FALSE, "MatIncreaseOverlap[1]"));
637: PetscCall(MatDestroySubMatrices(2, &Asub));
638: PetscCall(MatDestroySubMatrices(2, &Bsub));
639: PetscCall(ISDestroy(&Ais[0]));
640: PetscCall(ISDestroy(&Ais[1]));
641: PetscCall(ISDestroy(&Bis[0]));
642: PetscCall(ISDestroy(&Bis[1]));
643: }
644: PetscCall(TestMatZeroRows(A, B, squaretest, is, 0.0));
645: PetscCall(ISDestroy(&is));
647: /* test MatTranspose */
648: PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Test MatTranspose\n"));
649: PetscCall(MatTranspose(A, MAT_INITIAL_MATRIX, &A2));
650: PetscCall(MatTranspose(B, MAT_INITIAL_MATRIX, &B2));
651: PetscCall(CheckMat(A2, B2, PETSC_FALSE, "initial matrix MatTranspose"));
653: PetscCall(MatTranspose(A, MAT_REUSE_MATRIX, &A2));
654: PetscCall(CheckMat(A2, B2, PETSC_FALSE, "reuse matrix (not in place) MatTranspose"));
655: PetscCall(MatDestroy(&A2));
657: PetscCall(MatDuplicate(A, MAT_COPY_VALUES, &A2));
658: PetscCall(MatTranspose(A2, MAT_INPLACE_MATRIX, &A2));
659: PetscCall(CheckMat(A2, B2, PETSC_FALSE, "reuse matrix (in place) MatTranspose"));
660: PetscCall(MatDestroy(&A2));
662: PetscCall(MatTranspose(A, MAT_INITIAL_MATRIX, &A2));
663: PetscCall(CheckMat(A2, B2, PETSC_FALSE, "reuse matrix (different type) MatTranspose"));
664: PetscCall(MatDestroy(&A2));
665: PetscCall(MatDestroy(&B2));
667: /* test MatISFixLocalEmpty */
668: if (isaij) {
669: PetscInt r[2];
671: r[0] = 0;
672: r[1] = PetscMin(m, n) - 1;
673: PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Test MatISFixLocalEmpty\n"));
674: PetscCall(MatDuplicate(A, MAT_COPY_VALUES, &A2));
676: PetscCall(MatISFixLocalEmpty(A2, PETSC_TRUE));
677: PetscCall(MatAssemblyBegin(A2, MAT_FINAL_ASSEMBLY));
678: PetscCall(MatAssemblyEnd(A2, MAT_FINAL_ASSEMBLY));
679: PetscCall(CheckMat(A2, B, PETSC_FALSE, "MatISFixLocalEmpty (null)"));
681: PetscCall(MatZeroRows(A2, 2, r, 0.0, NULL, NULL));
682: PetscCall(MatViewFromOptions(A2, NULL, "-fixempty_view"));
683: PetscCall(MatDuplicate(B, MAT_COPY_VALUES, &B2));
684: PetscCall(MatZeroRows(B2, 2, r, 0.0, NULL, NULL));
685: PetscCall(MatISFixLocalEmpty(A2, PETSC_TRUE));
686: PetscCall(MatAssemblyBegin(A2, MAT_FINAL_ASSEMBLY));
687: PetscCall(MatAssemblyEnd(A2, MAT_FINAL_ASSEMBLY));
688: PetscCall(MatViewFromOptions(A2, NULL, "-fixempty_view"));
689: PetscCall(CheckMat(A2, B2, PETSC_FALSE, "MatISFixLocalEmpty (rows)"));
690: PetscCall(MatDestroy(&A2));
692: PetscCall(MatDuplicate(A, MAT_COPY_VALUES, &A2));
693: PetscCall(MatZeroRows(A2, 2, r, 0.0, NULL, NULL));
694: PetscCall(MatTranspose(A2, MAT_INPLACE_MATRIX, &A2));
695: PetscCall(MatTranspose(B2, MAT_INPLACE_MATRIX, &B2));
696: PetscCall(MatViewFromOptions(A2, NULL, "-fixempty_view"));
697: PetscCall(MatISFixLocalEmpty(A2, PETSC_TRUE));
698: PetscCall(MatAssemblyBegin(A2, MAT_FINAL_ASSEMBLY));
699: PetscCall(MatAssemblyEnd(A2, MAT_FINAL_ASSEMBLY));
700: PetscCall(MatViewFromOptions(A2, NULL, "-fixempty_view"));
701: PetscCall(CheckMat(A2, B2, PETSC_FALSE, "MatISFixLocalEmpty (cols)"));
703: PetscCall(MatDestroy(&A2));
704: PetscCall(MatDestroy(&B2));
706: if (squaretest) {
707: PetscCall(MatDuplicate(A, MAT_COPY_VALUES, &A2));
708: PetscCall(MatDuplicate(B, MAT_COPY_VALUES, &B2));
709: PetscCall(MatZeroRowsColumns(A2, 2, r, 0.0, NULL, NULL));
710: PetscCall(MatZeroRowsColumns(B2, 2, r, 0.0, NULL, NULL));
711: PetscCall(MatViewFromOptions(A2, NULL, "-fixempty_view"));
712: PetscCall(MatISFixLocalEmpty(A2, PETSC_TRUE));
713: PetscCall(MatAssemblyBegin(A2, MAT_FINAL_ASSEMBLY));
714: PetscCall(MatAssemblyEnd(A2, MAT_FINAL_ASSEMBLY));
715: PetscCall(MatViewFromOptions(A2, NULL, "-fixempty_view"));
716: PetscCall(CheckMat(A2, B2, PETSC_FALSE, "MatISFixLocalEmpty (rows+cols)"));
717: PetscCall(MatDestroy(&A2));
718: PetscCall(MatDestroy(&B2));
719: }
720: }
722: /* test MatInvertBlockDiagonal
723: special cases for block-diagonal matrices */
724: if (m == n) {
725: ISLocalToGlobalMapping map;
726: Mat Abd, Bbd;
727: IS is, bis;
728: const PetscScalar *isbd, *aijbd;
729: PetscScalar *vals;
730: const PetscInt *sts, *idxs;
731: PetscInt *idxs2, diff, perm, nl, bs, st, en, in;
732: PetscBool ok;
734: for (diff = 0; diff < 3; diff++) {
735: for (perm = 0; perm < 3; perm++) {
736: for (bs = 1; bs < 4; bs++) {
737: PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Test MatInvertBlockDiagonal blockdiag %" PetscInt_FMT " %" PetscInt_FMT " %" PetscInt_FMT " %" PetscInt_FMT "\n", n, diff, perm, bs));
738: PetscCall(PetscMalloc1(bs * bs, &vals));
739: PetscCall(MatGetOwnershipRanges(A, &sts));
740: switch (diff) {
741: case 1: /* inverted layout by processes */
742: in = 1;
743: st = sts[size - rank - 1];
744: en = sts[size - rank];
745: nl = en - st;
746: break;
747: case 2: /* round-robin layout */
748: in = size;
749: st = rank;
750: nl = n / size;
751: if (rank < n % size) nl++;
752: break;
753: default: /* same layout */
754: in = 1;
755: st = sts[rank];
756: en = sts[rank + 1];
757: nl = en - st;
758: break;
759: }
760: PetscCall(ISCreateStride(PETSC_COMM_WORLD, nl, st, in, &is));
761: PetscCall(ISGetLocalSize(is, &nl));
762: PetscCall(ISGetIndices(is, &idxs));
763: PetscCall(PetscMalloc1(nl, &idxs2));
764: for (i = 0; i < nl; i++) {
765: switch (perm) { /* invert some of the indices */
766: case 2:
767: idxs2[i] = rank % 2 ? idxs[i] : idxs[nl - i - 1];
768: break;
769: case 1:
770: idxs2[i] = rank % 2 ? idxs[nl - i - 1] : idxs[i];
771: break;
772: default:
773: idxs2[i] = idxs[i];
774: break;
775: }
776: }
777: PetscCall(ISRestoreIndices(is, &idxs));
778: PetscCall(ISCreateBlock(PETSC_COMM_WORLD, bs, nl, idxs2, PETSC_OWN_POINTER, &bis));
779: PetscCall(ISLocalToGlobalMappingCreateIS(bis, &map));
780: PetscCall(MatCreateIS(PETSC_COMM_WORLD, bs, PETSC_DECIDE, PETSC_DECIDE, bs * n, bs * n, map, map, &Abd));
781: PetscCall(ISLocalToGlobalMappingDestroy(&map));
782: PetscCall(MatISSetPreallocation(Abd, bs, NULL, 0, NULL));
783: for (i = 0; i < nl; i++) {
784: PetscInt b1, b2;
786: for (b1 = 0; b1 < bs; b1++) {
787: for (b2 = 0; b2 < bs; b2++) vals[b1 * bs + b2] = i * bs * bs + b1 * bs + b2 + 1 + (b1 == b2 ? 1.0 : 0);
788: }
789: PetscCall(MatSetValuesBlockedLocal(Abd, 1, &i, 1, &i, vals, INSERT_VALUES));
790: }
791: PetscCall(MatAssemblyBegin(Abd, MAT_FINAL_ASSEMBLY));
792: PetscCall(MatAssemblyEnd(Abd, MAT_FINAL_ASSEMBLY));
793: PetscCall(MatConvert(Abd, MATAIJ, MAT_INITIAL_MATRIX, &Bbd));
794: PetscCall(MatInvertBlockDiagonal(Abd, &isbd));
795: PetscCall(MatInvertBlockDiagonal(Bbd, &aijbd));
796: PetscCall(MatGetLocalSize(Bbd, &nl, NULL));
797: ok = PETSC_TRUE;
798: for (i = 0; i < nl / bs; i++) {
799: PetscInt b1, b2;
801: for (b1 = 0; b1 < bs; b1++) {
802: for (b2 = 0; b2 < bs; b2++) {
803: if (PetscAbsScalar(isbd[i * bs * bs + b1 * bs + b2] - aijbd[i * bs * bs + b1 * bs + b2]) > PETSC_SMALL) ok = PETSC_FALSE;
804: if (!ok) {
805: PetscCall(PetscPrintf(PETSC_COMM_SELF, "[%d] ERROR block %" PetscInt_FMT ", entry %" PetscInt_FMT " %" PetscInt_FMT ": %g %g\n", rank, i, b1, b2, (double)PetscAbsScalar(isbd[i * bs * bs + b1 * bs + b2]), (double)PetscAbsScalar(aijbd[i * bs * bs + b1 * bs + b2])));
806: break;
807: }
808: }
809: if (!ok) break;
810: }
811: if (!ok) break;
812: }
813: PetscCall(MatDestroy(&Abd));
814: PetscCall(MatDestroy(&Bbd));
815: PetscCall(PetscFree(vals));
816: PetscCall(ISDestroy(&is));
817: PetscCall(ISDestroy(&bis));
818: }
819: }
820: }
821: }
823: /* test MatGetDiagonalBlock */
824: PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Test MatGetDiagonalBlock\n"));
825: PetscCall(MatGetDiagonalBlock(A, &A2));
826: PetscCall(MatGetDiagonalBlock(B, &B2));
827: PetscCall(CheckMat(A2, B2, PETSC_FALSE, "MatGetDiagonalBlock"));
828: PetscCall(MatScale(A, 2.0));
829: PetscCall(MatScale(B, 2.0));
830: PetscCall(MatGetDiagonalBlock(A, &A2));
831: PetscCall(MatGetDiagonalBlock(B, &B2));
832: PetscCall(CheckMat(A2, B2, PETSC_FALSE, "MatGetDiagonalBlock"));
834: /* test MatISSetAllowRepeated on a MATIS */
835: PetscCall(MatISSetAllowRepeated(A, allow_repeated));
836: if (allow_repeated) { /* original MATIS maybe with repeated entries, test assembling of local matrices */
837: Mat lA, lA2;
839: for (PetscInt i = 0; i < 1; i++) { /* TODO: make MatScatter inherit from MATSHELL and support MatProducts */
840: PetscBool usemult = PETSC_FALSE;
842: PetscCall(MatDuplicate(A, MAT_COPY_VALUES, &A2));
843: if (i) {
844: Mat tA;
846: usemult = PETSC_TRUE;
847: PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Test MatISSetAllowRepeated(false) with possibly repeated entries and local shell matrices\n"));
848: PetscCall(MatISGetLocalMat(A2, &lA2));
849: PetscCall(MatConvert(lA2, MATSHELL, MAT_INITIAL_MATRIX, &tA));
850: PetscCall(MatISRestoreLocalMat(A2, &lA2));
851: PetscCall(MatISSetLocalMat(A2, tA));
852: PetscCall(MatDestroy(&tA));
853: } else {
854: PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Test MatISSetAllowRepeated(false) with possibly repeated entries\n"));
855: }
856: PetscCall(MatISSetAllowRepeated(A2, PETSC_FALSE));
857: PetscCall(MatISGetLocalMat(A, &lA));
858: PetscCall(MatISGetLocalMat(A2, &lA2));
859: if (!repmap) PetscCall(CheckMat(lA, lA2, usemult, "MatISSetAllowRepeated(false) with non-repeated entries"));
860: PetscCall(MatISRestoreLocalMat(A, &lA));
861: PetscCall(MatISRestoreLocalMat(A2, &lA2));
862: if (repmap) PetscCall(CheckMat(A2, B, usemult, "MatISSetAllowRepeated(false) with repeated entries"));
863: else PetscCall(CheckMat(A2, B, usemult, "MatISSetAllowRepeated(false) with non-repeated entries"));
864: PetscCall(MatDestroy(&A2));
865: }
866: } else { /* original matis with non-repeated entries, this should only recreate the local matrices */
867: Mat lA;
868: PetscBool flg;
870: PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Test MatISSetAllowRepeated(true) with non repeated entries\n"));
871: PetscCall(MatDuplicate(A, MAT_COPY_VALUES, &A2));
872: PetscCall(MatISSetAllowRepeated(A2, PETSC_TRUE));
873: PetscCall(MatISGetLocalMat(A2, &lA));
874: PetscCall(MatAssembled(lA, &flg));
875: PetscCheck(!flg, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local mat should be unassembled");
876: PetscCall(MatISRestoreLocalMat(A2, &lA));
877: PetscCall(MatDestroy(&A2));
878: }
880: /* free testing matrices */
881: PetscCall(ISLocalToGlobalMappingDestroy(&cmap));
882: PetscCall(ISLocalToGlobalMappingDestroy(&rmap));
883: PetscCall(MatDestroy(&A));
884: PetscCall(MatDestroy(&B));
885: PetscCall(PetscFinalize());
886: return 0;
887: }
889: PetscErrorCode CheckMat(Mat A, Mat B, PetscBool usemult, const char *func)
890: {
891: Mat Bcheck;
892: PetscReal error;
894: PetscFunctionBeginUser;
895: if (!usemult && B) {
896: PetscBool hasnorm;
898: PetscCall(MatHasOperation(B, MATOP_NORM, &hasnorm));
899: if (!hasnorm) usemult = PETSC_TRUE;
900: }
901: if (!usemult) {
902: if (B) {
903: MatType Btype;
905: PetscCall(MatGetType(B, &Btype));
906: PetscCall(MatConvert(A, Btype, MAT_INITIAL_MATRIX, &Bcheck));
907: } else {
908: PetscCall(MatConvert(A, MATAIJ, MAT_INITIAL_MATRIX, &Bcheck));
909: }
910: if (B) { /* if B is present, subtract it */
911: PetscCall(MatAXPY(Bcheck, -1., B, DIFFERENT_NONZERO_PATTERN));
912: }
913: PetscCall(MatNorm(Bcheck, NORM_INFINITY, &error));
914: if (error > PETSC_SQRT_MACHINE_EPSILON) {
915: ISLocalToGlobalMapping rl2g, cl2g;
917: PetscCall(PetscObjectSetName((PetscObject)Bcheck, "Bcheck"));
918: PetscCall(MatView(Bcheck, NULL));
919: if (B) {
920: PetscCall(PetscObjectSetName((PetscObject)B, "B"));
921: PetscCall(MatView(B, NULL));
922: PetscCall(MatDestroy(&Bcheck));
923: PetscCall(MatConvert(A, MATAIJ, MAT_INITIAL_MATRIX, &Bcheck));
924: PetscCall(PetscObjectSetName((PetscObject)Bcheck, "Assembled A"));
925: PetscCall(MatView(Bcheck, NULL));
926: }
927: PetscCall(MatDestroy(&Bcheck));
928: PetscCall(PetscObjectSetName((PetscObject)A, "A"));
929: PetscCall(MatView(A, NULL));
930: PetscCall(MatGetLocalToGlobalMapping(A, &rl2g, &cl2g));
931: if (rl2g) PetscCall(ISLocalToGlobalMappingView(rl2g, NULL));
932: if (cl2g) PetscCall(ISLocalToGlobalMappingView(cl2g, NULL));
933: SETERRQ(PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "ERROR ON %s: %g", func, (double)error);
934: }
935: PetscCall(MatDestroy(&Bcheck));
936: } else {
937: PetscBool ok, okt;
939: PetscCall(MatMultEqual(A, B, 3, &ok));
940: PetscCall(MatMultTransposeEqual(A, B, 3, &okt));
941: PetscCheck(ok && okt, PETSC_COMM_WORLD, PETSC_ERR_PLIB, "ERROR ON %s: mult ok ? %d, multtranspose ok ? %d", func, ok, okt);
942: }
943: PetscFunctionReturn(PETSC_SUCCESS);
944: }
946: PetscErrorCode TestMatZeroRows(Mat A, Mat Afull, PetscBool squaretest, IS is, PetscScalar diag)
947: {
948: Mat B, Bcheck, B2 = NULL, lB;
949: Vec x = NULL, b = NULL, b2 = NULL;
950: ISLocalToGlobalMapping l2gr, l2gc;
951: PetscReal error;
952: char diagstr[16];
953: const PetscInt *idxs;
954: PetscInt rst, ren, i, n, N, d;
955: PetscMPIInt rank;
956: PetscBool miss, haszerorows;
958: PetscFunctionBeginUser;
959: if (diag == 0.) {
960: PetscCall(PetscStrncpy(diagstr, "zero", sizeof(diagstr)));
961: } else {
962: PetscCall(PetscStrncpy(diagstr, "nonzero", sizeof(diagstr)));
963: }
964: PetscCall(ISView(is, NULL));
965: PetscCall(MatGetLocalToGlobalMapping(A, &l2gr, &l2gc));
966: /* tests MatDuplicate and MatCopy */
967: if (diag == 0.) {
968: PetscCall(MatDuplicate(A, MAT_COPY_VALUES, &B));
969: } else {
970: PetscCall(MatDuplicate(A, MAT_DO_NOT_COPY_VALUES, &B));
971: PetscCall(MatCopy(A, B, SAME_NONZERO_PATTERN));
972: }
973: PetscCall(MatISGetLocalMat(B, &lB));
974: PetscCall(MatHasOperation(lB, MATOP_ZERO_ROWS, &haszerorows));
975: if (squaretest && haszerorows) {
976: PetscCall(MatCreateVecs(B, &x, &b));
977: PetscCall(MatDuplicate(B, MAT_COPY_VALUES, &B2));
978: PetscCall(VecSetLocalToGlobalMapping(b, l2gr));
979: PetscCall(VecSetLocalToGlobalMapping(x, l2gc));
980: PetscCall(VecSetRandom(x, NULL));
981: PetscCall(VecSetRandom(b, NULL));
982: /* mimic b[is] = x[is] */
983: PetscCall(VecDuplicate(b, &b2));
984: PetscCall(VecSetLocalToGlobalMapping(b2, l2gr));
985: PetscCall(VecCopy(b, b2));
986: PetscCall(ISGetLocalSize(is, &n));
987: PetscCall(ISGetIndices(is, &idxs));
988: PetscCall(VecGetSize(x, &N));
989: for (i = 0; i < n; i++) {
990: if (0 <= idxs[i] && idxs[i] < N) {
991: PetscCall(VecSetValue(b2, idxs[i], diag, INSERT_VALUES));
992: PetscCall(VecSetValue(x, idxs[i], 1., INSERT_VALUES));
993: }
994: }
995: PetscCall(VecAssemblyBegin(b2));
996: PetscCall(VecAssemblyEnd(b2));
997: PetscCall(VecAssemblyBegin(x));
998: PetscCall(VecAssemblyEnd(x));
999: PetscCall(ISRestoreIndices(is, &idxs));
1000: /* test ZeroRows on MATIS */
1001: PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Test MatZeroRows (diag %s)\n", diagstr));
1002: PetscCall(MatZeroRowsIS(B, is, diag, x, b));
1003: PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Test MatZeroRowsColumns (diag %s)\n", diagstr));
1004: PetscCall(MatZeroRowsColumnsIS(B2, is, diag, NULL, NULL));
1005: } else if (haszerorows) {
1006: /* test ZeroRows on MATIS */
1007: PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Test MatZeroRows (diag %s)\n", diagstr));
1008: PetscCall(MatZeroRowsIS(B, is, diag, NULL, NULL));
1009: b = b2 = x = NULL;
1010: } else {
1011: PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Skipping MatZeroRows (diag %s)\n", diagstr));
1012: b = b2 = x = NULL;
1013: }
1015: if (squaretest && haszerorows) {
1016: PetscCall(VecAXPY(b2, -1., b));
1017: PetscCall(VecNorm(b2, NORM_INFINITY, &error));
1018: PetscCheck(error <= PETSC_SQRT_MACHINE_EPSILON, PETSC_COMM_WORLD, PETSC_ERR_PLIB, "ERROR IN ZEROROWS ON B %g (diag %s)", (double)error, diagstr);
1019: }
1021: /* test MatMissingDiagonal */
1022: PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Test MatMissingDiagonal\n"));
1023: PetscCallMPI(MPI_Comm_rank(PETSC_COMM_WORLD, &rank));
1024: PetscCall(MatMissingDiagonal(B, &miss, &d));
1025: PetscCall(MatGetOwnershipRange(B, &rst, &ren));
1026: PetscCall(PetscViewerASCIIPushSynchronized(PETSC_VIEWER_STDOUT_WORLD));
1027: PetscCall(PetscViewerASCIISynchronizedPrintf(PETSC_VIEWER_STDOUT_WORLD, "[%d] [%" PetscInt_FMT ",%" PetscInt_FMT ") Missing %d, row %" PetscInt_FMT " (diag %s)\n", rank, rst, ren, (int)miss, d, diagstr));
1028: PetscCall(PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD));
1029: PetscCall(PetscViewerASCIIPopSynchronized(PETSC_VIEWER_STDOUT_WORLD));
1031: PetscCall(VecDestroy(&x));
1032: PetscCall(VecDestroy(&b));
1033: PetscCall(VecDestroy(&b2));
1035: /* check the result of ZeroRows with that from MPIAIJ routines
1036: assuming that MatConvert_IS_XAIJ and MatZeroRows_MPIAIJ work fine */
1037: if (haszerorows) {
1038: PetscCall(MatDuplicate(Afull, MAT_COPY_VALUES, &Bcheck));
1039: PetscCall(MatSetOption(Bcheck, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_FALSE));
1040: PetscCall(MatZeroRowsIS(Bcheck, is, diag, NULL, NULL));
1041: PetscCall(CheckMat(B, Bcheck, PETSC_FALSE, "Zerorows"));
1042: PetscCall(MatDestroy(&Bcheck));
1043: }
1044: PetscCall(MatDestroy(&B));
1046: if (B2) { /* test MatZeroRowsColumns */
1047: PetscCall(MatDuplicate(Afull, MAT_COPY_VALUES, &B));
1048: PetscCall(MatSetOption(B, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_FALSE));
1049: PetscCall(MatZeroRowsColumnsIS(B, is, diag, NULL, NULL));
1050: PetscCall(CheckMat(B2, B, PETSC_FALSE, "MatZeroRowsColumns"));
1051: PetscCall(MatDestroy(&B));
1052: PetscCall(MatDestroy(&B2));
1053: }
1054: PetscFunctionReturn(PETSC_SUCCESS);
1055: }
1057: /*TEST
1059: test:
1060: requires: !complex
1061: args: -test_matlab -test_trans
1063: test:
1064: suffix: 2
1065: nsize: 4
1066: args: -mat_is_convert_local_nest -nr 3 -nc 4
1068: test:
1069: suffix: 3
1070: nsize: 5
1071: args: -m 11 -n 10 -mat_is_convert_local_nest -nr 2 -nc 1
1073: test:
1074: suffix: 4
1075: nsize: 6
1076: args: -m 9 -n 12 -test_trans -nr 2 -nc 7
1078: test:
1079: suffix: 5
1080: nsize: 6
1081: args: -m 12 -n 12 -test_trans -nr 3 -nc 1
1083: test:
1084: suffix: 6
1085: args: -m 12 -n 12 -test_trans -nr 2 -nc 3 -diffmap
1087: test:
1088: suffix: 7
1089: args: -m 12 -n 12 -test_trans -nr 2 -nc 3 -diffmap -permmap
1091: test:
1092: suffix: 8
1093: args: -m 12 -n 17 -test_trans -nr 2 -nc 3 -permmap
1095: test:
1096: suffix: 9
1097: nsize: 5
1098: args: -m 12 -n 12 -test_trans -nr 2 -nc 3 -diffmap
1100: test:
1101: suffix: 10
1102: nsize: 5
1103: args: -m 12 -n 12 -test_trans -nr 2 -nc 3 -diffmap -permmap
1105: test:
1106: suffix: vscat_default
1107: nsize: 5
1108: args: -m 12 -n 17 -test_trans -nr 2 -nc 3 -permmap
1109: output_file: output/ex23_11.out
1111: test:
1112: suffix: 12
1113: nsize: 3
1114: args: -m 12 -n 12 -symmetric -mat_is_localmat_type sbaij -test_trans -nr 2 -nc 3
1116: testset:
1117: output_file: output/ex23_13.out
1118: nsize: 3
1119: args: -m 12 -n 17 -test_trans -nr 2 -nc 3 -diffmap -permmap
1120: filter: grep -v "type:" | grep -v "block size is 1" | grep -v "not using I-node routines"
1121: test:
1122: suffix: baij
1123: args: -mat_is_localmat_type baij
1124: test:
1125: requires: viennacl
1126: suffix: viennacl
1127: args: -mat_is_localmat_type aijviennacl
1128: test:
1129: requires: cuda
1130: suffix: cusparse
1131: args: -mat_is_localmat_type aijcusparse
1132: test:
1133: requires: kokkos_kernels
1134: suffix: kokkos
1135: args: -mat_is_localmat_type aijkokkos
1137: test:
1138: suffix: negrep
1139: nsize: {{1 3}separate output}
1140: args: -m {{5 7}separate output} -n {{5 7}separate output} -test_trans -nr 2 -nc 3 -negmap {{0 1}separate output} -repmap {{0 1}separate output} -permmap -diffmap {{0 1}separate output} -allow_repeated 0
1142: test:
1143: suffix: negrep_allowrep
1144: nsize: {{1 3}separate output}
1145: args: -m {{5 7}separate output} -n {{5 7}separate output} -test_trans -nr 2 -nc 3 -negmap {{0 1}separate output} -repmap {{0 1}separate output} -permmap -diffmap {{0 1}separate output} -allow_repeated
1147: TEST*/