xref: /libCEED/tests/t319-basis.c (revision 99e754f07c08eea4e6609a33ed68aeb9dcf08b08)
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>
649aac155SJeremy L Thompson #include <stdio.h>
714556e63SJeremy L Thompson 
814556e63SJeremy L Thompson static CeedScalar Eval(CeedInt dim, const CeedScalar x[]) {
914556e63SJeremy L Thompson   CeedScalar result = (x[0] + 0.1) * (x[0] + 0.1);
1014556e63SJeremy L Thompson   if (dim > 1) result += (x[1] + 0.2) * (x[1] + 0.2);
1114556e63SJeremy L Thompson   if (dim > 2) result += -(x[2] + 0.3) * (x[2] + 0.3);
1214556e63SJeremy L Thompson   return result;
1314556e63SJeremy L Thompson }
1414556e63SJeremy L Thompson 
1514556e63SJeremy L Thompson static CeedScalar EvalGrad(CeedInt dim, const CeedScalar x[]) {
1614556e63SJeremy L Thompson   switch (dim) {
172b730f8bSJeremy L Thompson     case 0:
182b730f8bSJeremy L Thompson       return 2 * x[0] + 0.2;
192b730f8bSJeremy L Thompson     case 1:
202b730f8bSJeremy L Thompson       return 2 * x[1] + 0.4;
212b730f8bSJeremy L Thompson     default:
222b730f8bSJeremy L Thompson       return -2 * x[2] - 0.6;
2314556e63SJeremy L Thompson   }
2414556e63SJeremy L Thompson }
2514556e63SJeremy L Thompson 
2614556e63SJeremy L Thompson static CeedScalar GetTolerance(CeedScalarType scalar_type, int dim) {
2714556e63SJeremy L Thompson   CeedScalar tol;
2814556e63SJeremy L Thompson   if (scalar_type == CEED_SCALAR_FP32) {
292b730f8bSJeremy L Thompson     if (dim == 3) tol = 1.e-4;
302b730f8bSJeremy L Thompson     else tol = 1.e-5;
3114556e63SJeremy L Thompson   } else {
3214556e63SJeremy L Thompson     tol = 1.e-11;
3314556e63SJeremy L Thompson   }
3414556e63SJeremy L Thompson   return tol;
3514556e63SJeremy L Thompson }
3614556e63SJeremy L Thompson 
3714556e63SJeremy L Thompson int main(int argc, char **argv) {
3814556e63SJeremy L Thompson   Ceed ceed;
3914556e63SJeremy L Thompson 
4014556e63SJeremy L Thompson   CeedInit(argv[1], &ceed);
4114556e63SJeremy L Thompson 
4214556e63SJeremy L Thompson   for (CeedInt dim = 1; dim <= 3; dim++) {
434fee36f0SJeremy L Thompson     CeedVector x_corners, x_from, x_to, u_from, u_to, du_to;
4414556e63SJeremy L Thompson     CeedBasis  basis_x, basis_from, basis_to, basis_project;
454fee36f0SJeremy 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);
46*99e754f0SJeremy L Thompson     CeedScalar tol;
474fee36f0SJeremy L Thompson 
48*99e754f0SJeremy L Thompson     {
49*99e754f0SJeremy L Thompson       CeedScalarType scalar_type;
50*99e754f0SJeremy L Thompson 
51*99e754f0SJeremy L Thompson       CeedGetScalarType(&scalar_type);
52*99e754f0SJeremy L Thompson       tol = GetTolerance(scalar_type, dim);
53*99e754f0SJeremy L Thompson     }
544fee36f0SJeremy L Thompson     CeedVectorCreate(ceed, x_dim * dim, &x_corners);
554fee36f0SJeremy L Thompson     {
564fee36f0SJeremy L Thompson       CeedScalar x_array[x_dim * dim];
5714556e63SJeremy L Thompson 
582b730f8bSJeremy L Thompson       for (CeedInt d = 0; d < dim; d++) {
593c9d155aSZach Atkins         for (CeedInt i = 0; i < x_dim; i++) x_array[x_dim * d + i] = (i % CeedIntPow(2, d + 1)) / CeedIntPow(2, d) ? 1 : -1;
602b730f8bSJeremy L Thompson       }
614fee36f0SJeremy L Thompson       CeedVectorSetArray(x_corners, CEED_MEM_HOST, CEED_COPY_VALUES, x_array);
624fee36f0SJeremy L Thompson     }
634fee36f0SJeremy L Thompson     CeedVectorCreate(ceed, p_from_dim * dim, &x_from);
644fee36f0SJeremy L Thompson     CeedVectorCreate(ceed, p_to_dim * dim, &x_to);
654fee36f0SJeremy L Thompson     CeedVectorCreate(ceed, p_from_dim, &u_from);
664fee36f0SJeremy L Thompson     CeedVectorSetValue(u_from, 0);
674fee36f0SJeremy L Thompson     CeedVectorCreate(ceed, p_to_dim, &u_to);
684fee36f0SJeremy L Thompson     CeedVectorSetValue(u_to, 0);
694fee36f0SJeremy L Thompson     CeedVectorCreate(ceed, p_to_dim * dim, &du_to);
704fee36f0SJeremy L Thompson     CeedVectorSetValue(du_to, 0);
7114556e63SJeremy L Thompson 
7214556e63SJeremy L Thompson     // Get nodal coordinates
734fee36f0SJeremy L Thompson     CeedBasisCreateTensorH1Lagrange(ceed, dim, dim, 2, p_from, CEED_GAUSS_LOBATTO, &basis_x);
744fee36f0SJeremy L Thompson     CeedBasisApply(basis_x, 1, CEED_NOTRANSPOSE, CEED_EVAL_INTERP, x_corners, x_from);
7514556e63SJeremy L Thompson     CeedBasisDestroy(&basis_x);
764fee36f0SJeremy L Thompson     CeedBasisCreateTensorH1Lagrange(ceed, dim, dim, 2, p_to, CEED_GAUSS_LOBATTO, &basis_x);
774fee36f0SJeremy L Thompson     CeedBasisApply(basis_x, 1, CEED_NOTRANSPOSE, CEED_EVAL_INTERP, x_corners, x_to);
7814556e63SJeremy L Thompson     CeedBasisDestroy(&basis_x);
7914556e63SJeremy L Thompson 
8014556e63SJeremy L Thompson     // Create U and projection bases
814fee36f0SJeremy L Thompson     CeedBasisCreateTensorH1Lagrange(ceed, dim, 1, p_from, q, CEED_GAUSS, &basis_from);
824fee36f0SJeremy L Thompson     CeedBasisCreateTensorH1Lagrange(ceed, dim, 1, p_to, q, CEED_GAUSS, &basis_to);
8314556e63SJeremy L Thompson     CeedBasisCreateProjection(basis_from, basis_to, &basis_project);
8414556e63SJeremy L Thompson 
8514556e63SJeremy L Thompson     // Setup coarse solution
864fee36f0SJeremy L Thompson     {
874fee36f0SJeremy L Thompson       const CeedScalar *x_array;
884fee36f0SJeremy L Thompson       CeedScalar        u_array[p_from_dim];
894fee36f0SJeremy L Thompson 
904fee36f0SJeremy L Thompson       CeedVectorGetArrayRead(x_from, CEED_MEM_HOST, &x_array);
914fee36f0SJeremy L Thompson       for (CeedInt i = 0; i < p_from_dim; i++) {
924fee36f0SJeremy L Thompson         CeedScalar coord[dim];
934fee36f0SJeremy L Thompson         for (CeedInt d = 0; d < dim; d++) coord[d] = x_array[p_from_dim * d + i];
944fee36f0SJeremy L Thompson         u_array[i] = Eval(dim, coord);
9514556e63SJeremy L Thompson       }
964fee36f0SJeremy L Thompson       CeedVectorRestoreArrayRead(x_from, &x_array);
974fee36f0SJeremy L Thompson       CeedVectorSetArray(u_from, CEED_MEM_HOST, CEED_COPY_VALUES, u_array);
984fee36f0SJeremy L Thompson     }
9914556e63SJeremy L Thompson 
10014556e63SJeremy L Thompson     // Project to fine basis
1014fee36f0SJeremy L Thompson     CeedBasisApply(basis_project, 1, CEED_NOTRANSPOSE, CEED_EVAL_INTERP, u_from, u_to);
10214556e63SJeremy L Thompson 
10314556e63SJeremy L Thompson     // Check solution
1044fee36f0SJeremy L Thompson     {
1054fee36f0SJeremy L Thompson       const CeedScalar *x_array, *u_array;
1064fee36f0SJeremy L Thompson 
1074fee36f0SJeremy L Thompson       CeedVectorGetArrayRead(x_to, CEED_MEM_HOST, &x_array);
1084fee36f0SJeremy L Thompson       CeedVectorGetArrayRead(u_to, CEED_MEM_HOST, &u_array);
1094fee36f0SJeremy L Thompson       for (CeedInt i = 0; i < p_to_dim; i++) {
1104fee36f0SJeremy L Thompson         CeedScalar coord[dim];
1114fee36f0SJeremy L Thompson         for (CeedInt d = 0; d < dim; d++) coord[d] = x_array[d * p_to_dim + i];
1124fee36f0SJeremy L Thompson         const CeedScalar u = Eval(dim, coord);
1134fee36f0SJeremy L Thompson         if (fabs(u - u_array[i]) > tol) printf("[%" CeedInt_FMT ", %" CeedInt_FMT "] %f != %f\n", dim, i, u_array[i], u);
11414556e63SJeremy L Thompson       }
1154fee36f0SJeremy L Thompson       CeedVectorRestoreArrayRead(x_to, &x_array);
1164fee36f0SJeremy L Thompson       CeedVectorRestoreArrayRead(u_to, &u_array);
1174fee36f0SJeremy L Thompson     }
11814556e63SJeremy L Thompson 
11914556e63SJeremy L Thompson     // Project and take gradient
1204fee36f0SJeremy L Thompson     CeedBasisApply(basis_project, 1, CEED_NOTRANSPOSE, CEED_EVAL_GRAD, u_from, du_to);
12114556e63SJeremy L Thompson 
12214556e63SJeremy L Thompson     // Check solution
1234fee36f0SJeremy L Thompson     {
1244fee36f0SJeremy L Thompson       const CeedScalar *x_array, *du_array;
1254fee36f0SJeremy L Thompson 
1264fee36f0SJeremy L Thompson       CeedVectorGetArrayRead(x_to, CEED_MEM_HOST, &x_array);
1274fee36f0SJeremy L Thompson       CeedVectorGetArrayRead(du_to, CEED_MEM_HOST, &du_array);
1284fee36f0SJeremy L Thompson       for (CeedInt i = 0; i < p_to_dim; i++) {
1294fee36f0SJeremy L Thompson         CeedScalar coord[dim];
130*99e754f0SJeremy L Thompson 
1314fee36f0SJeremy L Thompson         for (CeedInt d = 0; d < dim; d++) coord[d] = x_array[p_to_dim * d + i];
13214556e63SJeremy L Thompson         for (CeedInt d = 0; d < dim; d++) {
1334fee36f0SJeremy L Thompson           const CeedScalar du = EvalGrad(d, coord);
134*99e754f0SJeremy L Thompson 
1353c9d155aSZach Atkins           if (fabs(du - du_array[p_to_dim * d + i]) > tol) {
13614556e63SJeremy L Thompson             // LCOV_EXCL_START
1374fee36f0SJeremy 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);
13814556e63SJeremy L Thompson             // LCOV_EXCL_STOP
13914556e63SJeremy L Thompson           }
14014556e63SJeremy L Thompson         }
1412b730f8bSJeremy L Thompson       }
1424fee36f0SJeremy L Thompson       CeedVectorRestoreArrayRead(x_to, &x_array);
1434fee36f0SJeremy L Thompson       CeedVectorRestoreArrayRead(du_to, &du_array);
1444fee36f0SJeremy L Thompson     }
14514556e63SJeremy L Thompson 
1464fee36f0SJeremy L Thompson     CeedVectorDestroy(&x_corners);
1474fee36f0SJeremy L Thompson     CeedVectorDestroy(&x_from);
1484fee36f0SJeremy L Thompson     CeedVectorDestroy(&x_to);
1494fee36f0SJeremy L Thompson     CeedVectorDestroy(&u_from);
1504fee36f0SJeremy L Thompson     CeedVectorDestroy(&u_to);
1514fee36f0SJeremy L Thompson     CeedVectorDestroy(&du_to);
15214556e63SJeremy L Thompson     CeedBasisDestroy(&basis_from);
15314556e63SJeremy L Thompson     CeedBasisDestroy(&basis_to);
15414556e63SJeremy L Thompson     CeedBasisDestroy(&basis_project);
15514556e63SJeremy L Thompson   }
15614556e63SJeremy L Thompson   CeedDestroy(&ceed);
15714556e63SJeremy L Thompson   return 0;
15814556e63SJeremy L Thompson }
159