xref: /libCEED/tests/t319-basis.c (revision 4fee36f0a30516a0b5ad51bf7eb3b32d83efd623)
114556e63SJeremy L Thompson /// @file
214556e63SJeremy L Thompson /// Test projection interp and grad in multiple dimensions
314556e63SJeremy L Thompson /// \test Test projection interp and grad in multiple dimensions
414556e63SJeremy L Thompson #include <ceed.h>
514556e63SJeremy L Thompson #include <math.h>
614556e63SJeremy L Thompson 
714556e63SJeremy L Thompson static CeedScalar Eval(CeedInt dim, const CeedScalar x[]) {
814556e63SJeremy L Thompson   CeedScalar result = (x[0] + 0.1) * (x[0] + 0.1);
914556e63SJeremy L Thompson   if (dim > 1) result += (x[1] + 0.2) * (x[1] + 0.2);
1014556e63SJeremy L Thompson   if (dim > 2) result += -(x[2] + 0.3) * (x[2] + 0.3);
1114556e63SJeremy L Thompson   return result;
1214556e63SJeremy L Thompson }
1314556e63SJeremy L Thompson 
1414556e63SJeremy L Thompson static CeedScalar EvalGrad(CeedInt dim, const CeedScalar x[]) {
1514556e63SJeremy L Thompson   switch (dim) {
162b730f8bSJeremy L Thompson     case 0:
172b730f8bSJeremy L Thompson       return 2 * x[0] + 0.2;
182b730f8bSJeremy L Thompson     case 1:
192b730f8bSJeremy L Thompson       return 2 * x[1] + 0.4;
202b730f8bSJeremy L Thompson     default:
212b730f8bSJeremy L Thompson       return -2 * x[2] - 0.6;
2214556e63SJeremy L Thompson   }
2314556e63SJeremy L Thompson }
2414556e63SJeremy L Thompson 
2514556e63SJeremy L Thompson static CeedScalar GetTolerance(CeedScalarType scalar_type, int dim) {
2614556e63SJeremy L Thompson   CeedScalar tol;
2714556e63SJeremy L Thompson   if (scalar_type == CEED_SCALAR_FP32) {
282b730f8bSJeremy L Thompson     if (dim == 3) tol = 1.e-4;
292b730f8bSJeremy L Thompson     else tol = 1.e-5;
3014556e63SJeremy L Thompson   } else {
3114556e63SJeremy L Thompson     tol = 1.e-11;
3214556e63SJeremy L Thompson   }
3314556e63SJeremy L Thompson   return tol;
3414556e63SJeremy L Thompson }
3514556e63SJeremy L Thompson 
3614556e63SJeremy L Thompson int main(int argc, char **argv) {
3714556e63SJeremy L Thompson   Ceed ceed;
3814556e63SJeremy L Thompson 
3914556e63SJeremy L Thompson   CeedInit(argv[1], &ceed);
4014556e63SJeremy L Thompson 
4114556e63SJeremy L Thompson   for (CeedInt dim = 1; dim <= 3; dim++) {
42*4fee36f0SJeremy L Thompson     CeedVector x_corners, x_from, x_to, u_from, u_to, du_to;
4314556e63SJeremy L Thompson     CeedBasis  basis_x, basis_from, basis_to, basis_project;
44*4fee36f0SJeremy L Thompson     CeedInt    p_from = 5, p_to = 6, q = 7, x_dim = CeedIntPow(2, dim), p_from_dim = CeedIntPow(p_from, dim), p_to_dim = CeedIntPow(p_to, dim);
45*4fee36f0SJeremy L Thompson 
46*4fee36f0SJeremy L Thompson     CeedVectorCreate(ceed, x_dim * dim, &x_corners);
47*4fee36f0SJeremy L Thompson     {
48*4fee36f0SJeremy L Thompson       CeedScalar x_array[x_dim * dim];
4914556e63SJeremy L Thompson 
502b730f8bSJeremy L Thompson       for (CeedInt d = 0; d < dim; d++) {
51*4fee36f0SJeremy L Thompson         for (CeedInt i = 0; i < x_dim; i++) x_array[x_dim * d + i] = (i % CeedIntPow(2, dim - d)) / CeedIntPow(2, dim - d - 1) ? 1 : -1;
522b730f8bSJeremy L Thompson       }
53*4fee36f0SJeremy L Thompson       CeedVectorSetArray(x_corners, CEED_MEM_HOST, CEED_COPY_VALUES, x_array);
54*4fee36f0SJeremy L Thompson     }
55*4fee36f0SJeremy L Thompson     CeedVectorCreate(ceed, p_from_dim * dim, &x_from);
56*4fee36f0SJeremy L Thompson     CeedVectorCreate(ceed, p_to_dim * dim, &x_to);
57*4fee36f0SJeremy L Thompson     CeedVectorCreate(ceed, p_from_dim, &u_from);
58*4fee36f0SJeremy L Thompson     CeedVectorSetValue(u_from, 0);
59*4fee36f0SJeremy L Thompson     CeedVectorCreate(ceed, p_to_dim, &u_to);
60*4fee36f0SJeremy L Thompson     CeedVectorSetValue(u_to, 0);
61*4fee36f0SJeremy L Thompson     CeedVectorCreate(ceed, p_to_dim * dim, &du_to);
62*4fee36f0SJeremy L Thompson     CeedVectorSetValue(du_to, 0);
6314556e63SJeremy L Thompson 
6414556e63SJeremy L Thompson     // Get nodal coordinates
65*4fee36f0SJeremy L Thompson     CeedBasisCreateTensorH1Lagrange(ceed, dim, dim, 2, p_from, CEED_GAUSS_LOBATTO, &basis_x);
66*4fee36f0SJeremy L Thompson     CeedBasisApply(basis_x, 1, CEED_NOTRANSPOSE, CEED_EVAL_INTERP, x_corners, x_from);
6714556e63SJeremy L Thompson     CeedBasisDestroy(&basis_x);
68*4fee36f0SJeremy L Thompson     CeedBasisCreateTensorH1Lagrange(ceed, dim, dim, 2, p_to, CEED_GAUSS_LOBATTO, &basis_x);
69*4fee36f0SJeremy L Thompson     CeedBasisApply(basis_x, 1, CEED_NOTRANSPOSE, CEED_EVAL_INTERP, x_corners, x_to);
7014556e63SJeremy L Thompson     CeedBasisDestroy(&basis_x);
7114556e63SJeremy L Thompson 
7214556e63SJeremy L Thompson     // Create U and projection bases
73*4fee36f0SJeremy L Thompson     CeedBasisCreateTensorH1Lagrange(ceed, dim, 1, p_from, q, CEED_GAUSS, &basis_from);
74*4fee36f0SJeremy L Thompson     CeedBasisCreateTensorH1Lagrange(ceed, dim, 1, p_to, q, CEED_GAUSS, &basis_to);
7514556e63SJeremy L Thompson     CeedBasisCreateProjection(basis_from, basis_to, &basis_project);
7614556e63SJeremy L Thompson 
7714556e63SJeremy L Thompson     // Setup coarse solution
78*4fee36f0SJeremy L Thompson     {
79*4fee36f0SJeremy L Thompson       const CeedScalar *x_array;
80*4fee36f0SJeremy L Thompson       CeedScalar        u_array[p_from_dim];
81*4fee36f0SJeremy L Thompson 
82*4fee36f0SJeremy L Thompson       CeedVectorGetArrayRead(x_from, CEED_MEM_HOST, &x_array);
83*4fee36f0SJeremy L Thompson       for (CeedInt i = 0; i < p_from_dim; i++) {
84*4fee36f0SJeremy L Thompson         CeedScalar coord[dim];
85*4fee36f0SJeremy L Thompson         for (CeedInt d = 0; d < dim; d++) coord[d] = x_array[p_from_dim * d + i];
86*4fee36f0SJeremy L Thompson         u_array[i] = Eval(dim, coord);
8714556e63SJeremy L Thompson       }
88*4fee36f0SJeremy L Thompson       CeedVectorRestoreArrayRead(x_from, &x_array);
89*4fee36f0SJeremy L Thompson       CeedVectorSetArray(u_from, CEED_MEM_HOST, CEED_COPY_VALUES, u_array);
90*4fee36f0SJeremy L Thompson     }
9114556e63SJeremy L Thompson 
9214556e63SJeremy L Thompson     // Project to fine basis
93*4fee36f0SJeremy L Thompson     CeedBasisApply(basis_project, 1, CEED_NOTRANSPOSE, CEED_EVAL_INTERP, u_from, u_to);
9414556e63SJeremy L Thompson 
9514556e63SJeremy L Thompson     // Check solution
9614556e63SJeremy L Thompson     CeedScalar tol = GetTolerance(CEED_SCALAR_TYPE, dim);
97*4fee36f0SJeremy L Thompson     {
98*4fee36f0SJeremy L Thompson       const CeedScalar *x_array, *u_array;
99*4fee36f0SJeremy L Thompson 
100*4fee36f0SJeremy L Thompson       CeedVectorGetArrayRead(x_to, CEED_MEM_HOST, &x_array);
101*4fee36f0SJeremy L Thompson       CeedVectorGetArrayRead(u_to, CEED_MEM_HOST, &u_array);
102*4fee36f0SJeremy L Thompson       for (CeedInt i = 0; i < p_to_dim; i++) {
103*4fee36f0SJeremy L Thompson         CeedScalar coord[dim];
104*4fee36f0SJeremy L Thompson         for (CeedInt d = 0; d < dim; d++) coord[d] = x_array[d * p_to_dim + i];
105*4fee36f0SJeremy L Thompson         const CeedScalar u = Eval(dim, coord);
106*4fee36f0SJeremy L Thompson         if (fabs(u - u_array[i]) > tol) printf("[%" CeedInt_FMT ", %" CeedInt_FMT "] %f != %f\n", dim, i, u_array[i], u);
10714556e63SJeremy L Thompson       }
108*4fee36f0SJeremy L Thompson       CeedVectorRestoreArrayRead(x_to, &x_array);
109*4fee36f0SJeremy L Thompson       CeedVectorRestoreArrayRead(u_to, &u_array);
110*4fee36f0SJeremy L Thompson     }
11114556e63SJeremy L Thompson 
11214556e63SJeremy L Thompson     // Project and take gradient
113*4fee36f0SJeremy L Thompson     CeedBasisApply(basis_project, 1, CEED_NOTRANSPOSE, CEED_EVAL_GRAD, u_from, du_to);
11414556e63SJeremy L Thompson 
11514556e63SJeremy L Thompson     // Check solution
116*4fee36f0SJeremy L Thompson     {
117*4fee36f0SJeremy L Thompson       const CeedScalar *x_array, *du_array;
118*4fee36f0SJeremy L Thompson 
119*4fee36f0SJeremy L Thompson       CeedVectorGetArrayRead(x_to, CEED_MEM_HOST, &x_array);
120*4fee36f0SJeremy L Thompson       CeedVectorGetArrayRead(du_to, CEED_MEM_HOST, &du_array);
121*4fee36f0SJeremy L Thompson       for (CeedInt i = 0; i < p_to_dim; i++) {
122*4fee36f0SJeremy L Thompson         CeedScalar coord[dim];
123*4fee36f0SJeremy L Thompson         for (CeedInt d = 0; d < dim; d++) coord[d] = x_array[p_to_dim * d + i];
12414556e63SJeremy L Thompson         for (CeedInt d = 0; d < dim; d++) {
125*4fee36f0SJeremy L Thompson           const CeedScalar du = EvalGrad(d, coord);
126*4fee36f0SJeremy L Thompson           if (fabs(du - du_array[p_to_dim * (dim - 1 - d) + i]) > tol) {
12714556e63SJeremy L Thompson             // LCOV_EXCL_START
128*4fee36f0SJeremy L Thompson             printf("[%" CeedInt_FMT ", %" CeedInt_FMT ", %" CeedInt_FMT "] %f != %f\n", dim, i, d, du_array[p_to_dim * (dim - 1 - d) + i], du);
12914556e63SJeremy L Thompson             // LCOV_EXCL_STOP
13014556e63SJeremy L Thompson           }
13114556e63SJeremy L Thompson         }
1322b730f8bSJeremy L Thompson       }
133*4fee36f0SJeremy L Thompson       CeedVectorRestoreArrayRead(x_to, &x_array);
134*4fee36f0SJeremy L Thompson       CeedVectorRestoreArrayRead(du_to, &du_array);
135*4fee36f0SJeremy L Thompson     }
13614556e63SJeremy L Thompson 
137*4fee36f0SJeremy L Thompson     CeedVectorDestroy(&x_corners);
138*4fee36f0SJeremy L Thompson     CeedVectorDestroy(&x_from);
139*4fee36f0SJeremy L Thompson     CeedVectorDestroy(&x_to);
140*4fee36f0SJeremy L Thompson     CeedVectorDestroy(&u_from);
141*4fee36f0SJeremy L Thompson     CeedVectorDestroy(&u_to);
142*4fee36f0SJeremy L Thompson     CeedVectorDestroy(&du_to);
14314556e63SJeremy L Thompson     CeedBasisDestroy(&basis_from);
14414556e63SJeremy L Thompson     CeedBasisDestroy(&basis_to);
14514556e63SJeremy L Thompson     CeedBasisDestroy(&basis_project);
14614556e63SJeremy L Thompson   }
14714556e63SJeremy L Thompson   CeedDestroy(&ceed);
14814556e63SJeremy L Thompson   return 0;
14914556e63SJeremy L Thompson }
150