// Copyright (c) 2017-2018, Lawrence Livermore National Security, LLC. // Produced at the Lawrence Livermore National Laboratory. LLNL-CODE-734707. // All Rights reserved. See files LICENSE and NOTICE for details. // // This file is part of CEED, a collection of benchmarks, miniapps, software // libraries and APIs for efficient high-order finite element and spectral // element discretizations for exascale applications. For more information and // source code availability see http://github.com/ceed. // // The CEED research is supported by the Exascale Computing Project 17-SC-20-SC, // a collaborative effort of two U.S. Department of Energy organizations (Office // of Science and the National Nuclear Security Administration) responsible for // the planning and preparation of a capable exascale ecosystem, including // software, applications, hardware, advanced system engineering and early // testbed platforms, in support of the nation's exascale computing imperative. #include #include "ceed-opt.h" #include "../ref/ceed-ref.h" //------------------------------------------------------------------------------ // Setup Input/Output Fields //------------------------------------------------------------------------------ static int CeedOperatorSetupFields_Opt(CeedQFunction qf, CeedOperator op, bool inOrOut, const CeedInt blksize, CeedElemRestriction *blkrestr, CeedVector *fullevecs, CeedVector *evecs, CeedVector *qvecs, CeedInt starte, CeedInt numfields, CeedInt Q) { CeedInt dim, ierr, ncomp, size, P; Ceed ceed; ierr = CeedOperatorGetCeed(op, &ceed); CeedChk(ierr); CeedBasis basis; CeedElemRestriction r; CeedOperatorField *opfields; CeedQFunctionField *qffields; if (inOrOut) { ierr = CeedOperatorGetFields(op, NULL, &opfields); CeedChk(ierr); ierr = CeedQFunctionGetFields(qf, NULL, &qffields); CeedChk(ierr); } else { ierr = CeedOperatorGetFields(op, &opfields, NULL); CeedChk(ierr); ierr = CeedQFunctionGetFields(qf, &qffields, NULL); CeedChk(ierr); } // Loop over fields for (CeedInt i=0; iindices) { ierr = CeedElemRestrictionGetIMode(r, &imode); CeedChk(ierr); ierr = CeedElemRestrictionCreateBlocked(ceed, imode, nelem, elemsize, blksize, nnodes, ncomp, CEED_MEM_HOST, CEED_COPY_VALUES, data->indices, &blkrestr[i+starte]); CeedChk(ierr); } else { CeedInt strides[3]; ierr = CeedElemRestrictionGetStrides(r, &strides); CeedChk(ierr); ierr = CeedElemRestrictionCreateBlockedStrided(ceed, nelem, elemsize, blksize, nnodes, ncomp, strides, &blkrestr[i+starte]); CeedChk(ierr); } ierr = CeedElemRestrictionCreateVector(blkrestr[i+starte], NULL, &fullevecs[i+starte]); CeedChk(ierr); } switch(emode) { case CEED_EVAL_NONE: ierr = CeedQFunctionFieldGetSize(qffields[i], &size); CeedChk(ierr); ierr = CeedVectorCreate(ceed, Q*size*blksize, &evecs[i]); CeedChk(ierr); ierr = CeedVectorCreate(ceed, Q*size*blksize, &qvecs[i]); CeedChk(ierr); break; case CEED_EVAL_INTERP: ierr = CeedQFunctionFieldGetSize(qffields[i], &size); CeedChk(ierr); ierr = CeedElemRestrictionGetElementSize(r, &P); CeedChk(ierr); ierr = CeedVectorCreate(ceed, P*size*blksize, &evecs[i]); CeedChk(ierr); ierr = CeedVectorCreate(ceed, Q*size*blksize, &qvecs[i]); CeedChk(ierr); break; case CEED_EVAL_GRAD: ierr = CeedOperatorFieldGetBasis(opfields[i], &basis); CeedChk(ierr); ierr = CeedQFunctionFieldGetSize(qffields[i], &size); CeedChk(ierr); ierr = CeedBasisGetDimension(basis, &dim); CeedChk(ierr); ierr = CeedElemRestrictionGetElementSize(r, &P); CeedChk(ierr); ierr = CeedVectorCreate(ceed, P*size/dim*blksize, &evecs[i]); CeedChk(ierr); ierr = CeedVectorCreate(ceed, Q*size*blksize, &qvecs[i]); CeedChk(ierr); break; case CEED_EVAL_WEIGHT: // Only on input fields ierr = CeedOperatorFieldGetBasis(opfields[i], &basis); CeedChk(ierr); ierr = CeedVectorCreate(ceed, Q*blksize, &qvecs[i]); CeedChk(ierr); ierr = CeedBasisApply(basis, blksize, CEED_NOTRANSPOSE, CEED_EVAL_WEIGHT, CEED_VECTOR_NONE, qvecs[i]); CeedChk(ierr); break; case CEED_EVAL_DIV: break; // Not implimented case CEED_EVAL_CURL: break; // Not implimented } } return 0; } //------------------------------------------------------------------------------ // Setup Operator //------------------------------------------------------------------------------ static int CeedOperatorSetup_Opt(CeedOperator op) { int ierr; bool setupdone; ierr = CeedOperatorGetSetupStatus(op, &setupdone); CeedChk(ierr); if (setupdone) return 0; Ceed ceed; ierr = CeedOperatorGetCeed(op, &ceed); CeedChk(ierr); Ceed_Opt *ceedimpl; ierr = CeedGetData(ceed, (void *)&ceedimpl); CeedChk(ierr); const CeedInt blksize = ceedimpl->blksize; CeedOperator_Opt *impl; ierr = CeedOperatorGetData(op, (void *)&impl); CeedChk(ierr); CeedQFunction qf; ierr = CeedOperatorGetQFunction(op, &qf); CeedChk(ierr); CeedInt Q, numinputfields, numoutputfields; ierr = CeedOperatorGetNumQuadraturePoints(op, &Q); CeedChk(ierr); ierr = CeedQFunctionGetIdentityStatus(qf, &impl->identityqf); CeedChk(ierr); ierr= CeedQFunctionGetNumArgs(qf, &numinputfields, &numoutputfields); CeedChk(ierr); CeedOperatorField *opinputfields, *opoutputfields; ierr = CeedOperatorGetFields(op, &opinputfields, &opoutputfields); CeedChk(ierr); CeedQFunctionField *qfinputfields, *qfoutputfields; ierr = CeedQFunctionGetFields(qf, &qfinputfields, &qfoutputfields); CeedChk(ierr); // Allocate ierr = CeedCalloc(numinputfields + numoutputfields, &impl->blkrestr); CeedChk(ierr); ierr = CeedCalloc(numinputfields + numoutputfields, &impl->evecs); CeedChk(ierr); ierr = CeedCalloc(numinputfields + numoutputfields, &impl->edata); CeedChk(ierr); ierr = CeedCalloc(16, &impl->inputstate); CeedChk(ierr); ierr = CeedCalloc(16, &impl->evecsin); CeedChk(ierr); ierr = CeedCalloc(16, &impl->evecsout); CeedChk(ierr); ierr = CeedCalloc(16, &impl->qvecsin); CeedChk(ierr); ierr = CeedCalloc(16, &impl->qvecsout); CeedChk(ierr); impl->numein = numinputfields; impl->numeout = numoutputfields; // Set up infield and outfield pointer arrays // Infields ierr = CeedOperatorSetupFields_Opt(qf, op, 0, blksize, impl->blkrestr, impl->evecs, impl->evecsin, impl->qvecsin, 0, numinputfields, Q); CeedChk(ierr); // Outfields ierr = CeedOperatorSetupFields_Opt(qf, op, 1, blksize, impl->blkrestr, impl->evecs, impl->evecsout, impl->qvecsout, numinputfields, numoutputfields, Q); CeedChk(ierr); // Identity QFunctions if (impl->identityqf) { CeedEvalMode inmode, outmode; CeedQFunctionField *infields, *outfields; ierr = CeedQFunctionGetFields(qf, &infields, &outfields); CeedChk(ierr); for (CeedInt i=0; iqvecsout[i]); CeedChk(ierr); impl->qvecsout[i] = impl->qvecsin[i]; ierr = CeedVectorAddReference(impl->qvecsin[i]); CeedChk(ierr); } } ierr = CeedOperatorSetSetupDone(op); CeedChk(ierr); return 0; } //------------------------------------------------------------------------------ // Setup Input Fields //------------------------------------------------------------------------------ static inline int CeedOperatorSetupInputs_Opt(CeedInt numinputfields, CeedQFunctionField *qfinputfields, CeedOperatorField *opinputfields, CeedVector invec, CeedOperator_Opt *impl, CeedRequest *request) { CeedInt ierr; CeedEvalMode emode; CeedVector vec; uint64_t state; for (CeedInt i=0; iinputstate[i]) { ierr = CeedElemRestrictionApply(impl->blkrestr[i], CEED_NOTRANSPOSE, vec, impl->evecs[i], request); CeedChk(ierr); impl->inputstate[i] = state; } } else { // Set Qvec for CEED_EVAL_NONE if (emode == CEED_EVAL_NONE) { ierr = CeedVectorGetArray(impl->evecsin[i], CEED_MEM_HOST, &impl->edata[i]); CeedChk(ierr); ierr = CeedVectorSetArray(impl->qvecsin[i], CEED_MEM_HOST, CEED_USE_POINTER, impl->edata[i]); CeedChk(ierr); ierr = CeedVectorRestoreArray(impl->evecsin[i], &impl->edata[i]); CeedChk(ierr); } } // Get evec ierr = CeedVectorGetArrayRead(impl->evecs[i], CEED_MEM_HOST, (const CeedScalar **) &impl->edata[i]); CeedChk(ierr); } } return 0; } //------------------------------------------------------------------------------ // Input Basis Action //------------------------------------------------------------------------------ static inline int CeedOperatorInputBasis_Opt(CeedInt e, CeedInt Q, CeedQFunctionField *qfinputfields, CeedOperatorField *opinputfields, CeedInt numinputfields, CeedInt blksize, CeedVector invec, bool skipactive, CeedOperator_Opt *impl, CeedRequest *request) { CeedInt ierr; CeedInt dim, elemsize, size; CeedElemRestriction Erestrict; CeedEvalMode emode; CeedBasis basis; CeedVector vec; for (CeedInt i=0; iblkrestr[i], e/blksize, CEED_NOTRANSPOSE, invec, impl->evecsin[i], request); CeedChk(ierr); activein = 1; } // Basis action switch(emode) { case CEED_EVAL_NONE: if (!activein) { ierr = CeedVectorSetArray(impl->qvecsin[i], CEED_MEM_HOST, CEED_USE_POINTER, &impl->edata[i][e*Q*size]); CeedChk(ierr); } break; case CEED_EVAL_INTERP: ierr = CeedOperatorFieldGetBasis(opinputfields[i], &basis); CeedChk(ierr); if (!activein) { ierr = CeedVectorSetArray(impl->evecsin[i], CEED_MEM_HOST, CEED_USE_POINTER, &impl->edata[i][e*elemsize*size]); CeedChk(ierr); } ierr = CeedBasisApply(basis, blksize, CEED_NOTRANSPOSE, CEED_EVAL_INTERP, impl->evecsin[i], impl->qvecsin[i]); CeedChk(ierr); break; case CEED_EVAL_GRAD: ierr = CeedOperatorFieldGetBasis(opinputfields[i], &basis); CeedChk(ierr); if (!activein) { ierr = CeedBasisGetDimension(basis, &dim); CeedChk(ierr); ierr = CeedVectorSetArray(impl->evecsin[i], CEED_MEM_HOST, CEED_USE_POINTER, &impl->edata[i][e*elemsize*size/dim]); CeedChk(ierr); } ierr = CeedBasisApply(basis, blksize, CEED_NOTRANSPOSE, CEED_EVAL_GRAD, impl->evecsin[i], impl->qvecsin[i]); CeedChk(ierr); break; case CEED_EVAL_WEIGHT: break; // No action // LCOV_EXCL_START case CEED_EVAL_DIV: case CEED_EVAL_CURL: { ierr = CeedOperatorFieldGetBasis(opinputfields[i], &basis); CeedChk(ierr); Ceed ceed; ierr = CeedBasisGetCeed(basis, &ceed); CeedChk(ierr); return CeedError(ceed, 1, "Ceed evaluation mode not implemented"); // LCOV_EXCL_STOP } } } return 0; } //------------------------------------------------------------------------------ // Output Basis Action //------------------------------------------------------------------------------ static inline int CeedOperatorOutputBasis_Opt(CeedInt e, CeedInt Q, CeedQFunctionField *qfoutputfields, CeedOperatorField *opoutputfields, CeedInt blksize, CeedInt numinputfields, CeedInt numoutputfields, CeedOperator op, CeedVector outvec, CeedOperator_Opt *impl, CeedRequest *request) { CeedInt ierr; CeedElemRestriction Erestrict; CeedEvalMode emode; CeedBasis basis; CeedVector vec; for (CeedInt i=0; iqvecsout[i], impl->evecsout[i]); CeedChk(ierr); break; case CEED_EVAL_GRAD: ierr = CeedOperatorFieldGetBasis(opoutputfields[i], &basis); CeedChk(ierr); ierr = CeedBasisApply(basis, blksize, CEED_TRANSPOSE, CEED_EVAL_GRAD, impl->qvecsout[i], impl->evecsout[i]); CeedChk(ierr); break; // LCOV_EXCL_START case CEED_EVAL_WEIGHT: { Ceed ceed; ierr = CeedOperatorGetCeed(op, &ceed); CeedChk(ierr); return CeedError(ceed, 1, "CEED_EVAL_WEIGHT cannot be an output " "evaluation mode"); } case CEED_EVAL_DIV: case CEED_EVAL_CURL: { Ceed ceed; ierr = CeedOperatorGetCeed(op, &ceed); CeedChk(ierr); return CeedError(ceed, 1, "Ceed evaluation mode not implemented"); // LCOV_EXCL_STOP } } // Restrict output block // Get output vector ierr = CeedOperatorFieldGetVector(opoutputfields[i], &vec); CeedChk(ierr); if (vec == CEED_VECTOR_ACTIVE) vec = outvec; // Restrict ierr = CeedElemRestrictionApplyBlock(impl->blkrestr[i+impl->numein], e/blksize, CEED_TRANSPOSE, impl->evecsout[i], vec, request); CeedChk(ierr); } return 0; } //------------------------------------------------------------------------------ // Restore Input Vectors //------------------------------------------------------------------------------ static inline int CeedOperatorRestoreInputs_Opt(CeedInt numinputfields, CeedQFunctionField *qfinputfields, CeedOperatorField *opinputfields, bool skipactive, CeedOperator_Opt *impl) { CeedInt ierr; CeedEvalMode emode; for (CeedInt i=0; ievecs[i], (const CeedScalar **) &impl->edata[i]); CeedChk(ierr); } } return 0; } //------------------------------------------------------------------------------ // Operator Apply //------------------------------------------------------------------------------ static int CeedOperatorApply_Opt(CeedOperator op, CeedVector invec, CeedVector outvec, CeedRequest *request) { int ierr; Ceed ceed; ierr = CeedOperatorGetCeed(op, &ceed); CeedChk(ierr); Ceed_Opt *ceedimpl; ierr = CeedGetData(ceed, (void *)&ceedimpl); CeedChk(ierr); CeedInt blksize = ceedimpl->blksize; CeedOperator_Opt *impl; ierr = CeedOperatorGetData(op, (void *)&impl); CeedChk(ierr); CeedInt Q, numinputfields, numoutputfields, numelements; ierr = CeedOperatorGetNumElements(op, &numelements); CeedChk(ierr); ierr = CeedOperatorGetNumQuadraturePoints(op, &Q); CeedChk(ierr); CeedInt nblks = (numelements/blksize) + !!(numelements%blksize); CeedQFunction qf; ierr = CeedOperatorGetQFunction(op, &qf); CeedChk(ierr); ierr= CeedQFunctionGetNumArgs(qf, &numinputfields, &numoutputfields); CeedChk(ierr); CeedOperatorField *opinputfields, *opoutputfields; ierr = CeedOperatorGetFields(op, &opinputfields, &opoutputfields); CeedChk(ierr); CeedQFunctionField *qfinputfields, *qfoutputfields; ierr = CeedQFunctionGetFields(qf, &qfinputfields, &qfoutputfields); CeedChk(ierr); CeedEvalMode emode; // Setup ierr = CeedOperatorSetup_Opt(op); CeedChk(ierr); // Input Evecs and Restriction ierr = CeedOperatorSetupInputs_Opt(numinputfields, qfinputfields, opinputfields, invec, impl, request); CeedChk(ierr); // Output Lvecs, Evecs, and Qvecs for (CeedInt i=0; ievecsout[i], CEED_MEM_HOST, &impl->edata[i + numinputfields]); CeedChk(ierr); ierr = CeedVectorSetArray(impl->qvecsout[i], CEED_MEM_HOST, CEED_USE_POINTER, impl->edata[i + numinputfields]); CeedChk(ierr); ierr = CeedVectorRestoreArray(impl->evecsout[i], &impl->edata[i + numinputfields]); CeedChk(ierr); } } // Loop through elements for (CeedInt e=0; eidentityqf) { ierr = CeedQFunctionApply(qf, Q*blksize, impl->qvecsin, impl->qvecsout); CeedChk(ierr); } // Output basis apply and restrict ierr = CeedOperatorOutputBasis_Opt(e, Q, qfoutputfields, opoutputfields, blksize, numinputfields, numoutputfields, op, outvec, impl, request); CeedChk(ierr); } // Restore input arrays ierr = CeedOperatorRestoreInputs_Opt(numinputfields, qfinputfields, opinputfields, false, impl); CeedChk(ierr); return 0; } //------------------------------------------------------------------------------ // Assemble Linear QFunction //------------------------------------------------------------------------------ static int CeedOperatorAssembleLinearQFunction_Opt(CeedOperator op, CeedVector *assembled, CeedElemRestriction *rstr, CeedRequest *request) { int ierr; Ceed ceed; ierr = CeedOperatorGetCeed(op, &ceed); CeedChk(ierr); Ceed_Opt *ceedimpl; ierr = CeedGetData(ceed, (void *)&ceedimpl); CeedChk(ierr); const CeedInt blksize = ceedimpl->blksize; CeedOperator_Opt *impl; ierr = CeedOperatorGetData(op, (void *)&impl); CeedChk(ierr); CeedInt Q, numinputfields, numoutputfields, numelements, size; ierr = CeedOperatorGetNumElements(op, &numelements); CeedChk(ierr); ierr = CeedOperatorGetNumQuadraturePoints(op, &Q); CeedChk(ierr); CeedInt nblks = (numelements/blksize) + !!(numelements%blksize); CeedQFunction qf; ierr = CeedOperatorGetQFunction(op, &qf); CeedChk(ierr); ierr= CeedQFunctionGetNumArgs(qf, &numinputfields, &numoutputfields); CeedChk(ierr); CeedOperatorField *opinputfields, *opoutputfields; ierr = CeedOperatorGetFields(op, &opinputfields, &opoutputfields); CeedChk(ierr); CeedQFunctionField *qfinputfields, *qfoutputfields; ierr = CeedQFunctionGetFields(qf, &qfinputfields, &qfoutputfields); CeedChk(ierr); CeedVector vec, lvec; CeedInt numactivein = 0, numactiveout = 0; CeedVector *activein = NULL; CeedScalar *a, *tmp; // Setup ierr = CeedOperatorSetup_Opt(op); CeedChk(ierr); // Check for identity if (impl->identityqf) // LCOV_EXCL_START return CeedError(ceed, 1, "Assembling identity qfunctions not supported"); // LCOV_EXCL_STOP // Input Evecs and Restriction ierr = CeedOperatorSetupInputs_Opt(numinputfields, qfinputfields, opinputfields, NULL, impl, request); CeedChk(ierr); // Count number of active input fields for (CeedInt i=0; iqvecsin[i], 0.0); CeedChk(ierr); ierr = CeedVectorGetArray(impl->qvecsin[i], CEED_MEM_HOST, &tmp); CeedChk(ierr); ierr = CeedRealloc(numactivein + size, &activein); CeedChk(ierr); for (CeedInt field=0; fieldqvecsin[i], &tmp); CeedChk(ierr); } } // Count number of active output fields for (CeedInt i=0; i 1) { ierr = CeedVectorSetValue(activein[(in+numactivein-1)%numactivein], 0.0); CeedChk(ierr); } // Set Outputs for (CeedInt out=0; outqvecsout[out], CEED_MEM_HOST, CEED_USE_POINTER, a); CeedChk(ierr); ierr = CeedQFunctionFieldGetSize(qfoutputfields[out], &size); CeedChk(ierr); a += size*Q*blksize; // Advance the pointer by the size of the output } } // Apply QFunction ierr = CeedQFunctionApply(qf, Q*blksize, impl->qvecsin, impl->qvecsout); CeedChk(ierr); } } // Un-set output Qvecs to prevent accidental overwrite of Assembled for (CeedInt out=0; outqvecsout[out], CEED_MEM_HOST, CEED_COPY_VALUES, NULL); CeedChk(ierr); } } // Restore input arrays ierr = CeedOperatorRestoreInputs_Opt(numinputfields, qfinputfields, opinputfields, true, impl); CeedChk(ierr); // Output blocked restriction ierr = CeedVectorRestoreArray(lvec, &a); CeedChk(ierr); ierr = CeedVectorSetValue(*assembled, 0.0); CeedChk(ierr); CeedElemRestriction blkrstr; ierr = CeedElemRestrictionCreateBlockedStrided(ceed, numelements, Q, blksize, numelements*Q, numactivein*numactiveout, strides, &blkrstr); CeedChk(ierr); ierr = CeedElemRestrictionApply(blkrstr, CEED_TRANSPOSE, lvec, *assembled, request); CeedChk(ierr); // Cleanup for (CeedInt i=0; inumein+impl->numeout; i++) { ierr = CeedElemRestrictionDestroy(&impl->blkrestr[i]); CeedChk(ierr); ierr = CeedVectorDestroy(&impl->evecs[i]); CeedChk(ierr); } ierr = CeedFree(&impl->blkrestr); CeedChk(ierr); ierr = CeedFree(&impl->evecs); CeedChk(ierr); ierr = CeedFree(&impl->edata); CeedChk(ierr); ierr = CeedFree(&impl->inputstate); CeedChk(ierr); for (CeedInt i=0; inumein; i++) { ierr = CeedVectorDestroy(&impl->evecsin[i]); CeedChk(ierr); ierr = CeedVectorDestroy(&impl->qvecsin[i]); CeedChk(ierr); } ierr = CeedFree(&impl->evecsin); CeedChk(ierr); ierr = CeedFree(&impl->qvecsin); CeedChk(ierr); for (CeedInt i=0; inumeout; i++) { ierr = CeedVectorDestroy(&impl->evecsout[i]); CeedChk(ierr); ierr = CeedVectorDestroy(&impl->qvecsout[i]); CeedChk(ierr); } ierr = CeedFree(&impl->evecsout); CeedChk(ierr); ierr = CeedFree(&impl->qvecsout); CeedChk(ierr); ierr = CeedFree(&impl); CeedChk(ierr); return 0; } //------------------------------------------------------------------------------ // Operator Create //------------------------------------------------------------------------------ int CeedOperatorCreate_Opt(CeedOperator op) { int ierr; Ceed ceed; ierr = CeedOperatorGetCeed(op, &ceed); CeedChk(ierr); Ceed_Opt *ceedimpl; ierr = CeedGetData(ceed, (void *)&ceedimpl); CeedChk(ierr); CeedInt blksize = ceedimpl->blksize; CeedOperator_Opt *impl; ierr = CeedCalloc(1, &impl); CeedChk(ierr); ierr = CeedOperatorSetData(op, (void *)&impl); CeedChk(ierr); if (blksize != 1 && blksize != 8) // LCOV_EXCL_START return CeedError(ceed, 1, "Opt backend cannot use blocksize: %d", blksize); // LCOV_EXCL_STOP ierr = CeedSetBackendFunction(ceed, "Operator", op, "AssembleLinearQFunction", CeedOperatorAssembleLinearQFunction_Opt); CeedChk(ierr); ierr = CeedSetBackendFunction(ceed, "Operator", op, "ApplyAdd", CeedOperatorApply_Opt); CeedChk(ierr); ierr = CeedSetBackendFunction(ceed, "Operator", op, "Destroy", CeedOperatorDestroy_Opt); CeedChk(ierr); return 0; } //------------------------------------------------------------------------------