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 4706bf528SJames Wright #include "t319-basis.h" 514556e63SJeremy L Thompson #include <ceed.h> 614556e63SJeremy L Thompson #include <math.h> 749aac155SJeremy L Thompson #include <stdio.h> 814556e63SJeremy L Thompson 914556e63SJeremy L Thompson static CeedScalar Eval(CeedInt dim, const CeedScalar x[]) { 1014556e63SJeremy L Thompson CeedScalar result = (x[0] + 0.1) * (x[0] + 0.1); 1114556e63SJeremy L Thompson if (dim > 1) result += (x[1] + 0.2) * (x[1] + 0.2); 1214556e63SJeremy L Thompson if (dim > 2) result += -(x[2] + 0.3) * (x[2] + 0.3); 1314556e63SJeremy L Thompson return result; 1414556e63SJeremy L Thompson } 1514556e63SJeremy L Thompson 1614556e63SJeremy L Thompson static CeedScalar EvalGrad(CeedInt dim, const CeedScalar x[]) { 1714556e63SJeremy L Thompson switch (dim) { 182b730f8bSJeremy L Thompson case 0: 192b730f8bSJeremy L Thompson return 2 * x[0] + 0.2; 202b730f8bSJeremy L Thompson case 1: 212b730f8bSJeremy L Thompson return 2 * x[1] + 0.4; 222b730f8bSJeremy L Thompson default: 232b730f8bSJeremy L Thompson return -2 * x[2] - 0.6; 2414556e63SJeremy L Thompson } 2514556e63SJeremy L Thompson } 2614556e63SJeremy L Thompson 2714556e63SJeremy L Thompson static CeedScalar GetTolerance(CeedScalarType scalar_type, int dim) { 2814556e63SJeremy L Thompson CeedScalar tol; 2914556e63SJeremy L Thompson if (scalar_type == CEED_SCALAR_FP32) { 302b730f8bSJeremy L Thompson if (dim == 3) tol = 1.e-4; 312b730f8bSJeremy L Thompson else tol = 1.e-5; 3214556e63SJeremy L Thompson } else { 3314556e63SJeremy L Thompson tol = 1.e-11; 3414556e63SJeremy L Thompson } 3514556e63SJeremy L Thompson return tol; 3614556e63SJeremy L Thompson } 3714556e63SJeremy L Thompson 38097cc795SJames Wright static void VerifyProjectedBasis(CeedBasis basis_project, CeedInt dim, CeedInt p_to_dim, CeedInt p_from_dim, CeedVector x_to, CeedVector x_from, 39097cc795SJames Wright CeedVector u_to, CeedVector u_from, CeedVector du_to) { 4099e754f0SJeremy L Thompson CeedScalar tol; 414fee36f0SJeremy L Thompson 4299e754f0SJeremy L Thompson { 4399e754f0SJeremy L Thompson CeedScalarType scalar_type; 4499e754f0SJeremy L Thompson 4599e754f0SJeremy L Thompson CeedGetScalarType(&scalar_type); 4699e754f0SJeremy L Thompson tol = GetTolerance(scalar_type, dim); 4799e754f0SJeremy L Thompson } 4814556e63SJeremy L Thompson 4914556e63SJeremy L Thompson // Setup coarse solution 504fee36f0SJeremy L Thompson { 514fee36f0SJeremy L Thompson const CeedScalar *x_array; 524fee36f0SJeremy L Thompson CeedScalar u_array[p_from_dim]; 534fee36f0SJeremy L Thompson 544fee36f0SJeremy L Thompson CeedVectorGetArrayRead(x_from, CEED_MEM_HOST, &x_array); 554fee36f0SJeremy L Thompson for (CeedInt i = 0; i < p_from_dim; i++) { 564fee36f0SJeremy L Thompson CeedScalar coord[dim]; 574fee36f0SJeremy L Thompson for (CeedInt d = 0; d < dim; d++) coord[d] = x_array[p_from_dim * d + i]; 584fee36f0SJeremy L Thompson u_array[i] = Eval(dim, coord); 5914556e63SJeremy L Thompson } 604fee36f0SJeremy L Thompson CeedVectorRestoreArrayRead(x_from, &x_array); 614fee36f0SJeremy L Thompson CeedVectorSetArray(u_from, CEED_MEM_HOST, CEED_COPY_VALUES, u_array); 624fee36f0SJeremy L Thompson } 6314556e63SJeremy L Thompson 6414556e63SJeremy L Thompson // Project to fine basis 654fee36f0SJeremy L Thompson CeedBasisApply(basis_project, 1, CEED_NOTRANSPOSE, CEED_EVAL_INTERP, u_from, u_to); 6614556e63SJeremy L Thompson 6714556e63SJeremy L Thompson // Check solution 684fee36f0SJeremy L Thompson { 694fee36f0SJeremy L Thompson const CeedScalar *x_array, *u_array; 704fee36f0SJeremy L Thompson 714fee36f0SJeremy L Thompson CeedVectorGetArrayRead(x_to, CEED_MEM_HOST, &x_array); 724fee36f0SJeremy L Thompson CeedVectorGetArrayRead(u_to, CEED_MEM_HOST, &u_array); 734fee36f0SJeremy L Thompson for (CeedInt i = 0; i < p_to_dim; i++) { 744fee36f0SJeremy L Thompson CeedScalar coord[dim]; 754fee36f0SJeremy L Thompson for (CeedInt d = 0; d < dim; d++) coord[d] = x_array[d * p_to_dim + i]; 764fee36f0SJeremy L Thompson const CeedScalar u = Eval(dim, coord); 774fee36f0SJeremy L Thompson if (fabs(u - u_array[i]) > tol) printf("[%" CeedInt_FMT ", %" CeedInt_FMT "] %f != %f\n", dim, i, u_array[i], u); 7814556e63SJeremy L Thompson } 794fee36f0SJeremy L Thompson CeedVectorRestoreArrayRead(x_to, &x_array); 804fee36f0SJeremy L Thompson CeedVectorRestoreArrayRead(u_to, &u_array); 814fee36f0SJeremy L Thompson } 8214556e63SJeremy L Thompson 8314556e63SJeremy L Thompson // Project and take gradient 844fee36f0SJeremy L Thompson CeedBasisApply(basis_project, 1, CEED_NOTRANSPOSE, CEED_EVAL_GRAD, u_from, du_to); 8514556e63SJeremy L Thompson 8614556e63SJeremy L Thompson // Check solution 874fee36f0SJeremy L Thompson { 884fee36f0SJeremy L Thompson const CeedScalar *x_array, *du_array; 894fee36f0SJeremy L Thompson 904fee36f0SJeremy L Thompson CeedVectorGetArrayRead(x_to, CEED_MEM_HOST, &x_array); 914fee36f0SJeremy L Thompson CeedVectorGetArrayRead(du_to, CEED_MEM_HOST, &du_array); 924fee36f0SJeremy L Thompson for (CeedInt i = 0; i < p_to_dim; i++) { 934fee36f0SJeremy L Thompson CeedScalar coord[dim]; 9499e754f0SJeremy L Thompson 954fee36f0SJeremy L Thompson for (CeedInt d = 0; d < dim; d++) coord[d] = x_array[p_to_dim * d + i]; 9614556e63SJeremy L Thompson for (CeedInt d = 0; d < dim; d++) { 974fee36f0SJeremy L Thompson const CeedScalar du = EvalGrad(d, coord); 9899e754f0SJeremy L Thompson 993c9d155aSZach Atkins if (fabs(du - du_array[p_to_dim * d + i]) > tol) { 10014556e63SJeremy L Thompson // LCOV_EXCL_START 1014fee36f0SJeremy 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); 10214556e63SJeremy L Thompson // LCOV_EXCL_STOP 10314556e63SJeremy L Thompson } 10414556e63SJeremy L Thompson } 1052b730f8bSJeremy L Thompson } 1064fee36f0SJeremy L Thompson CeedVectorRestoreArrayRead(x_to, &x_array); 1074fee36f0SJeremy L Thompson CeedVectorRestoreArrayRead(du_to, &du_array); 1084fee36f0SJeremy L Thompson } 109097cc795SJames Wright } 110097cc795SJames Wright 111097cc795SJames Wright int main(int argc, char **argv) { 112097cc795SJames Wright Ceed ceed; 113097cc795SJames Wright 114097cc795SJames Wright CeedInit(argv[1], &ceed); 115097cc795SJames Wright 116097cc795SJames Wright for (CeedInt dim = 1; dim <= 3; dim++) { 117097cc795SJames Wright CeedVector x_corners, x_from, x_to, u_from, u_to, du_to; 118097cc795SJames Wright CeedBasis basis_x, basis_from, basis_to, basis_project; 119097cc795SJames Wright 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); 120097cc795SJames Wright 121097cc795SJames Wright CeedVectorCreate(ceed, x_dim * dim, &x_corners); 122097cc795SJames Wright { 123097cc795SJames Wright CeedScalar x_array[x_dim * dim]; 124097cc795SJames Wright 125097cc795SJames Wright for (CeedInt d = 0; d < dim; d++) { 126097cc795SJames Wright for (CeedInt i = 0; i < x_dim; i++) x_array[x_dim * d + i] = (i % CeedIntPow(2, d + 1)) / CeedIntPow(2, d) ? 1 : -1; 127097cc795SJames Wright } 128097cc795SJames Wright CeedVectorSetArray(x_corners, CEED_MEM_HOST, CEED_COPY_VALUES, x_array); 129097cc795SJames Wright } 130097cc795SJames Wright CeedVectorCreate(ceed, p_from_dim * dim, &x_from); 131097cc795SJames Wright CeedVectorCreate(ceed, p_to_dim * dim, &x_to); 132097cc795SJames Wright CeedVectorCreate(ceed, p_from_dim, &u_from); 133097cc795SJames Wright CeedVectorSetValue(u_from, 0); 134097cc795SJames Wright CeedVectorCreate(ceed, p_to_dim, &u_to); 135097cc795SJames Wright CeedVectorSetValue(u_to, 0); 136097cc795SJames Wright CeedVectorCreate(ceed, p_to_dim * dim, &du_to); 137097cc795SJames Wright CeedVectorSetValue(du_to, 0); 138097cc795SJames Wright 139097cc795SJames Wright // Get nodal coordinates 140097cc795SJames Wright CeedBasisCreateTensorH1Lagrange(ceed, dim, dim, 2, p_from, CEED_GAUSS_LOBATTO, &basis_x); 141097cc795SJames Wright CeedBasisApply(basis_x, 1, CEED_NOTRANSPOSE, CEED_EVAL_INTERP, x_corners, x_from); 142097cc795SJames Wright CeedBasisDestroy(&basis_x); 143097cc795SJames Wright CeedBasisCreateTensorH1Lagrange(ceed, dim, dim, 2, p_to, CEED_GAUSS_LOBATTO, &basis_x); 144097cc795SJames Wright CeedBasisApply(basis_x, 1, CEED_NOTRANSPOSE, CEED_EVAL_INTERP, x_corners, x_to); 145097cc795SJames Wright CeedBasisDestroy(&basis_x); 146097cc795SJames Wright 147097cc795SJames Wright // Create U and projection bases 148097cc795SJames Wright CeedBasisCreateTensorH1Lagrange(ceed, dim, 1, p_from, q, CEED_GAUSS, &basis_from); 149097cc795SJames Wright CeedBasisCreateTensorH1Lagrange(ceed, dim, 1, p_to, q, CEED_GAUSS, &basis_to); 150097cc795SJames Wright CeedBasisCreateProjection(basis_from, basis_to, &basis_project); 151097cc795SJames Wright 152097cc795SJames Wright VerifyProjectedBasis(basis_project, dim, p_to_dim, p_from_dim, x_to, x_from, u_to, u_from, du_to); 153097cc795SJames Wright 154e104ad11SJames Wright // Create non-tensor bases 155097cc795SJames Wright CeedBasis basis_from_nontensor, basis_to_nontensor; 156e104ad11SJames Wright { 157097cc795SJames Wright CeedElemTopology topo; 158*cb270d31SJeremy L Thompson CeedInt num_comp, num_nodes, num_qpts; 159097cc795SJames Wright const CeedScalar *interp, *grad; 160097cc795SJames Wright 161097cc795SJames Wright CeedBasisGetTopology(basis_from, &topo); 162097cc795SJames Wright CeedBasisGetNumComponents(basis_from, &num_comp); 163097cc795SJames Wright CeedBasisGetNumNodes(basis_from, &num_nodes); 164*cb270d31SJeremy L Thompson CeedBasisGetNumQuadraturePoints(basis_from, &num_qpts); 165097cc795SJames Wright CeedBasisGetInterp(basis_from, &interp); 166097cc795SJames Wright CeedBasisGetGrad(basis_from, &grad); 167*cb270d31SJeremy L Thompson CeedBasisCreateH1(ceed, topo, num_comp, num_nodes, num_qpts, interp, grad, NULL, NULL, &basis_from_nontensor); 168097cc795SJames Wright 169097cc795SJames Wright CeedBasisGetTopology(basis_to, &topo); 170097cc795SJames Wright CeedBasisGetNumComponents(basis_to, &num_comp); 171097cc795SJames Wright CeedBasisGetNumNodes(basis_to, &num_nodes); 172*cb270d31SJeremy L Thompson CeedBasisGetNumQuadraturePoints(basis_to, &num_qpts); 173097cc795SJames Wright CeedBasisGetInterp(basis_to, &interp); 174097cc795SJames Wright CeedBasisGetGrad(basis_to, &grad); 175*cb270d31SJeremy L Thompson CeedBasisCreateH1(ceed, topo, num_comp, num_nodes, num_qpts, interp, grad, NULL, NULL, &basis_to_nontensor); 176097cc795SJames Wright } 177097cc795SJames Wright 178e104ad11SJames Wright // Test projection on non-tensor bases 179e104ad11SJames Wright CeedBasisDestroy(&basis_project); 180e104ad11SJames Wright CeedBasisCreateProjection(basis_from_nontensor, basis_to_nontensor, &basis_project); 181e104ad11SJames Wright VerifyProjectedBasis(basis_project, dim, p_to_dim, p_from_dim, x_to, x_from, u_to, u_from, du_to); 182e104ad11SJames Wright 183e104ad11SJames Wright // Test projection from non-tensor to tensor 184e104ad11SJames Wright CeedBasisDestroy(&basis_project); 185e104ad11SJames Wright CeedBasisCreateProjection(basis_from_nontensor, basis_to, &basis_project); 186e104ad11SJames Wright VerifyProjectedBasis(basis_project, dim, p_to_dim, p_from_dim, x_to, x_from, u_to, u_from, du_to); 187e104ad11SJames Wright 188e104ad11SJames Wright // Test projection from tensor to non-tensor 189e104ad11SJames Wright CeedBasisDestroy(&basis_project); 190e104ad11SJames Wright CeedBasisCreateProjection(basis_from, basis_to_nontensor, &basis_project); 191097cc795SJames Wright VerifyProjectedBasis(basis_project, dim, p_to_dim, p_from_dim, x_to, x_from, u_to, u_from, du_to); 19214556e63SJeremy L Thompson 1934fee36f0SJeremy L Thompson CeedVectorDestroy(&x_corners); 1944fee36f0SJeremy L Thompson CeedVectorDestroy(&x_from); 1954fee36f0SJeremy L Thompson CeedVectorDestroy(&x_to); 1964fee36f0SJeremy L Thompson CeedVectorDestroy(&u_from); 1974fee36f0SJeremy L Thompson CeedVectorDestroy(&u_to); 1984fee36f0SJeremy L Thompson CeedVectorDestroy(&du_to); 19914556e63SJeremy L Thompson CeedBasisDestroy(&basis_from); 200e104ad11SJames Wright CeedBasisDestroy(&basis_from_nontensor); 20114556e63SJeremy L Thompson CeedBasisDestroy(&basis_to); 202e104ad11SJames Wright CeedBasisDestroy(&basis_to_nontensor); 20314556e63SJeremy L Thompson CeedBasisDestroy(&basis_project); 20414556e63SJeremy L Thompson } 205706bf528SJames Wright 206706bf528SJames Wright // Test projection between basis of different topological dimension 207706bf528SJames Wright { 208706bf528SJames Wright CeedInt face_dim = 2, P_1D = 2; 209706bf528SJames Wright CeedBasis basis_face, basis_cell_to_face, basis_proj; 210706bf528SJames Wright 211706bf528SJames Wright CeedScalar *q_ref = NULL, *q_weights = NULL; 212706bf528SJames Wright const CeedScalar *grad, *interp; 213706bf528SJames Wright CeedInt P, Q; 214706bf528SJames Wright GetCellToFaceTabulation(CEED_GAUSS, &P, &Q, &interp, &grad); 215706bf528SJames Wright 216706bf528SJames Wright CeedBasisCreateTensorH1Lagrange(ceed, face_dim, 1, 2, P_1D, CEED_GAUSS, &basis_face); 217706bf528SJames Wright CeedBasisCreateH1(ceed, CEED_TOPOLOGY_HEX, 1, P, Q, (CeedScalar *)interp, (CeedScalar *)grad, q_ref, q_weights, &basis_cell_to_face); 218706bf528SJames Wright CeedBasisCreateProjection(basis_cell_to_face, basis_face, &basis_proj); 219706bf528SJames Wright const CeedScalar *interp_proj, *grad_proj, *interp_proj_ref, *grad_proj_ref; 220706bf528SJames Wright 221706bf528SJames Wright GetCellToFaceTabulation(CEED_GAUSS_LOBATTO, NULL, NULL, &interp_proj_ref, &grad_proj_ref); 222706bf528SJames Wright CeedBasisGetInterp(basis_proj, &interp_proj); 223706bf528SJames Wright CeedBasisGetGrad(basis_proj, &grad_proj); 224706bf528SJames Wright CeedScalar tol = 100 * CEED_EPSILON; 225706bf528SJames Wright 226706bf528SJames Wright for (CeedInt i = 0; i < 4 * 8; i++) { 2276c10af5dSJeremy L Thompson if (fabs(interp_proj[i] - ((CeedScalar *)interp_proj_ref)[i]) > tol) { 2286c10af5dSJeremy L Thompson // LCOV_EXCL_START 229706bf528SJames Wright printf("Mixed Topology Projection: interp[%" CeedInt_FMT "] expected %f, got %f\n", i, interp_proj[i], ((CeedScalar *)interp_proj_ref)[i]); 2306c10af5dSJeremy L Thompson // LCOV_EXCL_STOP 2316c10af5dSJeremy L Thompson } 232706bf528SJames Wright } 233706bf528SJames Wright 234706bf528SJames Wright for (CeedInt i = 0; i < 3 * 4 * 8; i++) { 2356c10af5dSJeremy L Thompson if (fabs(grad_proj[i] - ((CeedScalar *)grad_proj_ref)[i]) > tol) { 2366c10af5dSJeremy L Thompson // LCOV_EXCL_START 237706bf528SJames Wright printf("Mixed Topology Projection: grad[%" CeedInt_FMT "] expected %f, got %f\n", i, grad_proj[i], ((CeedScalar *)grad_proj_ref)[i]); 2386c10af5dSJeremy L Thompson // LCOV_EXCL_STOP 2396c10af5dSJeremy L Thompson } 240706bf528SJames Wright } 241706bf528SJames Wright 242706bf528SJames Wright CeedBasisDestroy(&basis_face); 243706bf528SJames Wright CeedBasisDestroy(&basis_cell_to_face); 244706bf528SJames Wright CeedBasisDestroy(&basis_proj); 245706bf528SJames Wright } 24614556e63SJeremy L Thompson CeedDestroy(&ceed); 24714556e63SJeremy L Thompson return 0; 24814556e63SJeremy L Thompson } 249