Actual source code: ex270.c
1: #include <petscsys.h>
2: #include <petscmat.h>
3: #include <petscoptions.h>
5: static const char help[] = "Test MatGetValue/Row for hypre matrix on device\n";
7: int main(int argc, char **argv)
8: {
9: PetscInt n = 10; // elements
10: PetscReal L = 10.0; // domain length
12: PetscCall(PetscInitialize(&argc, &argv, NULL, help));
14: PetscCall(PetscOptionsGetInt(NULL, NULL, "-n", &n, NULL));
15: PetscCall(PetscOptionsGetReal(NULL, NULL, "-L", &L, NULL));
17: const PetscInt N = n + 1; // nodes
18: const PetscReal h = L / (PetscReal)n;
20: Mat M;
21: PetscCall(MatCreate(PETSC_COMM_WORLD, &M));
22: PetscCall(MatSetSizes(M, PETSC_DECIDE, PETSC_DECIDE, N, N));
23: PetscCall(MatSetType(M, MATAIJ));
24: PetscCall(MatSetFromOptions(M));
25: // Tridiagonal pattern: up to 3 nnz/row (ends have 2). Use same for on/off diag for simplicity.
26: PetscCall(MatSetUp(M));
27: PetscCall(MatMPIAIJSetPreallocation(M, 3, NULL, 3, NULL));
28: PetscCall(MatSeqAIJSetPreallocation(M, 3, NULL));
30: // Ownership range for rows (nodes)
31: PetscInt rstart, rend;
32: PetscCall(MatGetOwnershipRange(M, &rstart, &rend));
34: // Element matrix (scaled)
35: const PetscScalar s = (PetscScalar)(h / 6.0);
36: const PetscScalar ae[4] = {2 * s, 1 * s, 1 * s, 2 * s};
38: // Assemble by looping over elements that start at locally-owned row i
39: PetscInt idx[2];
40: for (PetscInt i = PetscMax(rstart, 0); i < PetscMin(rend, n); ++i) {
41: idx[0] = i;
42: idx[1] = i + 1;
43: PetscCall(MatSetValues(M, 2, idx, 2, idx, ae, ADD_VALUES));
44: }
46: PetscCall(MatAssemblyBegin(M, MAT_FINAL_ASSEMBLY));
47: PetscCall(MatAssemblyEnd(M, MAT_FINAL_ASSEMBLY));
49: // --- Verification of MatGetRow ------------------------------------------
50: {
51: const PetscReal tol = 100 * PETSC_MACHINE_EPSILON; // tight but safe
52: PetscBool ok = PETSC_TRUE;
54: for (PetscInt i = rstart; i < rend; ++i) {
55: const PetscInt *cols;
56: const PetscScalar *getrowvals;
57: PetscScalar *getvals;
58: PetscInt ncols = 0, expected_ncols = 0;
59: PetscInt expected_cols[3];
60: PetscScalar expected_vals[3];
62: // Build expected data
63: if (i > 0) {
64: expected_cols[expected_ncols] = i - 1;
65: expected_vals[expected_ncols] = s;
66: ++expected_ncols;
67: }
68: expected_cols[expected_ncols] = i;
69: expected_vals[expected_ncols] = (i == 0 || i == N - 1) ? (2 * s) : (4 * s); // diag: h/3 at ends, 2h/3 interior
70: ++expected_ncols;
71: if (i + 1 < N) {
72: expected_cols[expected_ncols] = i + 1;
73: expected_vals[expected_ncols] = s;
74: ++expected_ncols;
75: }
77: PetscCall(PetscMalloc1(expected_ncols, &getvals));
78: PetscCall(MatGetRow(M, i, &ncols, &cols, &getrowvals));
79: PetscCall(MatGetValues(M, 1, &i, expected_ncols, (PetscInt *)expected_cols, getvals));
81: // Compare counts
82: if (ncols != expected_ncols) {
83: ok = PETSC_FALSE;
84: goto rowdone;
85: }
87: // Compare values (match by column)
88: for (PetscInt k = 0; k < ncols; ++k) {
89: PetscInt expected_k = -1;
90: /* Matrix is small. Just do a linear search */
91: for (PetscInt l = 0; l < expected_ncols; ++l) {
92: if (expected_cols[l] == cols[k]) {
93: expected_k = l;
94: break;
95: }
96: }
97: if (expected_k < 0) {
98: ok = PETSC_FALSE;
99: goto rowdone;
100: }
101: if ((PetscAbsScalar(getrowvals[k] - expected_vals[expected_k]) > tol) || (PetscAbsScalar(getvals[expected_k] - expected_vals[expected_k]) > tol)) {
102: ok = PETSC_FALSE;
103: goto rowdone;
104: }
105: }
107: rowdone:
108: PetscCall(MatRestoreRow(M, i, &ncols, &cols, &getrowvals));
109: PetscCall(PetscFree(getvals));
110: if (!ok) break;
111: }
113: PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, &ok, 1, MPI_C_BOOL, MPI_LAND, PETSC_COMM_WORLD));
114: if (ok) PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Mass matrix check: OK\n"));
115: else PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Mass matrix check: FAILED\n"));
116: }
117: // --------------------------------------------------------------------------
119: PetscCall(MatDestroy(&M));
120: PetscCall(PetscFinalize());
121: return 0;
122: }
124: /*TEST
126: test:
127: requires: hypre
128: suffix: 1
129: args: -mat_type hypre
131: test:
132: requires: hypre
133: suffix: 2
134: args: -mat_type hypre
135: nsize: 4
137: TEST*/