1 // Copyright (c) 2017-2018, Lawrence Livermore National Security, LLC. 2 // Produced at the Lawrence Livermore National Laboratory. LLNL-CODE-734707. 3 // All Rights reserved. See files LICENSE and NOTICE for details. 4 // 5 // This file is part of CEED, a collection of benchmarks, miniapps, software 6 // libraries and APIs for efficient high-order finite element and spectral 7 // element discretizations for exascale applications. For more information and 8 // source code availability see http://github.com/ceed. 9 // 10 // The CEED research is supported by the Exascale Computing Project 17-SC-20-SC, 11 // a collaborative effort of two U.S. Department of Energy organizations (Office 12 // of Science and the National Nuclear Security Administration) responsible for 13 // the planning and preparation of a capable exascale ecosystem, including 14 // software, applications, hardware, advanced system engineering and early 15 // testbed platforms, in support of the nation's exascale computing imperative. 16 17 #include <ceed/ceed.h> 18 #include <ceed/backend.h> 19 #include <math.h> 20 #include <stdbool.h> 21 #include <string.h> 22 #include "ceed-ref.h" 23 24 //------------------------------------------------------------------------------ 25 // Basis Apply 26 //------------------------------------------------------------------------------ 27 static int CeedBasisApply_Ref(CeedBasis basis, CeedInt num_elem, 28 CeedTransposeMode t_mode, CeedEvalMode eval_mode, 29 CeedVector U, CeedVector V) { 30 int ierr; 31 Ceed ceed; 32 ierr = CeedBasisGetCeed(basis, &ceed); CeedChkBackend(ierr); 33 CeedInt dim, num_comp, num_nodes, num_qpts; 34 ierr = CeedBasisGetDimension(basis, &dim); CeedChkBackend(ierr); 35 ierr = CeedBasisGetNumComponents(basis, &num_comp); CeedChkBackend(ierr); 36 ierr = CeedBasisGetNumNodes(basis, &num_nodes); CeedChkBackend(ierr); 37 ierr = CeedBasisGetNumQuadraturePoints(basis, &num_qpts); CeedChkBackend(ierr); 38 CeedTensorContract contract; 39 ierr = CeedBasisGetTensorContract(basis, &contract); CeedChkBackend(ierr); 40 const CeedInt add = (t_mode == CEED_TRANSPOSE); 41 const CeedScalar *u; 42 CeedScalar *v; 43 if (U != CEED_VECTOR_NONE) { 44 ierr = CeedVectorGetArrayRead(U, CEED_MEM_HOST, &u); CeedChkBackend(ierr); 45 } else if (eval_mode != CEED_EVAL_WEIGHT) { 46 // LCOV_EXCL_START 47 return CeedError(ceed, CEED_ERROR_BACKEND, 48 "An input vector is required for this CeedEvalMode"); 49 // LCOV_EXCL_STOP 50 } 51 ierr = CeedVectorGetArray(V, CEED_MEM_HOST, &v); CeedChkBackend(ierr); 52 53 // Clear v if operating in transpose 54 if (t_mode == CEED_TRANSPOSE) { 55 const CeedInt v_size = num_elem*num_comp*num_nodes; 56 for (CeedInt i = 0; i < v_size; i++) 57 v[i] = (CeedScalar) 0.0; 58 } 59 bool tensor_basis; 60 ierr = CeedBasisIsTensor(basis, &tensor_basis); CeedChkBackend(ierr); 61 // Tensor basis 62 if (tensor_basis) { 63 CeedInt P_1d, Q_1d; 64 ierr = CeedBasisGetNumNodes1D(basis, &P_1d); CeedChkBackend(ierr); 65 ierr = CeedBasisGetNumQuadraturePoints1D(basis, &Q_1d); CeedChkBackend(ierr); 66 switch (eval_mode) { 67 // Interpolate to/from quadrature points 68 case CEED_EVAL_INTERP: { 69 CeedBasis_Ref *impl; 70 ierr = CeedBasisGetData(basis, &impl); CeedChkBackend(ierr); 71 if (impl->collo_interp) { 72 memcpy(v, u, num_elem*num_comp*num_nodes*sizeof(u[0])); 73 } else { 74 CeedInt P = P_1d, Q = Q_1d; 75 if (t_mode == CEED_TRANSPOSE) { 76 P = Q_1d; Q = P_1d; 77 } 78 CeedInt pre = num_comp*CeedIntPow(P, dim-1), post = num_elem; 79 CeedScalar tmp[2][num_elem*num_comp*Q*CeedIntPow(P>Q?P:Q, dim-1)]; 80 const CeedScalar *interp_1d; 81 ierr = CeedBasisGetInterp1D(basis, &interp_1d); CeedChkBackend(ierr); 82 for (CeedInt d=0; d<dim; d++) { 83 ierr = CeedTensorContractApply(contract, pre, P, post, Q, 84 interp_1d, t_mode, add&&(d==dim-1), 85 d==0?u:tmp[d%2], 86 d==dim-1?v:tmp[(d+1)%2]); 87 CeedChkBackend(ierr); 88 pre /= P; 89 post *= Q; 90 } 91 } 92 } break; 93 // Evaluate the gradient to/from quadrature points 94 case CEED_EVAL_GRAD: { 95 // In CEED_NOTRANSPOSE mode: 96 // u has shape [dim, num_comp, P^dim, num_elem], row-major layout 97 // v has shape [dim, num_comp, Q^dim, num_elem], row-major layout 98 // In CEED_TRANSPOSE mode, the sizes of u and v are switched. 99 CeedInt P = P_1d, Q = Q_1d; 100 if (t_mode == CEED_TRANSPOSE) { 101 P = Q_1d, Q = Q_1d; 102 } 103 CeedBasis_Ref *impl; 104 ierr = CeedBasisGetData(basis, &impl); CeedChkBackend(ierr); 105 CeedInt pre = num_comp*CeedIntPow(P, dim-1), post = num_elem; 106 const CeedScalar *interp_1d; 107 ierr = CeedBasisGetInterp1D(basis, &interp_1d); CeedChkBackend(ierr); 108 if (impl->collograd1d) { 109 CeedScalar tmp[2][num_elem*num_comp*Q*CeedIntPow(P>Q?P:Q, dim-1)]; 110 CeedScalar interp[num_elem*num_comp*Q*CeedIntPow(P>Q?P:Q, dim-1)]; 111 // Interpolate to quadrature points (NoTranspose) 112 // or Grad to quadrature points (Transpose) 113 for (CeedInt d=0; d<dim; d++) { 114 ierr = CeedTensorContractApply(contract, pre, P, post, Q, 115 (t_mode == CEED_NOTRANSPOSE 116 ? interp_1d 117 : impl->collograd1d), 118 t_mode, add&&(d>0), 119 (t_mode == CEED_NOTRANSPOSE 120 ? (d==0?u:tmp[d%2]) 121 : u + d*num_qpts*num_comp*num_elem), 122 (t_mode == CEED_NOTRANSPOSE 123 ? (d==dim-1?interp:tmp[(d+1)%2]) 124 : interp)); 125 CeedChkBackend(ierr); 126 pre /= P; 127 post *= Q; 128 } 129 // Grad to quadrature points (NoTranspose) 130 // or Interpolate to nodes (Transpose) 131 P = Q_1d, Q = Q_1d; 132 if (t_mode == CEED_TRANSPOSE) { 133 P = Q_1d, Q = P_1d; 134 } 135 pre = num_comp*CeedIntPow(P, dim-1), post = num_elem; 136 for (CeedInt d=0; d<dim; d++) { 137 ierr = CeedTensorContractApply(contract, pre, P, post, Q, 138 (t_mode == CEED_NOTRANSPOSE 139 ? impl->collograd1d 140 : interp_1d), 141 t_mode, add&&(d==dim-1), 142 (t_mode == CEED_NOTRANSPOSE 143 ? interp 144 : (d==0?interp:tmp[d%2])), 145 (t_mode == CEED_NOTRANSPOSE 146 ? v + d*num_qpts*num_comp*num_elem 147 : (d==dim-1?v:tmp[(d+1)%2]))); 148 CeedChkBackend(ierr); 149 pre /= P; 150 post *= Q; 151 } 152 } else if (impl->collo_interp) { // Qpts collocated with nodes 153 const CeedScalar *grad_1d; 154 ierr = CeedBasisGetGrad1D(basis, &grad_1d); CeedChkBackend(ierr); 155 156 // Dim contractions, identity in other directions 157 CeedInt pre = num_comp*CeedIntPow(P, dim-1), post = num_elem; 158 for (CeedInt d=0; d<dim; d++) { 159 ierr = CeedTensorContractApply(contract, pre, P, post, Q, 160 grad_1d, t_mode, add&&(d>0), 161 t_mode == CEED_NOTRANSPOSE 162 ? u : u+d*num_comp*num_qpts*num_elem, 163 t_mode == CEED_TRANSPOSE 164 ? v : v+d*num_comp*num_qpts*num_elem); 165 CeedChkBackend(ierr); 166 pre /= P; 167 post *= Q; 168 } 169 } else { // Underintegration, P > Q 170 const CeedScalar *grad_1d; 171 ierr = CeedBasisGetGrad1D(basis, &grad_1d); CeedChkBackend(ierr); 172 173 if (t_mode == CEED_TRANSPOSE) { 174 P = Q_1d, Q = P_1d; 175 } 176 CeedScalar tmp[2][num_elem*num_comp*Q*CeedIntPow(P>Q?P:Q, dim-1)]; 177 178 // Dim**2 contractions, apply grad when pass == dim 179 for (CeedInt p=0; p<dim; p++) { 180 CeedInt pre = num_comp*CeedIntPow(P, dim-1), post = num_elem; 181 for (CeedInt d=0; d<dim; d++) { 182 ierr = CeedTensorContractApply(contract, pre, P, post, Q, 183 (p==d)? grad_1d : interp_1d, 184 t_mode, add&&(d==dim-1), 185 (d == 0 186 ? (t_mode == CEED_NOTRANSPOSE 187 ? u : u+p*num_comp*num_qpts*num_elem) 188 : tmp[d%2]), 189 (d == dim-1 190 ? (t_mode == CEED_TRANSPOSE 191 ? v : v+p*num_comp*num_qpts*num_elem) 192 : tmp[(d+1)%2])); 193 CeedChkBackend(ierr); 194 pre /= P; 195 post *= Q; 196 } 197 } 198 } 199 } break; 200 // Retrieve interpolation weights 201 case CEED_EVAL_WEIGHT: { 202 if (t_mode == CEED_TRANSPOSE) 203 // LCOV_EXCL_START 204 return CeedError(ceed, CEED_ERROR_BACKEND, 205 "CEED_EVAL_WEIGHT incompatible with CEED_TRANSPOSE"); 206 // LCOV_EXCL_STOP 207 CeedInt Q = Q_1d; 208 const CeedScalar *q_weight_1d; 209 ierr = CeedBasisGetQWeights(basis, &q_weight_1d); CeedChkBackend(ierr); 210 for (CeedInt d=0; d<dim; d++) { 211 CeedInt pre = CeedIntPow(Q, dim-d-1), post = CeedIntPow(Q, d); 212 for (CeedInt i=0; i<pre; i++) 213 for (CeedInt j=0; j<Q; j++) 214 for (CeedInt k=0; k<post; k++) { 215 CeedScalar w = q_weight_1d[j] 216 * (d == 0 ? 1 : v[((i*Q + j)*post + k)*num_elem]); 217 for (CeedInt e=0; e<num_elem; e++) 218 v[((i*Q + j)*post + k)*num_elem + e] = w; 219 } 220 } 221 } break; 222 // LCOV_EXCL_START 223 // Evaluate the divergence to/from the quadrature points 224 case CEED_EVAL_DIV: 225 return CeedError(ceed, CEED_ERROR_BACKEND, "CEED_EVAL_DIV not supported"); 226 // Evaluate the curl to/from the quadrature points 227 case CEED_EVAL_CURL: 228 return CeedError(ceed, CEED_ERROR_BACKEND, "CEED_EVAL_CURL not supported"); 229 // Take no action, BasisApply should not have been called 230 case CEED_EVAL_NONE: 231 return CeedError(ceed, CEED_ERROR_BACKEND, 232 "CEED_EVAL_NONE does not make sense in this context"); 233 // LCOV_EXCL_STOP 234 } 235 } else { 236 // Non-tensor basis 237 switch (eval_mode) { 238 // Interpolate to/from quadrature points 239 case CEED_EVAL_INTERP: { 240 CeedInt P = num_nodes, Q = num_qpts; 241 const CeedScalar *interp; 242 ierr = CeedBasisGetInterp(basis, &interp); CeedChkBackend(ierr); 243 if (t_mode == CEED_TRANSPOSE) { 244 P = num_qpts; Q = num_nodes; 245 } 246 ierr = CeedTensorContractApply(contract, num_comp, P, num_elem, Q, 247 interp, t_mode, add, u, v); 248 CeedChkBackend(ierr); 249 } 250 break; 251 // Evaluate the gradient to/from quadrature points 252 case CEED_EVAL_GRAD: { 253 CeedInt P = num_nodes, Q = num_qpts; 254 CeedInt dim_stride = num_qpts * num_comp * num_elem; 255 CeedInt grad_stride = num_qpts * num_nodes; 256 const CeedScalar *grad; 257 ierr = CeedBasisGetGrad(basis, &grad); CeedChkBackend(ierr); 258 if (t_mode == CEED_TRANSPOSE) { 259 P = num_qpts; Q = num_nodes; 260 for (CeedInt d = 0; d < dim; d++) { 261 ierr = CeedTensorContractApply(contract, num_comp, P, num_elem, Q, 262 grad + d * grad_stride, t_mode, add, 263 u + d * dim_stride, v); CeedChkBackend(ierr); 264 } 265 } else { 266 for (CeedInt d = 0; d < dim; d++) { 267 ierr = CeedTensorContractApply(contract, num_comp, P, num_elem, Q, 268 grad + d * grad_stride, t_mode, add, 269 u, v + d * dim_stride); CeedChkBackend(ierr); 270 } 271 } 272 } 273 break; 274 // Retrieve interpolation weights 275 case CEED_EVAL_WEIGHT: { 276 if (t_mode == CEED_TRANSPOSE) 277 // LCOV_EXCL_START 278 return CeedError(ceed, CEED_ERROR_BACKEND, 279 "CEED_EVAL_WEIGHT incompatible with CEED_TRANSPOSE"); 280 // LCOV_EXCL_STOP 281 const CeedScalar *q_weight; 282 ierr = CeedBasisGetQWeights(basis, &q_weight); CeedChkBackend(ierr); 283 for (CeedInt i=0; i<num_qpts; i++) 284 for (CeedInt e=0; e<num_elem; e++) 285 v[i*num_elem + e] = q_weight[i]; 286 } break; 287 // LCOV_EXCL_START 288 // Evaluate the divergence to/from the quadrature points 289 case CEED_EVAL_DIV: 290 return CeedError(ceed, CEED_ERROR_BACKEND, "CEED_EVAL_DIV not supported"); 291 // Evaluate the curl to/from the quadrature points 292 case CEED_EVAL_CURL: 293 return CeedError(ceed, CEED_ERROR_BACKEND, "CEED_EVAL_CURL not supported"); 294 // Take no action, BasisApply should not have been called 295 case CEED_EVAL_NONE: 296 return CeedError(ceed, CEED_ERROR_BACKEND, 297 "CEED_EVAL_NONE does not make sense in this context"); 298 // LCOV_EXCL_STOP 299 } 300 } 301 if (U != CEED_VECTOR_NONE) { 302 ierr = CeedVectorRestoreArrayRead(U, &u); CeedChkBackend(ierr); 303 } 304 ierr = CeedVectorRestoreArray(V, &v); CeedChkBackend(ierr); 305 return CEED_ERROR_SUCCESS; 306 } 307 308 //------------------------------------------------------------------------------ 309 // Basis Destroy Non-Tensor 310 //------------------------------------------------------------------------------ 311 static int CeedBasisDestroyNonTensor_Ref(CeedBasis basis) { 312 int ierr; 313 CeedTensorContract contract; 314 ierr = CeedBasisGetTensorContract(basis, &contract); CeedChkBackend(ierr); 315 ierr = CeedTensorContractDestroy(&contract); CeedChkBackend(ierr); 316 return CEED_ERROR_SUCCESS; 317 } 318 319 //------------------------------------------------------------------------------ 320 // Basis Create Non-Tensor 321 //------------------------------------------------------------------------------ 322 int CeedBasisCreateH1_Ref(CeedElemTopology topo, CeedInt dim, 323 CeedInt num_nodes, CeedInt num_qpts, 324 const CeedScalar *interp, 325 const CeedScalar *grad, 326 const CeedScalar *q_ref, 327 const CeedScalar *q_weight, 328 CeedBasis basis) { 329 int ierr; 330 Ceed ceed; 331 ierr = CeedBasisGetCeed(basis, &ceed); CeedChkBackend(ierr); 332 333 Ceed parent; 334 ierr = CeedGetParent(ceed, &parent); CeedChkBackend(ierr); 335 CeedTensorContract contract; 336 ierr = CeedTensorContractCreate(parent, basis, &contract); CeedChkBackend(ierr); 337 ierr = CeedBasisSetTensorContract(basis, &contract); CeedChkBackend(ierr); 338 339 ierr = CeedSetBackendFunction(ceed, "Basis", basis, "Apply", 340 CeedBasisApply_Ref); CeedChkBackend(ierr); 341 ierr = CeedSetBackendFunction(ceed, "Basis", basis, "Destroy", 342 CeedBasisDestroyNonTensor_Ref); CeedChkBackend(ierr); 343 344 return CEED_ERROR_SUCCESS; 345 } 346 347 //------------------------------------------------------------------------------ 348 // Basis Destroy Tensor 349 //------------------------------------------------------------------------------ 350 static int CeedBasisDestroyTensor_Ref(CeedBasis basis) { 351 int ierr; 352 CeedTensorContract contract; 353 ierr = CeedBasisGetTensorContract(basis, &contract); CeedChkBackend(ierr); 354 ierr = CeedTensorContractDestroy(&contract); CeedChkBackend(ierr); 355 356 CeedBasis_Ref *impl; 357 ierr = CeedBasisGetData(basis, &impl); CeedChkBackend(ierr); 358 ierr = CeedFree(&impl->collograd1d); CeedChkBackend(ierr); 359 ierr = CeedFree(&impl); CeedChkBackend(ierr); 360 361 return CEED_ERROR_SUCCESS; 362 } 363 364 //------------------------------------------------------------------------------ 365 // Basis Create Tensor 366 //------------------------------------------------------------------------------ 367 int CeedBasisCreateTensorH1_Ref(CeedInt dim, CeedInt P_1d, 368 CeedInt Q_1d, const CeedScalar *interp_1d, 369 const CeedScalar *grad_1d, 370 const CeedScalar *q_ref_1d, 371 const CeedScalar *q_weight_1d, 372 CeedBasis basis) { 373 int ierr; 374 Ceed ceed; 375 ierr = CeedBasisGetCeed(basis, &ceed); CeedChkBackend(ierr); 376 CeedBasis_Ref *impl; 377 ierr = CeedCalloc(1, &impl); CeedChkBackend(ierr); 378 // Check for collocated interp 379 if (Q_1d == P_1d) { 380 bool collocated = 1; 381 for (CeedInt i=0; i<P_1d; i++) { 382 collocated = collocated && (fabs(interp_1d[i+P_1d*i] - 1.0) < 1e-14); 383 for (CeedInt j=0; j<P_1d; j++) 384 if (j != i) 385 collocated = collocated && (fabs(interp_1d[j+P_1d*i]) < 1e-14); 386 } 387 impl->collo_interp = collocated; 388 } 389 // Calculate collocated grad 390 if (Q_1d >= P_1d && !impl->collo_interp) { 391 ierr = CeedMalloc(Q_1d*Q_1d, &impl->collograd1d); CeedChkBackend(ierr); 392 ierr = CeedBasisGetCollocatedGrad(basis, impl->collograd1d); 393 CeedChkBackend(ierr); 394 } 395 ierr = CeedBasisSetData(basis, impl); CeedChkBackend(ierr); 396 397 Ceed parent; 398 ierr = CeedGetParent(ceed, &parent); CeedChkBackend(ierr); 399 CeedTensorContract contract; 400 ierr = CeedTensorContractCreate(parent, basis, &contract); CeedChkBackend(ierr); 401 ierr = CeedBasisSetTensorContract(basis, &contract); CeedChkBackend(ierr); 402 403 ierr = CeedSetBackendFunction(ceed, "Basis", basis, "Apply", 404 CeedBasisApply_Ref); CeedChkBackend(ierr); 405 ierr = CeedSetBackendFunction(ceed, "Basis", basis, "Destroy", 406 CeedBasisDestroyTensor_Ref); CeedChkBackend(ierr); 407 return CEED_ERROR_SUCCESS; 408 } 409 410 //------------------------------------------------------------------------------ 411