Actual source code: ex4.c
1: static const char help[] = "Compare LMVM updates, products, and solves with host results.\n";
3: #include <petscksp.h>
4: #include <petscdevice.h>
6: static PetscErrorCode CheckResult(Vec actual, Vec expected)
7: {
8: const PetscScalar *a, *e;
9: PetscInt n;
11: PetscFunctionBeginUser;
12: PetscCall(VecGetLocalSize(actual, &n));
13: PetscCall(VecGetArrayRead(actual, &a));
14: PetscCall(VecGetArrayRead(expected, &e));
15: for (PetscInt i = 0; i < n; ++i)
16: PetscCheck(PetscAbsScalar(a[i] - e[i]) <= 500 * PETSC_MACHINE_EPSILON * PetscMax(1.0, PetscAbsScalar(e[i])), PETSC_COMM_SELF, PETSC_ERR_PLIB, "LMVM result differs at local entry %" PetscInt_FMT ": error %g", i, (double)PetscAbsScalar(a[i] - e[i]));
17: PetscCall(VecRestoreArrayRead(expected, &e));
18: PetscCall(VecRestoreArrayRead(actual, &a));
19: PetscFunctionReturn(PETSC_SUCCESS);
20: }
22: static PetscErrorCode TestLMVM(Vec x, PetscDeviceContext dctx)
23: {
24: Mat B, reference;
25: Vec f, result, hx, hf, expected;
26: PetscInt n, N, start;
27: PetscScalar *xa, *fa;
29: PetscFunctionBeginUser;
30: PetscCall(VecGetLocalSize(x, &n));
31: PetscCall(VecGetSize(x, &N));
32: PetscCall(VecGetOwnershipRange(x, &start, NULL));
33: PetscCall(VecDuplicate(x, &f));
34: PetscCall(VecDuplicate(x, &result));
35: PetscCall(VecCreate(PETSC_COMM_WORLD, &hx));
36: PetscCall(VecSetSizes(hx, n, N));
37: PetscCall(VecSetType(hx, VECSTANDARD));
38: PetscCall(VecDuplicate(hx, &hf));
39: PetscCall(VecDuplicate(hx, &expected));
40: PetscCall(MatCreate(PETSC_COMM_WORLD, &B));
41: PetscCall(MatSetSizes(B, n, n, N, N));
42: PetscCall(MatSetType(B, MATLMVMDBFGS));
43: PetscCall(MatSetFromOptions(B));
44: PetscCall(MatLMVMSetHistorySize(B, 3));
45: PetscCall(MatLMVMAllocate(B, x, f));
46: PetscCall(MatCreate(PETSC_COMM_WORLD, &reference));
47: PetscCall(MatSetSizes(reference, n, n, N, N));
48: PetscCall(MatSetType(reference, MATLMVMDBFGS));
49: PetscCall(MatSetFromOptions(reference));
50: PetscCall(MatLMVMSetHistorySize(reference, 3));
51: PetscCall(MatLMVMAllocate(reference, hx, hf));
52: PetscCall(VecSet(hx, 0));
53: for (PetscInt update = 0; update < 8; ++update) {
54: PetscCall(VecGetArray(hx, &xa));
55: PetscCall(VecGetArray(hf, &fa));
56: for (PetscInt i = 0; i < n; ++i) {
57: xa[i] += PetscSinReal((start + i + 1) * (update + 1));
58: fa[i] = (2.0 + (PetscReal)(start + i) / N) * xa[i];
59: }
60: PetscCall(VecRestoreArray(hf, &fa));
61: PetscCall(VecRestoreArray(hx, &xa));
62: PetscCall(VecCopy(hx, x));
63: PetscCall(VecCopy(hf, f));
64: PetscCall(MatLMVMUpdate(reference, hx, hf));
65: PetscCall(MatLMVMUpdate(B, x, f));
66: // Repeated applications exercise cached products as well as new history.
67: for (PetscInt repeat = 0; repeat < 2; ++repeat) {
68: for (PetscInt solve = 0; solve < 2; ++solve) {
69: if (solve) PetscCall(MatSolve(reference, hf, expected));
70: else PetscCall(MatMult(reference, hf, expected));
71: if (solve) PetscCall(MatSolve(B, f, result));
72: else PetscCall(MatMult(B, f, result));
73: PetscCall(PetscDeviceContextSynchronize(dctx));
74: PetscCall(CheckResult(result, expected));
75: }
76: }
77: }
78: PetscCall(MatDestroy(&reference));
79: PetscCall(MatDestroy(&B));
80: PetscCall(VecDestroy(&expected));
81: PetscCall(VecDestroy(&hf));
82: PetscCall(VecDestroy(&hx));
83: PetscCall(VecDestroy(&result));
84: PetscCall(VecDestroy(&f));
85: PetscFunctionReturn(PETSC_SUCCESS);
86: }
88: int main(int argc, char **argv)
89: {
90: Vec x;
91: PetscDeviceContext saved, dctx;
92: const PetscStreamType streams[] = {PETSC_STREAM_DEFAULT};
94: PetscFunctionBeginUser;
95: PetscCall(PetscInitialize(&argc, &argv, NULL, help));
96: PetscCall(KSPInitializePackage());
97: PetscCall(VecCreate(PETSC_COMM_WORLD, &x));
98: PetscCall(VecSetSizes(x, PETSC_DECIDE, 8));
99: PetscCall(VecSetFromOptions(x));
100: PetscCall(PetscDeviceContextGetCurrentContext(&saved));
101: PetscCall(PetscDeviceContextSynchronize(saved));
102: for (size_t k = 0; k < PETSC_STATIC_ARRAY_LENGTH(streams); ++k) {
103: PetscCall(PetscDeviceContextDuplicate(saved, &dctx));
104: PetscCall(PetscDeviceContextSetStreamType(dctx, streams[k]));
105: PetscCall(PetscDeviceContextSetUp(dctx));
106: PetscCall(PetscDeviceContextSetCurrentContext(dctx));
107: PetscCall(TestLMVM(x, dctx));
108: PetscCall(PetscDeviceContextSynchronize(dctx));
109: PetscCall(PetscDeviceContextSetCurrentContext(saved));
110: PetscCall(PetscDeviceContextDestroy(&dctx));
111: }
112: PetscCall(VecDestroy(&x));
113: PetscCall(PetscFinalize());
114: return 0;
115: }
117: /*TEST
119: testset:
120: nsize: {{1 2}}
121: output_file: output/empty.out
122: args: -mat_type {{lmvmdbfgs lmvmddfp lmvmdqn lmvmbfgs lmvmdfp}}
123: test:
124: suffix: cuda
125: requires: cuda
126: args: -vec_type cuda
127: test:
128: suffix: hip
129: requires: hip !complex
130: args: -vec_type hip
132: TEST*/