xref: /libCEED/tests/t319-basis.c (revision 49aac155e7a09736f56fb3abac0f57dab29f7cbf)
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>
6*49aac155SJeremy 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);
464fee36f0SJeremy L Thompson 
474fee36f0SJeremy L Thompson     CeedVectorCreate(ceed, x_dim * dim, &x_corners);
484fee36f0SJeremy L Thompson     {
494fee36f0SJeremy L Thompson       CeedScalar x_array[x_dim * dim];
5014556e63SJeremy L Thompson 
512b730f8bSJeremy L Thompson       for (CeedInt d = 0; d < dim; d++) {
524fee36f0SJeremy 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;
532b730f8bSJeremy L Thompson       }
544fee36f0SJeremy L Thompson       CeedVectorSetArray(x_corners, CEED_MEM_HOST, CEED_COPY_VALUES, x_array);
554fee36f0SJeremy L Thompson     }
564fee36f0SJeremy L Thompson     CeedVectorCreate(ceed, p_from_dim * dim, &x_from);
574fee36f0SJeremy L Thompson     CeedVectorCreate(ceed, p_to_dim * dim, &x_to);
584fee36f0SJeremy L Thompson     CeedVectorCreate(ceed, p_from_dim, &u_from);
594fee36f0SJeremy L Thompson     CeedVectorSetValue(u_from, 0);
604fee36f0SJeremy L Thompson     CeedVectorCreate(ceed, p_to_dim, &u_to);
614fee36f0SJeremy L Thompson     CeedVectorSetValue(u_to, 0);
624fee36f0SJeremy L Thompson     CeedVectorCreate(ceed, p_to_dim * dim, &du_to);
634fee36f0SJeremy L Thompson     CeedVectorSetValue(du_to, 0);
6414556e63SJeremy L Thompson 
6514556e63SJeremy L Thompson     // Get nodal coordinates
664fee36f0SJeremy L Thompson     CeedBasisCreateTensorH1Lagrange(ceed, dim, dim, 2, p_from, CEED_GAUSS_LOBATTO, &basis_x);
674fee36f0SJeremy L Thompson     CeedBasisApply(basis_x, 1, CEED_NOTRANSPOSE, CEED_EVAL_INTERP, x_corners, x_from);
6814556e63SJeremy L Thompson     CeedBasisDestroy(&basis_x);
694fee36f0SJeremy L Thompson     CeedBasisCreateTensorH1Lagrange(ceed, dim, dim, 2, p_to, CEED_GAUSS_LOBATTO, &basis_x);
704fee36f0SJeremy L Thompson     CeedBasisApply(basis_x, 1, CEED_NOTRANSPOSE, CEED_EVAL_INTERP, x_corners, x_to);
7114556e63SJeremy L Thompson     CeedBasisDestroy(&basis_x);
7214556e63SJeremy L Thompson 
7314556e63SJeremy L Thompson     // Create U and projection bases
744fee36f0SJeremy L Thompson     CeedBasisCreateTensorH1Lagrange(ceed, dim, 1, p_from, q, CEED_GAUSS, &basis_from);
754fee36f0SJeremy L Thompson     CeedBasisCreateTensorH1Lagrange(ceed, dim, 1, p_to, q, CEED_GAUSS, &basis_to);
7614556e63SJeremy L Thompson     CeedBasisCreateProjection(basis_from, basis_to, &basis_project);
7714556e63SJeremy L Thompson 
7814556e63SJeremy L Thompson     // Setup coarse solution
794fee36f0SJeremy L Thompson     {
804fee36f0SJeremy L Thompson       const CeedScalar *x_array;
814fee36f0SJeremy L Thompson       CeedScalar        u_array[p_from_dim];
824fee36f0SJeremy L Thompson 
834fee36f0SJeremy L Thompson       CeedVectorGetArrayRead(x_from, CEED_MEM_HOST, &x_array);
844fee36f0SJeremy L Thompson       for (CeedInt i = 0; i < p_from_dim; i++) {
854fee36f0SJeremy L Thompson         CeedScalar coord[dim];
864fee36f0SJeremy L Thompson         for (CeedInt d = 0; d < dim; d++) coord[d] = x_array[p_from_dim * d + i];
874fee36f0SJeremy L Thompson         u_array[i] = Eval(dim, coord);
8814556e63SJeremy L Thompson       }
894fee36f0SJeremy L Thompson       CeedVectorRestoreArrayRead(x_from, &x_array);
904fee36f0SJeremy L Thompson       CeedVectorSetArray(u_from, CEED_MEM_HOST, CEED_COPY_VALUES, u_array);
914fee36f0SJeremy L Thompson     }
9214556e63SJeremy L Thompson 
9314556e63SJeremy L Thompson     // Project to fine basis
944fee36f0SJeremy L Thompson     CeedBasisApply(basis_project, 1, CEED_NOTRANSPOSE, CEED_EVAL_INTERP, u_from, u_to);
9514556e63SJeremy L Thompson 
9614556e63SJeremy L Thompson     // Check solution
9714556e63SJeremy L Thompson     CeedScalar tol = GetTolerance(CEED_SCALAR_TYPE, dim);
984fee36f0SJeremy L Thompson     {
994fee36f0SJeremy L Thompson       const CeedScalar *x_array, *u_array;
1004fee36f0SJeremy L Thompson 
1014fee36f0SJeremy L Thompson       CeedVectorGetArrayRead(x_to, CEED_MEM_HOST, &x_array);
1024fee36f0SJeremy L Thompson       CeedVectorGetArrayRead(u_to, CEED_MEM_HOST, &u_array);
1034fee36f0SJeremy L Thompson       for (CeedInt i = 0; i < p_to_dim; i++) {
1044fee36f0SJeremy L Thompson         CeedScalar coord[dim];
1054fee36f0SJeremy L Thompson         for (CeedInt d = 0; d < dim; d++) coord[d] = x_array[d * p_to_dim + i];
1064fee36f0SJeremy L Thompson         const CeedScalar u = Eval(dim, coord);
1074fee36f0SJeremy L Thompson         if (fabs(u - u_array[i]) > tol) printf("[%" CeedInt_FMT ", %" CeedInt_FMT "] %f != %f\n", dim, i, u_array[i], u);
10814556e63SJeremy L Thompson       }
1094fee36f0SJeremy L Thompson       CeedVectorRestoreArrayRead(x_to, &x_array);
1104fee36f0SJeremy L Thompson       CeedVectorRestoreArrayRead(u_to, &u_array);
1114fee36f0SJeremy L Thompson     }
11214556e63SJeremy L Thompson 
11314556e63SJeremy L Thompson     // Project and take gradient
1144fee36f0SJeremy L Thompson     CeedBasisApply(basis_project, 1, CEED_NOTRANSPOSE, CEED_EVAL_GRAD, u_from, du_to);
11514556e63SJeremy L Thompson 
11614556e63SJeremy L Thompson     // Check solution
1174fee36f0SJeremy L Thompson     {
1184fee36f0SJeremy L Thompson       const CeedScalar *x_array, *du_array;
1194fee36f0SJeremy L Thompson 
1204fee36f0SJeremy L Thompson       CeedVectorGetArrayRead(x_to, CEED_MEM_HOST, &x_array);
1214fee36f0SJeremy L Thompson       CeedVectorGetArrayRead(du_to, CEED_MEM_HOST, &du_array);
1224fee36f0SJeremy L Thompson       for (CeedInt i = 0; i < p_to_dim; i++) {
1234fee36f0SJeremy L Thompson         CeedScalar coord[dim];
1244fee36f0SJeremy L Thompson         for (CeedInt d = 0; d < dim; d++) coord[d] = x_array[p_to_dim * d + i];
12514556e63SJeremy L Thompson         for (CeedInt d = 0; d < dim; d++) {
1264fee36f0SJeremy L Thompson           const CeedScalar du = EvalGrad(d, coord);
1274fee36f0SJeremy L Thompson           if (fabs(du - du_array[p_to_dim * (dim - 1 - d) + i]) > tol) {
12814556e63SJeremy L Thompson             // LCOV_EXCL_START
1294fee36f0SJeremy 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);
13014556e63SJeremy L Thompson             // LCOV_EXCL_STOP
13114556e63SJeremy L Thompson           }
13214556e63SJeremy L Thompson         }
1332b730f8bSJeremy L Thompson       }
1344fee36f0SJeremy L Thompson       CeedVectorRestoreArrayRead(x_to, &x_array);
1354fee36f0SJeremy L Thompson       CeedVectorRestoreArrayRead(du_to, &du_array);
1364fee36f0SJeremy L Thompson     }
13714556e63SJeremy L Thompson 
1384fee36f0SJeremy L Thompson     CeedVectorDestroy(&x_corners);
1394fee36f0SJeremy L Thompson     CeedVectorDestroy(&x_from);
1404fee36f0SJeremy L Thompson     CeedVectorDestroy(&x_to);
1414fee36f0SJeremy L Thompson     CeedVectorDestroy(&u_from);
1424fee36f0SJeremy L Thompson     CeedVectorDestroy(&u_to);
1434fee36f0SJeremy L Thompson     CeedVectorDestroy(&du_to);
14414556e63SJeremy L Thompson     CeedBasisDestroy(&basis_from);
14514556e63SJeremy L Thompson     CeedBasisDestroy(&basis_to);
14614556e63SJeremy L Thompson     CeedBasisDestroy(&basis_project);
14714556e63SJeremy L Thompson   }
14814556e63SJeremy L Thompson   CeedDestroy(&ceed);
14914556e63SJeremy L Thompson   return 0;
15014556e63SJeremy L Thompson }
151