Skip to content

Commit 7c57412

Browse files
committed
tests: add operator assembly tests for non-trivial oriented restrictions
1 parent c410a5e commit 7c57412

2 files changed

Lines changed: 544 additions & 0 deletions

File tree

tests/t574-operator.c

Lines changed: 307 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,307 @@
1+
/// @file
2+
/// Test full assembly of multi-basis asymmetric mass-like operator with oriented and curl-oriented element restrictions
3+
/// \test Test full assembly of multi-basis asymmetric mass-like operator with oriented and curl-oriented element restrictions
4+
#include "t571-operator.h"
5+
6+
#include <ceed.h>
7+
#include <math.h>
8+
#include <stdio.h>
9+
#include <stdlib.h>
10+
11+
int main(int argc, char **argv) {
12+
Ceed ceed;
13+
CeedElemRestriction elem_restriction_x, elem_restriction_q_data;
14+
CeedElemRestriction oriented_elem_restriction_u, curl_oriented_elem_restriction_u;
15+
CeedElemRestriction oriented_elem_restriction_p, curl_oriented_elem_restriction_p;
16+
CeedBasis basis_x, basis_u, basis_p;
17+
CeedQFunction qf_setup, qf_mass;
18+
CeedOperator op_setup, op_mass_oriented, op_mass_curl_oriented;
19+
CeedVector q_data, x, u, v;
20+
CeedInt p_u = 3, p_p = 2, q = 4, dim = 2;
21+
CeedInt n_x = 1, n_y = 1;
22+
CeedInt num_elem = n_x * n_y;
23+
CeedInt num_comp_u = 1, num_comp_p = 1; // Must be 1
24+
CeedInt num_dofs_u = (n_x * (p_u - 1) + 1) * (n_y * (p_u - 1) + 1), num_dofs_p = (n_x * (p_p - 1) + 1) * (n_y * (p_p - 1) + 1),
25+
num_qpts = num_elem * q * q;
26+
CeedInt ind_x[num_elem * p_u * p_u], ind_p[num_elem * p_p * p_p];
27+
CeedInt l_size = num_comp_u * num_dofs_u + num_comp_p * num_dofs_p;
28+
bool orients_u[num_elem * p_u * p_u], orients_p[num_elem * p_p * p_p];
29+
CeedInt8 curl_orients_u[3 * num_elem * p_u * p_u], curl_orients_p[3 * num_elem * p_p * p_p];
30+
CeedScalar assembled_values_oriented[l_size * l_size];
31+
CeedScalar assembled_values_curl_oriented[l_size * l_size];
32+
CeedScalar assembled_true[l_size * l_size];
33+
34+
CeedInit(argv[1], &ceed);
35+
36+
// Vectors
37+
CeedVectorCreate(ceed, dim * num_dofs_u, &x);
38+
{
39+
CeedScalar x_array[dim * num_dofs_u];
40+
41+
for (CeedInt i = 0; i < n_x * (p_u - 1) + 1; i++) {
42+
for (CeedInt j = 0; j < n_y * (p_u - 1) + 1; j++) {
43+
x_array[i + j * (n_x * 2 + 1) + 0 * num_dofs_u] = (CeedScalar)i / (n_x * (p_u - 1));
44+
x_array[i + j * (n_x * 2 + 1) + 1 * num_dofs_u] = (CeedScalar)j / (n_y * (p_u - 1));
45+
}
46+
}
47+
CeedVectorSetArray(x, CEED_MEM_HOST, CEED_COPY_VALUES, x_array);
48+
}
49+
CeedVectorCreate(ceed, l_size, &u);
50+
CeedVectorCreate(ceed, l_size, &v);
51+
CeedVectorCreate(ceed, num_qpts, &q_data);
52+
53+
// Restrictions
54+
for (CeedInt i = 0; i < num_elem; i++) {
55+
CeedInt col, row, offset;
56+
57+
col = i % n_x;
58+
row = i / n_x;
59+
offset = col * (p_u - 1) + row * (n_x * (p_u - 1) + 1) * (p_u - 1);
60+
for (CeedInt j = 0; j < p_u; j++) {
61+
for (CeedInt k = 0; k < p_u; k++) {
62+
bool normal = !((j % 2 > 0 && k % 2 == 0) || (j % 2 == 0 && k % 2 > 0));
63+
64+
ind_x[p_u * (p_u * i + k) + j] = offset + k * p_u + j;
65+
orients_u[p_u * (p_u * i + k) + j] = !normal;
66+
curl_orients_u[3 * (p_u * (p_u * i + k) + j) + 0] = j % 2 > 0 && k % 2 == 0 ? -1 : 0;
67+
curl_orients_u[3 * (p_u * (p_u * i + k) + j) + 1] = normal ? 1 : 0;
68+
curl_orients_u[3 * (p_u * (p_u * i + k) + j) + 2] = j % 2 == 0 && k % 2 > 0 ? -1 : 0;
69+
}
70+
}
71+
}
72+
const CeedInt offset_p = num_comp_u * num_dofs_u;
73+
for (CeedInt i = 0; i < num_elem; i++) {
74+
CeedInt col, row, offset;
75+
76+
col = i % n_x;
77+
row = i / n_x;
78+
offset = col * (p_p - 1) + row * (n_x * (p_p - 1) + 1) * (p_p - 1);
79+
for (CeedInt j = 0; j < p_p; j++) {
80+
for (CeedInt k = 0; k < p_p; k++) {
81+
bool normal = !((j % 2 > 0 && k % 2 == 0) || (j % 2 == 0 && k % 2 > 0));
82+
83+
ind_p[p_p * (p_p * i + k) + j] = offset + k * p_p + j + offset_p;
84+
orients_p[p_p * (p_p * i + k) + j] = !normal;
85+
curl_orients_p[3 * (p_p * (p_p * i + k) + j) + 0] = j % 2 == 0 && k % 2 > 0 ? -1 : 0;
86+
curl_orients_p[3 * (p_p * (p_p * i + k) + j) + 1] = normal ? 1 : 0;
87+
curl_orients_p[3 * (p_p * (p_p * i + k) + j) + 2] = j % 2 > 0 && k % 2 == 0 ? -1 : 0;
88+
}
89+
}
90+
}
91+
CeedElemRestrictionCreate(ceed, num_elem, p_u * p_u, dim, num_dofs_u, dim * num_dofs_u, CEED_MEM_HOST, CEED_USE_POINTER, ind_x,
92+
&elem_restriction_x);
93+
CeedElemRestrictionCreateOriented(ceed, num_elem, p_u * p_u, num_comp_u, num_dofs_u, l_size, CEED_MEM_HOST, CEED_USE_POINTER, ind_x, orients_u,
94+
&oriented_elem_restriction_u);
95+
CeedElemRestrictionCreateCurlOriented(ceed, num_elem, p_u * p_u, num_comp_u, num_dofs_u, l_size, CEED_MEM_HOST, CEED_USE_POINTER, ind_x,
96+
curl_orients_u, &curl_oriented_elem_restriction_u);
97+
98+
CeedElemRestrictionCreateOriented(ceed, num_elem, p_p * p_p, num_comp_p, num_dofs_p, l_size, CEED_MEM_HOST, CEED_USE_POINTER, ind_x, orients_p,
99+
&oriented_elem_restriction_p);
100+
CeedElemRestrictionCreateCurlOriented(ceed, num_elem, p_p * p_p, num_comp_p, num_dofs_p, l_size, CEED_MEM_HOST, CEED_USE_POINTER, ind_x,
101+
curl_orients_p, &curl_oriented_elem_restriction_p);
102+
103+
CeedInt strides_q_data[3] = {1, q * q * num_elem, q * q};
104+
CeedElemRestrictionCreateStrided(ceed, num_elem, q * q, 1, num_qpts * 1, strides_q_data, &elem_restriction_q_data);
105+
106+
// Bases
107+
CeedBasisCreateTensorH1Lagrange(ceed, dim, dim, p_u, q, CEED_GAUSS, &basis_x);
108+
CeedBasisCreateTensorH1Lagrange(ceed, dim, num_comp_u, p_u, q, CEED_GAUSS, &basis_u);
109+
CeedBasisCreateTensorH1Lagrange(ceed, dim, num_comp_p, p_p, q, CEED_GAUSS, &basis_p);
110+
111+
// QFunctions
112+
CeedQFunctionCreateInterior(ceed, 1, setup, setup_loc, &qf_setup);
113+
CeedQFunctionAddInput(qf_setup, "weight", 1, CEED_EVAL_WEIGHT);
114+
CeedQFunctionAddInput(qf_setup, "dx", dim * dim, CEED_EVAL_GRAD);
115+
CeedQFunctionAddOutput(qf_setup, "qdata", 1, CEED_EVAL_NONE);
116+
117+
CeedQFunctionCreateInterior(ceed, 1, multi_basis, multi_basis_loc, &qf_mass);
118+
CeedQFunctionAddInput(qf_mass, "qdata", 1, CEED_EVAL_NONE);
119+
CeedQFunctionAddInput(qf_mass, "u", num_comp_u, CEED_EVAL_INTERP);
120+
CeedQFunctionAddInput(qf_mass, "p", num_comp_p, CEED_EVAL_INTERP);
121+
CeedQFunctionAddOutput(qf_mass, "v", num_comp_u, CEED_EVAL_INTERP);
122+
CeedQFunctionAddOutput(qf_mass, "q", num_comp_p, CEED_EVAL_INTERP);
123+
124+
Context_t context = {num_comp_u, num_comp_p};
125+
CeedQFunctionContext ctx;
126+
127+
CeedQFunctionContextCreate(ceed, &ctx);
128+
CeedQFunctionContextSetData(ctx, CEED_MEM_HOST, CEED_COPY_VALUES, sizeof(Context_t), &context);
129+
CeedQFunctionSetContext(qf_mass, ctx);
130+
CeedQFunctionContextDestroy(&ctx);
131+
132+
// Operators
133+
CeedOperatorCreate(ceed, qf_setup, CEED_QFUNCTION_NONE, CEED_QFUNCTION_NONE, &op_setup);
134+
CeedOperatorSetField(op_setup, "weight", CEED_ELEMRESTRICTION_NONE, basis_x, CEED_VECTOR_NONE);
135+
CeedOperatorSetField(op_setup, "dx", elem_restriction_x, basis_x, CEED_VECTOR_ACTIVE);
136+
CeedOperatorSetField(op_setup, "qdata", elem_restriction_q_data, CEED_BASIS_NONE, CEED_VECTOR_ACTIVE);
137+
138+
CeedOperatorCreate(ceed, qf_mass, CEED_QFUNCTION_NONE, CEED_QFUNCTION_NONE, &op_mass_oriented);
139+
CeedOperatorSetField(op_mass_oriented, "qdata", elem_restriction_q_data, CEED_BASIS_NONE, q_data);
140+
CeedOperatorSetField(op_mass_oriented, "u", oriented_elem_restriction_u, basis_u, CEED_VECTOR_ACTIVE);
141+
CeedOperatorSetField(op_mass_oriented, "p", oriented_elem_restriction_p, basis_p, CEED_VECTOR_ACTIVE);
142+
CeedOperatorSetField(op_mass_oriented, "v", oriented_elem_restriction_u, basis_u, CEED_VECTOR_ACTIVE);
143+
CeedOperatorSetField(op_mass_oriented, "q", oriented_elem_restriction_p, basis_p, CEED_VECTOR_ACTIVE);
144+
145+
CeedOperatorCreate(ceed, qf_mass, CEED_QFUNCTION_NONE, CEED_QFUNCTION_NONE, &op_mass_curl_oriented);
146+
CeedOperatorSetField(op_mass_curl_oriented, "qdata", elem_restriction_q_data, CEED_BASIS_NONE, q_data);
147+
CeedOperatorSetField(op_mass_curl_oriented, "u", curl_oriented_elem_restriction_u, basis_u, CEED_VECTOR_ACTIVE);
148+
CeedOperatorSetField(op_mass_curl_oriented, "p", curl_oriented_elem_restriction_p, basis_p, CEED_VECTOR_ACTIVE);
149+
CeedOperatorSetField(op_mass_curl_oriented, "v", curl_oriented_elem_restriction_u, basis_u, CEED_VECTOR_ACTIVE);
150+
CeedOperatorSetField(op_mass_curl_oriented, "q", curl_oriented_elem_restriction_p, basis_p, CEED_VECTOR_ACTIVE);
151+
152+
// Apply Setup Operator
153+
CeedOperatorApply(op_setup, x, q_data, CEED_REQUEST_IMMEDIATE);
154+
155+
// Fully assemble operators
156+
CeedSize num_entries_oriented, num_entries_curl_oriented;
157+
CeedInt *rows_oriented, *rows_curl_oriented;
158+
CeedInt *cols_oriented, *cols_curl_oriented;
159+
CeedVector assembled_oriented, assembled_curl_oriented;
160+
161+
for (CeedInt k = 0; k < l_size * l_size; ++k) {
162+
assembled_values_oriented[k] = 0.0;
163+
assembled_values_curl_oriented[k] = 0.0;
164+
}
165+
CeedOperatorLinearAssembleSymbolic(op_mass_oriented, &num_entries_oriented, &rows_oriented, &cols_oriented);
166+
CeedOperatorLinearAssembleSymbolic(op_mass_curl_oriented, &num_entries_curl_oriented, &rows_curl_oriented, &cols_curl_oriented);
167+
CeedVectorCreate(ceed, num_entries_oriented, &assembled_oriented);
168+
CeedVectorCreate(ceed, num_entries_curl_oriented, &assembled_curl_oriented);
169+
CeedOperatorLinearAssemble(op_mass_oriented, assembled_oriented);
170+
CeedOperatorLinearAssemble(op_mass_curl_oriented, assembled_curl_oriented);
171+
{
172+
const CeedScalar *assembled_array;
173+
174+
CeedVectorGetArrayRead(assembled_oriented, CEED_MEM_HOST, &assembled_array);
175+
for (CeedInt k = 0; k < num_entries_oriented; ++k) {
176+
assembled_values_oriented[rows_oriented[k] * l_size + cols_oriented[k]] += assembled_array[k];
177+
}
178+
CeedVectorRestoreArrayRead(assembled_oriented, &assembled_array);
179+
}
180+
{
181+
const CeedScalar *assembled_array;
182+
183+
CeedVectorGetArrayRead(assembled_curl_oriented, CEED_MEM_HOST, &assembled_array);
184+
for (CeedInt k = 0; k < num_entries_curl_oriented; ++k) {
185+
assembled_values_curl_oriented[rows_curl_oriented[k] * l_size + cols_curl_oriented[k]] += assembled_array[k];
186+
}
187+
CeedVectorRestoreArrayRead(assembled_curl_oriented, &assembled_array);
188+
}
189+
190+
// Manually assemble oriented operator
191+
CeedInt old_index = -1;
192+
193+
CeedVectorSetValue(u, 0.0);
194+
for (CeedInt j = 0; j < l_size; j++) {
195+
CeedScalar *u_array;
196+
const CeedScalar *v_array;
197+
198+
// Set input
199+
CeedVectorGetArray(u, CEED_MEM_HOST, &u_array);
200+
u_array[j] = 1.0;
201+
if (j > 0) u_array[old_index] = 0.0;
202+
old_index = j;
203+
CeedVectorRestoreArray(u, &u_array);
204+
205+
// Compute effect of DoF ind
206+
CeedOperatorApply(op_mass_oriented, u, v, CEED_REQUEST_IMMEDIATE);
207+
208+
CeedVectorGetArrayRead(v, CEED_MEM_HOST, &v_array);
209+
for (CeedInt i = 0; i < l_size; i++) assembled_true[i * l_size + j] = v_array[i];
210+
CeedVectorRestoreArrayRead(v, &v_array);
211+
}
212+
213+
// Check output
214+
for (CeedInt i = 0; i < l_size; i++) {
215+
for (CeedInt j = 0; j < l_size; j++) {
216+
const CeedScalar assembled_value = assembled_values_oriented[i * l_size + j];
217+
const CeedScalar assembled_true_value = assembled_true[i * l_size + j];
218+
const CeedScalar error = fabs(assembled_value - assembled_true_value) / (fmax(fabs(assembled_true_value), 1.0));
219+
220+
if (!(error < 100. * CEED_EPSILON)) {
221+
// LCOV_EXCL_START
222+
const CeedInt node_out = (i < num_comp_u * num_dofs_u) ? i % num_dofs_u : (i - num_comp_u * num_dofs_u) % num_dofs_p;
223+
const CeedInt comp_out = (i < num_comp_u * num_dofs_u) ? i / num_dofs_u : (i - num_comp_u * num_dofs_u) / num_dofs_p;
224+
const CeedInt node_in = (j < num_comp_u * num_dofs_u) ? j % num_dofs_u : (j - num_comp_u * num_dofs_u) % num_dofs_p;
225+
const CeedInt comp_in = (j < num_comp_u * num_dofs_u) ? j / num_dofs_u : (j - num_comp_u * num_dofs_u) / num_dofs_p;
226+
227+
printf("[(%s, %" CeedInt_FMT ", %" CeedInt_FMT "), (%s, %" CeedInt_FMT ", %" CeedInt_FMT
228+
")] Error in oriented assembly: %g != %g (error: %g)\n",
229+
(i < num_comp_u * num_dofs_u ? "u" : "p"), node_out, comp_out, (j < num_comp_u * num_dofs_u ? "u" : "p"), node_in, comp_in,
230+
assembled_value, assembled_true_value, error);
231+
// LCOV_EXCL_STOP
232+
}
233+
}
234+
}
235+
236+
// Manually assemble curl-oriented operator
237+
old_index = -1;
238+
239+
CeedVectorSetValue(u, 0.0);
240+
for (CeedInt j = 0; j < l_size; j++) {
241+
CeedScalar *u_array;
242+
const CeedScalar *v_array;
243+
244+
// Set input
245+
CeedVectorGetArray(u, CEED_MEM_HOST, &u_array);
246+
u_array[j] = 1.0;
247+
if (j > 0) u_array[old_index] = 0.0;
248+
old_index = j;
249+
CeedVectorRestoreArray(u, &u_array);
250+
251+
// Compute effect of DoF ind
252+
CeedOperatorApply(op_mass_curl_oriented, u, v, CEED_REQUEST_IMMEDIATE);
253+
254+
CeedVectorGetArrayRead(v, CEED_MEM_HOST, &v_array);
255+
for (CeedInt i = 0; i < l_size; i++) assembled_true[i * l_size + j] = v_array[i];
256+
CeedVectorRestoreArrayRead(v, &v_array);
257+
}
258+
for (CeedInt i = 0; i < l_size; i++) {
259+
for (CeedInt j = 0; j < l_size; j++) {
260+
const CeedScalar assembled_value = assembled_values_curl_oriented[i * l_size + j];
261+
const CeedScalar assembled_true_value = assembled_true[i * l_size + j];
262+
const CeedScalar error = fabs(assembled_value - assembled_true_value) / (fmax(fabs(assembled_true_value), 1.0));
263+
264+
if (!(error < 100. * CEED_EPSILON)) {
265+
// LCOV_EXCL_START
266+
const CeedInt node_out = (i < num_comp_u * num_dofs_u) ? i % num_dofs_u : (i - num_comp_u * num_dofs_u) % num_dofs_p;
267+
const CeedInt comp_out = (i < num_comp_u * num_dofs_u) ? i / num_dofs_u : (i - num_comp_u * num_dofs_u) / num_dofs_p;
268+
const CeedInt node_in = (j < num_comp_u * num_dofs_u) ? j % num_dofs_u : (j - num_comp_u * num_dofs_u) % num_dofs_p;
269+
const CeedInt comp_in = (j < num_comp_u * num_dofs_u) ? j / num_dofs_u : (j - num_comp_u * num_dofs_u) / num_dofs_p;
270+
271+
printf("[(%s, %" CeedInt_FMT ", %" CeedInt_FMT "), (%s, %" CeedInt_FMT ", %" CeedInt_FMT
272+
")] Error in curl-oriented assembly: %g != %g (error: %g)\n",
273+
(i < num_comp_u * num_dofs_u ? "u" : "p"), node_out, comp_out, (j < num_comp_u * num_dofs_u ? "u" : "p"), node_in, comp_in,
274+
assembled_value, assembled_true_value, error);
275+
// LCOV_EXCL_STOP
276+
}
277+
}
278+
}
279+
280+
// Cleanup
281+
free(rows_oriented);
282+
free(cols_oriented);
283+
free(rows_curl_oriented);
284+
free(cols_curl_oriented);
285+
CeedVectorDestroy(&x);
286+
CeedVectorDestroy(&q_data);
287+
CeedVectorDestroy(&u);
288+
CeedVectorDestroy(&v);
289+
CeedVectorDestroy(&assembled_oriented);
290+
CeedVectorDestroy(&assembled_curl_oriented);
291+
CeedElemRestrictionDestroy(&oriented_elem_restriction_u);
292+
CeedElemRestrictionDestroy(&curl_oriented_elem_restriction_u);
293+
CeedElemRestrictionDestroy(&oriented_elem_restriction_p);
294+
CeedElemRestrictionDestroy(&curl_oriented_elem_restriction_p);
295+
CeedElemRestrictionDestroy(&elem_restriction_x);
296+
CeedElemRestrictionDestroy(&elem_restriction_q_data);
297+
CeedBasisDestroy(&basis_u);
298+
CeedBasisDestroy(&basis_p);
299+
CeedBasisDestroy(&basis_x);
300+
CeedQFunctionDestroy(&qf_setup);
301+
CeedQFunctionDestroy(&qf_mass);
302+
CeedOperatorDestroy(&op_setup);
303+
CeedOperatorDestroy(&op_mass_oriented);
304+
CeedOperatorDestroy(&op_mass_curl_oriented);
305+
CeedDestroy(&ceed);
306+
return 0;
307+
}

0 commit comments

Comments
 (0)