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.h> 18 #include <ceed-backend.h> 19 #include <math.h> 20 #include <stdbool.h> 21 #include <stddef.h> 22 #include <stdint.h> 23 #include "ceed-ref.h" 24 25 //------------------------------------------------------------------------------ 26 // Setup Input/Output Fields 27 //------------------------------------------------------------------------------ 28 static int CeedOperatorSetupFields_Ref(CeedQFunction qf, CeedOperator op, 29 bool inOrOut, 30 CeedVector *fullevecs, CeedVector *evecs, 31 CeedVector *qvecs, CeedInt starte, 32 CeedInt numfields, CeedInt Q) { 33 CeedInt dim, ierr, size, P; 34 Ceed ceed; 35 ierr = CeedOperatorGetCeed(op, &ceed); CeedChkBackend(ierr); 36 CeedBasis basis; 37 CeedElemRestriction Erestrict; 38 CeedOperatorField *opfields; 39 CeedQFunctionField *qffields; 40 if (inOrOut) { 41 ierr = CeedOperatorGetFields(op, NULL, &opfields); CeedChkBackend(ierr); 42 ierr = CeedQFunctionGetFields(qf, NULL, &qffields); CeedChkBackend(ierr); 43 } else { 44 ierr = CeedOperatorGetFields(op, &opfields, NULL); CeedChkBackend(ierr); 45 ierr = CeedQFunctionGetFields(qf, &qffields, NULL); CeedChkBackend(ierr); 46 } 47 48 // Loop over fields 49 for (CeedInt i=0; i<numfields; i++) { 50 CeedEvalMode emode; 51 ierr = CeedQFunctionFieldGetEvalMode(qffields[i], &emode); CeedChkBackend(ierr); 52 53 if (emode != CEED_EVAL_WEIGHT) { 54 ierr = CeedOperatorFieldGetElemRestriction(opfields[i], &Erestrict); 55 CeedChkBackend(ierr); 56 ierr = CeedElemRestrictionCreateVector(Erestrict, NULL, 57 &fullevecs[i+starte]); 58 CeedChkBackend(ierr); 59 } 60 61 switch(emode) { 62 case CEED_EVAL_NONE: 63 ierr = CeedQFunctionFieldGetSize(qffields[i], &size); CeedChkBackend(ierr); 64 ierr = CeedVectorCreate(ceed, Q*size, &qvecs[i]); CeedChkBackend(ierr); 65 break; 66 case CEED_EVAL_INTERP: 67 ierr = CeedQFunctionFieldGetSize(qffields[i], &size); CeedChkBackend(ierr); 68 ierr = CeedElemRestrictionGetElementSize(Erestrict, &P); 69 CeedChkBackend(ierr); 70 ierr = CeedVectorCreate(ceed, P*size, &evecs[i]); CeedChkBackend(ierr); 71 ierr = CeedVectorCreate(ceed, Q*size, &qvecs[i]); CeedChkBackend(ierr); 72 break; 73 case CEED_EVAL_GRAD: 74 ierr = CeedOperatorFieldGetBasis(opfields[i], &basis); CeedChkBackend(ierr); 75 ierr = CeedQFunctionFieldGetSize(qffields[i], &size); CeedChkBackend(ierr); 76 ierr = CeedBasisGetDimension(basis, &dim); CeedChkBackend(ierr); 77 ierr = CeedElemRestrictionGetElementSize(Erestrict, &P); 78 CeedChkBackend(ierr); 79 ierr = CeedVectorCreate(ceed, P*size/dim, &evecs[i]); CeedChkBackend(ierr); 80 ierr = CeedVectorCreate(ceed, Q*size, &qvecs[i]); CeedChkBackend(ierr); 81 break; 82 case CEED_EVAL_WEIGHT: // Only on input fields 83 ierr = CeedOperatorFieldGetBasis(opfields[i], &basis); CeedChkBackend(ierr); 84 ierr = CeedVectorCreate(ceed, Q, &qvecs[i]); CeedChkBackend(ierr); 85 ierr = CeedBasisApply(basis, 1, CEED_NOTRANSPOSE, CEED_EVAL_WEIGHT, 86 CEED_VECTOR_NONE, qvecs[i]); CeedChkBackend(ierr); 87 break; 88 case CEED_EVAL_DIV: 89 break; // Not implemented 90 case CEED_EVAL_CURL: 91 break; // Not implemented 92 } 93 } 94 return CEED_ERROR_SUCCESS; 95 } 96 97 //------------------------------------------------------------------------------ 98 // Setup Operator 99 //------------------------------------------------------------------------------/* 100 static int CeedOperatorSetup_Ref(CeedOperator op) { 101 int ierr; 102 bool setupdone; 103 ierr = CeedOperatorIsSetupDone(op, &setupdone); CeedChkBackend(ierr); 104 if (setupdone) return CEED_ERROR_SUCCESS; 105 Ceed ceed; 106 ierr = CeedOperatorGetCeed(op, &ceed); CeedChkBackend(ierr); 107 CeedOperator_Ref *impl; 108 ierr = CeedOperatorGetData(op, &impl); CeedChkBackend(ierr); 109 CeedQFunction qf; 110 ierr = CeedOperatorGetQFunction(op, &qf); CeedChkBackend(ierr); 111 CeedInt Q, numinputfields, numoutputfields; 112 ierr = CeedOperatorGetNumQuadraturePoints(op, &Q); CeedChkBackend(ierr); 113 ierr = CeedQFunctionIsIdentity(qf, &impl->identityqf); CeedChkBackend(ierr); 114 ierr = CeedQFunctionGetNumArgs(qf, &numinputfields, &numoutputfields); 115 CeedChkBackend(ierr); 116 CeedOperatorField *opinputfields, *opoutputfields; 117 ierr = CeedOperatorGetFields(op, &opinputfields, &opoutputfields); 118 CeedChkBackend(ierr); 119 CeedQFunctionField *qfinputfields, *qfoutputfields; 120 ierr = CeedQFunctionGetFields(qf, &qfinputfields, &qfoutputfields); 121 CeedChkBackend(ierr); 122 123 // Allocate 124 ierr = CeedCalloc(numinputfields + numoutputfields, &impl->evecs); 125 CeedChkBackend(ierr); 126 ierr = CeedCalloc(numinputfields + numoutputfields, &impl->edata); 127 CeedChkBackend(ierr); 128 129 ierr = CeedCalloc(16, &impl->inputstate); CeedChkBackend(ierr); 130 ierr = CeedCalloc(16, &impl->evecsin); CeedChkBackend(ierr); 131 ierr = CeedCalloc(16, &impl->evecsout); CeedChkBackend(ierr); 132 ierr = CeedCalloc(16, &impl->qvecsin); CeedChkBackend(ierr); 133 ierr = CeedCalloc(16, &impl->qvecsout); CeedChkBackend(ierr); 134 135 impl->numein = numinputfields; impl->numeout = numoutputfields; 136 137 // Set up infield and outfield evecs and qvecs 138 // Infields 139 ierr = CeedOperatorSetupFields_Ref(qf, op, 0, impl->evecs, 140 impl->evecsin, impl->qvecsin, 0, 141 numinputfields, Q); 142 CeedChkBackend(ierr); 143 // Outfields 144 ierr = CeedOperatorSetupFields_Ref(qf, op, 1, impl->evecs, 145 impl->evecsout, impl->qvecsout, 146 numinputfields, numoutputfields, Q); 147 CeedChkBackend(ierr); 148 149 // Identity QFunctions 150 if (impl->identityqf) { 151 CeedEvalMode inmode, outmode; 152 CeedQFunctionField *infields, *outfields; 153 ierr = CeedQFunctionGetFields(qf, &infields, &outfields); CeedChkBackend(ierr); 154 155 for (CeedInt i=0; i<numinputfields; i++) { 156 ierr = CeedQFunctionFieldGetEvalMode(infields[i], &inmode); 157 CeedChkBackend(ierr); 158 ierr = CeedQFunctionFieldGetEvalMode(outfields[i], &outmode); 159 CeedChkBackend(ierr); 160 161 ierr = CeedVectorDestroy(&impl->qvecsout[i]); CeedChkBackend(ierr); 162 impl->qvecsout[i] = impl->qvecsin[i]; 163 ierr = CeedVectorAddReference(impl->qvecsin[i]); CeedChkBackend(ierr); 164 } 165 } 166 167 ierr = CeedOperatorSetSetupDone(op); CeedChkBackend(ierr); 168 169 return CEED_ERROR_SUCCESS; 170 } 171 172 //------------------------------------------------------------------------------ 173 // Setup Operator Inputs 174 //------------------------------------------------------------------------------ 175 static inline int CeedOperatorSetupInputs_Ref(CeedInt numinputfields, 176 CeedQFunctionField *qfinputfields, CeedOperatorField *opinputfields, 177 CeedVector invec, const bool skipactive, CeedOperator_Ref *impl, 178 CeedRequest *request) { 179 CeedInt ierr; 180 CeedEvalMode emode; 181 CeedVector vec; 182 CeedElemRestriction Erestrict; 183 uint64_t state; 184 185 for (CeedInt i=0; i<numinputfields; i++) { 186 // Get input vector 187 ierr = CeedOperatorFieldGetVector(opinputfields[i], &vec); CeedChkBackend(ierr); 188 if (vec == CEED_VECTOR_ACTIVE) { 189 if (skipactive) 190 continue; 191 else 192 vec = invec; 193 } 194 195 ierr = CeedQFunctionFieldGetEvalMode(qfinputfields[i], &emode); 196 CeedChkBackend(ierr); 197 // Restrict and Evec 198 if (emode == CEED_EVAL_WEIGHT) { // Skip 199 } else { 200 // Restrict 201 ierr = CeedVectorGetState(vec, &state); CeedChkBackend(ierr); 202 // Skip restriction if input is unchanged 203 if (state != impl->inputstate[i] || vec == invec) { 204 ierr = CeedOperatorFieldGetElemRestriction(opinputfields[i], &Erestrict); 205 CeedChkBackend(ierr); 206 ierr = CeedElemRestrictionApply(Erestrict, CEED_NOTRANSPOSE, vec, 207 impl->evecs[i], request); CeedChkBackend(ierr); 208 impl->inputstate[i] = state; 209 } 210 // Get evec 211 ierr = CeedVectorGetArrayRead(impl->evecs[i], CEED_MEM_HOST, 212 (const CeedScalar **) &impl->edata[i]); 213 CeedChkBackend(ierr); 214 } 215 } 216 return CEED_ERROR_SUCCESS; 217 } 218 219 //------------------------------------------------------------------------------ 220 // Input Basis Action 221 //------------------------------------------------------------------------------ 222 static inline int CeedOperatorInputBasis_Ref(CeedInt e, CeedInt Q, 223 CeedQFunctionField *qfinputfields, CeedOperatorField *opinputfields, 224 CeedInt numinputfields, const bool skipactive, CeedOperator_Ref *impl) { 225 CeedInt ierr; 226 CeedInt dim, elemsize, size; 227 CeedElemRestriction Erestrict; 228 CeedEvalMode emode; 229 CeedBasis basis; 230 231 for (CeedInt i=0; i<numinputfields; i++) { 232 // Skip active input 233 if (skipactive) { 234 CeedVector vec; 235 ierr = CeedOperatorFieldGetVector(opinputfields[i], &vec); CeedChkBackend(ierr); 236 if (vec == CEED_VECTOR_ACTIVE) 237 continue; 238 } 239 // Get elemsize, emode, size 240 ierr = CeedOperatorFieldGetElemRestriction(opinputfields[i], &Erestrict); 241 CeedChkBackend(ierr); 242 ierr = CeedElemRestrictionGetElementSize(Erestrict, &elemsize); 243 CeedChkBackend(ierr); 244 ierr = CeedQFunctionFieldGetEvalMode(qfinputfields[i], &emode); 245 CeedChkBackend(ierr); 246 ierr = CeedQFunctionFieldGetSize(qfinputfields[i], &size); CeedChkBackend(ierr); 247 // Basis action 248 switch(emode) { 249 case CEED_EVAL_NONE: 250 ierr = CeedVectorSetArray(impl->qvecsin[i], CEED_MEM_HOST, 251 CEED_USE_POINTER, 252 &impl->edata[i][e*Q*size]); CeedChkBackend(ierr); 253 break; 254 case CEED_EVAL_INTERP: 255 ierr = CeedOperatorFieldGetBasis(opinputfields[i], &basis); 256 CeedChkBackend(ierr); 257 ierr = CeedVectorSetArray(impl->evecsin[i], CEED_MEM_HOST, 258 CEED_USE_POINTER, 259 &impl->edata[i][e*elemsize*size]); 260 CeedChkBackend(ierr); 261 ierr = CeedBasisApply(basis, 1, CEED_NOTRANSPOSE, 262 CEED_EVAL_INTERP, impl->evecsin[i], 263 impl->qvecsin[i]); CeedChkBackend(ierr); 264 break; 265 case CEED_EVAL_GRAD: 266 ierr = CeedOperatorFieldGetBasis(opinputfields[i], &basis); 267 CeedChkBackend(ierr); 268 ierr = CeedBasisGetDimension(basis, &dim); CeedChkBackend(ierr); 269 ierr = CeedVectorSetArray(impl->evecsin[i], CEED_MEM_HOST, 270 CEED_USE_POINTER, 271 &impl->edata[i][e*elemsize*size/dim]); 272 CeedChkBackend(ierr); 273 ierr = CeedBasisApply(basis, 1, CEED_NOTRANSPOSE, 274 CEED_EVAL_GRAD, impl->evecsin[i], 275 impl->qvecsin[i]); CeedChkBackend(ierr); 276 break; 277 case CEED_EVAL_WEIGHT: 278 break; // No action 279 // LCOV_EXCL_START 280 case CEED_EVAL_DIV: 281 case CEED_EVAL_CURL: { 282 ierr = CeedOperatorFieldGetBasis(opinputfields[i], &basis); 283 CeedChkBackend(ierr); 284 Ceed ceed; 285 ierr = CeedBasisGetCeed(basis, &ceed); CeedChkBackend(ierr); 286 return CeedError(ceed, CEED_ERROR_BACKEND, 287 "Ceed evaluation mode not implemented"); 288 // LCOV_EXCL_STOP 289 } 290 } 291 } 292 return CEED_ERROR_SUCCESS; 293 } 294 295 //------------------------------------------------------------------------------ 296 // Output Basis Action 297 //------------------------------------------------------------------------------ 298 static inline int CeedOperatorOutputBasis_Ref(CeedInt e, CeedInt Q, 299 CeedQFunctionField *qfoutputfields, CeedOperatorField *opoutputfields, 300 CeedInt numinputfields, CeedInt numoutputfields, CeedOperator op, 301 CeedOperator_Ref *impl) { 302 CeedInt ierr; 303 CeedInt dim, elemsize, size; 304 CeedElemRestriction Erestrict; 305 CeedEvalMode emode; 306 CeedBasis basis; 307 308 for (CeedInt i=0; i<numoutputfields; i++) { 309 // Get elemsize, emode, size 310 ierr = CeedOperatorFieldGetElemRestriction(opoutputfields[i], &Erestrict); 311 CeedChkBackend(ierr); 312 ierr = CeedElemRestrictionGetElementSize(Erestrict, &elemsize); 313 CeedChkBackend(ierr); 314 ierr = CeedQFunctionFieldGetEvalMode(qfoutputfields[i], &emode); 315 CeedChkBackend(ierr); 316 ierr = CeedQFunctionFieldGetSize(qfoutputfields[i], &size); 317 CeedChkBackend(ierr); 318 // Basis action 319 switch(emode) { 320 case CEED_EVAL_NONE: 321 break; // No action 322 case CEED_EVAL_INTERP: 323 ierr = CeedOperatorFieldGetBasis(opoutputfields[i], &basis); 324 CeedChkBackend(ierr); 325 ierr = CeedVectorSetArray(impl->evecsout[i], CEED_MEM_HOST, 326 CEED_USE_POINTER, 327 &impl->edata[i + numinputfields][e*elemsize*size]); 328 CeedChkBackend(ierr); 329 ierr = CeedBasisApply(basis, 1, CEED_TRANSPOSE, 330 CEED_EVAL_INTERP, impl->qvecsout[i], 331 impl->evecsout[i]); CeedChkBackend(ierr); 332 break; 333 case CEED_EVAL_GRAD: 334 ierr = CeedOperatorFieldGetBasis(opoutputfields[i], &basis); 335 CeedChkBackend(ierr); 336 ierr = CeedBasisGetDimension(basis, &dim); CeedChkBackend(ierr); 337 ierr = CeedVectorSetArray(impl->evecsout[i], CEED_MEM_HOST, 338 CEED_USE_POINTER, 339 &impl->edata[i + numinputfields][e*elemsize*size/dim]); 340 CeedChkBackend(ierr); 341 ierr = CeedBasisApply(basis, 1, CEED_TRANSPOSE, 342 CEED_EVAL_GRAD, impl->qvecsout[i], 343 impl->evecsout[i]); CeedChkBackend(ierr); 344 break; 345 // LCOV_EXCL_START 346 case CEED_EVAL_WEIGHT: { 347 Ceed ceed; 348 ierr = CeedOperatorGetCeed(op, &ceed); CeedChkBackend(ierr); 349 return CeedError(ceed, CEED_ERROR_BACKEND, 350 "CEED_EVAL_WEIGHT cannot be an output " 351 "evaluation mode"); 352 } 353 case CEED_EVAL_DIV: 354 case CEED_EVAL_CURL: { 355 Ceed ceed; 356 ierr = CeedOperatorGetCeed(op, &ceed); CeedChkBackend(ierr); 357 return CeedError(ceed, CEED_ERROR_BACKEND, 358 "Ceed evaluation mode not implemented"); 359 // LCOV_EXCL_STOP 360 } 361 } 362 } 363 return CEED_ERROR_SUCCESS; 364 } 365 366 //------------------------------------------------------------------------------ 367 // Restore Input Vectors 368 //------------------------------------------------------------------------------ 369 static inline int CeedOperatorRestoreInputs_Ref(CeedInt numinputfields, 370 CeedQFunctionField *qfinputfields, CeedOperatorField *opinputfields, 371 const bool skipactive, CeedOperator_Ref *impl) { 372 CeedInt ierr; 373 CeedEvalMode emode; 374 375 for (CeedInt i=0; i<numinputfields; i++) { 376 // Skip active inputs 377 if (skipactive) { 378 CeedVector vec; 379 ierr = CeedOperatorFieldGetVector(opinputfields[i], &vec); CeedChkBackend(ierr); 380 if (vec == CEED_VECTOR_ACTIVE) 381 continue; 382 } 383 // Restore input 384 ierr = CeedQFunctionFieldGetEvalMode(qfinputfields[i], &emode); 385 CeedChkBackend(ierr); 386 if (emode == CEED_EVAL_WEIGHT) { // Skip 387 } else { 388 ierr = CeedVectorRestoreArrayRead(impl->evecs[i], 389 (const CeedScalar **) &impl->edata[i]); 390 CeedChkBackend(ierr); 391 } 392 } 393 return CEED_ERROR_SUCCESS; 394 } 395 396 //------------------------------------------------------------------------------ 397 // Operator Apply 398 //------------------------------------------------------------------------------ 399 static int CeedOperatorApplyAdd_Ref(CeedOperator op, CeedVector invec, 400 CeedVector outvec, CeedRequest *request) { 401 int ierr; 402 CeedOperator_Ref *impl; 403 ierr = CeedOperatorGetData(op, &impl); CeedChkBackend(ierr); 404 CeedQFunction qf; 405 ierr = CeedOperatorGetQFunction(op, &qf); CeedChkBackend(ierr); 406 CeedInt Q, numelements, numinputfields, numoutputfields, size; 407 ierr = CeedOperatorGetNumQuadraturePoints(op, &Q); CeedChkBackend(ierr); 408 ierr = CeedOperatorGetNumElements(op, &numelements); CeedChkBackend(ierr); 409 ierr= CeedQFunctionGetNumArgs(qf, &numinputfields, &numoutputfields); 410 CeedChkBackend(ierr); 411 CeedOperatorField *opinputfields, *opoutputfields; 412 ierr = CeedOperatorGetFields(op, &opinputfields, &opoutputfields); 413 CeedChkBackend(ierr); 414 CeedQFunctionField *qfinputfields, *qfoutputfields; 415 ierr = CeedQFunctionGetFields(qf, &qfinputfields, &qfoutputfields); 416 CeedChkBackend(ierr); 417 CeedEvalMode emode; 418 CeedVector vec; 419 CeedElemRestriction Erestrict; 420 421 // Setup 422 ierr = CeedOperatorSetup_Ref(op); CeedChkBackend(ierr); 423 424 // Input Evecs and Restriction 425 ierr = CeedOperatorSetupInputs_Ref(numinputfields, qfinputfields, 426 opinputfields, invec, false, impl, 427 request); CeedChkBackend(ierr); 428 429 // Output Evecs 430 for (CeedInt i=0; i<numoutputfields; i++) { 431 ierr = CeedVectorGetArray(impl->evecs[i+impl->numein], CEED_MEM_HOST, 432 &impl->edata[i + numinputfields]); CeedChkBackend(ierr); 433 } 434 435 // Loop through elements 436 for (CeedInt e=0; e<numelements; e++) { 437 // Output pointers 438 for (CeedInt i=0; i<numoutputfields; i++) { 439 ierr = CeedQFunctionFieldGetEvalMode(qfoutputfields[i], &emode); 440 CeedChkBackend(ierr); 441 if (emode == CEED_EVAL_NONE) { 442 ierr = CeedQFunctionFieldGetSize(qfoutputfields[i], &size); 443 CeedChkBackend(ierr); 444 ierr = CeedVectorSetArray(impl->qvecsout[i], CEED_MEM_HOST, 445 CEED_USE_POINTER, 446 &impl->edata[i + numinputfields][e*Q*size]); 447 CeedChkBackend(ierr); 448 } 449 } 450 451 // Input basis apply 452 ierr = CeedOperatorInputBasis_Ref(e, Q, qfinputfields, opinputfields, 453 numinputfields, false, impl); 454 CeedChkBackend(ierr); 455 456 // Q function 457 if (!impl->identityqf) { 458 ierr = CeedQFunctionApply(qf, Q, impl->qvecsin, impl->qvecsout); 459 CeedChkBackend(ierr); 460 } 461 462 // Output basis apply 463 ierr = CeedOperatorOutputBasis_Ref(e, Q, qfoutputfields, opoutputfields, 464 numinputfields, numoutputfields, op, impl); 465 CeedChkBackend(ierr); 466 } 467 468 // Output restriction 469 for (CeedInt i=0; i<numoutputfields; i++) { 470 // Restore evec 471 ierr = CeedVectorRestoreArray(impl->evecs[i+impl->numein], 472 &impl->edata[i + numinputfields]); 473 CeedChkBackend(ierr); 474 // Get output vector 475 ierr = CeedOperatorFieldGetVector(opoutputfields[i], &vec); 476 CeedChkBackend(ierr); 477 // Active 478 if (vec == CEED_VECTOR_ACTIVE) 479 vec = outvec; 480 // Restrict 481 ierr = CeedOperatorFieldGetElemRestriction(opoutputfields[i], &Erestrict); 482 CeedChkBackend(ierr); 483 ierr = CeedElemRestrictionApply(Erestrict, CEED_TRANSPOSE, 484 impl->evecs[i+impl->numein], vec, request); 485 CeedChkBackend(ierr); 486 } 487 488 // Restore input arrays 489 ierr = CeedOperatorRestoreInputs_Ref(numinputfields, qfinputfields, 490 opinputfields, false, impl); 491 CeedChkBackend(ierr); 492 493 return CEED_ERROR_SUCCESS; 494 } 495 496 //------------------------------------------------------------------------------ 497 // Assemble Linear QFunction 498 //------------------------------------------------------------------------------ 499 static int CeedOperatorLinearAssembleQFunction_Ref(CeedOperator op, 500 CeedVector *assembled, CeedElemRestriction *rstr, CeedRequest *request) { 501 int ierr; 502 CeedOperator_Ref *impl; 503 ierr = CeedOperatorGetData(op, &impl); CeedChkBackend(ierr); 504 CeedQFunction qf; 505 ierr = CeedOperatorGetQFunction(op, &qf); CeedChkBackend(ierr); 506 CeedInt Q, numelements, numinputfields, numoutputfields, size; 507 ierr = CeedOperatorGetNumQuadraturePoints(op, &Q); CeedChkBackend(ierr); 508 ierr = CeedOperatorGetNumElements(op, &numelements); CeedChkBackend(ierr); 509 ierr= CeedQFunctionGetNumArgs(qf, &numinputfields, &numoutputfields); 510 CeedChkBackend(ierr); 511 CeedOperatorField *opinputfields, *opoutputfields; 512 ierr = CeedOperatorGetFields(op, &opinputfields, &opoutputfields); 513 CeedChkBackend(ierr); 514 CeedQFunctionField *qfinputfields, *qfoutputfields; 515 ierr = CeedQFunctionGetFields(qf, &qfinputfields, &qfoutputfields); 516 CeedChkBackend(ierr); 517 CeedVector vec; 518 CeedInt numactivein = 0, numactiveout = 0; 519 CeedVector *activein = NULL; 520 CeedScalar *a, *tmp; 521 Ceed ceed, ceedparent; 522 ierr = CeedOperatorGetCeed(op, &ceed); CeedChkBackend(ierr); 523 ierr = CeedGetOperatorFallbackParentCeed(ceed, &ceedparent); 524 CeedChkBackend(ierr); 525 ceedparent = ceedparent ? ceedparent : ceed; 526 527 // Setup 528 ierr = CeedOperatorSetup_Ref(op); CeedChkBackend(ierr); 529 530 // Check for identity 531 if (impl->identityqf) 532 // LCOV_EXCL_START 533 return CeedError(ceed, CEED_ERROR_BACKEND, 534 "Assembling identity QFunctions not supported"); 535 // LCOV_EXCL_STOP 536 537 // Input Evecs and Restriction 538 ierr = CeedOperatorSetupInputs_Ref(numinputfields, qfinputfields, 539 opinputfields, NULL, true, impl, request); 540 CeedChkBackend(ierr); 541 542 // Count number of active input fields 543 for (CeedInt i=0; i<numinputfields; i++) { 544 // Get input vector 545 ierr = CeedOperatorFieldGetVector(opinputfields[i], &vec); CeedChkBackend(ierr); 546 // Check if active input 547 if (vec == CEED_VECTOR_ACTIVE) { 548 ierr = CeedQFunctionFieldGetSize(qfinputfields[i], &size); CeedChkBackend(ierr); 549 ierr = CeedVectorSetValue(impl->qvecsin[i], 0.0); CeedChkBackend(ierr); 550 ierr = CeedVectorGetArray(impl->qvecsin[i], CEED_MEM_HOST, &tmp); 551 CeedChkBackend(ierr); 552 ierr = CeedRealloc(numactivein + size, &activein); CeedChkBackend(ierr); 553 for (CeedInt field=0; field<size; field++) { 554 ierr = CeedVectorCreate(ceed, Q, &activein[numactivein+field]); 555 CeedChkBackend(ierr); 556 ierr = CeedVectorSetArray(activein[numactivein+field], CEED_MEM_HOST, 557 CEED_USE_POINTER, &tmp[field*Q]); 558 CeedChkBackend(ierr); 559 } 560 numactivein += size; 561 ierr = CeedVectorRestoreArray(impl->qvecsin[i], &tmp); CeedChkBackend(ierr); 562 } 563 } 564 565 // Count number of active output fields 566 for (CeedInt i=0; i<numoutputfields; i++) { 567 // Get output vector 568 ierr = CeedOperatorFieldGetVector(opoutputfields[i], &vec); 569 CeedChkBackend(ierr); 570 // Check if active output 571 if (vec == CEED_VECTOR_ACTIVE) { 572 ierr = CeedQFunctionFieldGetSize(qfoutputfields[i], &size); 573 CeedChkBackend(ierr); 574 numactiveout += size; 575 } 576 } 577 578 // Check sizes 579 if (!numactivein || !numactiveout) 580 // LCOV_EXCL_START 581 return CeedError(ceed, CEED_ERROR_BACKEND, 582 "Cannot assemble QFunction without active inputs " 583 "and outputs"); 584 // LCOV_EXCL_STOP 585 586 // Create output restriction 587 CeedInt strides[3] = {1, Q, numactivein*numactiveout*Q}; /* *NOPAD* */ 588 ierr = CeedElemRestrictionCreateStrided(ceedparent, numelements, Q, 589 numactivein*numactiveout, 590 numactivein*numactiveout*numelements*Q, 591 strides, rstr); CeedChkBackend(ierr); 592 // Create assembled vector 593 ierr = CeedVectorCreate(ceedparent, numelements*Q*numactivein*numactiveout, 594 assembled); CeedChkBackend(ierr); 595 ierr = CeedVectorSetValue(*assembled, 0.0); CeedChkBackend(ierr); 596 ierr = CeedVectorGetArray(*assembled, CEED_MEM_HOST, &a); CeedChkBackend(ierr); 597 598 // Loop through elements 599 for (CeedInt e=0; e<numelements; e++) { 600 // Input basis apply 601 ierr = CeedOperatorInputBasis_Ref(e, Q, qfinputfields, opinputfields, 602 numinputfields, true, impl); 603 CeedChkBackend(ierr); 604 605 // Assemble QFunction 606 for (CeedInt in=0; in<numactivein; in++) { 607 // Set Inputs 608 ierr = CeedVectorSetValue(activein[in], 1.0); CeedChkBackend(ierr); 609 if (numactivein > 1) { 610 ierr = CeedVectorSetValue(activein[(in+numactivein-1)%numactivein], 611 0.0); CeedChkBackend(ierr); 612 } 613 // Set Outputs 614 for (CeedInt out=0; out<numoutputfields; out++) { 615 // Get output vector 616 ierr = CeedOperatorFieldGetVector(opoutputfields[out], &vec); 617 CeedChkBackend(ierr); 618 // Check if active output 619 if (vec == CEED_VECTOR_ACTIVE) { 620 CeedVectorSetArray(impl->qvecsout[out], CEED_MEM_HOST, 621 CEED_USE_POINTER, a); CeedChkBackend(ierr); 622 ierr = CeedQFunctionFieldGetSize(qfoutputfields[out], &size); 623 CeedChkBackend(ierr); 624 a += size*Q; // Advance the pointer by the size of the output 625 } 626 } 627 // Apply QFunction 628 ierr = CeedQFunctionApply(qf, Q, impl->qvecsin, impl->qvecsout); 629 CeedChkBackend(ierr); 630 } 631 } 632 633 // Un-set output Qvecs to prevent accidental overwrite of Assembled 634 for (CeedInt out=0; out<numoutputfields; out++) { 635 // Get output vector 636 ierr = CeedOperatorFieldGetVector(opoutputfields[out], &vec); 637 CeedChkBackend(ierr); 638 // Check if active output 639 if (vec == CEED_VECTOR_ACTIVE) { 640 CeedVectorTakeArray(impl->qvecsout[out], CEED_MEM_HOST, NULL); 641 CeedChkBackend(ierr); 642 } 643 } 644 645 // Restore input arrays 646 ierr = CeedOperatorRestoreInputs_Ref(numinputfields, qfinputfields, 647 opinputfields, true, impl); 648 CeedChkBackend(ierr); 649 650 // Restore output 651 ierr = CeedVectorRestoreArray(*assembled, &a); CeedChkBackend(ierr); 652 653 // Cleanup 654 for (CeedInt i=0; i<numactivein; i++) { 655 ierr = CeedVectorDestroy(&activein[i]); CeedChkBackend(ierr); 656 } 657 ierr = CeedFree(&activein); CeedChkBackend(ierr); 658 659 return CEED_ERROR_SUCCESS; 660 } 661 662 //------------------------------------------------------------------------------ 663 // Get Basis Emode Pointer 664 //------------------------------------------------------------------------------ 665 static inline void CeedOperatorGetBasisPointer_Ref(const CeedScalar **basisptr, 666 CeedEvalMode emode, const CeedScalar *identity, const CeedScalar *interp, 667 const CeedScalar *grad) { 668 switch (emode) { 669 case CEED_EVAL_NONE: 670 *basisptr = identity; 671 break; 672 case CEED_EVAL_INTERP: 673 *basisptr = interp; 674 break; 675 case CEED_EVAL_GRAD: 676 *basisptr = grad; 677 break; 678 case CEED_EVAL_WEIGHT: 679 case CEED_EVAL_DIV: 680 case CEED_EVAL_CURL: 681 break; // Caught by QF Assembly 682 } 683 } 684 685 //------------------------------------------------------------------------------ 686 // Create point block restriction 687 //------------------------------------------------------------------------------ 688 static int CreatePBRestriction_Ref(CeedElemRestriction rstr, 689 CeedElemRestriction *pbRstr) { 690 int ierr; 691 Ceed ceed; 692 ierr = CeedElemRestrictionGetCeed(rstr, &ceed); CeedChkBackend(ierr); 693 const CeedInt *offsets; 694 ierr = CeedElemRestrictionGetOffsets(rstr, CEED_MEM_HOST, &offsets); 695 CeedChkBackend(ierr); 696 697 // Expand offsets 698 CeedInt nelem, ncomp, elemsize, compstride, max = 1, *pbOffsets; 699 ierr = CeedElemRestrictionGetNumElements(rstr, &nelem); CeedChkBackend(ierr); 700 ierr = CeedElemRestrictionGetNumComponents(rstr, &ncomp); CeedChkBackend(ierr); 701 ierr = CeedElemRestrictionGetElementSize(rstr, &elemsize); CeedChkBackend(ierr); 702 ierr = CeedElemRestrictionGetCompStride(rstr, &compstride); 703 CeedChkBackend(ierr); 704 CeedInt shift = ncomp; 705 if (compstride != 1) 706 shift *= ncomp; 707 ierr = CeedCalloc(nelem*elemsize, &pbOffsets); CeedChkBackend(ierr); 708 for (CeedInt i = 0; i < nelem*elemsize; i++) { 709 pbOffsets[i] = offsets[i]*shift; 710 if (pbOffsets[i] > max) 711 max = pbOffsets[i]; 712 } 713 714 // Create new restriction 715 ierr = CeedElemRestrictionCreate(ceed, nelem, elemsize, ncomp*ncomp, 1, 716 max + ncomp*ncomp, CEED_MEM_HOST, 717 CEED_OWN_POINTER, pbOffsets, pbRstr); 718 CeedChkBackend(ierr); 719 720 // Cleanup 721 ierr = CeedElemRestrictionRestoreOffsets(rstr, &offsets); CeedChkBackend(ierr); 722 723 return CEED_ERROR_SUCCESS; 724 } 725 726 //------------------------------------------------------------------------------ 727 // Assemble diagonal common code 728 //------------------------------------------------------------------------------ 729 static inline int CeedOperatorAssembleAddDiagonalCore_Ref(CeedOperator op, 730 CeedVector assembled, CeedRequest *request, const bool pointBlock) { 731 int ierr; 732 Ceed ceed; 733 ierr = CeedOperatorGetCeed(op, &ceed); CeedChkBackend(ierr); 734 735 // Assemble QFunction 736 CeedQFunction qf; 737 ierr = CeedOperatorGetQFunction(op, &qf); CeedChkBackend(ierr); 738 CeedInt numinputfields, numoutputfields; 739 ierr= CeedQFunctionGetNumArgs(qf, &numinputfields, &numoutputfields); 740 CeedChkBackend(ierr); 741 CeedVector assembledqf; 742 CeedElemRestriction rstr; 743 ierr = CeedOperatorLinearAssembleQFunction(op, &assembledqf, &rstr, request); 744 CeedChkBackend(ierr); 745 ierr = CeedElemRestrictionDestroy(&rstr); CeedChkBackend(ierr); 746 CeedScalar maxnorm = 0; 747 ierr = CeedVectorNorm(assembledqf, CEED_NORM_MAX, &maxnorm); 748 CeedChkBackend(ierr); 749 750 // Determine active input basis 751 CeedOperatorField *opfields; 752 CeedQFunctionField *qffields; 753 ierr = CeedOperatorGetFields(op, &opfields, NULL); CeedChkBackend(ierr); 754 ierr = CeedQFunctionGetFields(qf, &qffields, NULL); CeedChkBackend(ierr); 755 CeedInt numemodein = 0, ncomp, dim = 1; 756 CeedEvalMode *emodein = NULL; 757 CeedBasis basisin = NULL; 758 CeedElemRestriction rstrin = NULL; 759 for (CeedInt i=0; i<numinputfields; i++) { 760 CeedVector vec; 761 ierr = CeedOperatorFieldGetVector(opfields[i], &vec); CeedChkBackend(ierr); 762 if (vec == CEED_VECTOR_ACTIVE) { 763 CeedElemRestriction rstr; 764 ierr = CeedOperatorFieldGetBasis(opfields[i], &basisin); CeedChkBackend(ierr); 765 ierr = CeedBasisGetNumComponents(basisin, &ncomp); CeedChkBackend(ierr); 766 ierr = CeedBasisGetDimension(basisin, &dim); CeedChkBackend(ierr); 767 ierr = CeedOperatorFieldGetElemRestriction(opfields[i], &rstr); 768 CeedChkBackend(ierr); 769 if (rstrin && rstrin != rstr) 770 // LCOV_EXCL_START 771 return CeedError(ceed, CEED_ERROR_BACKEND, 772 "Multi-field non-composite operator diagonal assembly not supported"); 773 // LCOV_EXCL_STOP 774 rstrin = rstr; 775 CeedEvalMode emode; 776 ierr = CeedQFunctionFieldGetEvalMode(qffields[i], &emode); 777 CeedChkBackend(ierr); 778 switch (emode) { 779 case CEED_EVAL_NONE: 780 case CEED_EVAL_INTERP: 781 ierr = CeedRealloc(numemodein + 1, &emodein); CeedChkBackend(ierr); 782 emodein[numemodein] = emode; 783 numemodein += 1; 784 break; 785 case CEED_EVAL_GRAD: 786 ierr = CeedRealloc(numemodein + dim, &emodein); CeedChkBackend(ierr); 787 for (CeedInt d=0; d<dim; d++) 788 emodein[numemodein+d] = emode; 789 numemodein += dim; 790 break; 791 case CEED_EVAL_WEIGHT: 792 case CEED_EVAL_DIV: 793 case CEED_EVAL_CURL: 794 break; // Caught by QF Assembly 795 } 796 } 797 } 798 799 // Determine active output basis 800 ierr = CeedOperatorGetFields(op, NULL, &opfields); CeedChkBackend(ierr); 801 ierr = CeedQFunctionGetFields(qf, NULL, &qffields); CeedChkBackend(ierr); 802 CeedInt numemodeout = 0; 803 CeedEvalMode *emodeout = NULL; 804 CeedBasis basisout = NULL; 805 CeedElemRestriction rstrout = NULL; 806 for (CeedInt i=0; i<numoutputfields; i++) { 807 CeedVector vec; 808 ierr = CeedOperatorFieldGetVector(opfields[i], &vec); CeedChkBackend(ierr); 809 if (vec == CEED_VECTOR_ACTIVE) { 810 CeedElemRestriction rstr; 811 ierr = CeedOperatorFieldGetBasis(opfields[i], &basisout); CeedChkBackend(ierr); 812 ierr = CeedOperatorFieldGetElemRestriction(opfields[i], &rstr); 813 CeedChkBackend(ierr); 814 if (rstrout && rstrout != rstr) 815 // LCOV_EXCL_START 816 return CeedError(ceed, CEED_ERROR_BACKEND, 817 "Multi-field non-composite operator diagonal assembly not supported"); 818 // LCOV_EXCL_STOP 819 rstrout = rstr; 820 CeedEvalMode emode; 821 ierr = CeedQFunctionFieldGetEvalMode(qffields[i], &emode); CeedChkBackend(ierr); 822 switch (emode) { 823 case CEED_EVAL_NONE: 824 case CEED_EVAL_INTERP: 825 ierr = CeedRealloc(numemodeout + 1, &emodeout); CeedChkBackend(ierr); 826 emodeout[numemodeout] = emode; 827 numemodeout += 1; 828 break; 829 case CEED_EVAL_GRAD: 830 ierr = CeedRealloc(numemodeout + dim, &emodeout); CeedChkBackend(ierr); 831 for (CeedInt d=0; d<dim; d++) 832 emodeout[numemodeout+d] = emode; 833 numemodeout += dim; 834 break; 835 case CEED_EVAL_WEIGHT: 836 case CEED_EVAL_DIV: 837 case CEED_EVAL_CURL: 838 break; // Caught by QF Assembly 839 } 840 } 841 } 842 843 // Assemble point-block diagonal restriction, if needed 844 CeedElemRestriction diagrstr = rstrout; 845 if (pointBlock) { 846 ierr = CreatePBRestriction_Ref(rstrout, &diagrstr); CeedChkBackend(ierr); 847 } 848 849 // Create diagonal vector 850 CeedVector elemdiag; 851 ierr = CeedElemRestrictionCreateVector(diagrstr, NULL, &elemdiag); 852 CeedChkBackend(ierr); 853 854 // Assemble element operator diagonals 855 CeedScalar *elemdiagarray, *assembledqfarray; 856 ierr = CeedVectorSetValue(elemdiag, 0.0); CeedChkBackend(ierr); 857 ierr = CeedVectorGetArray(elemdiag, CEED_MEM_HOST, &elemdiagarray); 858 CeedChkBackend(ierr); 859 ierr = CeedVectorGetArray(assembledqf, CEED_MEM_HOST, &assembledqfarray); 860 CeedChkBackend(ierr); 861 CeedInt nelem, nnodes, nqpts; 862 ierr = CeedElemRestrictionGetNumElements(diagrstr, &nelem); 863 CeedChkBackend(ierr); 864 ierr = CeedBasisGetNumNodes(basisin, &nnodes); CeedChkBackend(ierr); 865 ierr = CeedBasisGetNumQuadraturePoints(basisin, &nqpts); CeedChkBackend(ierr); 866 // Basis matrices 867 const CeedScalar *interpin, *interpout, *gradin, *gradout; 868 CeedScalar *identity = NULL; 869 bool evalNone = false; 870 for (CeedInt i=0; i<numemodein; i++) 871 evalNone = evalNone || (emodein[i] == CEED_EVAL_NONE); 872 for (CeedInt i=0; i<numemodeout; i++) 873 evalNone = evalNone || (emodeout[i] == CEED_EVAL_NONE); 874 if (evalNone) { 875 ierr = CeedCalloc(nqpts*nnodes, &identity); CeedChkBackend(ierr); 876 for (CeedInt i=0; i<(nnodes<nqpts?nnodes:nqpts); i++) 877 identity[i*nnodes+i] = 1.0; 878 } 879 ierr = CeedBasisGetInterp(basisin, &interpin); CeedChkBackend(ierr); 880 ierr = CeedBasisGetInterp(basisout, &interpout); CeedChkBackend(ierr); 881 ierr = CeedBasisGetGrad(basisin, &gradin); CeedChkBackend(ierr); 882 ierr = CeedBasisGetGrad(basisout, &gradout); CeedChkBackend(ierr); 883 // Compute the diagonal of B^T D B 884 // Each element 885 const CeedScalar qfvaluebound = maxnorm*1e-12; 886 for (CeedInt e=0; e<nelem; e++) { 887 CeedInt dout = -1; 888 // Each basis eval mode pair 889 for (CeedInt eout=0; eout<numemodeout; eout++) { 890 const CeedScalar *bt = NULL; 891 if (emodeout[eout] == CEED_EVAL_GRAD) 892 dout += 1; 893 CeedOperatorGetBasisPointer_Ref(&bt, emodeout[eout], identity, interpout, 894 &gradout[dout*nqpts*nnodes]); 895 CeedInt din = -1; 896 for (CeedInt ein=0; ein<numemodein; ein++) { 897 const CeedScalar *b = NULL; 898 if (emodein[ein] == CEED_EVAL_GRAD) 899 din += 1; 900 CeedOperatorGetBasisPointer_Ref(&b, emodein[ein], identity, interpin, 901 &gradin[din*nqpts*nnodes]); 902 // Each component 903 for (CeedInt compOut=0; compOut<ncomp; compOut++) 904 // Each qpoint/node pair 905 for (CeedInt q=0; q<nqpts; q++) 906 if (pointBlock) { 907 // Point Block Diagonal 908 for (CeedInt compIn=0; compIn<ncomp; compIn++) { 909 const CeedScalar qfvalue = 910 assembledqfarray[((((e*numemodein+ein)*ncomp+compIn)* 911 numemodeout+eout)*ncomp+compOut)*nqpts+q]; 912 if (fabs(qfvalue) > qfvaluebound) 913 for (CeedInt n=0; n<nnodes; n++) 914 elemdiagarray[((e*ncomp+compOut)*ncomp+compIn)*nnodes+n] += 915 bt[q*nnodes+n] * qfvalue * b[q*nnodes+n]; 916 } 917 } else { 918 // Diagonal Only 919 const CeedScalar qfvalue = 920 assembledqfarray[((((e*numemodein+ein)*ncomp+compOut)* 921 numemodeout+eout)*ncomp+compOut)*nqpts+q]; 922 if (fabs(qfvalue) > qfvaluebound) 923 for (CeedInt n=0; n<nnodes; n++) 924 elemdiagarray[(e*ncomp+compOut)*nnodes+n] += 925 bt[q*nnodes+n] * qfvalue * b[q*nnodes+n]; 926 } 927 } 928 } 929 } 930 ierr = CeedVectorRestoreArray(elemdiag, &elemdiagarray); CeedChkBackend(ierr); 931 ierr = CeedVectorRestoreArray(assembledqf, &assembledqfarray); 932 CeedChkBackend(ierr); 933 934 // Assemble local operator diagonal 935 ierr = CeedElemRestrictionApply(diagrstr, CEED_TRANSPOSE, elemdiag, 936 assembled, request); CeedChkBackend(ierr); 937 938 // Cleanup 939 if (pointBlock) { 940 ierr = CeedElemRestrictionDestroy(&diagrstr); CeedChkBackend(ierr); 941 } 942 ierr = CeedVectorDestroy(&assembledqf); CeedChkBackend(ierr); 943 ierr = CeedVectorDestroy(&elemdiag); CeedChkBackend(ierr); 944 ierr = CeedFree(&emodein); CeedChkBackend(ierr); 945 ierr = CeedFree(&emodeout); CeedChkBackend(ierr); 946 ierr = CeedFree(&identity); CeedChkBackend(ierr); 947 948 return CEED_ERROR_SUCCESS; 949 } 950 951 //------------------------------------------------------------------------------ 952 // Assemble composite diagonal common code 953 //------------------------------------------------------------------------------ 954 static inline int CeedOperatorLinearAssembleAddDiagonalCompositeCore_Ref( 955 CeedOperator op, CeedVector assembled, CeedRequest *request, 956 const bool pointBlock) { 957 int ierr; 958 CeedInt numSub; 959 CeedOperator *subOperators; 960 ierr = CeedOperatorGetNumSub(op, &numSub); CeedChkBackend(ierr); 961 ierr = CeedOperatorGetSubList(op, &subOperators); CeedChkBackend(ierr); 962 for (CeedInt i = 0; i < numSub; i++) { 963 ierr = CeedOperatorAssembleAddDiagonalCore_Ref(subOperators[i], assembled, 964 request, pointBlock); CeedChkBackend(ierr); 965 } 966 return CEED_ERROR_SUCCESS; 967 } 968 969 //------------------------------------------------------------------------------ 970 // Assemble Linear Diagonal 971 //------------------------------------------------------------------------------ 972 static int CeedOperatorLinearAssembleAddDiagonal_Ref(CeedOperator op, 973 CeedVector assembled, CeedRequest *request) { 974 int ierr; 975 bool isComposite; 976 ierr = CeedOperatorIsComposite(op, &isComposite); CeedChkBackend(ierr); 977 if (isComposite) { 978 return CeedOperatorLinearAssembleAddDiagonalCompositeCore_Ref(op, assembled, 979 request, false); 980 } else { 981 return CeedOperatorAssembleAddDiagonalCore_Ref(op, assembled, request, false); 982 } 983 } 984 985 //------------------------------------------------------------------------------ 986 // Assemble Linear Point Block Diagonal 987 //------------------------------------------------------------------------------ 988 static int CeedOperatorLinearAssembleAddPointBlockDiagonal_Ref(CeedOperator op, 989 CeedVector assembled, CeedRequest *request) { 990 int ierr; 991 bool isComposite; 992 ierr = CeedOperatorIsComposite(op, &isComposite); CeedChkBackend(ierr); 993 if (isComposite) { 994 return CeedOperatorLinearAssembleAddDiagonalCompositeCore_Ref(op, assembled, 995 request, true); 996 } else { 997 return CeedOperatorAssembleAddDiagonalCore_Ref(op, assembled, request, true); 998 } 999 } 1000 1001 //------------------------------------------------------------------------------ 1002 // Create FDM Element Inverse 1003 //------------------------------------------------------------------------------ 1004 int CeedOperatorCreateFDMElementInverse_Ref(CeedOperator op, 1005 CeedOperator *fdminv, CeedRequest *request) { 1006 int ierr; 1007 Ceed ceed, ceedparent; 1008 ierr = CeedOperatorGetCeed(op, &ceed); CeedChkBackend(ierr); 1009 ierr = CeedGetOperatorFallbackParentCeed(ceed, &ceedparent); 1010 CeedChkBackend(ierr); 1011 ceedparent = ceedparent ? ceedparent : ceed; 1012 CeedQFunction qf; 1013 ierr = CeedOperatorGetQFunction(op, &qf); CeedChkBackend(ierr); 1014 1015 // Determine active input basis 1016 bool interp = false, grad = false; 1017 CeedBasis basis = NULL; 1018 CeedElemRestriction rstr = NULL; 1019 CeedOperatorField *opfields; 1020 CeedQFunctionField *qffields; 1021 ierr = CeedOperatorGetFields(op, &opfields, NULL); CeedChkBackend(ierr); 1022 ierr = CeedQFunctionGetFields(qf, &qffields, NULL); CeedChkBackend(ierr); 1023 CeedInt numinputfields; 1024 ierr = CeedQFunctionGetNumArgs(qf, &numinputfields, NULL); CeedChkBackend(ierr); 1025 for (CeedInt i=0; i<numinputfields; i++) { 1026 CeedVector vec; 1027 ierr = CeedOperatorFieldGetVector(opfields[i], &vec); CeedChkBackend(ierr); 1028 if (vec == CEED_VECTOR_ACTIVE) { 1029 CeedEvalMode emode; 1030 ierr = CeedQFunctionFieldGetEvalMode(qffields[i], &emode); CeedChkBackend(ierr); 1031 interp = interp || emode == CEED_EVAL_INTERP; 1032 grad = grad || emode == CEED_EVAL_GRAD; 1033 ierr = CeedOperatorFieldGetBasis(opfields[i], &basis); CeedChkBackend(ierr); 1034 ierr = CeedOperatorFieldGetElemRestriction(opfields[i], &rstr); 1035 CeedChkBackend(ierr); 1036 } 1037 } 1038 if (!basis) 1039 // LCOV_EXCL_START 1040 return CeedError(ceed, CEED_ERROR_BACKEND, "No active field set"); 1041 // LCOV_EXCL_STOP 1042 CeedInt P1d, Q1d, elemsize, nqpts, dim, ncomp = 1, nelem = 1, lsize = 1; 1043 ierr = CeedBasisGetNumNodes1D(basis, &P1d); CeedChkBackend(ierr); 1044 ierr = CeedBasisGetNumNodes(basis, &elemsize); CeedChkBackend(ierr); 1045 ierr = CeedBasisGetNumQuadraturePoints1D(basis, &Q1d); CeedChkBackend(ierr); 1046 ierr = CeedBasisGetNumQuadraturePoints(basis, &nqpts); CeedChkBackend(ierr); 1047 ierr = CeedBasisGetDimension(basis, &dim); CeedChkBackend(ierr); 1048 ierr = CeedBasisGetNumComponents(basis, &ncomp); CeedChkBackend(ierr); 1049 ierr = CeedElemRestrictionGetNumElements(rstr, &nelem); CeedChkBackend(ierr); 1050 ierr = CeedElemRestrictionGetLVectorSize(rstr, &lsize); CeedChkBackend(ierr); 1051 1052 // Build and diagonalize 1D Mass and Laplacian 1053 bool tensorbasis; 1054 ierr = CeedBasisIsTensor(basis, &tensorbasis); CeedChkBackend(ierr); 1055 if (!tensorbasis) 1056 // LCOV_EXCL_START 1057 return CeedError(ceed, CEED_ERROR_BACKEND, 1058 "FDMElementInverse only supported for tensor " 1059 "bases"); 1060 // LCOV_EXCL_STOP 1061 CeedScalar *work, *mass, *laplace, *x, *x2, *lambda; 1062 ierr = CeedMalloc(Q1d*P1d, &work); CeedChkBackend(ierr); 1063 ierr = CeedMalloc(P1d*P1d, &mass); CeedChkBackend(ierr); 1064 ierr = CeedMalloc(P1d*P1d, &laplace); CeedChkBackend(ierr); 1065 ierr = CeedMalloc(P1d*P1d, &x); CeedChkBackend(ierr); 1066 ierr = CeedMalloc(P1d*P1d, &x2); CeedChkBackend(ierr); 1067 ierr = CeedMalloc(P1d, &lambda); CeedChkBackend(ierr); 1068 // -- Mass 1069 const CeedScalar *interp1d, *grad1d, *qweight1d; 1070 ierr = CeedBasisGetInterp1D(basis, &interp1d); CeedChkBackend(ierr); 1071 ierr = CeedBasisGetGrad1D(basis, &grad1d); CeedChkBackend(ierr); 1072 ierr = CeedBasisGetQWeights(basis, &qweight1d); CeedChkBackend(ierr); 1073 for (CeedInt i=0; i<Q1d; i++) 1074 for (CeedInt j=0; j<P1d; j++) 1075 work[i+j*Q1d] = interp1d[i*P1d+j]*qweight1d[i]; 1076 ierr = CeedMatrixMultiply(ceed, (const CeedScalar *)work, 1077 (const CeedScalar *)interp1d, mass, P1d, P1d, Q1d); 1078 CeedChkBackend(ierr); 1079 // -- Laplacian 1080 for (CeedInt i=0; i<Q1d; i++) 1081 for (CeedInt j=0; j<P1d; j++) 1082 work[i+j*Q1d] = grad1d[i*P1d+j]*qweight1d[i]; 1083 ierr = CeedMatrixMultiply(ceed, (const CeedScalar *)work, 1084 (const CeedScalar *)grad1d, laplace, P1d, P1d, Q1d); 1085 CeedChkBackend(ierr); 1086 // -- Diagonalize 1087 ierr = CeedSimultaneousDiagonalization(ceed, laplace, mass, x, lambda, P1d); 1088 CeedChkBackend(ierr); 1089 ierr = CeedFree(&work); CeedChkBackend(ierr); 1090 ierr = CeedFree(&mass); CeedChkBackend(ierr); 1091 ierr = CeedFree(&laplace); CeedChkBackend(ierr); 1092 for (CeedInt i=0; i<P1d; i++) 1093 for (CeedInt j=0; j<P1d; j++) 1094 x2[i+j*P1d] = x[j+i*P1d]; 1095 ierr = CeedFree(&x); CeedChkBackend(ierr); 1096 1097 // Assemble QFunction 1098 CeedVector assembled; 1099 CeedElemRestriction rstr_qf; 1100 ierr = CeedOperatorLinearAssembleQFunction(op, &assembled, &rstr_qf, 1101 request); CeedChkBackend(ierr); 1102 ierr = CeedElemRestrictionDestroy(&rstr_qf); CeedChkBackend(ierr); 1103 CeedScalar maxnorm = 0; 1104 ierr = CeedVectorNorm(assembled, CEED_NORM_MAX, &maxnorm); CeedChkBackend(ierr); 1105 1106 // Calculate element averages 1107 CeedInt nfields = ((interp?1:0) + (grad?dim:0))*((interp?1:0) + (grad?dim:0)); 1108 CeedScalar *elemavg; 1109 const CeedScalar *assembledarray, *qweightsarray; 1110 CeedVector qweights; 1111 ierr = CeedVectorCreate(ceedparent, nqpts, &qweights); CeedChkBackend(ierr); 1112 ierr = CeedBasisApply(basis, 1, CEED_NOTRANSPOSE, CEED_EVAL_WEIGHT, 1113 CEED_VECTOR_NONE, qweights); CeedChkBackend(ierr); 1114 ierr = CeedVectorGetArrayRead(assembled, CEED_MEM_HOST, &assembledarray); 1115 CeedChkBackend(ierr); 1116 ierr = CeedVectorGetArrayRead(qweights, CEED_MEM_HOST, &qweightsarray); 1117 CeedChkBackend(ierr); 1118 ierr = CeedCalloc(nelem, &elemavg); CeedChkBackend(ierr); 1119 for (CeedInt e=0; e<nelem; e++) { 1120 CeedInt count = 0; 1121 for (CeedInt q=0; q<nqpts; q++) 1122 for (CeedInt i=0; i<ncomp*ncomp*nfields; i++) 1123 if (fabs(assembledarray[e*nelem*nqpts*ncomp*ncomp*nfields + 1124 i*nqpts + q]) > maxnorm*1e-12) { 1125 elemavg[e] += assembledarray[e*nelem*nqpts*ncomp*ncomp*nfields + 1126 i*nqpts + q] / qweightsarray[q]; 1127 count++; 1128 } 1129 if (count) 1130 elemavg[e] /= count; 1131 } 1132 ierr = CeedVectorRestoreArrayRead(assembled, &assembledarray); 1133 CeedChkBackend(ierr); 1134 ierr = CeedVectorDestroy(&assembled); CeedChkBackend(ierr); 1135 ierr = CeedVectorRestoreArrayRead(qweights, &qweightsarray); 1136 CeedChkBackend(ierr); 1137 ierr = CeedVectorDestroy(&qweights); CeedChkBackend(ierr); 1138 1139 // Build FDM diagonal 1140 CeedVector qdata; 1141 CeedScalar *qdataarray; 1142 ierr = CeedVectorCreate(ceedparent, nelem*ncomp*lsize, &qdata); 1143 CeedChkBackend(ierr); 1144 ierr = CeedVectorSetArray(qdata, CEED_MEM_HOST, CEED_COPY_VALUES, NULL); 1145 CeedChkBackend(ierr); 1146 ierr = CeedVectorGetArray(qdata, CEED_MEM_HOST, &qdataarray); 1147 CeedChkBackend(ierr); 1148 for (CeedInt e=0; e<nelem; e++) 1149 for (CeedInt c=0; c<ncomp; c++) 1150 for (CeedInt n=0; n<lsize; n++) { 1151 if (interp) 1152 qdataarray[(e*ncomp+c)*lsize+n] = 1; 1153 if (grad) 1154 for (CeedInt d=0; d<dim; d++) { 1155 CeedInt i = (n / CeedIntPow(P1d, d)) % P1d; 1156 qdataarray[(e*ncomp+c)*lsize+n] += lambda[i]; 1157 } 1158 qdataarray[(e*ncomp+c)*lsize+n] = 1 / (elemavg[e] * 1159 qdataarray[(e*ncomp+c)*lsize+n]); 1160 } 1161 ierr = CeedFree(&elemavg); CeedChkBackend(ierr); 1162 ierr = CeedVectorRestoreArray(qdata, &qdataarray); CeedChkBackend(ierr); 1163 1164 // Setup FDM operator 1165 // -- Basis 1166 CeedBasis fdm_basis; 1167 CeedScalar *graddummy, *qrefdummy, *qweightdummy; 1168 ierr = CeedCalloc(P1d*P1d, &graddummy); CeedChkBackend(ierr); 1169 ierr = CeedCalloc(P1d, &qrefdummy); CeedChkBackend(ierr); 1170 ierr = CeedCalloc(P1d, &qweightdummy); CeedChkBackend(ierr); 1171 ierr = CeedBasisCreateTensorH1(ceedparent, dim, ncomp, P1d, P1d, x2, 1172 graddummy, qrefdummy, qweightdummy, 1173 &fdm_basis); CeedChkBackend(ierr); 1174 ierr = CeedFree(&graddummy); CeedChkBackend(ierr); 1175 ierr = CeedFree(&qrefdummy); CeedChkBackend(ierr); 1176 ierr = CeedFree(&qweightdummy); CeedChkBackend(ierr); 1177 ierr = CeedFree(&x2); CeedChkBackend(ierr); 1178 ierr = CeedFree(&lambda); CeedChkBackend(ierr); 1179 1180 // -- Restriction 1181 CeedElemRestriction rstr_i; 1182 CeedInt strides[3] = {1, lsize, lsize*ncomp}; 1183 ierr = CeedElemRestrictionCreateStrided(ceedparent, nelem, lsize, ncomp, 1184 lsize*nelem*ncomp, strides, &rstr_i); 1185 CeedChkBackend(ierr); 1186 // -- QFunction 1187 CeedQFunction mass_qf; 1188 ierr = CeedQFunctionCreateInteriorByName(ceedparent, "MassApply", &mass_qf); 1189 CeedChkBackend(ierr); 1190 // -- Operator 1191 ierr = CeedOperatorCreate(ceedparent, mass_qf, NULL, NULL, fdminv); 1192 CeedChkBackend(ierr); 1193 CeedOperatorSetField(*fdminv, "u", rstr_i, fdm_basis, CEED_VECTOR_ACTIVE); 1194 CeedChkBackend(ierr); 1195 CeedOperatorSetField(*fdminv, "qdata", rstr_i, CEED_BASIS_COLLOCATED, qdata); 1196 CeedChkBackend(ierr); 1197 CeedOperatorSetField(*fdminv, "v", rstr_i, fdm_basis, CEED_VECTOR_ACTIVE); 1198 CeedChkBackend(ierr); 1199 1200 // Cleanup 1201 ierr = CeedVectorDestroy(&qdata); CeedChkBackend(ierr); 1202 ierr = CeedBasisDestroy(&fdm_basis); CeedChkBackend(ierr); 1203 ierr = CeedElemRestrictionDestroy(&rstr_i); CeedChkBackend(ierr); 1204 ierr = CeedQFunctionDestroy(&mass_qf); CeedChkBackend(ierr); 1205 1206 return CEED_ERROR_SUCCESS; 1207 } 1208 1209 //------------------------------------------------------------------------------ 1210 // Operator Destroy 1211 //------------------------------------------------------------------------------ 1212 static int CeedOperatorDestroy_Ref(CeedOperator op) { 1213 int ierr; 1214 CeedOperator_Ref *impl; 1215 ierr = CeedOperatorGetData(op, &impl); CeedChkBackend(ierr); 1216 1217 for (CeedInt i=0; i<impl->numein+impl->numeout; i++) { 1218 ierr = CeedVectorDestroy(&impl->evecs[i]); CeedChkBackend(ierr); 1219 } 1220 ierr = CeedFree(&impl->evecs); CeedChkBackend(ierr); 1221 ierr = CeedFree(&impl->edata); CeedChkBackend(ierr); 1222 ierr = CeedFree(&impl->inputstate); CeedChkBackend(ierr); 1223 1224 for (CeedInt i=0; i<impl->numein; i++) { 1225 ierr = CeedVectorDestroy(&impl->evecsin[i]); CeedChkBackend(ierr); 1226 ierr = CeedVectorDestroy(&impl->qvecsin[i]); CeedChkBackend(ierr); 1227 } 1228 ierr = CeedFree(&impl->evecsin); CeedChkBackend(ierr); 1229 ierr = CeedFree(&impl->qvecsin); CeedChkBackend(ierr); 1230 1231 for (CeedInt i=0; i<impl->numeout; i++) { 1232 ierr = CeedVectorDestroy(&impl->evecsout[i]); CeedChkBackend(ierr); 1233 ierr = CeedVectorDestroy(&impl->qvecsout[i]); CeedChkBackend(ierr); 1234 } 1235 ierr = CeedFree(&impl->evecsout); CeedChkBackend(ierr); 1236 ierr = CeedFree(&impl->qvecsout); CeedChkBackend(ierr); 1237 1238 ierr = CeedFree(&impl); CeedChkBackend(ierr); 1239 return CEED_ERROR_SUCCESS; 1240 } 1241 1242 //------------------------------------------------------------------------------ 1243 // Operator Create 1244 //------------------------------------------------------------------------------ 1245 int CeedOperatorCreate_Ref(CeedOperator op) { 1246 int ierr; 1247 Ceed ceed; 1248 ierr = CeedOperatorGetCeed(op, &ceed); CeedChkBackend(ierr); 1249 CeedOperator_Ref *impl; 1250 1251 ierr = CeedCalloc(1, &impl); CeedChkBackend(ierr); 1252 ierr = CeedOperatorSetData(op, impl); CeedChkBackend(ierr); 1253 1254 ierr = CeedSetBackendFunction(ceed, "Operator", op, "LinearAssembleQFunction", 1255 CeedOperatorLinearAssembleQFunction_Ref); 1256 CeedChkBackend(ierr); 1257 ierr = CeedSetBackendFunction(ceed, "Operator", op, "LinearAssembleAddDiagonal", 1258 CeedOperatorLinearAssembleAddDiagonal_Ref); 1259 CeedChkBackend(ierr); 1260 ierr = CeedSetBackendFunction(ceed, "Operator", op, 1261 "LinearAssembleAddPointBlockDiagonal", 1262 CeedOperatorLinearAssembleAddPointBlockDiagonal_Ref); 1263 CeedChkBackend(ierr); 1264 ierr = CeedSetBackendFunction(ceed, "Operator", op, "CreateFDMElementInverse", 1265 CeedOperatorCreateFDMElementInverse_Ref); 1266 CeedChkBackend(ierr); 1267 ierr = CeedSetBackendFunction(ceed, "Operator", op, "ApplyAdd", 1268 CeedOperatorApplyAdd_Ref); CeedChkBackend(ierr); 1269 ierr = CeedSetBackendFunction(ceed, "Operator", op, "Destroy", 1270 CeedOperatorDestroy_Ref); CeedChkBackend(ierr); 1271 return CEED_ERROR_SUCCESS; 1272 } 1273 1274 //------------------------------------------------------------------------------ 1275 // Composite Operator Create 1276 //------------------------------------------------------------------------------ 1277 int CeedCompositeOperatorCreate_Ref(CeedOperator op) { 1278 int ierr; 1279 Ceed ceed; 1280 ierr = CeedOperatorGetCeed(op, &ceed); CeedChkBackend(ierr); 1281 ierr = CeedSetBackendFunction(ceed, "Operator", op, "LinearAssembleAddDiagonal", 1282 CeedOperatorLinearAssembleAddDiagonal_Ref); 1283 CeedChkBackend(ierr); 1284 ierr = CeedSetBackendFunction(ceed, "Operator", op, 1285 "LinearAssembleAddPointBlockDiagonal", 1286 CeedOperatorLinearAssembleAddPointBlockDiagonal_Ref); 1287 CeedChkBackend(ierr); 1288 return CEED_ERROR_SUCCESS; 1289 } 1290 //------------------------------------------------------------------------------ 1291